diff --git a/ChangeLog b/ChangeLog index 910f4d4..4608e00 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,87 @@ +0.65 + - Fixed FAT writing. + - Added some more missing DOS functions. + - Improved PIC so that it actually honours irq 2/9. + - Improved intelligent MPU-401 mode so that more games work with it. + - Some mouse fixes. + - Changed DMA transfers a bit so they bypass the paging tables. + - Added S3 XGA functionality. + - Improved paging so that read and write faults are handled differently. + - Rewrote exception handling a bit (no exception 0x0B with dos4gw anymore). + - Added IO exceptions in all but the dynamic core. + - Some ems improvements. + - Added midi-device selection code for the windows hosts. + - Fix crashes/segfaults related to the disabling of the pcspeaker. + - Added some more FILES=XX detection tricks. + - Fixed some vga detection schemes. + - Fixed screenshot corruption when using -noconsole in a read-only directory. + - Fix wrong scaled screenshots. + - Added some hidden file functions when using diskimages. (helps with cdrom + detection schemes) + - Fixed a bug in the mixer code, that muted the music in certain games. + - Added an assembly fpu core. + - Made the shell more flexible for batch files. + - Check for unaligned memory acces fixes hangups on ARM processors. + - Some 64 bit fixes. + - Added code to change configuration at runtime. + - Improved ADPCM emulation. + - Fixed a few cpu instructions. + - Always report vesa 2.0 and fix some colour issues with vesa games. + - Fix video mode 0x06 and 0x0a. + - Improvements to the joystick emulation. 4 buttons are supported as well. + - Add VCPI emulation for Origin games. + - Fixed a lot of things in the boot code. Most booters work now. + - Lots of improvements to the IPX emulation. + - Rewritten modem emulation. Should work with more games. + - Improvements to the dos memory managment routines. + - Add UMB (upper memory blocks) support. + - Emulate the pause key. + - Improve Composite CGA mode emulation. + - Lots of vga compatibility changes. + - Improved support for chained video modes. + - Improved mode and palette handling in cga modes. + - Mount accepts ~ now. + - Added a few of the EGA RIL functions. + - Added TandyDAC emulation. + - OS/2 support. + - Improved and speed up the dynamic cpu core. + - Fix some errors in the CD-ROM emulation layer. + - Added an automatic work-around for some graphics chipsets. + - Add PCjr support. + - Allow mousedriver to be replaced. Fixes a few games that come with their + own (internal) driver. + - Improved dynamic cpu core so it can handle pagefaults and some obscure + types of self-modifying code. + - Added -noautoexec switch to skip the contents of [autoexec] in the + configuration file. + - Improved v86 mode emulation (mainly for Strike Commander). + - Improved timer behavior. + - Improved extended keyboard support. + - Enhanced and added several DOS tables. + - Made core_full endian safe. + - Made pagefaults endian safe. + - Add support for moviecapturing + - Add support for 15/16/32 bit videomodes. + - Add some more VESA modi (4 bit). + - Add 1024x768 output. + - Changed screenrendering so it only draws changes to the screen. + - Allow remapping of the EMS page when the dma transfer was started from + the page frame + - Made EMS and DMA work together when playing from a mapped memory page. + - Renamed several configuration options, so that they are unique. + - Merged mpu and intelligent into one option. + - Merged fullfixed and fullresolution. + - Extended keys should be handled better. + - F11 and F12 work. + - Compilation fixes for various platforms. + - Fix a few crashes when giving bad input. + - Removed interp2x and added few new scalers. + - Reintroduce the lockfree mouse. (autolock=false) + - Add a larger cache for the dynamic cpu core. + - Improved soundblaster DSP, so it gets detected by creative tools. + - Lots of bugfixes. + - Even more bugfixes. + 0.63 - Fixed crash with keymapper (ctrl-f1) and output=surface. - Added unmounting. diff --git a/INSTALL b/INSTALL index 936cde7..e500002 100644 --- a/INSTALL +++ b/INSTALL @@ -50,8 +50,18 @@ In step 1 you could add the following switches: enables some memory increasing inlines. This greatly increases compiletime for maybe a increase in speed. +--disable-dynamic-x86 + disables the dynamic cpu core. Although it's unstable it can greatly + improve the speed of dosbox on x86 hosts. + +--disable-fpu-x86 + disables the assembly fpu core. Although relatively new the x86 fpu + core has more accuracy then the regular fpu core. + Check the src subdir for the binary. +NOTE: If capslock and numlock appear to be broken. open +src/ints/bios_keyboard.cpp and go to line 30 and read there how to fix it. Build instructions for VC++6 diff --git a/Makefile.in b/Makefile.in index 136d5bf..9519ad5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -41,7 +41,7 @@ target_triplet = @target@ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/config.h.in \ $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ - THANKS config.guess config.sub depcomp install-sh missing + THANKS TODO config.guess config.sub depcomp install-sh missing subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ @@ -101,6 +101,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -126,10 +128,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -236,7 +240,13 @@ uninstall-info-am: # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -248,7 +258,7 @@ $(RECURSIVE_TARGETS): local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ @@ -256,7 +266,13 @@ $(RECURSIVE_TARGETS): mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ @@ -277,7 +293,7 @@ maintainer-clean-recursive: local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ diff --git a/NEWS b/NEWS index efee9e0..705cb4f 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,87 @@ +0.65 + - Fixed FAT writing. + - Added some more missing DOS functions. + - Improved PIC so that it actually honours irq 2/9. + - Improved intelligent MPU-401 mode so that more games work with it. + - Some mouse fixes. + - Changed DMA transfers a bit so they bypass the paging tables. + - Added S3 XGA functionality. + - Improved paging so that read and write faults are handled differently. + - Rewrote exception handling a bit (no exception 0x0B with dos4gw anymore). + - Added IO exceptions in all but the dynamic core. + - Some ems improvements. + - Added midi-device selection code for the windows hosts. + - Fix crashes/segfaults related to the disabling of the pcspeaker. + - Added some more FILES=XX detection tricks. + - Fixed some vga detection schemes. + - Fixed screenshot corruption when using -noconsole in a read-only directory. + - Fix wrong scaled screenshots. + - Added some hidden file functions when using diskimages. (helps with cdrom + detection schemes) + - Fixed a bug in the mixer code, that muted the music in certain games. + - Added an assembly fpu core. + - Made the shell more flexible for batch files. + - Check for unaligned memory acces fixes hangups on ARM processors. + - Some 64 bit fixes. + - Added code to change configuration at runtime. + - Improved ADPCM emulation. + - Fixed a few cpu instructions. + - Always report vesa 2.0 and fix some colour issues with vesa games. + - Fix video mode 0x06 and 0x0a. + - Improvements to the joystick emulation. 4 buttons are supported as well. + - Add VCPI emulation for Origin games. + - Fixed a lot of things in the boot code. Most booters work now. + - Lots of improvements to the IPX emulation. + - Rewritten modem emulation. Should work with more games. + - Improvements to the dos memory managment routines. + - Add UMB (upper memory blocks) support. + - Emulate the pause key. + - Improve Composite CGA mode emulation. + - Lots of vga compatibility changes. + - Improved support for chained video modes. + - Improved mode and palette handling in cga modes. + - Mount accepts ~ now. + - Added a few of the EGA RIL functions. + - Added TandyDAC emulation. + - OS/2 support. + - Improved and speed up the dynamic cpu core. + - Fix some errors in the CD-ROM emulation layer. + - Added an automatic work-around for some graphics chipsets. + - Add PCjr support. + - Allow mousedriver to be replaced. Fixes a few games that come with their + own (internal) driver. + - Improved dynamic cpu core so it can handle pagefaults and some obscure + types of self-modifying code. + - Added -noautoexec switch to skip the contents of [autoexec] in the + configuration file. + - Improved v86 mode emulation (mainly for Strike Commander). + - Improved timer behavior. + - Improved extended keyboard support. + - Enhanced and added several DOS tables. + - Made core_full endian safe. + - Made pagefaults endian safe. + - Add support for moviecapturing + - Add support for 15/16/32 bit videomodes. + - Add some more VESA modi (4 bit). + - Add 1024x768 output. + - Changed screenrendering so it only draws changes to the screen. + - Allow remapping of the EMS page when the dma transfer was started from + the page frame + - Made EMS and DMA work together when playing from a mapped memory page. + - Renamed several configuration options, so that they are unique. + - Merged mpu and intelligent into one option. + - Merged fullfixed and fullresolution. + - Extended keys should be handled better. + - F11 and F12 work. + - Compilation fixes for various platforms. + - Fix a few crashes when giving bad input. + - Removed interp2x and added few new scalers. + - Reintroduce the lockfree mouse. (autolock=false) + - Add a larger cache for the dynamic cpu core. + - Improved soundblaster DSP, so it gets detected by creative tools. + - Lots of bugfixes. + - Even more bugfixes. + 0.63 - Fixed crash with keymapper (ctrl-f1) and output=surface. - Added unmounting. diff --git a/README b/README index e134421..1a6eac8 100644 --- a/README +++ b/README @@ -1,19 +1,19 @@ -DOSBox v0.63 +DOSBox v0.65 ===== NOTE: ===== -While we hope that, one day, DOSBox will run virtually all programs -ever made for the PC...we are not there yet. At present, DOSBox run on a high- -end machine will roughly be the equivalent of a 486 PC. The 0.60 +While we are hoping that one day, DOSBox will run all programs +ever made for the PC, we are not there yet. At present, DOSBox running on a +high-end machine will roughly be the equivalent of a 486 PC. The 0.60 release has added support for "protected mode" allowing for more complex and -recent programs, but note that this support is early in development and -nowhere near as complete as the support for 386 real-mode games (or -earlier). Also note that "protected mode" games need substantially more -resources and may require a much faster processor for you to run it properly -in DOSBox. +recent programs, but note that this support is still in an early stage of +development and unlike the support for 386 real-mode games (or earlier) hasn't +been completed yet. Also note that "protected mode" games need substantially +more resources and may require a much faster processor for you to run them +properly in DOSBox. @@ -49,9 +49,10 @@ Type INTRO in DOSBox. That's it. Some Frequently Asked Questions: Q: I've got a Z instead of a C at the prompt. +Q: My game crashes when using opengl/nb or is much slower. Q: My CD-ROM doesn't work. Q: The mouse doesn't work. -Q: The sound stutters. +Q: The sound stutters or sounds stretched/weird. Q: I can't type \ or : in DOSBox. Q: The game/application can't find its CD-ROM. Q: The game/application runs much too slow! @@ -66,16 +67,21 @@ Q: Great README, but I still don't get it. Q: I've got a Z instead of a C at the prompt. A: You have to make your directories available as drives in DOSBox by using - the "mount" command. For example, in Windows "mount C D:\" would give - you a C in DOSBox which points at your Windows D:\ drive. - In Linux, "mount c /home/username" would give you a C in DOSBox - which points at /home/username in Linux. + the "mount" command. For example, in Windows "mount C D:\GAMES" will give + you a C drive in DOSBox which points to your Windows D:\GAMES directory. + In Linux, "mount c /home/username" will give you a C drive in DOSBox + which points to /home/username in Linux. + + +Q: My game crashes when using opengl/nb or is much slower. +A: Somehow our opengl code isn't entirely stable on some platforms. + Use surface instead. Q: My CD-ROM doesn't work. -A: To mount your cdrom in DOSBox you have to specify some additional options - when mounting the cdrom. - To enable the most basic cdrom support: +A: To mount your CD-ROM in DOSBox you have to specify some additional options + when mounting the CD-ROM. + To enable the most basic CD-ROM support: - mount d f:\ -t cdrom To enable low-level SDL-support: - mount d f:\ -t cdrom -usecd 0 @@ -84,23 +90,23 @@ A: To mount your cdrom in DOSBox you have to specify some additional options To enable low-level aspi-support (win98 with aspi-layer installed): - mount d f:\ -t cdrom -usecd 0 -apsi - In the commands: - d driveletter you in DOSBox + In the commands: - d driveletter you will get in DOSBox - f:\ location of cdrom on your PC. - - 0 The number of the cdrom drive, reported by mount -cd + - 0 The number of the CD-ROM drive, reported by mount -cd See also the question: The game/application can't find its CD-ROM. Q: The mouse doesn't work. -A: Normally DOSBox detects the mouse being used by a game. If you click on - the screen then it should get locked (confined to the DOSBox window) - and work. Sometimes the DOSBox mouse detection doesn't work with certain - games. You might have to force to lock the mouse then with ctrl-F10. +A: Usually, DOSBox detects when a game uses mouse control. When you click on + the screen it should get locked (confined to the DOSBox window) and work. + With certain games, the DOSBox mouse detection doesn't work. In that case + you will have to lock the mouse manually by pressing CTRL-F10. -Q: The sound stutters. +Q: The sound stutters or sounds stretched/weird. A: You're using too much cpu power to keep DOSBox running at the current speed. - You can either lower the cycles or skip frames or get a faster machine. - You can also increase the prebuffer in the configfile + You can lower the cycles, skip frames or get a faster machine. + You can also increase the prebuffer in the configfile. Q: I can't type \ or : in DOSBox. @@ -108,16 +114,18 @@ A: This is a known problem. It only occurs if your keyboard layout isn't US. Some possible fixes: 1. Switch your keyboard layout. 2. Use / instead. - 3. Add the commands you want to execute to the "configfile". - 4. Start the keymapper (CTRL-F1 or add -startmapper switch to dosbox) - 5. for \ try the keys around "enter". For ":" try shift and the keys between - "enter" and "l" (US keyboard layout). - 6. Use keyb.com from FreeDOS (http://projects.freedos.net/keyb/). + 3. Open dosbox.conf and change usescancodes=false to usescancodes=true. + 4. Add the commands you want to execute to the "configfile". + 5. Start the keymapper (CTRL-F1 or add -startmapper switch to DOSBox). + 6. Use ALT-58 for : and ALT-92 for \. + 7. for \ try the keys around "enter". For ":" try shift and the keys + between "enter" and "l" (US keyboard layout). + 8. Use keyb.com from FreeDOS (http://projects.freedos.net/keyb/). Q: The game/application can't find its CD-ROM. A: Be sure to mount the CD-ROM with -t cdrom switch. Also try adding the - correct label (-label LABEL). To enable more low-level CD-ROM support add + correct label (-label LABEL). To enable more low-level CD-ROM support, add the following switch to mount: -usecd #, where # is the number of your CD-ROM drive reported by mount -cd. If you run Win32 you can specify -ioctl or -aspi. Look at the description elsewhere in this document for their @@ -145,26 +153,26 @@ A: DOSBox emulates several legacy sound devices: this with the Adlib emulation may result in conflicts. - Tandy 3 voice The emulation of this sound hardware is complete with the exception of - the noise channel, which is not very well documented and as such is only - a best guess as to the sound's accuracy. + the noise channel. The noise channel is not very well documented and as + such is only a best guess as to the sound's accuracy. - Adlib Borrowed from MAME, this emulation is almost perfect and includes the Adlib's ability to almost play digitized sound. - - SoundBlaster 16/ SoundBlaster Pro I & II /Sound Blaster I & II - Coupled with the Adlib, by default DOSBox provides Soundblaster 16 - level 16-bit stereo sound. You can select a different SoundBlaster - version in the configfile of DOSBox (See Internal Commands: CONFIG). + - SoundBlaster 16/ SoundBlaster Pro I & II /SoundBlaster I & II + By default DOSBox provides Soundblaster 16 level 16-bit stereo sound. + You can select a different SoundBlaster version in the configfile of + DOSBox (See Internal Commands: CONFIG). - Disney Soundsource Using the printer port, this sound device outputs digital sound only. - Gravis Ultrasound The emulation of this hardware is nearly complete, though the MIDI - capabilities have been left out since an MPU-401 has been + capabilities have been left out, since an MPU-401 has been emulated in other code. - MPU-401 A MIDI passthrough interface is also emulated. This method of sound output will only work when used with a General Midi or MT-32 device. -Q: DOSBox crashes on startup and I'm running arts +Q: DOSBox crashes on startup and I'm running arts. A: This isn't really a DOSBox problem, but the solution is to set the environment variable SDL_AUDIODRIVER to alsa or oss. @@ -187,70 +195,73 @@ http://dosbox.sourceforge.net 3. Usage: ========= -An overview of the commandline options you can give to DOSBox. +An overview of the command line options you can give to DOSBox. Windows Users must open cmd.exe or command.com or edit the shortcut to -dosbox.exe for this. +DOSBox.exe for this. The options are valid for all operating systems unless noted in the option description: dosbox [name] [-exit] [-c command] [-fullscreen] [-conf congfigfile] [-lang languagefile] [-machine machinetype] [-noconsole] - [-startmapper] + [-startmapper] [-noautoexec] dosbox -version name - If "name" is a directory it'll mount that as the C: drive. - If "name" is an executable it'll mount the directory of "name" + If "name" is a directory it will mount that as the C: drive. + If "name" is an executable it will mount the directory of "name" as the C: drive and execute "name". -exit - dosbox will close itself when the DOS application "name" ends. + DOSBox will close itself when the DOS application "name" ends. -c command Runs the specified command before running "name". Multiple commands - can be specified. Each command should start with -c though. + can be specified. Each command should start with "-c", though. A command can be: an Internal Program, a DOS command or an executable on a mounted drive. -fullscreen - Starts dosbox in fullscreen mode. + Starts DOSBox in fullscreen mode. -conf configfile - Start dosbox with the options specified in "configfile". + Start DOSBox with the options specified in "configfile". See Chapter 9 for more details. -lang languagefile - Start dosbox using the language specified in "languagefile". + Start DOSBox using the language specified in "languagefile". -noconsole (Windows Only) - Start dosbox without showing the console window. Output will + Start DOSBox without showing the console window. Output will be redirected to stdout.txt and stderr.txt -machine machinetype - Setup dosbox to emulate a specific type of machine. Valid choices are: - hercules, cga, tandy, vga (default). The machinetype has influence on + Setup DOSBox to emulate a specific type of machine. Valid choices are: + hercules, cga, pcjr, tandy, vga (default). The machinetype affects both the videocard and the available soundcards. -startmapper Enter the keymapper directly on startup. Useful for people with keyboard problems. + -noautoexec + Skips the [autoexec] section of the loaded configuration file. + -version output version information and exit. Useful for frontends. -Note: If a name/command/configfile/languagefile contains a space in it, put +Note: If a name/command/configfile/languagefile contains a space, put the whole name/command/configfile/languagefile between quotes ("command or file name"). For example: dosbox c:\atlantis\atlantis.exe -c "MOUNT D C:\SAVES" - This would mount c:\atlantis as c:\ and run atlantis.exe. + This mounts c:\atlantis as c:\ and runs atlantis.exe. Before it does that it would first mount C:\SAVES as the D drive. -In Windows you can also drag directories/files onto the dosbox executable. - +In Windows, you can also drag directories/files onto the DOSBox executable. + ===================== @@ -285,7 +296,7 @@ MOUNT -u "Emulated Drive letter" -freesize size_in_mb Sets the amount of free space available on a drive in MB's. This - is a more simple version of -size. + is a simpler version of -size. -label drivelabel Sets the name of the drive to "drivelabel". Needed on some @@ -295,19 +306,19 @@ MOUNT -u "Emulated Drive letter" For win32: label is extracted from "Real Drive". For Linux: label is set to NO_LABEL. - If you do specify a label this label will be kept as long as the drive + If you do specify a label, this label will be kept as long as the drive is mounted. It will not be updated !! -aspi - Forces to use the aspi layer. Only valid if mounting a cdrom under + Forces use of the aspi layer. Only valid if mounting a cdrom under Windows systems with an ASPI-Layer. -ioctl - Forces to use ioctl commands. Only valid if mounting a cdrom under + Forces use of ioctl commands. Only valid if mounting a cdrom under a Windows OS which support them (Win2000/XP/NT). -usecd number - Forces to use SDL cdrom support for drive number. + Forces use of SDL cdrom support for drive number. Number can be found by -cd. Valid on all systems. -cd @@ -320,16 +331,20 @@ MOUNT -u "Emulated Drive letter" Hardware support is then missing. Basically, MOUNT allows you to connect real hardware to DOSBox's "emulated" - PC. So MOUNT C C:\ tells DOSBox to use your real C: drive as drive C: in - DOSBox. It also allows you to change the drive's letter identification for - programs that demand specific drive letters. + PC. So MOUNT C C:\GAMES tells DOSBox to use your C:\GAMES directory as drive + C: in DOSBox. It also allows you to change the drive's letter identification + for programs that demand specific drive letters. For example: Touche: Adventures of The Fifth Musketeer must be run on your C: - drive. Using DOSBox and its mount command, you can trick into thinking it - is on C drive while placing it where you want it. For example, if the game - were in D:\TOUCHE, you can use the command MOUNT C D:\ would allow you to - run Touche from the D drive. - + drive. Using DOSBox and its mount command, you can trick the game into + believing it is on the C drive, while you can still place it where you + want it. For example, if the game is in D:\TOUCHE, the command MOUNT C D:\ + will allow you to run Touche from the D drive. + + Mounting your entire C drive with MOUNT C C:\ is NOT recommended! + If you or DOSBox makes a mistake you may loose all your files. + It's recommended to put all your applications/games in a subdirectory and + mount that. General MOUNT Examples: 1. To mount c:\DirX as a floppy : @@ -350,22 +365,50 @@ MEM Program to display the amount of free memory. CONFIG [-writeconf] [-writelang] localfile - Write the current configuration or language settings to file. - "localfile" is located on the local drive. Not a mounted drive in DOSBox. +CONFIG -set "section property=value" +CONFIG -get "section property" - The configuration file controls various settings of DOSBox: The amount - of emulated memory, the emulated soundcards and many more things. It - allows acces to AUTOEXEC.BAT as well. - See section 9 (The Config File) for more information. + CONFIG can be used to change or query various settings of DOSBox + during runtime. It can save the current settings and language strings to + disk. Information about all possible sections and properties can + be found in section 9 (The Config File). - The language file controls all visible ouput of the internal commands - and the internal dos. + -writeconf localfile + Write the current configuration settings to file. "localfile" is + located on the local drive, not a mounted drive in DOSBox. + The configuration file controls various settings of DOSBox: + the amount of emulated memory, the emulated soundcards and many more + things. It allows access to AUTOEXEC.BAT as well. + See section 9 (The Config File) for more information. + + -writelang localfile + Write the current language settings to file. "localfile" is + located on the local drive, not a mounted drive in DOSBox. + The language file controls all visible ouput of the internal commands + and the internal dos. + + -set "section property=value" + CONFIG will attempt to set the property to new value. At this moment + CONFIG can not report whether the command succeeded or not. + + -get "section property" + The current value of the property is reported and stored in the + environment variable %CONFIG%. This can be used to store the value + when using batch files. + + Both "-set" and "-get" work from batch files and can be used to set up your + own preferences for each game. + + Examples: + 1. To create a configfile in your current directory: + config -writeconf dosbox.conf + 2. To set the cpu cycles to 10000: + config -set "cpu cycles=10000" + 3. To turn ems memory emulation off: + config -set "dos ems=off" + 4. To check which cpu core is being used. + config -get "cpu core" - Example: - To create a configfile in your current directory: - config -writeconf dosbox.conf - - LOADFIX [-size] [program] [program-parameters] LOADFIX -f Program to reduce the amount of memory available. Useful for old programs @@ -395,9 +438,9 @@ RESCAN MIXER Makes DOSBox display its current volume settings. - You can change this way: + Here's how you can change them: - mixer channel left:right [/NOSHOW] + mixer channel left:right [/NOSHOW] [/LISTMIDI] channel Can be one of the following: MASTER, DISNEY, SPKR, GUS, SB, FM. @@ -409,8 +452,14 @@ MIXER /NOSHOW Prevents DOSBox from showing the result if you set one of the volume levels. - - + + /LISTMIDI + Lists the available midi devices on your pc (Windows). To select a + device other than the Windows default midi-mapper, add a line + 'config=id' to the [midi] section in the configuration file, where + 'id' is the number for the device as listed by LISTMIDI. + + IMGMOUNT A utility to mount disk images and CD-ROM images in DOSBox. @@ -418,9 +467,9 @@ IMGMOUNT -size [sectorsbytesize, sectorsperhead, heads, cylinders] imagefile - location of the image files to mount in DOSBox. The location is on a + Location of the image files to mount in DOSBox. The location is on a mounted drive inside DOSBox. CD-ROM images can be mounted - directly as well. They don't need to be a mounted drive. + directly as well. They don't have to be on a mounted drive. -t The following are valid image types: @@ -434,16 +483,16 @@ IMGMOUNT -fs The following are valid file system formats: iso: Specifies the ISO 9660 CD-ROM format. - fat: Specifies the image uses the FAT file system. DOSBox will attempt + fat: Specifies that the image uses the FAT file system. DOSBox will attempt to mount this image as a drive in DOSBox and make the files available from inside DOSBox. none: DOSBox will make no attempt to read the file system on the disk. - This is useful if one needs to format it or one wants to boot - off of the disk using the BOOT command. When using the "none" - filesystem, one must specify the drive number (2 or 3, + This is useful if you need to format it or if you want to boot + the disk using the BOOT command. When using the "none" + filesystem, you must specify the drive number (2 or 3, where 2 = master, 3 = slave) rather than a drive letter. For example, to mount a 70MB image as the slave drive device, - one would type: + you would type: "imgmount 3 d:\test.img -size 512,63,16,142 -fs none" (without the quotes) Compare this with a mount to read the drive in DOSBox, which would read as: @@ -470,13 +519,13 @@ BOOT diskimgN.img This can be any number of floppy disk images one wants mounted after DOSBox boots the specified drive letter. - To swap between images, one hits CTRL+F4 to swap out the current disk - and swap in the next disk in the list. Once the last disk in the list is - swapped out, the list loops back to the beginning. + To swap between images, hit CTRL-F4 to change from the current disk + to the next disk in the list. The list will loop back from the last + disk image to the beginning. [-l driveletter] - This parameter allows one to specify the drive to boot from. - The default is the A drive, the floppy drive. One can also boot off of + This parameter allows you to specify the drive to boot from. + The default is the A drive, the floppy drive. You can also boot a hard drive image mounted as master by specifying "-l C" without the quotes, or the drive as slave by specifying "-l D" @@ -487,14 +536,14 @@ IPX All of the IPX networking is managed through the internal DOSBox program IPXNET. For help on the IPX networking from inside DOSBox, type - "IPXNET HELP" (without quotes) and the program will list out the commands + "IPXNET HELP" (without quotes) and the program will list the commands and relevant documentation. With regard to actually setting up a network, one system needs to be - the server. To set this up, in a DOSBox session, one should type - "IPXNET STARTSERVER" (without the quotes). The server DOSBox session will - automatically add itself to the virtual IPX network. In turn, for every - other computer that should be part of the virtual IPX network, + the server. To set this up, type "IPXNET STARTSERVER" (without the quotes) + in a DOSBox session. The server DOSBox session will + automatically add itself to the virtual IPX network. For every + additional computer that should be part of the virtual IPX network, you'll need to type "IPXNET CONNECT ". For example, if your server is at bob.dosbox.com, you would type "IPXNET CONNECT bob.dosbox.com" on every non-server system. @@ -503,18 +552,18 @@ IPX IPXNET CONNECT - IPXNET CONNECT opens a connection to an IPX tunneling server + IPXNET CONNECT opens a connection to an IPX tunnelling server running on another DOSBox session. The "address" parameter specifies - the IP address or host name of the server computer. One can also - specify the UDP port to use. By default IPXNET uses port 213, the - assigned IANA port for IPX tunneling, for its connection. + the IP address or host name of the server computer. You can also + specify the UDP port to use. By default IPXNET uses port 213 - the + assigned IANA port for IPX tunnelling - for its connection. The syntax for IPXNET CONNECT is: IPXNET CONNECT address IPXNET DISCONNECT - IPXNET DISCONNECT closes the connection to the IPX tunneling server. + IPXNET DISCONNECT closes the connection to the IPX tunnelling server. The syntax for IPXNET DISCONNECT is: IPXNET DISCONNECT @@ -524,34 +573,34 @@ IPX IPXNET STARTSERVER starts and IPX tunneling server on this DOSBox session. By default, the server will accept connections on UDP port 213, though this can be changed. Once the server is started, DOSBox - will automatically start a client connection to the IPX tunneling server. + will automatically start a client connection to the IPX tunnelling server. - The syntax for IPXNET STARTSERVER is: - IPXNET STARTSERVER + The syntax for IPXNET STARTSERVER is: + IPXNET STARTSERVER - IPXNET STOPSERVER + IPXNET STOPSERVER - IPXNET STOPSERVER stops the IPX tunneling server running on this DOSBox + IPXNET STOPSERVER stops the IPX tunnelling server running on this DOSBox session. Care should be taken to ensure that all other connections have - terminated as well since stopping the server may cause lockups on other - machines still using the IPX tunneling server. + terminated as well, since stopping the server may cause lockups on other + machines that are still using the IPX tunnelling server. The syntax for IPXNET STOPSERVER is: IPXNET STOPSERVER - IPXNET PING + IPXNET PING - IPXNET PING broadcasts a ping request through the IPX tunneled network. + IPXNET PING broadcasts a ping request through the IPX tunnelled network. In response, all other connected computers will respond to the ping and report the time it took to receive and send the ping message. The syntax for IPXNET PING is: - IPXNET PING + IPXNET PING - IPXNET STATUS + IPXNET STATUS - IPXNET STATUS reports the current state of this DOSBox's sessions - IPX tunneling network. For a list of the computers connected to the + IPXNET STATUS reports the current state of this DOSBox session's + IPX tunnelling network. For a list of all computers connected to the network use the IPXNET PING command. The syntax for IPXNET STATUS is: @@ -566,9 +615,11 @@ For more information use the /? command line switch with the programs. 5. Special Keys: ================ -ALT-ENTER Go full screen and back. +ALT-ENTER Switch to full screen and back. +ALT-PAUSE Pause emulation. CTRL-F1 Start the keymapper. -CTRL-F4 Swap mounted disk-image. Update directory cache for all drives! +CTRL-F4 Change between mounted disk-images. Update directory cache for all drives! +CTRL-ALT-F5 Start/Stop creating a movie of the screen. CTRL-F5 Save a screenshot.(png) CTRL-F6 Start/Stop recording sound output to a wave file. CTRL-ALT-F7 Start/Stop recording of OPL commands. @@ -579,18 +630,19 @@ CTRL-F9 Kill dosbox. CTRL-F10 Capture/Release the mouse. CTRL-F11 Slow down emulation (Decrease DOSBox Cycles). CTRL-F12 Speed up emulation (Increase DOSBox Cycles). +ALT-F12 Unlock speed (turbo button). These are the default keybindings. They can be changed in the keymapper. Saved/recorded files can be found in current_directory/capture (can be changed in the configfile). -The directory has to exist prior to starting DOSBox else nothing +The directory has to exist prior to starting DOSBox, otherwise nothing gets saved/recorded ! NOTE: Once you increase your DOSBox cycles beyond your computer's maximum capacity, it will produce the same effect as slowing down the emulation. -This maximum will vary from computer to computer, there is no standard. +This maximum will vary from computer to computer; there is no standard. @@ -599,12 +651,12 @@ This maximum will vary from computer to computer, there is no standard. ============= When you start the keymapper (either with CTRL-F1 or -startmapper as a -commandline argument to the DOSBox executable) you are presented with +command line argument to the DOSBox executable) you are presented with a virtual keyboard. -This virtual keyboard corresponds with the keys DOSBox will report to its +This virtual keyboard corresponds to the keys DOSBox will report to its applications. If you click on a key with your mouse, you can see in the -lowerleft corner which key on your keyboard corresponds with it. +lower left corner which key on your keyboard corresponds to it. Event: EVENT BIND: BIND @@ -624,35 +676,35 @@ mod1,2,3 BIND. mod1 = CTRL and mod2 = ALT. These are generally only used when you want to change the special keys of DOSBox. Add - Add a new BIND to this EVENT. Basicly add a key from your keyboard which + Add a new BIND to this EVENT. Basically add a key from your keyboard which will produce the key EVENT in DOSBox. Del - Delete the BIND to this EVENT. If an EVENT has no BINDS than it's not + Delete the BIND to this EVENT. If an EVENT has no BINDS, then it's not possible to type this key in DOSBox. Next - Cycle through the list of keys(BINDS) which map to this EVENT. + Go through the list of keys(BINDS) which map to this EVENT. Example: Q1. You want to have the X on your keyboard to type a Z in DOSBox. - A. With your mouse click on the Z on the keyboard mapper. Click "Add". + A. Click on the Z on the keyboard mapper. Click "Add". Now press the X key on your keyboard. -Q2. If you click "Next" a few times you will notice that the Z on your +Q2. If you click "Next" a couple of times, you will notice that the Z on your keyboard also produces an Z in DOSBox. - A. Therefore select the Z again and click "Next" till you have the Z on + A. Therefore select the Z again, and click "Next" until you have the Z on your keyboard. Now click "Del". -Q3. If you try it out in DOSBox you will notice that pressing X makes ZX +Q3. If you try it out in DOSBox, you will notice that pressing X makes ZX appear. A. The X on your keyboard is still mapped to the X as well! Click on - the X in the keyboard mapper and search with "Next" till you find the + the X in the keyboard mapper and search with "Next" until you find the mapped key X. Click "Del". -If you change the default mapping you can save your changes by pressing -"Save". DOSBox will save the mapping to location specified in the configfile -(mapperfile=mapper.txt). At startup DOSBox will load your mapperfile if it's +If you change the default mapping, you can save your changes by pressing +"Save". DOSBox will save the mapping to a location specified in the configfile +(mapperfile=mapper.txt). At startup, DOSBox will load your mapperfile, if it's present in the configfile. @@ -663,8 +715,8 @@ present in the configfile. Fast machine. My guess would be pentium-2 400+ to get decent emulation of games written for an 286 machine. -For protected mode games a 1 Ghz machine is recommended and don't expect -them to run fast though! Be sure to read the next section on how to speed +For protected mode games a 1 Ghz machine is recommended - don't expect +them to run fast, though! Be sure to read the next section on how to speed it up somewhat. @@ -674,7 +726,7 @@ it up somewhat. =================================== DOSBox emulates the CPU, the sound and graphic cards, and some other -stuff, all at the same time. You can overclock DOSBox by using CTRL+F12, but +stuff, all at the same time. You can overclock DOSBox by using CTRL-F12, but you'll be limited by the power of your actual CPU. You can see how much free time your true CPU has by looking at the Task Manager in Windows 2000/XP and the System Monitor in Windows 95/98/ME. Once 100% of your real CPU time is @@ -689,14 +741,14 @@ Overclock DOSBox until 100% of your CPU is used (use the utilities above to check) Since VGA emulation is the most demanding part of DOSBox in terms of actual -CPU usage, we'll start here. Increase the number of frames skipped (in -increments of one) by pressing CRTL+F8. Your CPU usage should decrease. +CPU usage, we'll start there. Increase the number of frames skipped (in +increments of one) by pressing CTRL-F8. Your CPU usage should decrease. Go back one step and repeat this until the game runs fast enough for you. -Please note that this is a trade off: you lose in fluidity of video what you +Please note that this is a trade-off: you lose in fluidity of video what you gain in speed You can also try to disable the sound through the setup utility of the game -to further reduce load on your CPU. +to reduce load on your CPU further. @@ -710,7 +762,7 @@ programs section of the readme for usage of CONFIG.COM. You can edit the generated configfile to customize DOSBox. The file is divided into several sections (the names have [] around it). -Some sections have options which you can set. +Some sections have options you can set. # and % indicate comment-lines. The generated configfile contains the current settings. You can alter them and start DOSBox with the -conf switch to load the file and use these settings. @@ -726,10 +778,10 @@ current directory for dosbox.conf. Then it will look for ~/.dosboxrc (Linux), ====================== A language file can be generated by CONFIG.COM. -Read it and you will hopefully understand how to change it. -Start DOSBox with the -lang switch to use your new language file -or you can setup the filename in the config file in the [dosbox] section. -There's a language= entry that can be changed with the filename. +Read it, and you will hopefully understand how to change it. +Start DOSBox with the -lang switch to use your new language file. +Alternatively, you can setup the filename in the config file in the [dosbox] +section. There's a language= entry that can be changed with the filename. @@ -746,9 +798,9 @@ Check the INSTALL in the source distribution. 12. Special Thanks: =================== -Vlad R. of the vdmsound project for excellent sound blaster info. +Vlad R. of the VDMSound project for excellent SoundBlaster info. Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator. -The Bochs and DOSemu projects which I used for information. +The Bochs and DOSemu projects, which I used for information. Freedos for ideas in making my shell. Pierre-Yves Gérardy for hosting the old Beta Board. Colin Snover for hosting our forum. @@ -762,4 +814,4 @@ The Beta Testers. See the site: http://dosbox.sourceforge.net -for an emailaddress (The Crew-page). +for an email address (The Crew-page). diff --git a/TODO b/TODO new file mode 100644 index 0000000..d86eeac --- /dev/null +++ b/TODO @@ -0,0 +1 @@ +perharps check if console exists before setting name. diff --git a/acinclude.m4 b/acinclude.m4 index 5e72516..7ee0692 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -305,7 +305,7 @@ AC_SUBST(ALSA_LIBS) AH_TOP([ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -331,6 +331,12 @@ AH_BOTTOM([#if C_HAS_ATTRIBUTE #define GCC_ATTRIBUTE(x) /* attribute not supported */ #endif]) +AH_BOTTOM([#if C_HAS_BUILTIN_EXPECT +#define GCC_UNLIKELY(x) __builtin_expect((x),0) +#else +#define GCC_UNLIKELY(x) (x) +#endif]) + AH_BOTTOM([ typedef double Real64; diff --git a/aclocal.m4 b/aclocal.m4 index f50f255..6d88897 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,7 +1,7 @@ -# generated automatically by aclocal 1.9.3 -*- Autoconf -*- +# generated automatically by aclocal 1.9.5 -*- Autoconf -*- -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 -# Free Software Foundation, Inc. +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -11,23 +11,11 @@ # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. -# -*- Autoconf -*- -# Copyright (C) 2002, 2003 Free Software Foundation, Inc. -# Generated from amversion.in; do not edit by hand. - -# 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 +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- @@ -40,26 +28,15 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) # Call AM_AUTOMAKE_VERSION so it can be traced. # This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], - [AM_AUTOMAKE_VERSION([1.9.3])]) + [AM_AUTOMAKE_VERSION([1.9.5])]) -# AM_AUX_DIR_EXPAND +# AM_AUX_DIR_EXPAND -*- Autoconf -*- -# Copyright (C) 2001, 2003 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. +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to @@ -106,26 +83,16 @@ AC_PREREQ([2.50])dnl am_aux_dir=`cd $ac_aux_dir && pwd` ]) -# AM_CONDITIONAL -*- Autoconf -*- +# AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. - -# serial 6 +# serial 7 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- @@ -149,26 +116,15 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# serial 7 -*- Autoconf -*- -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. - +# serial 8 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, @@ -177,7 +133,6 @@ fi])]) # CC etc. in the Makefile, will ask for an AC_PROG_CC use... - # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. @@ -317,27 +272,16 @@ AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH]) ]) -# Generate code to set up dependency tracking. -*- Autoconf -*- +# Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 -# Free Software Foundation, Inc. +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. - -#serial 2 +#serial 3 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ @@ -396,54 +340,31 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) -# Like AC_CONFIG_HEADER, but automatically create stamp file. -*- Autoconf -*- +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# Copyright (C) 1996, 1997, 2000, 2001, 2003 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. - -# serial 7 +# serial 8 # AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) -# Do all the work for Automake. -*- Autoconf -*- +# Do all the work for Automake. -*- Autoconf -*- -# This macro actually does too much some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. +# serial 12 -# 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. - -# serial 11 +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) @@ -545,51 +466,27 @@ for _am_header in $config_headers :; do done echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. - -# Copyright (C) 2001, 2003 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. - AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl install_sh=${install_sh-"$am_aux_dir/install-sh"} AC_SUBST(install_sh)]) -# -*- Autoconf -*- -# Copyright (C) 2003 Free Software Foundation, Inc. +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. - -# serial 1 +# serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. @@ -604,26 +501,15 @@ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) -# Check to see how 'make' treats includes. -*- Autoconf -*- +# Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. - -# serial 2 +# serial 3 # AM_MAKE_INCLUDE() # ----------------- @@ -667,27 +553,16 @@ AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) -# -*- Autoconf -*- +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# Copyright (C) 1997, 1999, 2000, 2001, 2003 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. - -# serial 3 +# serial 4 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ @@ -713,27 +588,16 @@ else fi ]) +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + # AM_PROG_MKDIR_P # --------------- # Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. - -# Copyright (C) 2003, 2004 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. - +# # Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories # created by `make install' are always world readable, even if the # installer happens to have an overly restrictive umask (e.g. 077). @@ -787,26 +651,15 @@ else fi AC_SUBST([mkdir_p])]) -# Helper functions for option handling. -*- Autoconf -*- +# Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# This program is 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. - -# serial 2 +# serial 3 # _AM_MANGLE_OPTION(NAME) # ----------------------- @@ -831,28 +684,16 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. # -# Check to make sure that the build environment is sane. -# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. -# Copyright (C) 1996, 1997, 2000, 2001, 2003 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. - -# serial 3 +# serial 4 # AM_SANITY_CHECK # --------------- @@ -895,25 +736,14 @@ Check your system clock]) fi AC_MSG_RESULT(yes)]) +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + # AM_PROG_INSTALL_STRIP - -# Copyright (C) 2001, 2003 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. - +# --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip @@ -936,25 +766,13 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004 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. - -# serial 1 +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. +# serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- diff --git a/config.h.in b/config.h.in index 6e90905..1b92b29 100644 --- a/config.h.in +++ b/config.h.in @@ -2,7 +2,7 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -26,7 +26,8 @@ /* Define to 1 to enable internal debugger, requires libcurses */ #undef C_DEBUG -/* Define to 1 if you want serial passthrough support (Win32 only). */ +/* Define to 1 if you want serial passthrough support (Win32 and OS/2 only). + */ #undef C_DIRECTSERIAL /* Define to 1 to use x86 dynamic cpu core */ @@ -35,9 +36,19 @@ /* Define to 1 to enable floating point emulation */ #undef C_FPU +/* Define to 1 to use a x86 assembly fpu core */ +#undef C_FPU_X86 + /* Determines if the compilers supports attributes for structures. */ #undef C_HAS_ATTRIBUTE +/* Determines if the compilers supports __builtin_expect for branch + prediction. */ +#undef C_HAS_BUILTIN_EXPECT + +/* Define to 1 if you have the mprotect function */ +#undef C_HAVE_MPROTECT + /* Define to 1 to enable heavy debugging, also have to enable C_DEBUG */ #undef C_HEAVY_DEBUG @@ -62,6 +73,9 @@ /* Define to 1 to enable screenshots, requires libpng */ #undef C_SSHOT +/* Define to 1 to use a unaligned memory access */ +#undef C_UNALIGNED_MEMORY + /* environ can be included */ #undef ENVIRON_INCLUDED @@ -110,6 +124,9 @@ /* Compiling on Mac OS X */ #undef MACOSX +/* Compiling on OS/2 EMX */ +#undef OS2 + /* Name of package */ #undef PACKAGE @@ -179,6 +196,12 @@ #define GCC_ATTRIBUTE(x) /* attribute not supported */ #endif +#if C_HAS_BUILTIN_EXPECT +#define GCC_UNLIKELY(x) __builtin_expect((x),0) +#else +#define GCC_UNLIKELY(x) (x) +#endif + typedef double Real64; diff --git a/configure b/configure index 91b983a..416d8ff 100644 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.59 for dosbox 0.63. +# Generated by GNU Autoconf 2.59 for dosbox 0.65. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation @@ -267,8 +267,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='dosbox' PACKAGE_TARNAME='dosbox' -PACKAGE_VERSION='0.63' -PACKAGE_STRING='dosbox 0.63' +PACKAGE_VERSION='0.65' +PACKAGE_STRING='dosbox 0.65' PACKAGE_BUGREPORT='' ac_unique_file="README" @@ -309,7 +309,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE RANLIB ac_ct_RANLIB SDL_CONFIG SDL_CFLAGS SDL_LIBS EGREP ALSA_CFLAGS ALSA_LIBS LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA CYGPATH_W PACKAGE VERSION ACLOCAL AUTOCONF AUTOMAKE AUTOHEADER MAKEINFO install_sh STRIP ac_ct_STRIP INSTALL_STRIP_PROGRAM mkdir_p AWK SET_MAKE am__leading_dot AMTAR am__tar am__untar CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT DEPDIR am__include am__quote AMDEP_TRUE AMDEP_FALSE AMDEPBACKSLASH CCDEPMODE am__fastdepCC_TRUE am__fastdepCC_FALSE CPP CXX CXXFLAGS ac_ct_CXX CXXDEPMODE am__fastdepCXX_TRUE am__fastdepCXX_FALSE RANLIB ac_ct_RANLIB SDL_CONFIG SDL_CFLAGS SDL_LIBS EGREP ALSA_CFLAGS ALSA_LIBS WINDRES ac_ct_WINDRES HAVE_WINDRES_TRUE HAVE_WINDRES_FALSE LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -786,7 +786,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures dosbox 0.63 to adapt to many kinds of systems. +\`configure' configures dosbox 0.65 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -853,7 +853,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of dosbox 0.63:";; + short | recursive ) echo "Configuration of dosbox 0.65:";; esac cat <<\_ACEOF @@ -868,6 +868,9 @@ Optional Features: --enable-core-inline Enable inlined memory handling in CPU Core --disable-dynamic-x86 Disable x86 dynamic cpu core --disable-fpu Disable fpu support + --disable-fpu-x86 Disable x86 assembly fpu core + --disable-unaligned-memory + Disable unaligned memory access --disable-opengl Disable opengl support Optional Packages: @@ -987,7 +990,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -dosbox configure 0.63 +dosbox configure 0.65 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -1001,7 +1004,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by dosbox $as_me 0.63, which was +It was created by dosbox $as_me 0.65, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -1730,7 +1733,7 @@ fi # Define the identity of the package. PACKAGE='dosbox' - VERSION='0.63' + VERSION='0.65' cat >>confdefs.h <<_ACEOF @@ -3844,6 +3847,12 @@ else fi +if test x$target = xi386-pc-os2-emx ; then + CXXFLAGS="$CXXFLAGS -Zmt" + LDFLAGS="$LDFLAGS -Zomf -Zmt" + LIBS="$LIBS -los2me" +fi + SDL_VERSION=1.2.0 @@ -7292,6 +7301,67 @@ echo "${ECHO_T}no" >&6 fi rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +#Check if the compiler supports __builtin_expect + + +echo "$as_me:$LINENO: checking if compiler allows __builtin_expect" >&5 +echo $ECHO_N "checking if compiler allows __builtin_expect... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + +int main(int argc,char* argv[]){ +int x=10;if( __builtin_expect ((x==1),0) ) ; +return 0; +} + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6;cat >>confdefs.h <<\_ACEOF +#define C_HAS_BUILTIN_EXPECT 1 +_ACEOF + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext + + alsa_save_CFLAGS="$CFLAGS" alsa_save_LDFLAGS="$LDFLAGS" alsa_save_LIBS="$LIBS" @@ -7558,7 +7628,7 @@ fi -#Check for big endian machine, should #define WORD_BIGENDIAN if so +#Check for big endian machine, should #define WORDS_BIGENDIAN if so echo "$as_me:$LINENO: checking whether byte ordering is bigendian" >&5 echo $ECHO_N "checking whether byte ordering is bigendian... $ECHO_C" >&6 if test "${ac_cv_c_bigendian+set}" = set; then @@ -8072,7 +8142,10 @@ if test $ac_cv_lib_pdcurses_initscr = yes; then fi - if test x$have_curses_lib = xyes -a x$have_curses_h = xyes ; then + if test x$enable_debug = xno; then + echo "$as_me:$LINENO: result: Debugger not enabled" >&5 +echo "${ECHO_T}Debugger not enabled" >&6 + elif test x$have_curses_lib = xyes -a x$have_curses_h = xyes ; then LIBS="$LIBS -lcurses" cat >>confdefs.h <<\_ACEOF #define C_DEBUG 1 @@ -8126,7 +8199,7 @@ fi; echo "$as_me:$LINENO: checking for target cpu type" >&5 echo $ECHO_N "checking for target cpu type... $ECHO_C" >&6 case "$target_cpu" in - i386|i486|i586|i686) + i?86) cat >>confdefs.h <<\_ACEOF #define C_HOSTCPU X86 _ACEOF @@ -8134,18 +8207,41 @@ _ACEOF echo "$as_me:$LINENO: result: x86 compatible" >&5 echo "${ECHO_T}x86 compatible" >&6 c_hostcpu="x86" + c_unalignedmemory=yes ;; - *) + powerpc*) + cat >>confdefs.h <<\_ACEOF +#define C_HOSTCPU POWERPC +_ACEOF + + echo "$as_me:$LINENO: result: Power PC" >&5 +echo "${ECHO_T}Power PC" >&6 + c_hostcpu="powerpc" + c_unalignedmemory=yes + ;; + m68k*) + cat >>confdefs.h <<\_ACEOF +#define C_HOSTCPU M68K +_ACEOF + + echo "$as_me:$LINENO: result: Motorola 68000" >&5 +echo "${ECHO_T}Motorola 68000" >&6 + c_hostcpu="m68k" + c_unalignedmemory=yes + ;; + *) cat >>confdefs.h <<\_ACEOF #define C_HOSTCPU UNKOWN _ACEOF echo "$as_me:$LINENO: result: unknown" >&5 echo "${ECHO_T}unknown" >&6 + c_unalignedmemory=no ;; esac + # Check whether --enable-dynamic-x86 or --disable-dynamic-x86 was given. if test "${enable_dynamic_x86+set}" = set; then enableval="$enable_dynamic_x86" @@ -8174,8 +8270,6 @@ fi - - # Check whether --enable-fpu or --disable-fpu was given. if test "${enable_fpu+set}" = set; then enableval="$enable_fpu" @@ -8199,6 +8293,62 @@ fi +# Check whether --enable-fpu-x86 or --disable-fpu-x86 was given. +if test "${enable_fpu_x86+set}" = set; then + enableval="$enable_fpu_x86" + +else + enable_fpu_x86=yes +fi; +echo "$as_me:$LINENO: checking whether x86 assembly fpu core will be enabled" >&5 +echo $ECHO_N "checking whether x86 assembly fpu core will be enabled... $ECHO_C" >&6 +if test x$enable_fpu_x86 = xno ; then + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +else + if test x$enable_fpu = xyes; then + if test x$c_hostcpu = xx86 ; then + cat >>confdefs.h <<\_ACEOF +#define C_FPU_X86 1 +_ACEOF + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + fi + else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 + fi +fi + + + +# Check whether --enable-unaligned_memory or --disable-unaligned_memory was given. +if test "${enable_unaligned_memory+set}" = set; then + enableval="$enable_unaligned_memory" + +else + enable_unaligned_memory=yes +fi; +echo "$as_me:$LINENO: checking whether to enable unaligned memory access" >&5 +echo $ECHO_N "checking whether to enable unaligned memory access... $ECHO_C" >&6 +if test x$enable_unaligned_memory = xyes -a x$c_unalignedmemory = xyes; then + cat >>confdefs.h <<\_ACEOF +#define C_UNALIGNED_MEMORY 1 +_ACEOF + + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + + if test "${ac_cv_header_png_h+set}" = set; then echo "$as_me:$LINENO: checking for png.h" >&5 echo $ECHO_N "checking for png.h... $ECHO_C" >&6 @@ -8563,6 +8713,54 @@ if test $ac_cv_header_SDL_net_h = yes; then fi + +if test x$target = xi386-pc-os2-emx ; then + echo "$as_me:$LINENO: checking for SDLNet_Init in SDL_net" >&5 +echo $ECHO_N "checking for SDLNet_Init in SDL_net... $ECHO_C" >&6; + LIBS_BACKUP=$LIBS; + LIBS="$LIBS -lSDL_Net"; + cat >conftest.$ac_ext <<_ACEOF + + #include + int main(int argc,char * argv) { + return SDLNet_Init (); + }; + +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; have_sdl_net_lib=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LIBS=$LIBS_BACKUP +else echo "$as_me:$LINENO: checking for SDLNet_Init in -lSDL_net" >&5 echo $ECHO_N "checking for SDLNet_Init in -lSDL_net... $ECHO_C" >&6 if test "${ac_cv_lib_SDL_net_SDLNet_Init+set}" = set; then @@ -8630,6 +8828,7 @@ if test $ac_cv_lib_SDL_net_SDLNet_Init = yes; then have_sdl_net_lib=yes fi +fi if test x$have_sdl_net_lib = xyes -a x$have_sdl_net_h = xyes ; then LIBS="$LIBS -lSDL_net" cat >>confdefs.h <<\_ACEOF @@ -9241,6 +9440,247 @@ fi +if test "${ac_cv_header_sys_mman_h+set}" = set; then + echo "$as_me:$LINENO: checking for sys/mman.h" >&5 +echo $ECHO_N "checking for sys/mman.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_mman_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_mman_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_mman_h" >&6 +else + # Is the header compilable? +echo "$as_me:$LINENO: checking sys/mman.h usability" >&5 +echo $ECHO_N "checking sys/mman.h usability... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_header_compiler=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6 + +# Is the header present? +echo "$as_me:$LINENO: checking sys/mman.h presence" >&5 +echo $ECHO_N "checking sys/mman.h presence... $ECHO_C" >&6 +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 + (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6 + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: sys/mman.h: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: sys/mman.h: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: sys/mman.h: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: sys/mman.h: present but cannot be compiled" >&5 +echo "$as_me: WARNING: sys/mman.h: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: sys/mman.h: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: sys/mman.h: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: sys/mman.h: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: sys/mman.h: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: sys/mman.h: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: sys/mman.h: in the future, the compiler will take precedence" >&2;} + ( + cat <<\_ASBOX +## --------------------------------- ## +## Report this to the dosbox lists. ## +## --------------------------------- ## +_ASBOX + ) | + sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +echo "$as_me:$LINENO: checking for sys/mman.h" >&5 +echo $ECHO_N "checking for sys/mman.h... $ECHO_C" >&6 +if test "${ac_cv_header_sys_mman_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_header_sys_mman_h=$ac_header_preproc +fi +echo "$as_me:$LINENO: result: $ac_cv_header_sys_mman_h" >&5 +echo "${ECHO_T}$ac_cv_header_sys_mman_h" >&6 + +fi +if test $ac_cv_header_sys_mman_h = yes; then + +echo "$as_me:$LINENO: checking for mprotect" >&5 +echo $ECHO_N "checking for mprotect... $ECHO_C" >&6 +if test "${ac_cv_func_mprotect+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define mprotect to an innocuous variant, in case declares mprotect. + For example, HP-UX 11i declares gettimeofday. */ +#define mprotect innocuous_mprotect + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char mprotect (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef mprotect + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char mprotect (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_mprotect) || defined (__stub___mprotect) +choke me +#else +char (*f) () = mprotect; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != mprotect; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_func_mprotect=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_func_mprotect=no +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_func_mprotect" >&5 +echo "${ECHO_T}$ac_cv_func_mprotect" >&6 +if test $ac_cv_func_mprotect = yes; then + cat >>confdefs.h <<\_ACEOF +#define C_HAVE_MPROTECT 1 +_ACEOF + +fi + + +fi + + + + + echo "$as_me:$LINENO: checking for setpriority support" >&5 echo $ECHO_N "checking for setpriority support... $ECHO_C" >&6 cat >conftest.$ac_ext <<_ACEOF @@ -9461,10 +9901,121 @@ cat >>confdefs.h <<\_ACEOF _ACEOF ;; + *-*-os2-emx*) + +cat >>confdefs.h <<\_ACEOF +#define OS2 1 +_ACEOF + + +cat >>confdefs.h <<\_ACEOF +#define C_DIRECTSERIAL 1 +_ACEOF + + ;; +esac + +case "$target" in + *-*-cygwin* | *-*-mingw32*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. +set dummy ${ac_tool_prefix}windres; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_WINDRES+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$WINDRES"; then + ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_WINDRES="${ac_tool_prefix}windres" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +WINDRES=$ac_cv_prog_WINDRES +if test -n "$WINDRES"; then + echo "$as_me:$LINENO: result: $WINDRES" >&5 +echo "${ECHO_T}$WINDRES" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + +fi +if test -z "$ac_cv_prog_WINDRES"; then + ac_ct_WINDRES=$WINDRES + # Extract the first word of "windres", so it can be a program name with args. +set dummy windres; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_WINDRES+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_WINDRES"; then + ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_WINDRES="windres" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + + test -z "$ac_cv_prog_ac_ct_WINDRES" && ac_cv_prog_ac_ct_WINDRES=":" +fi +fi +ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES +if test -n "$ac_ct_WINDRES"; then + echo "$as_me:$LINENO: result: $ac_ct_WINDRES" >&5 +echo "${ECHO_T}$ac_ct_WINDRES" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + WINDRES=$ac_ct_WINDRES +else + WINDRES="$ac_cv_prog_WINDRES" +fi + + ;; + *) + WINDRES=":" + ;; esac - ac_config_files="$ac_config_files Makefile src/Makefile src/cpu/Makefile src/cpu/core_full/Makefile src/cpu/core_normal/Makefile src/cpu/core_dyn_x86/Makefile src/debug/Makefile src/dos/Makefile src/fpu/Makefile src/gui/Makefile src/hardware/Makefile src/ints/Makefile src/misc/Makefile src/shell/Makefile src/platform/Makefile src/platform/visualc/Makefile visualc/Makefile visualc_net/Makefile include/Makefile docs/Makefile" +if test "x$WINDRES" != "x:"; then + HAVE_WINDRES_TRUE= + HAVE_WINDRES_FALSE='#' +else + HAVE_WINDRES_TRUE='#' + HAVE_WINDRES_FALSE= +fi + + + + + ac_config_files="$ac_config_files Makefile src/Makefile src/cpu/Makefile src/cpu/core_full/Makefile src/cpu/core_normal/Makefile src/cpu/core_dyn_x86/Makefile src/debug/Makefile src/dos/Makefile src/fpu/Makefile src/gui/Makefile src/hardware/Makefile src/hardware/serialport/Makefile src/ints/Makefile src/libs/Makefile src/libs/zmbv/Makefile src/misc/Makefile src/shell/Makefile src/platform/Makefile src/platform/visualc/Makefile visualc/Makefile visualc_net/Makefile include/Makefile docs/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure @@ -9577,6 +10128,13 @@ echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. Usually this means the macro was only invoked conditionally." >&2;} { (exit 1); exit 1; }; } fi +if test -z "${HAVE_WINDRES_TRUE}" && test -z "${HAVE_WINDRES_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"HAVE_WINDRES\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"HAVE_WINDRES\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi : ${CONFIG_STATUS=./config.status} ac_clean_files_save=$ac_clean_files @@ -9848,7 +10406,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by dosbox $as_me 0.63, which was +This file was extended by dosbox $as_me 0.65, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9911,7 +10469,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -dosbox config.status 0.63 +dosbox config.status 0.65 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" @@ -10032,7 +10590,10 @@ do "src/fpu/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/fpu/Makefile" ;; "src/gui/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/gui/Makefile" ;; "src/hardware/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/hardware/Makefile" ;; + "src/hardware/serialport/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/hardware/serialport/Makefile" ;; "src/ints/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/ints/Makefile" ;; + "src/libs/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/libs/Makefile" ;; + "src/libs/zmbv/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/libs/zmbv/Makefile" ;; "src/misc/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/misc/Makefile" ;; "src/shell/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/shell/Makefile" ;; "src/platform/Makefile" ) CONFIG_FILES="$CONFIG_FILES src/platform/Makefile" ;; @@ -10193,6 +10754,10 @@ s,@SDL_LIBS@,$SDL_LIBS,;t t s,@EGREP@,$EGREP,;t t s,@ALSA_CFLAGS@,$ALSA_CFLAGS,;t t s,@ALSA_LIBS@,$ALSA_LIBS,;t t +s,@WINDRES@,$WINDRES,;t t +s,@ac_ct_WINDRES@,$ac_ct_WINDRES,;t t +s,@HAVE_WINDRES_TRUE@,$HAVE_WINDRES_TRUE,;t t +s,@HAVE_WINDRES_FALSE@,$HAVE_WINDRES_FALSE,;t t s,@LIBOBJS@,$LIBOBJS,;t t s,@LTLIBOBJS@,$LTLIBOBJS,;t t CEOF diff --git a/configure.in b/configure.in index 5343692..00cc1f8 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ dnl Init. -AC_INIT(dosbox,0.63) +AC_INIT(dosbox,0.65) AC_PREREQ(2.50) AC_CONFIG_SRCDIR(README) @@ -19,6 +19,14 @@ AC_PROG_CXX AC_PROG_INSTALL AC_PROG_RANLIB +dnl Some needed libaries for OS2 +dnl perharps join this with the other host depended checks. move them upwards +if test x$target = xi386-pc-os2-emx ; then + CXXFLAGS="$CXXFLAGS -Zmt" + LDFLAGS="$LDFLAGS -Zomf -Zmt" + LIBS="$LIBS -los2me" +fi + dnl Check for SDL SDL_VERSION=1.2.0 AM_PATH_SDL($SDL_VERSION, @@ -58,9 +66,20 @@ AC_MSG_CHECKING(if compiler allows __attribute__) AC_TRY_COMPILE([], [typedef struct { } __attribute__ ((packed)) junk;], [ AC_MSG_RESULT(yes);AC_DEFINE(C_HAS_ATTRIBUTE)],AC_MSG_RESULT(no)) +#Check if the compiler supports __builtin_expect +AH_TEMPLATE([C_HAS_BUILTIN_EXPECT],[Determines if the compilers supports __builtin_expect for branch prediction.]) +AC_MSG_CHECKING(if compiler allows __builtin_expect) +AC_TRY_COMPILE([],[ +int main(int argc,char* argv[]){ +int x=10;if( __builtin_expect ((x==1),0) ) ; +return 0; +} +], [ AC_MSG_RESULT(yes);AC_DEFINE(C_HAS_BUILTIN_EXPECT)],AC_MSG_RESULT(no)) + + AM_PATH_ALSA(0.9.0, AC_DEFINE(HAVE_ALSA,1,[Define to 1 to use ALSA for MIDI]) , : ) -#Check for big endian machine, should #define WORD_BIGENDIAN if so +#Check for big endian machine, should #define WORDS_BIGENDIAN if so AC_C_BIGENDIAN #Features to enable/disable @@ -71,7 +90,9 @@ AC_ARG_ENABLE(debug,AC_HELP_STRING([--enable-debug],[Enable debug mode]),[ AC_CHECK_LIB(curses, initscr, have_curses_lib=yes, , ) AC_CHECK_LIB(pdcurses, initscr, have_pdcurses_lib=yes, , ) - if test x$have_curses_lib = xyes -a x$have_curses_h = xyes ; then + if test x$enable_debug = xno; then + AC_MSG_RESULT([Debugger not enabled]) + elif test x$have_curses_lib = xyes -a x$have_curses_h = xyes ; then LIBS="$LIBS -lcurses" AC_DEFINE(C_DEBUG,1) if test x$enable_debug = xheavy ; then @@ -101,16 +122,31 @@ dnl The target cpu checks for dynamic cores AH_TEMPLATE(C_HOSTCPU,[The type of cpu this host has]) AC_MSG_CHECKING(for target cpu type) case "$target_cpu" in - i386|i486|i586|i686) + i?86) AC_DEFINE(C_HOSTCPU,X86) AC_MSG_RESULT(x86 compatible) c_hostcpu="x86" + c_unalignedmemory=yes ;; - *) + powerpc*) + AC_DEFINE(C_HOSTCPU,POWERPC) + AC_MSG_RESULT(Power PC) + c_hostcpu="powerpc" + c_unalignedmemory=yes + ;; + m68k*) + AC_DEFINE(C_HOSTCPU,M68K) + AC_MSG_RESULT(Motorola 68000) + c_hostcpu="m68k" + c_unalignedmemory=yes + ;; + *) AC_DEFINE(C_HOSTCPU,UNKOWN) AC_MSG_RESULT(unknown) + c_unalignedmemory=no ;; esac + AH_TEMPLATE(C_DYNAMIC_X86,[Define to 1 to use x86 dynamic cpu core]) AC_ARG_ENABLE(dynamic-x86,AC_HELP_STRING([--disable-dynamic-x86],[Disable x86 dynamic cpu core]),,enable_dynamic_x86=yes) AC_MSG_CHECKING(whether x86 dynamic cpu core will be enabled) @@ -125,8 +161,6 @@ else fi fi - - AH_TEMPLATE(C_FPU,[Define to 1 to enable floating point emulation]) AC_ARG_ENABLE(fpu,AC_HELP_STRING([--disable-fpu],[Disable fpu support]),,enable_fpu=yes) AC_MSG_CHECKING(whether fpu emulation will be enabled) @@ -137,6 +171,34 @@ else AC_MSG_RESULT(no) fi +AH_TEMPLATE(C_FPU_X86,[Define to 1 to use a x86 assembly fpu core]) +AC_ARG_ENABLE(fpu-x86,AC_HELP_STRING([--disable-fpu-x86],[Disable x86 assembly fpu core]),,enable_fpu_x86=yes) +AC_MSG_CHECKING(whether x86 assembly fpu core will be enabled) +if test x$enable_fpu_x86 = xno ; then + AC_MSG_RESULT(no) +else + if test x$enable_fpu = xyes; then + if test x$c_hostcpu = xx86 ; then + AC_DEFINE(C_FPU_X86,1) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + else + AC_MSG_RESULT(no) + fi +fi + +AH_TEMPLATE(C_UNALIGNED_MEMORY,[Define to 1 to use a unaligned memory access]) +AC_ARG_ENABLE(unaligned_memory,AC_HELP_STRING([--disable-unaligned-memory],[Disable unaligned memory access]),,enable_unaligned_memory=yes) +AC_MSG_CHECKING(whether to enable unaligned memory access) +if test x$enable_unaligned_memory = xyes -a x$c_unalignedmemory = xyes; then + AC_DEFINE(C_UNALIGNED_MEMORY,1) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + AH_TEMPLATE(C_SSHOT,[Define to 1 to enable screenshots, requires libpng]) AC_CHECK_HEADER(png.h,have_png_h=yes,) AC_CHECK_LIB(png, png_check_sig, have_png_lib=yes, ,-lz) @@ -150,7 +212,21 @@ fi AH_TEMPLATE(C_MODEM,[Define to 1 to enable internal modem support, requires SDL_net]) AH_TEMPLATE(C_IPX,[Define to 1 to enable IPX over Internet networking, requires SDL_net]) AC_CHECK_HEADER(SDL_net.h,have_sdl_net_h=yes,) + +if test x$target = xi386-pc-os2-emx ; then + AC_MSG_CHECKING(for SDLNet_Init in SDL_net); + LIBS_BACKUP=$LIBS; + LIBS="$LIBS -lSDL_Net"; + AC_LINK_IFELSE([ + #include + int main(int argc,char * argv[]) { + return SDLNet_Init (); + }; + ], [AC_MSG_RESULT(yes); have_sdl_net_lib=yes], AC_MSG_RESULT(no)) + LIBS=$LIBS_BACKUP +else AC_CHECK_LIB(SDL_net, SDLNet_Init, have_sdl_net_lib=yes, , ) +fi if test x$have_sdl_net_lib = xyes -a x$have_sdl_net_h = xyes ; then LIBS="$LIBS -lSDL_net" AC_DEFINE(C_MODEM,1) @@ -192,6 +268,13 @@ else AC_MSG_WARN([Can't find libSDL_sound, libSDL_sound support disabled]) fi +dnl Check for mprotect. Needed for 64 bits linux +AH_TEMPLATE(C_HAVE_MPROTECT,[Define to 1 if you have the mprotect function]) +AC_CHECK_HEADER([sys/mman.h], [ +AC_CHECK_FUNC([mprotect],[AC_DEFINE(C_HAVE_MPROTECT,1)]) +]) + +dnl Setpriority AH_TEMPLATE(C_SET_PRIORITY,[Define to 1 if you have setpriority support]) AC_MSG_CHECKING(for setpriority support) AC_LINK_IFELSE([ @@ -207,7 +290,7 @@ case "$target" in *-*-cygwin* | *-*-mingw32*) LIBS="$LIBS -lwinmm" AC_CHECK_HEADERS(ddraw.h) - AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32 only).]) + AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32 and OS/2 only).]) ;; *-*-darwin*) dnl We have a problem here: both MacOS X and Darwin report @@ -220,8 +303,25 @@ case "$target" in *-*-linux-gnu*) AC_DEFINE(LINUX, 1, [Compiling on GNU/Linux]) ;; + *-*-os2-emx*) + AC_DEFINE(OS2, 1, [Compiling on OS/2 EMX]) + AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32 and OS/2 only).]) + ;; esac +dnl Some stuff for the icon. +case "$target" in + *-*-cygwin* | *-*-mingw32*) + dnl Some stuff for the ico + AC_CHECK_TOOL(WINDRES, windres, :) + ;; + *) + WINDRES=":" + ;; +esac + AM_CONDITIONAL(HAVE_WINDRES, test "x$WINDRES" != "x:") + AC_SUBST(WINDRES) + AC_OUTPUT([ Makefile @@ -235,7 +335,10 @@ src/dos/Makefile src/fpu/Makefile src/gui/Makefile src/hardware/Makefile +src/hardware/serialport/Makefile src/ints/Makefile +src/libs/Makefile +src/libs/zmbv/Makefile src/misc/Makefile src/shell/Makefile src/platform/Makefile diff --git a/docs/Makefile.am b/docs/Makefile.am index 1773854..7e31317 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -1,7 +1,7 @@ # Main Makefile for DOSBox -man_MANS = dosbox.1 -EXTRA_DIST = $(man_MANS) +man_MANS = dosbox.1 +EXTRA_DIST = $(man_MANS) README.video diff --git a/docs/Makefile.in b/docs/Makefile.in index 05ac5e2..039924c 100644 --- a/docs/Makefile.in +++ b/docs/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -81,6 +81,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -106,10 +108,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -151,8 +155,8 @@ target_alias = @target_alias@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ -man_MANS = dosbox.1 -EXTRA_DIST = $(man_MANS) +man_MANS = dosbox.1 +EXTRA_DIST = $(man_MANS) README.video all: all-am .SUFFIXES: diff --git a/docs/README.video b/docs/README.video new file mode 100644 index 0000000..a79f802 --- /dev/null +++ b/docs/README.video @@ -0,0 +1,32 @@ +Starting with version 0.65, DOSBox allows you to create movies out of screen +output. + +To record a movie, you have to press CTRL-ALT-F5. +To stop/end the recording, you have to press CTRL-ALT-F5 again. + +To play the recorded movie, you need a movie player which can handle the +ZMBV codec. MS Windows users can find this codec in the start menu entry of +DOSBox. Users of Linux and other OSes should look for a movie player that +uses the ffmpeg libary (you may need to update or ask your distribution to +upgrade). + +FAQ: +Q: During the display of the movies the sound is lagging. +A: Check your display properties to see whether your refresh rate is set to +at least 70 hz. Try playing the movie in virtualdub (http://virtualdub.sf.net) + +Q: Why does the resulting movie consist of multiple files? +A: Each time the game changes resolution, DOSBox creates a new movie file, +because a movie file can only contain one resolution. + +Q: Can I set the cycles higher than my PC can handle during recording? +A: Yes. During recording, the game might play slowly and stuttering, but the +resulting movie should play at the intended speed and have no stuttering. + +Q: CTRL-ALT-F5 switches to the console under linux. +A: 1. Start DOSBox like this: dosbox -startmapper + 2. Click on Video, click on Add + 3. Press the key you want (for example scroll lock or printscreen) + 4. Click exit. + 5. You can make movies by pressing scroll lock or whichever key you + selected. diff --git a/docs/dosbox.1 b/docs/dosbox.1 index 7ffa802..f5c3065 100644 --- a/docs/dosbox.1 +++ b/docs/dosbox.1 @@ -1,5 +1,5 @@ .\" Hey, EMACS: -*- nroff -*- -.TH DOSBOX 1 "Nov 18, 2004" +.TH DOSBOX 1 "Mar 28, 2006" .\" Please adjust this date whenever revising the manpage. .SH NAME dosbox \- an x86/DOS emulator with sound/graphics @@ -7,6 +7,7 @@ dosbox \- an x86/DOS emulator with sound/graphics .B dosbox .B [\-fullscreen] .B [\-startmapper] +.B [\-noautoexec] .BI "[\-conf " configfile ] .BI "[\-lang " langfile ] .B [file] @@ -35,6 +36,9 @@ A summary of options is included below. .B \-startmapper .RB "Start the internal keymapper on startup of " dosbox ". You can use it to change the keys " dosbox " uses." .TP +.B \-noautoexec +Skips the [autoexec] section of the loaded configuration file. +.TP .BI \-c " command" .RI "Runs the specified " command " before running " .BR file . @@ -56,7 +60,7 @@ wish to execute on startup. .TP .BI \-machine " machinetype .RB "Setup " dosbox " to emulate a specific type of machine." -.RI "Valid choices are: " "hercules, cga, tandy, vga(default)". +.RI "Valid choices are: " "hercules, cga, pcjr, tandy, vga(default)". The machinetype has influence on both the videocard and the available soundcards. .TP @@ -214,8 +218,12 @@ automatically loaded, else ~/.dosboxrc (if present) will be loaded. .TP 12m .IP ALT\-ENTER Go full screen and back. +.IP ALT\-PAUSE +Pause emulation. .IP CTRL\-F1 Start the keymapper. +.IP CTRL\-ALT\-F5 +Start/Stop creating a movie of the screen. .IP CTRL\-F4 Swap mounted disk-image (Only used with imgmount). Update directory cache for all drives! @@ -239,6 +247,8 @@ Capture/Release the mouse. Slow down emulation (Increase dosbox Cycles). .IP CTRL\-F12 Speed up emulation (Decrease dosbox Cycles). +.IP ALT\-F12 +Unlock speed (turbo button). .PP These are the default keybindings. They can be changed in the keymapper. .PP @@ -268,11 +278,11 @@ So: .PP .RB "Close every program but " dosbox . .PP -.RB "Overclock " dosbox " until 100% of your CPU is used.(CTR\-+F12)" +.RB "Overclock " dosbox " until 100% of your CPU is used.(CTRL\-F12)" .PP .RB "Since VGA emulation is the most demanding part of " dosbox " in terms of actual" CPU usage, we'll start here. Increase the number of frames skipped (in -increments of one) by pressing CRTL\-F8. Your CPU usage should decrease. +increments of one) by pressing CTRL\-F8. Your CPU usage should decrease. Go back one step and repeat this until the game runs fast enough for you. Please note that this is a trade off: you lose in fluidity of video what you gain in speed. diff --git a/include/Makefile.in b/include/Makefile.in index c8f595d..e3dbcde 100644 --- a/include/Makefile.in +++ b/include/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -80,6 +80,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -105,10 +107,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/include/bios.h b/include/bios.h index e80bc06..d222ef2 100644 --- a/include/bios.h +++ b/include/bios.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _BIOS_H_ -#define _BIOS_H_ +#ifndef DOSBOX_BIOS_H +#define DOSBOX_BIOS_H #define BIOS_BASE_ADDRESS_COM1 0x400 #define BIOS_BASE_ADDRESS_COM2 0x402 @@ -30,6 +30,7 @@ #define BIOS_CONFIGURATION 0x410 /* 0x412 is reserved */ #define BIOS_MEMORY_SIZE 0x413 +#define BIOS_TRUE_MEMORY_SIZE 0x415 /* #define bios_expansion_memory_size (*(unsigned int *) 0x415) */ #define BIOS_KEYBOARD_STATE 0x417 #define BIOS_KEYBOARD_FLAGS1 BIOS_KEYBOARD_STATE @@ -72,7 +73,9 @@ /* 0x47b is reserved */ #define BIOS_COM1_TIMEOUT 0x47c #define BIOS_COM2_TIMEOUT 0x47d -/* 0x47e is reserved */ +#define BIOS_COM3_TIMEOUT 0x47e +#define BIOS_COM4_TIMEOUT 0x47f +/* 0x47e is reserved */ //<- why that? /* 0x47f-0x4ff is unknow for me */ #define BIOS_KEYBOARD_BUFFER_START 0x480 #define BIOS_KEYBOARD_BUFFER_END 0x482 @@ -112,8 +115,12 @@ struct diskGeo { extern diskGeo DiskGeometryList[]; #include +#ifndef DOSBOX_MEM_H #include "mem.h" +#endif +#ifndef DOSBOX_DOS_INC_H #include "dos_inc.h" +#endif class imageDisk { public: @@ -153,7 +160,7 @@ extern DOS_DTA *imgDTA; void swapInDisks(void); void swapInNextDisk(void); -void BIOS_ZeroExtendedSize(void); +void BIOS_ZeroExtendedSize(bool in); void char_out(Bit8u chr,Bit32u att,Bit8u page); void INT10_StartUp(void); void INT16_StartUp(void); diff --git a/include/callback.h b/include/callback.h index ca919ab..345e7ea 100644 --- a/include/callback.h +++ b/include/callback.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,17 +16,21 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __CALLBACK_H -#define __CALLBACK_H +/* $Id: callback.h,v 1.16 2006/02/09 11:47:47 qbix79 Exp $ */ -#include +#ifndef DOSBOX_CALLBACK_H +#define DOSBOX_CALLBACK_H + +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif typedef Bitu (*CallBack_Handler)(void); extern CallBack_Handler CallBack_Handlers[]; -enum { CB_RETF,CB_IRET,CB_IRET_STI }; +enum { CB_RETN, CB_RETF,CB_IRET,CB_IRET_STI }; -#define CB_MAX 1024 +#define CB_MAX 144 #define CB_SEG 0xC800 #define CB_BASE (CB_SEG << 4) @@ -48,12 +52,37 @@ void CALLBACK_RunRealInt(Bit8u intnum); void CALLBACK_RunRealFar(Bit16u seg,Bit16u off); bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* description=0); -bool CALLBACK_SetupAt(Bitu callback,CallBack_Handler handler,Bitu type,Bitu linearAddress, const char* description=0); +/* Returns with the size of the extra callback */ +Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress); const char* CALLBACK_GetDescription(Bitu callback); bool CALLBACK_Free(Bitu callback); void CALLBACK_SCF(bool val); void CALLBACK_SZF(bool val); -#endif +extern Bitu call_priv_io; + + +class CALLBACK_HandlerObject{ +private: + bool installed; + Bit16u m_callback; + enum {NONE,SETUP,SETUPAT} m_type; + struct { + RealPt old_vector; + Bit8u interrupt; + bool installed; + } vectorhandler; +public: + CALLBACK_HandlerObject():installed(false),m_type(NONE){vectorhandler.installed=false;} + ~CALLBACK_HandlerObject(); + //Install and allocate a callback. + void Install(CallBack_Handler handler,Bitu type,const char* description=0); + //Only allocate a callback number + void Allocate(CallBack_Handler handler,const char* description=0); + Bit16u Get_callback(){return m_callback;} + RealPt Get_RealPointer(){ return RealMake(CB_SEG,m_callback << 4);} + void Set_RealVec(Bit8u vec); +}; +#endif diff --git a/include/cpu.h b/include/cpu.h index 9fd9bfe..9e755a1 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,17 +16,24 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __CPU_H -#define __CPU_H +#ifndef DOSBOX_CPU_H +#define DOSBOX_CPU_H +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" +#endif +#ifndef DOSBOX_REGS_H #include "regs.h" +#endif +#ifndef DOSBOX_MEM_H #include "mem.h" +#endif /* CPU Cycle Timing */ extern Bits CPU_Cycles; extern Bits CPU_CycleLeft; extern Bits CPU_CycleMax; +extern bool CPU_CycleAuto; /* Some common Defines */ /* A CPU Handler */ @@ -43,8 +50,8 @@ Bits CPU_Core_Dyn_X86_Run(void); extern Bit16u parity_lookup[256]; -void CPU_LLDT(Bitu selector); -void CPU_LTR(Bitu selector); +bool CPU_LLDT(Bitu selector); +bool CPU_LTR(Bitu selector); void CPU_LIDT(Bitu limit,Bitu base); void CPU_LGDT(Bitu limit,Bitu base); @@ -57,8 +64,13 @@ void CPU_ARPL(Bitu & dest_sel,Bitu src_sel); void CPU_LAR(Bitu selector,Bitu & ar); void CPU_LSL(Bitu selector,Bitu & limit); -bool CPU_SET_CRX(Bitu cr,Bitu value); +void CPU_SET_CRX(Bitu cr,Bitu value); +bool CPU_WRITE_CRX(Bitu cr,Bitu value); Bitu CPU_GET_CRX(Bitu cr); +bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue); + +bool CPU_WRITE_DRX(Bitu dr,Bitu value); +bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue); void CPU_SMSW(Bitu & word); Bitu CPU_LMSW(Bitu word); @@ -85,6 +97,7 @@ void CPU_ENTER(bool use32,Bitu bytes,Bitu level); #define CPU_INT_SOFTWARE 0x1 #define CPU_INT_EXCEPTION 0x2 #define CPU_INT_HAS_ERROR 0x4 +#define CPU_INT_NOIOPLCHECK 0x8 void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip); INLINE void CPU_HW_Interrupt(Bitu num) { @@ -93,6 +106,9 @@ INLINE void CPU_HW_Interrupt(Bitu num) { INLINE void CPU_SW_Interrupt(Bitu num,Bitu oldeip) { CPU_Interrupt(num,CPU_INT_SOFTWARE,oldeip); } +INLINE void CPU_SW_Interrupt_NoIOPLCheck(Bitu num,Bitu oldeip) { + CPU_Interrupt(num,CPU_INT_SOFTWARE|CPU_INT_NOIOPLCHECK,oldeip); +} bool CPU_PrepareException(Bitu which,Bitu error); void CPU_Exception(Bitu which,Bitu error=0); @@ -108,18 +124,25 @@ void CPU_Push32(Bitu value); void CPU_SetFlags(Bitu word,Bitu mask); + +#define EXCEPTION_UD 6 +#define EXCEPTION_TS 10 +#define EXCEPTION_NP 11 +#define EXCEPTION_SS 12 +#define EXCEPTION_GP 13 + +#define CR0_PROTECTION 0x00000001 +#define CR0_MONITORPROCESSOR 0x00000002 +#define CR0_FPUEMULATION 0x00000004 +#define CR0_TASKSWITCH 0x00000008 +#define CR0_FPUPRESENT 0x00000010 +#define CR0_PAGING 0x80000000 + + // ********************************************************************* // Descriptor // ********************************************************************* -#define CR0_PROTECTION 0x00000001 -#define CR0_FPUENABLED 0x00000002 -#define CR0_FPUMONITOR 0x00000004 -#define CR0_TASKSWITCH 0x00000008 -#define CR0_FPUPRESENT 0x00000010 -#define CR0_PAGING 0x80000000 - - #define DESC_INVALID 0x00 #define DESC_286_TSS_A 0x01 #define DESC_LDT 0x02 @@ -352,9 +375,16 @@ public: return ldt_value; } bool LLDT(Bitu value) { -//TODO checking + if ((value&0xfffc)==0) { + ldt_value=0; + ldt_base=0; + ldt_limit=0; + return true; + } Descriptor desc; - GetDescriptor(value,desc); + if (!GetDescriptor(value,desc)) return !CPU_PrepareException(EXCEPTION_GP,value); + if (desc.Type()!=DESC_LDT) return !CPU_PrepareException(EXCEPTION_GP,value); + if (!desc.saved.seg.p) return !CPU_PrepareException(EXCEPTION_NP,value); ldt_base=desc.GetBase(); ldt_limit=desc.GetLimit(); ldt_value=value; @@ -402,6 +432,7 @@ struct CPUBlock { Bitu which,error; } exception; Bits direction; + Bit32u drx[8]; }; extern CPUBlock cpu; @@ -418,4 +449,3 @@ INLINE void CPU_SetFlagsw(Bitu word) { #endif - diff --git a/include/cross.h b/include/cross.h index 5ad0102..3d6e1ca 100644 --- a/include/cross.h +++ b/include/cross.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: cross.h,v 1.11 2004/09/16 21:46:03 qbix79 Exp $ */ +/* $Id: cross.h,v 1.16 2006/02/09 11:47:47 qbix79 Exp $ */ -#ifndef _CROSS_H -#define _CROSS_H +#ifndef DOSBOX_CROSS_H +#define DOSBOX_CROSS_H #include #include @@ -40,7 +40,7 @@ #define CROSS_LEN 512 /* Maximum filename size */ -#if defined (WIN32) /* Win 32 */ +#if defined (WIN32) || defined (OS2) /* Win 32 & OS/2*/ #define CROSS_FILENAME(blah) #define CROSS_FILESPLIT '\\' #define F_OK 0 @@ -57,4 +57,3 @@ #endif #endif - diff --git a/include/debug.h b/include/debug.h index 78805b7..ce8a002 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -20,7 +20,7 @@ void DEBUG_SetupConsole(void); void DEBUG_DrawScreen(void); bool DEBUG_Breakpoint(void); bool DEBUG_IntBreakpoint(Bit8u intNum); -void DEBUG_Enable(void); +void DEBUG_Enable(bool pressed); void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off); bool DEBUG_ExitLoop(void); void DEBUG_RefreshPage(char scroll); diff --git a/include/dma.h b/include/dma.h index 9e8f36c..a366895 100644 --- a/include/dma.h +++ b/include/dma.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dma.h,v 1.12 2004/08/04 09:12:50 qbix79 Exp $ */ +/* $Id: dma.h,v 1.16 2006/02/09 11:47:47 qbix79 Exp $ */ -#ifndef __DMA_H -#define __DMA_H +#ifndef DOSBOX_DMA_H +#define DOSBOX_DMA_H enum DMAEvent { DMA_REACHED_TC, @@ -31,19 +31,6 @@ enum DMAEvent { class DmaChannel; typedef void (* DMA_CallBack)(DmaChannel * chan,DMAEvent event); -class DmaController { -public: - bool flipflop; - Bit8u ctrlnum; - Bit8u chanbase; -public: - DmaController(Bit8u num) { - flipflop = false; - ctrlnum = num; - chanbase = num * 4; - } -}; - class DmaChannel { public: Bit32u pagebase; @@ -85,9 +72,37 @@ public: Bitu Write(Bitu size, Bit8u * buffer); }; -extern DmaChannel *DmaChannels[8]; -extern DmaController *DmaControllers[2]; +class DmaController { +private: + Bit8u ctrlnum; + bool flipflop; + DmaChannel *DmaChannels[4]; +public: + IO_ReadHandleObject DMA_ReadHandler[0x11]; + IO_WriteHandleObject DMA_WriteHandler[0x11]; + DmaController(Bit8u num) { + flipflop = false; + ctrlnum = num; /* first or second DMA controller */ + for(Bit8u i=0;i<4;i++) { + DmaChannels[i] = new DmaChannel(i+ctrlnum*4,ctrlnum==1); + } + } + ~DmaController(void) { + for(Bit8u i=0;i<4;i++) { + delete DmaChannels[i]; + } + } + DmaChannel * GetChannel(Bit8u chan) { + if (chan<4) return DmaChannels[chan]; + else return NULL; + } + void WriteControllerReg(Bitu reg,Bitu val,Bitu len); + Bitu ReadControllerReg(Bitu reg,Bitu len); +}; + +DmaChannel * GetDMAChannel(Bit8u chan); + +void CloseSecondDMAController(void); +bool SecondDMAControllerAvailable(void); #endif - - diff --git a/include/dos_inc.h b/include/dos_inc.h index d1f6acf..5bac4c5 100644 --- a/include/dos_inc.h +++ b/include/dos_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,13 +16,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_inc.h,v 1.51 2004/11/16 14:28:15 qbix79 Exp $ */ +/* $Id: dos_inc.h,v 1.59 2006/02/09 11:47:47 qbix79 Exp $ */ -#ifndef DOS_H_ -#define DOS_H_ +#ifndef DOSBOX_DOS_INC_H +#define DOSBOX_DOS_INC_H -#include -#include +#ifndef DOSBOX_DOS_SYSTEM_H +#include "dos_system.h" +#endif +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif #ifdef _MSC_VER #pragma pack (1) @@ -72,6 +76,15 @@ enum { RETURN_EXIT=0,RETURN_CTRLC=1,RETURN_ABORT=2,RETURN_TSR=3}; #define DOS_DRIVES 26 #define DOS_DEVICES 10 + +#define DOS_INFOBLOCK_SEG 0x80 +#define DOS_CDS_SEG 0x90 +#define DOS_CONSTRING_SEG 0xa0 +#define DOS_CONDRV_SEG 0xa4 +#define DOS_SDA_SEG 0xb2 +#define DOS_SDA_OFS 0 +#define DOS_MEM_START 0x102 //First Segment that DOS can use + /* internal Dos Tables */ extern DOS_File * Files[DOS_FILES]; @@ -143,8 +156,10 @@ bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks); bool DOS_FreeMemory(Bit16u segment); void DOS_FreeProcessMemory(Bit16u pspseg); Bit16u DOS_GetMemory(Bit16u pages); -void DOS_SetMemAllocStrategy(Bit16u strat); +bool DOS_SetMemAllocStrategy(Bit16u strat); Bit16u DOS_GetMemAllocStrategy(void); +void DOS_BuildUMBChain(const char* use_umbs,bool ems_active); +bool DOS_LinkUMBsToMemChain(Bit16u linkstate); /* FCB stuff */ bool DOS_FCBOpen(Bit16u seg,Bit16u offset); @@ -208,6 +223,7 @@ INLINE Bit16u DOS_PackDate(Bit16u year,Bit16u mon,Bit16u day) { #define DOSERR_REMOVE_CURRENT_DIRECTORY 16 #define DOSERR_NOT_SAME_DEVICE 17 #define DOSERR_NO_MORE_FILES 18 +#define DOSERR_FILE_ALREADY_EXISTS 80 /* Remains some classes used to access certain things */ @@ -341,18 +357,24 @@ public: DOS_InfoBlock () {}; void SetLocation(Bit16u seg); void SetFirstMCB(Bit16u _first_mcb); - void SetfirstFileTable(RealPt _first_table); void SetBuffers(Bit16u x,Bit16u y); void SetCurDirStruct(Bit32u _curdirstruct); void SetFCBTable(Bit32u _fcbtable); void SetDeviceChainStart(Bit32u _devchain); - void SetDiskInfoBuffer(Bit32u _dinfobuf); - RealPt GetPointer (void); + void SetDiskBufferHeadPt(Bit32u _dbheadpt); + void SetStartOfUMBChain(Bit16u _umbstartseg); + void SetUMBChainState(Bit8u _umbchaining); + Bit16u GetStartOfUMBChain(void); + Bit8u GetUMBChainState(void); + RealPt GetPointer(void); #ifdef _MSC_VER #pragma pack(1) #endif struct sDIB { + Bit8u unknown1[4]; + Bit16u magicWord; // -0x22 needs to be 1 + Bit8u unknown2[8]; Bit16u regCXfrom5e; // -0x18 CX from last int21/ah=5e Bit16u countLRUcache; // -0x16 LRU counter for FCB caching Bit16u countLRUopens; // -0x14 LRU counter for FCB openings @@ -387,7 +409,17 @@ public: Bit8u bootDrive; // 0x43 boot drive Bit8u useDwordMov; // 0x44 use dword moves Bit16u extendedSize; // 0x45 size of extended memory - // some more stuff, hopefully never used. + Bit32u diskBufferHeadPt; // 0x47 pointer to least-recently used buffer header + Bit16u dirtyDiskBuffers; // 0x4b number of dirty disk buffers + Bit32u lookaheadBufPt; // 0x4d pointer to lookahead buffer + Bit16u lookaheadBufNumber; // 0x51 number of lookahead buffers + Bit8u bufferLocation; // 0x53 workspace buffer location + Bit32u workspaceBuffer; // 0x54 pointer to workspace buffer + Bit8u unknown3[11]; // 0x58 + Bit8u chainingUMB; // 0x63 bit0: UMB chain linked to MCB chain + Bit16u minMemForExec; // 0x64 minimum paragraphs needed for current program + Bit16u startOfUMBChain; // 0x66 segment of first UMB-MCB + Bit16u memAllocScanStart; // 0x68 start paragraph for memory allocation } GCC_ATTRIBUTE(packed); #ifdef _MSC_VER #pragma pack () @@ -506,11 +538,6 @@ private: #endif }; -extern Bit16u sdaseg; -#define DOS_SDA_SEG sdaseg -#define DOS_SDA_OFS 0 - - class DOS_SDA : public MemStruct { public: DOS_SDA(Bit16u _seg,Bit16u _offs) { SetPt(_seg,_offs); } @@ -584,4 +611,3 @@ INLINE Bit8u RealHandle(Bit16u handle) { } #endif - diff --git a/include/dos_system.h b/include/dos_system.h index c27ccae..d17bfdb 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,15 +16,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_system.h,v 1.28 2004/11/13 12:08:42 qbix79 Exp $ */ +/* $Id: dos_system.h,v 1.31 2006/02/09 11:47:47 qbix79 Exp $ */ + +#ifndef DOSBOX_DOS_SYSTEM_H +#define DOSBOX_DOS_SYSTEM_H -#ifndef DOSSYSTEM_H_ -#define DOSSYSTEM_H_ -#include #include +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" +#endif +#ifndef DOSBOX_CROSS_H #include "cross.h" +#endif #define DOS_NAMELENGTH 12 #define DOS_NAMELENGTH_ASCII (DOS_NAMELENGTH+1) @@ -247,7 +251,8 @@ public: char * GetInfo(void); char curdir[DOS_PATHLENGTH]; char info[256]; - + /* Can be overridden for example in iso images */ + virtual char const * GetLabel(){return dirCache.GetLabel();}; DOS_Drive_Cache dirCache; }; @@ -262,8 +267,12 @@ enum { DOS_SEEK_SET=0,DOS_SEEK_CUR=1,DOS_SEEK_END=2}; typedef bool (MultiplexHandler)(void); void DOS_AddMultiplexHandler(MultiplexHandler * handler); +void DOS_DelMultiplexHandler(MultiplexHandler * handler); +/* AddDevice stores the pointer to a created device */ void DOS_AddDevice(DOS_Device * adddev); +/* DelDevice destroys the device that is pointed to. */ +void DOS_DelDevice(DOS_Device * dev); + void VFILE_Register(const char * name,Bit8u * data,Bit32u size); #endif - diff --git a/include/dosbox.h b/include/dosbox.h index 0bd156a..cb84385 100644 --- a/include/dosbox.h +++ b/include/dosbox.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,16 +16,15 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if !defined __DOSBOX_H -#define __DOSBOX_H +#ifndef DOSBOX_DOSBOX_H +#define DOSBOX_DOSBOX_H + +#include "config.h" void E_Exit(char * message,...); void MSG_Add(const char*,const char*); //add messages to the internal langaugefile -const char* MSG_Get(char const *); //get messages from the internal langaugafile - -#include -#include "config.h" +const char* MSG_Get(char const *); //get messages from the internal langaugafile class Section; @@ -44,15 +43,24 @@ enum MachineType { MCH_HERC, MCH_CGA, MCH_TANDY, + MCH_PCJR, MCH_VGA }; +enum SVGACards { + SVGA_None, + SVGA_S3Trio +}; + +extern SVGACards svgaCard; extern MachineType machine; extern bool SDLNetInited; -#ifndef __LOGGING_H_ +#define IS_TANDY_ARCH ((machine==MCH_TANDY) || (machine==MCH_PCJR)) +#define TANDY_ARCH_CASE MCH_TANDY: case MCH_PCJR + +#ifndef DOSBOX_LOGGING_H #include "logging.h" #endif // the logging system. -#endif /* __DOSBOX_H */ - +#endif /* DOSBOX_DOSBOX_H */ diff --git a/include/fpu.h b/include/fpu.h index 50f50e0..6bea5ce 100644 --- a/include/fpu.h +++ b/include/fpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __FPU_H -#define __FPU_H +#ifndef DOSBOX_FPU_H +#define DOSBOX_FPU_H +#ifndef DOSBOX_MEM_H #include "mem.h" +#endif void FPU_ESC0_Normal(Bitu rm); void FPU_ESC0_EA(Bitu func,PhysPt ea); diff --git a/include/hardware.h b/include/hardware.h index 638e597..fcfa4ac 100644 --- a/include/hardware.h +++ b/include/hardware.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _HARDWARE_H_ -#define _HARDWARE_H_ +#ifndef DOSBOX_HARDWARE_H +#define DOSBOX_HARDWARE_H #include @@ -25,13 +25,26 @@ class Section; enum OPL_Mode { OPL_none,OPL_cms,OPL_opl2,OPL_dualopl2,OPL_opl3 }; +#define CAPTURE_WAVE 0x01 +#define CAPTURE_OPL 0x02 +#define CAPTURE_MIDI 0x04 +#define CAPTURE_IMAGE 0x08 +#define CAPTURE_VIDEO 0x10 + +extern Bitu CaptureState; + +void OPL_Init(Section* sec,OPL_Mode mode); +void CMS_Init(Section* sec); +void OPL_ShutDown(Section* sec); +void CMS_ShutDown(Section* sec); -void OPL_Init(Section* sec,Bitu base,OPL_Mode mode,Bitu rate); -void CMS_Init(Section* sec,Bitu base,Bitu rate); extern Bit8u adlib_commandreg; FILE * OpenCaptureFile(const char * type,const char * ext); +void CAPTURE_AddWave(Bit32u freq, Bit32u len, Bit16s * data); +#define CAPTURE_FLAG_DBLW 0x1 +#define CAPTURE_FLAG_DBLH 0x2 +void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, float fps, Bit8u * data, Bit8u * pal); +void CAPTURE_AddMidi(bool sysex, Bitu len, Bit8u * data); #endif - - diff --git a/include/inout.h b/include/inout.h index bb83949..b61aa6c 100644 --- a/include/inout.h +++ b/include/inout.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,11 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: inout.h,v 1.9 2006/02/09 11:47:47 qbix79 Exp $ */ + +#ifndef DOSBOX_INOUT_H +#define DOSBOX_INOUT_H + #define IO_MAX (64*1024+3) #define IO_MB 0x1 @@ -32,28 +37,36 @@ extern IO_ReadHandler * io_readhandlers[3][IO_MAX]; void IO_RegisterReadHandler(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1); void IO_RegisterWriteHandler(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1); -void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=0); -void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=0); +void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=1); +void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=1); -INLINE void IO_WriteB(Bitu port,Bitu val) { - io_writehandlers[0][port](port,val,1); -}; -INLINE void IO_WriteW(Bitu port,Bitu val) { - io_writehandlers[1][port](port,val,2); -}; -INLINE void IO_WriteD(Bitu port,Bitu val) { - io_writehandlers[2][port](port,val,4); -}; +void IO_WriteB(Bitu port,Bitu val); +void IO_WriteW(Bitu port,Bitu val); +void IO_WriteD(Bitu port,Bitu val); -INLINE Bitu IO_ReadB(Bitu port) { - return io_readhandlers[0][port](port,1); -} -INLINE Bitu IO_ReadW(Bitu port) { - return io_readhandlers[1][port](port,2); -} -INLINE Bitu IO_ReadD(Bitu port) { - return io_readhandlers[2][port](port,4); -} +Bitu IO_ReadB(Bitu port); +Bitu IO_ReadW(Bitu port); +Bitu IO_ReadD(Bitu port); + +/* Classes to manage the IO objects created by the various devices. + * The io objects will remove itself on destruction.*/ +class IO_Base{ +protected: + bool installed; + Bitu m_port, m_mask,m_range; +public: + IO_Base():installed(false){}; +}; +class IO_ReadHandleObject: private IO_Base{ +public: + void Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1); + ~IO_ReadHandleObject(); +}; +class IO_WriteHandleObject: private IO_Base{ +public: + void Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1); + ~IO_WriteHandleObject(); +}; INLINE void IO_Write(Bitu port,Bit8u val) { IO_WriteB(port,val); @@ -62,4 +75,4 @@ INLINE Bit8u IO_Read(Bitu port){ return IO_ReadB(port); } - +#endif diff --git a/include/ipx.h b/include/ipx.h index 5a3e4c1..2b16337 100644 --- a/include/ipx.h +++ b/include/ipx.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,20 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _IPX_H_ -#define _IPX_H_ +/* $Id: ipx.h,v 1.9 2006/02/26 13:46:31 qbix79 Exp $ */ + +#ifndef DOSBOX_IPX_H +#define DOSBOX_IPX_H + +// Uncomment this for a lot of debug messages: +//#define IPX_DEBUGMSG + +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif // In Use Flag codes #define USEFLAG_AVAILABLE 0x00 @@ -31,7 +43,6 @@ #define USEFLAG_LISTENING 0xfe #define USEFLAG_SENDING 0xff - // Completion codes #define COMP_SUCCESS 0x00 #define COMP_REMOTETERM 0xec @@ -52,7 +63,6 @@ // For Uint8 type #include "SDL_net.h" - struct PackedIP { Uint32 host; Uint16 port; @@ -78,6 +88,48 @@ struct IPXHeader { } dest, src; } GCC_ATTRIBUTE(packed); +struct fragmentDescriptor { + Bit16u offset; + Bit16u segment; + Bit16u size; +}; + +#define IPXBUFFERSIZE 1424 + +class ECBClass { +public: + RealPt ECBAddr; + bool isInESRList; + ECBClass *prevECB; + ECBClass *nextECB; + Bit8u iuflag; + + #ifdef IPX_DEBUGMSG + Bitu SerialNumber; + #endif + + ECBClass(Bit16u segment, Bit16u offset); + Bit16u getSocket(void); + + Bit8u getInUseFlag(void); + + void setInUseFlag(Bit8u flagval); + + void setCompletionFlag(Bit8u flagval); + + Bit16u getFragCount(void); + + void getFragDesc(Bit16u descNum, fragmentDescriptor *fragDesc); + RealPt getESRAddr(void); + + void NotifyESR(void); + + void setImmAddress(Bit8u *immAddr); + void getImmAddress(Bit8u* immAddr); + + ~ECBClass(); +}; + // The following routines may not be needed on all systems. On my build of SDL the IPaddress structure is 8 octects // and therefore screws up my IPXheader structure since it needs to be packed. @@ -89,4 +141,3 @@ void PackIP(IPaddress ipAddr, PackedIP *ipPack); #endif #endif - diff --git a/include/ipxserver.h b/include/ipxserver.h index 7b9f1cc..041e541 100644 --- a/include/ipxserver.h +++ b/include/ipxserver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _IPXSERVER_H_ -#define _IPXSERVER_H_ +#ifndef DOSBOX_IPXSERVER_H_ +#define DOSBOX_IPXSERVER_H_ #if C_IPX @@ -33,7 +33,6 @@ struct packetBuffer { }; #define SOCKETTABLESIZE 16 -#define IPXBUFFERSIZE 1024 #define CONVIP(hostvar) hostvar & 0xff, (hostvar >> 8) & 0xff, (hostvar >> 16) & 0xff, (hostvar >> 24) & 0xff #define CONVIPX(hostvar) hostvar[0], hostvar[1], hostvar[2], hostvar[3], hostvar[4], hostvar[5] @@ -47,4 +46,3 @@ Bit8u packetCRC(Bit8u *buffer, Bit16u bufSize); #endif #endif - diff --git a/include/joystick.h b/include/joystick.h index 8476525..7b2b64b 100644 --- a/include/joystick.h +++ b/include/joystick.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: joystick.h,v 1.8 2006/02/09 11:47:48 qbix79 Exp $ */ +#ifndef DOSBOX_JOYSTICK_H +#define DOSBOX_JOYSTICK_H void JOYSTICK_Enable(Bitu which,bool enabled); void JOYSTICK_Button(Bitu which,Bitu num,bool pressed); @@ -31,3 +34,14 @@ bool JOYSTICK_GetButton(Bitu which, Bitu num); float JOYSTICK_GetMove_X(Bitu which); float JOYSTICK_GetMove_Y(Bitu which); + +enum JoystickType { + JOY_NONE, + JOY_2AXIS, + JOY_4AXIS, + JOY_FCS, + JOY_CH +}; + +extern JoystickType joytype; +#endif diff --git a/include/keyboard.h b/include/keyboard.h index 614f031..76878d7 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _KEYBOARD_H_ -#define _KEYBOARD_H_ +#ifndef DOSBOX_KEYBOARD_H +#define DOSBOX_KEYBOARD_H enum KBD_KEYS { KBD_NONE, @@ -34,7 +34,7 @@ enum KBD_KEYS { KBD_capslock,KBD_scrolllock,KBD_numlock, KBD_grave,KBD_minus,KBD_equals,KBD_backslash,KBD_leftbracket,KBD_rightbracket, - KBD_semicolon,KBD_quote,KBD_period,KBD_comma,KBD_slash, + KBD_semicolon,KBD_quote,KBD_period,KBD_comma,KBD_slash,KBD_extra_lt_gt, KBD_printscreen,KBD_pause, KBD_insert,KBD_home,KBD_pageup,KBD_delete,KBD_end,KBD_pagedown, @@ -47,6 +47,7 @@ enum KBD_KEYS { KBD_LAST }; +void KEYBOARD_ClrBuffer(void); void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed); #endif diff --git a/include/logging.h b/include/logging.h index 570bc7f..81ee253 100644 --- a/include/logging.h +++ b/include/logging.h @@ -1,5 +1,5 @@ -#ifndef __LOGGING_H_ -#define __LOGGING_H_ +#ifndef DOSBOX_LOGGING_H +#define DOSBOX_LOGGING_H enum LOG_TYPES { LOG_ALL, LOG_VGA, LOG_VGAGFX,LOG_VGAMISC,LOG_INT10, @@ -45,6 +45,8 @@ struct LOG void operator()(char const* buf, double f1) { return;} void operator()(char const* buf, double f1, double f2) { return;} void operator()(char const* buf, double f1, double f2, double f3) { return;} + void operator()(char const* buf, double f1, double f2, double f3, double f4) { return;} + void operator()(char const* buf, double f1, double f2, double f3, double f4, double f5) { return;} void operator()(char const* buf, char const* s1) { return;} void operator()(char const* buf, char const* s1, double f1) { return;} @@ -61,5 +63,4 @@ void GFX_ShowMsg(char * format,...); #endif //C_DEBUG -#endif //__LOGGING_H_ - +#endif //DOSBOX_LOGGING_H diff --git a/include/mapper.h b/include/mapper.h index 7947023..d789ded 100644 --- a/include/mapper.h +++ b/include/mapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef MAPPER_H_ -#define MAPPER_H_ +#ifndef DOSBOX_MAPPER_H +#define DOSBOX_MAPPER_H enum MapKeys { MK_f1,MK_f2,MK_f3,MK_f4,MK_f5,MK_f6,MK_f7,MK_f8,MK_f9,MK_f10,MK_f11,MK_f12, @@ -25,13 +25,12 @@ enum MapKeys { }; -typedef void (MAPPER_Handler)(void); +typedef void (MAPPER_Handler)(bool pressed); void MAPPER_AddHandler(MAPPER_Handler * handler,MapKeys key,Bitu mods,char * eventname,char * buttonname); void MAPPER_Init(void); void MAPPER_StartUp(Section * sec); -void MAPPER_Run(void); - - +void MAPPER_Run(bool pressed); +void MAPPER_LosingFocus(void); #define MMOD1 0x1 diff --git a/include/mem.h b/include/mem.h index f213305..b91ff93 100644 --- a/include/mem.h +++ b/include/mem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,9 +16,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if !defined __MEM_H -#define __MEM_H -#include +#ifndef DOSBOX_MEM_H +#define DOSBOX_MEM_H + +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif typedef Bit32u PhysPt; typedef Bit8u * HostPt; @@ -29,6 +32,7 @@ typedef Bit32s MemHandle; #define MEM_PAGESIZE 4096 extern HostPt MemBase; +HostPt GetMemBase(void); bool MEM_A20_Enabled(void); void MEM_A20_Enable(bool enable); @@ -52,7 +56,7 @@ MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where); Working on big or little endian machines */ -#ifdef WORDS_BIGENDIAN +#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) INLINE Bit8u host_readb(HostPt off) { return off[0]; @@ -77,10 +81,6 @@ INLINE void host_writed(HostPt off,Bit32u val) { off[3]=(Bit8u)(val >> 24); }; -#define MLEB(_MLE_VAL_) (_MLE_VAL_) -#define MLEW(_MLE_VAL_) ((_MLE_VAL_ >> 8) | (_MLE_VAL_ << 8)) -#define MLED(_MLE_VAL_) ((_MLE_VAL_ >> 24)|((_MLE_VAL_ >> 8)&0xFF00)|((_MLE_VAL_ << 8)&0xFF0000)|((_MLE_VAL_ << 24)&0xFF000000)) - #else INLINE Bit8u host_readb(HostPt off) { @@ -102,16 +102,20 @@ INLINE void host_writed(HostPt off,Bit32u val) { *(Bit32u *)(off)=val; }; -#define MLEB(_MLE_VAL_) (_MLE_VAL_) -#define MLEW(_MLE_VAL_) (_MLE_VAL_) -#define MLED(_MLE_VAL_) (_MLE_VAL_) - #endif -#define WLE(VAR_,VAL_) \ - if (sizeof(VAR_)==1) VAR_=MLEB(VAL_); \ - if (sizeof(VAR_)==2) VAR_=MLEW(VAL_); \ - if (sizeof(VAR_)==4) VAR_=MLED(VAL_); + +INLINE void var_write(Bit8u * var, Bit8u val) { + host_writeb((HostPt)var, val); +} + +INLINE void var_write(Bit16u * var, Bit16u val) { + host_writew((HostPt)var, val); +} + +INLINE void var_write(Bit32u * var, Bit32u val) { + host_writed((HostPt)var, val); +} /* The Folowing six functions are slower but they recognize the paged memory system */ @@ -199,7 +203,12 @@ INLINE RealPt RealMake(Bit16u seg,Bit16u off) { INLINE void RealSetVec(Bit8u vec,RealPt pt) { mem_writed(vec<<2,pt); -} +} + +INLINE void RealSetVec(Bit8u vec,RealPt pt,RealPt &old) { + old = mem_readd(vec<<2); + mem_writed(vec<<2,pt); +} INLINE RealPt RealGetVec(Bit8u vec) { return mem_readd(vec<<2); diff --git a/include/mixer.h b/include/mixer.h index cf8fafd..c778bf5 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#ifndef DOSBOX_MIXER_H +#define DOSBOX_MIXER_H + +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif + typedef void (*MIXER_MixHandler)(Bit8u * sampdate,Bit32u len); typedef void (*MIXER_Handler)(Bitu len); @@ -65,9 +72,24 @@ public: MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,char * name); MixerChannel * MIXER_FindChannel(const char * name); +/* Find the device you want to delete with findchannel "delchan gets deleted" */ +void MIXER_DelChannel(MixerChannel* delchan); + +/* Object to maintain a mixerchannel; As all objects it registers itself with create + * and removes itself when destroyed. */ +class MixerObject{ +private: + bool installed; + char m_name[32]; +public: + MixerObject():installed(false){}; + MixerChannel* Install(MIXER_Handler handler,Bitu freq,char * name); + ~MixerObject(); +}; + /* PC Speakers functions, tightly related to the timer functions */ - void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode); void PCSPEAKER_SetType(Bitu mode); +#endif diff --git a/include/mouse.h b/include/mouse.h index 8a9c6e6..4dcb46a 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,18 +16,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: mouse.h,v 1.7 2004/08/04 09:12:51 qbix79 Exp $ */ +/* $Id: mouse.h,v 1.12 2006/02/09 11:47:48 qbix79 Exp $ */ -#ifndef _MOUSE_H_ -#define _MOUSE_H_ +#ifndef DOSBOX_MOUSE_H +#define DOSBOX_MOUSE_H void Mouse_ShowCursor(void); void Mouse_HideCursor(void); -void Mouse_SetPS2State(bool use); +bool Mouse_SetPS2State(bool use); void Mouse_ChangePS2Callback(Bit16u pseg, Bit16u pofs); -void Mouse_CursorMoved(float x,float y); +void Mouse_CursorMoved(float xrel,float yrel,float x,float y,bool emulate); void Mouse_CursorSet(float x,float y); void Mouse_ButtonPressed(Bit8u button); void Mouse_ButtonReleased(Bit8u button); @@ -35,5 +35,4 @@ void Mouse_ButtonReleased(Bit8u button); void Mouse_AutoLock(bool enable); void Mouse_NewVideoMode(void); -#endif - +#endif diff --git a/include/paging.h b/include/paging.h index fc92ab9..0309e74 100644 --- a/include/paging.h +++ b/include/paging.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,13 +16,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: paging.h,v 1.12 2004/10/12 10:45:10 harekiet Exp $ */ +/* $Id: paging.h,v 1.22 2006/02/09 11:47:48 qbix79 Exp $ */ -#ifndef _PAGING_H_ -#define _PAGING_H_ +#ifndef DOSBOX_PAGING_H +#define DOSBOX_PAGING_H +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" +#endif +#ifndef DOSBOX_MEM_H #include "mem.h" +#endif class PageDirectory; @@ -50,7 +54,14 @@ public: virtual void writeb(PhysPt addr,Bitu val); virtual void writew(PhysPt addr,Bitu val); virtual void writed(PhysPt addr,Bitu val); - virtual HostPt GetHostPt(Bitu phys_page); + virtual HostPt GetHostReadPt(Bitu phys_page); + virtual HostPt GetHostWritePt(Bitu phys_page); + virtual bool readb_checked(PhysPt addr, Bitu * val); + virtual bool readw_checked(PhysPt addr, Bitu * val); + virtual bool readd_checked(PhysPt addr, Bitu * val); + virtual bool writeb_checked(PhysPt addr,Bitu val); + virtual bool writew_checked(PhysPt addr,Bitu val); + virtual bool writed_checked(PhysPt addr,Bitu val); Bitu flags; }; @@ -69,8 +80,8 @@ void PAGING_UnlinkPages(Bitu lin_page,Bitu pages); void PAGING_MapPage(Bitu lin_page,Bitu phys_page); bool PAGING_MakePhysPage(Bitu & page); -void MEM_SetLFB(Bitu _page,Bitu _pages,HostPt _pt); -void MEM_SetPageHandler(Bitu phys_page,Bitu pages,PageHandler * handler); +void MEM_SetLFB( Bitu page, Bitu pages, PageHandler *handler); +void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler); void MEM_ResetPageHandler(Bitu phys_page, Bitu pages); @@ -78,6 +89,19 @@ void MEM_ResetPageHandler(Bitu phys_page, Bitu pages); #pragma pack (1) #endif struct X86_PageEntryBlock{ +#ifdef WORDS_BIGENDIAN + Bit32u base:20; + Bit32u avl:3; + Bit32u g:1; + Bit32u pat:1; + Bit32u d:1; + Bit32u a:1; + Bit32u pcd:1; + Bit32u pwt:1; + Bit32u us:1; + Bit32u wr:1; + Bit32u p:1; +#else Bit32u p:1; Bit32u wr:1; Bit32u us:1; @@ -89,6 +113,7 @@ struct X86_PageEntryBlock{ Bit32u g:1; Bit32u avl:3; Bit32u base:20; +#endif } GCC_ATTRIBUTE(packed); #ifdef _MSC_VER #pragma pack () @@ -117,7 +142,8 @@ struct PagingBlock { Bitu used; Bit32u entries[PAGING_LINKS]; } links; - bool enabled; + Bit32u firstmb[LINK_START]; + bool enabled; }; extern PagingBlock paging; @@ -126,12 +152,27 @@ extern PagingBlock paging; PageHandler * MEM_GetPageHandler(Bitu phys_page); +/* Use this helper function to access linear addresses in readX/writeX functions */ +INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) { + return (paging.tlb.phys_page[linePage>>12]<<12); +} + +INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) { + return (paging.tlb.phys_page[linAddr>>12]<<12)|(linAddr&0xfff); +} + + /* Unaligned address handlers */ Bit16u mem_unalignedreadw(PhysPt address); Bit32u mem_unalignedreadd(PhysPt address); void mem_unalignedwritew(PhysPt address,Bit16u val); void mem_unalignedwrited(PhysPt address,Bit32u val); +bool mem_unalignedreadw_checked_x86(PhysPt address,Bit16u * val); +bool mem_unalignedreadd_checked_x86(PhysPt address,Bit32u * val); +bool mem_unalignedwritew_checked_x86(PhysPt address,Bit16u val); +bool mem_unalignedwrited_checked_x86(PhysPt address,Bit32u val); + /* Special inlined memory reading/writing */ INLINE Bit8u mem_readb_inline(PhysPt address) { @@ -141,20 +182,21 @@ INLINE Bit8u mem_readb_inline(PhysPt address) { } INLINE Bit16u mem_readw_inline(PhysPt address) { - if (address & 1) return mem_unalignedreadw(address); + if (!(address & 1)) { + Bitu index=(address>>12); - Bitu index=(address>>12); - if (paging.tlb.read[index]) return host_readw(paging.tlb.read[index]+address); - else return paging.tlb.handler[index]->readw(address); + if (paging.tlb.read[index]) return host_readw(paging.tlb.read[index]+address); + else return paging.tlb.handler[index]->readw(address); + } else return mem_unalignedreadw(address); } - INLINE Bit32u mem_readd_inline(PhysPt address) { - if (address & 3) return mem_unalignedreadd(address); + if (!(address & 3)) { + Bitu index=(address>>12); - Bitu index=(address>>12); - if (paging.tlb.read[index]) return host_readd(paging.tlb.read[index]+address); - else return paging.tlb.handler[index]->readd(address); + if (paging.tlb.read[index]) return host_readd(paging.tlb.read[index]+address); + else return paging.tlb.handler[index]->readd(address); + } else return mem_unalignedreadd(address); } INLINE void mem_writeb_inline(PhysPt address,Bit8u val) { @@ -165,21 +207,135 @@ INLINE void mem_writeb_inline(PhysPt address,Bit8u val) { } INLINE void mem_writew_inline(PhysPt address,Bit16u val) { - if (address & 1) {mem_unalignedwritew(address,val);return;} + if (!(address & 1)) { + Bitu index=(address>>12); - Bitu index=(address>>12); - - if (paging.tlb.write[index]) host_writew(paging.tlb.write[index]+address,val); - else paging.tlb.handler[index]->writew(address,val); + if (paging.tlb.write[index]) host_writew(paging.tlb.write[index]+address,val); + else paging.tlb.handler[index]->writew(address,val); + } else mem_unalignedwritew(address,val); } INLINE void mem_writed_inline(PhysPt address,Bit32u val) { - if (address & 3) {mem_unalignedwrited(address,val);return;} - - Bitu index=(address>>12); - if (paging.tlb.write[index]) host_writed(paging.tlb.write[index]+address,val); - else paging.tlb.handler[index]->writed(address,val); + if (!(address & 3)) { + Bitu index=(address>>12); + if (paging.tlb.write[index]) host_writed(paging.tlb.write[index]+address,val); + else paging.tlb.handler[index]->writed(address,val); + } else mem_unalignedwrited(address,val); } + +INLINE Bit16u mem_readw_dyncorex86(PhysPt address) { + if ((address & 0xfff)<0xfff) { + Bitu index=(address>>12); + + if (paging.tlb.read[index]) return host_readw(paging.tlb.read[index]+address); + else return paging.tlb.handler[index]->readw(address); + } else return mem_unalignedreadw(address); +} + +INLINE Bit32u mem_readd_dyncorex86(PhysPt address) { + if ((address & 0xfff)<0xffd) { + Bitu index=(address>>12); + + if (paging.tlb.read[index]) return host_readd(paging.tlb.read[index]+address); + else return paging.tlb.handler[index]->readd(address); + } else return mem_unalignedreadd(address); +} + +INLINE void mem_writew_dyncorex86(PhysPt address,Bit16u val) { + if ((address & 0xfff)<0xfff) { + Bitu index=(address>>12); + + if (paging.tlb.write[index]) host_writew(paging.tlb.write[index]+address,val); + else paging.tlb.handler[index]->writew(address,val); + } else mem_unalignedwritew(address,val); +} + +INLINE void mem_writed_dyncorex86(PhysPt address,Bit32u val) { + if ((address & 0xfff)<0xffd) { + Bitu index=(address>>12); + + if (paging.tlb.write[index]) host_writed(paging.tlb.write[index]+address,val); + else paging.tlb.handler[index]->writed(address,val); + } else mem_unalignedwrited(address,val); +} + + +INLINE bool mem_readb_checked_x86(PhysPt address, Bit8u * val) { + Bitu index=(address>>12); + if (paging.tlb.read[index]) { + *val=host_readb(paging.tlb.read[index]+address); + return false; + } else { + Bitu uval; + bool retval; + retval=paging.tlb.handler[index]->readb_checked(address, &uval); + *val=(Bit8u)uval; + return retval; + } +} + +INLINE bool mem_readw_checked_x86(PhysPt address, Bit16u * val) { + if ((address & 0xfff)<0xfff) { + Bitu index=(address>>12); + if (paging.tlb.read[index]) { + *val=host_readw(paging.tlb.read[index]+address); + return false; + } else { + Bitu uval; + bool retval; + retval=paging.tlb.handler[index]->readw_checked(address, &uval); + *val=(Bit16u)uval; + return retval; + } + } else return mem_unalignedreadw_checked_x86(address, val); +} + + +INLINE bool mem_readd_checked_x86(PhysPt address, Bit32u * val) { + if ((address & 0xfff)<0xffd) { + Bitu index=(address>>12); + if (paging.tlb.read[index]) { + *val=host_readd(paging.tlb.read[index]+address); + return false; + } else { + Bitu uval; + bool retval; + retval=paging.tlb.handler[index]->readd_checked(address, &uval); + *val=(Bit32u)uval; + return retval; + } + } else return mem_unalignedreadd_checked_x86(address, val); +} + +INLINE bool mem_writeb_checked_x86(PhysPt address,Bit8u val) { + Bitu index=(address>>12); + if (paging.tlb.write[index]) { + host_writeb(paging.tlb.write[index]+address,val); + return false; + } else return paging.tlb.handler[index]->writeb_checked(address,val); +} + +INLINE bool mem_writew_checked_x86(PhysPt address,Bit16u val) { + if ((address & 0xfff)<0xfff) { + Bitu index=(address>>12); + if (paging.tlb.write[index]) { + host_writew(paging.tlb.write[index]+address,val); + return false; + } else return paging.tlb.handler[index]->writew_checked(address,val); + } else return mem_unalignedwritew_checked_x86(address,val); +} + +INLINE bool mem_writed_checked_x86(PhysPt address,Bit32u val) { + if ((address & 0xfff)<0xffd) { + Bitu index=(address>>12); + if (paging.tlb.write[index]) { + host_writed(paging.tlb.write[index]+address,val); + return false; + } else return paging.tlb.handler[index]->writed_checked(address,val); + } else return mem_unalignedwrited_checked_x86(address,val); +} + + #endif diff --git a/include/pic.h b/include/pic.h index 43caaf4..90a49b4 100644 --- a/include/pic.h +++ b/include/pic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __PIC_H -#define __PIC_H +#ifndef DOSBOX_PIC_H +#define DOSBOX_PIC_H /* CPU Cycle Timing */ @@ -60,4 +60,3 @@ void PIC_RemoveEvents(PIC_EventHandler handler); void PIC_SetIRQMask(Bitu irq, bool masked); #endif - diff --git a/include/programs.h b/include/programs.h index b5a7a3b..7d6be6a 100644 --- a/include/programs.h +++ b/include/programs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,19 +16,20 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __PROGRAM_H -#define __PROGRAM_H +#ifndef DOSBOX_PROGRAMS_H +#define DOSBOX_PROGRAMS_H + +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" +#endif +#ifndef DOSBOX_DOS_INC_H #include "dos_inc.h" +#endif +#ifndef DOSBOX_SETUP_H #include "setup.h" +#endif - -class Program; - -typedef void (PROGRAMS_Main)(Program * * make); -void PROGRAMS_MakeFile(char * name,PROGRAMS_Main * main); - class Program { public: Program(); @@ -40,20 +41,15 @@ public: CommandLine * cmd; DOS_PSP * psp; virtual void Run(void)=0; - bool Program::GetEnvStr(const char * entry,std::string & result); + bool GetEnvStr(const char * entry,std::string & result); bool GetEnvNum(Bitu num,std::string & result); Bitu GetEnvCount(void); bool SetEnv(const char * entry,const char * new_string); - void WriteOut(const char * format,...); /* Write to standard output */ + void WriteOut(const char * format,...); /* Write to standard output */ }; -void SHELL_AddAutoexec(char * line,...); - - - - - +typedef void (PROGRAMS_Main)(Program * * make); +void PROGRAMS_MakeFile(char * name,PROGRAMS_Main * main); #endif - diff --git a/include/regs.h b/include/regs.h index 1c859b1..02eb255 100644 --- a/include/regs.h +++ b/include/regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if !defined __REGS_H -#define __REGS_H +#ifndef DOSBOX_REGS_H +#define DOSBOX_REGS_H -#include +#ifndef DOSBOX_MEM_H +#include "mem.h" +#endif #define FLAG_CF 0x00000001 #define FLAG_PF 0x00000004 @@ -165,4 +167,3 @@ enum { #define reg_flags cpu_regs.flags #endif - diff --git a/include/render.h b/include/render.h index 8a31386..539e40e 100644 --- a/include/render.h +++ b/include/render.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,17 +16,69 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __RENDER_H -#define __RENDER_H +#ifndef DOSBOX_RENDER_H +#define DOSBOX_RENDER_H -typedef void (* RENDER_Line_Handler)(const Bit8u * src); +#include "../src/gui/render_scalers.h" -void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,double ratio,bool dblw,bool dblh); +typedef struct { + struct { + Bit8u red; + Bit8u green; + Bit8u blue; + Bit8u unused; + } rgb[256]; + union { + Bit16u b16[256]; + Bit32u b32[256]; + } lut; + bool changed; + Bit8u modified[256]; + Bitu first; + Bitu last; +} RenderPal_t; + +typedef struct { + struct { + Bitu width; + Bitu height; + Bitu bpp; + bool dblw,dblh; + double ratio; + float fps; + } src; + struct { + Bitu count; + Bitu max; + } frameskip; + struct { + Bitu size; + scalerMode_t inMode; + scalerMode_t outMode; + scalerOperation_t op; + bool clearCache; + ScalerLineHandler_t lineHandler; + ScalerLineHandler_t linePalHandler; + ScalerComplexHandler_t complexHandler; + Bitu blocks, lastBlock; + Bitu outPitch; + Bit8u *outWrite; + Bitu cachePitch; + Bit8u *cacheRead; + Bitu inHeight, inLine, outLine; + } scale; + RenderPal_t pal; + bool updating; + bool active; + bool aspect; +} Render_t; + +extern Render_t render; +extern ScalerLineHandler_t RENDER_DrawLine; +void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh); bool RENDER_StartUpdate(void); -void RENDER_EndUpdate(void); +void RENDER_EndUpdate( bool fullUpdate ); void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue); -extern RENDER_Line_Handler RENDER_DrawLine; #endif - diff --git a/include/serialport.h b/include/serialport.h index 3aac522..12f62e9 100644 --- a/include/serialport.h +++ b/include/serialport.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,140 +16,284 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if !defined __SERIALPORT_H -#define __SERIALPORT_H +/* $Id: serialport.h,v 1.12 2006/02/09 11:47:48 qbix79 Exp $ */ -#include +#ifndef DOSBOX_SERIALPORT_H +#define DOSBOX_SERIALPORT_H -#include "dosbox.h" +// Uncomment this for a lot of debug messages: +// #define SERIALPORT_DEBUGMSG + +#ifndef DOSBOX_DOSBOX_H +#include "dosbox.h" +#endif +#ifndef DOSBOX_INOUT_H +#include "inout.h" +#endif +#ifndef DOSBOX_TIMER_H +#include "timer.h" +#endif -//If it's too high you overflow terminal clients buffers i think -#define QUEUE_SIZE 1024 // Serial port interface // -#define MS_CTS 0x01 -#define MS_DSR 0x02 -#define MS_RI 0x04 -#define MS_DCD 0x08 - -#define MC_DTR 0x1 -#define MC_RTS 0x2 - - -class CFifo { -public: - CFifo(Bitu _size) { - size=_size; - pos=used=0; - data=new Bit8u[size]; - } - ~CFifo() { - delete[] data; - } - INLINE Bitu left(void) { - return size-used; - } - INLINE Bitu inuse(void) { - return used; - } - void clear(void) { - used=pos=0; - } - bool isFull() { - return (used >= size); - } - void addb(Bit8u _val) { - assert(used=size) where-=size; - data[where]=_val; - used++; - } - void adds(Bit8u * _str,Bitu _len) { - assert((used+_len)<=size); - Bitu where=pos+used; - used+=_len; - while (_len--) { - if (where>=size) where-=size; - data[where++]=*_str++; - } - } - Bit8u getb(void) { - if (!used) return data[pos]; - Bitu where=pos; - if (++pos>=size) pos-=size; - used--; - return data[where]; - } - void gets(Bit8u * _str,Bitu _len) { - assert(used>=_len); - used-=_len; - while (_len--) { - *_str++=data[pos]; - if (++pos>=size) pos-=size; - } - } -private: - Bit8u * data; - Bitu size,pos,used; -}; - class CSerial { public: - CSerial() { - - } - // Constructor takes base port (0x3f0, 0x2f0, 0x2e0, etc.), IRQ, and initial bps // - CSerial (Bit16u initbase, Bit8u initirq, Bit32u initbps); + // Constructor takes base port (0x3f8, 0x2f8, 0x2e8, etc.), IRQ, and initial bps // + CSerial(IO_ReadHandler* rh, IO_WriteHandler* wh, + TIMER_TickHandler TimerHandler, + Bit16u initbase, Bit8u initirq, Bit32u initbps, + Bit8u bytesize, const char* parity, Bit8u stopbits); + + TIMER_TickHandler TimerHnd; virtual ~CSerial(); + void InstallTimerHandler(TIMER_TickHandler); + + IO_ReadHandleObject ReadHandler[8]; + IO_WriteHandleObject WriteHandler[8]; - void write_reg(Bitu reg, Bitu val); - Bitu read_reg(Bitu reg); - - void SetModemStatus(Bit8u status); - virtual bool CanRecv(void)=0; - virtual bool CanSend(void)=0; - virtual void Send(Bit8u val)=0; - virtual Bit8u Recv(Bit8u val)=0; - virtual void Timer(void); - - void checkint(void); - + void Timer(void); + virtual void Timer2(void)=0; + Bitu base; Bitu irq; - Bitu bps; - Bit8u mctrl; + + bool getDTR(); + bool getRTS(); - CFifo *rqueue; - CFifo *tqueue; + bool getRI(); + bool getCD(); + bool getDSR(); + bool getCTS(); + + void setRI(bool value); + void setDSR(bool value); + void setCD(bool value); + void setCTS(bool value); + + void Write_THR(Bit8u data); + Bitu Read_RHR(); + Bitu Read_IER(); + void Write_IER(Bit8u data); + Bitu Read_ISR(); + Bitu Read_LCR(); + void Write_LCR(Bit8u data); + Bitu Read_MCR(); + void Write_MCR(Bit8u data); + Bitu Read_LSR(); + + // Really old hardware seems to have the delta part of this register writable + void Write_MSR(Bit8u data); + + Bitu Read_MSR(); + Bitu Read_SPR(); + void Write_SPR(Bit8u data); + void Write_reserved(Bit8u data, Bit8u address); + + // If a byte comes from wherever(loopback or real port or maybe + // that softmodem thingy), put it in here. + void receiveByte(Bit8u data); + + // If an error was received, put it here (in LSR register format) + void receiveError(Bit8u errorword); + + // connected device checks, if port can receive data: + bool CanReceiveByte(); + + // When done sending, notify here + void ByteTransmitted(); + + // Virtual app has read the received data + virtual void RXBufferEmpty()=0; + + // real transmit + virtual void transmitByte(Bit8u val)=0; + + // switch break state to the passed value + virtual void setBreak(bool value)=0; + + // set output lines + virtual void updateModemControlLines(/*Bit8u mcr*/)=0; + + // change baudrate, number of bits, parity, word length al at once + virtual void updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr)=0; + + // CSerial requests an update of the input lines + virtual void updateMSR()=0; + + // after update request, or some "real" changes, + // modify MSR here + void changeMSR(Bit8u data); // make public + + void Init_Registers(Bit32u initbps, + Bit8u bytesize, const char* parity, Bit8u stopbits); private: - void UpdateBaudrate(void); - bool FIFOenabled; - Bit8u FIFOsize; - bool dotxint; - - Bit8u scratch; - Bit8u dlab; - Bit8u divisor_lsb; - Bit8u divisor_msb; - Bit8u local_loopback; - Bit8u iir; - Bit8u ier; - Bit8u mstatus; - Bit8u linectrl; - Bit8u errors; + // I used this spec: http://www.exar.com/products/st16c450v420.pdf + + void changeMSR_Loopback(Bit8u data); + + void WriteRealIER(Bit8u data); + // reason for an interrupt has occured - functions triggers interrupt + // if it is enabled and no higher-priority irq pending + void rise(Bit8u priority); + + // clears the pending interrupt + void clear(Bit8u priority); + + #define ERROR_PRIORITY 4 // overrun, parity error, frame error, break + #define RX_PRIORITY 1 // a byte has been received + #define TX_PRIORITY 2 // tx buffer has become empty + #define MSR_PRIORITY 8 // CRS, DSR, RI, DCD change + #define NONE_PRIORITY 0 + + + Bit8u pending_interrupts; // stores triggered interupts + Bit8u current_priority; + Bit8u waiting_interrupts; // these are on, but maybe not enabled + + // 16C450 (no FIFO) + // read/write name + + + Bit8u DLL; // r Baudrate divider low byte + Bit8u DLM; // r "" high byte + + Bit8u RHR; // r Receive Holding Register, also LSB of Divisor Latch (r/w) + #define RHR_OFFSET 0 + // Data: whole byte + + Bit8u THR; // w Transmit Holding Register + #define THR_OFFSET 0 + // Data: whole byte + + Bit8u IER; // r/w Interrupt Enable Register, also MSB of Divisor Latch (r/w) + #define IER_OFFSET 1 + // Data: + // bit0 receive holding register + // bit1 transmit holding register + // bit2 receive line status interrupt + // bit3 modem status interrupt + + #define RHR_INT_Enable_MASK 0x1 + #define THR_INT_Enable_MASK 0x2 + #define Receive_Line_INT_Enable_MASK 0x4 + #define Modem_Status_INT_Enable_MASK 0x8 + + Bit8u ISR; // r Interrupt Status Register + #define ISR_OFFSET 2 + + #define ISR_CLEAR_VAL 0x1 + #define ISR_ERROR_VAL 0x6 + #define ISR_RX_VAL 0x4 + #define ISR_TX_VAL 0x2 + #define ISR_MSR_VAL 0x0 +public: + Bit8u LCR; // r/w Line Control Register +private: + #define LCR_OFFSET 3 + // bit0: word length bit0 + // bit1: word length bit1 + // bit2: stop bits + // bit3: parity enable + // bit4: even parity + // bit5: set parity + // bit6: set break + // bit7: divisor latch enable + + + #define LCR_BREAK_MASK 0x40 + #define LCR_DIVISOR_Enable_MASK 0x80 + #define LCR_PORTCONFIG_MASK 0x3F + + #define LCR_PARITY_NONE 0x0 + #define LCR_PARITY_ODD 0x8 + #define LCR_PARITY_EVEN 0x18 + #define LCR_PARITY_MARK 0x28 + #define LCR_PARITY_SPACE 0x38 + + #define LCR_DATABITS_5 0x0 + #define LCR_DATABITS_6 0x1 + #define LCR_DATABITS_7 0x2 + #define LCR_DATABITS_8 0x3 + + #define LCR_STOPBITS_1 0x0 + #define LCR_STOPBITS_MORE_THAN_1 0x4 + + Bit8u MCR; // r/w Modem Control Register + #define MCR_OFFSET 4 + // bit0: DTR + // bit1: RTS + // bit2: OP1 + // bit3: OP2 + // bit4: loop back enable + + #define MCR_LOOPBACK_Enable_MASK 0x10 + #define MCR_LEVELS_MASK 0xf + + #define MCR_DTR_MASK 0x1 + #define MCR_RTS_MASK 0x2 + #define MCR_OP1_MASK 0x4 + #define MCR_OP2_MASK 0x8 + + Bit8u LSR; // r Line Status Register + #define LSR_OFFSET 5 + + #define LSR_RX_DATA_READY_MASK 0x1 + #define LSR_OVERRUN_ERROR_MASK 0x2 + #define LSR_PARITY_ERROR_MASK 0x4 + #define LSR_FRAMING_ERROR_MASK 0x8 + #define LSR_RX_BREAK_MASK 0x10 + #define LSR_TX_HOLDING_EMPTY_MASK 0x20 + #define LSR_TX_EMPTY_MASK 0x40 + + #define LSR_ERROR_MASK 0x1e + + + Bit8u MSR; // r Modem Status Register + #define MSR_OFFSET 6 + // bit0: deltaCTS + // bit1: deltaDSR + // bit2: deltaRI + // bit3: deltaCD + // bit4: CTS + // bit5: DSR + // bit6: RI + // bit7: CD + + #define MSR_delta_MASK 0xf + #define MSR_LINE_MASK 0xf0 + + #define MSR_dCTS_MASK 0x1 + #define MSR_dDSR_MASK 0x2 + #define MSR_dRI_MASK 0x4 + #define MSR_dCD_MASK 0x8 + #define MSR_CTS_MASK 0x10 + #define MSR_DSR_MASK 0x20 + #define MSR_RI_MASK 0x40 + #define MSR_CD_MASK 0x80 + + Bit8u SPR; // r/w Scratchpad Register + #define SPR_OFFSET 7 + + + // For loopback purposes... + bool loopback_pending; + Bit8u loopback_data; + void transmitLoopbackByte(Bit8u val); + + // 16C550 (FIFO) + // TODO + //Bit8u FCR; // FIFO Control Register + }; -#include - -typedef std::list CSerialList; -typedef std::list::iterator CSerial_it; - -extern CSerialList seriallist; +#define COM1_BASE 0x3f8 +#define COM2_BASE 0x2f8 +#define COM3_BASE 0x3e8 +#define COM4_BASE 0x2e8 #endif diff --git a/include/setup.h b/include/setup.h index 6224aff..be90b5d 100644 --- a/include/setup.h +++ b/include/setup.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,16 +16,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: setup.h,v 1.16 2004/08/04 09:12:51 qbix79 Exp $ */ +/* $Id: setup.h,v 1.22 2006/02/09 11:47:48 qbix79 Exp $ */ -#ifndef _SETUP_H_ -#define _SETUP_H_ +#ifndef DOSBOX_SETUP_H +#define DOSBOX_SETUP_H #ifdef _MSC_VER #pragma warning ( disable : 4786 ) #endif +#ifndef DOSBOX_CROSS_H #include "cross.h" +#endif #include #include @@ -34,7 +36,7 @@ public: CommandLine(int argc,char * argv[]); CommandLine(char * name,char * cmdline); const char * GetFileName(){ return file_name.c_str();} - + bool FindExist(char * name,bool remove=false); bool FindHex(char * name,int & value,bool remove=false); bool FindInt(char * name,int & value,bool remove=false); @@ -42,6 +44,7 @@ public: bool FindCommand(unsigned int which,std::string & value); bool FindStringBegin(char * begin,std::string & value, bool remove=false); bool FindStringRemain(char * name,std::string & value); + bool GetStringRemain(std::string & value); unsigned int GetCount(void); private: typedef std::list::iterator cmd_it; @@ -63,16 +66,16 @@ public: Property(const char* _propname):propname(_propname) { } virtual void SetValue(char* input)=0; virtual void GetValuestring(char* str)=0; - Value GetValue() { return __value;} - std::string propname; - Value __value; + Value GetValue() { return value;} virtual ~Property(){ } + std::string propname; + Value value; }; class Prop_int:public Property { public: Prop_int(const char* _propname, int _value):Property(_propname) { - __value._int=_value; + value._int=_value; } void SetValue(char* input); void GetValuestring(char* str); @@ -81,7 +84,7 @@ public: class Prop_float:public Property { public: Prop_float(const char* _propname, float _value):Property(_propname){ - __value._float=_value; + value._float=_value; } void SetValue(char* input); void GetValuestring(char* str); @@ -91,7 +94,7 @@ public: class Prop_bool:public Property { public: Prop_bool(const char* _propname, bool _value):Property(_propname) { - __value._bool=_value; + value._bool=_value; } void SetValue(char* input); void GetValuestring(char* str); @@ -101,10 +104,10 @@ public: class Prop_string:public Property{ public: Prop_string(const char* _propname, char* _value):Property(_propname) { - __value._string=new std::string(_value); + value._string=new std::string(_value); } ~Prop_string(){ - delete __value._string; + delete value._string; } void SetValue(char* input); void GetValuestring(char* str); @@ -112,45 +115,51 @@ public: class Prop_hex:public Property { public: Prop_hex(const char* _propname, int _value):Property(_propname) { - __value._hex=_value; + value._hex=_value; } void SetValue(char* input); ~Prop_hex(){ } - void GetValuestring(char* str); + void GetValuestring(char* str); }; class Section { -public: - Section(const char* _sectionname) { sectionname=_sectionname; } - virtual ~Section(){ ExecuteDestroy();} - +private: typedef void (*SectionFunction)(Section*); - void AddInitFunction(SectionFunction func) {initfunctions.push_back(func);} - void AddDestroyFunction(SectionFunction func) {destroyfunctions.push_front(func);} - void ExecuteInit() { - typedef std::list::iterator func_it; - for (func_it tel=initfunctions.begin(); tel!=initfunctions.end(); tel++){ - (*tel)(this); + /* Wrapper class around startup and shutdown functions. the variable + * canchange indicates it can be called on configuration changes */ + struct Function_wrapper { + SectionFunction function; + bool canchange; + Function_wrapper(SectionFunction _fun,bool _ch){ + function=_fun; + canchange=_ch; } - } - void ExecuteDestroy() { - typedef std::list::iterator func_it; - for (func_it tel=destroyfunctions.begin(); tel!=destroyfunctions.end(); tel++){ - (*tel)(this); - } - } - std::list initfunctions; - std::list destroyfunctions; - virtual void HandleInputline(char * _line){} - virtual void PrintData(FILE* outfile) {} - std::string sectionname; + }; + std::list initfunctions; + std::list destroyfunctions; + std::string sectionname; +public: + Section(const char* _sectionname):sectionname(_sectionname) { } + + void AddInitFunction(SectionFunction func,bool canchange=false) {initfunctions.push_back(Function_wrapper(func,canchange));} + void AddDestroyFunction(SectionFunction func,bool canchange=false) {destroyfunctions.push_front(Function_wrapper(func,canchange));} + void ExecuteInit(bool initall=true); + void ExecuteDestroy(bool destroyall=true); + const char* GetName() {return sectionname.c_str();} + + virtual char* GetPropValue(const char* _property)=0; + virtual void HandleInputline(char * _line)=0; + virtual void PrintData(FILE* outfile)=0; + virtual ~Section() { /*Children must call executedestroy ! */} }; class Section_prop:public Section { - public: +private: + std::list properties; + typedef std::list::iterator it; +public: Section_prop(const char* _sectionname):Section(_sectionname){} - void Add_int(const char* _propname, int _value=0); void Add_string(const char* _propname, char* _value=NULL); void Add_bool(const char* _propname, bool _value=false); @@ -164,30 +173,38 @@ class Section_prop:public Section { float Get_float(const char* _propname); void HandleInputline(char *gegevens); void PrintData(FILE* outfile); - - std::list properties; - typedef std::list::iterator it; + virtual char* GetPropValue(const char* _property); + //ExecuteDestroy should be here else the destroy functions use destroyed properties + virtual ~Section_prop(); }; class Section_line: public Section{ public: Section_line(const char* _sectionname):Section(_sectionname){} + ~Section_line(){ExecuteDestroy(true);} void HandleInputline(char* gegevens); void PrintData(FILE* outfile); + virtual char* GetPropValue(const char* _property); std::string data; }; class Config{ +public: + CommandLine * cmdline; +private: + std::list sectionlist; + typedef std::list::iterator it; + typedef std::list::reverse_iterator reverse_it; + void (* _start_function)(void); public: Config(CommandLine * cmd){ cmdline=cmd;} ~Config(); - CommandLine * cmdline; - Section * AddSection(const char * _name,void (*_initfunction)(Section*)); Section_line * AddSection_line(const char * _name,void (*_initfunction)(Section*)); - Section_prop * AddSection_prop(const char * _name,void (*_initfunction)(Section*)); + Section_prop * AddSection_prop(const char * _name,void (*_initfunction)(Section*),bool canchange=false); Section* GetSection(const char* _sectionname); + Section* GetSectionFromProperty(const char* prop); void SetStartUp(void (*_function)(void)); void Init(); @@ -196,12 +213,17 @@ public: void PrintConfig(const char* configfilename); bool ParseConfigFile(const char* configfilename); void ParseEnv(char ** envp); - - std::list sectionlist; - typedef std::list::iterator it; - typedef std::list::reverse_iterator reverse_it; -private: - void (* _start_function)(void); }; +class Module_base { + /* Base for all hardware and software "devices" */ +protected: + Section* m_configuration; +public: + Module_base(Section* configuration){m_configuration=configuration;}; +// Module_base(Section* configuration, SaveState* state) {}; + ~Module_base(){/*LOG_MSG("executed")*/;};//Destructors are required + /* Returns true if succesful.*/ + virtual bool Change_Config(Section* newconfig) {return false;} ; +}; #endif diff --git a/include/shell.h b/include/shell.h index 7e0accb..3bd8baf 100644 --- a/include/shell.h +++ b/include/shell.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,22 +16,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: shell.h,v 1.9 2004/11/13 12:06:39 qbix79 Exp $ */ - -#ifndef SHELL_H_ -#define SHELL_H_ +/* $Id: shell.h,v 1.15 2006/02/09 11:47:48 qbix79 Exp $ */ +#ifndef DOSBOX_SHELL_H +#define DOSBOX_SHELL_H #include -#include +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" -#include "mem.h" +#endif +#ifndef DOSBOX_PROGRAMS_H #include "programs.h" -#include "dos_inc.h" -#include "regs.h" -#include "support.h" -#include "callback.h" -#include "setup.h" +#endif #include #include @@ -40,6 +36,9 @@ #define CMD_MAXCMDS 20 #define CMD_OLDSIZE 4096 extern Bitu call_shellstop; +/* first_shell is used to add and delete stuff from the shell env + * by "external" programs. (config) */ +extern Program * first_shell; class DOS_Shell; @@ -75,7 +74,9 @@ public: void InputCommand(char * line); void ShowPrompt(); void DoCommand(char * cmd); - void Execute(char * name,char * args); + bool Execute(char * name,char * args); + /* Checks if it matches a hardware-property */ + bool CheckConfig(char* cmd,char*line); /* Some internal used functions */ char * Which(char * name); /* Some supported commands */ @@ -144,4 +145,20 @@ static inline char* ExpandDot(char*args, char* buffer) { return buffer; } +/* Object to manage lines in the autoexec.bat The lines get removed from + * the file if the object gets destroyed. The environment is updated + * as well if the line set a a variable */ +class AutoexecObject{ +private: + bool installed; + char buf[256]; +public: + AutoexecObject():installed(false){}; + void Install(char * line,...); + void InstallBefore(char* line, ...); + ~AutoexecObject(); +private: + void CreateAutoexec(void); +}; + #endif diff --git a/include/support.h b/include/support.h index 0fab9b2..83ee6ff 100644 --- a/include/support.h +++ b/include/support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,13 +16,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#if !defined __SUPPORT_H -#define __SUPPORT_H +#ifndef DOSBOX_SUPPORT_H +#define DOSBOX_SUPPORT_H #include #include - +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" +#endif #if defined (_MSC_VER) /* MS Visual C++ */ #define strcasecmp(a,b) stricmp(a,b) @@ -33,6 +34,8 @@ //#define nocasestrcmp(a,b) stricmp(a,b) #endif +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + #ifdef HAVE_STRINGS_H #include #endif @@ -62,4 +65,3 @@ INLINE char * lowcase(char * str) { #endif - diff --git a/include/timer.h b/include/timer.h index a807884..b6ebab9 100644 --- a/include/timer.h +++ b/include/timer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,8 +16,9 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef _TIMER_H_ -#define _TIMER_H_ +#ifndef DOSBOX_TIMER_H +#define DOSBOX_TIMER_H + /* underlying clock rate in HZ */ #include @@ -35,4 +36,3 @@ void TIMER_DelTickHandler(TIMER_TickHandler handler); void TIMER_AddTick(void); #endif - diff --git a/include/vga.h b/include/vga.h index a8814c0..8c365c9 100644 --- a/include/vga.h +++ b/include/vga.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,23 +16,26 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef VGA_H_ -#define VGA_H_ +#ifndef DOSBOX_VGA_H +#define DOSBOX_VGA_H -#include +#ifndef DOSBOX_DOSBOX_H #include "dosbox.h" +#endif + +class PageHandler; enum VGAModes { - M_CGA2,M_CGA4, - M_EGA16, - M_VGA, - M_LIN8, + M_CGA2, M_CGA4, + M_EGA, M_VGA, + M_LIN4, M_LIN8, M_LIN15, M_LIN16, M_LIN32, M_TEXT, - M_HERC_GFX,M_HERC_TEXT, - M_CGA16,M_TANDY2,M_TANDY4,M_TANDY16,M_TANDY_TEXT, + M_HERC_GFX, M_HERC_TEXT, + M_CGA16, M_TANDY2, M_TANDY4, M_TANDY16, M_TANDY_TEXT, M_ERROR, }; + #define CLK_25 25175 #define CLK_28 28322 @@ -61,6 +64,7 @@ typedef struct { /* Some other screen related variables */ Bitu line_compare; bool chained; /* Enable or Disabled Chain 4 Mode */ + bool compatible_chain4; /* Pixel Scrolling */ Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */ @@ -84,7 +88,6 @@ typedef struct { Bit32u full_not_enable_set_reset; Bit32u full_enable_set_reset; Bit32u full_enable_and_set_reset; - } VGA_Config; typedef struct { @@ -194,6 +197,8 @@ typedef struct { Bit8u gfx_control; Bit8u palette_mask; Bit8u border_color; + bool is_32k_mode; + bool pcjr_flipflop; } VGA_TANDY; typedef struct { @@ -287,10 +292,20 @@ union VGA_Memory { Bit8u linear[512*1024*4]; Bit8u paged[512*1024][4]; VGA_Latch latched[512*1024]; -}; +}; +typedef struct { + Bit32u page; + Bit32u addr; + Bit32u mask; + PageHandler *handler; +} VGA_LFB; + +#define VGA_CHANGE_SHIFT 9 +typedef Bit8u VGA_Changed[(2*1024*1024) >> VGA_CHANGE_SHIFT]; typedef struct { VGAModes mode; /* The mode the vga system is in */ + VGAModes lastmode; Bit8u misc_output; VGA_Draw draw; VGA_Config config; @@ -307,6 +322,9 @@ typedef struct { VGA_TANDY tandy; VGA_OTHER other; VGA_Memory mem; + VGA_LFB lfb; + VGA_Changed changed; + Bit8u * gfxmem_start; } VGA_Type; @@ -343,6 +361,15 @@ void VGA_StartUpdateLFB(void); void VGA_SetBlinking(Bitu enabled); void VGA_SetCGA2Table(Bit8u val0,Bit8u val1); void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3); +void VGA_ActivateHardwareCursor(void); +void VGA_KillDrawing(void); + +/* S3 Functions */ +Bitu SVGA_S3_GetClock(void); +void SVGA_S3_WriteCRTC(Bitu reg,Bitu val,Bitu iolen); +Bitu SVGA_S3_ReadCRTC(Bitu reg,Bitu iolen); +void SVGA_S3_WriteSEQ(Bitu reg,Bitu val,Bitu iolen); +Bitu SVGA_S3_ReadSEQ(Bitu reg,Bitu iolen); extern VGA_Type vga; @@ -350,6 +377,7 @@ extern Bit32u ExpandTable[256]; extern Bit32u FillTable[16]; extern Bit32u CGA_2_Table[16]; extern Bit32u CGA_4_Table[256]; +extern Bit32u CGA_4_HiRes_Table[256]; extern Bit32u CGA_16_Table[256]; extern Bit32u TXT_Font_Table[16]; extern Bit32u TXT_FG_Table[16]; @@ -359,4 +387,3 @@ extern Bit32u Expand16BigTable[0x10000]; #endif - diff --git a/include/video.h b/include/video.h index 4c3b807..e439369 100644 --- a/include/video.h +++ b/include/video.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,16 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef __VIDEO_H -#define __VIDEO_H +#ifndef DOSBOX_VIDEO_H +#define DOSBOX_VIDEO_H -typedef void (* GFX_ResetCallBack)(void); +typedef enum { + GFX_CallBackReset, + GFX_CallBackStop, + GFX_CallBackRedraw, +} GFX_CallBackFunctions_t; + +typedef void (*GFX_CallBack_t)( GFX_CallBackFunctions_t function ); struct GFX_PalEntry { Bit8u r; @@ -28,43 +34,38 @@ struct GFX_PalEntry { Bit8u unused; }; -#define CAN_8 0x0001 -#define CAN_16 0x0002 -#define CAN_32 0x0004 +#define GFX_CAN_8 0x0001 +#define GFX_CAN_15 0x0002 +#define GFX_CAN_16 0x0004 +#define GFX_CAN_32 0x0008 -#define CAN_ALL (CAN_8|CAN_16|CAN_32) +#define GFX_LOVE_8 0x0010 +#define GFX_LOVE_15 0x0020 +#define GFX_LOVE_16 0x0040 +#define GFX_LOVE_32 0x0080 -#define LOVE_8 0x0010 -#define LOVE_16 0x0020 -#define LOVE_32 0x0040 +#define GFX_RGBONLY 0x0100 -#define NEED_RGB 0x0100 -#define DONT_ASPECT 0x0200 +#define GFX_SCALING 0x1000 +#define GFX_HARDWARE 0x2000 -#define HAVE_SCALING 0x1000 - - -enum GFX_Modes { - GFX_8,GFX_15,GFX_16,GFX_32,GFX_NONE, -}; +#define GFX_CAN_RANDOM 0x4000 //If the interface can also do random access surface void GFX_Events(void); void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries); Bitu GFX_GetBestMode(Bitu flags); - Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue); -GFX_Modes GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_ResetCallBack cb_reset); +Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t cb); void GFX_ResetScreen(void); void GFX_Start(void); void GFX_Stop(void); void GFX_SwitchFullScreen(void); bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch); -void GFX_EndUpdate(void); +void GFX_EndUpdate( const Bit16u *changedLines ); /* Mouse related */ void GFX_CaptureMouse(void); extern bool mouselocked; //true if mouse is confined to window #endif - diff --git a/install-sh b/install-sh index 0b65ee8..dd97db7 100644 --- a/install-sh +++ b/install-sh @@ -1,7 +1,7 @@ #!/bin/sh # install - install a program, script, or datafile -scriptversion=2004-10-22.00 +scriptversion=2004-09-10.20 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the @@ -213,7 +213,7 @@ do fi # This sed command emulates the dirname command. - dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` + dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. @@ -226,8 +226,7 @@ do oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' - set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` - shift + set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` IFS=$oIFS pathcomp= diff --git a/src/Makefile.am b/src/Makefile.am index 24279b3..bccc59a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,10 +1,18 @@ AM_CPPFLAGS = -I$(top_srcdir)/include -SUBDIRS = cpu debug dos fpu gui hardware ints misc shell platform +SUBDIRS = cpu debug dos fpu gui hardware libs ints misc shell platform bin_PROGRAMS = dosbox dosbox_SOURCES = dosbox.cpp dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \ - ints/libints.a misc/libmisc.a shell/libshell.a + ints/libints.a misc/libmisc.a shell/libshell.a hardware/serialport/libserial.a + +if HAVE_WINDRES +dosbox_LDADD += dosbox_ico.o +endif + +EXTRA_DIST = dosbox.rc dosbox.ico +dosbox_ico.o: dosbox.rc dosbox.ico + $(WINDRES) dosbox.rc dosbox_ico.o diff --git a/src/Makefile.in b/src/Makefile.in index e9c7319..471bdbc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -40,6 +40,7 @@ build_triplet = @build@ host_triplet = @host@ target_triplet = @target@ bin_PROGRAMS = dosbox$(EXEEXT) +@HAVE_WINDRES_TRUE@am__append_1 = dosbox_ico.o subdir = src DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 @@ -55,9 +56,11 @@ binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) am_dosbox_OBJECTS = dosbox.$(OBJEXT) dosbox_OBJECTS = $(am_dosbox_OBJECTS) +@HAVE_WINDRES_TRUE@am__DEPENDENCIES_1 = dosbox_ico.o dosbox_DEPENDENCIES = cpu/libcpu.a debug/libdebug.a dos/libdos.a \ fpu/libfpu.a hardware/libhardware.a gui/libgui.a \ - ints/libints.a misc/libmisc.a shell/libshell.a + ints/libints.a misc/libmisc.a shell/libshell.a \ + hardware/serialport/libserial.a $(am__DEPENDENCIES_1) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles @@ -104,6 +107,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -129,10 +134,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -175,11 +182,13 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ AM_CPPFLAGS = -I$(top_srcdir)/include -SUBDIRS = cpu debug dos fpu gui hardware ints misc shell platform +SUBDIRS = cpu debug dos fpu gui hardware libs ints misc shell platform dosbox_SOURCES = dosbox.cpp -dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \ - ints/libints.a misc/libmisc.a shell/libshell.a - +dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a \ + hardware/libhardware.a gui/libgui.a ints/libints.a \ + misc/libmisc.a shell/libshell.a \ + hardware/serialport/libserial.a $(am__append_1) +EXTRA_DIST = dosbox.rc dosbox.ico all: all-recursive .SUFFIXES: @@ -245,7 +254,8 @@ installcheck-binPROGRAMS: $(bin_PROGRAMS) f=`echo "$$p" | \ sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ for opt in --help --version; do \ - if "$(DESTDIR)$(bindir)/$$f" $$opt > c$${pid}_.out 2> c$${pid}_.err \ + if "$(DESTDIR)$(bindir)/$$f" $$opt >c$${pid}_.out \ + 2>c$${pid}_.err &2; bad=1; fi; \ @@ -285,7 +295,13 @@ uninstall-info-am: # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -297,7 +313,7 @@ $(RECURSIVE_TARGETS): local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ @@ -305,7 +321,13 @@ $(RECURSIVE_TARGETS): mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ @@ -326,7 +348,7 @@ maintainer-clean-recursive: local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -537,6 +559,8 @@ uninstall-info: uninstall-info-recursive mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ uninstall uninstall-am uninstall-binPROGRAMS uninstall-info-am +dosbox_ico.o: dosbox.rc dosbox.ico + $(WINDRES) dosbox.rc dosbox_ico.o # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: diff --git a/src/cpu/Makefile.in b/src/cpu/Makefile.in index 7c1751d..ffd6634 100644 --- a/src/cpu/Makefile.in +++ b/src/cpu/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -109,6 +109,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -134,10 +136,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -265,7 +269,13 @@ uninstall-info-am: # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -277,7 +287,7 @@ $(RECURSIVE_TARGETS): local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ @@ -285,7 +295,13 @@ $(RECURSIVE_TARGETS): mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ @@ -306,7 +322,7 @@ maintainer-clean-recursive: local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index e64a48f..e35416f 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,28 +16,26 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: callback.cpp,v 1.22 2004/08/29 11:22:37 qbix79 Exp $ */ +/* $Id: callback.cpp,v 1.31 2006/02/12 23:28:21 harekiet Exp $ */ #include -#include #include #include "dosbox.h" #include "callback.h" #include "mem.h" #include "cpu.h" -#include "pic.h" /* CallBack are located at 0xC800:0 And they are 16 bytes each and you can define them to behave in certain ways like a far return or and IRET */ - CallBack_Handler CallBack_Handlers[CB_MAX]; char* CallBack_Description[CB_MAX]; static Bitu call_stop,call_idle,call_default; +Bitu call_priv_io; static Bitu illegal_handler(void) { E_Exit("Illegal CallBack Called"); @@ -55,6 +53,11 @@ Bitu CALLBACK_Allocate(void) { return 0; } +void CALLBACK_DeAllocate(Bitu in) { + CallBack_Handlers[in]=&illegal_handler; +} + + void CALLBACK_Idle(void) { /* this makes the cpu execute instructions to handle irq's and then come back */ Bitu oldIF=GETFLAG(IF); @@ -67,7 +70,8 @@ void CALLBACK_Idle(void) { reg_eip=oldeip; SegSet16(cs,oldcs); SETFLAGBIT(IF,oldIF); - if (CPU_Cycles>0) CPU_Cycles=0; + if (!CPU_CycleAuto && CPU_Cycles>0) + CPU_Cycles=0; } static Bitu default_handler(void) { @@ -104,8 +108,6 @@ void CALLBACK_RunRealInt(Bit8u intnum) { SegSet16(cs,oldcs); } - - void CALLBACK_SZF(bool val) { Bit16u tempf=mem_readw(SegPhys(ss)+reg_sp+4) & 0xFFBF; Bit16u newZF=(val==true) << 6; @@ -118,8 +120,7 @@ void CALLBACK_SCF(bool val) { mem_writew(SegPhys(ss)+reg_sp+4,(tempf | newCF)); }; -void CALLBACK_SetDescription(Bitu nr, const char* descr) -{ +void CALLBACK_SetDescription(Bitu nr, const char* descr) { if (descr) { CallBack_Description[nr] = new char[strlen(descr)+1]; strcpy(CallBack_Description[nr],descr); @@ -127,8 +128,7 @@ void CALLBACK_SetDescription(Bitu nr, const char* descr) CallBack_Description[nr] = 0; }; -const char* CALLBACK_GetDescription(Bitu nr) -{ +const char* CALLBACK_GetDescription(Bitu nr) { if (nr>=CB_MAX) return 0; return CallBack_Description[nr]; }; @@ -155,44 +155,100 @@ bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* phys_writew(CB_BASE+(callback<<4)+3,callback); //The immediate word phys_writeb(CB_BASE+(callback<<4)+5,(Bit8u)0xCF); //An IRET Instruction break; - default: E_Exit("CALLBACK:Setup:Illegal type %d",type); - } CallBack_Handlers[callback]=handler; CALLBACK_SetDescription(callback,descr); return true; } -bool CALLBACK_SetupAt(Bitu callback,CallBack_Handler handler,Bitu type,Bitu linearAddress,const char* descr) { - if (callback>=CB_MAX) return false; +void CALLBACK_RemoveSetup(Bitu callback) { + for (Bitu i = 0;i < 16;i++) { + phys_writeb(CB_BASE+(callback<<4)+i ,(Bit8u) 0x00); + } +} + +Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress) { + if (callback>=CB_MAX) + return 0; switch (type) { + case CB_RETN: + phys_writeb(physAddress+0,(Bit8u)0xFE); //GRP 4 + phys_writeb(physAddress+1,(Bit8u)0x38); //Extra Callback instruction + phys_writew(physAddress+2, callback); //The immediate word + phys_writeb(physAddress+4,(Bit8u)0xC3); //A RETN Instruction + return 5; case CB_RETF: - mem_writeb(linearAddress+0,(Bit8u)0xFE); //GRP 4 - mem_writeb(linearAddress+1,(Bit8u)0x38); //Extra Callback instruction - mem_writew(linearAddress+2, callback); //The immediate word - mem_writeb(linearAddress+4,(Bit8u)0xCB); //A RETF Instruction - break; + phys_writeb(physAddress+0,(Bit8u)0xFE); //GRP 4 + phys_writeb(physAddress+1,(Bit8u)0x38); //Extra Callback instruction + phys_writew(physAddress+2, callback); //The immediate word + phys_writeb(physAddress+4,(Bit8u)0xCB); //A RETF Instruction + return 5; case CB_IRET: - mem_writeb(linearAddress+0,(Bit8u)0xFE); //GRP 4 - mem_writeb(linearAddress+1,(Bit8u)0x38); //Extra Callback instruction - mem_writew(linearAddress+2,callback); //The immediate word - mem_writeb(linearAddress+4,(Bit8u)0xCF); //An IRET Instruction - break; + phys_writeb(physAddress+0,(Bit8u)0xFE); //GRP 4 + phys_writeb(physAddress+1,(Bit8u)0x38); //Extra Callback instruction + phys_writew(physAddress+2,callback); //The immediate word + phys_writeb(physAddress+4,(Bit8u)0xCF); //An IRET Instruction + return 5; case CB_IRET_STI: - mem_writeb(linearAddress+0,(Bit8u)0xFB); //STI - mem_writeb(linearAddress+1,(Bit8u)0xFE); //GRP 4 - mem_writeb(linearAddress+2,(Bit8u)0x38); //Extra Callback instruction - mem_writew(linearAddress+3, callback); //The immediate word - mem_writeb(linearAddress+5,(Bit8u)0xCF); //An IRET Instruction - break; + phys_writeb(physAddress+0,(Bit8u)0xFB); //STI + phys_writeb(physAddress+1,(Bit8u)0xFE); //GRP 4 + phys_writeb(physAddress+2,(Bit8u)0x38); //Extra Callback instruction + phys_writew(physAddress+3, callback); //The immediate word + phys_writeb(physAddress+5,(Bit8u)0xCF); //An IRET Instruction + return 6; default: E_Exit("CALLBACK:Setup:Illegal type %d",type); } - CallBack_Handlers[callback]=handler; - CALLBACK_SetDescription(callback,descr); - return true; + return 0; +} + +CALLBACK_HandlerObject::~CALLBACK_HandlerObject(){ + if(!installed) return; + if(m_type == CALLBACK_HandlerObject::SETUP) { + if(vectorhandler.installed){ + //See if we are the current handler. if so restore the old one + if(RealGetVec(vectorhandler.interrupt) == Get_RealPointer()) { + RealSetVec(vectorhandler.interrupt,vectorhandler.old_vector); + } else + LOG(LOG_MISC,LOG_WARN)("Interrupt vector changed on %X %s",vectorhandler.interrupt,CALLBACK_GetDescription(m_callback)); + } + CALLBACK_RemoveSetup(m_callback); + } else if(m_type == CALLBACK_HandlerObject::SETUPAT){ + E_Exit("Callback:SETUP at not handled yet."); + } else if(m_type == CALLBACK_HandlerObject::NONE){ + //Do nothing. Merely DeAllocate the callback + } else E_Exit("what kind of callback is this!"); + if(CallBack_Description[m_callback]) delete [] CallBack_Description[m_callback]; + CallBack_Description[m_callback] = 0; + CALLBACK_DeAllocate(m_callback); +} + +void CALLBACK_HandlerObject::Install(CallBack_Handler handler,Bitu type,const char* description){ + if(!installed) { + installed=true; + m_type=SETUP; + m_callback=CALLBACK_Allocate(); + CALLBACK_Setup(m_callback,handler,type,description); + } else E_Exit("Allready installed"); +} +void CALLBACK_HandlerObject::Allocate(CallBack_Handler handler,const char* description) { + if(!installed) { + installed=true; + m_type=NONE; + m_callback=CALLBACK_Allocate(); + CALLBACK_SetDescription(m_callback,description); + CallBack_Handlers[m_callback]=handler; + } else E_Exit("Allready installed"); +} + +void CALLBACK_HandlerObject::Set_RealVec(Bit8u vec){ + if(!vectorhandler.installed) { + vectorhandler.installed=true; + vectorhandler.interrupt=vec; + RealSetVec(vec,Get_RealPointer(),vectorhandler.old_vector); + } else E_Exit ("double usage of vector handler"); } void CALLBACK_Init(Section* sec) { @@ -219,6 +275,7 @@ void CALLBACK_Init(Section* sec) { /* Setup all Interrupt to point to the default handler */ call_default=CALLBACK_Allocate(); CALLBACK_Setup(call_default,&default_handler,CB_IRET,"default"); + /* Only setup default handler for first half of interrupt table */ for (i=0;i<0x40;i++) { real_writed(0,i*4,CALLBACK_RealPointer(call_default)); @@ -237,6 +294,22 @@ void CALLBACK_Init(Section* sec) { real_writed(0,0x67*4,CALLBACK_RealPointer(call_default)); real_writed(0,0x5c*4,CALLBACK_RealPointer(call_default)); //Network stuff //real_writed(0,0xf*4,0); some games don't like it + + call_priv_io=CALLBACK_Allocate(); + + phys_writeb(CB_BASE+(call_priv_io<<4)+0x00,(Bit8u)0xec); // in al, dx + phys_writeb(CB_BASE+(call_priv_io<<4)+0x01,(Bit8u)0xcb); // retf + phys_writeb(CB_BASE+(call_priv_io<<4)+0x02,(Bit8u)0xed); // in ax, dx + phys_writeb(CB_BASE+(call_priv_io<<4)+0x03,(Bit8u)0xcb); // retf + phys_writeb(CB_BASE+(call_priv_io<<4)+0x04,(Bit8u)0x66); // in eax, dx + phys_writeb(CB_BASE+(call_priv_io<<4)+0x05,(Bit8u)0xed); + phys_writeb(CB_BASE+(call_priv_io<<4)+0x06,(Bit8u)0xcb); // retf + + phys_writeb(CB_BASE+(call_priv_io<<4)+0x08,(Bit8u)0xee); // out dx, al + phys_writeb(CB_BASE+(call_priv_io<<4)+0x09,(Bit8u)0xcb); // retf + phys_writeb(CB_BASE+(call_priv_io<<4)+0x0a,(Bit8u)0xef); // out dx, ax + phys_writeb(CB_BASE+(call_priv_io<<4)+0x0b,(Bit8u)0xcb); // retf + phys_writeb(CB_BASE+(call_priv_io<<4)+0x0c,(Bit8u)0x66); // out dx, eax + phys_writeb(CB_BASE+(call_priv_io<<4)+0x0d,(Bit8u)0xef); + phys_writeb(CB_BASE+(call_priv_io<<4)+0x0e,(Bit8u)0xcb); // retf } - - diff --git a/src/cpu/core_dyn_x86.cpp b/src/cpu/core_dyn_x86.cpp index 1cda8ba..5dd4e64 100644 --- a/src/cpu/core_dyn_x86.cpp +++ b/src/cpu/core_dyn_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -20,10 +20,23 @@ #if (C_DYNAMIC_X86) +#define CHECKED_MEMORY_ACCESS + #include #include #include #include +#include +#include + +#if (C_HAVE_MPROTECT) +#include + +#include +#ifndef PAGESIZE +#define PAGESIZE 4096 +#endif +#endif /* C_HAVE_MPROTECT */ #include "callback.h" #include "regs.h" @@ -33,11 +46,15 @@ #include "paging.h" #include "inout.h" -#define CACHE_TOTAL (512*1024) +#ifdef CHECKED_MEMORY_ACCESS +#define CACHE_MAXSIZE (4096*2) +#else #define CACHE_MAXSIZE (4096) -#define CACHE_BLOCKS (32*1024) +#endif +#define CACHE_PAGES (128*8) +#define CACHE_TOTAL (CACHE_PAGES*4096) +#define CACHE_BLOCKS (64*1024) #define CACHE_ALIGN (16) -#define CACHE_PAGES (128) #define DYN_HASH_SHIFT (4) #define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT) #define DYN_LINKS (16) @@ -48,6 +65,10 @@ #define DYN_LOG #endif +#if C_FPU +#define CPU_FPU 1 //Enable FPU escape instructions +#endif + enum { G_EAX,G_ECX,G_EDX,G_EBX, G_ESP,G_EBP,G_ESI,G_EDI, @@ -98,8 +119,12 @@ enum BlockReturn { BR_OpcodeFull, #endif BR_CallBack, + BR_SMCBlock }; +#define SMC_CURRENT_BLOCK 0xffff + + #define DYNFLG_HAS16 0x1 //Would like 8-bit host reg support #define DYNFLG_HAS8 0x2 //Would like 16-bit host reg support #define DYNFLG_LOAD 0x4 //Load value when accessed @@ -133,14 +158,14 @@ static struct { Bitu ea,tmpb,tmpd,stack,shift; } extra_regs; -static void IllegalOption(void) { - E_Exit("Illegal option"); +static void IllegalOption(const char* msg) { + E_Exit("DynCore: illegal option in %s",msg); } #include "core_dyn_x86/cache.h" static struct { - Bitu callback; + Bitu callback,readdata; } core_dyn; @@ -180,12 +205,23 @@ static void dyn_loadstate(DynState * state) { } } - static void dyn_synchstate(DynState * state) { for (Bitu i=0;iregs[i]); } } + +static void dyn_saveregister(DynReg * src_reg, DynReg * dst_reg) { + dst_reg->flags=src_reg->flags; + dst_reg->genreg=src_reg->genreg; +} + +static void dyn_restoreregister(DynReg * src_reg, DynReg * dst_reg) { + dst_reg->flags=src_reg->flags; + dst_reg->genreg=src_reg->genreg; + dst_reg->genreg->dynreg=dst_reg; // necessary when register has been released +} + #include "core_dyn_x86/decoder.h" Bits CPU_Core_Dyn_X86_Run(void) { @@ -220,6 +256,10 @@ run_block: return CBRET_NONE; case BR_CallBack: return core_dyn.callback; + case BR_SMCBlock: +// LOG_MSG("selfmodification of running block at %x:%x",SegValue(cs),reg_eip); + cpu.exception.which=0; + // fallthrough, let the normal core handle the block-modifying instruction case BR_Opcode: CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=1; @@ -306,11 +346,14 @@ void CPU_Core_Dyn_X86_Init(void) { DynRegs[G_SHIFT].flags=DYNFLG_HAS8|DYNFLG_HAS16; DynRegs[G_EXIT].data=0; DynRegs[G_EXIT].flags=DYNFLG_HAS16; - /* Initialize code cache and dynamic blocks */ - cache_init(); /* Init the generator */ gen_init(); return; } +void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache) { + /* Initialize code cache and dynamic blocks */ + cache_init(enable_cache); +} + #endif diff --git a/src/cpu/core_dyn_x86/Makefile.in b/src/cpu/core_dyn_x86/Makefile.in index 17f1707..1cc69a1 100644 --- a/src/cpu/core_dyn_x86/Makefile.in +++ b/src/cpu/core_dyn_x86/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -80,6 +80,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -105,10 +107,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/cpu/core_dyn_x86/cache.h b/src/cpu/core_dyn_x86/cache.h index 348021d..07ff1b9 100644 --- a/src/cpu/core_dyn_x86/cache.h +++ b/src/cpu/core_dyn_x86/cache.h @@ -42,10 +42,14 @@ static struct { CodePageHandler * last_page; } cache; +#if (C_HAVE_MPROTECT) +static Bit8u cache_code_link_blocks[2][16] GCC_ATTRIBUTE(aligned(PAGESIZE)); +#else static Bit8u cache_code_link_blocks[2][16]; -static Bit8u cache_code[CACHE_TOTAL+CACHE_MAXSIZE]; -static CacheBlock cache_blocks[CACHE_BLOCKS]; +#endif + static CacheBlock link_blocks[2]; + class CodePageHandler :public PageHandler { public: CodePageHandler() {} @@ -59,21 +63,27 @@ public: memset(&hash_map,0,sizeof(hash_map)); memset(&write_map,0,sizeof(write_map)); } - void InvalidateRange(Bitu start,Bitu end) { + bool InvalidateRange(Bitu start,Bitu end) { Bits index=1+(start>>DYN_HASH_SHIFT); + bool is_current_block=false; + Bit32u ip_point=SegPhys(cs)+reg_eip; + ip_point=((paging.tlb.phys_page[ip_point>>12]-phys_page)<<12)+(ip_point&0xfff); while (index>=0) { Bitu map=0; for (Bitu count=start;count<=end;count++) map+=write_map[count]; - if (!map) return; + if (!map) return is_current_block; CacheBlock * block=hash_map[index]; while (block) { CacheBlock * nextblock=block->hash.next; - if (start<=block->page.end && end>=block->page.start) + if (start<=block->page.end && end>=block->page.start) { + if (ip_point<=block->page.end && ip_point>=block->page.start) is_current_block=true; block->Clear(); + } block=nextblock; } index--; } + return is_current_block; } void writeb(PhysPt addr,Bitu val){ addr&=4095; @@ -102,6 +112,48 @@ public: if (!active_count) Release(); } else InvalidateRange(addr,addr+3); } + bool writeb_checked(PhysPt addr,Bitu val) { + addr&=4095; + if (!*(Bit8u*)&write_map[addr]) { + if (!active_blocks) { + active_count--; + if (!active_count) Release(); + } + } else if (InvalidateRange(addr,addr)) { + cpu.exception.which=SMC_CURRENT_BLOCK; + return true; + } + host_writeb(hostmem+addr,val); + return false; + } + bool writew_checked(PhysPt addr,Bitu val) { + addr&=4095; + if (!*(Bit16u*)&write_map[addr]) { + if (!active_blocks) { + active_count--; + if (!active_count) Release(); + } + } else if (InvalidateRange(addr,addr+1)) { + cpu.exception.which=SMC_CURRENT_BLOCK; + return true; + } + host_writew(hostmem+addr,val); + return false; + } + bool writed_checked(PhysPt addr,Bitu val) { + addr&=4095; + if (!*(Bit32u*)&write_map[addr]) { + if (!active_blocks) { + active_count--; + if (!active_count) Release(); + } + } else if (InvalidateRange(addr,addr+3)) { + cpu.exception.which=SMC_CURRENT_BLOCK; + return true; + } + host_writed(hostmem+addr,val); + return false; + } void AddCacheBlock(CacheBlock * block) { Bitu index=1+(block->page.start>>DYN_HASH_SHIFT); block->hash.next=hash_map[index]; @@ -161,10 +213,13 @@ public: } return 0; } - HostPt GetHostPt(Bitu phys_page) { - hostmem=old_pagehandler->GetHostPt(phys_page); + HostPt GetHostReadPt(Bitu phys_page) { + hostmem=old_pagehandler->GetHostReadPt(phys_page); return hostmem; } + HostPt GetHostWritePt(Bitu phys_page) { + return GetHostReadPt( phys_page ); + } public: Bit8u write_map[4096]; CodePageHandler * next, * prev; @@ -235,10 +290,13 @@ void CacheBlock::Clear(void) { } if (link[ind].to!=&link_blocks[ind]) { CacheBlock * * wherelink=&link[ind].to->link[ind].from; - while (*wherelink!=this) { - wherelink=&(*wherelink)->link[ind].next; + while (*wherelink != this && *wherelink) { + wherelink = &(*wherelink)->link[ind].next; } - *wherelink=(*wherelink)->link[ind].next; + if(*wherelink) + *wherelink = (*wherelink)->link[ind].next; + else + LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate"); } } else cache_addunsedblock(this); @@ -332,34 +390,68 @@ static INLINE void cache_addd(Bit32u val) { static void gen_return(BlockReturn retcode); -static void cache_init(void) { +static Bit8u * cache_code=NULL; +static CacheBlock * cache_blocks=NULL; + +/* Define temporary pagesize so the MPROTECT case and the regular case share as much code as possible */ +#if (C_HAVE_MPROTECT) +#define PAGESIZE_TEMP PAGESIZE +#else +#define PAGESIZE_TEMP 1 +#endif + + +static void cache_init(bool enable) { + static bool cache_initialized = false; Bits i; - memset(&cache_blocks,0,sizeof(cache_blocks)); - cache.block.free=&cache_blocks[0]; - for (i=0;icache.start=&cache_code[0]; - block->cache.size=CACHE_TOTAL; - block->cache.next=0; //Last block in the list - cache.pos=&cache_code_link_blocks[0][0]; - link_blocks[0].cache.start=cache.pos; - gen_return(BR_Link1); - cache.pos=&cache_code_link_blocks[1][0]; - link_blocks[1].cache.start=cache.pos; - gen_return(BR_Link2); - cache.free_pages=0; - cache.last_page=0; - cache.used_pages=0; - /* Setup the code pages */ - for (i=0;inext=cache.free_pages; - cache.free_pages=newpage; + if (enable) { + if (cache_initialized) return; + cache_initialized = true; + if (cache_blocks == NULL) { + cache_blocks=(CacheBlock*)malloc(CACHE_BLOCKS*sizeof(CacheBlock)); + if(!cache_blocks) E_Exit("Allocating cache_blocks has failed"); + memset(cache_blocks,0,sizeof(CacheBlock)*CACHE_BLOCKS); + cache.block.free=&cache_blocks[0]; + for (i=0;icache.start=&cache_code[0]; + block->cache.size=CACHE_TOTAL; + block->cache.next=0; //Last block in the list + } + /* Setup the default blocks for block linkage returns */ + cache.pos=&cache_code_link_blocks[0][0]; + link_blocks[0].cache.start=cache.pos; + gen_return(BR_Link1); + cache.pos=&cache_code_link_blocks[1][0]; + link_blocks[1].cache.start=cache.pos; + gen_return(BR_Link2); + cache.free_pages=0; + cache.last_page=0; + cache.used_pages=0; + /* Setup the code pages */ + for (i=0;inext=cache.free_pages; + cache.free_pages=newpage; + } } } diff --git a/src/cpu/core_dyn_x86/decoder.h b/src/cpu/core_dyn_x86/decoder.h index 7027c65..19dc1a4 100644 --- a/src/cpu/core_dyn_x86/decoder.h +++ b/src/cpu/core_dyn_x86/decoder.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "fpu.h" +#define DYN_FPU_ESC(code) { \ + dyn_get_modrm(); \ + if (decode.modrm.val >= 0xc0) { \ + gen_call_function((void*)&FPU_ESC ## code ## _Normal,"%Id",decode.modrm.val); \ + } else { \ + dyn_fill_ea(); \ + gen_call_function((void*)&FPU_ESC ## code ## _EA,"%Id%Dd",decode.modrm.val,DREG(EA)); \ + gen_releasereg(DREG(EA)); \ + } \ +} + enum REP_Type { REP_NONE=0,REP_NZ,REP_Z }; @@ -88,24 +100,6 @@ static Bit32u decode_fetchd(void) { return mem_readd(decode.code-4); } -static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) { - if (high) gen_call_function((void *)&mem_readb,"%Dd%Rh",addr,dst); - else gen_call_function((void *)&mem_readb,"%Dd%Rl",addr,dst); -} -static void dyn_write_byte(DynReg * addr,DynReg * val,Bitu high) { - if (high) gen_call_function((void *)&mem_writeb,"%Dd%Dh",addr,val); - else gen_call_function((void *)&mem_writeb,"%Dd%Dl",addr,val); -} - -static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) { - if (dword) gen_call_function((void *)&mem_readd,"%Dd%Rd",addr,dst); - else gen_call_function((void *)&mem_readw,"%Dd%Rw",addr,dst); -} - -static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { - if (dword) gen_call_function((void *)&mem_writed,"%Dd%Dd",addr,val); - else gen_call_function((void *)&mem_writew,"%Dd%Dw",addr,val); -} static void dyn_reduce_cycles(void) { gen_protectflags(); @@ -113,7 +107,7 @@ static void dyn_reduce_cycles(void) { gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles); } -static void dyn_save_critical_regs(void) { +static void dyn_save_noncritical_regs(void) { gen_releasereg(DREG(EAX)); gen_releasereg(DREG(ECX)); gen_releasereg(DREG(EDX)); @@ -122,6 +116,10 @@ static void dyn_save_critical_regs(void) { gen_releasereg(DREG(EBP)); gen_releasereg(DREG(ESI)); gen_releasereg(DREG(EDI)); +} + +static void dyn_save_critical_regs(void) { + dyn_save_noncritical_regs(); gen_releasereg(DREG(FLAGS)); gen_releasereg(DREG(EIP)); gen_releasereg(DREG(CYCLES)); @@ -135,23 +133,188 @@ static void dyn_set_eip_last_end(DynReg * endreg) { static INLINE void dyn_set_eip_end(void) { gen_protectflags(); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),decode.code-decode.code_start); + gen_dop_word_imm(DOP_ADD,cpu.code.big,DREG(EIP),decode.code-decode.code_start); +} + +static INLINE void dyn_set_eip_end(DynReg * endreg) { + gen_protectflags(); + gen_dop_word(DOP_MOV,cpu.code.big,DREG(TMPW),DREG(EIP)); + gen_dop_word_imm(DOP_ADD,cpu.code.big,DREG(TMPW),decode.code-decode.code_start); } static INLINE void dyn_set_eip_last(void) { gen_protectflags(); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),decode.op_start-decode.code_start); + gen_dop_word_imm(DOP_ADD,cpu.code.big,DREG(EIP),decode.op_start-decode.code_start); } -static void dyn_push(DynReg * dynreg) { + +enum save_info_type {exception, cycle_check, normal}; + +struct { + save_info_type type; + DynState state; + Bit8u * branch_pos; + Bit32u eip_change; + Bitu cycles; +} save_info[512]; + +Bitu used_save_info=0; + + +static BlockReturn DynRunException(Bit32u eip_add,Bit32u cycle_sub,Bit32u dflags) { + reg_flags=(dflags&FMASK_TEST) | (reg_flags&(~FMASK_TEST)); + reg_eip+=eip_add; + CPU_Cycles-=cycle_sub; + if (cpu.exception.which==SMC_CURRENT_BLOCK) return BR_SMCBlock; + CPU_Exception(cpu.exception.which,cpu.exception.error); + return BR_Normal; +} + +static void dyn_check_bool_exception(DynReg * check) { + gen_dop_byte(DOP_OR,check,0,check,0); + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ); + dyn_savestate(&save_info[used_save_info].state); + if (!decode.cycles) decode.cycles++; + save_info[used_save_info].cycles=decode.cycles; + save_info[used_save_info].eip_change=decode.op_start-decode.code_start; + if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff; + save_info[used_save_info].type=exception; + used_save_info++; +} + +static void dyn_check_bool_exception_al(void) { + cache_addw(0xc00a); // or al, al + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ); + dyn_savestate(&save_info[used_save_info].state); + if (!decode.cycles) decode.cycles++; + save_info[used_save_info].cycles=decode.cycles; + save_info[used_save_info].eip_change=decode.op_start-decode.code_start; + if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff; + save_info[used_save_info].type=exception; + used_save_info++; +} + +static void dyn_fill_blocks(void) { + for (Bitu sct=0; sctlink[0].to,offsetof(CacheBlock,cache.start)); - gen_fill_branch(data); - /* Branch taken */ - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),eip_base+eip_add); - gen_releasereg(DREG(EIP)); - gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start)); - dyn_closeblock(); + + /* Branch not taken */ + dyn_reduce_cycles(); + gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),eip_base); + gen_releasereg(DREG(CYCLES)); + gen_releasereg(DREG(EIP)); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + gen_fill_branch(data); + + /* Branch taken */ + dyn_restoreregister(&save_cycles,DREG(CYCLES)); + dyn_restoreregister(&save_eip,DREG(EIP)); + dyn_reduce_cycles(); + gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),eip_base+eip_add); + gen_releasereg(DREG(CYCLES)); + gen_releasereg(DREG(EIP)); + gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); } enum LoopTypes { @@ -915,9 +1201,10 @@ static void dyn_call_near_imm(void) { Bits imm; if (decode.big_op) imm=(Bit32s)decode_fetchd(); else imm=(Bit16s)decode_fetchw(); - dyn_set_eip_end(); - dyn_push(DREG(EIP)); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),imm); + dyn_set_eip_end(DREG(TMPW)); + dyn_push(DREG(TMPW)); + gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(TMPW),imm); + gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),DREG(TMPW)); dyn_reduce_cycles(); dyn_save_critical_regs(); gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); @@ -931,8 +1218,7 @@ static void dyn_ret_far(Bitu bytes) { dyn_flags_gen_to_host(); dyn_save_critical_regs(); gen_call_function((void*)&CPU_RET,"%Id%Id%Drd",decode.big_op,bytes,DREG(TMPW)); - dyn_flags_host_to_gen(); - gen_return(BR_Normal); + gen_return_fast(BR_Normal); dyn_closeblock(); } @@ -945,8 +1231,7 @@ static void dyn_call_far_imm(void) { dyn_flags_gen_to_host(); dyn_save_critical_regs(); gen_call_function((void*)&CPU_CALL,"%Id%Id%Id%Drd",decode.big_op,sel,off,DREG(TMPW)); - dyn_flags_host_to_gen(); - gen_return(BR_Normal); + gen_return_fast(BR_Normal); dyn_closeblock(); } @@ -960,8 +1245,7 @@ static void dyn_jmp_far_imm(void) { dyn_flags_gen_to_host(); dyn_save_critical_regs(); gen_call_function((void*)&CPU_JMP,"%Id%Id%Id%Drd",decode.big_op,sel,off,DREG(TMPW)); - dyn_flags_host_to_gen(); - gen_return(BR_Normal); + gen_return_fast(BR_Normal); dyn_closeblock(); } @@ -972,8 +1256,7 @@ static void dyn_iret(void) { dyn_set_eip_last_end(DREG(TMPW)); dyn_save_critical_regs(); gen_call_function((void*)&CPU_IRET,"%Id%Drd",decode.big_op,DREG(TMPW)); - dyn_flags_host_to_gen(); - gen_return(BR_Normal); + gen_return_fast(BR_Normal); dyn_closeblock(); } @@ -984,8 +1267,7 @@ static void dyn_interrupt(Bitu num) { dyn_set_eip_last_end(DREG(TMPW)); dyn_save_critical_regs(); gen_call_function((void*)&CPU_Interrupt,"%Id%Id%Drd",num,CPU_INT_SOFTWARE,DREG(TMPW)); - dyn_flags_host_to_gen(); - gen_return(BR_Normal); + gen_return_fast(BR_Normal); dyn_closeblock(); } @@ -1012,9 +1294,9 @@ static CacheBlock * CreateCacheBlock(CodePageHandler * codepage,PhysPt start,Bit /* Start with the cycles check */ gen_protectflags(); gen_dop_word_imm(DOP_CMP,true,DREG(CYCLES),0); - Bit8u * cyclebranch=gen_create_branch(BR_NLE); - gen_return(BR_Cycles); - gen_fill_branch(cyclebranch); + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_LE); + save_info[used_save_info].type=cycle_check; + used_save_info++; gen_releasereg(DREG(CYCLES)); decode.cycles=0; while (max_opcodes--) { @@ -1033,8 +1315,8 @@ restart_prefix: case 0x01:dyn_dop_evgv(DOP_ADD);break; case 0x02:dyn_dop_gbeb(DOP_ADD);break; case 0x03:dyn_dop_gvev(DOP_ADD);break; - case 0x04:gen_needflags();gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break; - case 0x05:gen_needflags();gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x04:gen_discardflags();gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break; + case 0x05:gen_discardflags();gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x06:dyn_push_seg(es);break; case 0x07:dyn_pop_seg(es);break; @@ -1042,8 +1324,8 @@ restart_prefix: case 0x09:dyn_dop_evgv(DOP_OR);break; case 0x0a:dyn_dop_gbeb(DOP_OR);break; case 0x0b:dyn_dop_gvev(DOP_OR);break; - case 0x0c:gen_needflags();gen_dop_byte_imm(DOP_OR,DREG(EAX),0,decode_fetchb());break; - case 0x0d:gen_needflags();gen_dop_word_imm(DOP_OR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x0c:gen_discardflags();gen_dop_byte_imm(DOP_OR,DREG(EAX),0,decode_fetchb());break; + case 0x0d:gen_discardflags();gen_dop_word_imm(DOP_OR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x0e:dyn_push_seg(cs);break; case 0x0f: { @@ -1089,8 +1371,8 @@ restart_prefix: case 0x11:dyn_dop_evgv(DOP_ADC);break; case 0x12:dyn_dop_gbeb(DOP_ADC);break; case 0x13:dyn_dop_gvev(DOP_ADC);break; - case 0x14:gen_needflags();gen_dop_byte_imm(DOP_ADC,DREG(EAX),0,decode_fetchb());break; - case 0x15:gen_needflags();gen_dop_word_imm(DOP_ADC,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x14:gen_needcarry();gen_dop_byte_imm(DOP_ADC,DREG(EAX),0,decode_fetchb());break; + case 0x15:gen_needcarry();gen_dop_word_imm(DOP_ADC,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x16:dyn_push_seg(ss);break; case 0x17:dyn_pop_seg(ss);break; @@ -1098,48 +1380,48 @@ restart_prefix: case 0x19:dyn_dop_evgv(DOP_SBB);break; case 0x1a:dyn_dop_gbeb(DOP_SBB);break; case 0x1b:dyn_dop_gvev(DOP_SBB);break; - case 0x1c:gen_needflags();gen_dop_byte_imm(DOP_SBB,DREG(EAX),0,decode_fetchb());break; - case 0x1d:gen_needflags();gen_dop_word_imm(DOP_SBB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x1c:gen_needcarry();gen_dop_byte_imm(DOP_SBB,DREG(EAX),0,decode_fetchb());break; + case 0x1d:gen_needcarry();gen_dop_word_imm(DOP_SBB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x1e:dyn_push_seg(ds);break; case 0x1f:dyn_pop_seg(ds);break; case 0x20:dyn_dop_ebgb(DOP_AND);break; case 0x21:dyn_dop_evgv(DOP_AND);break; case 0x22:dyn_dop_gbeb(DOP_AND);break; case 0x23:dyn_dop_gvev(DOP_AND);break; - case 0x24:gen_needflags();gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break; - case 0x25:gen_needflags();gen_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x24:gen_discardflags();gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break; + case 0x25:gen_discardflags();gen_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x26:dyn_segprefix(es);goto restart_prefix; case 0x28:dyn_dop_ebgb(DOP_SUB);break; case 0x29:dyn_dop_evgv(DOP_SUB);break; case 0x2a:dyn_dop_gbeb(DOP_SUB);break; case 0x2b:dyn_dop_gvev(DOP_SUB);break; - case 0x2c:gen_needflags();gen_dop_byte_imm(DOP_SUB,DREG(EAX),0,decode_fetchb());break; - case 0x2d:gen_needflags();gen_dop_word_imm(DOP_SUB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x2c:gen_discardflags();gen_dop_byte_imm(DOP_SUB,DREG(EAX),0,decode_fetchb());break; + case 0x2d:gen_discardflags();gen_dop_word_imm(DOP_SUB,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x2e:dyn_segprefix(cs);goto restart_prefix; case 0x30:dyn_dop_ebgb(DOP_XOR);break; case 0x31:dyn_dop_evgv(DOP_XOR);break; case 0x32:dyn_dop_gbeb(DOP_XOR);break; case 0x33:dyn_dop_gvev(DOP_XOR);break; - case 0x34:gen_needflags();gen_dop_byte_imm(DOP_XOR,DREG(EAX),0,decode_fetchb());break; - case 0x35:gen_needflags();gen_dop_word_imm(DOP_XOR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x34:gen_discardflags();gen_dop_byte_imm(DOP_XOR,DREG(EAX),0,decode_fetchb());break; + case 0x35:gen_discardflags();gen_dop_word_imm(DOP_XOR,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x36:dyn_segprefix(ss);goto restart_prefix; case 0x38:dyn_dop_ebgb(DOP_CMP);break; case 0x39:dyn_dop_evgv(DOP_CMP);break; case 0x3a:dyn_dop_gbeb(DOP_CMP);break; case 0x3b:dyn_dop_gvev(DOP_CMP);break; - case 0x3c:gen_needflags();gen_dop_byte_imm(DOP_CMP,DREG(EAX),0,decode_fetchb());break; - case 0x3d:gen_needflags();gen_dop_word_imm(DOP_CMP,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x3c:gen_discardflags();gen_dop_byte_imm(DOP_CMP,DREG(EAX),0,decode_fetchb());break; + case 0x3d:gen_discardflags();gen_dop_word_imm(DOP_CMP,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; case 0x3e:dyn_segprefix(ds);goto restart_prefix; /* INC/DEC general register */ case 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47: - gen_needflags();gen_sop_word(SOP_INC,decode.big_op,&DynRegs[opcode&7]); + gen_needcarry();gen_sop_word(SOP_INC,decode.big_op,&DynRegs[opcode&7]); break; case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f: - gen_needflags();gen_sop_word(SOP_DEC,decode.big_op,&DynRegs[opcode&7]); + gen_needcarry();gen_sop_word(SOP_DEC,decode.big_op,&DynRegs[opcode&7]); break; /* PUSH/POP General register */ case 0x50:case 0x51:case 0x52:case 0x53:case 0x55:case 0x56:case 0x57: @@ -1156,13 +1438,13 @@ restart_prefix: case 0x60: /* PUSHA */ gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP)); for (i=G_EAX;i<=G_EDI;i++) { - dyn_push((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW)); + dyn_push_unchecked((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW)); } gen_releasereg(DREG(TMPW)); break; case 0x61: /* POPA */ for (i=G_EDI;i>=G_EAX;i--) { - dyn_pop((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW)); + dyn_pop_unchecked((i!=G_ESP) ? &DynRegs[i] : DREG(TMPW)); } gen_releasereg(DREG(TMPW)); break; @@ -1213,9 +1495,14 @@ restart_prefix: case 0x8c:dyn_mov_ev_seg();break; /* LEA Gv */ case 0x8d: - dyn_get_modrm();dyn_fill_ea(false); - gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(EA)); - gen_releasereg(DREG(EA)); + dyn_get_modrm(); + if (decode.big_op) { + dyn_fill_ea(false,&DynRegs[decode.modrm.reg]); + } else { + dyn_fill_ea(false); + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(EA)); + gen_releasereg(DREG(EA)); + } break; /* Mov seg,ev */ case 0x8e:dyn_mov_seg_ev();break; @@ -1258,36 +1545,32 @@ restart_prefix: case 0xa0: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); - dyn_read_byte(DREG(EA),DREG(EAX),false); - gen_releasereg(DREG(EA)); + dyn_read_byte_release(DREG(EA),DREG(EAX),false); break; /* MOV AX,direct addresses */ case 0xa1: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); - dyn_read_word(DREG(EA),DREG(EAX),decode.big_op); - gen_releasereg(DREG(EA)); + dyn_read_word_release(DREG(EA),DREG(EAX),decode.big_op); break; /* MOV direct address,AL */ case 0xa2: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); - dyn_write_byte(DREG(EA),DREG(EAX),false); - gen_releasereg(DREG(EA)); + dyn_write_byte_release(DREG(EA),DREG(EAX),false); break; /* MOV direct addresses,AX */ case 0xa3: gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, decode.big_addr ? decode_fetchd() : decode_fetchw()); - dyn_write_word(DREG(EA),DREG(EAX),decode.big_op); - gen_releasereg(DREG(EA)); + dyn_write_word_release(DREG(EA),DREG(EAX),decode.big_op); break; /* MOVSB/W/D*/ case 0xa4:dyn_string(STR_MOVSB);break; case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break; /* TEST AL,AX Imm */ - case 0xa8:gen_needflags();gen_dop_byte_imm(DOP_TEST,DREG(EAX),0,decode_fetchb());break; - case 0xa9:gen_needflags();gen_dop_word_imm(DOP_TEST,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0xa8:gen_discardflags();gen_dop_byte_imm(DOP_TEST,DREG(EAX),0,decode_fetchb());break; + case 0xa9:gen_discardflags();gen_dop_word_imm(DOP_TEST,decode.big_op,DREG(EAX),decode.big_op ? decode_fetchd() : decode_fetchw());break; /* STOSB/W/D*/ case 0xaa:dyn_string(STR_STOSB);break; case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break; @@ -1331,12 +1614,45 @@ restart_prefix: //GRP2 Eb/Ev,CL case 0xd2:dyn_grp2_eb(grp2_cl);break; case 0xd3:dyn_grp2_ev(grp2_cl);break; - + //FPU +#ifdef CPU_FPU + case 0xd8: + DYN_FPU_ESC(0); + break; + case 0xd9: + DYN_FPU_ESC(1); + break; + case 0xda: + DYN_FPU_ESC(2); + break; + case 0xdb: + DYN_FPU_ESC(3); + break; + case 0xdc: + DYN_FPU_ESC(4); + break; + case 0xdd: + DYN_FPU_ESC(5); + break; + case 0xde: + DYN_FPU_ESC(6); + break; + case 0xdf: + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + if (decode.modrm.val == 0xe0) gen_releasereg(DREG(EAX)); /* FSTSW */ + gen_call_function((void*)&FPU_ESC7_Normal,"%Id",decode.modrm.val); + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_ESC7_EA,"%Id%Dd",decode.modrm.val,DREG(EA)); + gen_releasereg(DREG(EA)); + } + break; +#endif //Loop's case 0xe2:dyn_loop(LOOP_NONE);goto finish_block; case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block; //IN AL/AX,imm - case 0xe4:gen_call_function((void*)&IO_ReadB,"%Id%Rl",decode_fetchb(),DREG(EAX));break; case 0xe5: if (decode.big_op) { @@ -1383,7 +1699,6 @@ restart_prefix: gen_call_function((void*)&IO_WriteW,"%Dw%Dw",DREG(EDX),DREG(EAX)); } break; - case 0xf2: //REPNE/NZ decode.rep=REP_NZ; goto restart_prefix; @@ -1403,10 +1718,12 @@ restart_prefix: case 0xfa: //CLI gen_call_function((void *)&CPU_CLI,"%Rd",DREG(TMPB)); if (cpu.pmode) dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); break; case 0xfb: //STI gen_call_function((void *)&CPU_STI,"%Rd",DREG(TMPB)); if (cpu.pmode) dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode break; case 0xfc: //CLD @@ -1427,12 +1744,12 @@ restart_prefix: case 0x1://DEC Eb if (decode.modrm.mod<3) { dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); - gen_needflags(); + gen_needcarry(); gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,DREG(TMPB),0); - dyn_write_byte(DREG(EA),DREG(TMPB),false); - gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); + dyn_write_byte_release(DREG(EA),DREG(TMPB),false); + gen_releasereg(DREG(TMPB)); } else { - gen_needflags(); + gen_needcarry(); gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC, &DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); } @@ -1452,23 +1769,24 @@ restart_prefix: { dyn_get_modrm();DynReg * src; if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); - src=DREG(TMPW); + dyn_fill_ea(); + dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + src=DREG(TMPW); } else src=&DynRegs[decode.modrm.rm]; switch (decode.modrm.reg) { case 0x0://INC Ev case 0x1://DEC Ev - gen_needflags(); + gen_needcarry(); gen_sop_word(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op,src); if (decode.modrm.mod<3){ - dyn_write_word(DREG(EA),DREG(TMPW),decode.big_op); - gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPW)); + dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); + gen_releasereg(DREG(TMPW)); } break; case 0x2: /* CALL Ev */ - gen_lea(DREG(EIP),DREG(EIP),0,0,decode.code-decode.code_start); - dyn_push(DREG(EIP)); + gen_lea(DREG(TMPB),DREG(EIP),0,0,decode.code-decode.code_start); + dyn_push(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src); goto core_close_block; case 0x4: /* JMP Ev */ @@ -1479,8 +1797,8 @@ restart_prefix: gen_protectflags(); dyn_flags_gen_to_host(); gen_lea(DREG(EA),DREG(EA),0,0,decode.big_op ? 4: 2); - dyn_set_eip_last_end(DREG(TMPB)); dyn_read_word(DREG(EA),DREG(EA),false); + dyn_set_eip_last_end(DREG(TMPB)); dyn_save_critical_regs(); gen_call_function( decode.modrm.reg == 3 ? (void*)&CPU_CALL : (void*)&CPU_JMP, @@ -1489,10 +1807,11 @@ restart_prefix: dyn_flags_host_to_gen(); goto core_close_block; case 0x6: /* PUSH Ev */ + gen_releasereg(DREG(EA)); dyn_push(src); break; default: - IllegalOption(); + IllegalOption("opcode 0xff"); }} break; default: diff --git a/src/cpu/core_dyn_x86/helpers.h b/src/cpu/core_dyn_x86/helpers.h index 6fa75b3..b1e6775 100644 --- a/src/cpu/core_dyn_x86/helpers.h +++ b/src/cpu/core_dyn_x86/helpers.h @@ -1,18 +1,22 @@ static bool dyn_helper_divb(Bit8u val) { if (!val) return CPU_PrepareException(0,0); Bitu quo=reg_ax / val; - reg_ah=(Bit8u)(reg_ax % val); - reg_al=(Bit8u)quo; + Bit8u rem=(Bit8u)(reg_ax % val); + Bit8u quo8=(Bit8u)(quo&0xff); if (quo>0xff) return CPU_PrepareException(0,0); + reg_ah=rem; + reg_al=quo8; return false; } static bool dyn_helper_idivb(Bit8s val) { if (!val) return CPU_PrepareException(0,0); Bits quo=(Bit16s)reg_ax / val; - reg_ah=(Bit8s)((Bit16s)reg_ax % val); - reg_al=(Bit8s)quo; - if (quo!=(Bit8s)reg_al) return CPU_PrepareException(0,0); + Bit8s rem=(Bit8s)((Bit16s)reg_ax % val); + Bit8s quo8s=(Bit8s)(quo&0xff); + if (quo!=(Bit16s)quo8s) return CPU_PrepareException(0,0); + reg_ah=rem; + reg_al=quo8s; return false; } @@ -20,9 +24,11 @@ static bool dyn_helper_divw(Bit16u val) { if (!val) return CPU_PrepareException(0,0); Bitu num=(reg_dx<<16)|reg_ax; Bitu quo=num/val; - reg_dx=(Bit16u)(num % val); - reg_ax=(Bit16u)quo; - if (quo!=reg_ax) return CPU_PrepareException(0,0); + Bit16u rem=(Bit16u)(num % val); + Bit16u quo16=(Bit16u)(quo&0xffff); + if (quo!=(Bit32u)quo16) return CPU_PrepareException(0,0); + reg_dx=rem; + reg_ax=quo16; return false; } @@ -30,9 +36,11 @@ static bool dyn_helper_idivw(Bit16s val) { if (!val) return CPU_PrepareException(0,0); Bits num=(reg_dx<<16)|reg_ax; Bits quo=num/val; - reg_dx=(Bit16s)(num % val); - reg_ax=(Bit16s)quo; - if (quo!=(Bit16s)reg_ax) return CPU_PrepareException(0,0); + Bit16s rem=(Bit16s)(num % val); + Bit16s quo16s=(Bit16s)quo; + if (quo!=(Bit32s)quo16s) return CPU_PrepareException(0,0); + reg_dx=rem; + reg_ax=quo16s; return false; } @@ -40,9 +48,11 @@ static bool dyn_helper_divd(Bit32u val) { if (!val) return CPU_PrepareException(0,0); Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax; Bit64u quo=num/val; - reg_edx=(Bit32u)(num % val); - reg_eax=(Bit32u)quo; - if (quo!=(Bit64u)reg_eax) return CPU_PrepareException(0,0); + Bit32u rem=(Bit32u)(num % val); + Bit32u quo32=(Bit32u)(quo&0xffffffff); + if (quo!=(Bit64u)quo32) return CPU_PrepareException(0,0); + reg_edx=rem; + reg_eax=quo32; return false; } @@ -50,8 +60,10 @@ static bool dyn_helper_idivd(Bit32s val) { if (!val) return CPU_PrepareException(0,0); Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax; Bit64s quo=num/val; - reg_edx=(Bit32s)(num % val); - reg_eax=(Bit32s)(quo); - if (quo!=(Bit64s)((Bit32s)reg_eax)) return CPU_PrepareException(0,0); + Bit32s rem=(Bit32s)(num % val); + Bit32s quo32s=(Bit32s)(quo&0xffffffff); + if (quo!=(Bit64s)quo32s) return CPU_PrepareException(0,0); + reg_edx=rem; + reg_eax=quo32s; return false; } diff --git a/src/cpu/core_dyn_x86/risc_x86.h b/src/cpu/core_dyn_x86/risc_x86.h index bc15b74..7c9b5e3 100644 --- a/src/cpu/core_dyn_x86/risc_x86.h +++ b/src/cpu/core_dyn_x86/risc_x86.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -39,36 +39,35 @@ static struct { class GenReg { public: - GenReg(Bit8u _index,bool _protect) { - index=_index;protect=_protect; + GenReg(Bit8u _index) { + index=_index; notusable=false;dynreg=0; } DynReg * dynreg; Bitu last_used; //Keeps track of last assigned regs Bit8u index; bool notusable; - bool protect; - void Load(DynReg * _dynreg) { + void Load(DynReg * _dynreg,bool stale=false) { if (!_dynreg) return; - if (dynreg) Clear(); + if (GCC_UNLIKELY((Bitu)dynreg)) Clear(); dynreg=_dynreg; last_used=x86gen.last_used; dynreg->flags&=~DYNFLG_CHANGED; dynreg->genreg=this; - if (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE)) { + if ((!stale) && (dynreg->flags & (DYNFLG_LOAD|DYNFLG_ACTIVE))) { cache_addw(0x058b+(index << (8+3))); //Mov reg,[data] cache_addd((Bit32u)dynreg->data); } dynreg->flags|=DYNFLG_ACTIVE; } void Save(void) { - if (!dynreg) IllegalOption(); + if (GCC_UNLIKELY(!((Bitu)dynreg))) IllegalOption("GenReg->Save"); dynreg->flags&=~DYNFLG_CHANGED; cache_addw(0x0589+(index << (8+3))); //Mov [data],reg cache_addd((Bit32u)dynreg->data); } void Release(void) { - if (!dynreg) return; + if (GCC_UNLIKELY(!((Bitu)dynreg))) return; if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) { Save(); } @@ -82,8 +81,6 @@ public: } dynreg->genreg=0;dynreg=0; } - - }; static BlockReturn gen_runcode(Bit8u * code) { @@ -131,7 +128,7 @@ return_address: return retval; } -static GenReg * FindDynReg(DynReg * dynreg) { +static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) { x86gen.last_used++; if (dynreg->genreg) { dynreg->genreg->last_used=x86gen.last_used; @@ -143,11 +140,11 @@ static GenReg * FindDynReg(DynReg * dynreg) { first_used=-1; if (dynreg->flags & DYNFLG_HAS8) { /* Has to be eax,ebx,ecx,edx */ - for (i=first_index=0;i<=X86_REG_EDX;i++) { + for (i=first_index=0;i<=X86_REG_EBX;i++) { GenReg * genreg=x86gen.regs[i]; if (genreg->notusable) continue; if (!(genreg->dynreg)) { - genreg->Load(dynreg); + genreg->Load(dynreg,stale); return genreg; } if (genreg->last_usedLoad(dynreg); - return newreg; } else { for (i=first_index=X86_REGS-1;i>=0;i--) { GenReg * genreg=x86gen.regs[i]; if (genreg->notusable) continue; if (!(genreg->dynreg)) { - genreg->Load(dynreg); + genreg->Load(dynreg,stale); return genreg; } if (genreg->last_usedLoad(dynreg); - return newreg; } + /* No free register found use earliest assigned one */ + GenReg * newreg=x86gen.regs[first_index]; + newreg->Load(dynreg,stale); + return newreg; } static GenReg * ForceDynReg(GenReg * genreg,DynReg * dynreg) { @@ -242,6 +235,30 @@ static void gen_protectflags(void) { } } +static void gen_discardflags(void) { + if (!x86gen.flagsactive) { + x86gen.flagsactive=true; + cache_addw(0xc483); //ADD ESP,4 + cache_addb(0x4); + } +} + +static void gen_needcarry(void) { + if (!x86gen.flagsactive) { + x86gen.flagsactive=true; + cache_addw(0x2cd1); //SHR DWORD [ESP],1 + cache_addb(0x24); + cache_addd(0x0424648d); //LEA ESP,[ESP+4] + } +} + +static bool skip_flags=false; + +static void set_skipflags(bool state) { + if (!state) gen_discardflags(); + skip_flags=state; +} + static void gen_reinit(void) { x86gen.last_used=0; x86gen.flagsactive=false; @@ -252,87 +269,72 @@ static void gen_reinit(void) { static void gen_dop_byte(DualOps op,DynReg * dr1,Bit8u di1,DynReg * dr2,Bit8u di2) { GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); + Bit8u tmp; switch (op) { - case DOP_ADD:cache_addb(0x02);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_OR: cache_addb(0x0a);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_ADC:cache_addb(0x12);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_SBB:cache_addb(0x1a);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_AND:cache_addb(0x22);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_SUB:cache_addb(0x2a);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_XOR:cache_addb(0x32);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_CMP:cache_addb(0x3a);break; - case DOP_MOV:cache_addb(0x8a);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_XCHG:cache_addb(0x86);dr1->flags|=DYNFLG_CHANGED;dr2->flags|=DYNFLG_CHANGED;break; - case DOP_TEST:cache_addb(0x84);break; + case DOP_ADD: tmp=0x02; break; + case DOP_ADC: tmp=0x12; break; + case DOP_SUB: tmp=0x2a; break; + case DOP_SBB: tmp=0x1a; break; + case DOP_CMP: tmp=0x3a; goto nochange; + case DOP_XOR: tmp=0x32; break; + case DOP_AND: tmp=0x22; if ((dr1==dr2) && (di1==di2)) goto nochange; break; + case DOP_OR: tmp=0x0a; if ((dr1==dr2) && (di1==di2)) goto nochange; break; + case DOP_TEST: tmp=0x84; goto nochange; + case DOP_MOV: if ((dr1==dr2) && (di1==di2)) return; tmp=0x8a; break; + case DOP_XCHG: tmp=0x86; dr2->flags|=DYNFLG_CHANGED; break; default: - IllegalOption(); + IllegalOption("gen_dop_byte"); } - cache_addb(0xc0+((gr1->index+di1)<<3)+gr2->index+di2); + dr1->flags|=DYNFLG_CHANGED; +nochange: + cache_addw(tmp|(0xc0+((gr1->index+di1)<<3)+gr2->index+di2)<<8); } static void gen_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1,Bitu imm) { GenReg * gr1=FindDynReg(dr1); + Bit16u tmp; switch (op) { - case DOP_ADD: - cache_addw(0xc080+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_OR: - cache_addw(0xc880+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_ADC: - cache_addw(0xd080+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_SBB: - cache_addw(0xd880+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_AND: - cache_addw(0xe080+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_SUB: - cache_addw(0xe880+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_XOR: - cache_addw(0xf080+((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_CMP: - cache_addw(0xf880+((gr1->index+di1)<<8)); - break;//Doesn't change - case DOP_MOV: - cache_addb(0xb0+gr1->index+di1); - dr1->flags|=DYNFLG_CHANGED; - break; - case DOP_TEST: - cache_addw(0xc0f6+((gr1->index+di1)<<8)); - break;//Doesn't change + case DOP_ADD: tmp=0xc080; break; + case DOP_ADC: tmp=0xd080; break; + case DOP_SUB: tmp=0xe880; break; + case DOP_SBB: tmp=0xd880; break; + case DOP_CMP: tmp=0xf880; goto nochange; //Doesn't change + case DOP_XOR: tmp=0xf080; break; + case DOP_AND: tmp=0xe080; break; + case DOP_OR: tmp=0xc880; break; + case DOP_TEST: tmp=0xc0f6; goto nochange; //Doesn't change + case DOP_MOV: cache_addb(0xb0+gr1->index+di1); + dr1->flags|=DYNFLG_CHANGED; + goto finish; default: - IllegalOption(); + IllegalOption("gen_dop_byte_imm"); } + dr1->flags|=DYNFLG_CHANGED; +nochange: + cache_addw(tmp+((gr1->index+di1)<<8)); +finish: cache_addb(imm); } static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) { GenReg * gr1=FindDynReg(dr1); + Bit16u tmp; switch (op) { - case SOP_INC:cache_addw(0xc0FE + ((gr1->index+di1)<<8));break; - case SOP_DEC:cache_addw(0xc8FE + ((gr1->index+di1)<<8));break; - case SOP_NOT:cache_addw(0xd0f6 + ((gr1->index+di1)<<8));break; - case SOP_NEG:cache_addw(0xd8f6 + ((gr1->index+di1)<<8));break; + case SOP_INC: tmp=0xc0FE; break; + case SOP_DEC: tmp=0xc8FE; break; + case SOP_NOT: tmp=0xd0f6; break; + case SOP_NEG: tmp=0xd8f6; break; default: - IllegalOption(); + IllegalOption("gen_sop_byte"); } + cache_addw(tmp + ((gr1->index+di1)<<8)); dr1->flags|=DYNFLG_CHANGED; } static void gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr) { - GenReg * gdr=FindDynReg(ddr);GenReg * gsr=FindDynReg(dsr); + GenReg * gsr=FindDynReg(dsr); + GenReg * gdr=FindDynReg(ddr,true); if (sign) cache_addw(0xbf0f); else cache_addw(0xb70f); cache_addb(0xc0+(gdr->index<<3)+(gsr->index)); @@ -340,7 +342,8 @@ static void gen_extend_word(bool sign,DynReg * ddr,DynReg * dsr) { } static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) { - GenReg * gdr=FindDynReg(ddr);GenReg * gsr=FindDynReg(dsr); + GenReg * gsr=FindDynReg(dsr); + GenReg * gdr=FindDynReg(ddr,dword); if (!dword) cache_addb(0x66); if (sign) cache_addw(0xbe0f); else cache_addw(0xb60f); @@ -368,6 +371,7 @@ static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm Bit8u sib=(gsr1->index)+(gsr2->index<<3)+(scale<<6); cache_addb(sib); } else { + if ((ddr==dsr1) && !imm_size) return; cache_addb(0x8d); //LEA cache_addb(rm_base+gsr1->index); } @@ -394,59 +398,80 @@ static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm } static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) { - GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); - if (!dword) cache_addb(0x66); + GenReg * gr2=FindDynReg(dr2); + GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); + Bit8u tmp; switch (op) { - case DOP_ADD:cache_addb(0x03);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_OR: cache_addb(0x0b);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_ADC:cache_addb(0x13);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_SBB:cache_addb(0x1b);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_AND:cache_addb(0x23);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_SUB:cache_addb(0x2b);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_XOR:cache_addb(0x33);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_CMP:cache_addb(0x3b);break; - case DOP_MOV:cache_addb(0x8b);dr1->flags|=DYNFLG_CHANGED;break; - case DOP_XCHG:cache_addb(0x87);dr1->flags|=DYNFLG_CHANGED;dr2->flags|=DYNFLG_CHANGED;break; - case DOP_TEST:cache_addb(0x85);break; + case DOP_ADD: tmp=0x03; break; + case DOP_ADC: tmp=0x13; break; + case DOP_SUB: tmp=0x2b; break; + case DOP_SBB: tmp=0x1b; break; + case DOP_CMP: tmp=0x3b; goto nochange; + case DOP_XOR: tmp=0x33; break; + case DOP_AND: tmp=0x23; if (dr1==dr2) goto nochange; break; + case DOP_OR: tmp=0x0b; if (dr1==dr2) goto nochange; break; + case DOP_TEST: tmp=0x85; goto nochange; + case DOP_MOV: if (dr1==dr2) return; tmp=0x8b; break; + case DOP_XCHG: + dr2->flags|=DYNFLG_CHANGED; + if (dword && !((dr1->flags&DYNFLG_HAS8) ^ (dr2->flags&DYNFLG_HAS8))) { + dr1->genreg=gr2;dr1->genreg->dynreg=dr1; + dr2->genreg=gr1;dr2->genreg->dynreg=dr2; + dr1->flags|=DYNFLG_CHANGED; + return; + } + tmp=0x87; + break; default: - IllegalOption(); + IllegalOption("gen_dop_word"); } - cache_addb(0xc0+(gr1->index<<3)+gr2->index); + dr1->flags|=DYNFLG_CHANGED; +nochange: + if (!dword) cache_addb(0x66); + cache_addw(tmp|(0xc0+(gr1->index<<3)+gr2->index)<<8); } static void gen_dop_word_imm(DualOps op,bool dword,DynReg * dr1,Bits imm) { - GenReg * gr1=FindDynReg(dr1); + GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); + Bit16u tmp; if (!dword) cache_addb(0x66); switch (op) { - case DOP_ADD:cache_addw(0xc081+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_OR: cache_addw(0xc881+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_ADC:cache_addw(0xd081+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_SBB:cache_addw(0xd881+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_AND:cache_addw(0xe081+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_SUB:cache_addw(0xe881+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_XOR:cache_addw(0xf081+(gr1->index<<8));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_CMP:cache_addw(0xf881+(gr1->index<<8));break;//Doesn't change - case DOP_MOV:cache_addb(0xb8+(gr1->index));dr1->flags|=DYNFLG_CHANGED;break; - case DOP_TEST:cache_addw(0xc0f7+(gr1->index<<8));break;//Doesn't change + case DOP_ADD: tmp=0xc081; break; + case DOP_ADC: tmp=0xd081; break; + case DOP_SUB: tmp=0xe881; break; + case DOP_SBB: tmp=0xd881; break; + case DOP_CMP: tmp=0xf881; goto nochange; //Doesn't change + case DOP_XOR: tmp=0xf081; break; + case DOP_AND: tmp=0xe081; break; + case DOP_OR: tmp=0xc881; break; + case DOP_TEST: tmp=0xc0f7; goto nochange; //Doesn't change + case DOP_MOV: cache_addb(0xb8+(gr1->index)); dr1->flags|=DYNFLG_CHANGED; goto finish; default: - IllegalOption(); + IllegalOption("gen_dop_word_imm"); } + dr1->flags|=DYNFLG_CHANGED; +nochange: + cache_addw(tmp+(gr1->index<<8)); +finish: if (dword) cache_addd(imm); else cache_addw(imm); } static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) { GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); - if (!dword) cache_addb(0x66); - cache_addw(0xaf0f); - cache_addb(0xc0+(gr1->index<<3)+gr2->index); dr1->flags|=DYNFLG_CHANGED; + if (!dword) { + cache_addd(0xaf0f66|(0xc0+(gr1->index<<3)+gr2->index)<<24); + } else { + cache_addw(0xaf0f); + cache_addb(0xc0+(gr1->index<<3)+gr2->index); + } } static void gen_imul_word_imm(bool dword,DynReg * dr1,DynReg * dr2,Bits imm) { GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); if (!dword) cache_addb(0x66); - if ((imm>=-128 && imm<=127)) { + if ((imm>=-128 && imm<=127)) { cache_addb(0x6b); cache_addb(0xc0+(gr1->index<<3)+gr2->index); cache_addb(imm); @@ -469,7 +494,7 @@ static void gen_sop_word(SingleOps op,bool dword,DynReg * dr1) { case SOP_NOT:cache_addw(0xd0f7+(gr1->index<<8));break; case SOP_NEG:cache_addw(0xd8f7+(gr1->index<<8));break; default: - IllegalOption(); + IllegalOption("gen_sop_word"); } dr1->flags|=DYNFLG_CHANGED; } @@ -498,10 +523,13 @@ static void gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx) { static void gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm) { GenReg * gr1=FindDynReg(dr1); - if (!dword) cache_addb(0x66); - cache_addw(0xc0c1+(((Bit16u)op) << 11) + ((gr1->index)<<8)); - cache_addb(imm); dr1->flags|=DYNFLG_CHANGED; + if (!dword) { + cache_addd(0x66|((0xc0c1+((Bit16u)op << 11) + (gr1->index<<8))|imm<<16)<<8); + } else { + cache_addw(0xc0c1+((Bit16u)op << 11) + (gr1->index<<8)); + cache_addb(imm); + } } static void gen_cbw(bool dword,DynReg * dyn_ax) { @@ -514,10 +542,10 @@ static void gen_cbw(bool dword,DynReg * dyn_ax) { static void gen_cwd(bool dword,DynReg * dyn_ax,DynReg * dyn_dx) { ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx); - if (!dword) cache_addb(0x66); - cache_addb(0x99); dyn_ax->flags|=DYNFLG_CHANGED; dyn_dx->flags|=DYNFLG_CHANGED; + if (!dword) cache_addw(0x9966); + else cache_addb(0x99); } static void gen_mul_byte(bool imul,DynReg * dyn_ax,DynReg * dr1,Bit8u di1) { @@ -563,6 +591,7 @@ static void gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg static void gen_call_function(void * func,char * ops,...) { Bits paramcount=0; + bool release_flags=false; struct ParamInfo { char * line; Bitu value; @@ -570,9 +599,9 @@ static void gen_call_function(void * func,char * ops,...) { ParamInfo * retparam=0; /* Clear the EAX Genreg for usage */ x86gen.regs[X86_REG_EAX]->Clear(); - x86gen.regs[X86_REG_EAX]->notusable=true;; + x86gen.regs[X86_REG_EAX]->notusable=true; /* Save the flags */ - gen_protectflags(); + if (GCC_UNLIKELY(!skip_flags)) gen_protectflags(); /* Scan for the amount of params */ if (ops) { va_list params; @@ -626,7 +655,7 @@ static void gen_call_function(void * func,char * ops,...) { release=true; goto scanagain; default: - IllegalOption(); + IllegalOption("gen_call_function param:DREG"); } if (release) gen_releasereg(dynreg); } @@ -635,8 +664,11 @@ static void gen_call_function(void * func,char * ops,...) { retparam =&pinfo[pindex]; pinfo[pindex].line=scan; break; + case 'F': /* Release flags from stack */ + release_flags=true; + break; default: - IllegalOption(); + IllegalOption("gen_call_function unknown param"); } } } @@ -649,12 +681,16 @@ static void gen_call_function(void * func,char * ops,...) { /* Restore the params of the stack */ if (paramcount) { cache_addw(0xc483); //add ESP,imm byte - cache_addb(paramcount*4); + cache_addb(paramcount*4+(release_flags?4:0)); + } else if (release_flags) { + cache_addw(0xc483); //add ESP,imm byte + cache_addb(4); } /* Save the return value in correct register */ if (retparam) { DynReg * dynreg=(DynReg *)retparam->value; GenReg * genreg=FindDynReg(dynreg); + if (genreg->index) // test for (e)ax/al switch (*retparam->line) { case 'd': cache_addw(0xc08b+(genreg->index <<(8+3))); //mov reg,eax @@ -676,10 +712,47 @@ static void gen_call_function(void * func,char * ops,...) { x86gen.regs[X86_REG_EAX]->notusable=false; } +static void gen_call_write(DynReg * dr,Bit32u val,Bitu write_size) { + /* Clear the EAX Genreg for usage */ + x86gen.regs[X86_REG_EAX]->Clear(); + x86gen.regs[X86_REG_EAX]->notusable=true; + gen_protectflags(); + + cache_addb(0x68); //PUSH val + cache_addd(val); + GenReg * genreg=FindDynReg(dr); + cache_addb(0x50+genreg->index); //PUSH reg + + /* Clear some unprotected registers */ + x86gen.regs[X86_REG_ECX]->Clear(); + x86gen.regs[X86_REG_EDX]->Clear(); + /* Do the actual call to the procedure */ + cache_addb(0xe8); +#ifdef CHECKED_MEMORY_ACCESS + switch (write_size) { + case 1: cache_addd((Bit32u)mem_writeb_checked_x86 - (Bit32u)cache.pos-4); break; + case 2: cache_addd((Bit32u)mem_writew_checked_x86 - (Bit32u)cache.pos-4); break; + case 4: cache_addd((Bit32u)mem_writed_checked_x86 - (Bit32u)cache.pos-4); break; + default: IllegalOption("gen_call_write"); + } +#else + switch (write_size) { + case 1: cache_addd((Bit32u)mem_writeb - (Bit32u)cache.pos-4); break; + case 2: cache_addd((Bit32u)mem_writew_dyncorex86 - (Bit32u)cache.pos-4); break; + case 4: cache_addd((Bit32u)mem_writed_dyncorex86 - (Bit32u)cache.pos-4); break; + default: IllegalOption("gen_call_write"); + } +#endif + + cache_addw(0xc483); //ADD ESP,8 + cache_addb(2*4); + x86gen.regs[X86_REG_EAX]->notusable=false; + gen_releasereg(dr); +} + static Bit8u * gen_create_branch(BranchTypes type) { /* First free all registers */ - cache_addb(0x70+type); - cache_addb(0); + cache_addw(0x70+type); return (cache.pos-1); } @@ -692,6 +765,16 @@ static void gen_fill_branch(Bit8u * data,Bit8u * from=cache.pos) { *data=(from-data-1); } +static Bit8u * gen_create_branch_long(BranchTypes type) { + cache_addw(0x800f+(type<<8)); + cache_addd(0); + return (cache.pos-4); +} + +static void gen_fill_branch_long(Bit8u * data,Bit8u * from=cache.pos) { + *(Bit32u*)data=(from-data-4); +} + static Bit8u * gen_create_jump(Bit8u * to=0) { /* First free all registers */ cache_addb(0xe9); @@ -720,7 +803,7 @@ static void gen_jmp_ptr(void * ptr,Bits imm=0) { } static void gen_save_flags(DynReg * dynreg) { - if (x86gen.flagsactive) IllegalOption(); + if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_save_flags"); GenReg * genreg=FindDynReg(dynreg); cache_addb(0x8b); //MOV REG,[esp] cache_addw(0x2404+(genreg->index << 3)); @@ -728,7 +811,7 @@ static void gen_save_flags(DynReg * dynreg) { } static void gen_load_flags(DynReg * dynreg) { - if (x86gen.flagsactive) IllegalOption(); + if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_load_flags"); cache_addw(0xc483); //ADD ESP,4 cache_addb(0x4); GenReg * genreg=FindDynReg(dynreg); @@ -748,29 +831,62 @@ static void gen_load_host(void * data,DynReg * dr1,Bitu size) { case 2:cache_addw(0xb70f);break; //movzx word case 4:cache_addb(0x8b);break; //mov default: - IllegalOption(); + IllegalOption("gen_load_host"); } cache_addb(0x5+(gr1->index<<3)); cache_addd((Bit32u)data); dr1->flags|=DYNFLG_CHANGED; } +static void gen_mov_host(void * data,DynReg * dr1,Bitu size,Bit8u di1=0) { + GenReg * gr1=FindDynReg(dr1); + switch (size) { + case 1:cache_addb(0x8a);break; //mov byte + case 2:cache_addb(0x66); //mov word + case 4:cache_addb(0x8b);break; //mov + default: + IllegalOption("gen_load_host"); + } + cache_addb(0x5+((gr1->index+(di1?4:0))<<3)); + cache_addd((Bit32u)data); + dr1->flags|=DYNFLG_CHANGED; +} + static void gen_return(BlockReturn retcode) { gen_protectflags(); cache_addb(0x59); //POP ECX, the flags - cache_addb(0xb8); //MOV EAX, retcode - cache_addd(retcode); + if (retcode==0) cache_addw(0xc033); //MOV EAX, 0 + else { + cache_addb(0xb8); //MOV EAX, retcode + cache_addd(retcode); + } + cache_addb(0xc3); //RET +} + +static void gen_return_fast(BlockReturn retcode,bool ret_exception=false) { + if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_return_fast"); + cache_addw(0x0d8b); //MOV ECX, the flags + cache_addd((Bit32u)&cpu_regs.flags); + if (!ret_exception) { + cache_addw(0xc483); //ADD ESP,4 + cache_addb(0x4); + if (retcode==0) cache_addw(0xc033); //MOV EAX, 0 + else { + cache_addb(0xb8); //MOV EAX, retcode + cache_addd(retcode); + } + } cache_addb(0xc3); //RET } static void gen_init(void) { - x86gen.regs[X86_REG_EAX]=new GenReg(0,false); - x86gen.regs[X86_REG_ECX]=new GenReg(1,false); - x86gen.regs[X86_REG_EDX]=new GenReg(2,false); - x86gen.regs[X86_REG_EBX]=new GenReg(3,true); - x86gen.regs[X86_REG_EBP]=new GenReg(5,true); - x86gen.regs[X86_REG_ESI]=new GenReg(6,true); - x86gen.regs[X86_REG_EDI]=new GenReg(7,true); + x86gen.regs[X86_REG_EAX]=new GenReg(0); + x86gen.regs[X86_REG_ECX]=new GenReg(1); + x86gen.regs[X86_REG_EDX]=new GenReg(2); + x86gen.regs[X86_REG_EBX]=new GenReg(3); + x86gen.regs[X86_REG_EBP]=new GenReg(5); + x86gen.regs[X86_REG_ESI]=new GenReg(6); + x86gen.regs[X86_REG_EDI]=new GenReg(7); } diff --git a/src/cpu/core_dyn_x86/string.h b/src/cpu/core_dyn_x86/string.h index 10abb19..6138426 100644 --- a/src/cpu/core_dyn_x86/string.h +++ b/src/cpu/core_dyn_x86/string.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -51,7 +51,7 @@ static void dyn_string(STRING_OP op) { case STR_INSB: case STR_INSW: case STR_INSD: tmp_reg=DREG(TMPB);usesi=false;usedi=true;break; default: - IllegalOption(); + IllegalOption("dyn_string op"); } gen_load_host(&cpu.direction,DREG(TMPW),4); switch (op & 3) { @@ -59,7 +59,7 @@ static void dyn_string(STRING_OP op) { case 1:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),1);break; case 2:gen_shift_word_imm(SHIFT_SHL,true,DREG(TMPW),2);break; default: - IllegalOption(); + IllegalOption("dyn_string shift"); } if (usesi) { @@ -80,13 +80,10 @@ static void dyn_string(STRING_OP op) { dyn_savestate(&rep_state); Bit8u * rep_start=cache.pos; Bit8u * rep_ecx_jmp; - /* Check if ECX!=zero and decrease it */ + /* Check if ECX!=zero */ if (decode.rep) { gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX)); - Bit8u * branch_ecx=gen_create_branch(BR_NZ); - rep_ecx_jmp=gen_create_jump(); - gen_fill_branch(branch_ecx); - gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); + rep_ecx_jmp=gen_create_branch_long(BR_Z); } if (usesi) { if (!decode.big_addr) { @@ -95,7 +92,6 @@ static void dyn_string(STRING_OP op) { } else { gen_lea(DREG(EA),si_base,DREG(ESI),0,0); } - gen_dop_word(DOP_ADD,decode.big_addr,DREG(ESI),DREG(TMPW)); switch (op&3) { case 0:dyn_read_byte(DREG(EA),tmp_reg,false);break; case 1:dyn_read_word(DREG(EA),tmp_reg,false);break; @@ -117,7 +113,6 @@ static void dyn_string(STRING_OP op) { } else { gen_lea(DREG(EA),di_base,DREG(EDI),0,0); } - gen_dop_word(DOP_ADD,decode.big_addr,DREG(EDI),DREG(TMPW)); /* Maybe something special to be done to fill the value */ switch (op) { case STR_INSB: @@ -139,25 +134,31 @@ static void dyn_string(STRING_OP op) { dyn_write_word(DREG(EA),tmp_reg,true); break; default: - IllegalOption(); + IllegalOption("dyn_string op"); } } gen_releasereg(DREG(EA));gen_releasereg(DREG(TMPB)); + + /* update registers */ + if (usesi) gen_dop_word(DOP_ADD,decode.big_addr,DREG(ESI),DREG(TMPW)); + if (usedi) gen_dop_word(DOP_ADD,decode.big_addr,DREG(EDI),DREG(TMPW)); + if (decode.rep) { - DynState cycle_state; + gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); gen_sop_word(SOP_DEC,true,DREG(CYCLES)); gen_releasereg(DREG(CYCLES)); - dyn_savestate(&cycle_state); - Bit8u * cycle_branch=gen_create_branch(BR_NLE); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),decode.op_start-decode.code_start); - dyn_save_critical_regs(); - gen_return(BR_Cycles); - gen_fill_branch(cycle_branch); - dyn_loadstate(&cycle_state); - dyn_synchstate(&rep_state); + dyn_savestate(&save_info[used_save_info].state); + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_LE); + save_info[used_save_info].eip_change=decode.op_start-decode.code_start; + save_info[used_save_info].type=normal; + used_save_info++; + /* Jump back to start of ECX check */ + dyn_synchstate(&rep_state); gen_create_jump(rep_start); - gen_fill_jump(rep_ecx_jmp); + + dyn_loadstate(&rep_state); + gen_fill_branch_long(rep_ecx_jmp); } gen_releasereg(DREG(TMPW)); } diff --git a/src/cpu/core_full.cpp b/src/cpu/core_full.cpp index d1ee282..6e372c3 100644 --- a/src/cpu/core_full.cpp +++ b/src/cpu/core_full.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -86,7 +86,7 @@ nextopcode:; SaveIP(); continue; illegalopcode: - LOG_MSG("Illegal opcode"); + LOG(LOG_CPU,LOG_NORMAL)("Illegal opcode"); CPU_Exception(0x6,0); } FillFlags(); diff --git a/src/cpu/core_full/Makefile.in b/src/cpu/core_full/Makefile.in index 9336272..a1c3dcc 100644 --- a/src/cpu/core_full/Makefile.in +++ b/src/cpu/core_full/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -80,6 +80,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -105,10 +107,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/cpu/core_full/load.h b/src/cpu/core_full/load.h index 3a63a3d..73ced33 100644 --- a/src/cpu/core_full/load.h +++ b/src/cpu/core_full/load.h @@ -1,10 +1,10 @@ switch (inst.code.load) { /* General loading */ case L_POPwRM: - inst.op1.w = Pop_16(); + inst_op1_w = Pop_16(); goto case_L_MODRM; case L_POPdRM: - inst.op1.d = Pop_32(); + inst_op1_d = Pop_32(); goto case_L_MODRM; case_L_MODRM: case L_MODRM: @@ -21,160 +21,160 @@ l_MODRMswitch: switch (inst.code.extra) { /* Byte */ case M_Ib: - inst.op1.d=Fetchb(); + inst_op1_d=Fetchb(); break; case M_Ebx: - if (inst.rm<0xc0) inst.op1.ds=(Bit8s)LoadMb(inst.rm_eaa); - else inst.op1.ds=(Bit8s)reg_8(inst.rm_eai); + if (inst.rm<0xc0) inst_op1_ds=(Bit8s)LoadMb(inst.rm_eaa); + else inst_op1_ds=(Bit8s)reg_8(inst.rm_eai); break; case M_EbIb: - inst.op2.d=Fetchb(); + inst_op2_d=Fetchb(); case M_Eb: - if (inst.rm<0xc0) inst.op1.d=LoadMb(inst.rm_eaa); - else inst.op1.d=reg_8(inst.rm_eai); + if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa); + else inst_op1_d=reg_8(inst.rm_eai); break; case M_EbGb: - if (inst.rm<0xc0) inst.op1.d=LoadMb(inst.rm_eaa); - else inst.op1.d=reg_8(inst.rm_eai); - inst.op2.d=reg_8(inst.rm_index); + if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa); + else inst_op1_d=reg_8(inst.rm_eai); + inst_op2_d=reg_8(inst.rm_index); break; case M_GbEb: - if (inst.rm<0xc0) inst.op2.d=LoadMb(inst.rm_eaa); - else inst.op2.d=reg_8(inst.rm_eai); + if (inst.rm<0xc0) inst_op2_d=LoadMb(inst.rm_eaa); + else inst_op2_d=reg_8(inst.rm_eai); case M_Gb: - inst.op1.d=reg_8(inst.rm_index);; + inst_op1_d=reg_8(inst.rm_index);; break; /* Word */ case M_Iw: - inst.op1.d=Fetchw(); + inst_op1_d=Fetchw(); break; case M_EwxGwx: - inst.op2.ds=(Bit16s)reg_16(inst.rm_index); + inst_op2_ds=(Bit16s)reg_16(inst.rm_index); goto l_M_Ewx; case M_EwxIbx: - inst.op2.ds=Fetchbs(); + inst_op2_ds=Fetchbs(); goto l_M_Ewx; case M_EwxIwx: - inst.op2.ds=Fetchws(); + inst_op2_ds=Fetchws(); l_M_Ewx: case M_Ewx: - if (inst.rm<0xc0) inst.op1.ds=(Bit16s)LoadMw(inst.rm_eaa); - else inst.op1.ds=(Bit16s)reg_16(inst.rm_eai); + if (inst.rm<0xc0) inst_op1_ds=(Bit16s)LoadMw(inst.rm_eaa); + else inst_op1_ds=(Bit16s)reg_16(inst.rm_eai); break; case M_EwIb: - inst.op2.d=Fetchb(); + inst_op2_d=Fetchb(); goto l_M_Ew; case M_EwIbx: - inst.op2.ds=Fetchbs(); + inst_op2_ds=Fetchbs(); goto l_M_Ew; case M_EwIw: - inst.op2.d=Fetchw(); + inst_op2_d=Fetchw(); goto l_M_Ew; case M_EwGwCL: - inst.imm.d=reg_cl; + inst_imm_d=reg_cl; goto l_M_EwGw; case M_EwGwIb: - inst.imm.d=Fetchb(); + inst_imm_d=Fetchb(); goto l_M_EwGw; case M_EwGwt: - inst.op2.d=reg_16(inst.rm_index); - inst.rm_eaa+=((Bit16s)inst.op2.d >> 4) * 2; + inst_op2_d=reg_16(inst.rm_index); + inst.rm_eaa+=((Bit16s)inst_op2_d >> 4) * 2; goto l_M_Ew; l_M_EwGw: case M_EwGw: - inst.op2.d=reg_16(inst.rm_index); + inst_op2_d=reg_16(inst.rm_index); l_M_Ew: case M_Ew: - if (inst.rm<0xc0) inst.op1.d=LoadMw(inst.rm_eaa); - else inst.op1.d=reg_16(inst.rm_eai); + if (inst.rm<0xc0) inst_op1_d=LoadMw(inst.rm_eaa); + else inst_op1_d=reg_16(inst.rm_eai); break; case M_GwEw: - if (inst.rm<0xc0) inst.op2.d=LoadMw(inst.rm_eaa); - else inst.op2.d=reg_16(inst.rm_eai); + if (inst.rm<0xc0) inst_op2_d=LoadMw(inst.rm_eaa); + else inst_op2_d=reg_16(inst.rm_eai); case M_Gw: - inst.op1.d=reg_16(inst.rm_index);; + inst_op1_d=reg_16(inst.rm_index);; break; /* DWord */ case M_Id: - inst.op1.d=Fetchd(); + inst_op1_d=Fetchd(); break; case M_EdxGdx: - inst.op2.ds=(Bit32s)reg_32(inst.rm_index); + inst_op2_ds=(Bit32s)reg_32(inst.rm_index); case M_Edx: - if (inst.rm<0xc0) inst.op1.d=(Bit32s)LoadMd(inst.rm_eaa); - else inst.op1.d=(Bit32s)reg_32(inst.rm_eai); + if (inst.rm<0xc0) inst_op1_d=(Bit32s)LoadMd(inst.rm_eaa); + else inst_op1_d=(Bit32s)reg_32(inst.rm_eai); break; case M_EdIb: - inst.op2.d=Fetchb(); + inst_op2_d=Fetchb(); goto l_M_Ed; case M_EdIbx: - inst.op2.ds=Fetchbs(); + inst_op2_ds=Fetchbs(); goto l_M_Ed; case M_EdId: - inst.op2.d=Fetchd(); + inst_op2_d=Fetchd(); goto l_M_Ed; case M_EdGdCL: - inst.imm.d=reg_cl; + inst_imm_d=reg_cl; goto l_M_EdGd; case M_EdGdt: - inst.op2.d=reg_32(inst.rm_index); - inst.rm_eaa+=((Bit32s)inst.op2.d >> 5) * 4; + inst_op2_d=reg_32(inst.rm_index); + inst.rm_eaa+=((Bit32s)inst_op2_d >> 5) * 4; goto l_M_Ed; case M_EdGdIb: - inst.imm.d=Fetchb(); + inst_imm_d=Fetchb(); goto l_M_EdGd; l_M_EdGd: case M_EdGd: - inst.op2.d=reg_32(inst.rm_index); + inst_op2_d=reg_32(inst.rm_index); l_M_Ed: case M_Ed: - if (inst.rm<0xc0) inst.op1.d=LoadMd(inst.rm_eaa); - else inst.op1.d=reg_32(inst.rm_eai); + if (inst.rm<0xc0) inst_op1_d=LoadMd(inst.rm_eaa); + else inst_op1_d=reg_32(inst.rm_eai); break; case M_GdEd: - if (inst.rm<0xc0) inst.op2.d=LoadMd(inst.rm_eaa); - else inst.op2.d=reg_32(inst.rm_eai); + if (inst.rm<0xc0) inst_op2_d=LoadMd(inst.rm_eaa); + else inst_op2_d=reg_32(inst.rm_eai); case M_Gd: - inst.op1.d=reg_32(inst.rm_index); + inst_op1_d=reg_32(inst.rm_index); break; /* Others */ case M_SEG: //TODO Check for limit - inst.op1.d=SegValue((SegNames)inst.rm_index); + inst_op1_d=SegValue((SegNames)inst.rm_index); break; case M_Efw: if (inst.rm>=0xc0) goto illegalopcode; - inst.op1.d=LoadMw(inst.rm_eaa); - inst.op2.d=LoadMw(inst.rm_eaa+2); + inst_op1_d=LoadMw(inst.rm_eaa); + inst_op2_d=LoadMw(inst.rm_eaa+2); break; case M_Efd: if (inst.rm>=0xc0) goto illegalopcode; - inst.op1.d=LoadMd(inst.rm_eaa); - inst.op2.d=LoadMw(inst.rm_eaa+4); + inst_op1_d=LoadMd(inst.rm_eaa); + inst_op2_d=LoadMw(inst.rm_eaa+4); break; case M_EA: - inst.op1.d=inst.rm_off; + inst_op1_d=inst.rm_off; break; case M_POPw: - inst.op1.d = Pop_16(); + inst_op1_d = Pop_16(); break; case M_POPd: - inst.op1.d = Pop_32(); + inst_op1_d = Pop_32(); break; case M_GRP: inst.code=Groups[inst.code.op][inst.rm_index]; goto l_MODRMswitch; case M_GRP_Ib: - inst.op2.d=Fetchb(); + inst_op2_d=Fetchb(); inst.code=Groups[inst.code.op][inst.rm_index]; goto l_MODRMswitch; case M_GRP_CL: - inst.op2.d=reg_cl; + inst_op2_d=reg_cl; inst.code=Groups[inst.code.op][inst.rm_index]; goto l_MODRMswitch; case M_GRP_1: - inst.op2.d=1; + inst_op2_d=1; inst.code=Groups[inst.code.op][inst.rm_index]; goto l_MODRMswitch; case 0: @@ -185,61 +185,61 @@ l_M_Ed: } break; case L_POPw: - inst.op1.d = Pop_16(); + inst_op1_d = Pop_16(); break; case L_POPd: - inst.op1.d = Pop_32(); + inst_op1_d = Pop_32(); break; case L_POPfw: - inst.op1.d = Pop_16(); - inst.op2.d = Pop_16(); + inst_op1_d = Pop_16(); + inst_op2_d = Pop_16(); break; case L_POPfd: - inst.op1.d = Pop_32(); - inst.op2.d = Pop_16(); + inst_op1_d = Pop_32(); + inst_op2_d = Pop_16(); break; case L_Ib: - inst.op1.d=Fetchb(); + inst_op1_d=Fetchb(); break; case L_Ibx: - inst.op1.ds=Fetchbs(); + inst_op1_ds=Fetchbs(); break; case L_Iw: - inst.op1.d=Fetchw(); + inst_op1_d=Fetchw(); break; case L_Iwx: - inst.op1.ds=Fetchws(); + inst_op1_ds=Fetchws(); break; case L_Idx: case L_Id: - inst.op1.d=Fetchd(); + inst_op1_d=Fetchd(); break; case L_Ifw: - inst.op1.d=Fetchw(); - inst.op2.d=Fetchw(); + inst_op1_d=Fetchw(); + inst_op2_d=Fetchw(); break; case L_Ifd: - inst.op1.d=Fetchd(); - inst.op2.d=Fetchw(); + inst_op1_d=Fetchd(); + inst_op2_d=Fetchw(); break; /* Direct load of registers */ case L_REGbIb: - inst.op2.d=Fetchb(); + inst_op2_d=Fetchb(); case L_REGb: - inst.op1.d=reg_8(inst.code.extra); + inst_op1_d=reg_8(inst.code.extra); break; case L_REGwIw: - inst.op2.d=Fetchw(); + inst_op2_d=Fetchw(); case L_REGw: - inst.op1.d=reg_16(inst.code.extra); + inst_op1_d=reg_16(inst.code.extra); break; case L_REGdId: - inst.op2.d=Fetchd(); + inst_op2_d=Fetchd(); case L_REGd: - inst.op1.d=reg_32(inst.code.extra); + inst_op1_d=reg_32(inst.code.extra); break; case L_SEG: - inst.op1.d=SegValue((SegNames)inst.code.extra); + inst_op1_d=SegValue((SegNames)inst.code.extra); break; /* Depending on addressize */ case L_OP: @@ -277,11 +277,11 @@ l_M_Ed: inst.prefix=(inst.prefix & ~1) | (cpu.code.big ^ 1); goto restartopcode; case L_VAL: - inst.op1.d=inst.code.extra; + inst_op1_d=inst.code.extra; break; case L_INTO: if (!get_OF()) goto nextopcode; - inst.op1.d=4; + inst_op1_d=4; break; case D_IRETw: FillFlags(); @@ -428,6 +428,10 @@ l_M_Ed: case D_WAIT: case D_NOP: goto nextopcode; + case D_LOCK: /* FIXME: according to intel, LOCK should raise an exception if it's not followed by one of a small set of instructions; + probably doesn't matter for our purposes as it is a pentium prefix anyhow */ + LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK"); + goto nextopcode; case D_ENTERw: { Bitu bytes=Fetchw(); @@ -468,12 +472,18 @@ l_M_Ed: CPU_CPUID(); goto nextopcode; case D_HLT: + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); FillFlags(); CPU_HLT(GetIP()); return CBRET_NONE; case D_CLTS: - //TODO Really clear it sometime + if (cpu.pmode && cpu.cpl) goto illegalopcode; + cpu.cr0&=(~CR0_TASKSWITCH); goto nextopcode; + case D_ICEBP: + FillFlags(); + CPU_SW_Interrupt_NoIOPLCheck(1,GetIP()); + continue; default: LOG(LOG_CPU,LOG_ERROR)("LOAD:Unhandled code %d opcode %X",inst.code.load,inst.entry); goto illegalopcode; diff --git a/src/cpu/core_full/op.h b/src/cpu/core_full/op.h index bed42c1..8f25a72 100644 --- a/src/cpu/core_full/op.h +++ b/src/cpu/core_full/op.h @@ -1,223 +1,223 @@ /* Do the actual opcode */ switch (inst.code.op) { case t_ADDb: case t_ADDw: case t_ADDd: - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d + lf_var2d; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d + lf_var2d; lflags.type=inst.code.op; break; case t_CMPb: case t_CMPw: case t_CMPd: case t_SUBb: case t_SUBw: case t_SUBd: - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d - lf_var2d; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d - lf_var2d; lflags.type=inst.code.op; break; case t_ORb: case t_ORw: case t_ORd: - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d | lf_var2d; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d | lf_var2d; lflags.type=inst.code.op; break; case t_XORb: case t_XORw: case t_XORd: - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d ^ lf_var2d; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d ^ lf_var2d; lflags.type=inst.code.op; break; case t_TESTb: case t_TESTw: case t_TESTd: case t_ANDb: case t_ANDw: case t_ANDd: - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d & lf_var2d; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d & lf_var2d; lflags.type=inst.code.op; break; case t_ADCb: case t_ADCw: case t_ADCd: lflags.oldcf=(get_CF()!=0); - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d + lf_var2d + lflags.oldcf; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d + lf_var2d + lflags.oldcf; lflags.type=inst.code.op; break; case t_SBBb: case t_SBBw: case t_SBBd: lflags.oldcf=(get_CF()!=0); - lf_var1d=inst.op1.d; - lf_var2d=inst.op2.d; - inst.op1.d=lf_resd=lf_var1d - lf_var2d - lflags.oldcf; + lf_var1d=inst_op1_d; + lf_var2d=inst_op2_d; + inst_op1_d=lf_resd=lf_var1d - lf_var2d - lflags.oldcf; lflags.type=inst.code.op; break; case t_INCb: case t_INCw: case t_INCd: LoadCF; - lf_var1d=inst.op1.d; - inst.op1.d=lf_resd=inst.op1.d+1; + lf_var1d=inst_op1_d; + inst_op1_d=lf_resd=inst_op1_d+1; lflags.type=inst.code.op; break; case t_DECb: case t_DECw: case t_DECd: LoadCF; - lf_var1d=inst.op1.d; - inst.op1.d=lf_resd=inst.op1.d-1; + lf_var1d=inst_op1_d; + inst_op1_d=lf_resd=inst_op1_d-1; lflags.type=inst.code.op; break; /* Using the instructions.h defines */ case t_ROLb: - ROLB(inst.op1.b,inst.op2.b,LoadD,SaveD); + ROLB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_ROLw: - ROLW(inst.op1.w,inst.op2.b,LoadD,SaveD); + ROLW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_ROLd: - ROLD(inst.op1.d,inst.op2.b,LoadD,SaveD); + ROLD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case t_RORb: - RORB(inst.op1.b,inst.op2.b,LoadD,SaveD); + RORB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_RORw: - RORW(inst.op1.w,inst.op2.b,LoadD,SaveD); + RORW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_RORd: - RORD(inst.op1.d,inst.op2.b,LoadD,SaveD); + RORD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case t_RCLb: - RCLB(inst.op1.b,inst.op2.b,LoadD,SaveD); + RCLB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_RCLw: - RCLW(inst.op1.w,inst.op2.b,LoadD,SaveD); + RCLW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_RCLd: - RCLD(inst.op1.d,inst.op2.b,LoadD,SaveD); + RCLD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case t_RCRb: - RCRB(inst.op1.b,inst.op2.b,LoadD,SaveD); + RCRB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_RCRw: - RCRW(inst.op1.w,inst.op2.b,LoadD,SaveD); + RCRW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_RCRd: - RCRD(inst.op1.d,inst.op2.b,LoadD,SaveD); + RCRD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case t_SHLb: - SHLB(inst.op1.b,inst.op2.b,LoadD,SaveD); + SHLB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_SHLw: - SHLW(inst.op1.w,inst.op2.b,LoadD,SaveD); + SHLW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_SHLd: - SHLD(inst.op1.d,inst.op2.b,LoadD,SaveD); + SHLD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case t_SHRb: - SHRB(inst.op1.b,inst.op2.b,LoadD,SaveD); + SHRB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_SHRw: - SHRW(inst.op1.w,inst.op2.b,LoadD,SaveD); + SHRW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_SHRd: - SHRD(inst.op1.d,inst.op2.b,LoadD,SaveD); + SHRD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case t_SARb: - SARB(inst.op1.b,inst.op2.b,LoadD,SaveD); + SARB(inst_op1_b,inst_op2_b,LoadD,SaveD); break; case t_SARw: - SARW(inst.op1.w,inst.op2.b,LoadD,SaveD); + SARW(inst_op1_w,inst_op2_b,LoadD,SaveD); break; case t_SARd: - SARD(inst.op1.d,inst.op2.b,LoadD,SaveD); + SARD(inst_op1_d,inst_op2_b,LoadD,SaveD); break; case O_DSHLw: { - DSHLW(inst.op1.w,inst.op2.w,inst.imm.b,LoadD,SaveD); + DSHLW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD); break; } case O_DSHRw: { - DSHRW(inst.op1.w,inst.op2.w,inst.imm.b,LoadD,SaveD); + DSHRW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD); break; } case O_DSHLd: { - DSHLD(inst.op1.d,inst.op2.d,inst.imm.b,LoadD,SaveD); + DSHLD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD); break; } case O_DSHRd: { - DSHRD(inst.op1.d,inst.op2.d,inst.imm.b,LoadD,SaveD); + DSHRD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD); break; } case t_NEGb: - lf_var1b=inst.op1.b; - inst.op1.b=lf_resb=0-inst.op1.b; + lf_var1b=inst_op1_b; + inst_op1_b=lf_resb=0-inst_op1_b; lflags.type=t_NEGb; break; case t_NEGw: - lf_var1w=inst.op1.w; - inst.op1.w=lf_resw=0-inst.op1.w; + lf_var1w=inst_op1_w; + inst_op1_w=lf_resw=0-inst_op1_w; lflags.type=t_NEGw; break; case t_NEGd: - lf_var1d=inst.op1.d; - inst.op1.d=lf_resd=0-inst.op1.d; + lf_var1d=inst_op1_d; + inst_op1_d=lf_resd=0-inst_op1_d; lflags.type=t_NEGd; break; case O_NOT: - inst.op1.d=~inst.op1.d; + inst_op1_d=~inst_op1_d; break; /* Special instructions */ case O_IMULRw: - DIMULW(inst.op1.ws,inst.op1.ws,inst.op2.ws,LoadD,SaveD); + DIMULW(inst_op1_ws,inst_op1_ws,inst_op2_ws,LoadD,SaveD); break; case O_IMULRd: - DIMULD(inst.op1.ds,inst.op1.ds,inst.op2.ds,LoadD,SaveD); + DIMULD(inst_op1_ds,inst_op1_ds,inst_op2_ds,LoadD,SaveD); break; case O_MULb: - MULB(inst.op1.b,LoadD,0); + MULB(inst_op1_b,LoadD,0); goto nextopcode; case O_MULw: - MULW(inst.op1.w,LoadD,0); + MULW(inst_op1_w,LoadD,0); goto nextopcode; case O_MULd: - MULD(inst.op1.d,LoadD,0); + MULD(inst_op1_d,LoadD,0); goto nextopcode; case O_IMULb: - IMULB(inst.op1.b,LoadD,0); + IMULB(inst_op1_b,LoadD,0); goto nextopcode; case O_IMULw: - IMULW(inst.op1.w,LoadD,0); + IMULW(inst_op1_w,LoadD,0); goto nextopcode; case O_IMULd: - IMULD(inst.op1.d,LoadD,0); + IMULD(inst_op1_d,LoadD,0); goto nextopcode; case O_DIVb: - DIVB(inst.op1.b,LoadD,0); + DIVB(inst_op1_b,LoadD,0); goto nextopcode; case O_DIVw: - DIVW(inst.op1.w,LoadD,0); + DIVW(inst_op1_w,LoadD,0); goto nextopcode; case O_DIVd: - DIVD(inst.op1.d,LoadD,0); + DIVD(inst_op1_d,LoadD,0); goto nextopcode; case O_IDIVb: - IDIVB(inst.op1.b,LoadD,0); + IDIVB(inst_op1_b,LoadD,0); goto nextopcode; case O_IDIVw: - IDIVW(inst.op1.w,LoadD,0); + IDIVW(inst_op1_w,LoadD,0); goto nextopcode; case O_IDIVd: - IDIVD(inst.op1.d,LoadD,0); + IDIVD(inst_op1_d,LoadD,0); goto nextopcode; case O_AAM: - AAM(inst.op1.b); + AAM(inst_op1_b); goto nextopcode; case O_AAD: - AAD(inst.op1.b); + AAD(inst_op1_b); goto nextopcode; case O_C_O: inst.cond=TFLG_O; break; @@ -302,15 +302,15 @@ switch (inst.code.op) { case O_XCHG_AX: { Bit16u temp=reg_ax; - reg_ax=inst.op1.w; - inst.op1.w=temp; + reg_ax=inst_op1_w; + inst_op1_w=temp; break; } case O_XCHG_EAX: { Bit32u temp=reg_eax; - reg_eax=inst.op1.d; - inst.op1.d=temp; + reg_eax=inst_op1_d; + inst_op1_d=temp; break; } case O_CALLNw: @@ -323,90 +323,94 @@ switch (inst.code.op) { break; case O_CALLFw: FillFlags(); - CPU_CALL(false,inst.op2.d,inst.op1.d,GetIP()); + CPU_CALL(false,inst_op2_d,inst_op1_d,GetIP()); continue; case O_CALLFd: FillFlags(); - CPU_CALL(true,inst.op2.d,inst.op1.d,GetIP()); + CPU_CALL(true,inst_op2_d,inst_op1_d,GetIP()); continue; case O_JMPFw: FillFlags(); - CPU_JMP(false,inst.op2.d,inst.op1.d,GetIP()); + CPU_JMP(false,inst_op2_d,inst_op1_d,GetIP()); continue; case O_JMPFd: FillFlags(); - CPU_JMP(true,inst.op2.d,inst.op1.d,GetIP()); + CPU_JMP(true,inst_op2_d,inst_op1_d,GetIP()); continue; case O_INT: FillFlags(); #if C_DEBUG if (((inst.entry & 0xFF)==0xcc) && DEBUG_Breakpoint()) return debugCallback; - else if (DEBUG_IntBreakpoint(inst.op1.b)) + else if (DEBUG_IntBreakpoint(inst_op1_b)) return debugCallback; #endif - CPU_SW_Interrupt(inst.op1.b,GetIP()); + CPU_SW_Interrupt(inst_op1_b,GetIP()); continue; case O_INb: - if (CPU_IO_Exception(inst.op1.d,1)) RunException(); - reg_al=IO_ReadB(inst.op1.d); + if (CPU_IO_Exception(inst_op1_d,1)) RunException(); + reg_al=IO_ReadB(inst_op1_d); goto nextopcode; case O_INw: - if (CPU_IO_Exception(inst.op1.d,2)) RunException(); - reg_ax=IO_ReadW(inst.op1.d); + if (CPU_IO_Exception(inst_op1_d,2)) RunException(); + reg_ax=IO_ReadW(inst_op1_d); goto nextopcode; case O_INd: - if (CPU_IO_Exception(inst.op1.d,4)) RunException(); - reg_eax=IO_ReadD(inst.op1.d); + if (CPU_IO_Exception(inst_op1_d,4)) RunException(); + reg_eax=IO_ReadD(inst_op1_d); goto nextopcode; case O_OUTb: - if (CPU_IO_Exception(inst.op1.d,1)) RunException(); - IO_WriteB(inst.op1.d,reg_al); + if (CPU_IO_Exception(inst_op1_d,1)) RunException(); + IO_WriteB(inst_op1_d,reg_al); goto nextopcode; case O_OUTw: - if (CPU_IO_Exception(inst.op1.d,2)) RunException(); - IO_WriteW(inst.op1.d,reg_ax); + if (CPU_IO_Exception(inst_op1_d,2)) RunException(); + IO_WriteW(inst_op1_d,reg_ax); goto nextopcode; case O_OUTd: - if (CPU_IO_Exception(inst.op1.d,4)) RunException(); - IO_WriteD(inst.op1.d,reg_eax); + if (CPU_IO_Exception(inst_op1_d,4)) RunException(); + IO_WriteD(inst_op1_d,reg_eax); goto nextopcode; case O_CBACK: FillFlags();SaveIP(); - return inst.op1.d; + return inst_op1_d; case O_GRP6w: case O_GRP6d: + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; switch (inst.rm_index) { case 0x00: /* SLDT */ { Bitu selector; CPU_SLDT(selector); - inst.op1.d=(Bit32u)selector; + inst_op1_d=(Bit32u)selector; } break; case 0x01: /* STR */ { Bitu selector; CPU_STR(selector); - inst.op1.d=(Bit32u)selector; + inst_op1_d=(Bit32u)selector; } break; case 0x02: /* LLDT */ - CPU_LLDT(inst.op1.d); + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LLDT(inst_op1_d)) RunException(); goto nextopcode; /* Else value will saved */ case 0x03: /* LTR */ - CPU_LTR(inst.op1.d); + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LTR(inst_op1_d)) RunException(); goto nextopcode; /* Else value will saved */ case 0x04: /* VERR */ FillFlags(); - CPU_VERR(inst.op1.d); + CPU_VERR(inst_op1_d); goto nextopcode; /* Else value will saved */ case 0x05: /* VERW */ FillFlags(); - CPU_VERW(inst.op1.d); + CPU_VERW(inst_op1_d); goto nextopcode; /* Else value will saved */ default: LOG(LOG_CPU,LOG_ERROR)("Group 6 Illegal subfunction %X",inst.rm_index); + goto illegalopcode; } break; case O_GRP7w: @@ -429,76 +433,80 @@ switch (inst.code.op) { goto nextopcode; } case 2: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); CPU_LGDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF)); goto nextopcode; case 3: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); CPU_LIDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF)); goto nextopcode; case 4: /* SMSW */ { Bitu word;CPU_SMSW(word); - inst.op1.d=word; + inst_op1_d=word; break; } case 6: /* LMSW */ FillFlags(); - CPU_LMSW(inst.op1.w); + if (CPU_LMSW(inst_op1_w)) RunException(); goto nextopcode; default: LOG(LOG_CPU,LOG_ERROR)("Group 7 Illegal subfunction %X",inst.rm_index); + goto illegalopcode; } break; case O_M_CRx_Rd: - CPU_SET_CRX(inst.rm_index,inst.op1.d); + if (CPU_WRITE_CRX(inst.rm_index,inst_op1_d)) RunException(); break; case O_M_Rd_CRx: - inst.op1.d=CPU_GET_CRX(inst.rm_index); + if (CPU_READ_CRX(inst.rm_index,inst_op1_d)) RunException(); break; case O_M_DRx_Rd: -// LOG(LOG_CPU,LOG_NORMAL)("MOV DR%d,%X",inst.rm_index,inst.op1.d); + if (CPU_WRITE_DRX(inst.rm_index,inst_op1_d)) RunException(); break; case O_M_Rd_DRx: - inst.op1.d=0; -// LOG(LOG_CPU,LOG_NORMAL)("MOV %X,DR%d",inst.op1.d,inst.rm_index); + if (CPU_READ_DRX(inst.rm_index,inst_op1_d)) RunException(); break; case O_LAR: { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; FillFlags(); - Bitu ar=inst.op2.d; - CPU_LAR(inst.op1.w,ar); - inst.op1.d=(Bit32u)ar; + Bitu ar=inst_op2_d; + CPU_LAR(inst_op1_w,ar); + inst_op1_d=(Bit32u)ar; } break; case O_LSL: { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; FillFlags(); - Bitu limit=inst.op2.d; - CPU_LSL(inst.op1.w,limit); - inst.op1.d=(Bit32u)limit; + Bitu limit=inst_op2_d; + CPU_LSL(inst_op1_w,limit); + inst_op1_d=(Bit32u)limit; } break; case O_ARPL: { if ((reg_flags & FLAG_VM) || !cpu.pmode) goto illegalopcode; FillFlags(); - Bitu new_sel=inst.op1.d; - CPU_ARPL(new_sel,inst.op2.d); - inst.op1.d=(Bit32u)new_sel; + Bitu new_sel=inst_op1_d; + CPU_ARPL(new_sel,inst_op2_d); + inst_op1_d=(Bit32u)new_sel; } break; case O_BSFw: { FillFlags(); - if (!inst.op1.w) { + if (!inst_op1_w) { SETFLAGBIT(ZF,true); goto nextopcode; } else { Bitu count=0; while (1) { - if (inst.op1.w & 0x1) break; - count++;inst.op1.w>>=1; + if (inst_op1_w & 0x1) break; + count++;inst_op1_w>>=1; } - inst.op1.d=count; + inst_op1_d=count; SETFLAGBIT(ZF,false); } } @@ -506,16 +514,16 @@ switch (inst.code.op) { case O_BSFd: { FillFlags(); - if (!inst.op1.d) { + if (!inst_op1_d) { SETFLAGBIT(ZF,true); goto nextopcode; } else { Bitu count=0; while (1) { - if (inst.op1.d & 0x1) break; - count++;inst.op1.d>>=1; + if (inst_op1_d & 0x1) break; + count++;inst_op1_d>>=1; } - inst.op1.d=count; + inst_op1_d=count; SETFLAGBIT(ZF,false); } } @@ -523,16 +531,16 @@ switch (inst.code.op) { case O_BSRw: { FillFlags(); - if (!inst.op1.w) { + if (!inst_op1_w) { SETFLAGBIT(ZF,true); goto nextopcode; } else { Bitu count=15; while (1) { - if (inst.op1.w & 0x8000) break; - count--;inst.op1.w<<=1; + if (inst_op1_w & 0x8000) break; + count--;inst_op1_w<<=1; } - inst.op1.d=count; + inst_op1_d=count; SETFLAGBIT(ZF,false); } } @@ -540,60 +548,60 @@ switch (inst.code.op) { case O_BSRd: { FillFlags(); - if (!inst.op1.d) { + if (!inst_op1_d) { SETFLAGBIT(ZF,true); goto nextopcode; } else { Bitu count=31; while (1) { - if (inst.op1.d & 0x80000000) break; - count--;inst.op1.d<<=1; + if (inst_op1_d & 0x80000000) break; + count--;inst_op1_d<<=1; } - inst.op1.d=count; + inst_op1_d=count; SETFLAGBIT(ZF,false); } } break; case O_BTw: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 15)))); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); break; case O_BTSw: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 15)))); - inst.op1.d|=(1 << (inst.op2.d & 15)); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + inst_op1_d|=(1 << (inst_op2_d & 15)); break; case O_BTCw: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 15)))); - inst.op1.d^=(1 << (inst.op2.d & 15)); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + inst_op1_d^=(1 << (inst_op2_d & 15)); break; case O_BTRw: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 15)))); - inst.op1.d&=~(1 << (inst.op2.d & 15)); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15)))); + inst_op1_d&=~(1 << (inst_op2_d & 15)); break; case O_BTd: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 31)))); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); break; case O_BTSd: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 31)))); - inst.op1.d|=(1 << (inst.op2.d & 31)); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + inst_op1_d|=(1 << (inst_op2_d & 31)); break; case O_BTCd: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 31)))); - inst.op1.d^=(1 << (inst.op2.d & 31)); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + inst_op1_d^=(1 << (inst_op2_d & 31)); break; case O_BTRd: FillFlags(); - SETFLAGBIT(CF,(inst.op1.d & (1 << (inst.op2.d & 31)))); - inst.op1.d&=~(1 << (inst.op2.d & 31)); + SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31)))); + inst_op1_d&=~(1 << (inst_op2_d & 31)); break; case O_BSWAP: - BSWAP(inst.op1.d); + BSWAP(inst_op1_d); break; case O_FPU: #if C_FPU @@ -626,7 +634,7 @@ switch (inst.code.op) { Bit16s bound_min, bound_max; bound_min=LoadMw(inst.rm_eaa); bound_max=LoadMw(inst.rm_eaa+2); - if ( (((Bit16s)inst.op1.w) < bound_min) || (((Bit16s)inst.op1.w) > bound_max) ) { + if ( (((Bit16s)inst_op1_w) < bound_min) || (((Bit16s)inst_op1_w) > bound_max) ) { EXCEPTION(5); } } diff --git a/src/cpu/core_full/optable.h b/src/cpu/core_full/optable.h index 4e60876..cf11994 100644 --- a/src/cpu/core_full/optable.h +++ b/src/cpu/core_full/optable.h @@ -171,7 +171,7 @@ static OpCode OpCodeTable[1024]={ {L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTw ,0 ,REGI_DX}, /* 0xf0 - 0xf7 */ -{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 }, {L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 }, {D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 }, {L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,9 ,0 ,M_GRP }, @@ -316,7 +316,7 @@ static OpCode OpCodeTable[1024]={ {L_MODRM ,0 ,S_Gw ,M_Ebx },{L_MODRM ,0 ,S_Gw ,M_Ewx }, /* 0x1c0 - 0x1cc */ -{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDw ,S_EwGw ,M_GwEw }, {0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, {0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, {0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, @@ -526,7 +526,7 @@ static OpCode OpCodeTable[1024]={ {L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTd ,0 ,REGI_DX}, /* 0x2f0 - 0x2f7 */ -{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 }, {L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 }, {0 ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 }, {L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,0xa ,0 ,M_GRP }, @@ -672,7 +672,7 @@ static OpCode OpCodeTable[1024]={ {L_MODRM ,0 ,S_Gd ,M_Ebx },{L_MODRM ,0 ,S_Gd ,M_Ewx }, /* 0x3c0 - 0x3cc */ -{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, +{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDd ,S_EdGd ,M_GdEd }, {0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, {0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, {0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 }, diff --git a/src/cpu/core_full/save.h b/src/cpu/core_full/save.h index ba9968e..4e10db1 100644 --- a/src/cpu/core_full/save.h +++ b/src/cpu/core_full/save.h @@ -2,95 +2,95 @@ switch (inst.code.save) { /* Byte */ case S_C_Eb: - inst.op1.b=inst.cond ? 1 : 0; + inst_op1_b=inst.cond ? 1 : 0; case S_Eb: - if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst.op1.b); - else reg_8(inst.rm_eai)=inst.op1.b; + if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b); + else reg_8(inst.rm_eai)=inst_op1_b; break; case S_Gb: - reg_8(inst.rm_index)=inst.op1.b; + reg_8(inst.rm_index)=inst_op1_b; break; case S_EbGb: - if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst.op1.b); - else reg_8(inst.rm_eai)=inst.op1.b; - reg_8(inst.rm_index)=inst.op2.b; + if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b); + else reg_8(inst.rm_eai)=inst_op1_b; + reg_8(inst.rm_index)=inst_op2_b; break; /* Word */ case S_Ew: - if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst.op1.w); - else reg_16(inst.rm_eai)=inst.op1.w; + if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w); + else reg_16(inst.rm_eai)=inst_op1_w; break; case S_Gw: - reg_16(inst.rm_index)=inst.op1.w; + reg_16(inst.rm_index)=inst_op1_w; break; case S_EwGw: - if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst.op1.w); - else reg_16(inst.rm_eai)=inst.op1.w; - reg_16(inst.rm_index)=inst.op2.w; + if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w); + else reg_16(inst.rm_eai)=inst_op1_w; + reg_16(inst.rm_index)=inst_op2_w; break; /* Dword */ case S_Ed: - if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst.op1.d); - else reg_32(inst.rm_eai)=inst.op1.d; + if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); + else reg_32(inst.rm_eai)=inst_op1_d; break; case S_EdMw: /* Special one 16 to memory, 32 zero extend to reg */ - if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst.op1.w); - else reg_32(inst.rm_eai)=inst.op1.d; + if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w); + else reg_32(inst.rm_eai)=inst_op1_d; break; case S_Gd: - reg_32(inst.rm_index)=inst.op1.d; + reg_32(inst.rm_index)=inst_op1_d; break; case S_EdGd: - if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst.op1.d); - else reg_32(inst.rm_eai)=inst.op1.d; - reg_32(inst.rm_index)=inst.op2.d; + if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); + else reg_32(inst.rm_eai)=inst_op1_d; + reg_32(inst.rm_index)=inst_op2_d; break; case S_REGb: - reg_8(inst.code.extra)=inst.op1.b; + reg_8(inst.code.extra)=inst_op1_b; break; case S_REGw: - reg_16(inst.code.extra)=inst.op1.w; + reg_16(inst.code.extra)=inst_op1_w; break; case S_REGd: - reg_32(inst.code.extra)=inst.op1.d; + reg_32(inst.code.extra)=inst_op1_d; break; case S_SEGm: - if (CPU_SetSegGeneral((SegNames)inst.rm_index,inst.op1.w)) RunException(); + if (CPU_SetSegGeneral((SegNames)inst.rm_index,inst_op1_w)) RunException(); break; case S_SEGGw: - if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst.op2.w)) RunException(); - reg_16(inst.rm_index)=inst.op1.w; + if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException(); + reg_16(inst.rm_index)=inst_op1_w; break; case S_SEGGd: - if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst.op2.w)) RunException(); - reg_32(inst.rm_index)=inst.op1.d; + if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException(); + reg_32(inst.rm_index)=inst_op1_d; break; case S_PUSHw: - Push_16(inst.op1.w); + Push_16(inst_op1_w); break; case S_PUSHd: - Push_32(inst.op1.d); + Push_32(inst_op1_d); break; case S_C_AIPw: if (!inst.cond) goto nextopcode; case S_AIPw: SaveIP(); - reg_eip+=inst.op1.d; + reg_eip+=inst_op1_d; reg_eip&=0xffff; continue; case S_C_AIPd: if (!inst.cond) goto nextopcode; case S_AIPd: SaveIP(); - reg_eip+=inst.op1.d; + reg_eip+=inst_op1_d; continue; case S_IPIw: reg_esp+=Fetchw(); case S_IP: SaveIP(); - reg_eip=inst.op1.d; + reg_eip=inst_op1_d; continue; case 0: break; diff --git a/src/cpu/core_full/support.h b/src/cpu/core_full/support.h index 120a854..d7f68f7 100644 --- a/src/cpu/core_full/support.h +++ b/src/cpu/core_full/support.h @@ -45,6 +45,7 @@ enum { D_SAHF,D_LAHF, D_CPUID, D_HLT,D_CLTS, + D_LOCK,D_ICEBP, L_ERROR, }; @@ -164,11 +165,22 @@ struct FullData { Bitu rm_mod; OpCode code; EAPoint cseip; +#ifdef WORDS_BIGENDIAN + union { + Bit32u dword[1]; + Bit32s dwords[1]; + Bit16u word[2]; + Bit16s words[2]; + Bit8u byte[4]; + Bit8s bytes[4]; + } blah1,blah2,blah_imm; +#else union { Bit8u b;Bit8s bs; Bit16u w;Bit16s ws; Bit32u d;Bit32s ds; } op1,op2,imm; +#endif Bitu new_flags; struct { EAPoint base; @@ -178,6 +190,55 @@ struct FullData { Bitu prefix; }; +/* Some defines to get the names correct. */ +#ifdef WORDS_BIGENDIAN + +#define inst_op1_b inst.blah1.byte[3] +#define inst_op1_bs inst.blah1.bytes[3] +#define inst_op1_w inst.blah1.word[1] +#define inst_op1_ws inst.blah1.words[1] +#define inst_op1_d inst.blah1.dword[0] +#define inst_op1_ds inst.blah1.dwords[0] + +#define inst_op2_b inst.blah2.byte[3] +#define inst_op2_bs inst.blah2.bytes[3] +#define inst_op2_w inst.blah2.word[1] +#define inst_op2_ws inst.blah2.words[1] +#define inst_op2_d inst.blah2.dword[0] +#define inst_op2_ds inst.blah2.dwords[0] + +#define inst_imm_b inst.blah_imm.byte[3] +#define inst_imm_bs inst.blah_imm.bytes[3] +#define inst_imm_w inst.blah_imm.word[1] +#define inst_imm_ws inst.blah_imm.words[1] +#define inst_imm_d inst.blah_imm.dword[0] +#define inst_imm_ds inst.blah_imm.dwords[0] + +#else + +#define inst_op1_b inst.op1.b +#define inst_op1_bs inst.op1.bs +#define inst_op1_w inst.op1.w +#define inst_op1_ws inst.op1.ws +#define inst_op1_d inst.op1.d +#define inst_op1_ds inst.op1.ds + +#define inst_op2_b inst.op2.b +#define inst_op2_bs inst.op2.bs +#define inst_op2_w inst.op2.w +#define inst_op2_ws inst.op2.ws +#define inst_op2_d inst.op2.d +#define inst_op2_ds inst.op2.ds + +#define inst_imm_b inst.imm.b +#define inst_imm_bs inst.imm.bs +#define inst_imm_w inst.imm.w +#define inst_imm_ws inst.imm.ws +#define inst_imm_d inst.imm.d +#define inst_imm_ds inst.imm.ds + +#endif + #define PREFIX_NONE 0x0 #define PREFIX_ADDR 0x1 diff --git a/src/cpu/core_normal.cpp b/src/cpu/core_normal.cpp index 9aa0db9..5ff39ee 100644 --- a/src/cpu/core_normal.cpp +++ b/src/cpu/core_normal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -171,7 +171,7 @@ restart_opcode: sprintf(writecode,"%X",mem_readb(core.cseip++)); writecode+=2; } - LOG(LOG_CPU,LOG_ERROR)("Illegal/Unhandled opcode %s",tempcode); + LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); } #endif CPU_Exception(6,0); @@ -188,13 +188,12 @@ decode_end: } Bits CPU_Core_Normal_Trap_Run(void) { - Bits oldCycles = CPU_Cycles; CPU_Cycles = 1; core.trap.skip=false; Bits ret=CPU_Core_Normal_Run(); - if (!core.trap.skip) CPU_SW_Interrupt(1,reg_eip); + if (!core.trap.skip) CPU_HW_Interrupt(1); CPU_Cycles = oldCycles-1; cpudecoder = &CPU_Core_Normal_Run; diff --git a/src/cpu/core_normal/Makefile.in b/src/cpu/core_normal/Makefile.in index eab5f25..ce0a632 100644 --- a/src/cpu/core_normal/Makefile.in +++ b/src/cpu/core_normal/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -80,6 +80,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -105,10 +107,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/cpu/core_normal/helpers.h b/src/cpu/core_normal/helpers.h index 9f18fb2..237144b 100644 --- a/src/cpu/core_normal/helpers.h +++ b/src/cpu/core_normal/helpers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/core_normal/prefix_0f.h b/src/cpu/core_normal/prefix_0f.h index 6bea18d..cb24f83 100644 --- a/src/cpu/core_normal/prefix_0f.h +++ b/src/cpu/core_normal/prefix_0f.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -18,6 +18,7 @@ CASE_0F_W(0x00) /* GRP 6 Exxx */ { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; GetRM;Bitu which=(rm>>3)&7; switch (which) { case 0x00: /* SLDT */ @@ -37,10 +38,20 @@ if (rm >= 0xc0 ) {GetEArw;loadval=*earw;} else {GetEAa;loadval=LoadMw(eaa);} switch (which) { - case 0x02:CPU_LLDT(loadval);break; - case 0x03:CPU_LTR(loadval);break; - case 0x04:CPU_VERR(loadval);break; - case 0x05:CPU_VERW(loadval);break; + case 0x02: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LLDT(loadval)) RUNEXCEPTION(); + break; + case 0x03: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LTR(loadval)) RUNEXCEPTION(); + break; + case 0x04: + CPU_VERR(loadval); + break; + case 0x05: + CPU_VERW(loadval); + break; } } break; @@ -66,9 +77,11 @@ SaveMd(eaa+2,base); break; case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF); break; case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF); break; case 0x04: /* SMSW */ @@ -83,6 +96,12 @@ } else { GetEArw;Bitu limit; switch (which) { + case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; + case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; case 0x04: /* SMSW */ CPU_SMSW(limit); *earw=limit; @@ -98,6 +117,7 @@ break; CASE_0F_W(0x02) /* LAR Gw,Ew */ { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; FillFlags(); GetRMrw;Bitu ar=*rmrw; if (rm >= 0xc0) { @@ -110,6 +130,7 @@ break; CASE_0F_W(0x03) /* LSL Gw,Ew */ { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; FillFlags(); GetRMrw;Bitu limit=*rmrw; if (rm >= 0xc0) { @@ -121,52 +142,59 @@ } break; CASE_0F_B(0x06) /* CLTS */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + cpu.cr0&=(~CR0_TASKSWITCH); break; CASE_0F_B(0x20) /* MOV Rd.CRx */ { GetRM; Bitu which=(rm >> 3) & 7; - if (rm >= 0xc0 ) { - GetEArd; - *eard=CPU_GET_CRX(which); - } else { - GetEAa; + if (rm < 0xc0 ) { + rm |= 0xc0; LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%d with non-register",which); } + GetEArd; + Bit32u crx_value; + if (CPU_READ_CRX(which,crx_value)) RUNEXCEPTION(); + *eard=crx_value; } break; CASE_0F_B(0x21) /* MOV Rd,DRx */ { GetRM; Bitu which=(rm >> 3) & 7; - if (rm >= 0xc0 ) { - GetEArd; - } else { - GetEAa; + if (rm < 0xc0 ) { + rm |= 0xc0; LOG(LOG_CPU,LOG_ERROR)("MOV XXX,DR% with non-register",which); } + GetEArd; + Bit32u drx_value; + if (CPU_READ_DRX(which,drx_value)) RUNEXCEPTION(); + *eard=drx_value; } break; CASE_0F_B(0x22) /* MOV CRx,Rd */ { GetRM; Bitu which=(rm >> 3) & 7; - if (rm >= 0xc0 ) { - GetEArd; - if (CPU_SET_CRX(which,*eard)) RUNEXCEPTION(); - } else goto illegal_opcode; + if (rm < 0xc0 ) { + rm |= 0xc0; + LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR% with non-register",which); + } + GetEArd; + if (CPU_WRITE_CRX(which,*eard)) RUNEXCEPTION(); } break; CASE_0F_B(0x23) /* MOV DRx,Rd */ { GetRM; Bitu which=(rm >> 3) & 7; - if (rm >= 0xc0 ) { - GetEArd; - } else { - GetEAa; + if (rm < 0xc0 ) { + rm |= 0xc0; LOG(LOG_CPU,LOG_ERROR)("MOV DR%,XXX with non-register",which); } + GetEArd; + if (CPU_WRITE_DRX(which,*eard)) RUNEXCEPTION(); } break; CASE_0F_W(0x80) /* JO */ @@ -444,6 +472,20 @@ else {GetEAa;*rmrw=LoadMbs(eaa);} break; } + CASE_0F_B(0xc0) /* XADD Gb,Eb */ + { + GetRMrb;Bit8u oldrmrb=*rmrb; + if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;*earb+=oldrmrb;} + else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,LoadMb(eaa)+oldrmrb);} + break; + } + CASE_0F_W(0xc1) /* XADD Gw,Ew */ + { + GetRMrw;Bit16u oldrmrw=*rmrw; + if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;*earw+=oldrmrw;} + else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,LoadMw(eaa)+oldrmrw);} + break; + } CASE_0F_B(0xc8) /* BSWAP EAX */ BSWAP(reg_eax);break; CASE_0F_B(0xc9) /* BSWAP ECX */ diff --git a/src/cpu/core_normal/prefix_66.h b/src/cpu/core_normal/prefix_66.h index 07c55b5..a839c42 100644 --- a/src/cpu/core_normal/prefix_66.h +++ b/src/cpu/core_normal/prefix_66.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -331,8 +331,8 @@ case 0x05: /* MOV Ew,GS */ val=SegValue(gs);break; default: - val=0; - E_Exit("CPU:8c:Illegal RM Byte"); + LOG(LOG_CPU,LOG_ERROR)("CPU:8c:Illegal RM Byte"); + goto illegal_opcode; } if (rm >= 0xc0 ) {GetEArd;*eard=val;} else {GetEAa;SaveMw(eaa,val);} @@ -389,6 +389,12 @@ Bit32u newip=Fetchd();Bit16u newcs=Fetchw(); FillFlags(); CPU_CALL(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } CASE_D(0x9c) /* PUSHFD */ @@ -581,6 +587,12 @@ Bit16u newcs=Fetchw(); FillFlags(); CPU_JMP(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } CASE_D(0xeb) /* JMP Jb */ @@ -657,11 +669,18 @@ continue; case 0x03: /* CALL FAR Ed */ { + if (rm >= 0xc0) goto illegal_opcode; GetEAa; Bit32u newip=LoadMd(eaa); Bit16u newcs=LoadMw(eaa+4); FillFlags(); CPU_CALL(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } case 0x04: /* JMP NEAR Ed */ @@ -670,11 +689,18 @@ continue; case 0x05: /* JMP FAR Ed */ { + if (rm >= 0xc0) goto illegal_opcode; GetEAa; Bit32u newip=LoadMd(eaa); Bit16u newcs=LoadMw(eaa+4); FillFlags(); CPU_JMP(true,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } break; diff --git a/src/cpu/core_normal/prefix_66_0f.h b/src/cpu/core_normal/prefix_66_0f.h index 512117c..d9cc990 100644 --- a/src/cpu/core_normal/prefix_66_0f.h +++ b/src/cpu/core_normal/prefix_66_0f.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -15,8 +15,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + CASE_0F_D(0x00) /* GRP 6 Exxx */ { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; GetRM;Bitu which=(rm>>3)&7; switch (which) { case 0x00: /* SLDT */ @@ -37,15 +39,26 @@ if (rm >= 0xc0 ) {GetEArw;loadval=*earw;} else {GetEAa;loadval=LoadMw(eaa);} switch (which) { - case 0x02:CPU_LLDT(loadval);break; - case 0x03:CPU_LTR(loadval);break; - case 0x04:CPU_VERR(loadval);break; - case 0x05:CPU_VERW(loadval);break; + case 0x02: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LLDT(loadval)) RUNEXCEPTION(); + break; + case 0x03: + if (cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (CPU_LTR(loadval)) RUNEXCEPTION(); + break; + case 0x04: + CPU_VERR(loadval); + break; + case 0x05: + CPU_VERW(loadval); + break; } } break; default: LOG(LOG_CPU,LOG_ERROR)("GRP6:Illegal call %2X",which); + goto illegal_opcode; } } break; @@ -66,9 +79,11 @@ SaveMd(eaa+2,(Bit32u)base); break; case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2)); break; case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2)); break; case 0x04: /* SMSW */ @@ -77,21 +92,28 @@ break; case 0x06: /* LMSW */ limit=LoadMw(eaa); - if (!CPU_LMSW((Bit16u)limit)) goto decode_end; + if (CPU_LMSW((Bit16u)limit)) RUNEXCEPTION(); break; } } else { GetEArd;Bitu limit; switch (which) { + case 0x02: /* LGDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; + case 0x03: /* LIDT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + goto illegal_opcode; case 0x04: /* SMSW */ CPU_SMSW(limit); *eard=(Bit32u)limit; break; case 0x06: /* LMSW */ - if (!CPU_LMSW(*eard)) goto decode_end; + if (CPU_LMSW(*eard)) RUNEXCEPTION(); break; default: LOG(LOG_CPU,LOG_ERROR)("Illegal group 7 RM subfunction %d",which); + goto illegal_opcode; break; } @@ -100,6 +122,7 @@ break; CASE_0F_D(0x02) /* LAR Gd,Ed */ { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; FillFlags(); GetRMrd;Bitu ar=*rmrd; if (rm >= 0xc0) { @@ -112,6 +135,7 @@ break; CASE_0F_D(0x03) /* LSL Gd,Ew */ { + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode; FillFlags(); GetRMrd;Bitu limit=*rmrd; /* Just load 16-bit values for selectors */ @@ -376,3 +400,10 @@ else {GetEAa;*rmrd=LoadMws(eaa);} break; } + CASE_0F_D(0xc1) /* XADD Gd,Ed */ + { + GetRMrd;Bit32u oldrmrd=*rmrd; + if (rm >= 0xc0 ) {GetEArd;*rmrd=*eard;*eard+=oldrmrd;} + else {GetEAa;*rmrd=LoadMd(eaa);SaveMd(eaa,LoadMd(eaa)+oldrmrd);} + break; + } diff --git a/src/cpu/core_normal/prefix_none.h b/src/cpu/core_normal/prefix_none.h index 0cc2c35..44a9a94 100644 --- a/src/cpu/core_normal/prefix_none.h +++ b/src/cpu/core_normal/prefix_none.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -472,8 +472,8 @@ case 0x05: /* MOV Ew,GS */ val=SegValue(gs);break; default: - val=0; - E_Exit("CPU:8c:Illegal RM Byte"); + LOG(LOG_CPU,LOG_ERROR)("CPU:8c:Illegal RM Byte"); + goto illegal_opcode; } if (rm >= 0xc0 ) {GetEArw;*earw=val;} else {GetEAa;SaveMw(eaa,val);} @@ -551,6 +551,12 @@ FillFlags(); Bit16u newip=Fetchw();Bit16u newcs=Fetchw(); CPU_CALL(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } CASE_B(0x9b) /* WAIT */ @@ -727,7 +733,7 @@ if (DEBUG_Breakpoint()) return debugCallback; #endif - CPU_SW_Interrupt(3,GETIP); + CPU_SW_Interrupt_NoIOPLCheck(3,GETIP); #if CPU_TRAP_CHECK core.trap.skip=true; #endif @@ -761,14 +767,14 @@ { FillFlags(); CPU_IRET(false,GETIP); -#if CPU_PIC_CHECK - if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE; -#endif #if CPU_TRAP_CHECK if (GETFLAG(TF)) { cpudecoder=CPU_Core_Normal_Trap_Run; return CBRET_NONE; } +#endif +#if CPU_PIC_CHECK + if (GETFLAG(IF) && PIC_IRQCheck) return CBRET_NONE; #endif continue; } @@ -900,6 +906,12 @@ Bit16u newcs=Fetchw(); FillFlags(); CPU_JMP(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } CASE_W(0xeb) /* JMP Jb */ @@ -926,8 +938,15 @@ IO_WriteW(reg_dx,reg_ax); break; CASE_B(0xf0) /* LOCK */ - LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK"); + LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK"); /* FIXME: see case D_LOCK in core_full/load.h */ break; + CASE_B(0xf1) /* ICEBP */ + FillFlags(); + CPU_SW_Interrupt_NoIOPLCheck(1,GETIP); +#if CPU_TRAP_CHECK + core.trap.skip=true; +#endif + continue; CASE_B(0xf2) /* REPNZ */ DO_PREFIX_REP(false); break; @@ -935,6 +954,7 @@ DO_PREFIX_REP(true); break; CASE_B(0xf4) /* HLT */ + if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); FillFlags(); CPU_HLT(GETIP); return CBRET_NONE; //Needs to return for hlt cpu core @@ -1094,11 +1114,18 @@ continue; case 0x03: /* CALL Ep */ { + if (rm >= 0xc0) goto illegal_opcode; GetEAa; Bit16u newip=LoadMw(eaa); Bit16u newcs=LoadMw(eaa+2); FillFlags(); CPU_CALL(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } break; @@ -1108,11 +1135,18 @@ continue; case 0x05: /* JMP Ep */ { + if (rm >= 0xc0) goto illegal_opcode; GetEAa; Bit16u newip=LoadMw(eaa); Bit16u newcs=LoadMw(eaa+2); FillFlags(); CPU_JMP(false,newcs,newip,GETIP); +#if CPU_TRAP_CHECK + if (GETFLAG(TF)) { + cpudecoder=CPU_Core_Normal_Trap_Run; + return CBRET_NONE; + } +#endif continue; } break; diff --git a/src/cpu/core_normal/string.h b/src/cpu/core_normal/string.h index 33ce3d5..a2639eb 100644 --- a/src/cpu/core_normal/string.h +++ b/src/cpu/core_normal/string.h @@ -34,6 +34,7 @@ static void DoString(STRING_OP type) { CPU_Cycles=0; LOADIP; //RESET IP to the start } else { + if ((count<=1) && (CPU_Cycles<=1)) CPU_Cycles--; /* Won't interrupt scas and cmps instruction since they can interrupt themselves */ count_left=0; } diff --git a/src/cpu/core_normal/support.h b/src/cpu/core_normal/support.h index 910f167..2d1aeb1 100644 --- a/src/cpu/core_normal/support.h +++ b/src/cpu/core_normal/support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/core_normal/table_ea.h b/src/cpu/core_normal/table_ea.h index a7352e8..bfe5ed0 100644 --- a/src/cpu/core_normal/table_ea.h +++ b/src/cpu/core_normal/table_ea.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/core_simple.cpp b/src/cpu/core_simple.cpp index 7ff744e..72d722e 100644 --- a/src/cpu/core_simple.cpp +++ b/src/cpu/core_simple.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -165,7 +165,7 @@ restart_opcode: // sprintf(writecode,"%X",mem_readb(core.cseip++)); writecode+=2; } - LOG(LOG_CPU,LOG_ERROR)("Illegal/Unhandled opcode %s",tempcode); + LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode); } #endif CPU_Exception(6,0); @@ -200,4 +200,3 @@ Bits CPU_Core_Simple_Trap_Run(void) { void CPU_Core_Simple_Init(void) { } - diff --git a/src/cpu/cpu.cpp b/src/cpu/cpu.cpp index acb576b..1a58ff5 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: cpu.cpp,v 1.61 2004/08/23 12:17:29 harekiet Exp $ */ +/* $Id: cpu.cpp,v 1.79 2006/02/26 16:11:00 qbix79 Exp $ */ #include #include "dosbox.h" @@ -45,20 +45,60 @@ Bits CPU_CycleMax = 2500; Bits CPU_CycleUp = 0; Bits CPU_CycleDown = 0; CPU_Decoder * cpudecoder; +bool CPU_CycleAuto; void CPU_Core_Full_Init(void); void CPU_Core_Normal_Init(void); void CPU_Core_Simple_Init(void); void CPU_Core_Dyn_X86_Init(void); +void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache); + +/* In debug mode exceptions are tested and dosbox exits when + * a unhandled exception state is detected. + * USE CHECK_EXCEPT to raise an exception in that case to see if that exception + * solves the problem. + * + * In non-debug mode dosbox doesn't do detection (and hence doesn't crash at + * that point). (game might crash later due to the unhandled exception) */ + +#if C_DEBUG +// #define CPU_CHECK_EXCEPT 1 +// #define CPU_CHECK_IGNORE 1 + /* Use CHECK_EXCEPT when something doesn't work to see if a exception is + * needed that isn't enabled by default.*/ +#else +/* NORMAL NO CHECKING => More Speed */ +#define CPU_CHECK_IGNORE 1 +#endif /* C_DEBUG */ + +#if defined(CPU_CHECK_IGNORE) +#define CPU_CHECK_COND(cond,msg,exc,sel) { \ + cond; \ +} +#elif defined(CPU_CHECK_EXCEPT) +#define CPU_CHECK_COND(cond,msg,exc,sel) { \ + if (cond) { \ + CPU_Exception(exc,sel); \ + return; \ + } \ +} +#else +#define CPU_CHECK_COND(cond,msg,exc,sel) { \ + if (cond) E_Exit(msg); \ +} +#endif + void CPU_Push16(Bitu value) { - reg_esp=(reg_esp&~cpu.stack.mask)|((reg_esp-2)&cpu.stack.mask); - mem_writew(SegPhys(ss) + (reg_esp & cpu.stack.mask) ,value); + Bit32u new_esp=(reg_esp&~cpu.stack.mask)|((reg_esp-2)&cpu.stack.mask); + mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value); + reg_esp=new_esp; } void CPU_Push32(Bitu value) { - reg_esp=(reg_esp&~cpu.stack.mask)|((reg_esp-4)&cpu.stack.mask); - mem_writed(SegPhys(ss) + (reg_esp & cpu.stack.mask) ,value); + Bit32u new_esp=(reg_esp&~cpu.stack.mask)|((reg_esp-4)&cpu.stack.mask); + mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value); + reg_esp=new_esp; } Bitu CPU_Pop16(void) { @@ -96,7 +136,7 @@ bool CPU_PrepareException(Bitu which,Bitu error) { bool CPU_CLI(void) { if (cpu.pmode && ((!GETFLAG(VM) && (GETFLAG_IOPL0)) mask &= (~FLAG_IOPL); + if (cpu.pmode && !GETFLAG(VM) && (GETFLAG_IOPL0; @@ -302,7 +400,8 @@ doconforming: CPU_SetSegGeneral(ds,new_ds); CPU_SetSegGeneral(fs,new_fs); CPU_SetSegGeneral(gs,new_gs); - CPU_LTR(new_tss_selector); + if (!cpu_tss.SetSelector(new_tss_selector)) LOG(LOG_CPU,LOG_NORMAL)("TaskSwitch: set tss selector %X failed",new_tss_selector); + cpu_tss.desc.SetBusy(true); // LOG_MSG("Task CPL %X CS:%X IP:%X SS:%X SP:%X eflags %x",cpu.cpl,SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags); return true; } @@ -320,8 +419,8 @@ bool CPU_IO_Exception(Bitu port,Bitu size) { } return false; doexception: - LOG_MSG("Exception"); - return CPU_PrepareException(13,0); + LOG(LOG_CPU,LOG_NORMAL)("IO Exception port %X",port); + return CPU_PrepareException(EXCEPTION_GP,0); } void CPU_Exception(Bitu which,Bitu error ) { @@ -340,7 +439,7 @@ void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) { LOG(LOG_CPU,LOG_ERROR)("Call to interrupt 0xCD this is BAD"); DEBUG_HeavyWriteLogInstruction(); #endif - E_Exit("Call to interrupt 0xCD this is BAD"); + E_Exit("Call to interrupt 0xCD this is BAD"); case 0x03: if (DEBUG_Breakpoint()) { CPU_Cycles=0; @@ -349,7 +448,7 @@ void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) { }; #endif if (!cpu.pmode) { - /* Save everything on a 16-bit stack */ + /* Save everything on a 16-bit stack */ CPU_Push16(reg_flags & 0xffff); CPU_Push16(SegValue(cs)); CPU_Push16(oldeip); @@ -364,23 +463,31 @@ void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) { return; } else { /* Protected Mode Interrupt */ -// if (type&CPU_INT_SOFTWARE && cpu.v86) goto realmode_interrupt; -// DEBUG_EnableDebugger(); -// LOG_MSG("interrupt start CPL %d v86 %d",cpu.cpl,cpu.v86); - if ((reg_flags & FLAG_VM) && (type&CPU_INT_SOFTWARE)) { + if ((reg_flags & FLAG_VM) && (type&CPU_INT_SOFTWARE) && !(type&CPU_INT_NOIOPLCHECK)) { // LOG_MSG("Software int in v86, AH %X IOPL %x",reg_ah,(reg_flags & FLAG_IOPL) >>12); if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) { - CPU_Exception(13,0); + CPU_Exception(EXCEPTION_GP,0); return; } } Descriptor gate; -//TODO Check for software interrupt and check gate's dplcpu.cpl) E_Exit("Interrupt to higher privilege"); + CPU_CHECK_COND(cs_dpl>cpu.cpl, + "Interrupt to higher privilege", + EXCEPTION_GP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) switch (cs_desc.Type()) { case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: if (cs_dpl0", + EXCEPTION_GP,gate_sel & 0xfffc) + Bitu n_ss,n_esp; Bitu o_ss,o_esp; o_ss=SegValue(ss); o_esp=reg_esp; cpu_tss.Get_SSx_ESPx(cs_dpl,n_ss,n_esp); + CPU_CHECK_COND((n_ss & 0xfffc)==0, + "INT:Gate with SS zero selector", + EXCEPTION_TS,(type&CPU_INT_SOFTWARE)?0:1) Descriptor n_ss_desc; - cpu.gdt.GetDescriptor(n_ss,n_ss_desc); + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc), + "INT:Gate with SS beyond limit", + EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + CPU_CHECK_COND(((n_ss & 3)!=cs_dpl) || (n_ss_desc.DPL()!=cs_dpl), + "INT:Inner level with CS_DPL!=SS_DPL and SS_RPL", + EXCEPTION_TS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + + // check if stack segment is a writable data segment + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + break; + default: + E_Exit("INT:Inner level:Stack segment not writable."); // or #TS(ss_sel+EXT) + } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "INT:Inner level with nonpresent SS", + EXCEPTION_SS,(n_ss & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + + // commit point Segs.phys[ss]=n_ss_desc.GetBase(); Segs.val[ss]=n_ss; if (n_ss_desc.Big()) { @@ -412,8 +556,10 @@ void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) { } else { cpu.stack.big=false; cpu.stack.mask=0xffff; - reg_sp=n_esp; + reg_sp=n_esp & 0xffff; } + + cpu.cpl=cs_dpl; if (gate.Type() & 0x8) { /* 32-bit Gate */ if (reg_flags & FLAG_VM) { CPU_Push32(SegValue(gs));SegSet16(gs,0x0); @@ -429,15 +575,20 @@ void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip) { CPU_Push16(o_esp); } // LOG_MSG("INT:Gate to inner level SS:%X SP:%X",n_ss,n_esp); - cpu.cpl=cs_dpl; goto do_interrupt; } + if (cs_dpl!=cpu.cpl) + E_Exit("Non-conforming intra privilege INT with DPL!=CPL"); case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: - /* Prepare stack for gate to same priviledge */ - if (reg_flags & FLAG_VM) - E_Exit("V86 interrupt doesn't change to pl0"); + /* Prepare stack for gate to same priviledge */ + CPU_CHECK_COND(!cs_desc.saved.seg.p, + "INT:Same level:CS segment not present", + EXCEPTION_NP,(gate_sel & 0xfffc)+(type&CPU_INT_SOFTWARE)?0:1) + if ((reg_flags & FLAG_VM) && (cs_dpl0; + reg_eip=gate_off; + if (!(gate.Type()&1)) SETFLAGBIT(IF,false); SETFLAGBIT(TF,false); SETFLAGBIT(NT,false); SETFLAGBIT(VM,false); - Segs.val[cs]=(gate_sel&0xfffc) | cpu.cpl; - Segs.phys[cs]=cs_desc.GetBase(); - cpu.code.big=cs_desc.Big()>0; LOG(LOG_CPU,LOG_NORMAL)("INT:Gate to %X:%X big %d %s",gate_sel,gate_off,cs_desc.Big(),gate.Type() & 0x8 ? "386" : "286"); - reg_eip=gate_off; return; } case DESC_TASK_GATE: @@ -482,119 +635,135 @@ do_interrupt: return ; // make compiler happy } + void CPU_IRET(bool use32,Bitu oldeip) { if (!cpu.pmode) { /* RealMode IRET */ -realmode_iret: if (use32) { reg_eip=CPU_Pop32(); SegSet16(cs,CPU_Pop32()); - CPU_SetFlagsd(CPU_Pop32()); + CPU_SetFlags(CPU_Pop32(),FMASK_ALL); } else { reg_eip=CPU_Pop16(); SegSet16(cs,CPU_Pop16()); - CPU_SetFlagsw(CPU_Pop16()); + CPU_SetFlags(CPU_Pop16(),FMASK_ALL & 0xffff); } cpu.code.big=false; return; } else { /* Protected mode IRET */ if (reg_flags & FLAG_VM) { if ((reg_flags & FLAG_IOPL)!=FLAG_IOPL) { - CPU_Exception(13,0); + // win3.x e + CPU_Exception(EXCEPTION_GP,0); return; - } else goto realmode_iret; + } else { + if (use32) { + reg_eip=CPU_Pop32(); + SegSet16(cs,CPU_Pop32()); + /* IOPL can not be modified in v86 mode by IRET */ + CPU_SetFlags(CPU_Pop32(),FMASK_NORMAL|FLAG_NT); + } else { + reg_eip=CPU_Pop16(); + SegSet16(cs,CPU_Pop16()); + /* IOPL can not be modified in v86 mode by IRET */ + CPU_SetFlags(CPU_Pop16(),FMASK_NORMAL|FLAG_NT); + } + cpu.code.big=false; + return; + } } -// DEBUG_EnableDebugger(); -// LOG_MSG("IRET start CPL %d v86 %d",cpu.cpl,cpu.v86); /* Check if this is task IRET */ if (GETFLAG(NT)) { if (GETFLAG(VM)) E_Exit("Pmode IRET with VM bit set"); - if (!cpu_tss.IsValid()) E_Exit("TASK Iret without valid TSS"); + CPU_CHECK_COND(!cpu_tss.IsValid(), + "TASK Iret without valid TSS", + EXCEPTION_TS,cpu_tss.selector & 0xfffc) + if (!cpu_tss.desc.IsBusy()) LOG(LOG_CPU,LOG_ERROR)("TASK Iret:TSS not busy"); Bitu back_link=cpu_tss.Get_back(); CPU_SwitchTask(back_link,TSwitch_IRET,oldeip); return; } Bitu n_cs_sel,n_eip,n_flags; if (use32) { + // commit point n_eip=CPU_Pop32(); n_cs_sel=CPU_Pop32() & 0xffff; n_flags=CPU_Pop32(); - if (n_flags & FLAG_VM) { - cpu.cpl=3; - CPU_SetFlags(n_flags,FMASK_ALL | FLAG_VM); + if ((n_flags & FLAG_VM) && (cpu.cpl==0)) { + reg_eip=n_eip & 0xffff; Bitu n_ss,n_esp,n_es,n_ds,n_fs,n_gs; n_esp=CPU_Pop32(); n_ss=CPU_Pop32() & 0xffff; - n_es=CPU_Pop32() & 0xffff; n_ds=CPU_Pop32() & 0xffff; n_fs=CPU_Pop32() & 0xffff; n_gs=CPU_Pop32() & 0xffff; + + CPU_SetFlags(n_flags,FMASK_ALL | FLAG_VM); + cpu.cpl=3; + CPU_SetSegGeneral(ss,n_ss); CPU_SetSegGeneral(es,n_es); CPU_SetSegGeneral(ds,n_ds); CPU_SetSegGeneral(fs,n_fs); CPU_SetSegGeneral(gs,n_gs); - reg_eip=n_eip & 0xffff; reg_esp=n_esp; cpu.code.big=false; SegSet16(cs,n_cs_sel); LOG(LOG_CPU,LOG_NORMAL)("IRET:Back to V86: CS:%X IP %X SS:%X SP %X FLAGS:%X",SegValue(cs),reg_eip,SegValue(ss),reg_esp,reg_flags); return; } + if (n_flags & FLAG_VM) E_Exit("IRET from pmode to v86 with CPL!=0"); } else { n_eip=CPU_Pop16(); n_cs_sel=CPU_Pop16(); n_flags=(reg_flags & 0xffff0000) | CPU_Pop16(); if (n_flags & FLAG_VM) E_Exit("VM Flag in 16-bit iret"); } + CPU_CHECK_COND((n_cs_sel & 0xfffc)==0, + "IRET:CS selector zero", + EXCEPTION_GP,0) Bitu n_cs_rpl=n_cs_sel & 3; Descriptor n_cs_desc; - cpu.gdt.GetDescriptor(n_cs_sel,n_cs_desc); - if (n_cs_rpln_cs_rpl, + "IRET:C:DPL>RPL", + EXCEPTION_GP,n_cs_sel & 0xfffc) + break; + default: + E_Exit("IRET:Illegal descriptor type %X",n_cs_desc.Type()); + } + CPU_CHECK_COND(!n_cs_desc.saved.seg.p, + "IRET with nonpresent code segment", + EXCEPTION_NP,n_cs_sel & 0xfffc) + if (n_cs_rpl==cpu.cpl) { /* Return to same level */ - switch (n_cs_desc.Type()) { - case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: - case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: - if (!(cpu.cpl==n_cs_desc.DPL())) E_Exit("IRET:Same Level:NC:DPL!=CPL"); - break; - case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: - case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: - if (!(n_cs_desc.DPL()>=cpu.cpl)) E_Exit("IRET:Same level:C:DPL0; Segs.val[cs]=n_cs_sel; reg_eip=n_eip; - CPU_SetFlagsd(n_flags); + Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL; + if (GETFLAG_IOPL0; - Segs.val[cs]=n_cs_sel; - - CPU_SetFlagsd(n_flags); - - cpu.cpl=n_cs_rpl; - reg_eip=n_eip; Bitu n_ss,n_esp; if (use32) { n_esp=CPU_Pop32(); @@ -603,20 +772,93 @@ realmode_iret: n_esp=CPU_Pop16(); n_ss=CPU_Pop16(); } - CPU_SetSegGeneral(ss,n_ss); - if (cpu.stack.big) { + CPU_CHECK_COND((n_ss & 0xfffc)==0, + "IRET:Outer level:SS selector zero", + EXCEPTION_GP,0) + CPU_CHECK_COND((n_ss & 3)!=n_cs_rpl, + "IRET:Outer level:SS rpl!=CS rpl", + EXCEPTION_GP,n_ss & 0xfffc) + Descriptor n_ss_desc; + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc), + "IRET:Outer level:SS beyond limit", + EXCEPTION_GP,n_ss & 0xfffc) + CPU_CHECK_COND(n_ss_desc.DPL()!=n_cs_rpl, + "IRET:Outer level:SS dpl!=CS rpl", + EXCEPTION_GP,n_ss & 0xfffc) + + // check if stack segment is a writable data segment + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + break; + default: + E_Exit("IRET:Outer level:Stack segment not writable"); // or #GP(ss_sel) + } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "IRET:Outer level:Stack segment not present", + EXCEPTION_NP,n_ss & 0xfffc) + + Segs.phys[cs]=n_cs_desc.GetBase(); + cpu.code.big=n_cs_desc.Big()>0; + Segs.val[cs]=n_cs_sel; + + Bitu mask=cpu.cpl ? (FMASK_NORMAL | FLAG_NT) : FMASK_ALL; + if (GETFLAG_IOPLdesc.DPL()) CPU_SetSegGeneral(es,0); break; + default: break; } + cpu.gdt.GetDescriptor(SegValue(ds),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(ds,0); break; + default: break; } + cpu.gdt.GetDescriptor(SegValue(fs),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(fs,0); break; + default: break; } + cpu.gdt.GetDescriptor(SegValue(gs),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(gs,0); break; + default: break; } + LOG(LOG_CPU,LOG_NORMAL)("IRET:Outer level:%X:%X big %d",n_cs_sel,n_eip,cpu.code.big); } return; } } + void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip) { if (!cpu.pmode || (reg_flags & FLAG_VM)) { if (!use32) { @@ -628,24 +870,38 @@ void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip) { cpu.code.big=false; return; } else { + CPU_CHECK_COND((selector & 0xfffc)==0, + "JMP:CS selector zero", + EXCEPTION_GP,0) Bitu rpl=selector & 3; Descriptor desc; - cpu.gdt.GetDescriptor(selector,desc); - if (!desc.saved.seg.p) { - CPU_Exception(0x0B,selector & 0xfffc); - return; - } + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(selector,desc), + "JMP:CS beyond limits", + EXCEPTION_GP,selector & 0xfffc) switch (desc.Type()) { case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: - if (rpl>cpu.cpl) E_Exit("JMP:NC:RPL>CPL"); - if (cpu.cpl!=desc.DPL()) E_Exit("JMP:NC:RPL != DPL"); + CPU_CHECK_COND(rpl>cpu.cpl, + "JMP:NC:RPL>CPL", + EXCEPTION_GP,selector & 0xfffc) + CPU_CHECK_COND(cpu.cpl!=desc.DPL(), + "JMP:NC:RPL != DPL", + EXCEPTION_GP,selector & 0xfffc) LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:NC to %X:%X big %d",selector,offset,desc.Big()); goto CODE_jmp; case DESC_CODE_N_C_A: case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: LOG(LOG_CPU,LOG_NORMAL)("JMP:Code:C to %X:%X big %d",selector,offset,desc.Big()); + CPU_CHECK_COND(cpu.cpl0; @@ -653,8 +909,12 @@ CODE_jmp: reg_eip=offset; return; case DESC_386_TSS_A: - if (desc.DPL()cpu.cpl) E_Exit("CALL:CODE:NC:RPL>CPL"); - if (call.DPL()!=cpu.cpl) E_Exit("CALL:CODE:NC:DPL!=CPL"); + CPU_CHECK_COND(rpl>cpu.cpl, + "CALL:CODE:NC:RPL>CPL", + EXCEPTION_GP,selector & 0xfffc) + CPU_CHECK_COND(call.DPL()!=cpu.cpl, + "CALL:CODE:NC:DPL!=CPL", + EXCEPTION_GP,selector & 0xfffc) LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:NC to %X:%X",selector,offset); goto call_code; case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: - if (call.DPL()>cpu.cpl) E_Exit("CALL:CODE:C:DPL>CPL"); + CPU_CHECK_COND(call.DPL()>cpu.cpl, + "CALL:CODE:C:DPL>CPL", + EXCEPTION_GP,selector & 0xfffc) LOG(LOG_CPU,LOG_NORMAL)("CALL:CODE:C to %X:%X",selector,offset); call_code: + if (!call.saved.seg.p) { + // borland extender (RTM) + CPU_Exception(EXCEPTION_NP,selector & 0xfffc); + return; + } + // commit point if (!use32) { CPU_Push16(SegValue(cs)); CPU_Push16(oldeip); @@ -718,45 +990,109 @@ call_code: case DESC_386_CALL_GATE: case DESC_286_CALL_GATE: { - if (call.DPL()cpu.cpl, + "CALL:Gate:CS DPL>CPL", + EXCEPTION_GP,n_cs_sel & 0xfffc) Bitu n_cs_rpl = n_cs_sel & 3; Bitu n_eip = call.GetOffset(); switch (n_cs_desc.Type()) { case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA: - /* Check if we goto innter priviledge */ + /* Check if we goto inner priviledge */ if (n_cs_dpl < cpu.cpl) { + CPU_CHECK_COND(!n_cs_desc.saved.seg.p, + "CALL:Gate:CS not present", + EXCEPTION_NP,n_cs_sel & 0xfffc) /* Get new SS:ESP out of TSS */ Bitu n_ss_sel,n_esp; Descriptor n_ss_desc; cpu_tss.Get_SSx_ESPx(n_cs_dpl,n_ss_sel,n_esp); - if (!cpu.gdt.GetDescriptor(n_ss_sel,n_ss_desc)) E_Exit("Call:Gate:Invalid SS selector."); - /* New CPL is new SS DPL */ - cpu.cpl = n_ss_desc.DPL(); + CPU_CHECK_COND((n_ss_sel & 0xfffc)==0, + "CALL:Gate:NC:SS selector zero", + EXCEPTION_TS,0) + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss_sel,n_ss_desc), + "CALL:Gate:Invalid SS selector", + EXCEPTION_TS,n_ss_sel & 0xfffc) + CPU_CHECK_COND(((n_ss_sel & 3)!=n_cs_desc.DPL()) || (n_ss_desc.DPL()!=n_cs_desc.DPL()), + "CALL:Gate:Invalid SS selector privileges", + EXCEPTION_TS,n_ss_sel & 0xfffc) + + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + // writable data segment + break; + default: + E_Exit("Call:Gate:SS no writable data segment"); // or #TS(ss_sel) + } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "CALL:Gate:Stack segment not present", + EXCEPTION_SS,n_ss_sel & 0xfffc) + /* Load the new SS:ESP and save data on it */ Bitu o_esp = reg_esp; Bitu o_ss = SegValue(ss); PhysPt o_stack = SegPhys(ss)+(reg_esp & cpu.stack.mask); - - CPU_SetSegGeneral(ss,n_ss_sel); - if (cpu.stack.big) reg_esp=n_esp; - else reg_sp=n_esp; + + // catch pagefaults + if (call.saved.gate.paramcount&31) { + if (call.Type()==DESC_386_CALL_GATE) { + for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) + mem_readd(o_stack+i*4); + } else { + for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) + mem_readw(o_stack+i*2); + } + } + + // commit point + Segs.val[ss]=n_ss_sel; + Segs.phys[ss]=n_ss_desc.GetBase(); + if (n_ss_desc.Big()) { + cpu.stack.big=true; + cpu.stack.mask=0xffffffff; + reg_esp=n_esp; + } else { + cpu.stack.big=false; + cpu.stack.mask=0xffff; + reg_sp=n_esp & 0xffff; + } + + cpu.cpl = n_cs_desc.DPL(); + Bit16u oldcs = SegValue(cs); + /* Switch to new CS:EIP */ + Segs.phys[cs] = n_cs_desc.GetBase(); + Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl; + cpu.code.big = n_cs_desc.Big()>0; + reg_eip = n_eip; + if (!use32) reg_eip&=0xffff; + if (call.Type()==DESC_386_CALL_GATE) { CPU_Push32(o_ss); //save old stack CPU_Push32(o_esp); if (call.saved.gate.paramcount&31) for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) CPU_Push32(mem_readd(o_stack+i*4)); - CPU_Push32(SegValue(cs)); + CPU_Push32(oldcs); CPU_Push32(oldeip); } else { CPU_Push16(o_ss); //save old stack @@ -764,30 +1100,44 @@ call_code: if (call.saved.gate.paramcount&31) for (Bits i=(call.saved.gate.paramcount&31)-1;i>=0;i--) CPU_Push16(mem_readw(o_stack+i*2)); - CPU_Push16(SegValue(cs)); + CPU_Push16(oldcs); CPU_Push16(oldeip); } - cpu.cpl = n_cs_desc.DPL(); - /* Switch to new CS:EIP */ - Segs.phys[cs] = n_cs_desc.GetBase(); - Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl; - cpu.code.big = n_cs_desc.Big()>0; - reg_eip = n_eip; - if (!use32) reg_eip&=0xffff; break; - } + } else if (n_cs_dpl > cpu.cpl) + E_Exit("CALL:GATE:CS DPL>CPL"); // or #GP(sel) case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: -call_gate_same_privilege: - E_Exit("Call gate to same priviledge"); + // zrdx extender + + if (call.Type()==DESC_386_CALL_GATE) { + CPU_Push32(SegValue(cs)); + CPU_Push32(oldeip); + } else { + CPU_Push16(SegValue(cs)); + CPU_Push16(oldeip); + } + + /* Switch to new CS:EIP */ + Segs.phys[cs] = n_cs_desc.GetBase(); + Segs.val[cs] = (n_cs_sel & 0xfffc) | cpu.cpl; + cpu.code.big = n_cs_desc.Big()>0; + reg_eip = n_eip; + if (!use32) reg_eip&=0xffff; break; + default: + E_Exit("CALL:GATE:CS no executable segment"); } } /* Call Gates */ break; case DESC_386_TSS_A: - if (call.DPL()=cpu.cpl)) E_Exit("RET to C segment of higher privilege"); + CPU_CHECK_COND(desc.DPL()>cpu.cpl, + "RET to C segment of higher privilege", + EXCEPTION_GP,selector & 0xfffc) break; default: E_Exit("RET from illegal descriptor type %X",desc.Type()); } RET_same_level: + if (!desc.saved.seg.p) { + // borland extender (RTM) + CPU_Exception(EXCEPTION_NP,selector & 0xfffc); + return; + } + + // commit point + if (!use32) { + offset=CPU_Pop16(); + selector=CPU_Pop16(); + } else { + offset=CPU_Pop32(); + selector=CPU_Pop32() & 0xffff; + } Segs.phys[cs]=desc.GetBase(); cpu.code.big=desc.Big()>0; @@ -869,29 +1232,114 @@ RET_same_level: return; } else { /* Return to outer level */ - if (bytes) E_Exit("RETF outer level with immediate value"); + switch (desc.Type()) { + case DESC_CODE_N_NC_A:case DESC_CODE_N_NC_NA: + case DESC_CODE_R_NC_A:case DESC_CODE_R_NC_NA: + CPU_CHECK_COND(desc.DPL()!=rpl, + "RET to outer NC segment with DPL!=RPL", + EXCEPTION_GP,selector & 0xfffc) + break; + case DESC_CODE_N_C_A:case DESC_CODE_N_C_NA: + case DESC_CODE_R_C_A:case DESC_CODE_R_C_NA: + CPU_CHECK_COND(desc.DPL()>rpl, + "RET to outer C segment with DPL>RPL", + EXCEPTION_GP,selector & 0xfffc) + break; + default: + E_Exit("RET from illegal descriptor type %X",desc.Type()); // or #GP(selector) + } + + CPU_CHECK_COND(!desc.saved.seg.p, + "RET:Outer level:CS not present", + EXCEPTION_NP,selector & 0xfffc) + + // commit point Bitu n_esp,n_ss; if (use32) { + offset=CPU_Pop32(); + selector=CPU_Pop32() & 0xffff; + reg_esp+=bytes; n_esp = CPU_Pop32(); n_ss = CPU_Pop32() & 0xffff; } else { + offset=CPU_Pop16(); + selector=CPU_Pop16(); + reg_esp+=bytes; n_esp = CPU_Pop16(); n_ss = CPU_Pop16(); } - cpu.cpl = rpl; - CPU_SetSegGeneral(ss,n_ss); - if (cpu.stack.big) { - reg_esp = n_esp; - } else { - reg_sp = n_esp; + CPU_CHECK_COND((n_ss & 0xfffc)==0, + "RET to outer level with SS selector zero", + EXCEPTION_GP,0) + + Descriptor n_ss_desc; + CPU_CHECK_COND(!cpu.gdt.GetDescriptor(n_ss,n_ss_desc), + "RET:SS beyond limits", + EXCEPTION_GP,n_ss & 0xfffc) + + CPU_CHECK_COND(((n_ss & 3)!=rpl) || (n_ss_desc.DPL()!=rpl), + "RET to outer segment with invalid SS privileges", + EXCEPTION_GP,n_ss & 0xfffc) + switch (n_ss_desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + break; + default: + E_Exit("RET:SS selector type no writable data segment"); // or #GP(selector) } + CPU_CHECK_COND(!n_ss_desc.saved.seg.p, + "RET:Stack segment not present", + EXCEPTION_SS,n_ss & 0xfffc) + cpu.cpl = rpl; Segs.phys[cs]=desc.GetBase(); cpu.code.big=desc.Big()>0; Segs.val[cs]=(selector&0xfffc) | cpu.cpl; reg_eip=offset; + Segs.val[ss]=n_ss; + Segs.phys[ss]=n_ss_desc.GetBase(); + if (n_ss_desc.Big()) { + cpu.stack.big=true; + cpu.stack.mask=0xffffffff; + reg_esp=n_esp+bytes; + } else { + cpu.stack.big=false; + cpu.stack.mask=0xffff; + reg_sp=(n_esp & 0xffff)+bytes; + } + + Descriptor desc; + cpu.gdt.GetDescriptor(SegValue(es),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(es,0); break; + default: break; } + cpu.gdt.GetDescriptor(SegValue(ds),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(ds,0); break; + default: break; } + cpu.gdt.GetDescriptor(SegValue(fs),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(fs,0); break; + default: break; } + cpu.gdt.GetDescriptor(SegValue(gs),desc); + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_N_NC_A: case DESC_CODE_N_NC_NA: case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (cpu.cpl>desc.DPL()) CPU_SetSegGeneral(gs,0); break; + default: break; } + // LOG(LOG_MISC,LOG_ERROR)("RET - Higher level to %X:%X RPL %X DPL %X",selector,offset,rpl,desc.DPL()); return; } @@ -906,27 +1354,49 @@ void CPU_SLDT(Bitu & selector) { selector=cpu.gdt.SLDT(); } -void CPU_LLDT(Bitu selector) { - cpu.gdt.LLDT(selector); +bool CPU_LLDT(Bitu selector) { + if (!cpu.gdt.LLDT(selector)) { + LOG(LOG_CPU,LOG_ERROR)("LLDT failed, selector=%X",selector); + return true; + } LOG(LOG_CPU,LOG_NORMAL)("LDT Set to %X",selector); + return false; } void CPU_STR(Bitu & selector) { selector=cpu_tss.selector; } -void CPU_LTR(Bitu selector) { - cpu_tss.SetSelector(selector); +bool CPU_LTR(Bitu selector) { + if ((selector & 0xfffc)==0) { + cpu_tss.SetSelector(selector); + return false; + } + TSS_Descriptor desc; + if ((selector & 4) || (!cpu.gdt.GetDescriptor(selector,desc))) { + LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X",selector); + return CPU_PrepareException(EXCEPTION_GP,selector); + } + + if ((desc.Type()==DESC_286_TSS_A) || (desc.Type()==DESC_386_TSS_A)) { + if (!desc.saved.seg.p) { + LOG(LOG_CPU,LOG_ERROR)("LTR failed, selector=%X (not present)",selector); + return CPU_PrepareException(EXCEPTION_NP,selector); + } + if (!cpu_tss.SetSelector(selector)) E_Exit("LTR failed, selector=%X",selector); + cpu_tss.desc.SetBusy(true); + } else { + /* Descriptor was no available TSS descriptor */ + LOG(LOG_CPU,LOG_NORMAL)("LTR failed, selector=%X (type=%X)",selector,desc.Type()); + return CPU_PrepareException(EXCEPTION_GP,selector); + } + return false; } -Bitu gdt_count=0; - void CPU_LGDT(Bitu limit,Bitu base) { - LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X count %d",base,limit,gdt_count++); + LOG(LOG_CPU,LOG_NORMAL)("GDT Set to base:%X limit:%X",base,limit); cpu.gdt.SetLimit(limit); cpu.gdt.SetBase(base); -// if (gdt_count>20) DEBUG_EnableDebugger(); -// DEBUG_EnableDebugger(); } void CPU_LIDT(Bitu limit,Bitu base) { @@ -946,12 +1416,12 @@ void CPU_SIDT(Bitu & limit,Bitu & base) { } -bool CPU_SET_CRX(Bitu cr,Bitu value) { +void CPU_SET_CRX(Bitu cr,Bitu value) { switch (cr) { case 0: { Bitu changed=cpu.cr0 ^ value; - if (!changed) return false; + if (!changed) return; cpu.cr0=value; if (value & CR0_PROTECTION) { cpu.pmode=true; @@ -959,6 +1429,7 @@ bool CPU_SET_CRX(Bitu cr,Bitu value) { PAGING_Enable((value & CR0_PAGING)>0); } else { cpu.pmode=false; + if (value & CR0_PAGING) LOG_MSG("Paging requested without PE=1"); PAGING_Enable(false); LOG(LOG_CPU,LOG_NORMAL)("Real mode"); } @@ -974,6 +1445,13 @@ bool CPU_SET_CRX(Bitu cr,Bitu value) { LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV CR%d,%X",cr,value); break; } +} + +bool CPU_WRITE_CRX(Bitu cr,Bitu value) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0); + CPU_SET_CRX(cr,value); return false; } @@ -984,7 +1462,7 @@ Bitu CPU_GET_CRX(Bitu cr) { case 2: return paging.cr2; case 3: - return PAGING_GetDirBase(); + return PAGING_GetDirBase() & 0xfffff000; default: LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, CR%d",cr); break; @@ -992,12 +1470,73 @@ Bitu CPU_GET_CRX(Bitu cr) { return 0; } +bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + if ((cr==1) || (cr>4)) return CPU_PrepareException(EXCEPTION_UD,0); + retvalue=CPU_GET_CRX(cr); + return false; +} + + +bool CPU_WRITE_DRX(Bitu dr,Bitu value) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + switch (dr) { + case 0: + case 1: + case 2: + case 3: + cpu.drx[dr]=value; + break; + case 4: + case 6: + cpu.drx[6]=(value|0xffff0ff0) & 0xffffefff; + break; + case 5: + case 7: + cpu.drx[7]=(value|0x400) & 0xffff2fff; + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV DR%d,%X",dr,value); + break; + } + return false; +} + +bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue) { + /* Check if privileged to access control registers */ + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); + switch (dr) { + case 0: + case 1: + case 2: + case 3: + case 6: + case 7: + retvalue=cpu.drx[dr]; + break; + case 4: + retvalue=cpu.drx[6]; + break; + case 5: + retvalue=cpu.drx[7]; + break; + default: + LOG(LOG_CPU,LOG_ERROR)("Unhandled MOV XXX, DR%d",dr); + retvalue=0; + break; + } + return false; +} + void CPU_SMSW(Bitu & word) { word=cpu.cr0; } Bitu CPU_LMSW(Bitu word) { + if (cpu.pmode && (cpu.cpl>0)) return CPU_PrepareException(EXCEPTION_GP,0); word&=0xf; if (cpu.cr0 & 1) word|=1; word|=(cpu.cr0&0xfffffff0); @@ -1176,24 +1715,38 @@ bool CPU_SetSegGeneral(SegNames seg,Bitu value) { } return false; } else { - Descriptor desc; - cpu.gdt.GetDescriptor(value,desc); - - if (value!=0) { - if (!desc.saved.seg.p) { - if (seg==ss) E_Exit("CPU_SetSegGeneral: Stack segment not present."); - // Throw Exception 0x0B - Segment not present - return CPU_PrepareException(0x0B,value & 0xfffc); - } else if (seg==ss) { - // Stack segment loaded with illegal segment ? - if ((desc.saved.seg.typeDESC_DATA_ED_RW_A)) { - return CPU_PrepareException(0x0D,value & 0xfffc); - } - } - } - Segs.val[seg]=value; - Segs.phys[seg]=desc.GetBase(); if (seg==ss) { + // Stack needs to be non-zero + if ((value & 0xfffc)==0) { + E_Exit("CPU_SetSegGeneral: Stack segment zero"); +// return CPU_PrepareException(EXCEPTION_GP,0); + } + Descriptor desc; + if (!cpu.gdt.GetDescriptor(value,desc)) { + E_Exit("CPU_SetSegGeneral: Stack segment beyond limits"); +// return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + } + if (((value & 3)!=cpu.cpl) || (desc.DPL()!=cpu.cpl)) { + E_Exit("CPU_SetSegGeneral: Stack segment with invalid privileges"); +// return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + } + + switch (desc.Type()) { + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + break; + default: + //Earth Siege 1 + return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + } + + if (!desc.saved.seg.p) { + E_Exit("CPU_SetSegGeneral: Stack segment not present"); // or #SS(sel) +// return CPU_PrepareException(EXCEPTION_SS,value & 0xfffc); + } + + Segs.val[seg]=value; + Segs.phys[seg]=desc.GetBase(); if (desc.Big()) { cpu.stack.big=true; cpu.stack.mask=0xffffffff; @@ -1201,7 +1754,43 @@ bool CPU_SetSegGeneral(SegNames seg,Bitu value) { cpu.stack.big=false; cpu.stack.mask=0xffff; } + } else { + if ((value & 0xfffc)==0) { + Segs.val[seg]=value; + Segs.phys[seg]=0; // ?? + return false; + } + Descriptor desc; + if (!cpu.gdt.GetDescriptor(value,desc)) { + return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + } + switch (desc.Type()) { + case DESC_DATA_EU_RO_NA: case DESC_DATA_EU_RO_A: + case DESC_DATA_EU_RW_NA: case DESC_DATA_EU_RW_A: + case DESC_DATA_ED_RO_NA: case DESC_DATA_ED_RO_A: + case DESC_DATA_ED_RW_NA: case DESC_DATA_ED_RW_A: + case DESC_CODE_R_NC_A: case DESC_CODE_R_NC_NA: + if (((value & 3)>desc.DPL()) || (cpu.cpl>desc.DPL())) { + // extreme pinball + return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + } + break; + case DESC_CODE_R_C_A: case DESC_CODE_R_C_NA: + break; + default: + // gabriel knight + return CPU_PrepareException(EXCEPTION_GP,value & 0xfffc); + + } + if (!desc.saved.seg.p) { + // win + return CPU_PrepareException(EXCEPTION_NP,value & 0xfffc); + } + + Segs.val[seg]=value; + Segs.phys[seg]=desc.GetBase(); } + return false; } } @@ -1209,7 +1798,7 @@ bool CPU_SetSegGeneral(SegNames seg,Bitu value) { bool CPU_PopSeg(SegNames seg,bool use32) { Bitu val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); if (CPU_SetSegGeneral(seg,val)) return true; - Bitu addsp=2 << use32; + Bitu addsp=use32?0x04:0x02; reg_esp=(reg_esp&~cpu.stack.mask)|((reg_esp+addsp)&cpu.stack.mask); return false; } @@ -1217,16 +1806,16 @@ bool CPU_PopSeg(SegNames seg,bool use32) { void CPU_CPUID(void) { switch (reg_eax) { case 0: /* Vendor ID String and maximum level? */ - reg_eax=0; - reg_ebx=('G'<< 24) || ('e' << 16) || ('n' << 8) || 'u'; - reg_edx=('i'<< 24) || ('n' << 16) || ('e' << 8) || 'T'; - reg_ecx=('n'<< 24) || ('t' << 16) || ('e' << 8) || 'l'; + reg_eax=1; /* Maximum level */ + reg_ebx='G' | ('e' << 8) | ('n' << 16) | ('u'<< 24); + reg_edx='i' | ('n' << 8) | ('e' << 16) | ('I'<< 24); + reg_ecx='n' | ('t' << 8) | ('e' << 16) | ('l'<< 24); break; case 1: /* get processor type/family/model/stepping and feature flags */ reg_eax=0x402; /* intel 486 sx? */ reg_ebx=0; /* Not Supported */ reg_ecx=0; /* No features */ - reg_edx=0; /* Nothing either */ + reg_edx=1; /* FPU */ break; default: LOG(LOG_CPU,LOG_ERROR)("Unhandled CPUID Function %x",reg_eax); @@ -1245,17 +1834,12 @@ static Bits HLT_Decode(void) { } void CPU_HLT(Bitu oldeip) { - if (cpu.cpl) { - CPU_Exception(13,0); - return; - } reg_eip=oldeip; CPU_Cycles=0; cpu.hlt.cs=SegValue(cs); cpu.hlt.eip=reg_eip; cpu.hlt.old_decoder=cpudecoder; cpudecoder=&HLT_Decode; - return; } void CPU_ENTER(bool use32,Bitu bytes,Bitu level) { @@ -1292,7 +1876,9 @@ void CPU_ENTER(bool use32,Bitu bytes,Bitu level) { } extern void GFX_SetTitle(Bits cycles ,Bits frameskip,bool paused); -static void CPU_CycleIncrease(void) { +static void CPU_CycleIncrease(bool pressed) { + if (!pressed || CPU_CycleAuto) + return; Bits old_cycles=CPU_CycleMax; if(CPU_CycleUp < 100){ CPU_CycleMax = (Bits)(CPU_CycleMax * (1 + (float)CPU_CycleUp / 100.0)); @@ -1306,7 +1892,9 @@ static void CPU_CycleIncrease(void) { GFX_SetTitle(CPU_CycleMax,-1,false); } -static void CPU_CycleDecrease(void) { +static void CPU_CycleDecrease(bool pressed) { + if (!pressed || CPU_CycleAuto) + return; if(CPU_CycleDown < 100){ CPU_CycleMax = (Bits)(CPU_CycleMax / (1 + (float)CPU_CycleDown / 100.0)); } else { @@ -1318,69 +1906,112 @@ static void CPU_CycleDecrease(void) { GFX_SetTitle(CPU_CycleMax,-1,false); } -void CPU_Init(Section* sec) { - Section_prop * section=static_cast(sec); - reg_eax=0; - reg_ebx=0; - reg_ecx=0; - reg_edx=0; - reg_edi=0; - reg_esi=0; - reg_ebp=0; - reg_esp=0; - - SegSet16(cs,0); - SegSet16(ds,0); - SegSet16(es,0); - SegSet16(fs,0); - SegSet16(gs,0); - SegSet16(ss,0); - - CPU_SetFlags(FLAG_IF,FMASK_ALL); //Enable interrupts - cpu.cr0=0xffffffff; - CPU_SET_CRX(0,0); //Initialize - cpu.code.big=false; - cpu.stack.mask=0xffff; - cpu.stack.big=false; - cpu.idt.SetBase(0); - cpu.idt.SetLimit(1023); +class CPU: public Module_base { +private: + static bool inited; +public: + CPU(Section* configuration):Module_base(configuration) { + if(inited) { + Change_Config(configuration); + return; + } + inited=true; + Section_prop * section=static_cast(configuration); + reg_eax=0; + reg_ebx=0; + reg_ecx=0; + reg_edx=0; + reg_edi=0; + reg_esi=0; + reg_ebp=0; + reg_esp=0; - /* Init the cpu cores */ - CPU_Core_Normal_Init(); - CPU_Core_Simple_Init(); - CPU_Core_Full_Init(); -#if (C_DYNAMIC_X86) - CPU_Core_Dyn_X86_Init(); -#endif - MAPPER_AddHandler(CPU_CycleDecrease,MK_f11,MMOD1,"cycledown","Dec Cycles"); - MAPPER_AddHandler(CPU_CycleIncrease,MK_f12,MMOD1,"cycleup" ,"Inc Cycles"); - CPU_Cycles=0; - CPU_CycleMax=section->Get_int("cycles");; - CPU_CycleUp=section->Get_int("cycleup"); - CPU_CycleDown=section->Get_int("cycledown"); - const char * core=section->Get_string("core"); - cpudecoder=&CPU_Core_Normal_Run; - if (!strcasecmp(core,"normal")) { - cpudecoder=&CPU_Core_Normal_Run; - } else if (!strcasecmp(core,"simple")) { - cpudecoder=&CPU_Core_Simple_Run; - } else if (!strcasecmp(core,"full")) { - cpudecoder=&CPU_Core_Full_Run; - } -#if (C_DYNAMIC_X86) - else if (!strcasecmp(core,"dynamic")) { - cpudecoder=&CPU_Core_Dyn_X86_Run; - } -#endif - else { - LOG_MSG("CPU:Unknown core type %s, switcing back to normal.",core); - } - CPU_JMP(false,0,0,0); //Setup the first cpu core + SegSet16(cs,0); + SegSet16(ds,0); + SegSet16(es,0); + SegSet16(fs,0); + SegSet16(gs,0); + SegSet16(ss,0); + + CPU_SetFlags(FLAG_IF,FMASK_ALL); //Enable interrupts + cpu.cr0=0xffffffff; + CPU_SET_CRX(0,0); //Initialize + cpu.code.big=false; + cpu.stack.mask=0xffff; + cpu.stack.big=false; + cpu.idt.SetBase(0); + cpu.idt.SetLimit(1023); - if (!CPU_CycleMax) CPU_CycleMax = 2500; - if(!CPU_CycleUp) CPU_CycleUp = 500; - if(!CPU_CycleDown) CPU_CycleDown = 20; - CPU_CycleLeft=0; - GFX_SetTitle(CPU_CycleMax,-1,false); + for (Bitu i=0; i<7; i++) cpu.drx[i]=0; + cpu.drx[6]=0xffff1ff0; + cpu.drx[7]=0x00000400; + + /* Init the cpu cores */ + CPU_Core_Normal_Init(); + CPU_Core_Simple_Init(); + CPU_Core_Full_Init(); +#if (C_DYNAMIC_X86) + CPU_Core_Dyn_X86_Init(); +#endif + MAPPER_AddHandler(CPU_CycleDecrease,MK_f11,MMOD1,"cycledown","Dec Cycles"); + MAPPER_AddHandler(CPU_CycleIncrease,MK_f12,MMOD1,"cycleup" ,"Inc Cycles"); + Change_Config(configuration); + CPU_JMP(false,0,0,0); //Setup the first cpu core + } + bool Change_Config(Section* newconfig){ + Section_prop * section=static_cast(newconfig); + CPU_CycleLeft=0;//needed ? + CPU_Cycles=0; + const char *cyclesLine = section->Get_string("cycles"); + if (!strcasecmp(cyclesLine,"auto")) { + CPU_CycleMax=0; + CPU_CycleAuto=true; + } else { + CPU_CycleMax=atoi(cyclesLine); + CPU_CycleAuto=false; + } + CPU_CycleUp=section->Get_int("cycleup"); + CPU_CycleDown=section->Get_int("cycledown"); + const char * core=section->Get_string("core"); + cpudecoder=&CPU_Core_Normal_Run; + if (!strcasecmp(core,"normal")) { + cpudecoder=&CPU_Core_Normal_Run; + } else if (!strcasecmp(core,"simple")) { + cpudecoder=&CPU_Core_Simple_Run; + } else if (!strcasecmp(core,"full")) { + cpudecoder=&CPU_Core_Full_Run; + } +#if (C_DYNAMIC_X86) + else if (!strcasecmp(core,"dynamic")) { + cpudecoder=&CPU_Core_Dyn_X86_Run; + } +#endif + else { + LOG_MSG("CPU:Unknown core type %s, switching back to normal.",core); + } + +#if (C_DYNAMIC_X86) + CPU_Core_Dyn_X86_Cache_Init(!strcasecmp(core,"dynamic")); +#endif + + if(CPU_CycleMax <= 0) CPU_CycleMax = 2500; + if(CPU_CycleUp <= 0) CPU_CycleUp = 500; + if(CPU_CycleDown <= 0) CPU_CycleDown = 20; + GFX_SetTitle(CPU_CycleMax,-1,false); + return true; + } + ~CPU(){ /* empty */}; +}; + +static CPU * test; + +void CPU_ShutDown(Section* sec) { + delete test; } +void CPU_Init(Section* sec) { + test = new CPU(sec); + sec->AddDestroyFunction(&CPU_ShutDown,true); +} +//initialize static members +bool CPU::inited=false; diff --git a/src/cpu/flags.cpp b/src/cpu/flags.cpp index fabc39a..5d87837 100644 --- a/src/cpu/flags.cpp +++ b/src/cpu/flags.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/instructions.h b/src/cpu/instructions.h index 2e27ae5..bd5981c 100644 --- a/src/cpu/instructions.h +++ b/src/cpu/instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -599,9 +599,11 @@ Bitu val=load(op1); \ if (val==0) EXCEPTION(0); \ Bitu quo=reg_ax / val; \ - reg_ah=(Bit8u)(reg_ax % val); \ - reg_al=(Bit8u)quo; \ + Bit8u rem=(Bit8u)(reg_ax % val); \ + Bit8u quo8=(Bit8u)(quo&0xff); \ if (quo>0xff) EXCEPTION(0); \ + reg_ah=rem; \ + reg_al=quo8; \ } @@ -611,9 +613,11 @@ if (val==0) EXCEPTION(0); \ Bitu num=(reg_dx<<16)|reg_ax; \ Bitu quo=num/val; \ - reg_dx=(Bit16u)(num % val); \ - reg_ax=(Bit16u)quo; \ - if (quo>0xffff) EXCEPTION(0); \ + Bit16u rem=(Bit16u)(num % val); \ + Bit16u quo16=(Bit16u)(quo&0xffff); \ + if (quo!=(Bit32u)quo16) EXCEPTION(0); \ + reg_dx=rem; \ + reg_ax=quo16; \ } #define DIVD(op1,load,save) \ @@ -622,9 +626,11 @@ if (!val) EXCEPTION(0); \ Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax; \ Bit64u quo=num/val; \ - reg_edx=(Bit32u)(num % val); \ - reg_eax=(Bit32u)quo; \ - if (quo!=(Bit64u)reg_eax) EXCEPTION(0); \ + Bit32u rem=(Bit32u)(num % val); \ + Bit32u quo32=(Bit32u)(quo&0xffffffff); \ + if (quo!=(Bit64u)quo32) EXCEPTION(0); \ + reg_edx=rem; \ + reg_eax=quo32; \ } @@ -633,9 +639,11 @@ Bits val=(Bit8s)(load(op1)); \ if (val==0) EXCEPTION(0); \ Bits quo=((Bit16s)reg_ax) / val; \ - reg_ah=(Bit8s)(((Bit16s)reg_ax) % val); \ - reg_al=(Bit8s)quo; \ - if (quo!=(Bit8s)reg_al) EXCEPTION(0); \ + Bit8s rem=(Bit8s)((Bit16s)reg_ax % val); \ + Bit8s quo8s=(Bit8s)(quo&0xff); \ + if (quo!=(Bit16s)quo8s) EXCEPTION(0); \ + reg_ah=rem; \ + reg_al=quo8s; \ } @@ -645,9 +653,11 @@ if (!val) EXCEPTION(0); \ Bits num=(Bit32s)((reg_dx<<16)|reg_ax); \ Bits quo=num/val; \ - reg_dx=(Bit16u)(num % val); \ - reg_ax=(Bit16s)quo; \ - if (quo!=(Bit16s)reg_ax) EXCEPTION(0); \ + Bit16s rem=(Bit16s)(num % val); \ + Bit16s quo16s=(Bit16s)quo; \ + if (quo!=(Bit32s)quo16s) EXCEPTION(0); \ + reg_dx=rem; \ + reg_ax=quo16s; \ } #define IDIVD(op1,load,save) \ @@ -656,9 +666,11 @@ if (!val) EXCEPTION(0); \ Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax; \ Bit64s quo=num/val; \ - reg_edx=(Bit32s)(num % val); \ - reg_eax=(Bit32s)(quo); \ - if (quo!=(Bit64s)((Bit32s)reg_eax)) EXCEPTION(0); \ + Bit32s rem=(Bit32s)(num % val); \ + Bit32s quo32s=(Bit32s)(quo&0xffffffff); \ + if (quo!=(Bit64s)quo32s) EXCEPTION(0); \ + reg_edx=rem; \ + reg_eax=quo32s; \ } #define IMULB(op1,load,save) \ diff --git a/src/cpu/lazyflags.h b/src/cpu/lazyflags.h index 9cf2a73..227d5f2 100644 --- a/src/cpu/lazyflags.h +++ b/src/cpu/lazyflags.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/modrm.cpp b/src/cpu/modrm.cpp index e726f79..15e4cd0 100644 --- a/src/cpu/modrm.cpp +++ b/src/cpu/modrm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/modrm.h b/src/cpu/modrm.h index b51e0f2..e98f139 100644 --- a/src/cpu/modrm.h +++ b/src/cpu/modrm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/cpu/paging.cpp b/src/cpu/paging.cpp index 6198baf..7c804cf 100644 --- a/src/cpu/paging.cpp +++ b/src/cpu/paging.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -27,11 +27,13 @@ #include "lazyflags.h" #include "cpu.h" #include "debug.h" +#include "setup.h" #define LINK_TOTAL (64*1024) PagingBlock paging; -static Bit32u mapfirstmb[LINK_START]; + + Bitu PageHandler::readb(PhysPt addr) { E_Exit("No byte handler for read from %d",addr); @@ -65,10 +67,34 @@ void PageHandler::writed(PhysPt addr,Bitu val) { writeb(addr+3,(Bit8u) (val >> 24)); }; -HostPt PageHandler::GetHostPt(Bitu phys_page) { +HostPt PageHandler::GetHostReadPt(Bitu phys_page) { return 0; } +HostPt PageHandler::GetHostWritePt(Bitu phys_page) { + return 0; +} + +bool PageHandler::readb_checked(PhysPt addr, Bitu * val) { + *val=readb(addr); return false; +} +bool PageHandler::readw_checked(PhysPt addr, Bitu * val) { + *val=readw(addr); return false; +} +bool PageHandler::readd_checked(PhysPt addr, Bitu * val) { + *val=readd(addr); return false; +} +bool PageHandler::writeb_checked(PhysPt addr,Bitu val) { + writeb(addr,val); return false; +} +bool PageHandler::writew_checked(PhysPt addr,Bitu val) { + writew(addr,val); return false; +} +bool PageHandler::writed_checked(PhysPt addr,Bitu val) { + writed(addr,val); return false; +} + + struct PF_Entry { Bitu cs; @@ -77,7 +103,7 @@ struct PF_Entry { }; #define PF_QUEUESIZE 16 -struct { +static struct { Bitu used; PF_Entry entries[PF_QUEUESIZE]; } pf_queue; @@ -104,7 +130,7 @@ Bitu DEBUG_EnableDebugger(void); bool first=false; -void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,Bitu type) { +void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,bool writefault,Bitu faultcode) { /* Save the state of the cpu cores */ LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -113,14 +139,14 @@ void PAGING_PageFault(PhysPt lin_addr,Bitu page_addr,Bitu type) { cpudecoder=&PageFaultCore; paging.cr2=lin_addr; PF_Entry * entry=&pf_queue.entries[pf_queue.used++]; - LOG(LOG_PAGING,LOG_NORMAL)("PageFault at %X type %d queue %d",lin_addr,type,pf_queue.used); + LOG(LOG_PAGING,LOG_NORMAL)("PageFault at %X type [%x:%x] queue %d",lin_addr,writefault,faultcode,pf_queue.used); // LOG_MSG("EAX:%04X ECX:%04X EDX:%04X EBX:%04X",reg_eax,reg_ecx,reg_edx,reg_ebx); // LOG_MSG("CS:%04X EIP:%08X SS:%04x SP:%08X",SegValue(cs),reg_eip,SegValue(ss),reg_esp); entry->cs=SegValue(cs); entry->eip=reg_eip; entry->page_addr=page_addr; //Caused by a write by default? - CPU_Exception(14,0x2 ); + CPU_Exception(14,(writefault?0x02:0x00) | faultcode); #if C_DEBUG // DEBUG_EnableDebugger(); #endif @@ -136,30 +162,66 @@ class InitPageHandler : public PageHandler { public: InitPageHandler() {flags=PFLAG_INIT|PFLAG_NOCODE;} Bitu readb(PhysPt addr) { - InitPage(addr); + InitPage(addr,false); return mem_readb(addr); } Bitu readw(PhysPt addr) { - InitPage(addr); + InitPage(addr,false); return mem_readw(addr); } Bitu readd(PhysPt addr) { - InitPage(addr); + InitPage(addr,false); return mem_readd(addr); } void writeb(PhysPt addr,Bitu val) { - InitPage(addr); + InitPage(addr,true); mem_writeb(addr,val); } void writew(PhysPt addr,Bitu val) { - InitPage(addr); + InitPage(addr,true); mem_writew(addr,val); } void writed(PhysPt addr,Bitu val) { - InitPage(addr); + InitPage(addr,true); mem_writed(addr,val); } - void InitPage(Bitu lin_addr) { + bool readb_checked(PhysPt addr, Bitu * val) { + if (InitPage(addr,false,true)) { + *val=mem_readb(addr); + return false; + } else return true; + } + bool readw_checked(PhysPt addr, Bitu * val) { + if (InitPage(addr,false,true)){ + *val=mem_readw(addr); + return false; + } else return true; + } + bool readd_checked(PhysPt addr, Bitu * val) { + if (InitPage(addr,false,true)) { + *val=mem_readd(addr); + return false; + } else return true; + } + bool writeb_checked(PhysPt addr,Bitu val) { + if (InitPage(addr,true,true)) { + mem_writeb(addr,val); + return false; + } else return true; + } + bool writew_checked(PhysPt addr,Bitu val) { + if (InitPage(addr,true,true)) { + mem_writew(addr,val); + return false; + } else return true; + } + bool writed_checked(PhysPt addr,Bitu val) { + if (InitPage(addr,true,true)) { + mem_writed(addr,val); + return false; + } else return true; + } + bool InitPage(Bitu lin_addr,bool writing,bool check_only=false) { Bitu lin_page=lin_addr >> 12; Bitu phys_page; if (paging.enabled) { @@ -169,32 +231,63 @@ public: X86PageEntry table; table.load=phys_readd(table_addr); if (!table.block.p) { - LOG(LOG_PAGING,LOG_ERROR)("NP Table"); - PAGING_PageFault(lin_addr,table_addr,0); + if (check_only) { + paging.cr2=lin_addr; + cpu.exception.which=14; + cpu.exception.error=writing?0x02:0x00; + return false; + } + LOG(LOG_PAGING,LOG_NORMAL)("NP Table"); + PAGING_PageFault(lin_addr,table_addr,false,writing?0x02:0x00); table.load=phys_readd(table_addr); if (!table.block.p) E_Exit("Pagefault didn't correct table"); } - table.block.a=table.block.d=1; //Set access/Dirty - phys_writed(table_addr,table.load); + if (!table.block.a) { + table.block.a=1; //Set access + phys_writed(table_addr,table.load); + } X86PageEntry entry; Bitu entry_addr=(table.block.base<<12)+t_index*4; entry.load=phys_readd(entry_addr); if (!entry.block.p) { - LOG(LOG_PAGING,LOG_ERROR)("NP Page"); - PAGING_PageFault(lin_addr,entry_addr,0); + if (check_only) { + paging.cr2=lin_addr; + cpu.exception.which=14; + cpu.exception.error=writing?0x02:0x00; + return false; + } +// LOG(LOG_PAGING,LOG_NORMAL)("NP Page"); + PAGING_PageFault(lin_addr,entry_addr,false,writing?0x02:0x00); entry.load=phys_readd(entry_addr); if (!entry.block.p) E_Exit("Pagefault didn't correct page"); } - entry.block.a=entry.block.d=1; //Set access/Dirty - phys_writed(entry_addr,entry.load); + if (cpu.cpl==3) { + if ((entry.block.us==0) || (table.block.us==0) && (((entry.block.wr==0) || (table.block.wr==0)) && writing)) { + LOG(LOG_PAGING,LOG_NORMAL)("Page access denied: cpl=%i, %x:%x:%x:%x",cpu.cpl,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + if (check_only) { + paging.cr2=lin_addr; + cpu.exception.which=14; + cpu.exception.error=0x05 | (writing?0x02:0x00); + return false; + } + PAGING_PageFault(lin_addr,entry_addr,writing,0x05 | (writing?0x02:0x00)); + } + } + if (check_only) return true; + if ((!entry.block.a) || (!entry.block.d)) { + entry.block.a=1; //Set access + entry.block.d=1; //Set dirty + phys_writed(entry_addr,entry.load); + } phys_page=entry.block.base; } else { - if (lin_pageGetHostPt(phys_page); paging.tlb.phys_page[lin_page]=phys_page; - if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=host_mem-lin_base; + if (handler->flags & PFLAG_READABLE) paging.tlb.read[lin_page]=handler->GetHostReadPt(phys_page)-lin_base; else paging.tlb.read[lin_page]=0; - if (handler->flags & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=host_mem-lin_base; + if (handler->flags & PFLAG_WRITEABLE) paging.tlb.write[lin_page]=handler->GetHostWritePt(phys_page)-lin_base; else paging.tlb.write[lin_page]=0; paging.links.entries[paging.links.used++]=lin_page; @@ -275,7 +367,7 @@ void PAGING_LinkPage(Bitu lin_page,Bitu phys_page) { void PAGING_MapPage(Bitu lin_page,Bitu phys_page) { if (lin_page #include +#include #include "dosbox.h" #if C_DEBUG @@ -39,6 +40,8 @@ #include "shell.h" #include "programs.h" #include "debug_inc.h" +#include "../cpu/lazyflags.h" +#include "keyboard.h" #ifdef WIN32 void WIN32_Console(); @@ -53,16 +56,37 @@ int old_cursor_state; static void DrawCode(void); static bool DEBUG_Log_Loop(int count); static void DEBUG_RaiseTimerIrq(void); -static void SaveMemory(Bitu seg, Bitu ofs1, Bit32s num); +static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num); +static void SaveMemoryBin(Bitu seg, Bitu ofs1, Bit32u num); static void LogGDT(void); static void LogLDT(void); static void LogIDT(void); +static void LogPages(char* selname); +static void LogCPUInfo(void); static void OutputVecTable(char* filename); static void DrawVariables(void); char* AnalyzeInstruction(char* inst, bool saveSelector); Bit32u GetHexValue(char* str, char*& hex); +class DebugPageHandler : public PageHandler { +public: + Bitu readb(PhysPt addr) { + } + Bitu readw(PhysPt addr) { + } + Bitu readd(PhysPt addr) { + } + void writeb(PhysPt addr,Bitu val) { + } + void writew(PhysPt addr,Bitu val) { + } + void writed(PhysPt addr,Bitu val) { + } + + + +}; class DEBUG; @@ -77,6 +101,7 @@ bool logHeavy = false; static FILE* cpuLogFile = 0; static bool cpuLog = false; static int cpuLogCounter = 0; +static int cpuLogType = 1; // log detail #endif @@ -88,7 +113,7 @@ static struct { static char curSelectorName[3] = { 0,0,0 }; static Segment oldsegs[6]; -static Bitu oldflags; +static Bitu oldflags,oldcpucpl; DBGBlock dbg; static Bitu input_count; Bitu cycle_count; @@ -134,7 +159,7 @@ Bit32u PhysMakeProt(Bit16u selector, Bit32u offset) Bit32u GetAddress(Bit16u seg, Bit32u offset) { if (seg==SegValue(cs)) return SegPhys(cs)+offset; - if (cpu.pmode) { + if (cpu.pmode && !(reg_flags & FLAG_VM)) { Descriptor desc; if (cpu.gdt.GetDescriptor(seg,desc)) return PhysMakeProt(seg,offset); } @@ -147,15 +172,43 @@ bool GetDescriptorInfo(char* selname, char* out1, char* out2) Bitu sel; Descriptor desc; - if (strstr(selname,"cs") || strstr(selname,"CS")) sel = SegValue(cs); else - if (strstr(selname,"ds") || strstr(selname,"DS")) sel = SegValue(ds); else - if (strstr(selname,"es") || strstr(selname,"ES")) sel = SegValue(es); else - if (strstr(selname,"fs") || strstr(selname,"FS")) sel = SegValue(fs); else - if (strstr(selname,"gs") || strstr(selname,"GS")) sel = SegValue(gs); else - if (strstr(selname,"ss") || strstr(selname,"SS")) sel = SegValue(ss); else - sel = GetHexValue(selname,selname); - // FIXME: Call Gate Descriptors + if (strstr(selname,"cs") || strstr(selname,"CS")) sel = SegValue(cs); + else if (strstr(selname,"ds") || strstr(selname,"DS")) sel = SegValue(ds); + else if (strstr(selname,"es") || strstr(selname,"ES")) sel = SegValue(es); + else if (strstr(selname,"fs") || strstr(selname,"FS")) sel = SegValue(fs); + else if (strstr(selname,"gs") || strstr(selname,"GS")) sel = SegValue(gs); + else if (strstr(selname,"ss") || strstr(selname,"SS")) sel = SegValue(ss); + else { + sel = GetHexValue(selname,selname); + if (*selname==0) selname=" "; + } if (cpu.gdt.GetDescriptor(sel,desc)) { + switch (desc.Type()) { + case DESC_TASK_GATE: + sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type); + sprintf(out2," TaskGate dpl : %01X %1X",desc.saved.gate.dpl,desc.saved.gate.p); + return true; + case DESC_LDT: + case DESC_286_TSS_A: + case DESC_286_TSS_B: + case DESC_386_TSS_A: + case DESC_386_TSS_B: + sprintf(out1,"%s: b:%08X type:%02X pag",selname,desc.GetBase(),desc.saved.seg.type); + sprintf(out2," l:%08X dpl : %01X %1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.g); + return true; + case DESC_286_CALL_GATE: + case DESC_386_CALL_GATE: + sprintf(out1,"%s: s:%08X type:%02X p params: %02X",selname,desc.GetSelector(),desc.saved.gate.type,desc.saved.gate.paramcount); + sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p); + return true; + case DESC_286_INT_GATE: + case DESC_286_TRAP_GATE: + case DESC_386_INT_GATE: + case DESC_386_TRAP_GATE: + sprintf(out1,"%s: s:%08X type:%02X p",selname,desc.GetSelector(),desc.saved.gate.type); + sprintf(out2," o:%08X dpl : %01X %1X",desc.GetOffset(),desc.saved.gate.dpl,desc.saved.gate.p); + return true; + } sprintf(out1,"%s: b:%08X type:%02X parbg",selname,desc.GetBase(),desc.saved.seg.type); sprintf(out2," l:%08X dpl : %01X %1X%1X%1X%1X%1X",desc.GetLimit(),desc.saved.seg.dpl,desc.saved.seg.p,desc.saved.seg.avl,desc.saved.seg.r,desc.saved.seg.big,desc.saved.seg.g); return true; @@ -163,7 +216,6 @@ bool GetDescriptorInfo(char* selname, char* out1, char* out2) strcpy(out1," "); strcpy(out2," "); } - //out1[0] = out2[0] = 0; return false; }; @@ -174,7 +226,7 @@ bool GetDescriptorInfo(char* selname, char* out1, char* out2) class CDebugVar { public: - CDebugVar(char* _name, PhysPt _adr) { adr=_adr; (strlen(name)<15)?strcpy(name,_name):strncpy(name,_name,15); name[15]=0; }; + CDebugVar(char* _name, PhysPt _adr) { adr=_adr; safe_strncpy(name,_name,16); }; char* GetName(void) { return name; }; PhysPt GetAdr (void) { return adr; }; @@ -536,6 +588,9 @@ void CBreakpoint::ShowList(void) } else if (bp->GetType()==BKPNT_MEMORY) { DEBUG_ShowMsg("%02X. BPMEM %04X:%04X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue()); nr++; + } else if (bp->GetType()==BKPNT_MEMORY_PROT) { + DEBUG_ShowMsg("%02X. BPPM %04X:%08X (%02X)\n",nr,bp->GetSegment(),bp->GetOffset(),bp->GetValue()); + nr++; }; } }; @@ -603,15 +658,16 @@ static void DrawData(void) { /* Data win */ for (int y=0; y<8; y++) { // Adress - mvwprintw (dbg.win_data,1+y,0,"%04X:%04X ",dataSeg,add); + if (add<0x10000) mvwprintw (dbg.win_data,1+y,0,"%04X:%04X ",dataSeg,add); + else mvwprintw (dbg.win_data,1+y,0,"%04X:%08X ",dataSeg,add); for (int x=0; x<16; x++) { address = GetAddress(dataSeg,add); if (!(paging.tlb.handler[address >> 12]->flags & PFLAG_INIT)) { ch = mem_readb(address); } else ch = 0; - mvwprintw (dbg.win_data,1+y,11+3*x,"%02X",ch); - if (ch<32) ch='.'; - mvwprintw (dbg.win_data,1+y,60+x,"%c",ch); + mvwprintw (dbg.win_data,1+y,14+3*x,"%02X",ch); + if (ch<32 || !isprint(*reinterpret_cast(&ch))) ch='.'; + mvwprintw (dbg.win_data,1+y,63+x,"%c",ch); add++; }; } @@ -661,8 +717,14 @@ static void DrawRegisters(void) { SetColor((reg_flags ^ oldflags)&FLAG_TF); mvwprintw (dbg.win_reg,1,77,"%01X",GETFLAG(TF) ? 1:0); + SetColor((reg_flags ^ oldflags)&FLAG_IOPL); + mvwprintw (dbg.win_reg,2,72,"%01X",GETFLAG(IOPL)>>12); oldflags=reg_flags; + SetColor(cpu.cpl ^ oldcpucpl); + mvwprintw (dbg.win_reg,2,78,"%01X",cpu.cpl); + oldcpucpl=cpu.cpl; + if (cpu.pmode) { if (reg_flags & FLAG_VM) mvwprintw(dbg.win_reg,0,76,"VM86"); else if (cpu.code.big) mvwprintw(dbg.win_reg,0,76,"Pr32"); @@ -843,12 +905,13 @@ bool ChangeRegister(char* str) if (strstr(hex,"SS")==hex) { hex+=2; SegSet16(ss,(Bit16u)GetHexValue(hex,hex)); } else if (strstr(hex,"AF")==hex) { hex+=2; SETFLAGBIT(AF,GetHexValue(hex,hex)); } else if (strstr(hex,"CF")==hex) { hex+=2; SETFLAGBIT(CF,GetHexValue(hex,hex)); } else - if (strstr(hex,"DF")==hex) { hex+=2; SETFLAGBIT(PF,GetHexValue(hex,hex)); } else + if (strstr(hex,"DF")==hex) { hex+=2; SETFLAGBIT(DF,GetHexValue(hex,hex)); } else if (strstr(hex,"IF")==hex) { hex+=2; SETFLAGBIT(IF,GetHexValue(hex,hex)); } else if (strstr(hex,"OF")==hex) { hex+=3; SETFLAGBIT(OF,GetHexValue(hex,hex)); } else if (strstr(hex,"ZF")==hex) { hex+=3; SETFLAGBIT(ZF,GetHexValue(hex,hex)); } else if (strstr(hex,"PF")==hex) { hex+=3; SETFLAGBIT(PF,GetHexValue(hex,hex)); } else - { return false; }; + if (strstr(hex,"SF")==hex) { hex+=3; SETFLAGBIT(SF,GetHexValue(hex,hex)); } else + { return false; }; return true; }; @@ -869,6 +932,15 @@ bool ParseCommand(char* str) SaveMemory(seg,ofs,num); return true; }; + found = strstr(str,"MEMDUMPBIN "); + if (found) { // Insert variable + found+=11; + Bit16u seg = (Bit16u)GetHexValue(found,found); found++; + Bit32u ofs = GetHexValue(found,found); found++; + Bit32u num = GetHexValue(found,found); found++; + SaveMemoryBin(seg,ofs,num); + return true; + }; found = strstr(str,"IV "); if (found) { // Insert variable @@ -964,8 +1036,11 @@ bool ParseCommand(char* str) Bit16u seg = (Bit16u)GetHexValue(found,found);found++; // skip ":" Bit32u ofs = GetHexValue(found,found); CBreakpoint* bp = CBreakpoint::AddMemBreakpoint(seg,ofs); - if (bp) bp->SetType(BKPNT_MEMORY_PROT); - DEBUG_ShowMsg("DEBUG: Set prot-mode memory breakpoint at %04X:%08X\n",seg,ofs); + if (bp) + { + bp->SetType(BKPNT_MEMORY_PROT); + DEBUG_ShowMsg("DEBUG: Set prot-mode memory breakpoint at %04X:%08X\n",seg,ofs); + } return true; } found = strstr(str,"BPLM "); @@ -1039,10 +1114,51 @@ bool ParseCommand(char* str) // DEBUG_Log_Loop(GetHexValue(found,found)); cpuLogFile = fopen("LOGCPU.TXT","wt"); if (!cpuLogFile) { - DEBUG_ShowMsg("DEBUG: Logfile couldnt be created.\n"); + DEBUG_ShowMsg("DEBUG: Logfile couldn't be created.\n"); return false; } cpuLog = true; + cpuLogType = 1; + cpuLogCounter = GetHexValue(found,found); + + debugging=false; + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); + ignoreAddressOnce = SegPhys(cs)+reg_eip; + DOSBOX_SetNormalLoop(); + return true; + } + + found = strstr(str,"LOGS "); + if (found) { // Create Cpu log file + found+=4; + DEBUG_ShowMsg("DEBUG: Starting log\n"); + cpuLogFile = fopen("LOGCPU.TXT","wt"); + if (!cpuLogFile) { + DEBUG_ShowMsg("DEBUG: Logfile couldn't be created.\n"); + return false; + } + cpuLog = true; + cpuLogType = 0; + cpuLogCounter = GetHexValue(found,found); + + debugging=false; + CBreakpoint::ActivateBreakpoints(SegPhys(cs)+reg_eip,true); + ignoreAddressOnce = SegPhys(cs)+reg_eip; + DOSBOX_SetNormalLoop(); + return true; + } + + found = strstr(str,"LOGL "); + if (found) { // Create Cpu log file + found+=4; + DEBUG_ShowMsg("DEBUG: Starting log\n"); + cpuLogFile = fopen("LOGCPU.TXT","wt"); + if (!cpuLogFile) { + DEBUG_ShowMsg("DEBUG: Logfile couldn't be created.\n"); + return false; + } + cpuLog = true; + cpuLogType = 2; cpuLogCounter = GetHexValue(found,found); debugging=false; @@ -1100,6 +1216,18 @@ bool ParseCommand(char* str) LogIDT(); } + found = strstr(str,"PAGING"); + if (found) { + found += 6; + while (found[0]==' ') found++; + LogPages(found); + } + + found = strstr(str,"CPU"); + if (found) { + LogCPUInfo(); + } + found = strstr(str,"INTVEC "); if (found) { @@ -1124,15 +1252,6 @@ bool ParseCommand(char* str) } } - /* found = strstr(str,"EXCEPTION "); - if (found) { - found += 9; - Bit8u num = GetHexValue(found,found); - DPMI_CreateException(num,0xDD); - DEBUG_ShowMsg("Exception %04X\n",num); - }; -*/ - #if C_HEAVY_DEBUG found = strstr(str,"HEAVYLOG"); if (found) { // Create Cpu log file @@ -1169,6 +1288,7 @@ bool ParseCommand(char* str) DEBUG_ShowMsg("INT [nr] / INTT [nr] - Execute / Trace into interrupt.\n"); #if C_HEAVY_DEBUG DEBUG_ShowMsg("LOG [num] - Write cpu log file.\n"); + DEBUG_ShowMsg("LOGS/LOGL [num] - Write short/long cpu log file.\n"); DEBUG_ShowMsg("HEAVYLOG - Enable/Disable automatic cpu when dosbox exits.\n"); #endif DEBUG_ShowMsg("SR [reg] [value] - Set register value.\n"); @@ -1176,14 +1296,21 @@ bool ParseCommand(char* str) DEBUG_ShowMsg("IV [seg]:[off] [name] - Create var name for memory address.\n"); DEBUG_ShowMsg("SV [filename] - Save var list in file.\n"); - DEBUG_ShowMsg("LV [seg]:[off] [name] - Load var list from file.\n"); + DEBUG_ShowMsg("LV [filename] - Load var list from file.\n"); DEBUG_ShowMsg("MEMDUMP [seg]:[off] [len] - Write memory to file memdump.txt.\n"); + DEBUG_ShowMsg("MEMDUMPBIN [s]:[o] [len] - Write memory to file memdump.bin.\n"); DEBUG_ShowMsg("SELINFO [segName] - Show selector info.\n"); DEBUG_ShowMsg("INTVEC [filename] - Writes interrupt vector table to file.\n"); DEBUG_ShowMsg("INTHAND [intNum] - Set code view to interrupt handler.\n"); + DEBUG_ShowMsg("CPU - Display CPU status information.\n"); + DEBUG_ShowMsg("GDT - Lists descriptors of the GDT.\n"); + DEBUG_ShowMsg("LDT - Lists descriptors of the LDT.\n"); + DEBUG_ShowMsg("IDT - Lists descriptors of the IDT.\n"); + DEBUG_ShowMsg("PAGING [page] - Display content of page table.\n"); + DEBUG_ShowMsg("H - Help\n"); return TRUE; @@ -1288,65 +1415,65 @@ char* AnalyzeInstruction(char* inst, bool saveSelector) // Must be a jump if (instu[0] == 'J') { - bool jmp = 0; + bool jmp = false; switch (instu[1]) { - case 'A' : { jmp = !GETFLAGBOOL(CF) && !GETFLAGBOOL(ZF); // JA + case 'A' : { jmp = (get_CF()?false:true) && (get_ZF()?false:true); // JA } break; case 'B' : { if (instu[2] == 'E') { - jmp = GETFLAGBOOL(CF) && GETFLAGBOOL(ZF); // JBE + jmp = (get_CF()?true:false) && (get_ZF()?true:false); // JBE } else { - jmp = GETFLAGBOOL(CF); // JB + jmp = get_CF()?true:false; // JB } } break; case 'C' : { if (instu[2] == 'X') { jmp = reg_cx == 0; // JCXZ } else { - jmp = GETFLAGBOOL(CF); // JC + jmp = get_CF()?true:false; // JC } } break; - case 'E' : { jmp = GETFLAGBOOL(ZF); // JE + case 'E' : { jmp = get_ZF()?true:false; // JE } break; case 'G' : { if (instu[2] == 'E') { - jmp = !GETFLAGBOOL(SF); // JGE + jmp = get_SF()?false:true; // JGE } else { - jmp = !GETFLAGBOOL(SF) && !GETFLAGBOOL(ZF); // JG + jmp = (get_SF()?false:true) && (get_ZF()?false:true); // JG } } break; case 'L' : { if (instu[2] == 'E') { - jmp = GETFLAGBOOL(SF) || GETFLAGBOOL(ZF); // JLE + jmp = (get_SF()?true:false) || (get_ZF()?true:false) ; // JLE } else { - jmp = GETFLAGBOOL(SF); // JL + jmp = get_SF()?true:false; // JL } } break; case 'M' : { jmp = true; // JMP } break; case 'N' : { switch (instu[2]) { case 'B' : - case 'C' : { jmp = !GETFLAGBOOL(CF); // JNB / JNC + case 'C' : { jmp = get_CF()?false:true; // JNB / JNC } break; - case 'E' : { jmp = !GETFLAGBOOL(ZF); // JNE + case 'E' : { jmp = get_ZF()?false:true; // JNE } break; - case 'O' : { jmp = !GETFLAGBOOL(OF); // JNO + case 'O' : { jmp = get_OF()?false:true; // JNO } break; - case 'P' : { jmp = !GETFLAGBOOL(PF); // JNP + case 'P' : { jmp = get_PF()?false:true; // JNP } break; - case 'S' : { jmp = !GETFLAGBOOL(SF); // JNS + case 'S' : { jmp = get_SF()?false:true; // JNS } break; - case 'Z' : { jmp = !GETFLAGBOOL(ZF); // JNZ + case 'Z' : { jmp = get_ZF()?false:true; // JNZ } break; } } break; - case 'O' : { jmp = GETFLAGBOOL(OF); // JMP + case 'O' : { jmp = get_OF()?true:false; // JMP } break; case 'P' : { if (instu[2] == 'O') { - jmp = !GETFLAGBOOL(PF); // JPO + jmp = get_PF()?false:true; // JPO } else { - jmp = GETFLAGBOOL(SF); // JP / JPE + jmp = get_SF()?true:false; // JP / JPE } } break; - case 'S' : { jmp = GETFLAGBOOL(SF); // JS + case 'S' : { jmp = get_SF()?true:false; // JS } break; - case 'Z' : { jmp = GETFLAGBOOL(ZF); // JZ + case 'Z' : { jmp = get_ZF()?true:false; // JZ } break; } if (jmp) { @@ -1374,6 +1501,7 @@ Bit32u DEBUG_CheckKeys(void) { ParseCommand(codeViewData.inputStr); break; case 0x107: //backspace (linux) + case 0x7f: //backspace in some terminal emulators (linux) case 0x08: // delete if (strlen(codeViewData.inputStr)>0) codeViewData.inputStr[strlen(codeViewData.inputStr)-1] = 0; break; @@ -1418,19 +1546,24 @@ Bit32u DEBUG_CheckKeys(void) { ret=(*cpudecoder)(); break; case 'D': dataSeg = SegValue(ds); - dataOfs = reg_si; + if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esi; + else dataOfs = reg_si; break; case 'E': dataSeg = SegValue(es); - dataOfs = reg_di; + if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edi; + else dataOfs = reg_di; break; case 'X': dataSeg = SegValue(ds); - dataOfs = reg_dx; + if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_edx; + else dataOfs = reg_dx; break; case 'B': dataSeg = SegValue(es); - dataOfs = reg_bx; + if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_ebx; + else dataOfs = reg_bx; break; case 'S': dataSeg = SegValue(ss); - dataOfs = reg_sp; + if (cpu.pmode && !(reg_flags & FLAG_VM)) dataOfs = reg_esp; + else dataOfs = reg_sp; break; case 'R' : dataOfs -= 16; break; @@ -1527,7 +1660,9 @@ Bitu DEBUG_Loop(void) { return DEBUG_CheckKeys(); } -void DEBUG_Enable(void) { +void DEBUG_Enable(bool pressed) { + if (!pressed) + return; static bool showhelp=false; debugging=true; SetCodeWinStart(); @@ -1537,6 +1672,7 @@ void DEBUG_Enable(void) { showhelp=true; DEBUG_ShowMsg("***| PRESS \"H\" TO SHOW ALL COMMANDS. PRESS \"RETURN\" TO ENTER COMMANDMODE. |***\n"); } + KEYBOARD_ClrBuffer(); } void DEBUG_DrawScreen(void) { @@ -1603,6 +1739,68 @@ static void LogIDT(void) }; }; +void LogPages(char* selname) +{ + char out1[512]; + if (paging.enabled) { + Bitu sel = GetHexValue(selname,selname); + if ((sel==0x00) && ((*selname==0) || (*selname=='*'))) { + for (int i=0; i<0xfffff; i++) { + Bitu table_addr=(paging.base.page<<12)+(i >> 10)*4; + X86PageEntry table; + table.load=phys_readd(table_addr); + if (table.block.p) { + X86PageEntry entry; + Bitu entry_addr=(table.block.base<<12)+(i & 0x3ff)*4; + entry.load=phys_readd(entry_addr); + if (entry.block.p) { + sprintf(out1,"page %05Xxxx -> %04Xxxx flags [uw] %x:%x::%x:%x",i,entry.block.base,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + LOG(LOG_MISC,LOG_ERROR)(out1); + } + } + } + } else { + Bitu table_addr=(paging.base.page<<12)+(sel >> 10)*4; + X86PageEntry table; + table.load=phys_readd(table_addr); + if (table.block.p) { + X86PageEntry entry; + Bitu entry_addr=(table.block.base<<12)+(sel & 0x3ff)*4; + entry.load=phys_readd(entry_addr); + sprintf(out1,"page %05Xxxx -> %04Xxxx flags [puw] %x:%x::%x:%x::%x:%x",sel,entry.block.base,entry.block.p,table.block.p,entry.block.us,table.block.us,entry.block.wr,table.block.wr); + LOG(LOG_MISC,LOG_ERROR)(out1); + } else { + sprintf(out1,"pagetable %03X not present, flags [puw] %x::%x::%x",(sel >> 10),table.block.p,table.block.us,table.block.wr); + LOG(LOG_MISC,LOG_ERROR)(out1); + } + } + } +}; + +static void LogCPUInfo(void) +{ + char out1[512]; + sprintf(out1,"cr0:%08X cr2:%08X cr3:%08X cpl=%x",cpu.cr0,paging.cr2,paging.cr3,cpu.cpl); + LOG(LOG_MISC,LOG_ERROR)(out1); + sprintf(out1,"eflags:%08X [vm=%x iopl=%x nt=%x]",reg_flags,GETFLAG(VM)>>17,GETFLAG(IOPL)>>12,GETFLAG(NT)>>14); + LOG(LOG_MISC,LOG_ERROR)(out1); + sprintf(out1,"GDT base=%08X limit=%08X",cpu.gdt.GetBase(),cpu.gdt.GetLimit()); + LOG(LOG_MISC,LOG_ERROR)(out1); + sprintf(out1,"IDT base=%08X limit=%08X",cpu.idt.GetBase(),cpu.idt.GetLimit()); + LOG(LOG_MISC,LOG_ERROR)(out1); + + Bitu sel; + Descriptor desc; + CPU_STR(sel); + cpu.gdt.GetDescriptor(sel,desc); + sprintf(out1,"TR selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1); + LOG(LOG_MISC,LOG_ERROR)(out1); + sel=cpu.gdt.SLDT(); + cpu.gdt.GetDescriptor(sel,desc); + sprintf(out1,"LDT selector=%04X, base=%08X limit=%08X*%X",sel,desc.GetBase(),desc.GetLimit(),desc.saved.seg.g?0x4000:1); + LOG(LOG_MISC,LOG_ERROR)(out1); +}; + static void LogInstruction(Bit16u segValue, Bit32u eipValue, char* buffer) { static char empty[15] = { 32,32,32,32,32,32,32,32,32,32,32,32,32,32,0 }; @@ -1614,13 +1812,41 @@ static void LogInstruction(Bit16u segValue, Bit32u eipValue, char* buffer) char* res = empty; if (showExtend) { res = AnalyzeInstruction(dline,false); + len = strlen(dline); +#if C_HEAVY_DEBUG + if (cpuLogType>=2) { + Bitu reslen=strlen(res); + if (reslen<24) for (Bitu i=0; i<24-reslen; i++) strcat(res," "); + } else +#endif if (!res || (strlen(res)==0)) res = empty; }; - - if (len<30) for (Bitu i=0; i<30-len; i++) strcat(dline," "); + // Get register values - sprintf(buffer,"%04X:%08X %s %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X IF:%01X\n",segValue,eipValue,dline,res,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss), - GETFLAGBOOL(CF),GETFLAGBOOL(ZF),GETFLAGBOOL(SF),GETFLAGBOOL(OF),GETFLAGBOOL(AF),GETFLAGBOOL(PF),GETFLAGBOOL(IF)); +#if C_HEAVY_DEBUG + if (cpuLogType==1) { +#endif + if (len<30) for (Bitu i=0; i<30-len; i++) strcat(dline," "); + sprintf(buffer,"%04X:%08X %s %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X FS:%04X GS:%04X SS:%04X CF:%01X ZF:%01X SF:%01X OF:%01X AF:%01X PF:%01X IF:%01X\n",segValue,eipValue,dline,res,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(es),SegValue(fs),SegValue(gs),SegValue(ss), + get_CF()?1:0,get_ZF()?1:0,get_SF()?1:0,get_OF()?1:0,get_AF()?1:0,get_PF()?1:0,GETFLAGBOOL(IF)); +#if C_HEAVY_DEBUG + } else if (cpuLogType==0) { + if (len<27) for (Bitu i=0; i<27-len; i++) strcat(dline," "); + sprintf(buffer,"%04X:%04X %s EAX:%08X EBX:%08X ECX:%08X EDX:%08X ESI:%08X EDI:%08X EBP:%08X ESP:%08X DS:%04X ES:%04X SS:%04X C%01X Z%01X S%01X O%01X I%01X\n",segValue,eipValue,dline,reg_eax,reg_ebx,reg_ecx,reg_edx,reg_esi,reg_edi,reg_ebp,reg_esp,SegValue(ds),SegValue(es),SegValue(ss), + get_CF()?1:0,get_ZF()?1:0,get_SF()?1:0,get_OF()?1:0,GETFLAGBOOL(IF)); + } else { + if (len<34) for (Bitu i=0; i<34-len; i++) strcat(dline," "); + char ibytes[200]=""; char tmpc[200]; + for (Bitu i=0; iFindCommand(1,temp_line); - strncpy(filename,temp_line.c_str(),128); + safe_strncpy(filename,temp_line.c_str(),128); // Read commandline Bit16u i =2; bool ok = false; @@ -1723,7 +1949,7 @@ void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off) Bitu DEBUG_EnableDebugger(void) { exitLoop = true; - DEBUG_Enable(); + DEBUG_Enable(true); CPU_Cycles=CPU_CycleLeft=0; return 0; }; @@ -1758,7 +1984,8 @@ static void DEBUG_ShutDown(Section * sec) #ifndef WIN32 curs_set(old_cursor_state); tcsetattr(0, TCSANOW,&consolesettings); - printf("\e[0m\e[2J"); +// printf("\e[0m\e[2J"); //Seems to destroy scrolling + printf("\ec"); fflush(NULL); #endif }; @@ -1770,7 +1997,7 @@ void DEBUG_Init(Section* sec) { MSG_Add("DEBUG_CONFIGFILE_HELP","Debugger related options.\n"); DEBUG_DrawScreen(); /* Add some keyhandlers */ - MAPPER_AddHandler(DEBUG_Enable,MK_pause,0,"debugger","Debugger"); + MAPPER_AddHandler(DEBUG_Enable,MK_pause,MMOD2,"debugger","Debugger"); /* Clear the TBreakpoint list */ memset((void*)&codeViewData,0,sizeof(codeViewData)); /* setup debug.com */ @@ -1857,7 +2084,7 @@ bool CDebugVar::LoadVars(char* name) return true; }; -static void SaveMemory(Bitu seg, Bitu ofs1, Bit32s num) +static void SaveMemory(Bitu seg, Bitu ofs1, Bit32u num) { FILE* f = fopen("MEMDUMP.TXT","wt"); if (!f) { @@ -1884,6 +2111,22 @@ static void SaveMemory(Bitu seg, Bitu ofs1, Bit32s num) DEBUG_ShowMsg("DEBUG: Memory dump success.\n"); }; +static void SaveMemoryBin(Bitu seg, Bitu ofs1, Bit32u num) { + FILE* f = fopen("MEMDUMP.BIN","wb"); + if (!f) { + DEBUG_ShowMsg("DEBUG: Memory binary dump failed.\n"); + return; + } + + for(Bitu x = 0; x < num;x++) { + Bit8u val = mem_readb(GetAddress(seg,ofs1+x)); + fwrite(&val,1,1,f); + }; + + fclose(f); + DEBUG_ShowMsg("DEBUG: Memory dump binary success.\n"); +}; + static void OutputVecTable(char* filename) { FILE* f = fopen(filename, "wt"); diff --git a/src/debug/debug_disasm.cpp b/src/debug/debug_disasm.cpp index f0c0460..3ccbded 100644 --- a/src/debug/debug_disasm.cpp +++ b/src/debug/debug_disasm.cpp @@ -260,7 +260,7 @@ static char *op386map1[256] = { "call %Jv", "jmp %Jv", "jmp %Ap", "jmp %Ks%Jb", "in al,dx", "in %eax,dx", "out dx,al", "out dx,%eax", /* f */ - "lock %p ", 0, "repne %p ", "repe %p ", + "lock %p ", "icebp", "repne %p ", "repe %p ", "hlt", "cmc", "%g2", "%g2", "clc", "stc", "cli", "sti", "cld", "std", "%g3", "%g4" @@ -269,8 +269,8 @@ static char *op386map1[256] = { static char *second[] = { /* 0 */ "%g5", "%g6", "lar %Gv,%Ew", "lsl %Gv,%Ew", - 0, "loadall", "clts", "loadall", - "invd", "wbinvd", 0, 0, + 0, "[loadall]", "clts", "[loadall]", + "invd", "wbinvd", 0, "UD2", 0, 0, 0, 0, /* 1 */ "mov %Eb,%Gb", "mov %Ev,%Gv", "mov %Gb,%Eb", "mov %Gv,%Ev", @@ -308,7 +308,7 @@ static char *second[] = { "sets %Eb", "setns %Eb", "setp %Eb", "setnp %Eb", "setl %Eb", "setge %Eb", "setle %Eb", "setg %Eb", /* a */ - "push fs", "pop fs", 0, "bt %Ev,%Gv", + "push fs", "pop fs", "cpuid", "bt %Ev,%Gv", "shld %Ev,%Gv,%Ib", "shld %Ev,%Gv,cl", 0, 0, "push gs", "pop gs", 0, "bts %Ev,%Gv", "shrd %Ev,%Gv,%Ib", "shrd %Ev,%Gv,cl", 0, "imul %Gv,%Ev", @@ -354,7 +354,7 @@ static char *groups[][8] = { /* group 0 is group 3 for %Ev set */ "verr %Ew", "verw %Ew", 0, 0 }, /* 6 */ { "sgdt %Ms", "sidt %Ms", "lgdt %Ms", "lidt %Ms", - "smsw %Ew", 0, "lmsw %Ew", 0 }, + "smsw %Ew", 0, "lmsw %Ew", "invlpg" }, /* 7 */ { 0, 0, 0, 0, "bt", "bts", "btr", "btc" } @@ -363,8 +363,10 @@ static char *groups[][8] = { /* group 0 is group 3 for %Ev set */ /* zero here means invalid. If first entry starts with '*', use st(i) */ /* no assumed %EFs here. Indexed by RM(modrm()) */ static char *f0[] = { 0, 0, 0, 0, 0, 0, 0, 0}; +static char *fop_8[] = { "*fld st,%GF" }; static char *fop_9[] = { "*fxch st,%GF" }; static char *fop_10[] = { "fnop", 0, 0, 0, 0, 0, 0, 0 }; +static char *fop_11[] = { "*fst st,%GF" }; static char *fop_12[] = { "fchs", "fabs", 0, 0, "ftst", "fxam", 0, 0 }; static char *fop_13[] = { "fld1", "fldl2t", "fldl2e", "fldpi", "fldlg2", "fldln2", "fldz", 0 }; @@ -373,20 +375,24 @@ static char *fop_14[] = { "f2xm1", "fyl2x", "fptan", "fpatan", static char *fop_15[] = { "fprem", "fyl2xp1", "fsqrt", "fsincos", "frndint", "fscale", "fsin", "fcos" }; static char *fop_21[] = { 0, "fucompp", 0, 0, 0, 0, 0, 0 }; -static char *fop_28[] = { 0, 0, "fclex", "finit", 0, 0, 0, 0 }; +static char *fop_28[] = { "[fneni]", "[fndis]", "fclex", "finit", "[fnsetpm]", "[frstpm]", 0, 0 }; static char *fop_32[] = { "*fadd %GF,st" }; static char *fop_33[] = { "*fmul %GF,st" }; +static char *fop_34[] = { "*fcom %GF,st" }; +static char *fop_35[] = { "*fcomp %GF,st" }; static char *fop_36[] = { "*fsubr %GF,st" }; static char *fop_37[] = { "*fsub %GF,st" }; static char *fop_38[] = { "*fdivr %GF,st" }; static char *fop_39[] = { "*fdiv %GF,st" }; static char *fop_40[] = { "*ffree %GF" }; +static char *fop_41[] = { "*fxch %GF" }; static char *fop_42[] = { "*fst %GF" }; static char *fop_43[] = { "*fstp %GF" }; static char *fop_44[] = { "*fucom %GF" }; static char *fop_45[] = { "*fucomp %GF" }; static char *fop_48[] = { "*faddp %GF,st" }; static char *fop_49[] = { "*fmulp %GF,st" }; +static char *fop_50[] = { "*fcomp %GF,st" }; static char *fop_51[] = { 0, "fcompp", 0, 0, 0, 0, 0, 0 }; static char *fop_52[] = { "*fsubrp %GF,st" }; static char *fop_53[] = { "*fsubp %GF,st" }; @@ -396,12 +402,12 @@ static char *fop_60[] = { "fstsw ax", 0, 0, 0, 0, 0, 0, 0 }; static char **fspecial[] = { /* 0=use st(i), 1=undefined 0 in fop_* means undefined */ 0, 0, 0, 0, 0, 0, 0, 0, - 0, fop_9, fop_10, 0, fop_12, fop_13, fop_14, fop_15, + fop_8, fop_9, fop_10, fop_11, fop_12, fop_13, fop_14, fop_15, f0, f0, f0, f0, f0, fop_21, f0, f0, f0, f0, f0, f0, fop_28, f0, f0, f0, - fop_32, fop_33, f0, f0, fop_36, fop_37, fop_38, fop_39, - fop_40, f0, fop_42, fop_43, fop_44, fop_45, f0, f0, - fop_48, fop_49, f0, fop_51, fop_52, fop_53, fop_54, fop_55, + fop_32, fop_33, fop_34, fop_35, fop_36, fop_37, fop_38, fop_39, + fop_40, fop_41, fop_42, fop_43, fop_44, fop_45, f0, f0, + fop_48, fop_49, fop_50, fop_51, fop_52, fop_53, fop_54, fop_55, f0, f0, f0, f0, fop_60, f0, f0, f0, }; diff --git a/src/debug/debug_gui.cpp b/src/debug/debug_gui.cpp index d9809ff..749333d 100644 --- a/src/debug/debug_gui.cpp +++ b/src/debug/debug_gui.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,9 +16,10 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - +/* $Id: debug_gui.cpp,v 1.28 2006/02/09 11:47:48 qbix79 Exp $ */ #include "dosbox.h" + #if C_DEBUG #include "setup.h" #include @@ -36,11 +37,16 @@ struct _LogGroup { char * front; bool enabled; }; +#include +#include +using namespace std; + +#define MAX_LOG_BUFFER 500 +static list logBuff; +static list::iterator logBuffPos = logBuff.end(); static _LogGroup loggrp[LOG_MAX]={{"",true},{0,false}}; static FILE* debuglog; -static std::list logBuff; -static std::list::iterator logBuffPos = logBuff.end(); extern int old_cursor_state; @@ -60,19 +66,15 @@ void DEBUG_ShowMsg(char * format,...) { if(debuglog) fprintf(debuglog,"%s",buf); - char* newLine = new char[strlen(buf) + 1]; - strcpy(newLine, buf); if (logBuffPos!=logBuff.end()) { logBuffPos=logBuff.end(); DEBUG_RefreshPage(0); mvwprintw(dbg.win_out,dbg.win_out->_maxy-1, 0, ""); } - logBuff.push_back(newLine); - if (logBuff.size()>500) { - char * firstline = logBuff.front(); - delete firstline; + logBuff.push_back(buf); + if (logBuff.size() > MAX_LOG_BUFFER) logBuff.pop_front(); - } + logBuffPos = logBuff.end(); wprintw(dbg.win_out,"%s",buf); wrefresh(dbg.win_out); @@ -82,14 +84,15 @@ void DEBUG_RefreshPage(char scroll) { if (scroll==-1 && logBuffPos!=logBuff.begin()) logBuffPos--; else if (scroll==1 && logBuffPos!=logBuff.end()) logBuffPos++; - std::list::iterator i = logBuffPos; + list::iterator i = logBuffPos; int rem_lines = dbg.win_out->_maxy; wclear(dbg.win_out); while (rem_lines > 0 && i!=logBuff.begin()) { - rem_lines -= (int) (strlen(*--i) / dbg.win_out->_maxx) + 1; - mvwprintw(dbg.win_out,rem_lines-1, 0, *i); + rem_lines -= (int) ((*--i).size() / dbg.win_out->_maxx) + 1; + /* Const cast is needed for pdcurses which has no const char in mvwprintw (bug maybe) */ + mvwprintw(dbg.win_out,rem_lines-1, 0, const_cast((*i).c_str())); } wrefresh(dbg.win_out); } @@ -127,6 +130,8 @@ static void Draw_RegisterLayout(void) { mvwaddstr(dbg.win_reg,1,28,"CS="); mvwaddstr(dbg.win_reg,1,38,"EIP="); + mvwaddstr(dbg.win_reg,2,75,"CPL"); + mvwaddstr(dbg.win_reg,2,68,"IOPL"); mvwaddstr(dbg.win_reg,1,52,"C Z S O A P D I T "); } diff --git a/src/debug/debug_inc.h b/src/debug/debug_inc.h index 713e957..a1cbf52 100644 --- a/src/debug/debug_inc.h +++ b/src/debug/debug_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -18,7 +18,7 @@ /* Local Debug Function */ -/* $Id: debug_inc.h,v 1.8 2004/08/28 12:51:35 qbix79 Exp $ */ +/* $Id: debug_inc.h,v 1.10 2006/02/09 11:47:48 qbix79 Exp $ */ #include #include "mem.h" diff --git a/src/debug/debug_win32.cpp b/src/debug/debug_win32.cpp index d1302f9..c3c48e5 100644 --- a/src/debug/debug_win32.cpp +++ b/src/debug/debug_win32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -69,6 +69,7 @@ static void ResizeConsole( HANDLE hConsole, SHORT xSize, SHORT ySize ) { void WIN32_Console() { AllocConsole(); + SetConsoleTitle("DOSBox Debugger"); ResizeConsole(GetStdHandle(STD_OUTPUT_HANDLE),80,50); } #endif diff --git a/src/debug/disasm_tables.h b/src/debug/disasm_tables.h index ac1798a..b0d3c4c 100644 --- a/src/debug/disasm_tables.h +++ b/src/debug/disasm_tables.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/dos/Makefile.am b/src/dos/Makefile.am index 4d206c7..0beeb4a 100644 --- a/src/dos/Makefile.am +++ b/src/dos/Makefile.am @@ -6,4 +6,5 @@ libdos_a_SOURCES = dos.cpp dos_devices.cpp dos_execute.cpp dos_files.cpp dos_ioc dos_misc.cpp dos_classes.cpp dos_programs.cpp dos_tables.cpp \ drives.cpp drives.h drive_virtual.cpp drive_local.cpp drive_cache.cpp drive_fat.cpp \ drive_iso.cpp dev_con.h dos_mscdex.cpp \ - cdrom.h cdrom.cpp cdrom_ioctl_win32.cpp cdrom_aspi_win32.cpp cdrom_ioctl_linux.cpp cdrom_image.cpp + cdrom.h cdrom.cpp cdrom_ioctl_win32.cpp cdrom_aspi_win32.cpp cdrom_ioctl_linux.cpp cdrom_image.cpp \ + cdrom_ioctl_os2.cpp diff --git a/src/dos/Makefile.in b/src/dos/Makefile.in index a329148..ff36b98 100644 --- a/src/dos/Makefile.in +++ b/src/dos/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -62,7 +62,8 @@ am_libdos_a_OBJECTS = dos.$(OBJEXT) dos_devices.$(OBJEXT) \ drive_cache.$(OBJEXT) drive_fat.$(OBJEXT) drive_iso.$(OBJEXT) \ dos_mscdex.$(OBJEXT) cdrom.$(OBJEXT) \ cdrom_ioctl_win32.$(OBJEXT) cdrom_aspi_win32.$(OBJEXT) \ - cdrom_ioctl_linux.$(OBJEXT) cdrom_image.$(OBJEXT) + cdrom_ioctl_linux.$(OBJEXT) cdrom_image.$(OBJEXT) \ + cdrom_ioctl_os2.$(OBJEXT) libdos_a_OBJECTS = $(am_libdos_a_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -107,6 +108,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -132,10 +135,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -184,7 +189,8 @@ libdos_a_SOURCES = dos.cpp dos_devices.cpp dos_execute.cpp dos_files.cpp dos_ioc dos_misc.cpp dos_classes.cpp dos_programs.cpp dos_tables.cpp \ drives.cpp drives.h drive_virtual.cpp drive_local.cpp drive_cache.cpp drive_fat.cpp \ drive_iso.cpp dev_con.h dos_mscdex.cpp \ - cdrom.h cdrom.cpp cdrom_ioctl_win32.cpp cdrom_aspi_win32.cpp cdrom_ioctl_linux.cpp cdrom_image.cpp + cdrom.h cdrom.cpp cdrom_ioctl_win32.cpp cdrom_aspi_win32.cpp cdrom_ioctl_linux.cpp cdrom_image.cpp \ + cdrom_ioctl_os2.cpp all: all-am @@ -237,6 +243,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdrom_aspi_win32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdrom_image.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdrom_ioctl_linux.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdrom_ioctl_os2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdrom_ioctl_win32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dos.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dos_classes.Po@am__quote@ diff --git a/src/dos/cdrom.cpp b/src/dos/cdrom.cpp index 9663313..96a17ae 100644 --- a/src/dos/cdrom.cpp +++ b/src/dos/cdrom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -53,7 +53,9 @@ bool CDROM_Interface_SDL::SetDevice (char* path, int forceCD) int num = SDL_CDNumDrives(); if ((forceCD>=0) && (forceCD #include @@ -29,9 +29,12 @@ #include #include "cdrom.h" #include "drives.h" +#include "support.h" #if !defined(WIN32) #include +#else +#include #endif using namespace std; @@ -256,7 +259,7 @@ bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long s Bitu buflen = num * sectorSize; Bit8u* buf = new Bit8u[buflen]; - bool success; + bool success = true; //Gobliiins reads 0 sectors for(int i = 0; i < num; i++) { success = ReadSector(&buf[i * sectorSize], raw, sector); if (!success) break; @@ -387,6 +390,22 @@ bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, int sectorSize, bool mod return (pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1); } +#if defined(WIN32) +static string dirname(char * file) { + char * sep = strrchr(file, '\\'); + if (sep == NULL) + sep = strrchr(file, '/'); + if (sep == NULL) + return ""; + else { + int len = (int)(sep - file); + char tmp[MAX_FILENAME_LENGTH]; + safe_strncpy(tmp, file, len+1); + return tmp; + } +} +#endif + bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) { Track track = {0, 0, 0, 0, 0, 0, false, NULL}; @@ -398,12 +417,8 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) bool success; bool canAddTrack = false; char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument - strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); -#if defined(WIN32) - string pathname(""); -#else + safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); string pathname(dirname(tmp)); -#endif ifstream in; in.open(cuefile, ios::in); if (in.fail()) return false; @@ -572,17 +587,15 @@ bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) if (stat(filename.c_str(), &test) == 0) return true; // check if file with path relative to cue file exists -#ifndef WIN32 string tmpstr(pathname + "/" + filename); if (stat(tmpstr.c_str(), &test) == 0) { filename = tmpstr; return true; } -#endif // finally check if file is in a dosbox local drive char fullname[CROSS_LEN]; char tmp[CROSS_LEN]; - strncpy(tmp, filename.c_str(), CROSS_LEN); + safe_strncpy(tmp, filename.c_str(), CROSS_LEN); Bit8u drive; if (!DOS_MakeName(tmp, fullname, &drive)) return false; diff --git a/src/dos/cdrom_ioctl_linux.cpp b/src/dos/cdrom_ioctl_linux.cpp index fe5eac3..a05e0ab 100644 --- a/src/dos/cdrom_ioctl_linux.cpp +++ b/src/dos/cdrom_ioctl_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -19,6 +19,7 @@ #include #include "cdrom.h" +#include "support.h" #if defined (LINUX) #include @@ -45,7 +46,7 @@ bool CDROM_Interface_Ioctl::GetUPC(unsigned char& attr, char* upc) if (ret > 0) { attr = 0; - strncpy(upc, (char*)cdrom_mcn.medium_catalog_number, 14); + safe_strncpy(upc, (char*)cdrom_mcn.medium_catalog_number, 14); } return (ret > 0); @@ -86,7 +87,7 @@ bool CDROM_Interface_Ioctl::SetDevice(char* path, int forceCD) if (success) { const char* tmp = SDL_CDName(forceCD); - if (tmp) strncpy(device_name, tmp, 512); + if (tmp) safe_strncpy(device_name, tmp, 512); else success = false; } diff --git a/src/dos/cdrom_ioctl_os2.cpp b/src/dos/cdrom_ioctl_os2.cpp new file mode 100644 index 0000000..383ea77 --- /dev/null +++ b/src/dos/cdrom_ioctl_os2.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: cdrom_ioctl_os2.cpp,v 1.2 2006/02/09 11:47:48 qbix79 Exp $ */ + +#include +#include "dosbox.h" +#include "cdrom.h" + +#if defined (OS2) +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#define INCL_DOSDEVICES +#define INCL_DOSDEVIOCTL +#include "os2.h" + +// Ripped from linux/cdrom.h +#define CD_FRAMESIZE_RAW 2352 +#define CD_FRAMESIZE 2048 + +CDROM_Interface_Ioctl::CDROM_Interface_Ioctl(void) : CDROM_Interface_SDL(){ + strcpy(device_name, ""); +} + +bool CDROM_Interface_Ioctl::GetUPC(unsigned char& attr, char* upc){ + HFILE cdrom_fd = 0; + ULONG ulAction = 0; + APIRET rc = DosOpen((unsigned char*)device_name, &cdrom_fd, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_DASD | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L); + if (rc != NO_ERROR) { + return false; + } + char data[50]; + ULONG len = sizeof(data); + char sig[] = {'C', 'D', '0', '1'}; + ULONG sigsize = 4; + rc = DosDevIOCtl(cdrom_fd, IOCTL_CDROMDISK, CDROMDISK_GETUPC, sig, sigsize, &sigsize, + data, len, &len); + if (rc != NO_ERROR) { + return false; + } + rc = DosClose(cdrom_fd); + return rc == NO_ERROR; +} + +bool CDROM_Interface_Ioctl::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num){ + HFILE cdrom_fd = 0; + ULONG ulAction = 0; + APIRET rc = DosOpen((unsigned char*)device_name, &cdrom_fd, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_DASD | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L); + if (rc != NO_ERROR) { + return false; + } + + Bitu buflen = raw ? num * CD_FRAMESIZE_RAW : num * CD_FRAMESIZE; + Bit8u* buf = new Bit8u[buflen]; + int ret = NO_ERROR; + + if (raw) { + struct paramseek { + UCHAR sig[4]; + UCHAR mode; + ULONG sec; + + paramseek(ULONG sector) + { + sig[0] = 'C'; sig[1] = 'D'; sig[2] = '0'; sig[3] = '1'; + sec = sector; + } + } param_seek(sector); + ULONG paramsize = sizeof (paramseek); + rc = DosDevIOCtl(cdrom_fd, IOCTL_CDROMDISK, CDROMDISK_SEEK, ¶m_seek, paramsize, ¶msize, + 0, 0, 0); + if (rc != NO_ERROR) { + return false; + } + + struct paramread { + UCHAR sig[4]; + UCHAR mode; + USHORT number; + BYTE sec; + BYTE reserved; + BYTE interleave; + + paramread(USHORT num) + { + sig[0] = 'C'; sig[1] = 'D'; sig[2] = '0'; sig[3] = '1'; + mode = 0; number = num; + sec = interleave = 0; + } + } param_read(num); + paramsize = sizeof (paramread); + ULONG len = buflen; + rc = DosDevIOCtl(cdrom_fd, IOCTL_CDROMDISK, CDROMDISK_READLONG, ¶m_read, paramsize, ¶msize, + buf, len, &len); + if (rc != NO_ERROR) { + return false; + } + } else { + ULONG pos = 0; + rc = DosSetFilePtr(cdrom_fd, sector * CD_FRAMESIZE, FILE_BEGIN, &pos); + if (rc != NO_ERROR) { + return false; + } + ULONG read = 0; + rc = DosRead(cdrom_fd, buf, buflen, &read); + if (rc != NO_ERROR || read != buflen) { + return false; + } + } + rc = DosClose(cdrom_fd); + MEM_BlockWrite(buffer, buf, buflen); + delete[] buf; + + return (ret == NO_ERROR); +} + +bool CDROM_Interface_Ioctl::SetDevice(char* path, int forceCD) { + bool success = CDROM_Interface_SDL::SetDevice(path, forceCD); + + if (success) { + char temp[3] = {0, 0, 0}; + if (path[1] == ':') { + temp[0] = path[0]; + temp[1] = path[1]; + temp[2] = 0; + } + strncpy(device_name, temp, 512); + } else { + strcpy(device_name, ""); + success = false; + } + + return success; +} + +#endif diff --git a/src/dos/cdrom_ioctl_win32.cpp b/src/dos/cdrom_ioctl_win32.cpp index cc5adaa..cfaa5e2 100644 --- a/src/dos/cdrom_ioctl_win32.cpp +++ b/src/dos/cdrom_ioctl_win32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: cdrom_ioctl_win32.cpp,v 1.11 2004/08/04 09:12:53 qbix79 Exp $ */ +/* $Id: cdrom_ioctl_win32.cpp,v 1.13 2006/02/09 11:47:48 qbix79 Exp $ */ #if defined (WIN32) diff --git a/src/dos/dev_con.h b/src/dos/dev_con.h index ae239db..7c7e50e 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dev_con.h,v 1.19 2004/10/17 14:45:00 qbix79 Exp $ */ +/* $Id: dev_con.h,v 1.24 2006/02/26 16:05:13 qbix79 Exp $ */ #include "dos_inc.h" #include "../ints/int10.h" @@ -34,7 +34,8 @@ public: void ClearAnsi(void); Bit16u GetInformation(void); private: - Bit8u cache; + Bit8u readcache; + Bit8u lastwrite; struct ansi { /* should create a constructor which fills them with the appriorate values */ bool esc; bool sci; @@ -53,13 +54,13 @@ private: bool device_CON::Read(Bit8u * data,Bit16u * size) { Bit16u oldax=reg_ax; Bit16u count=0; - if ((cache) && (*size)) { - data[count++]=cache; - if(dos.echo) INT10_TeletypeOutput(cache,7); - cache=0; + if ((readcache) && (*size)) { + data[count++]=readcache; + if(dos.echo) INT10_TeletypeOutput(readcache,7); + readcache=0; } while (*size>count) { - reg_ah=0; + reg_ah=(machine==MCH_VGA)?0x10:0x0; CALLBACK_RunRealInt(0x16); switch(reg_al) { case 13: @@ -83,13 +84,22 @@ bool device_CON::Read(Bit8u * data,Bit16u * size) { continue; //no data read yet so restart whileloop. } break; - default: - data[count++]=reg_al; + case 0xe0: /* Extended keys in the int 16 0x10 case */ + if(!reg_ah) { /*extended key if reg_ah isn't 0 */ + data[count++] = reg_al; + } else { + data[count++] = 0; + if (*size>count) data[count++] = reg_ah; + else readcache = reg_ah; + } break; - case 0: + case 0: /* Extended keys in the int 16 0x0 case */ data[count++]=reg_al; if (*size>count) data[count++]=reg_ah; - else cache=reg_ah; + else readcache=reg_ah; + break; + default: + data[count++]=reg_al; break; } if(dos.echo) { //what to do if *size==1 and character is BS ????? @@ -117,9 +127,11 @@ bool device_CON::Write(Bit8u * data,Bit16u * size) { count++; continue; } else { + /* Some sort of "hack" now that \n doesn't set col to 0 (int10_char.cpp old chessgame) */ + if((data[count] == '\n') && (lastwrite != '\r')) INT10_TeletypeOutputAttr('\r',ansi.attr,ansi.enabled); /* pass attribute only if ansi is enabled */ INT10_TeletypeOutputAttr(data[count],ansi.attr,ansi.enabled); - count++; + lastwrite = data[count++]; continue; } } @@ -130,7 +142,7 @@ bool device_CON::Write(Bit8u * data,Bit16u * size) { case '[': ansi.sci=true; break; - case '7': /* save cursor pos +attr */ + case '7': /* save cursor pos + attr */ case '8': /* restore this (Wonder if this is actually used) */ case 'D':/* scrolling DOWN*/ case 'M':/* scrolling UP*/ @@ -298,16 +310,15 @@ bool device_CON::Write(Bit8u * data,Bit16u * size) { break; case 'J': /*erase screen and move cursor home*/ if(ansi.data[0]==0) ansi.data[0]=2; - if(ansi.data[0]!=2) {/* only number 2 (the standard one supported) */ - LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: esc[%dJ called : not supported",ansi.data[0]); - break; + if(ansi.data[0]!=2) {/* every version behaves like type 2 */ + LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: esc[%dJ called : not supported handling as 2",ansi.data[0]); } - for(i=0;i<(Bitu)ansi.ncols*ansi.nrows;i++) INT10_TeletypeOutputAttr(' ',ansi.attr,true); + INT10_ScrollWindow(0,0,999,999,0,ansi.attr,0xFF); ClearAnsi(); INT10_SetCursorPos(0,0,0); break; - case 'h': /* set MODE (if code =7 enable linewrap) */ - case 'I': /*RESET MODE */ + case 'h': /* SET MODE (if code =7 enable linewrap) */ + case 'I': /* RESET MODE */ LOG(LOG_IOCTL,LOG_NORMAL)("ANSI: set/reset mode called(not supported)"); ClearAnsi(); break; @@ -320,9 +331,13 @@ bool device_CON::Write(Bit8u * data,Bit16u * size) { ansi.saverow=CURSOR_POS_ROW(0); ClearAnsi(); break; - case 'K':/* erase till end of line */ - for(i = CURSOR_POS_COL(0);i<(Bitu) ansi.ncols; i++) INT10_TeletypeOutputAttr(' ',ansi.attr,true); - ClearAnsi(); /* maybe set cursor back to starting place ???? */ + case 'K':/* erase till end of line (don't touch cursor) */ + col = CURSOR_POS_COL(0); + row = CURSOR_POS_ROW(0); + INT10_WriteChar(' ',ansi.attr,0,ansi.ncols-col,true); //Use this one to prevent scrolling when end of screen is reached + //for(i = col;i<(Bitu) ansi.ncols; i++) INT10_TeletypeOutputAttr(' ',ansi.attr,true); + INT10_SetCursorPos(row,col,0); + ClearAnsi(); break; case 'l':/* (if code =7) disable linewrap */ case 'p':/* reassign keys (needs strings) */ @@ -351,14 +366,15 @@ bool device_CON::Close() { Bit16u device_CON::GetInformation(void) { Bit16u head=mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); Bit16u tail=mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); - - if ((head==tail) && !cache) return 0x80D3; /* No Key Available */ + + if ((head==tail) && !readcache) return 0x80D3; /* No Key Available */ return 0x8093; /* Key Available */ }; device_CON::device_CON() { SetName("CON"); - cache=0; + readcache=0; + lastwrite=0; ansi.enabled=false; ansi.attr=0x7; ansi.ncols=real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); //should be updated once set/reset mode is implemented diff --git a/src/dos/dos.cpp b/src/dos/dos.cpp index d5feb7a..cfd2afb 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,9 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos.cpp,v 1.77 2004/11/16 14:24:52 qbix79 Exp $ */ +/* $Id: dos.cpp,v 1.93 2006/03/08 15:57:23 qbix79 Exp $ */ -#include #include #include #include @@ -30,12 +29,13 @@ #include "regs.h" #include "dos_inc.h" #include "setup.h" +#include "support.h" DOS_Block dos; DOS_InfoBlock dos_infoblock; -Bit8u dos_copybuf[0x10000]; -static Bitu call_20,call_21,call_25,call_26,call_27,call_28,call_29; +#define DOS_COPYBUFSIZE 0x10000 +Bit8u dos_copybuf[DOS_COPYBUFSIZE]; void DOS_SetError(Bit16u code) { dos.errorcode=code; @@ -89,8 +89,9 @@ static Bitu DOS_21Handler(void) { } default: { - Bit8u c=reg_dl;Bit16u n=1; + Bit8u c = reg_dl;Bit16u n = 1; DOS_WriteFile(STDOUT,&c,&n); + reg_al = reg_dl; } break; }; @@ -125,8 +126,23 @@ static Bitu DOS_21Handler(void) { Bit8u free=mem_readb(data); Bit8u read=0;Bit8u c;Bit16u n=1; if (!free) break; - while (read= free) { // Keyboard buffer full + Bit8u bell = 7; + DOS_WriteFile(STDOUT, &bell, &n); + continue; + } DOS_WriteFile(STDOUT,&c,&n); mem_writeb(data+read+2,c); if (c==13) @@ -143,6 +159,13 @@ static Bitu DOS_21Handler(void) { case 0x0c: /* Flush Buffer and read STDIN call */ { switch (reg_al) { + case 0x0: + /* flush STDIN-buffer */ + Bit8u c;Bit16u n; + while (DOS_GetSTDINStatus()) { + n=1; DOS_ReadFile(STDIN,&c,&n); + } + break; case 0x1: case 0x6: case 0x7: @@ -251,7 +274,7 @@ static Bitu DOS_21Handler(void) { { Bit8u difference; char string[1024]; - MEM_StrCopy(SegPhys(ds)+reg_si,string,1024); + MEM_StrCopy(SegPhys(ds)+reg_si,string,1023); // 1024 toasts the stack reg_al=FCB_Parsename(SegValue(es),reg_di,reg_al ,string, &difference); reg_si+=difference; } @@ -346,6 +369,11 @@ static Bitu DOS_21Handler(void) { case 0:reg_dl=dos.breakcheck;break; /* Get the breakcheck flag */ case 1:dos.breakcheck=(reg_dl>0);break; /* Set the breakcheck flag */ case 2:{bool old=dos.breakcheck;dos.breakcheck=(reg_dl>0);reg_dl=old;}break; + case 3: /* Get cpsw */ + /* Fallthrough */ + case 4: /* Set cpsw */ + LOG(LOG_DOSMISC,LOG_ERROR)("Someone playing with cpsw %x",reg_ax); + break; case 5:reg_dl=3;break;//TODO should be z /* Always boot from c: :) */ case 6: /* Get true version number */ reg_bl=dos.version.major; @@ -396,8 +424,8 @@ static Bitu DOS_21Handler(void) { case 0x38: /* Set Country Code */ if (reg_al==0) { /* Get country specidic information */ PhysPt dest = SegPhys(ds)+reg_dx; - MEM_BlockWrite(dest,dos.tables.country,0x22); - reg_bx = 0x01; + MEM_BlockWrite(dest,dos.tables.country,0x18); + reg_ax = reg_bx = 0x01; CALLBACK_SCF(false); break; } else { /* Set country code */ @@ -554,7 +582,8 @@ static Bitu DOS_21Handler(void) { } break; case 0x46: /* DUP2,FORCEDUP Force duplicate file handle */ - if (DOS_ForceDuplicateEntry(reg_bx,reg_ax)) { + if (DOS_ForceDuplicateEntry(reg_bx,reg_cx)) { + reg_ax=reg_cx; //Not all sources agree on it. CALLBACK_SCF(false); } else { reg_ax=dos.errorcode; @@ -706,15 +735,22 @@ static Bitu DOS_21Handler(void) { reg_ax=DOS_GetMemAllocStrategy(); break; case 1: /* Set Strategy */ - DOS_SetMemAllocStrategy(reg_bx); + if (DOS_SetMemAllocStrategy(reg_bx)) CALLBACK_SCF(false); + else { + reg_ax=1; + CALLBACK_SCF(true); + } break; case 2: /* Get UMB Link Status */ - reg_ax=1; // no UMB support - CALLBACK_SCF(true); + reg_al=dos_infoblock.GetUMBChainState()&1; + CALLBACK_SCF(false); break; case 3: /* Set UMB Link Status */ - reg_ax=1; // failure, no support - CALLBACK_SCF(true); + if (DOS_LinkUMBsToMemChain(reg_bx)) CALLBACK_SCF(false); + else { + reg_ax=1; + CALLBACK_SCF(true); + } break; default: LOG(LOG_DOSMISC,LOG_ERROR)("DOS:58:Not Supported Set//Get memory allocation call %X",reg_al); @@ -746,7 +782,7 @@ static Bitu DOS_21Handler(void) { Bit16u handle; if (DOS_OpenFile(name1,0,&handle)) { DOS_CloseFile(handle); - DOS_SetError(DOSERR_ACCESS_DENIED); + DOS_SetError(DOSERR_FILE_ALREADY_EXISTS); reg_ax=dos.errorcode; CALLBACK_SCF(true); break; @@ -795,19 +831,20 @@ static Bitu DOS_21Handler(void) { } else reg_al = 0xff; //Doesn't officially touch carry flag break; case 0x64: /* Set device driver lookahead flag */ - E_Exit("Unhandled Dos 21 call %02X",reg_ah); + LOG(LOG_DOSMISC,LOG_NORMAL)("set driver look ahead flag"); break; case 0x65: /* Get extented country information and a lot of other useless shit*/ { /* Todo maybe fully support this for now we set it standard for USA */ LOG(LOG_DOSMISC,LOG_ERROR)("DOS:65:Extended country information call %X",reg_ax); - if(reg_cx < 0x05 ) { + if((reg_al <= 0x07) && (reg_cx < 0x05)) { DOS_SetError(DOSERR_FUNCTION_NUMBER_INVALID); CALLBACK_SCF(true); break; } + Bitu len = 0; /* For 0x21 and 0x22 */ PhysPt data=SegPhys(es)+reg_di; switch (reg_al) { - case 1: + case 0x01: mem_writeb(data + 0x00,reg_al); mem_writew(data + 0x01,0x26); mem_writew(data + 0x03,1); @@ -819,15 +856,40 @@ static Bitu DOS_21Handler(void) { } CALLBACK_SCF(false); break; - case 2: // Get pointer to uppercase table - case 3: // Get pointer to lowercase table - case 4: // Get pointer to filename uppercase table - case 5: // Get pointer to filename terminator table - case 6: // Get pointer to collating sequence table - case 7: // Get pointer to double byte char set table - mem_writeb(data,reg_al); - mem_writed(data+1,dos.tables.dcbs); //used to be 0 - reg_cx=5; + case 0x02: // Get pointer to uppercase table + case 0x03: // Get pointer to lowercase table + case 0x04: // Get pointer to filename uppercase table + case 0x05: // Get pointer to filename terminator table + case 0x06: // Get pointer to collating sequence table + case 0x07: // Get pointer to double byte char set table + mem_writeb(data + 0x00, reg_al); + mem_writed(data + 0x01, dos.tables.dcbs); //used to be 0 + reg_cx = 5; + CALLBACK_SCF(false); + break; + case 0x20: /* Capitalize Character */ + { + int in = reg_dl; + int out = toupper(in); + reg_dl = out; + } + CALLBACK_SCF(false); + break; + case 0x21: /* Capitalize String (cx=length) */ + case 0x22: /* Capatilize ASCIZ string */ + data = SegPhys(ds) + reg_dx; + if(reg_al == 0x21) len = reg_cx; + else len = mem_strlen(data); /* Is limited to 1024 */ + + if(len > DOS_COPYBUFSIZE - 1) E_Exit("DOS:0x65 Buffer overflow"); + if(len) { + MEM_BlockRead(data,dos_copybuf,len); + dos_copybuf[len] = 0; + //No upcase as String(0x21) might be multiple asciz strings + for(Bitu count = 0; count < len;count++) + dos_copybuf[count] = toupper(*reinterpret_cast(dos_copybuf+count)); + MEM_BlockWrite(data,dos_copybuf,len); + } CALLBACK_SCF(false); break; default: @@ -960,64 +1022,66 @@ static Bitu DOS_29Handler(void) { } -void DOS_ShutDown(Section* sec) -{ - for (Bit16u i=0;itm_mday; + dos.date.month=(Bit8u)loctime->tm_mon+1; + dos.date.year=(Bit16u)loctime->tm_year+1900; + Bit32u ticks=(Bit32u)((loctime->tm_hour*3600+loctime->tm_min*60+loctime->tm_sec)*18.2); + mem_writed(BIOS_TIMER,ticks); + } + ~DOS(){ + for (Bit16u i=0;itm_mday; - dos.date.month=(Bit8u)loctime->tm_mon+1; - dos.date.year=(Bit16u)loctime->tm_year+1900; - Bit32u ticks=(Bit32u)((loctime->tm_hour*3600+loctime->tm_min*60+loctime->tm_sec)*18.2); - mem_writed(BIOS_TIMER,ticks); - - /* shutdown function */ - sec->AddDestroyFunction(&DOS_ShutDown); - +void DOS_ShutDown(Section* sec) { + delete test; } +void DOS_Init(Section* sec) { + test = new DOS(sec); + /* shutdown function */ + sec->AddDestroyFunction(&DOS_ShutDown,false); +} diff --git a/src/dos/dos_classes.cpp b/src/dos/dos_classes.cpp index 2b9874c..8a201f0 100644 --- a/src/dos/dos_classes.cpp +++ b/src/dos/dos_classes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_classes.cpp,v 1.42 2004/10/17 14:45:00 qbix79 Exp $ */ +/* $Id: dos_classes.cpp,v 1.47 2006/02/09 11:47:48 qbix79 Exp $ */ #include #include @@ -58,12 +58,12 @@ void DOS_ParamBlock::SaveData(void) { } -void DOS_InfoBlock::SetLocation(Bit16u segment) -{ +void DOS_InfoBlock::SetLocation(Bit16u segment) { seg = segment; pt=PhysMake(seg,0); -/* Clear the initual Block */ + /* Clear the initial Block */ for(Bitu i=0;i16mb + sSave(sDIB,extendedSize,(Bit16u)(MEM_TotalPages()*4-1024)); + sSave(sDIB,magicWord,(Bit16u)0x0001); // dos5+ sSave(sDIB,sharingCount,(Bit16u)0); sSave(sDIB,sharingDelay,(Bit16u)0); + sSave(sDIB,ptrCONinput,(Bit16u)0); // no unread input available + sSave(sDIB,maxSectorLength,(Bit16u)0x200); + + sSave(sDIB,dirtyDiskBuffers,(Bit16u)0); + sSave(sDIB,lookaheadBufPt,(Bit32u)0); + sSave(sDIB,lookaheadBufNumber,(Bit16u)0); + sSave(sDIB,bufferLocation,(Bit8u)0); // buffer in base memory, no workspace + sSave(sDIB,workspaceBuffer,(Bit32u)0); + + sSave(sDIB,minMemForExec,(Bit16u)0); + sSave(sDIB,memAllocScanStart,(Bit16u)DOS_MEM_START); + sSave(sDIB,startOfUMBChain,(Bit16u)0xffff); + sSave(sDIB,chainingUMB,(Bit8u)0); sSave(sDIB,nulNextDriver,(Bit32u)0xffffffff); sSave(sDIB,nulAttributes,(Bit16u)0x8004); @@ -98,45 +113,58 @@ void DOS_InfoBlock::SetLocation(Bit16u segment) sSave(sDIB,nulString[5],(Bit8u)0x20); sSave(sDIB,nulString[6],(Bit8u)0x20); sSave(sDIB,nulString[7],(Bit8u)0x20); + + /* Create a fake SFT, so programs think there are 100 file handles */ + Bit16u sftOffset=offsetof(sDIB,firstFileTable)+0xa2; + sSave(sDIB,firstFileTable,RealMake(segment,sftOffset)); + real_writed(segment,sftOffset+0x00,RealMake(segment+0x11,0)); //Next File Table + real_writew(segment,sftOffset+0x04,100); //File Table supports 100 files + real_writed(segment+0x11,0x00,0xffffffff); //Last File Table + real_writew(segment+0x11,0x04,100); //File Table supports 100 files } -void DOS_InfoBlock::SetFirstMCB(Bit16u _firstmcb) -{ +void DOS_InfoBlock::SetFirstMCB(Bit16u _firstmcb) { sSave(sDIB,firstMCB,_firstmcb); //c2woody } -void DOS_InfoBlock::SetfirstFileTable(RealPt _first_table){ - sSave(sDIB,firstFileTable,_first_table); -} - void DOS_InfoBlock::SetBuffers(Bit16u x,Bit16u y) { sSave(sDIB,buffers_x,x); sSave(sDIB,buffers_y,y); - } -void DOS_InfoBlock::SetCurDirStruct(Bit32u _curdirstruct) -{ +void DOS_InfoBlock::SetCurDirStruct(Bit32u _curdirstruct) { sSave(sDIB,curDirStructure,_curdirstruct); } -void DOS_InfoBlock::SetFCBTable(Bit32u _fcbtable) -{ +void DOS_InfoBlock::SetFCBTable(Bit32u _fcbtable) { sSave(sDIB,fcbTable,_fcbtable); } -void DOS_InfoBlock::SetDeviceChainStart(Bit32u _devchain) -{ +void DOS_InfoBlock::SetDeviceChainStart(Bit32u _devchain) { sSave(sDIB,nulNextDriver,_devchain); } -void DOS_InfoBlock::SetDiskInfoBuffer(Bit32u _dinfobuf) -{ - sSave(sDIB,diskInfoBuffer,_dinfobuf); +void DOS_InfoBlock::SetDiskBufferHeadPt(Bit32u _dbheadpt) { + sSave(sDIB,diskBufferHeadPt,_dbheadpt); } -RealPt DOS_InfoBlock::GetPointer(void) -{ +Bit16u DOS_InfoBlock::GetStartOfUMBChain(void) { + return sGet(sDIB,startOfUMBChain); +} + +void DOS_InfoBlock::SetStartOfUMBChain(Bit16u _umbstartseg) { + sSave(sDIB,startOfUMBChain,_umbstartseg); +} + +Bit8u DOS_InfoBlock::GetUMBChainState(void) { + return sGet(sDIB,chainingUMB); +} + +void DOS_InfoBlock::SetUMBChainState(Bit8u _umbchaining) { + sSave(sDIB,chainingUMB,_umbchaining); +} + +RealPt DOS_InfoBlock::GetPointer(void) { return RealMake(seg,offsetof(sDIB,firstDPB)); } diff --git a/src/dos/dos_devices.cpp b/src/dos/dos_devices.cpp index 83bb2bc..aded20f 100644 --- a/src/dos/dos_devices.cpp +++ b/src/dos/dos_devices.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_devices.cpp,v 1.8 2004/10/25 21:08:47 qbix79 Exp $ */ +/* $Id: dos_devices.cpp,v 1.11 2006/02/09 11:47:48 qbix79 Exp $ */ #include #include "dosbox.h" @@ -33,7 +33,6 @@ DOS_Device * Devices[DOS_DEVICES]; -static Bitu device_count; class device_NUL : public DOS_Device { public: @@ -111,37 +110,48 @@ DOS_File & DOS_File::operator= (const DOS_File & orig) { Bit8u DOS_FindDevice(char * name) { /* should only check for the names before the dot and spacepadded */ - char temp[CROSS_LEN];//TODOD + char temp[CROSS_LEN];//TODO if(!name || !(*name)) return DOS_DEVICES; strcpy(temp,name); char* dot= strrchr(temp,'.'); - if(dot && *dot) dot=0; //no ext checking + if(dot && *dot) *dot=0; //no ext checking /* loop through devices */ - Bit8u index=0; - while (indexname)) return index; } - index++; } return DOS_DEVICES; } void DOS_AddDevice(DOS_Device * adddev) { +//Caller creates the device. We store a pointer to it //TODO Give the Device a real handler in low memory that responds to calls - if (device_countSetDeviceNumber(device_count); - device_count++; - } else { - E_Exit("DOS:Too many devices added"); + for(Bitu i = 0; i < DOS_DEVICES;i++) { + if(!Devices[i]){ + Devices[i] = adddev; + Devices[i]->SetDeviceNumber(i); + return; + } + } + E_Exit("DOS:Too many devices added"); +} + +void DOS_DelDevice(DOS_Device * dev) { +// We will destroy the device if we find it in our list. +// TODO:The file table is not checked to see the device is opened somewhere! + for (Bitu i = 0; i name,dev->name)){ + delete Devices[i]; + Devices[i] = 0; + return; + } } } void DOS_SetupDevices(void) { - device_count=0; DOS_Device * newdev; newdev=new device_CON(); DOS_AddDevice(newdev); @@ -149,4 +159,3 @@ void DOS_SetupDevices(void) { newdev2=new device_NUL(); DOS_AddDevice(newdev2); } - diff --git a/src/dos/dos_execute.cpp b/src/dos/dos_execute.cpp index c512506..2841f86 100644 --- a/src/dos/dos_execute.cpp +++ b/src/dos/dos_execute.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_execute.cpp,v 1.44 2004/08/04 09:12:53 qbix79 Exp $ */ +/* $Id: dos_execute.cpp,v 1.54 2006/02/09 11:47:48 qbix79 Exp $ */ #include #include @@ -131,7 +131,9 @@ bool DOS_Terminate(bool tsr) { /* Set the CS:IP stored in int 0x22 back on the stack */ mem_writew(SegPhys(ss)+reg_sp+0,RealOff(old22)); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(old22)); - mem_writew(SegPhys(ss)+reg_sp+4,0x200); //stack isn't preserved + /* set IOPL=3 (Strike Commander), nested task set, + interrupts enabled, test flags cleared */ + mem_writew(SegPhys(ss)+reg_sp+4,0x7202); // Free memory owned by process if (!tsr) DOS_FreeProcessMemory(mempsp); DOS_UpdatePSPName(); @@ -185,8 +187,11 @@ static bool MakeEnv(char * name,Bit16u * segment) { bool DOS_NewPSP(Bit16u segment, Bit16u size) { DOS_PSP psp(segment); psp.MakeNew(size); - DOS_PSP psp_parent(psp.GetParent()); + Bit16u parent_psp_seg=psp.GetParent(); + DOS_PSP psp_parent(parent_psp_seg); psp.CopyFileTable(&psp_parent,false); + // copy command line as well (Kings Quest AGI -cga switch) + psp.SetCommandTail(RealMake(parent_psp_seg,0x80)); return true; }; @@ -243,19 +248,33 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { DOS_CloseFile(fhandle); return false; } - /* Convert the header to correct endian, i hope this works */ - HostPt endian=(HostPt)&head; - for (i=0;i 1 MB"); + head.pages&=0x07ff; + headersize = head.headersize*16; + imagesize = head.pages*512-headersize; + if (imagesize+headersize<512) imagesize = 512-headersize; + } } + Bit8u * loadbuf=(Bit8u *)new Bit8u[0x10000]; if (flags!=OVERLAY) { /* Create an environment block */ envseg=block.exec.envseg; @@ -267,6 +286,14 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { Bit16u minsize,maxsize;Bit16u maxfree=0xffff;DOS_AllocateMemory(&pspseg,&maxfree); if (iscom) { minsize=0x1000;maxsize=0xffff; + if (machine==MCH_PCJR) { + /* try to load file into memory below 96k */ + pos=0;DOS_SeekFile(fhandle,&pos,DOS_SEEK_SET); + Bit16u dataread=0x1800; + DOS_ReadFile(fhandle,loadbuf,&dataread); + if (dataread<0x1800) maxsize=dataread; + if (minsize>maxsize) minsize=maxsize; + } } else { /* Exe size calculated from header */ minsize=long2para(imagesize+(head.minmemory<<4)+256); if (head.maxmemory!=0) maxsize=long2para(imagesize+(head.maxmemory<<4)+256); @@ -280,13 +307,27 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { if (maxfree0x7FFF) { readsize=0x8000;DOS_ReadFile(fhandle,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); - if (readsize!=0x8000) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); +// if (readsize!=0x8000) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); loadaddress+=0x8000;imagesize-=0x8000; } if (imagesize>0) { readsize=(Bit16u)imagesize;DOS_ReadFile(fhandle,loadbuf,&readsize); MEM_BlockWrite(loadaddress,loadbuf,readsize); - if (readsize!=imagesize) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); +// if (readsize!=imagesize) LOG(LOG_EXEC,LOG_NORMAL)("Illegal header"); } /* Relocate the exe image */ Bit16u relocate; @@ -376,10 +417,16 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { reg_sp-=6; mem_writew(SegPhys(ss)+reg_sp+0,RealOff(csip)); mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(csip)); - mem_writew(SegPhys(ss)+reg_sp+4,0x200); + /* DOS starts programs with a RETF, so our IRET + should not modify critical flags (IOPL in v86 mode); + interrupt flag is set explicitly, test flags cleared */ + mem_writew(SegPhys(ss)+reg_sp+4,(reg_flags&(~FMASK_TEST))|FLAG_IF); /* Setup the rest of the registers */ - reg_ax=0;reg_si=0x100; - reg_cx=reg_dx=reg_bx=reg_di=reg_bp=0; + reg_ax=reg_bx=0;reg_cx=0xff; + reg_dx=pspseg; + reg_si=RealOff(csip); + reg_di=RealOff(sssp); + reg_bp=0x91c; /* DOS internal stack begin relict */ SegSet16(ds,pspseg);SegSet16(es,pspseg); #if C_DEBUG /* Started from debug.com, then set breakpoint at start */ @@ -407,9 +454,3 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { } return false; } - - - - - - diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index d569829..7c098b0 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_files.cpp,v 1.59 2004/11/16 14:28:15 qbix79 Exp $ */ +/* $Id: dos_files.cpp,v 1.72 2006/03/10 09:38:24 qbix79 Exp $ */ #include #include @@ -53,7 +53,10 @@ void DOS_SetDefaultDrive(Bit8u drive) { } bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) { - if(strlen(name) == 0) { + + if(!name || *name == 0 || *name == ' ') { + /* Both \0 and space are seperators and + * empty filenames report file not found */ DOS_SetError(DOSERR_FILE_NOT_FOUND); return false; } @@ -81,15 +84,16 @@ bool DOS_MakeName(char * name,char * fullname,Bit8u * drive) { case '/': upname[w++]='\\'; break; - case ' ': + case ' ': /* should be seperator */ break; case '\\': case '$': case '#': case '@': case '(': case ')': case '!': case '%': case '{': case '}': case '`': case '~': case '_': case '-': case '.': case '*': case '?': case '&': - case '\'': case '+': case '^': + case '\'': case '+': case '^': case 246: case 255: case 0xa0: upname[w++]=c; break; default: + LOG(LOG_FILES,LOG_NORMAL)("Makename encountered an illegal char %c hex:%X !",c,c); DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; break; } @@ -195,8 +199,20 @@ bool DOS_ChangeDir(char * dir) { bool DOS_MakeDir(char * dir) { Bit8u drive;char fulldir[DOS_PATHLENGTH]; + size_t len = strlen(dir); + if(!len || dir[len-1] == '\\') { + DOS_SetError(DOSERR_PATH_NOT_FOUND); + return false; + } if (!DOS_MakeName(dir,fulldir,&drive)) return false; - return Drives[drive]->MakeDir(fulldir); + if(Drives[drive]->MakeDir(fulldir)) return true; + + /* Determine reason for failing */ + if(Drives[drive]->TestDir(fulldir)) + DOS_SetError(DOSERR_ACCESS_DENIED); + else + DOS_SetError(DOSERR_PATH_NOT_FOUND); + return false; } bool DOS_RemoveDir(char * dir) { @@ -242,6 +258,12 @@ bool DOS_FindFirst(char * search,Bit16u attr,bool fcb_findfirst) { DOS_DTA dta(dos.dta()); Bit8u drive;char fullsearch[DOS_PATHLENGTH]; char dir[DOS_PATHLENGTH];char pattern[DOS_PATHLENGTH]; + size_t len = strlen(search); + if(len && search[len - 1] == '\\' && !( (len > 2) && (search[len - 2] == ':') && (attr == DOS_ATTR_VOLUME) )) { + //Dark Forces installer, but c:\ is allright for volume labels(exclusively set) + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; + } if (!DOS_MakeName(search,fullsearch,&drive)) return false; /* Split the search in dir and pattern */ char * find_last; @@ -267,7 +289,14 @@ bool DOS_FindFirst(char * search,Bit16u attr,bool fcb_findfirst) { bool DOS_FindNext(void) { DOS_DTA dta(dos.dta()); - if (Drives[dta.GetSearchDrive()]->FindNext(dta)) return true; + Bit8u i = dta.GetSearchDrive(); + if(i >= DOS_DRIVES || !Drives[i]) { + /* Corrupt search. */ + LOG(LOG_FILES,LOG_ERROR)("Corrupt search!!!!"); + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; + } + if (Drives[i]->FindNext(dta)) return true; return false; } @@ -394,21 +423,20 @@ bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) { if (flags>2) LOG(LOG_FILES,LOG_ERROR)("Special file open command %X file %s",flags,name); else LOG(LOG_FILES,LOG_NORMAL)("file open command %X file %s",flags,name); + DOS_PSP psp(dos.psp()); Bit16u attr = 0; - if(DOS_GetFileAttr(name,&attr)){ //DON'T ALLOW directories to be openened + Bit8u devnum = DOS_FindDevice((char *)name); + bool device = (devnum != DOS_DEVICES); + if(!device && DOS_GetFileAttr(name,&attr)) { + //DON'T ALLOW directories to be openened.(skip test if file is device). if((attr & DOS_ATTR_DIRECTORY) || (attr & DOS_ATTR_VOLUME)){ DOS_SetError(DOSERR_ACCESS_DENIED); return false; } } - - DOS_PSP psp(dos.psp()); - Bit8u devnum=DOS_DEVICES; - devnum=DOS_FindDevice((char *)name); - bool device=(devnum!=DOS_DEVICES); + char fullname[DOS_PATHLENGTH];Bit8u drive;Bit8u i; - - /* First check if the name is correct */ + /* First check if the name is correct */ if (!DOS_MakeName(name,fullname,&drive)) return false; Bit8u handle=255; /* Check for a free file handle */ @@ -440,7 +468,11 @@ bool DOS_OpenFile(char * name,Bit8u flags,Bit16u * entry) { psp.SetFileHandle(*entry,handle); return true; } else { - DOS_SetError(DOSERR_FILE_NOT_FOUND); + //Test if file exists, but opened in read-write mode (and writeprotected) + if(((flags&3) != OPEN_READ) && Drives[drive]->FileExists(fullname)) + DOS_SetError(DOSERR_ACCESS_DENIED); + else + DOS_SetError(DOSERR_FILE_NOT_FOUND); return false; } } @@ -501,7 +533,7 @@ bool DOS_SetFileAttr(char * name,Bit16u attr) Bit16u attrTemp; char fullname[DOS_PATHLENGTH];Bit8u drive; if (!DOS_MakeName(name,fullname,&drive)) return false; - if (strcmp(Drives[drive]->GetInfo(),"CDRom.")==0) { + if (strcmp(Drives[drive]->GetInfo(),"CDRom.")==0 || strcmp(Drives[drive]->GetInfo(),"isoDrive")==0) { DOS_SetError(DOSERR_ACCESS_DENIED); return false; } @@ -558,14 +590,12 @@ bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry) { }; bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry) { - // Dont duplicate console handles -/* if (entry<=STDPRN) { - newentry = entry; - return true; - }; -*/ - Bit8u orig=RealHandle(entry); - if (orig>=DOS_FILES) { + if(entry == newentry) { + DOS_SetError(DOSERR_INVALID_HANDLE); + return false; + } + Bit8u orig = RealHandle(entry); + if (orig >= DOS_FILES) { DOS_SetError(DOSERR_INVALID_HANDLE); return false; }; @@ -573,18 +603,13 @@ bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry) { DOS_SetError(DOSERR_INVALID_HANDLE); return false; }; - Bit8u newone=RealHandle(newentry); - if (newone>=DOS_FILES) { - DOS_SetError(DOSERR_INVALID_HANDLE); - return false; - }; - if (Files[newone]) { + Bit8u newone = RealHandle(newentry); + if (newone < DOS_FILES && Files[newone]) { DOS_CloseFile(newentry); - return false; - }; + } DOS_PSP psp(dos.psp()); Files[orig]->AddRef(); - psp.SetFileHandle(newentry,(Bit8u)entry); + psp.SetFileHandle(newentry,orig); return true; }; @@ -626,8 +651,7 @@ static bool isvalid(const char in){ #define PARSE_RET_WILD 1 #define PARSE_RET_BADDRIVE 0xff -Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change){ - +Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change) { char * string_begin=string;Bit8u ret=0; DOS_FCB fcb(seg,offset); bool hasdrive,hasname,hasext; @@ -649,7 +673,9 @@ Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u * #pragma pack() #endif /* Get the old information from the previous fcb */ - fcb.GetName(fcb_name.full);fcb_name.part.drive[1]=0;fcb_name.part.name[8]=0;fcb_name.part.ext[3]=0; + fcb.GetName(fcb_name.full); + fcb_name.part.drive[0]-='A'-1;fcb_name.part.drive[1]=0; + fcb_name.part.name[8]=0;fcb_name.part.ext[3]=0; /* Strip of the leading sepetaror */ if((parser & PARSE_SEP_STOP) && *string) { //ignore leading seperator char sep[] = FCB_SEP;char a[2]; @@ -989,7 +1015,7 @@ bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_c Bit16u _free_clusters; Drives[drive]->AllocationInfo(_bytes_sector,_sectors_cluster,_total_clusters,&_free_clusters); SegSet16(ds,RealSeg(dos.tables.mediaid)); - reg_bx=RealOff(dos.tables.mediaid+drive); + reg_bx=RealOff(dos.tables.mediaid+drive*2); return true; } @@ -1034,8 +1060,3 @@ void DOS_SetupFiles (void) { } Drives[25]=new Virtual_Drive(); } - - - - - diff --git a/src/dos/dos_ioctl.cpp b/src/dos/dos_ioctl.cpp index 4e00170..a627c2c 100644 --- a/src/dos/dos_ioctl.cpp +++ b/src/dos/dos_ioctl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_ioctl.cpp,v 1.21 2004/11/03 23:13:54 qbix79 Exp $ */ +/* $Id: dos_ioctl.cpp,v 1.26 2006/02/09 11:47:48 qbix79 Exp $ */ #include #include "dosbox.h" @@ -26,7 +26,7 @@ #include "dos_inc.h" bool DOS_IOCTL(void) { - Bitu handle;Bit8u drive; + Bitu handle=0;Bit8u drive=0; if (reg_al<8) { /* call 0-7 use a file handle */ handle=RealHandle(reg_bx); if (handle>=DOS_FILES) { @@ -37,6 +37,12 @@ bool DOS_IOCTL(void) { DOS_SetError(DOSERR_INVALID_HANDLE); return false; } + } else { /* the others use a diskdrive */ + drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; + if( !(( drive < DOS_DRIVES ) && Drives[drive]) ) { + DOS_SetError(DOSERR_INVALID_DRIVE); + return false; + } } switch(reg_al) { case 0x00: /* Get Device Information */ @@ -66,34 +72,20 @@ bool DOS_IOCTL(void) { reg_al=0xff; return true; case 0x08: /* Check if block device removable */ - drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; - if (Drives[drive]) { - /* Drive a,b are removable if mounted * - * So are cdrom drives */ - if (drive < 2 || Drives[drive]->isRemovable()) - reg_ax=0; - else reg_ax=1; - return true; - } else { - DOS_SetError(DOSERR_INVALID_DRIVE); - return false; - } + /* cdrom drives and drive a&b are removable */ + if (drive < 2 || Drives[drive]->isRemovable()) + reg_ax=0; + else reg_ax=1; + return true; case 0x09: /* Check if block device remote */ - drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; - if (Drives[drive]) { - reg_dx=0; - if (Drives[drive]->isRemote()) reg_dx|=(1 << 12); - //TODO Set bit 9 on drives that don't support direct I/O - reg_al=0; - return true; - } else { - DOS_SetError(DOSERR_INVALID_DRIVE); - return false; - } + reg_dx=0; + if (Drives[drive]->isRemote()) reg_dx|=(1 << 12); + //TODO Set bit 9 on drives that don't support direct I/O + reg_al=0; + return true; case 0x0D: /* Generic block device request */ { PhysPt ptr = SegPhys(ds)+reg_dx; - drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; switch (reg_cl) { case 0x60: /* Get Device parameters */ mem_writeb(ptr ,0x03); // special function @@ -106,6 +98,31 @@ bool DOS_IOCTL(void) { mem_writeb(ptr+8,0x00); // unit number mem_writed(ptr+0x1f,0xffffffff); // next parameter block break; + case 0x46: + case 0x66: /* Volume label */ + { + char const* bufin=Drives[drive]->GetLabel(); + char buffer[11] ={' '}; + + char const* find_ext=strchr(bufin,'.'); + if (find_ext) { + Bitu size=find_ext-bufin;if (size>8) size=8; + memcpy(buffer,bufin,size); + find_ext++; + memcpy(buffer+size,find_ext,(strlen(find_ext)>3) ? 3 : strlen(find_ext)); + } else { + memcpy(buffer,bufin,(strlen(bufin) > 8) ? 8 : strlen(bufin)); + } + + char buf2[8]={ 'F','A','T','1','6',' ',' ',' '}; + if(drive<2) buf2[4] = '2'; //FAT12 for floppies + + mem_writew(ptr+0,0); // 0 + mem_writed(ptr+2,0x1234); //Serial number + MEM_BlockWrite(ptr+6,buffer,11);//volumename + if(reg_cl == 0x66) MEM_BlockWrite(ptr+0x11, buf2,8);//filesystem + } + break; default : LOG(LOG_IOCTL,LOG_ERROR)("DOS:IOCTL Call 0D:%2X Drive %2X unhandled",reg_cl,drive); return false; @@ -113,15 +130,8 @@ bool DOS_IOCTL(void) { return true; } case 0xE: /* Get Logical Drive Map */ - drive=reg_bl;if (!drive) drive=dos.current_drive;else drive--; - if (Drives[drive]) { - reg_al=0; /* Only 1 logical drive assigned */ - return true; - } else { - DOS_SetError(DOSERR_INVALID_DRIVE); - return false; - } - break; + reg_al = 0; /* Only 1 logical drive assigned */ + return true; default: LOG(LOG_DOSMISC,LOG_ERROR)("DOS:IOCTL Call %2X unhandled",reg_al); return false; @@ -136,4 +146,3 @@ bool DOS_GetSTDINStatus(void) { if (Files[handle] && (Files[handle]->GetInformation() & 64)) return false; return true; }; - diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index d292db6..5a8b737 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -19,10 +19,9 @@ #include "dosbox.h" #include "mem.h" #include "dos_inc.h" +#include "callback.h" - -#define MEM_START 0x68 //First Segment that DOS can use -//#define MEM_START 4000 //First Segment that DOS can use +#define UMB_START_SEG 0x9fff static Bit16u memAllocStrategy = 0x00; @@ -50,94 +49,204 @@ void DOS_FreeProcessMemory(Bit16u pspseg) { if (mcb.GetPSPSeg()==pspseg) { mcb.SetPSPSeg(MCB_FREE); } - if (mcb.GetType()==0x5a) break; + if (mcb.GetType()==0x5a) { + /* check if currently last block reaches up to the PCJr graphics memory */ + if ((machine==MCH_PCJR) && (mcb_segment+mcb.GetSize()==0x17fe) && + (real_readb(0x17ff,0)==0x4d) && (real_readw(0x17ff,1)==8)) { + /* re-enable the memory past segment 0x2000 */ + mcb.SetType(0x4d); + } else break; + } mcb_segment+=mcb.GetSize()+1; mcb.SetPt(mcb_segment); } + + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start==UMB_START_SEG) { + DOS_MCB umb_mcb(umb_start); + while (true) { + if (umb_mcb.GetPSPSeg()==pspseg) { + umb_mcb.SetPSPSeg(MCB_FREE); + } + if (umb_mcb.GetType()!=0x4d) break; + umb_start+=umb_mcb.GetSize()+1; + umb_mcb.SetPt(umb_start); + } + } else if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); + DOS_CompressMemory(); -}; +} -Bit16u DOS_GetMemAllocStrategy() -{ +Bit16u DOS_GetMemAllocStrategy() { return memAllocStrategy; -}; +} -void DOS_SetMemAllocStrategy(Bit16u strat) -{ - memAllocStrategy = strat; -}; +bool DOS_SetMemAllocStrategy(Bit16u strat) { + if ((strat&0x3f)<3) { + memAllocStrategy = strat; + return true; + } + /* otherwise an invalid allocation strategy was specified */ + return false; +} bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks) { DOS_CompressMemory(); - Bit16u bigsize=0;Bit16u mcb_segment=dos.firstMCB; + Bit16u bigsize=0; + Bit16u mem_strat=memAllocStrategy; + Bit16u mcb_segment=dos.firstMCB; + + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start==UMB_START_SEG) { + /* start with UMBs if requested (bits 7 or 6 set) */ + if (mem_strat&0xc0) mcb_segment=umb_start; + } else if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); + DOS_MCB mcb(0); DOS_MCB mcb_next(0); DOS_MCB psp_mcb(dos.psp()-1); char psp_name[9]; psp_mcb.GetFileName(psp_name); - bool stop=false; - while(!stop) { + Bit16u found_seg=0,found_seg_size=0; + for (;;) { mcb.SetPt(mcb_segment); if (mcb.GetPSPSeg()==0) { /* Check for enough free memory in current block */ Bit16u block_size=mcb.GetSize(); if (block_size<(*blocks)) { if (bigsizetotal, + in the second case resize block to maximum */ + + if ((mcb_next.GetPSPSeg()==MCB_FREE) && (mcb.GetType()!=0x5a)) { + /* adjust type of joined MCB */ + mcb.SetType(mcb_next.GetType()); } - *blocks=total; + mcb.SetSize(total); + mcb.SetPSPSeg(dos.psp()); + if (*blocks==total) return true; /* block fit exactly */ + + *blocks=total; /* return maximum */ DOS_SetError(DOSERR_INSUFFICIENT_MEMORY); return false; } @@ -170,34 +286,199 @@ bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks) { bool DOS_FreeMemory(Bit16u segment) { //TODO Check if allowed to free this segment - if ((segment-1) < MEM_START){ + if (segment < DOS_MEM_START+1) { LOG(LOG_DOSMISC,LOG_ERROR)("Program tried to free %X ---ERROR",segment); + DOS_SetError(DOSERR_MB_ADDRESS_INVALID); return false; } DOS_MCB mcb(segment-1); + if ((mcb.GetType()!=0x4d) && (mcb.GetType()!=0x5a)) { + DOS_SetError(DOSERR_MB_ADDRESS_INVALID); + return false; + } mcb.SetPSPSeg(MCB_FREE); DOS_CompressMemory(); return true; } +void DOS_BuildUMBChain(const char* use_umbs,bool ems_active) { + if ((strcmp(use_umbs,"false")!=0) && (machine!=MCH_TANDY)) { + Bit16u first_umb_seg=0xca00; + Bit16u first_umb_size=0x600; + if (strcmp(use_umbs,"max")==0) { + first_umb_seg-=0x100; + first_umb_size+=0x100; + } -void DOS_SetupMemory(void) { - // Create a dummy device MCB with PSPSeg=0x0008 - DOS_MCB mcb_devicedummy((Bit16u)MEM_START); - mcb_devicedummy.SetPSPSeg(0x0008); // Devices - mcb_devicedummy.SetSize(1); - mcb_devicedummy.SetType(0x4d); // More blocks will follow - - DOS_MCB mcb((Bit16u)MEM_START+2); - mcb.SetPSPSeg(MCB_FREE); //Free - if (machine==MCH_TANDY) { - mcb.SetSize(0x97FE - MEM_START - 2); - } else mcb.SetSize(0x9FFE - MEM_START - 2); - mcb.SetType(0x5a); //Last Block + dos_infoblock.SetStartOfUMBChain(UMB_START_SEG); + dos_infoblock.SetUMBChainState(0); // UMBs not linked yet - dos.firstMCB=MEM_START; - dos_infoblock.SetFirstMCB(MEM_START); + DOS_MCB umb_mcb(first_umb_seg); + umb_mcb.SetPSPSeg(0); // currently free + umb_mcb.SetSize(first_umb_size-1); + umb_mcb.SetType(0x5a); + + /* Scan MCB-chain for last block */ + Bit16u mcb_segment=dos.firstMCB; + DOS_MCB mcb(mcb_segment); + while (mcb.GetType()!=0x5a) { + mcb_segment+=mcb.GetSize()+1; + mcb.SetPt(mcb_segment); + } + + /* A system MCB has to cover the space between the + regular MCB-chain and the UMBs */ + Bit16u cover_mcb=(Bit16u)(mcb_segment+mcb.GetSize()+1); + mcb.SetPt(cover_mcb); + mcb.SetType(0x4d); + mcb.SetPSPSeg(0x0008); + mcb.SetSize(first_umb_seg-cover_mcb-1); + mcb.SetFileName("SC "); + + if (!ems_active && (strcmp(use_umbs,"max")==0) && (machine!=MCH_PCJR)) { + Bit16u ems_umb_seg=0xe000; + Bit16u ems_umb_size=0x1000; + + /* Continue UMB-chain */ + umb_mcb.SetSize(first_umb_size-2); + umb_mcb.SetType(0x4d); + + DOS_MCB umb2_mcb(ems_umb_seg); + umb2_mcb.SetPSPSeg(0); // currently free + umb2_mcb.SetSize(ems_umb_size-1); + umb2_mcb.SetType(0x5a); + + /* A system MCB has to take out the space between the previous and this UMB */ + cover_mcb=(Bit16u)(first_umb_seg+umb_mcb.GetSize()+1); + mcb.SetPt(cover_mcb); + mcb.SetType(0x4d); + mcb.SetPSPSeg(0x0008); + mcb.SetSize(ems_umb_seg-cover_mcb-1); + mcb.SetFileName("SC "); + } + } else { + dos_infoblock.SetStartOfUMBChain(0xffff); + dos_infoblock.SetUMBChainState(0); + } +} + +bool DOS_LinkUMBsToMemChain(Bit16u linkstate) { + /* Get start of UMB-chain */ + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start!=UMB_START_SEG) { + if (umb_start!=0xffff) LOG(LOG_DOSMISC,LOG_ERROR)("Corrupt UMB chain: %x",umb_start); + return true; + } + + if ((linkstate&1)==(dos_infoblock.GetUMBChainState()&1)) return true; + + /* Scan MCB-chain for last block before UMB-chain */ + Bit16u mcb_segment=dos.firstMCB; + Bit16u prev_mcb_segment; + DOS_MCB mcb(mcb_segment); + while ((mcb_segment!=umb_start) && (mcb.GetType()!=0x5a)) { + prev_mcb_segment=mcb_segment; + mcb_segment+=mcb.GetSize()+1; + mcb.SetPt(mcb_segment); + } + DOS_MCB prev_mcb(prev_mcb_segment); + + switch (linkstate) { + case 0x0000: // unlink + if ((prev_mcb.GetType()==0x4d) && (mcb_segment==umb_start)) { + prev_mcb.SetType(0x5a); + } + dos_infoblock.SetUMBChainState(0); + break; + case 0x0001: // link + if (mcb.GetType()==0x5a) { + mcb.SetType(0x4d); + dos_infoblock.SetUMBChainState(1); + } + break; + default: + LOG_MSG("Invalid link state %x when reconfiguring MCB chain",linkstate); + return false; + } + + return true; +} + + +static Bitu DOS_default_handler(void) { + LOG(LOG_CPU,LOG_ERROR)("DOS rerouted Interrupt Called %X",lastint); + return CBRET_NONE; +}; + +static CALLBACK_HandlerObject callbackhandler; +void DOS_SetupMemory(void) { + /* Let dos claim a few bios interrupts. Makes DOSBox more compatible with + * buggy games, which compare against the interrupt table. (probably a + * broken linked list implementation) */ + callbackhandler.Allocate(&DOS_default_handler,"DOS default int"); + real_writeb(0x70,4,(Bit8u)0xFE); //GRP 4 + real_writeb(0x70,5,(Bit8u)0x38); //Extra Callback instruction + real_writew(0x70,6,callbackhandler.Get_callback()); //The immediate word + real_writeb(0x70,8,(Bit8u)0xCF); //An IRET Instruction + real_writed(0,0x01*4,0x700004); + real_writed(0,0x02*4,0x700004); //BioMenace (segment<0x8000) + real_writed(0,0x03*4,0x700004); //Alien Incident (offset!=0) + real_writed(0,0x04*4,0x700004); //Shadow President (lower byte of segment!=0) +// real_writed(0,0x0f*4,0x700004); //Always a tricky one (soundblaster irq) + + // Create a dummy device MCB with PSPSeg=0x0008 + DOS_MCB mcb_devicedummy((Bit16u)DOS_MEM_START); + mcb_devicedummy.SetPSPSeg(MCB_DOS); // Devices + mcb_devicedummy.SetSize(1); + mcb_devicedummy.SetType(0x4d); // More blocks will follow +// mcb_devicedummy.SetFileName("SD "); + + Bit16u mcb_sizes=2; + // Create a small empty MCB (result from a growing environment block) + DOS_MCB tempmcb((Bit16u)DOS_MEM_START+mcb_sizes); + tempmcb.SetPSPSeg(MCB_FREE); + tempmcb.SetSize(4); + mcb_sizes+=5; + tempmcb.SetType(0x4d); + + // Lock the previous empty MCB + DOS_MCB tempmcb2((Bit16u)DOS_MEM_START+mcb_sizes); + tempmcb2.SetPSPSeg(0x40); // can be removed by loadfix + tempmcb2.SetSize(16); + mcb_sizes+=17; + tempmcb2.SetType(0x4d); + + DOS_MCB mcb((Bit16u)DOS_MEM_START+mcb_sizes); + mcb.SetPSPSeg(MCB_FREE); //Free + mcb.SetType(0x5a); //Last Block + if (machine==MCH_TANDY) { + /* memory up to 608k available, the rest (to 640k) is used by + the tandy graphics system's variable mapping of 0xb800 */ + mcb.SetSize(0x97FE - DOS_MEM_START - mcb_sizes); + } else if (machine==MCH_PCJR) { + /* memory from 128k to 640k is available */ + mcb_devicedummy.SetPt((Bit16u)0x2000); + mcb_devicedummy.SetPSPSeg(MCB_FREE); + mcb_devicedummy.SetSize(0x9FFE - 0x2000); + mcb_devicedummy.SetType(0x5a); + + /* exclude PCJr graphics region */ + mcb_devicedummy.SetPt((Bit16u)0x17ff); + mcb_devicedummy.SetPSPSeg(MCB_DOS); + mcb_devicedummy.SetSize(0x800); + mcb_devicedummy.SetType(0x4d); + + /* memory below 96k */ + mcb.SetSize(0x1800 - DOS_MEM_START - (2+mcb_sizes)); + mcb.SetType(0x4d); + } else { + /* complete memory up to 640k available */ + mcb.SetSize(0x9FFE - DOS_MEM_START - mcb_sizes); + } + + dos.firstMCB=DOS_MEM_START; + dos_infoblock.SetFirstMCB(DOS_MEM_START); } diff --git a/src/dos/dos_misc.cpp b/src/dos/dos_misc.cpp index 0fa2c72..fd0549e 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,37 +16,39 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_misc.cpp,v 1.12 2004/08/04 09:12:53 qbix79 Exp $ */ +/* $Id: dos_misc.cpp,v 1.16 2006/02/09 11:47:48 qbix79 Exp $ */ #include "dosbox.h" #include "callback.h" #include "mem.h" #include "regs.h" #include "dos_inc.h" +#include static Bitu call_int2f,call_int2a; -struct MultiplexBlock { - MultiplexHandler * handler; - MultiplexBlock * next; -}; -static MultiplexBlock * first_multiplex; +static std::list Multiplex; +typedef std::list::iterator Multiplex_it; void DOS_AddMultiplexHandler(MultiplexHandler * handler) { - MultiplexBlock * new_multiplex=new(MultiplexBlock); - new_multiplex->next=first_multiplex; - new_multiplex->handler=handler; - first_multiplex=new_multiplex; + Multiplex.push_front(handler); +} + +void DOS_DelMultiplexHandler(MultiplexHandler * handler) { + for(Multiplex_it it =Multiplex.begin();it != Multiplex.end();it++) { + if(*it == handler) { + Multiplex.erase(it); + return; + } + } } static Bitu INT2F_Handler(void) { - MultiplexBlock * loop_multiplex=first_multiplex; - while (loop_multiplex) { - if ((*loop_multiplex->handler)()) return CBRET_NONE; - loop_multiplex=loop_multiplex->next; - } - LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Multiplex Unhandled call %4X",reg_ax); + for(Multiplex_it it = Multiplex.begin();it != Multiplex.end();it++) + if( (*it)() ) return CBRET_NONE; + + LOG(LOG_DOSMISC,LOG_ERROR)("DOS:Multiplex Unhandled call %4X",reg_ax); return CBRET_NONE; }; @@ -58,6 +60,12 @@ static Bitu INT2A_Handler(void) { static bool DOS_MultiplexFunctions(void) { switch (reg_ax) { + case 0x1216: /* GET ADDRESS OF SYSTEM FILE TABLE ENTRY */ + /* Should do a lot more. Let's see if we can get away with it */ + LOG(LOG_DOSMISC,LOG_ERROR)("Some BAD filetable call used bx=%X",reg_bx); + if(reg_bx <= DOS_FILES) CALLBACK_SCF(false); + else CALLBACK_SCF(true); + return true; case 0x1607: if (reg_bx == 0x15) { switch (reg_cx) { @@ -116,7 +124,6 @@ static bool DOS_MultiplexFunctions(void) { void DOS_SetupMisc(void) { /* Setup the dos multiplex interrupt */ - first_multiplex=0; call_int2f=CALLBACK_Allocate(); CALLBACK_Setup(call_int2f,&INT2F_Handler,CB_IRET,"DOS Int 2f"); RealSetVec(0x2f,CALLBACK_RealPointer(call_int2f)); @@ -126,4 +133,3 @@ void DOS_SetupMisc(void) { CALLBACK_Setup(call_int2a,&INT2A_Handler,CB_IRET,"DOS Int 2a"); RealSetVec(0x2A,CALLBACK_RealPointer(call_int2a)); }; - diff --git a/src/dos/dos_mscdex.cpp b/src/dos/dos_mscdex.cpp index 444de4f..e9389a8 100644 --- a/src/dos/dos_mscdex.cpp +++ b/src/dos/dos_mscdex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_mscdex.cpp,v 1.26 2004/10/17 14:45:00 qbix79 Exp $ */ +/* $Id: dos_mscdex.cpp,v 1.37 2006/03/26 11:54:44 qbix79 Exp $ */ #include #include @@ -34,7 +34,7 @@ #define MSCDEX_VERSION_HIGH 2 #define MSCDEX_VERSION_LOW 23 -#define MSCDEX_MAX_DRIVES 5 +#define MSCDEX_MAX_DRIVES 8 // Error Codes #define MSCDEX_ERROR_BAD_FORMAT 11 @@ -149,7 +149,7 @@ private: Bit32u volumeSize; // for media change } TDriveInfo; - PhysPt defaultBuffer; + Bit16u defaultBufSeg; TDriveInfo dinfo[MSCDEX_MAX_DRIVES]; CDROM_Interface* cdrom[MSCDEX_MAX_DRIVES]; @@ -161,7 +161,7 @@ CMscdex::CMscdex(void) { numDrives = 0; rootDriverHeaderSeg = 0; - defaultBuffer = 0; + defaultBufSeg = 0; memset(dinfo,0,sizeof(dinfo)); for (Bit32u i=0; i 1 && strcmp(searchName,"..")) + if(searchName[searchlen-1] =='.') searchName[searchlen-1] = 0; + + //LOG(LOG_MISC,LOG_ERROR)("MSCDEX: Get DirEntry : Find : %s",searchName); // read vtoc PhysPt defBuffer = GetDefaultBuffer(); if (!ReadSectors(GetSubUnit(drive),false,16,1,defBuffer)) return false; @@ -613,25 +619,57 @@ bool CMscdex::GetDirectoryEntry(Bit16u drive, bool copyFlag, PhysPt pathname, Ph nameLength = mem_readb(defBuffer+index+32); MEM_StrCopy(defBuffer+index+33,entryName,nameLength); if (strcmp(entryName,useName)==0) { -// LOG(LOG_MISC,LOG_ERROR)("MSCDEX: Get DirEntry : Found : %s",useName); + //LOG(LOG_MISC,LOG_ERROR)("MSCDEX: Get DirEntry : Found : %s",useName); foundName = true; break; } + /* Xcom Apocalipse searches for MUSIC. and expects to find MUSIC;1 + * All Files on the CDROM are of the kind blah;1 + */ + char* longername = strchr(entryName,';'); + if(longername) { + *longername = 0; + if (strcmp(entryName,useName)==0) { + //LOG(LOG_MISC,LOG_ERROR)("MSCDEX: Get DirEntry : Found : %s",useName); + foundName = true; + break; + } + } index += entryLength; } while (index+33<=2048); if (foundName) { // TO DO : name gefunden, Daten in den Buffer kopieren if (foundComplete) { - if (copyFlag) LOG(LOG_MISC,LOG_ERROR)("MSCDEX: GetDirEntry: Unsupported copyflag. (result structure should be different"); - // Direct copy - MEM_BlockCopy(buffer,defBuffer+index,entryLength); + if (copyFlag) { + LOG(LOG_MISC,LOG_WARN)("MSCDEX: GetDirEntry: Copyflag structure not entirely accurate maybe"); + Bit8u readBuf[256]; + Bit8u writeBuf[256]; + if (entryLength > 256) + return false; + MEM_BlockRead( defBuffer+index, readBuf, entryLength ); + writeBuf[0] = readBuf[1]; // 00h BYTE length of XAR in Logical Block Numbers + memcpy( &writeBuf[1], &readBuf[0x2], 4); // 01h DWORD Logical Block Number of file start + writeBuf[5] = 0;writeBuf[6] = 8; // 05h WORD size of disk in logical blocks + memcpy( &writeBuf[7], &readBuf[0xa], 4); // 07h DWORD file length in bytes + memcpy( &writeBuf[0xb], &readBuf[0x12], 7); // 0bh DWORD date and time + writeBuf[0x12] = readBuf[0x19]; // 12h BYTE bit flags + writeBuf[0x13] = readBuf[0x1a]; // 13h BYTE interleave size + writeBuf[0x14] = readBuf[0x1b]; // 14h BYTE interleave skip factor + memcpy( &writeBuf[0x15], &readBuf[0x1c], 2); // 15h WORD volume set sequence number + writeBuf[0x17] = readBuf[0x20]; + memcpy( &writeBuf[0x18], &readBuf[21], readBuf[0x20] <= 38 ? readBuf[0x20] : 38 ); + MEM_BlockWrite( buffer, writeBuf, 0x18 + 40 ); + } else { + // Direct copy + MEM_BlockCopy(buffer,defBuffer+index,entryLength); + } error = iso ? 1:0; return true; } // directory wechseln - dirEntrySector = mem_readd(defBuffer+index+2); - dirSize = mem_readd(defBuffer+index+10); + dirEntrySector = mem_readd(defBuffer+index+2); + dirSize = mem_readd(defBuffer+index+10); } else { // continue search in next sector dirSize -= 2048; @@ -725,8 +763,7 @@ Bit16u CMscdex::GetStatusWord(Bit8u subUnit) return status; }; -void CMscdex::InitNewMedia(Bit8u subUnit) -{ +void CMscdex::InitNewMedia(Bit8u subUnit) { if (subUnitInitNewMedia(); @@ -735,16 +772,12 @@ void CMscdex::InitNewMedia(Bit8u subUnit) static CMscdex* mscdex = 0; -static Bitu MSCDEX_Strategy_Handler(void) -{ -// LOG("MSCDEX: Device Strategy Routine called."); +static Bitu MSCDEX_Strategy_Handler(void) { +// MSCDEX_LOG("MSCDEX: Device Strategy Routine called."); return CBRET_NONE; } -static Bitu MSCDEX_Interrupt_Handler(void) -{ -// LOG("MSCDEX: Device Interrupt Routine called."); - +static Bitu MSCDEX_Interrupt_Handler(void) { Bit8u subFuncNr = 0xFF; PhysPt data = PhysMake(SegValue(es),reg_bx); Bit8u subUnit = mem_readb(data+1); @@ -752,7 +785,7 @@ static Bitu MSCDEX_Interrupt_Handler(void) MSCDEX_LOG("MSCDEX: Driver Function %02X",funcNr); - switch (funcNr) { + switch (funcNr) { case 0x03 : { /* IOCTL INPUT */ PhysPt buffer = PhysMake(mem_readw(data+0x10),mem_readw(data+0x0E)); @@ -765,11 +798,15 @@ static Bitu MSCDEX_Interrupt_Handler(void) case 0x01 :{/* Get current position */ TMSF pos; mscdex->GetCurrentPos(subUnit,pos); - mem_writeb(buffer+1,0x01); // Red book + /*mem_writeb(buffer+1,0x01); // Red book mem_writeb(buffer+2,pos.fr); mem_writeb(buffer+3,pos.sec); mem_writeb(buffer+4,pos.min); - mem_writeb(buffer+5,0x00); + mem_writeb(buffer+5,0x00);*/ + //Changed to HSG as default + //(Seems to fix a few broken games which don't test for it) + mem_writeb(buffer+1,0x00); //HSG + mem_writed(buffer+2,MSF_TO_FRAMES (pos.min, pos.sec, pos.fr)); }break; case 0x06 : /* Get Device status */ mem_writed(buffer+1,mscdex->GetDeviceStatus(subUnit)); @@ -862,6 +899,10 @@ static Bitu MSCDEX_Interrupt_Handler(void) case 0x01 : // (un)Lock door // do nothing -> report as success break; + case 0x02 : // Reset Drive + LOG(LOG_MISC,LOG_WARN)("cdromDrive reset"); + mscdex->StopAudio(subUnit); + break; case 0x05 : // load media mscdex->LoadUnloadMedia(subUnit,false); break; @@ -913,12 +954,23 @@ static Bitu MSCDEX_Interrupt_Handler(void) return CBRET_NONE; } -static bool MSCDEX_Handler(void) -{ +static bool MSCDEX_Handler(void) { + if(reg_ah == 0x11) { + if(reg_al == 0x00) { + reg_al = 0xff; + return true; + } else { + LOG(LOG_MISC,LOG_ERROR)("NETWORK REDIRECTOR USED!!!"); + reg_ax = 0x49;//NETWERK SOFTWARE NOT INSTALLED + CALLBACK_SCF(true); + return true; + } + } + if (reg_ah!=0x15) return false; PhysPt data = PhysMake(SegValue(es),reg_bx); - MSCDEX_LOG("MSCDEX: INT 2F %04X BX= %04X CX=%04X",reg_ax,reg_bx,reg_bx); + MSCDEX_LOG("MSCDEX: INT 2F %04X BX= %04X CX=%04X",reg_ax,reg_bx,reg_cx); switch (reg_ax) { case 0x1500: /* Install check */ @@ -1076,4 +1128,3 @@ void MSCDEX_Init(Section* sec) /* Create MSCDEX */ mscdex = new CMscdex; }; - diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index a7fffe7..383d151 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_programs.cpp,v 1.33 2004/11/13 12:08:43 qbix79 Exp $ */ +/* $Id: dos_programs.cpp,v 1.56 2006/03/12 21:12:20 qbix79 Exp $ */ #include #include @@ -32,6 +32,15 @@ #include "dos_inc.h" #include "bios.h" +#if defined(OS2) +#define INCL DOSFILEMGR +#define INCL_DOSERRORS +#include "os2.h" +#endif + +#if C_DEBUG +Bitu DEBUG_EnableDebugger(void); +#endif void MSCDEX_SetCDInterface(int intNr, int forceCD); @@ -138,20 +147,70 @@ public: if (!cmd->FindCommand(2,temp_line)) goto showusage; if (!temp_line.size()) goto showusage; -#if defined (WIN32) + struct stat test; + //Win32 : strip tailing backslashes + //os2: some special drive check + //rest: substiture ~ for home + bool failed = false; +#if defined (WIN32) || defined(OS2) /* Removing trailing backslash if not root dir so stat will succeed */ if(temp_line.size() > 3 && temp_line[temp_line.size()-1]=='\\') temp_line.erase(temp_line.size()-1,1); -#endif - struct stat test; if (stat(temp_line.c_str(),&test)) { +#endif +#if defined(WIN32) +// Nothing to do here. +#elif defined (OS2) + if (temp_line.size() <= 2) // Seems to be a drive. + { + failed = true; + HFILE cdrom_fd = 0; + ULONG ulAction = 0; + + APIRET rc = DosOpen((unsigned char*)temp_line.c_str(), &cdrom_fd, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_DASD | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L); + DosClose(cdrom_fd); + if (rc != NO_ERROR && rc != ERROR_NOT_READY) + { + failed = true; + } else { + failed = false; + } + } + } + if (failed) { +#else + if (stat(temp_line.c_str(),&test)) { + failed = true; + if(temp_line.size() && temp_line[0] == '~') { + char * home = getenv("HOME"); + if(home) temp_line.replace(0,1,std::string(home)); + if(!stat(temp_line.c_str(),&test)) failed = false; + } + } + if(failed) { +#endif WriteOut(MSG_Get("PROGRAM_MOUNT_ERROR_1"),temp_line.c_str()); return; } /* Not a switch so a normal directory/file */ if (!(test.st_mode & S_IFDIR)) { +#ifdef OS2 + HFILE cdrom_fd = 0; + ULONG ulAction = 0; + + APIRET rc = DosOpen((unsigned char*)temp_line.c_str(), &cdrom_fd, &ulAction, 0L, FILE_NORMAL, OPEN_ACTION_OPEN_IF_EXISTS, + OPEN_FLAGS_DASD | OPEN_SHARE_DENYNONE | OPEN_ACCESS_READONLY, 0L); + DosClose(cdrom_fd); + if (rc != NO_ERROR && rc != ERROR_NOT_READY) { WriteOut(MSG_Get("PROGRAM_MOUNT_ERROR_2"),temp_line.c_str()); return; } +#else + WriteOut(MSG_Get("PROGRAM_MOUNT_ERROR_2"),temp_line.c_str()); + return; +#endif + } + if (temp_line[temp_line.size()-1]!=CROSS_FILESPLIT) temp_line+=CROSS_FILESPLIT; Bit8u bit8size=(Bit8u) sizes[1]; if (type=="cdrom") { @@ -173,6 +232,12 @@ public: default : WriteOut(MSG_Get("MSCDEX_UNKNOWN_ERROR")); break; }; } else { + /* Give a warning when mount c:\ or the / */ +#if defined (WIN32) || defined(OS2) + if( (temp_line == "c:\\") || (temp_line == "C:\\")) WriteOut(MSG_Get("PROGRAM_MOUNT_WARNING_WIN")); +#else + if(temp_line == "/") WriteOut(MSG_Get("PROGRAM_MOUNT_WARNING_OTHER")); +#endif newdrive=new localDrive(temp_line.c_str(),sizes[0],bit8size,sizes[2],sizes[3],mediaid); } } else { @@ -187,10 +252,20 @@ public: if (!newdrive) E_Exit("DOS:Can't create drive"); Drives[drive-'A']=newdrive; /* Set the correct media byte in the table */ - mem_writeb(Real2Phys(dos.tables.mediaid)+drive-'A',newdrive->GetMediaByte()); + mem_writeb(Real2Phys(dos.tables.mediaid)+(drive-'A')*2,newdrive->GetMediaByte()); WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_2"),drive,newdrive->GetInfo()); /* check if volume label is given and don't allow it to updated in the future */ if (cmd->FindString("-label",label,true)) newdrive->dirCache.SetLabel(label.c_str(),false); + /* For hard drives set the label to DRIVELETTER_Drive. + * For floppy drives set the label to DRIVELETTER_Floppy. + * This way every drive except cdroms should get a label.*/ + else if(type == "dir") { + label = drive; label += "_DRIVE"; + newdrive->dirCache.SetLabel(label.c_str(),true); + } else if(type == "floppy") { + label = drive; label += "_FLOPPY"; + newdrive->dirCache.SetLabel(label.c_str(),true); + } return; showusage: WriteOut(MSG_Get("PROGRAM_MOUNT_USAGE")); @@ -207,9 +282,42 @@ public: void Run(void) { /* Show conventional Memory */ WriteOut("\n"); + + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + Bit8u umb_flag=dos_infoblock.GetUMBChainState(); + Bit8u old_memstrat=DOS_GetMemAllocStrategy()&0xff; + if (umb_start!=0xffff) { + if ((umb_flag&1)==1) DOS_LinkUMBsToMemChain(0); + DOS_SetMemAllocStrategy(0); + } + Bit16u seg,blocks;blocks=0xffff; DOS_AllocateMemory(&seg,&blocks); - WriteOut(MSG_Get("PROGRAM_MEM_CONVEN"),blocks*16/1024); + if ((machine==MCH_PCJR) && (real_readb(0x2000,0)==0x5a) && (real_readw(0x2000,1)==0) && (real_readw(0x2000,3)==0x7ffe)) { + WriteOut(MSG_Get("PROGRAM_MEM_CONVEN"),0x7ffe*16/1024); + } else WriteOut(MSG_Get("PROGRAM_MEM_CONVEN"),blocks*16/1024); + + if (umb_start!=0xffff) { + DOS_LinkUMBsToMemChain(1); + DOS_SetMemAllocStrategy(0x40); // search in UMBs only + + Bit16u largest_block=0,total_blocks=0,block_count=0; + for (;; block_count++) { + blocks=0xffff; + DOS_AllocateMemory(&seg,&blocks); + if (blocks==0) break; + total_blocks+=blocks; + if (blocks>largest_block) largest_block=blocks; + DOS_AllocateMemory(&seg,&blocks); + } + + Bit8u current_umb_flag=dos_infoblock.GetUMBChainState(); + if ((current_umb_flag&1)!=(umb_flag&1)) DOS_LinkUMBsToMemChain(umb_flag); + DOS_SetMemAllocStrategy(old_memstrat); // restore strategy + + if (block_count>0) WriteOut(MSG_Get("PROGRAM_MEM_UPPER"),total_blocks*16/1024,block_count,largest_block*16/1024); + } + /* Test for and show free XMS */ reg_ax=0x4300;CALLBACK_RunRealInt(0x2f); if (reg_al==0x80) { @@ -240,7 +348,6 @@ static void MEM_ProgramStart(Program * * make) { extern Bit32u floppytype; - class BOOT : public Program { private: FILE *getFSFile(Bit8u * filename, Bit32u *ksize, Bit32u *bsize) { @@ -282,9 +389,21 @@ private: WriteOut(MSG_Get("PROGRAM_BOOT_PRINT_ERROR")); } + void disable_umb_ems_xms(void) { + Section* dos_sec = control->GetSection("dos"); + dos_sec->ExecuteDestroy(false); + char test[20]; + strcpy(test,"umb=false"); + dos_sec->HandleInputline(test); + strcpy(test,"xms=false"); + dos_sec->HandleInputline(test); + strcpy(test,"ems=false"); + dos_sec->HandleInputline(test); + dos_sec->ExecuteInit(false); + } public: - + void Run(void) { FILE *usefile; Bitu i; @@ -299,7 +418,7 @@ public: drive = 'A'; while(iGetCount()) { if(cmd->FindCommand(i+1, temp_line)) { - if(temp_line == "-l") { + if((temp_line == "-l") || (temp_line == "-L")) { /* Specifying drive... next argument then is the drive */ i++; if(cmd->FindCommand(i+1, temp_line)) { @@ -341,39 +460,56 @@ public: return; } - WriteOut(MSG_Get("PROGRAM_BOOT_BOOT"),"Booting from drive %c...\n", drive); - bootSector bootarea; imageDiskList[drive-65]->Read_Sector(0,0,1,(Bit8u *)&bootarea); - for(i=0;i<512;i++) real_writeb(0, 0x7c00 + i, bootarea.rawdata[i]); + if ((bootarea.rawdata[0]==0x50) && (bootarea.rawdata[1]==0x43) && (bootarea.rawdata[2]==0x6a) && (bootarea.rawdata[3]==0x72)) { + if (machine!=MCH_PCJR) WriteOut(MSG_Get("PROGRAM_BOOT_CART_WO_PCJR")); + else { + disable_umb_ems_xms(); + Bit8u rombuf[65536]; + fseek(usefile,0x200L, SEEK_SET); + fread(rombuf, 1, rombytesize-0x200, usefile); + fclose(usefile); - + /* write cartridge data into ROM */ + Bit16u romseg=host_readw(&bootarea.rawdata[0x1ce]); + for(i=0;iFindCommand(commandNr++,temp_line)) { // get Filename char filename[128]; - strncpy(filename,temp_line.c_str(),128); + safe_strncpy(filename,temp_line.c_str(),128); // Setup commandline bool ok; char args[256]; @@ -470,12 +606,41 @@ static void RESCAN_ProgramStart(Program * * make) { class INTRO : public Program { public: + void DisplayMount(void) { + /* Basic mounting has a version for each operating system. + * This is done this way so both messages appear in the language file*/ + WriteOut(MSG_Get("PROGRAM_INTRO_MOUNT_START")); +#if (WIN32) + WriteOut(MSG_Get("PROGRAM_INTRO_MOUNT_WINDOWS")); +#else + WriteOut(MSG_Get("PROGRAM_INTRO_MOUNT_OTHER")); +#endif + WriteOut(MSG_Get("PROGRAM_INTRO_MOUNT_END")); + } + void Run(void) { if(cmd->FindExist("cdrom",false)) { - WriteOut(MSG_Get("PROGRAM_INTRO_CDROM")); + WriteOut(MSG_Get("PROGRAM_INTRO_CDROM")); return; } + if(cmd->FindExist("mount",false)) { + WriteOut("\033[2J");//Clear screen before printing + DisplayMount(); + return; + } + if(cmd->FindExist("special",false)) { + WriteOut(MSG_Get("PROGRAM_INTRO_SPECIAL")); + return; + } + /* Default action is to show all pages */ WriteOut(MSG_Get("PROGRAM_INTRO")); + Bit8u c;Bit16u n=1; + DOS_ReadFile (STDIN,&c,&n); + DisplayMount(); + DOS_ReadFile (STDIN,&c,&n); + WriteOut(MSG_Get("PROGRAM_INTRO_CDROM")); + DOS_ReadFile (STDIN,&c,&n); + WriteOut(MSG_Get("PROGRAM_INTRO_SPECIAL")); } }; @@ -497,16 +662,17 @@ public: std::string fstype="fat"; cmd->FindString("-t",type,true); cmd->FindString("-fs",fstype,true); + if(type == "cdrom") type = "iso"; //Tiny hack for people who like to type -t cdrom Bit8u mediaid; if (type=="floppy" || type=="hdd" || type=="iso") { Bit16u sizes[4]; std::string str_size; - mediaid=0xF8; + mediaid=0xF8; if (type=="floppy") { mediaid=0xF0; - } else if (type=="cdrom" || type=="iso") { + } else if (type=="iso") { str_size="650,127,16513,1700"; mediaid=0xF8; fstype = "iso"; @@ -531,8 +697,7 @@ public: if(fstype=="fat" || fstype=="iso") { // get the drive letter - cmd->FindCommand(1,temp_line); - if ((temp_line.size() > 2) || ((temp_line.size()>1) && (temp_line[1]!=':'))) { + if (!cmd->FindCommand(1,temp_line) || (temp_line.size() > 2) || ((temp_line.size()>1) && (temp_line[1]!=':'))) { WriteOut(MSG_Get("PROGRAM_IMGMOUNT_SPECIFY_DRIVE")); return; } @@ -570,10 +735,10 @@ public: // convert dosbox filename to system filename char fullname[CROSS_LEN]; char tmp[CROSS_LEN]; - strncpy(tmp, temp_line.c_str(), CROSS_LEN); + safe_strncpy(tmp, temp_line.c_str(), CROSS_LEN); Bit8u drive; - if (!DOS_MakeName(tmp, fullname, &drive)) { + if (!DOS_MakeName(tmp, fullname, &drive) || strncmp(Drives[drive]->GetInfo(),"local directory",15)) { WriteOut(MSG_Get("PROGRAM_IMGMOUNG_FILE_NOT_FOUND")); return; } @@ -597,6 +762,7 @@ public: newdrive=new fatDrive(temp_line.c_str(),sizes[0],sizes[1],sizes[2],sizes[3],0); } else if (fstype=="iso") { int error; + MSCDEX_SetCDInterface(CDROM_USE_SDL, -1); newdrive = new isoDrive(drive, temp_line.c_str(), mediaid, error); switch (error) { case 0 : WriteOut(MSG_Get("MSCDEX_SUCCESS")); break; @@ -619,7 +785,11 @@ public: newImage = new imageDisk(newDisk, (Bit8u *)temp_line.c_str(), imagesize, (imagesize > 2880)); if(imagesize>2880) newImage->Set_Geometry(sizes[2],sizes[3],sizes[1],sizes[0]); } + } else { + WriteOut(MSG_Get("PROGRAM_IMGMOUNT_TYPE_UNSUPPORTED"),type.c_str()); + return; } + if(fstype=="fat") { if (Drives[drive-'A']) { WriteOut(MSG_Get("PROGRAM_IMGMOUNT_ALLREADY_MOUNTED")); @@ -629,7 +799,7 @@ public: if (!newdrive) WriteOut(MSG_Get("PROGRAM_IMGMOUNT_CANT_CREATE")); Drives[drive-'A']=newdrive; // Set the correct media byte in the table - mem_writeb(Real2Phys(dos.tables.mediaid)+drive-'A',mediaid); + mem_writeb(Real2Phys(dos.tables.mediaid)+(drive-'A')*2,mediaid); WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_2"),drive,temp_line.c_str()); if(((fatDrive *)newdrive)->loadedDisk->hardDrive) { if(imageDiskList[2] == NULL) { @@ -655,7 +825,7 @@ public: if (!newdrive) WriteOut(MSG_Get("PROGRAM_IMGMOUNT_CANT_CREATE")); Drives[drive-'A']=newdrive; // Set the correct media byte in the table - mem_writeb(Real2Phys(dos.tables.mediaid)+drive-'A',mediaid); + mem_writeb(Real2Phys(dos.tables.mediaid)+(drive-'A')*2,mediaid); WriteOut(MSG_Get("PROGRAM_MOUNT_STATUS_2"),drive,temp_line.c_str()); } else if (fstype=="none") { if(imageDiskList[drive] != NULL) delete imageDiskList[drive]; @@ -690,10 +860,13 @@ void DOS_SetupPrograms(void) { MSG_Add("PROGRAM_MOUNT_UMOUNT_NOT_MOUNTED","Drive %c isn't mounted.\n"); MSG_Add("PROGRAM_MOUNT_UMOUNT_SUCCES","Drive %c has succesfully been removed.\n"); MSG_Add("PROGRAM_MOUNT_UMOUNT_NO_VIRTUAL","Virtual Drives can not be unMOUNTed.\n"); - + MSG_Add("PROGRAM_MOUNT_WARNING_WIN","\033[31;1mMounting c:\\ is NOT recommended. Please mount a (sub)directory next time.\033[0m\n"); + MSG_Add("PROGRAM_MOUNT_WARNING_OTHER","\033[31;1mMounting / is NOT recommended. Please mount a (sub)directory next time.\033[0m\n"); + MSG_Add("PROGRAM_MEM_CONVEN","%10d Kb free conventional memory\n"); MSG_Add("PROGRAM_MEM_EXTEND","%10d Kb free extended memory\n"); MSG_Add("PROGRAM_MEM_EXPAND","%10d Kb free expanded memory\n"); + MSG_Add("PROGRAM_MEM_UPPER","%10d Kb free upper memory in %d blocks (largest UMB %d Kb)\n"); MSG_Add("PROGRAM_LOADFIX_ALLOC","%d kb allocated.\n"); MSG_Add("PROGRAM_LOADFIX_DEALLOC","%d kb freed.\n"); @@ -711,27 +884,52 @@ void DOS_SetupPrograms(void) { MSG_Add("PROGRAM_RESCAN_SUCCESS","Drive cache cleared.\n"); MSG_Add("PROGRAM_INTRO", - "\033[2J\033[33;1mWelcome to DOSBox\033[0m, an x86 emulator with sound and graphics.\n" + "\033[2J\033[32;1mWelcome to DOSBox\033[0m, an x86 emulator with sound and graphics.\n" "DOSBox creates a shell for you which looks like old plain DOS.\n" - "\n" - "Here are some commands to get you started:\n" + "\n" + "For information about basic mount type \033[34;1mintro mount\033[0m\n" + "For information about CD-ROM support type \033[34;1mintro cdrom\033[0m\n" + "For information about special keys type \033[34;1mintro special\033[0m\n" + "For more information about DOSBox, go to \033[34;1mhttp://dosbox.sourceforge.net/wiki\033[0m\n" + "\n" + "\033[31;1mDOSBox will stop/exit without a warning if an error occured!\033[0m\n" + "\n" + "\n" + ); + MSG_Add("PROGRAM_INTRO_MOUNT_START", + "\033[32;1mHere are some commands to get you started:\033[0m\n" "Before you can use the files located on your own filesystem,\n" "You have to mount the directory containing the files.\n" - "For \033[1mWindows\033[0m:\n" - "\033[34;1mmount c c:\\dosprog\033[0m will create a C drive in DOSBox with c:\\dosprog as contents.\n" - "\n" - "For \033[1mother platforms\033[0m:\n" - "\033[34;1mmount c /home/user/dosprog\033[0m will do the same.\n" "\n" + ); + MSG_Add("PROGRAM_INTRO_MOUNT_WINDOWS", + "\033[44;1m\xC9\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBB\n" + "\xBA \033[32mmount c c:\\dosprog\\\033[37m will create a C drive with c:\\dosprog as contents. \xBA\n" + "\xBA \xBA\n" + "\xBA \033[32mc:\\dosprog\\\033[37m is an example. Replace it with your own games directory. \033[37m \xBA\n" + "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC\033[0m\n" + ); + MSG_Add("PROGRAM_INTRO_MOUNT_OTHER", + "\033[44;1m\xC9\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBB\n" + "\xBA \033[32mmount c ~/dosprog\033[37m will create a C drive with ~/dosprog as contents. \xBA\n" + "\xBA \xBA\n" + "\xBA \033[32m~/dosprog\033[37m is an example. Replace it with your own games directory. \033[37m \xBA\n" + "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC\033[0m\n" + ); + MSG_Add("PROGRAM_INTRO_MOUNT_END", "When the mount has succesfully completed you can type \033[34;1mc:\033[0m to go to your freshly\n" "mounted C-drive. Typing \033[34;1mdir\033[0m there will show its contents." " \033[34;1mcd\033[0m will allow you to\n" - "enter a directory (recognised by the \033[1m[]\033[0m in a directory listing).\n" + "enter a directory (recognised by the \033[33;1m[]\033[0m in a directory listing).\n" "You can run programs/files which end with \033[31m.exe .bat\033[0m and \033[31m.com\033[0m.\n" - "\n" - "For information about CD-ROM support type \033[34;1mintro cdrom\033[0m\n" - "\n" - "\033[32;1mDOSBox will stop/exit without a warning if an error occured!\033[0m\n" ); MSG_Add("PROGRAM_INTRO_CDROM", "\033[2J\033[32;1mHow to mount a Real/Virtual CD-ROM Drive in DOSBox:\033[0m\n" @@ -756,7 +954,29 @@ void DOS_SetupPrograms(void) { "\n" "Replace \033[0;31mD:\\\033[0m with the location of your CD-ROM.\n" "Replace the \033[33;1m0\033[0m in \033[34;1m-usecd \033[33m0\033[0m with the number reported for your CD-ROM if you type:\n" - "\033[34;1mmount -cd\033[0m" + "\033[34;1mmount -cd\033[0m\n" + ); + MSG_Add("PROGRAM_INTRO_SPECIAL", + "\033[2J\033[32;1mSpecial keys:\033[0m\n" + "These are the default keybindings.\n" + "They can be changed in the \033[33mkeymapper\033[0m.\n" + "\n" + "\033[33;1mALT-ENTER\033[0m : Go full screen and back.\n" + "\033[33;1mALT-PAUSE\033[0m : Pause DOSBox.\n" + "\033[33;1mCTRL-F1\033[0m : Start the \033[33mkeymapper\033[0m.\n" + "\033[33;1mCTRL-F4\033[0m : Update directory cache for all drives! Swap mounted disk-image.\n" + "\033[33;1mCTRL-ALT-F5\033[0m : Start/Stop creating a movie of the screen.\n" + "\033[33;1mCTRL-F5\033[0m : Save a screenshot.\n" + "\033[33;1mCTRL-F6\033[0m : Start/Stop recording sound output to a wave file.\n" + "\033[33;1mCTRL-ALT-F7\033[0m : Start/Stop recording of OPL commands.\n" + "\033[33;1mCTRL-ALT-F8\033[0m : Start/Stop the recording of raw MIDI commands.\n" + "\033[33;1mCTRL-F7\033[0m : Decrease frameskip.\n" + "\033[33;1mCTRL-F8\033[0m : Increase frameskip.\n" + "\033[33;1mCTRL-F9\033[0m : Kill DOSBox.\n" + "\033[33;1mCTRL-F10\033[0m : Capture/Release the mouse.\n" + "\033[33;1mCTRL-F11\033[0m : Slow down emulation (Decrease DOSBox Cycles).\n" + "\033[33;1mCTRL-F12\033[0m : Speed up emulation (Increase DOSBox Cycles).\n" + "\033[33;1mALT-F12\033[0m : Unlock speed (turbo button).\n" ); MSG_Add("PROGRAM_BOOT_NOT_EXIST","Bootdisk file does not exist. Failing.\n"); MSG_Add("PROGRAM_BOOT_NOT_OPEN","Cannot open bootdisk file. Failing.\n"); @@ -774,6 +994,7 @@ void DOS_SetupPrograms(void) { MSG_Add("PROGRAM_BOOT_IMAGE_OPEN","Opening image file: %s\n"); MSG_Add("PROGRAM_BOOT_IMAGE_NOT_OPEN","Cannot open %s"); MSG_Add("PROGRAM_BOOT_BOOT","Booting from drive %c...\n"); + MSG_Add("PROGRAM_BOOT_CART_WO_PCJR","PCJr cartridge found, but machine is not PCJr"); MSG_Add("PROGRAM_IMGMOUNT_SPECIFY_DRIVE","Must specify drive letter to mount image at.\n"); MSG_Add("PROGRAM_IMGMOUNT_SPECIFY2","Must specify drive number (0 or 3) to mount image at (0,1=fda,fdb;2,3=hda,hdb).\n"); @@ -782,6 +1003,7 @@ void DOS_SetupPrograms(void) { "\n" "For \033[33mhardrive\033[0m images: Must specify drive geometry for hard drives:\n" "bytes_per_sector, sectors_per_cylinder, heads_per_cylinder, cylinder_count.\n"); + MSG_Add("PROGRAM_IMGMOUNT_TYPE_UNSUPPORTED","Type \"%s\" is unsupported. Specify \"hdd\" or \"floppy\" or\"iso\".\n"); MSG_Add("PROGRAM_IMGMOUNT_FORMAT_UNSUPPORTED","Format \"%s\" is unsupported. Specify \"fat\" or \"iso\" or \"none\".\n"); MSG_Add("PROGRAM_IMGMOUNT_SPECIFY_FILE","Must specify file-image to mount.\n"); MSG_Add("PROGRAM_IMGMOUNG_FILE_NOT_FOUND","Image file not found.\n"); diff --git a/src/dos/dos_tables.cpp b/src/dos/dos_tables.cpp index 52c7c3c..9145d42 100644 --- a/src/dos/dos_tables.cpp +++ b/src/dos/dos_tables.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dos_tables.cpp,v 1.17 2004/11/16 14:28:16 qbix79 Exp $ */ +/* $Id: dos_tables.cpp,v 1.22 2006/02/09 11:47:48 qbix79 Exp $ */ #include "dosbox.h" #include "mem.h" @@ -41,7 +41,6 @@ RealPt DOS_TableLowCase; static Bitu call_casemap; static Bit16u dos_memseg; -Bit16u sdaseg; Bit16u DOS_GetMemory(Bit16u pages) { if (pages+dos_memseg>=0xe000) { @@ -76,25 +75,24 @@ static Bit8u country_info[0x22] = { void DOS_SetupTables(void) { dos_memseg=0xd000; Bit16u seg,seg2;Bitu i; - dos.tables.mediaid=RealMake(DOS_GetMemory(2),0); + dos.tables.mediaid=RealMake(DOS_GetMemory(4),0); dos.tables.tempdta=RealMake(DOS_GetMemory(4),0); dos.tables.tempdta_fcbdelete=RealMake(DOS_GetMemory(4),0); - for (i=0;i20 detection routine */ /* Possibly obselete when SFT is properly handled */ - real_writed(0x5d,0x0a,0x204e4f43); - real_writed(0x5d,0x1a,0x204e4f43); - real_writed(0x5d,0x2a,0x204e4f43); + real_writed(DOS_CONSTRING_SEG,0x0a,0x204e4f43); + real_writed(DOS_CONSTRING_SEG,0x1a,0x204e4f43); + real_writed(DOS_CONSTRING_SEG,0x2a,0x204e4f43); /* create a CON device driver */ - seg=0x60; + seg=DOS_CONDRV_SEG; real_writed(seg,0x00,0xffffffff); // next ptr real_writew(seg,0x04,0x8013); // attributes real_writed(seg,0x06,0xffffffff); // strategy routine @@ -102,17 +100,8 @@ void DOS_SetupTables(void) { real_writed(seg,0x0e,0x20202020); // driver name dos_infoblock.SetDeviceChainStart(RealMake(seg,0)); - /* Create a fake SFT, so programs think there are 100 file handles */ - seg=0x62; - seg2=0x63; - real_writed(seg,0,seg2<<16); //Next File Table - real_writew(seg,4,100); //File Table supports 100 files - real_writed(seg2,0,0xffffffff); //Last File Table - real_writew(seg2,4,100); //File Table supports 100 files - dos_infoblock.SetfirstFileTable(RealMake(seg,0)); - - /* Create a fake CDS */ - seg=0x64; + /* Create a fake Current Directory Structure */ + seg=DOS_CDS_SEG; real_writed(seg,0x00,0x005c3a43); dos_infoblock.SetCurDirStruct(RealMake(seg,0)); @@ -128,13 +117,15 @@ void DOS_SetupTables(void) { real_writew(seg,4,100); //File Table supports 100 files dos_infoblock.SetFCBTable(RealMake(seg,0)); - /* Create a fake disk info buffer */ + /* Create a fake disk buffer head */ seg=DOS_GetMemory(6); - seg2=DOS_GetMemory(6); - real_writed(seg,0x00,seg2<<16); - real_writed(seg2,0x00,0xffffffff); - real_writed(seg2,0x0d,0xffffffff); - dos_infoblock.SetDiskInfoBuffer(RealMake(seg,0)); + for (Bitu ct=0; ct<0x20; ct++) real_writeb(seg,ct,0); + real_writew(seg,0x00,0xffff); // forward ptr + real_writew(seg,0x02,0xffff); // backward ptr + real_writeb(seg,0x04,0xff); // not in use + real_writeb(seg,0x0a,0x01); // number of FATs + real_writed(seg,0x0d,0xffffffff); // pointer to DPB + dos_infoblock.SetDiskBufferHeadPt(RealMake(seg,0)); /* Set buffers to a nice value */ dos_infoblock.SetBuffers(50,50); diff --git a/src/dos/drive_cache.cpp b/src/dos/drive_cache.cpp index f4c5d84..25e64ab 100644 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -1,6 +1,6 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: drive_cache.cpp,v 1.40 2004/11/13 12:08:43 qbix79 Exp $ */ +/* $Id: drive_cache.cpp,v 1.46 2006/02/09 11:47:48 qbix79 Exp $ */ #include "drives.h" #include "dos_inc.h" @@ -34,6 +34,12 @@ #include #endif +#if defined (OS2) +#define INCL_DOSERRORS +#define INCL_DOSFILEMGR +#include +#endif + int fileInfoCounter = 0; bool SortByName(DOS_Drive_Cache::CFileInfo* const &a, DOS_Drive_Cache::CFileInfo* const &b) @@ -155,11 +161,21 @@ void DOS_Drive_Cache::SetBaseDir(const char* baseDir) ReadDir(id,result); }; // Get Volume Label -#if defined (WIN32) +#if defined (WIN32) || defined (OS2) char labellocal[256]={ 0 }; char drive[4] = "C:\\"; drive[0] = basePath[0]; +#if defined (WIN32) if (GetVolumeInformation(drive,labellocal,256,NULL,NULL,NULL,NULL,0)) { +#else // OS2 + FSINFO fsinfo; + ULONG drivenumber = drive[0]; + if (drivenumber > 26) { // drive letter was lowercase + drivenumber = drive[0] - 'a' + 1; + } + APIRET rc = DosQueryFSInfo(drivenumber, FSIL_VOLSER, &fsinfo, sizeof(FSINFO)); + if (rc == NO_ERROR) { +#endif /* Set label and allow being updated */ SetLabel(labellocal,true); } @@ -262,8 +278,7 @@ void DOS_Drive_Cache::CacheOut(const char* path, bool ignoreLastDir) char tmp[CROSS_LEN] = { 0 }; Bit32s len = strrchr(path,CROSS_FILESPLIT) - path; if (len>0) { - strncpy(tmp,path,len); - tmp[len] = 0; + safe_strncpy(tmp,path,len+1); } else { strcpy(tmp,path); } @@ -315,9 +330,10 @@ bool DOS_Drive_Cache::GetShortName(const char* fullname, char* shortname) int DOS_Drive_Cache::CompareShortname(const char* compareName, const char* shortName) { - char* cpos = strchr(shortName,'~'); + char const* cpos = strchr(shortName,'~'); if (cpos) { - Bits compareCount1 = (int)cpos - (int)shortName; +/* the following code is replaced as it's not safe when char* is 64 bits */ +/* Bits compareCount1 = (int)cpos - (int)shortName; char* endPos = strchr(cpos,'.'); Bitu numberSize = endPos ? int(endPos)-int(cpos) : strlen(cpos); @@ -327,6 +343,18 @@ int DOS_Drive_Cache::CompareShortname(const char* compareName, const char* short compareCount2 -= numberSize; if (compareCount2>compareCount1) compareCount1 = compareCount2; +*/ + size_t compareCount1 = strcspn(shortName,"~"); + size_t numberSize = strcspn(cpos,"."); + size_t compareCount2 = strcspn(compareName,"."); + if(compareCount2 > 8) compareCount2 = 8; + /* We want + * compareCount2 -= numberSize; + * if (compareCount2>compareCount1) compareCount1 = compareCount2; + * but to prevent negative numbers: + */ + if(compareCount2 > compareCount1 + numberSize) + compareCount1 = compareCount2 - numberSize; return strncmp(compareName,shortName,compareCount1); } return strcmp(compareName,shortName); @@ -450,11 +478,10 @@ void DOS_Drive_Cache::CreateShortName(CFileInfo* curDir, CFileInfo* info) info->shortNr = CreateShortNameID(curDir,tmpName); sprintf(buffer,"%d",info->shortNr); // Copy first letters - Bit16u tocopy; + Bit16u tocopy = 0; if (len+strlen(buffer)+1>8) tocopy = 8 - strlen(buffer) - 1; else tocopy = len; - strncpy(info->shortname,tmpName,tocopy); - info->shortname[tocopy] = 0; + safe_strncpy(info->shortname,tmpName,tocopy+1); // Copy number strcat(info->shortname,"~"); strcat(info->shortname,buffer); @@ -514,7 +541,7 @@ DOS_Drive_Cache::CFileInfo* DOS_Drive_Cache::FindDirInfo(const char* path, char* do { // bool errorcheck = false; pos = strchr(start,CROSS_FILESPLIT); - if (pos) { strncpy(dir,start,pos-start); dir[pos-start] = 0; /*errorcheck = true;*/ } + if (pos) { safe_strncpy(dir,start,pos-start+1); /*errorcheck = true;*/ } else { strcpy(dir,start); }; // Path found diff --git a/src/dos/drive_fat.cpp b/src/dos/drive_fat.cpp index 573d6a0..4a6ea24 100644 --- a/src/dos/drive_fat.cpp +++ b/src/dos/drive_fat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: drive_fat.cpp,v 1.6 2004/11/03 23:13:54 qbix79 Exp $ */ +/* $Id: drive_fat.cpp,v 1.12 2006/02/20 08:59:52 qbix79 Exp $ */ #include #include @@ -37,6 +37,9 @@ #define FAT16 1 #define FAT32 2 +Bit8u fatSectBuffer[1024]; +Bit32u curFatSect; + class fatFile : public DOS_File { public: fatFile(const char* name, Bit32u startCluster, Bit32u fileLen, fatDrive *useDrive); @@ -82,9 +85,6 @@ static void convToDirFile(char *filename, char *filearray) { charidx = 8; } } - - - } fatFile::fatFile(const char* name, Bit32u startCluster, Bit32u fileLen, fatDrive *useDrive) { @@ -125,13 +125,13 @@ bool fatFile::Read(Bit8u * data, Bit16u *size) { currentSector = myDrive->getAbsoluteSectFromBytePos(firstCluster, seekpos); if(currentSector == 0) { /* EOC reached before EOF */ - LOG_MSG("EOC reached before EOF, seekpos %d, filelen %d", seekpos, filelength); + //LOG_MSG("EOC reached before EOF, seekpos %d, filelen %d", seekpos, filelength); *size = sizecount; return true; } curSectOff = 0; myDrive->loadedDisk->Read_AbsoluteSector(currentSector, sectorBuffer); - LOG_MSG("Reading absolute sector at %d for seekpos %d", currentSector, seekpos); + //LOG_MSG("Reading absolute sector at %d for seekpos %d", currentSector, seekpos); } --sizedec; sizecount++; @@ -147,12 +147,16 @@ bool fatFile::Write(Bit8u * data, Bit16u *size) { Bit16u sizedec, sizecount; sizedec = *size; sizecount = 0; + while(sizedec != 0) { /* Increase filesize if necessary */ if(seekpos >= filelength) { if(filelength == 0) { firstCluster = myDrive->getFirstFreeClust(); myDrive->allocateCluster(firstCluster, 0); + currentSector = myDrive->getAbsoluteSectFromBytePos(firstCluster, seekpos); + myDrive->loadedDisk->Read_AbsoluteSector(currentSector, sectorBuffer); + loadedSector = true; } filelength = seekpos+1; } @@ -191,7 +195,6 @@ finalizeWrite: *size =sizecount; return true; - } bool fatFile::Seek(Bit32u *pos, Bit32u type) { @@ -244,13 +247,8 @@ Bit32u fatDrive::getClusterValue(Bit32u clustNum) { Bit32u fatoffset; Bit32u fatsectnum; Bit32u fatentoff; - Bit32u clustValue; - - /* Load two sectors at once for FAT12 */ - Bit8u sectbuffer[1024]; - switch(fattype) { case FAT12: fatoffset = clustNum + (clustNum / 2); @@ -265,12 +263,16 @@ Bit32u fatDrive::getClusterValue(Bit32u clustNum) { fatsectnum = bootbuffer.reservedsectors + (fatoffset / bootbuffer.bytespersector) + partSectOff; fatentoff = fatoffset % bootbuffer.bytespersector; - loadedDisk->Read_AbsoluteSector(fatsectnum, §buffer[0]); - loadedDisk->Read_AbsoluteSector(fatsectnum+1, §buffer[512]); + if(curFatSect != fatsectnum) { + /* Load two sectors at once for FAT12 */ + loadedDisk->Read_AbsoluteSector(fatsectnum, &fatSectBuffer[0]); + loadedDisk->Read_AbsoluteSector(fatsectnum+1, &fatSectBuffer[512]); + curFatSect = fatsectnum; + } switch(fattype) { case FAT12: - clustValue = *((Bit16u *)§buffer[fatentoff]); + clustValue = *((Bit16u *)&fatSectBuffer[fatentoff]); if(clustNum & 0x1) { clustValue >>= 4; } else { @@ -278,10 +280,10 @@ Bit32u fatDrive::getClusterValue(Bit32u clustNum) { } break; case FAT16: - clustValue = *((Bit16u *)§buffer[fatentoff]); + clustValue = *((Bit16u *)&fatSectBuffer[fatentoff]); break; case FAT32: - clustValue = *((Bit32u *)§buffer[fatentoff]); + clustValue = *((Bit32u *)&fatSectBuffer[fatentoff]); break; } @@ -294,10 +296,6 @@ void fatDrive::setClusterValue(Bit32u clustNum, Bit32u clustValue) { Bit32u fatentoff; Bit32u tmpValue; - - /* Load two sectors at once for FAT12 */ - Bit8u sectbuffer[1024]; - switch(fattype) { case FAT12: fatoffset = clustNum + (clustNum / 2); @@ -312,12 +310,16 @@ void fatDrive::setClusterValue(Bit32u clustNum, Bit32u clustValue) { fatsectnum = bootbuffer.reservedsectors + (fatoffset / bootbuffer.bytespersector) + partSectOff; fatentoff = fatoffset % bootbuffer.bytespersector; - loadedDisk->Read_AbsoluteSector(fatsectnum, §buffer[0]); - loadedDisk->Read_AbsoluteSector(fatsectnum+1, §buffer[512]); + if(curFatSect != fatsectnum) { + /* Load two sectors at once for FAT12 */ + loadedDisk->Read_AbsoluteSector(fatsectnum, &fatSectBuffer[0]); + loadedDisk->Read_AbsoluteSector(fatsectnum+1, &fatSectBuffer[512]); + curFatSect = fatsectnum; + } switch(fattype) { case FAT12: - tmpValue = *((Bit16u *)§buffer[fatentoff]); + tmpValue = *((Bit16u *)&fatSectBuffer[fatentoff]); if(clustNum & 0x1) { clustValue &= 0xfff; clustValue <<= 4; @@ -329,19 +331,19 @@ void fatDrive::setClusterValue(Bit32u clustNum, Bit32u clustValue) { tmpValue &= 0xf000; tmpValue |= clustValue; } - *((Bit16u *)§buffer[fatentoff]) = tmpValue; + *((Bit16u *)&fatSectBuffer[fatentoff]) = tmpValue; break; case FAT16: - *((Bit16u *)§buffer[fatentoff]) = clustValue; + *((Bit16u *)&fatSectBuffer[fatentoff]) = clustValue; break; case FAT32: - *((Bit32u *)§buffer[fatentoff]) = clustValue; + *((Bit32u *)&fatSectBuffer[fatentoff]) = clustValue; break; } int fc; for(fc=0;fcWrite_AbsoluteSector(fatsectnum + (fc * bootbuffer.sectorsperfat), §buffer[0]); - loadedDisk->Write_AbsoluteSector(fatsectnum+1+(fc * bootbuffer.sectorsperfat), §buffer[512]); + loadedDisk->Write_AbsoluteSector(fatsectnum + (fc * bootbuffer.sectorsperfat), &fatSectBuffer[0]); + loadedDisk->Write_AbsoluteSector(fatsectnum+1+(fc * bootbuffer.sectorsperfat), &fatSectBuffer[512]); } } @@ -355,7 +357,7 @@ bool fatDrive::getEntryName(char *fullname, char *entname) { char * findFile; strcpy(dirtoken,fullname); - LOG_MSG("Testing for filename %s", fullname); + //LOG_MSG("Testing for filename %s", fullname); findDir = strtok(dirtoken,"\\"); findFile = findDir; while(findDir != NULL) { @@ -378,7 +380,7 @@ bool fatDrive::getFileDirEntry(char * filename, direntry * useEntry, Bit32u * di /* Skip if testing in root directory */ if ((len>0) && (filename[len-1]!='\\')) { - LOG_MSG("Testing for filename %s", filename); + //LOG_MSG("Testing for filename %s", filename); findDir = strtok(dirtoken,"\\"); findFile = findDir; while(findDir != NULL) { @@ -387,6 +389,13 @@ bool fatDrive::getFileDirEntry(char * filename, direntry * useEntry, Bit32u * di findFile = findDir; if(!FindNextInternal(currentClust, *imgDTA, &foundEntry)) break; + else { + //Found something. See if it's a directory (findfirst always finds regular files) + char find_name[DOS_NAMELENGTH_ASCII];Bit16u find_date,find_time;Bit32u find_size;Bit8u find_attr; + imgDTA->GetResult(find_name,find_size,find_date,find_time,find_attr); + if(!(find_attr & DOS_ATTR_DIRECTORY)) break; + } + currentClust = foundEntry.loFirstClust; findDir = strtok(NULL,"\\"); } @@ -398,13 +407,10 @@ bool fatDrive::getFileDirEntry(char * filename, direntry * useEntry, Bit32u * di imgDTA->SetupSearch(0,0x5,findFile); imgDTA->SetDirID(0); if(!FindNextInternal(currentClust, *imgDTA, &foundEntry)) return false; - + memcpy(useEntry, &foundEntry, sizeof(direntry)); *dirClust = (Bit32u)currentClust; *subEntry = ((Bit32u)imgDTA->GetDirID()-1); - - - return true; } @@ -418,20 +424,23 @@ bool fatDrive::getDirClustNum(char *dir, Bit32u *clustNum, bool parDir) { /* Skip if testing for root directory */ if ((len>0) && (dir[len-1]!='\\')) { - LOG_MSG("Testing for dir %s", dir); + //LOG_MSG("Testing for dir %s", dir); findDir = strtok(dirtoken,"\\"); while(findDir != NULL) { imgDTA->SetupSearch(0,DOS_ATTR_DIRECTORY,findDir); imgDTA->SetDirID(0); findDir = strtok(NULL,"\\"); - if(!parDir) { - if(!FindNextInternal(currentClust, *imgDTA, &foundEntry)) return false; + if(parDir && (findDir == NULL)) break; + + char find_name[DOS_NAMELENGTH_ASCII];Bit16u find_date,find_time;Bit32u find_size;Bit8u find_attr; + if(!FindNextInternal(currentClust, *imgDTA, &foundEntry)) { + return false; } else { - if(findDir == NULL) break; - if(!FindNextInternal(currentClust, *imgDTA, &foundEntry)) return false; + imgDTA->GetResult(find_name,find_size,find_date,find_time,find_attr); + if(!(find_attr &DOS_ATTR_DIRECTORY)) return false; } currentClust = foundEntry.loFirstClust; - + } *clustNum = currentClust; return true; @@ -441,7 +450,6 @@ bool fatDrive::getDirClustNum(char *dir, Bit32u *clustNum, bool parDir) { return true; } return false; - } Bit32u fatDrive::getSectorSize(void) { @@ -449,7 +457,7 @@ Bit32u fatDrive::getSectorSize(void) { } Bit32u fatDrive::getAbsoluteSectFromBytePos(Bit32u startClustNum, Bit32u bytePos) { - return getAbsoluteSectFromChain(startClustNum, bytePos / bootbuffer.bytespersector); + return getAbsoluteSectFromChain(startClustNum, bytePos / bootbuffer.bytespersector); } Bit32u fatDrive::getAbsoluteSectFromChain(Bit32u startClustNum, Bit32u logicalSector) { @@ -473,13 +481,14 @@ Bit32u fatDrive::getAbsoluteSectFromChain(Bit32u startClustNum, Bit32u logicalSe if(testvalue >= 0xfffffff8) isEOF = true; break; } - if((isEOF) && (skipClust>1)) { + if((isEOF) && (skipClust>=1)) { //LOG_MSG("End of cluster chain reached before end of logical sector seek!"); return 0; } currentClust = testvalue; --skipClust; } + return (getClustFirstSect(currentClust) + sectClust); } @@ -542,10 +551,6 @@ Bit32u fatDrive::appendCluster(Bit32u startCluster) { zeroOutCluster(newClust); return newClust; - - - - } bool fatDrive::allocateCluster(Bit32u useCluster, Bit32u prevCluster) { @@ -559,6 +564,7 @@ bool fatDrive::allocateCluster(Bit32u useCluster, Bit32u prevCluster) { /* Point cluster to new cluster in chain */ setClusterValue(prevCluster, useCluster); + //LOG_MSG("Chaining cluser %d to %d", prevCluster, useCluster); } switch(fattype) { @@ -573,7 +579,6 @@ bool fatDrive::allocateCluster(Bit32u useCluster, Bit32u prevCluster) { break; } return true; - } fatDrive::fatDrive(const char *sysFilename, Bit32u bytesector, Bit32u cylsector, Bit32u headscyl, Bit32u cylinders, Bit32u startSector) { @@ -667,9 +672,8 @@ fatDrive::fatDrive(const char *sysFilename, Bit32u bytesector, Bit32u cylsector, /* There is no cluster 0, this means we are in the root directory */ cwdDirCluster = 0; - - - + memset(fatSectBuffer,0,1024); + curFatSect = 0xffffffff; } bool fatDrive::AllocationInfo(Bit16u *_bytes_sector, Bit8u *_sectors_cluster, Bit16u *_total_clusters, Bit16u *_free_clusters) { @@ -695,10 +699,9 @@ Bit32u fatDrive::getFirstFreeClust(void) { /* No free cluster found */ return 0; - } -bool fatDrive::isRemote(void) { return false; } +bool fatDrive::isRemote(void) { return false; } bool fatDrive::isRemovable(void) { return false; } Bit8u fatDrive::GetMediaByte(void) { return loadedDisk->GetBiosType(); } @@ -710,21 +713,25 @@ bool fatDrive::FileCreate(DOS_File **file, char *name, Bit16u attributes) { char pathName[11]; /* Check if file already exists */ - if(getFileDirEntry(name, &fileEntry, &dirClust, &subEntry)) return false; + if(getFileDirEntry(name, &fileEntry, &dirClust, &subEntry)) { + /* Truncate file */ + fileEntry.entrysize=0; + directoryChange(dirClust, &fileEntry, subEntry); + } else { + /* Can we even get the name of the file itself? */ + if(!getEntryName(name, &dirName[0])) return false; + convToDirFile(&dirName[0], &pathName[0]); - /* Can we even get the name of the file itself? */ - if(!getEntryName(name, &dirName[0])) return false; - convToDirFile(&dirName[0], &pathName[0]); + /* Can we find the base directory? */ + if(!getDirClustNum(name, &dirClust, true)) return false; + memset(&fileEntry, 0, sizeof(direntry)); + memcpy(&fileEntry.entryname, &pathName[0], 11); + fileEntry.attrib = attributes; + addDirectoryEntry(dirClust, fileEntry); - /* Can we find the base directory? */ - if(!getDirClustNum(name, &dirClust, true)) return false; - memset(&fileEntry, 0, sizeof(direntry)); - memcpy(&fileEntry.entryname, &pathName[0], 11); - fileEntry.attrib = attributes; - addDirectoryEntry(dirClust, fileEntry); - - /* Check if file exists now */ - if(!getFileDirEntry(name, &fileEntry, &dirClust, &subEntry)) return false; + /* Check if file exists now */ + if(!getFileDirEntry(name, &fileEntry, &dirClust, &subEntry)) return false; + } /* Empty file created, now lets open it */ /* TODO: check for read-only flag and requested write access */ @@ -777,9 +784,20 @@ bool fatDrive::FindFirst(char *_dir, DOS_DTA &dta,bool fcb_findfirst) { direntry dummyClust; Bit8u attr;char pattern[DOS_NAMELENGTH_ASCII]; dta.GetSearchParams(attr,pattern); + if(attr==DOS_ATTR_VOLUME) { + if (strcmp(GetLabel(), "") == 0 ) { + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; + } + dta.SetResult(GetLabel(),0,0,0,DOS_ATTR_VOLUME); + return true; + } if(attr & DOS_ATTR_VOLUME) //check for root dir or fcb_findfirst LOG(LOG_DOSMISC,LOG_WARN)("findfirst for volumelabel used on fatDrive. Unhandled!!!!!"); - if(!getDirClustNum(_dir, &cwdDirCluster, false)) return false; + if(!getDirClustNum(_dir, &cwdDirCluster, false)) { + DOS_SetError(DOSERR_PATH_NOT_FOUND); + return false; + } dta.SetDirID(0); return FindNextInternal(cwdDirCluster, dta, &dummyClust); } @@ -828,7 +846,10 @@ nextfile: } else { tmpsector = getAbsoluteSectFromChain(dirClustNumber, logentsector); /* A zero sector number can't happen */ - if(tmpsector == 0) return false; + if(tmpsector == 0) { + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; + } loadedDisk->Read_AbsoluteSector(tmpsector,sectbuf); } dirPos++; @@ -838,7 +859,10 @@ nextfile: if (sectbuf[entryoffset].entryname[0] == 0xe5) goto nextfile; /* End of directory list */ - if (sectbuf[entryoffset].entryname[0] == 0x00) return false; + if (sectbuf[entryoffset].entryname[0] == 0x00) { + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; + } memset(find_name,0,DOS_NAMELENGTH_ASCII); memset(extension,0,4); @@ -851,14 +875,17 @@ nextfile: strcat(find_name, extension); } - if((attrs & (sectbuf[entryoffset].attrib | 0x21)) == 0) goto nextfile; + /* Ignore files with volume label. FindFirst should search for those. (return the first one found) */ + if(sectbuf[entryoffset].attrib & 0x8) goto nextfile; + + /* Always find ARCHIVES even if bit is not set Perhaps test is not the best test */ + if(~attrs & sectbuf[entryoffset].attrib & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM) ) goto nextfile; if(!WildFileCmp(find_name,srch_pattern)) goto nextfile; dta.SetResult(find_name, sectbuf[entryoffset].entrysize, sectbuf[entryoffset].crtDate, sectbuf[entryoffset].crtTime, sectbuf[entryoffset].attrib); memcpy(foundEntry, §buf[entryoffset], sizeof(direntry)); return true; - } bool fatDrive::FindNext(DOS_DTA &dta) { @@ -868,8 +895,31 @@ bool fatDrive::FindNext(DOS_DTA &dta) { } bool fatDrive::GetFileAttr(char *name, Bit16u *attr) { - /* TODO: Stub */ - return false; + direntry fileEntry; + Bit32u dirClust, subEntry; + if(!getFileDirEntry(name, &fileEntry, &dirClust, &subEntry)) { + char dirName[DOS_NAMELENGTH_ASCII]; + char pathName[11]; + + /* Can we even get the name of the directory itself? */ + if(!getEntryName(name, &dirName[0])) return false; + convToDirFile(&dirName[0], &pathName[0]); + + /* Get parent directory starting cluster */ + if(!getDirClustNum(name, &dirClust, true)) return false; + + /* Find directory entry in parent directory */ + Bit32s fileidx = 2; + while(directoryBrowse(dirClust, &fileEntry, fileidx)) { + if(memcmp(&fileEntry.entryname, &pathName[0], 11) == 0) { + *attr=fileEntry.attrib; + return true; + } + fileidx++; + } + return false; + } else *attr=fileEntry.attrib; + return true; } bool fatDrive::directoryBrowse(Bit32u dirClustNumber, direntry *useEntry, Bit32s entNum) { @@ -995,7 +1045,6 @@ bool fatDrive::addDirectoryEntry(Bit32u dirClustNumber, direntry useEntry) { } } - return false; } @@ -1008,7 +1057,6 @@ void fatDrive::zeroOutCluster(Bit32u clustNumber) { for(i=0;iWrite_AbsoluteSector(getAbsoluteSectFromChain(clustNumber,i), &secBuffer[0]); } - } bool fatDrive::MakeDir(char *dir) { @@ -1061,7 +1109,6 @@ bool fatDrive::MakeDir(char *dir) { addDirectoryEntry(dummyClust, tmpentry); return true; - } bool fatDrive::RemoveDir(char *dir) { @@ -1117,7 +1164,6 @@ bool fatDrive::RemoveDir(char *dir) { } bool fatDrive::Rename(char *oldname, char*newname) { - return false; } diff --git a/src/dos/drive_iso.cpp b/src/dos/drive_iso.cpp index 7a7b0eb..db81455 100644 --- a/src/dos/drive_iso.cpp +++ b/src/dos/drive_iso.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,13 +16,14 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: drive_iso.cpp,v 1.4 2004/11/03 23:13:55 qbix79 Exp $ */ +/* $Id: drive_iso.cpp,v 1.12 2006/02/12 13:32:30 qbix79 Exp $ */ #include #include #include "cdrom.h" #include "dosbox.h" #include "dos_system.h" +#include "support.h" #include "drives.h" using namespace std; @@ -57,7 +58,7 @@ isoFile::isoFile(isoDrive *drive, const char *name, FileStat_Block *stat, Bit32u fileEnd = fileBegin + size; cachedSector = -1; open = true; - info = info; + this->info = info; this->name = NULL; SetName(name); } @@ -144,13 +145,16 @@ bool MSCDEX_GetVolumeName(Bit8u subUnit, char* name); isoDrive::isoDrive(char driveLetter, const char *fileName, Bit8u mediaid, int &error) { + nextFreeDirIterator = 0; + memset(dirIterators, 0, sizeof(dirIterators)); + memset(sectorHashEntries, 0, sizeof(sectorHashEntries)); + memset(&rootEntry, 0, sizeof(isoDirEntry)); + error = MSCDEX_AddDrive(driveLetter, fileName, subUnit); if (!error) { if (loadImage()) { strcpy(info, "isoDrive"); - searchCache.clear(); - dirIter = searchCache.end(); this->mediaid = mediaid; char buffer[32] = { 0 }; if (!MSCDEX_GetVolumeName(subUnit, buffer)) strcpy(buffer, ""); @@ -241,34 +245,29 @@ bool isoDrive::FindFirst(char *dir, DOS_DTA &dta, bool fcb_findfirst) return false; } - Bit32u sectorStart = EXTENT_LOCATION(de); - Bit32u sectorEnd = sectorStart + DATA_LENGTH(de) / ISO_FRAMESIZE; - if (DATA_LENGTH(de) % ISO_FRAMESIZE != 0) sectorEnd++; - searchCache.clear(); - - for(Bit32u sector = sectorStart; sector < sectorEnd; sector++) { - Bit8u block[ISO_FRAMESIZE]; - readSector(block, sector); - - Bit32u pos = 0; - while (pos < ISO_FRAMESIZE && block[pos] != 0 && (pos + block[pos]) <= ISO_FRAMESIZE) { - isoDirEntry tmp; - int length = readDirEntry(&tmp, &block[pos]); - if (length < 0) return false; - searchCache.push_back(tmp); - pos += length; - } - } - dirIter = searchCache.begin(); + // get a directory iterator and save its id in the dta + dta.SetDirID(GetDirIterator(&de)); Bit8u attr; char pattern[ISO_MAXPATHNAME]; dta.GetSearchParams(attr, pattern); - if ((attr & DOS_ATTR_VOLUME) && ((*dir == 0) || fcb_findfirst)) { - // Get Volume Label (DOS_ATTR_VOLUME) and only in basedir - dta.SetResult(discLabel, 0, 0, 0, DOS_ATTR_VOLUME); - return true; + + if (attr == DOS_ATTR_VOLUME) { + if (strlen(discLabel) != 0) { + dta.SetResult(discLabel, 0, 0, 0, DOS_ATTR_VOLUME); + return true; + } else { + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; + } + } else if ((attr & DOS_ATTR_VOLUME) && (*dir == 0) && !fcb_findfirst) { + if (WildFileCmp(discLabel,pattern)) { + // Get Volume Label (DOS_ATTR_VOLUME) and only in basedir and if it matches the searchstring + dta.SetResult(discLabel, 0, 0, 0, DOS_ATTR_VOLUME); + return true; + } } + return FindNext(dta); } @@ -278,17 +277,21 @@ bool isoDrive::FindNext(DOS_DTA &dta) char pattern[DOS_NAMELENGTH_ASCII]; dta.GetSearchParams(attr, pattern); - while (dirIter != searchCache.end()) { - isoDirEntry &de = *dirIter; - Bit8u findAttr; - if (IS_DIR(de.fileFlags)) findAttr = DOS_ATTR_DIRECTORY; - else findAttr = DOS_ATTR_ARCHIVE; - + int dirIterator = dta.GetDirID(); + + isoDirEntry de; + while (GetNextDirEntry(dirIterator, &de)) { + Bit8u findAttr = 0; + if (IS_DIR(de.fileFlags)) findAttr |= DOS_ATTR_DIRECTORY; + else findAttr |= DOS_ATTR_ARCHIVE; + if (IS_HIDDEN(de.fileFlags)) findAttr |= DOS_ATTR_HIDDEN; + if (WildFileCmp((char*)de.ident, pattern) && !(~attr & findAttr & (DOS_ATTR_DIRECTORY | DOS_ATTR_HIDDEN | DOS_ATTR_SYSTEM))) { /* file is okay, setup everything to be copied in DTA Block */ char findName[DOS_NAMELENGTH_ASCII]; + findName[0] = 0; if(strlen((char*)de.ident) < DOS_NAMELENGTH_ASCII) { strcpy(findName, (char*)de.ident); upcase(findName); @@ -297,12 +300,11 @@ bool isoDrive::FindNext(DOS_DTA &dta) Bit16u findDate = DOS_PackDate(1900 + de.dateYear, de.dateMonth, de.dateDay); Bit16u findTime = DOS_PackTime(de.timeHour, de.timeMin, de.timeSec); dta.SetResult(findName, findSize, findDate, findTime, findAttr); - - dirIter++; return true; } - dirIter++; } + // after searching the directory, free the iterator + FreeDirIterator(dirIterator); DOS_SetError(DOSERR_NO_MORE_FILES); return false; @@ -372,6 +374,88 @@ bool isoDrive::isRemovable(void) return true; } +int isoDrive::GetDirIterator(const isoDirEntry* de) +{ + int dirIterator = nextFreeDirIterator; + + // get start and end sector of the directory entry (pad end sector if necessary) + dirIterators[dirIterator].currentSector = EXTENT_LOCATION(*de); + dirIterators[dirIterator].endSector = + EXTENT_LOCATION(*de) + DATA_LENGTH(*de) / ISO_FRAMESIZE - 1; + if (DATA_LENGTH(*de) % ISO_FRAMESIZE != 0) + dirIterators[dirIterator].endSector++; + + // reset position and mark as valid + dirIterators[dirIterator].pos = 0; + dirIterators[dirIterator].valid = true; + + // advance to next directory iterator (wrap around if necessary) + nextFreeDirIterator = (nextFreeDirIterator + 1) % MAX_OPENDIRS; + + return dirIterator; +} + +bool isoDrive::GetNextDirEntry(const int dirIteratorHandle, isoDirEntry* de) +{ + bool result = false; + Bit8u* buffer = NULL; + DirIterator& dirIterator = dirIterators[dirIteratorHandle]; + + // check if the directory entry is valid + if (dirIterator.valid && ReadCachedSector(&buffer, dirIterator.currentSector)) { + // check if the next sector has to be read + if ((dirIterator.pos >= ISO_FRAMESIZE) + || (buffer[dirIterator.pos] == 0) + || (dirIterator.pos + buffer[dirIterator.pos] > ISO_FRAMESIZE)) { + + // check if there is another sector available + if (dirIterator.currentSector < dirIterator.endSector) { + dirIterator.pos = 0; + dirIterator.currentSector++; + if (!ReadCachedSector(&buffer, dirIterator.currentSector)) { + return false; + } + } else { + return false; + } + } + // read sector and advance sector pointer + int length = readDirEntry(de, &buffer[dirIterator.pos]); + result = length >= 0; + dirIterator.pos += length; + } + return result; +} + +void isoDrive::FreeDirIterator(const int dirIterator) +{ + dirIterators[dirIterator].valid = false; + + // if this was the last aquired iterator decrement nextFreeIterator + if ((dirIterator + 1) % MAX_OPENDIRS == nextFreeDirIterator) { + nextFreeDirIterator--; + } +} + +bool isoDrive::ReadCachedSector(Bit8u** buffer, const Bit32u sector) +{ + // get hash table entry + int pos = sector % ISO_MAX_HASH_TABLE_SIZE; + SectorHashEntry& he = sectorHashEntries[pos]; + + // check if the entry is valid and contains the correct sector + if (!he.valid || he.sector != sector) { + if (!CDROM_Interface_Image::images[subUnit]->ReadSector(he.data, false, sector)) { + return false; + } + he.valid = true; + he.sector = sector; + } + + *buffer = he.data; + return true; +} + inline bool isoDrive :: readSector(Bit8u *buffer, Bit32u sector) { return CDROM_Interface_Image::images[subUnit]->ReadSector(buffer, false, sector); @@ -417,50 +501,36 @@ bool isoDrive :: loadImage() return (readDirEntry(&this->rootEntry, pvd.rootEntry)); } -bool isoDrive :: lookupSingle(isoDirEntry *de, const char *name, Bit32u start, Bit32u length) -{ - Bit32u end = start + length / ISO_FRAMESIZE; - if (length % ISO_FRAMESIZE != 0) end++; - - for(Bit32u i = start; i < end; i++) { - Bit8u sector[ISO_FRAMESIZE]; - if (!readSector(sector, i)) return false; - - int pos = 0; - while (pos < ISO_FRAMESIZE && sector[pos] != 0 && (pos + sector[pos]) <= ISO_FRAMESIZE) { - int deLength = readDirEntry(de, §or[pos]); - if (deLength < 1) return false; - pos += deLength; - int tmp = strncasecmp((char*)de->ident, name, 38); - if (tmp == 0) return true; - } - } - return false; -} - bool isoDrive :: lookup(isoDirEntry *de, const char *path) { *de = this->rootEntry; if (!strcmp(path, "")) return true; char isoPath[ISO_MAXPATHNAME]; - strncpy(isoPath, path, ISO_MAXPATHNAME); + safe_strncpy(isoPath, path, ISO_MAXPATHNAME); strreplace(isoPath, '\\', '/'); - int beginPos = 0; - int pos = 0; - while (isoPath[pos] != 0) { - if (isoPath[pos] == '/') { - char name[38]; - if (pos - beginPos >= 38) return false; - if (beginPos >= ISO_MAXPATHNAME) return false; - strncpy(name, &isoPath[beginPos], pos - beginPos); - name[pos - beginPos] = 0; - beginPos = pos + 1; - if (!IS_DIR(de->fileFlags)) return false; - if (!lookupSingle(de, name, EXTENT_LOCATION(*de), DATA_LENGTH(*de))) return false; + // iterate over all path elements (name), and search each of them in the current de + for(char* name = strtok(isoPath, "/"); NULL != name; name = strtok(NULL, "/")) { + + bool found = false; + // current entry must be a directory, abort otherwise + if (IS_DIR(de->fileFlags)) { + + // remove the trailing dot if present + int nameLength = strlen(name); + if (nameLength > 0 && name[nameLength - 1] == '.') name[nameLength - 1] = 0; + + // look for the current path element + int dirIterator = GetDirIterator(de); + while (!found && GetNextDirEntry(dirIterator, de)) { + if (0 == strncasecmp((char*) de->ident, name, ISO_MAX_FILENAME_LENGTH)) { + found = true; + } + } + FreeDirIterator(dirIterator); } - pos++; + if (!found) return false; } - return lookupSingle(de, &isoPath[beginPos], EXTENT_LOCATION(*de), DATA_LENGTH(*de)); + return true; } diff --git a/src/dos/drive_local.cpp b/src/dos/drive_local.cpp index 6d92a11..bc5ea8e 100644 --- a/src/dos/drive_local.cpp +++ b/src/dos/drive_local.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: drive_local.cpp,v 1.54 2004/11/16 14:13:46 qbix79 Exp $ */ +/* $Id: drive_local.cpp,v 1.64 2006/03/13 19:58:09 qbix79 Exp $ */ #include #include @@ -29,7 +29,7 @@ #include "drives.h" #include "support.h" #include "cross.h" - +#include "inout.h" class localFile : public DOS_File { public: @@ -53,13 +53,24 @@ bool localDrive::FileCreate(DOS_File * * file,char * name,Bit16u attributes) { strcpy(newname,basedir); strcat(newname,name); CROSS_FILENAME(newname); - FILE * hand=fopen(dirCache.GetExpandName(newname),"wb+"); + char* temp_name = dirCache.GetExpandName(newname); //Can only be used in till a new drive_cache action is preformed */ + /* Test if file exists (so we need to truncate it). don't add to dirCache then */ + bool existing_file=false; + + FILE * test=fopen(temp_name,"rb+"); + if(test) { + fclose(test); + existing_file=true; + + } + + FILE * hand=fopen(temp_name,"wb+"); if (!hand){ LOG_MSG("Warning: file creation failed: %s",newname); return false; } - dirCache.AddEntry(newname, true); + if(!existing_file) dirCache.AddEntry(newname, true); /* Make the 16 bit device information */ *file=new localFile(name,hand,0x202); @@ -161,17 +172,24 @@ bool localDrive::FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst) { Bit8u sAttr; dta.GetSearchParams(sAttr,tempDir); - if ( (sAttr & DOS_ATTR_VOLUME) && ( (*_dir==0) || fcb_findfirst ) ) { - // Get Volume Label (DOS_ATTR_VOLUME) and only in basedir - // or it's a fcb findfirst as that always returns label + + if (sAttr == DOS_ATTR_VOLUME) { if ( strcmp(dirCache.GetLabel(), "") == 0 ) { - LOG(LOG_DOSMISC,LOG_ERROR)("DRIVELABEL REQUESTED: none present, returned NOLABEL"); - dta.SetResult("NO_LABEL",0,0,0,DOS_ATTR_VOLUME); - return true; +// LOG(LOG_DOSMISC,LOG_ERROR)("DRIVELABEL REQUESTED: none present, returned NOLABEL"); +// dta.SetResult("NO_LABEL",0,0,0,DOS_ATTR_VOLUME); +// return true; + DOS_SetError(DOSERR_NO_MORE_FILES); + return false; } - // Get Volume Label && ignore search string (pandora) dta.SetResult(dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME); return true; + } else if ((sAttr & DOS_ATTR_VOLUME) && (*_dir == 0) && !fcb_findfirst) { + //should check for a valid leading directory instead of 0 + //exists==true if the volume label matches the searchmask and the path is valid + if (WildFileCmp(dirCache.GetLabel(),tempDir)) { + dta.SetResult(dirCache.GetLabel(),0,0,0,DOS_ATTR_VOLUME); + return true; + } } return FindNext(dta); } @@ -187,7 +205,6 @@ bool localDrive::FindNext(DOS_DTA & dta) { Bit8u find_attr; dta.GetSearchParams(srch_attr,srch_pattern); - Bitu id = dta.GetDirID(); again: @@ -195,7 +212,6 @@ again: DOS_SetError(DOSERR_NO_MORE_FILES); return false; } - if(!WildFileCmp(dir_ent,srch_pattern)) goto again; strcpy(full_name,srchInfo[id].srch_dir); @@ -262,8 +278,8 @@ bool localDrive::MakeDir(char * dir) { int temp=mkdir(dirCache.GetExpandName(newdir),0700); #endif if (temp==0) dirCache.CacheOut(newdir,true); - // if dir already exists, return success too. - return (temp==0) || ((temp!=0) && (errno==EEXIST)); + + return (temp==0);// || ((temp!=0) && (errno==EEXIST)); } bool localDrive::RemoveDir(char * dir) { @@ -283,11 +299,11 @@ bool localDrive::TestDir(char * dir) { CROSS_FILENAME(newdir); dirCache.ExpandName(newdir); // Skip directory test, if "\" - Bit16u len = strlen(newdir); - if ((len>0) && (newdir[len-1]!='\\')) { + size_t len = strlen(newdir); + if (len && (newdir[len-1]!='\\')) { // It has to be a directory ! struct stat test; - if (stat(newdir,&test)==-1) return false; + if (stat(newdir,&test)) return false; if ((test.st_mode & S_IFDIR)==0) return false; }; int temp=access(newdir,F_OK); @@ -384,6 +400,11 @@ bool localFile::Read(Bit8u * data,Bit16u * size) { if (last_action==WRITE) fseek(fhandle,ftell(fhandle),SEEK_SET); last_action=READ; *size=fread(data,1,*size,fhandle); + /* Fake harddrive motion. Inspector Gadget with soundblaster compatible */ + /* Same for Igor */ + /* hardrive motion => unmask irq 2. Only do it when it's masked as unmasking is realitively heavy to emulate */ + Bit8u mask = IO_Read(0x21); + if(mask & 0x4 ) IO_Write(0x21,mask&0xfb); return true; }; @@ -409,7 +430,7 @@ bool localFile::Seek(Bit32u * pos,Bit32u type) { //TODO Give some doserrorcode; return false;//ERROR } - int ret=fseek(fhandle,*pos,seektype); + int ret=fseek(fhandle,*reinterpret_cast(pos),seektype); if (ret!=0) { // Out of file range, pretend everythings ok // and move file pointer top end of file... ?! (Black Thorne) diff --git a/src/dos/drive_virtual.cpp b/src/dos/drive_virtual.cpp index d9321c5..ae1e786 100644 --- a/src/dos/drive_virtual.cpp +++ b/src/dos/drive_virtual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -49,6 +49,20 @@ void VFILE_Register(const char * name,Bit8u * data,Bit32u size) { first_file=new_file; } +void VFILE_Remove(const char *name) { + VFILE_Block * chan=first_file; + VFILE_Block * * where=&first_file; + while (chan) { + if (strcmp(name,chan->name) == 0) { + *where = chan->next; + if(chan == first_file) first_file = chan->next; + delete chan; + return; + } + where=&chan->next; + chan=chan->next; + } +} class Virtual_File : public DOS_File { public: @@ -212,6 +226,14 @@ bool Virtual_Drive::FindNext(DOS_DTA & dta) { } bool Virtual_Drive::GetFileAttr(char * name,Bit16u * attr) { + VFILE_Block * cur_file=first_file; + while (cur_file) { + if (strcasecmp(name,cur_file->name)==0) { + *attr = DOS_ATTR_ARCHIVE; //Maybe readonly ? + return true; + } + cur_file=cur_file->next; + } return false; } diff --git a/src/dos/drives.cpp b/src/dos/drives.cpp index d0c0cfb..8b82162 100644 --- a/src/dos/drives.cpp +++ b/src/dos/drives.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -35,7 +35,7 @@ bool WildFileCmp(const char * file, const char * wild) strcpy(wild_name," "); strcpy(wild_ext," "); - find_ext=strchr(file,'.'); + find_ext=strrchr(file,'.'); if (find_ext) { Bitu size=find_ext-file;if (size>8) size=8; memcpy(file_name,file,size); @@ -45,7 +45,7 @@ bool WildFileCmp(const char * file, const char * wild) memcpy(file_name,file,(strlen(file) > 8) ? 8 : strlen(file)); } upcase(file_name);upcase(file_ext); - find_ext=strchr(wild,'.'); + find_ext=strrchr(wild,'.'); if (find_ext) { Bitu size=find_ext-wild;if (size>8) size=8; memcpy(wild_name,wild,size); diff --git a/src/dos/drives.h b/src/dos/drives.h index 9f66a23..8a3d39c 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: drives.h,v 1.25 2004/11/03 23:13:55 qbix79 Exp $ */ +/* $Id: drives.h,v 1.31 2006/02/12 13:32:30 qbix79 Exp $ */ #ifndef _DRIVES_H__ #define _DRIVES_H__ @@ -264,7 +264,7 @@ struct isoDirEntry { #pragma pack () #endif -#if defined (WORD_BIGENDIAN) +#if defined (WORDS_BIGENDIAN) #define EXTENT_LOCATION(de) ((de).extentLocationM) #define DATA_LENGTH(de) ((de).dataLengthM) #else @@ -274,9 +274,13 @@ struct isoDirEntry { #define ISO_FRAMESIZE 2048 #define ISO_DIRECTORY 2 +#define ISO_HIDDEN 1 +#define ISO_MAX_FILENAME_LENGTH 37 #define ISO_MAXPATHNAME 256 #define ISO_FIRST_VD 16 #define IS_DIR(fileFlags) (fileFlags & ISO_DIRECTORY) +#define IS_HIDDEN(fileFlags) (fileFlags & ISO_HIDDEN) +#define ISO_MAX_HASH_TABLE_SIZE 100 class isoDrive : public DOS_Drive { public: @@ -300,14 +304,33 @@ public: virtual bool isRemote(void); virtual bool isRemovable(void); bool readSector(Bit8u *buffer, Bit32u sector); + virtual char const* GetLabel(void) {return discLabel;}; private: int readDirEntry(isoDirEntry *de, Bit8u *data); bool loadImage(); bool lookupSingle(isoDirEntry *de, const char *name, Bit32u sectorStart, Bit32u length); bool lookup(isoDirEntry *de, const char *path); + + int GetDirIterator(const isoDirEntry* de); + bool GetNextDirEntry(const int dirIterator, isoDirEntry* de); + void FreeDirIterator(const int dirIterator); + bool ReadCachedSector(Bit8u** buffer, const Bit32u sector); + + struct DirIterator { + bool valid; + Bit32u currentSector; + Bit32u endSector; + Bit32u pos; + } dirIterators[MAX_OPENDIRS]; + + int nextFreeDirIterator; + + struct SectorHashEntry { + bool valid; + Bit32u sector; + Bit8u data[ISO_FRAMESIZE]; + } sectorHashEntries[ISO_MAX_HASH_TABLE_SIZE]; - std::vector searchCache; - std::vector::iterator dirIter; isoDirEntry rootEntry; Bit8u mediaid; Bit8u subUnit; diff --git a/src/dos/scsidefs.h b/src/dos/scsidefs.h index 061ca90..e0f7961 100644 --- a/src/dos/scsidefs.h +++ b/src/dos/scsidefs.h @@ -1,288 +1,288 @@ -/* Got it from Bochs */ - -///////////////////////////////////////////////////////////////////////// -// $Id: scsidefs.h,v 1.2 2004/01/02 14:34:48 qbix79 Exp $ -///////////////////////////////////////////////////////////////////////// -// -// -// iodev/scsidefs.h -// $Id: scsidefs.h,v 1.2 2004/01/02 14:34:48 qbix79 Exp $ -// -// This file was copied from ... ? -// - -//*************************************************************************** -// -// Name: SCSIDEFS.H -// -// Description: SCSI definitions ('C' Language) -// -//*************************************************************************** - -//*************************************************************************** -// %%% TARGET STATUS VALUES %%% -//*************************************************************************** -#define STATUS_GOOD 0x00 // Status Good -#define STATUS_CHKCOND 0x02 // Check Condition -#define STATUS_CONDMET 0x04 // Condition Met -#define STATUS_BUSY 0x08 // Busy -#define STATUS_INTERM 0x10 // Intermediate -#define STATUS_INTCDMET 0x14 // Intermediate-condition met -#define STATUS_RESCONF 0x18 // Reservation conflict -#define STATUS_COMTERM 0x22 // Command Terminated -#define STATUS_QFULL 0x28 // Queue full - -//*************************************************************************** -// %%% SCSI MISCELLANEOUS EQUATES %%% -//*************************************************************************** -#define MAXLUN 7 // Maximum Logical Unit Id -#define MAXTARG 7 // Maximum Target Id -#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs -#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's - -//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ -// -// %%% SCSI COMMAND OPCODES %%% -// -///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ - -//*************************************************************************** -// %%% Commands for all Device Types %%% -//*************************************************************************** -#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) -#define SCSI_COMPARE 0x39 // Compare (O) -#define SCSI_COPY 0x18 // Copy (O) -#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) -#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) -#define SCSI_LOG_SELECT 0x4C // Log Select (O) -#define SCSI_LOG_SENSE 0x4D // Log Sense (O) -#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) -#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) -#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) -#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) -#define SCSI_READ_BUFF 0x3C // Read Buffer (O) -#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) -#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) -#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) -#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) - -//*************************************************************************** -// %%% Commands Unique to Direct Access Devices %%% -//*************************************************************************** -#define SCSI_COMPARE 0x39 // Compare (O) -#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) -#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) -#define SCSI_PREFETCH 0x34 // Prefetch (O) -#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) -#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) -#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) -#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) -#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) -#define SCSI_READ_LONG 0x3E // Read Long (O) -#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) -#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) -#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) -#define SCSI_REZERO 0x01 // Rezero Unit (O) -#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) -#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) -#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) -#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) -#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) -#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY) -#define SCSI_SET_LIMIT 0x33 // Set Limits (O) -#define SCSI_START_STP 0x1B // Start/Stop Unit (O) -#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) -#define SCSI_VERIFY 0x2F // Verify (O) -#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) -#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) -#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) -#define SCSI_WRITE_LONG 0x3F // Write Long (O) -#define SCSI_WRITE_SAME 0x41 // Write Same (O) - -//*************************************************************************** -// %%% Commands Unique to Sequential Access Devices %%% -//*************************************************************************** -#define SCSI_ERASE 0x19 // Erase (MANDATORY) -#define SCSI_LOAD_UN 0x1B // Load/Unload (O) -#define SCSI_LOCATE 0x2B // Locate (O) -#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) -#define SCSI_READ_POS 0x34 // Read Position (O) -#define SCSI_READ_REV 0x0F // Read Reverse (O) -#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) -#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) -#define SCSI_REWIND 0x01 // Rewind (MANDATORY) -#define SCSI_SPACE 0x11 // Space (MANDATORY) -#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) -#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) - -//*************************************************************************** -// %%% Commands Unique to Printer Devices %%% -//*************************************************************************** -#define SCSI_PRINT 0x0A // Print (MANDATORY) -#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) -#define SCSI_STOP_PNT 0x1B // Stop Print (O) -#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) - -//*************************************************************************** -// %%% Commands Unique to Processor Devices %%% -//*************************************************************************** -#define SCSI_RECEIVE 0x08 // Receive (O) -#define SCSI_SEND 0x0A // Send (O) - -//*************************************************************************** -// %%% Commands Unique to Write-Once Devices %%% -//*************************************************************************** -#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) -#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) -#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) -#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) -#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) -#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) -#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) -#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) -#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) -#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) -#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) -#define SCSI_WRITE12 0xAA // Write 12-Byte (O) -#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) -#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) - -//*************************************************************************** -// %%% Commands Unique to CD-ROM Devices %%% -//*************************************************************************** -#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) -#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) -#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) -#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) -#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) -#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) -#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) -#define SCSI_READHEADER 0x44 // Read Header (O) -#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) -#define SCSI_READ_TOC 0x43 // Read TOC (O) - -//*************************************************************************** -// %%% Commands Unique to Scanner Devices %%% -//*************************************************************************** -#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) -#define SCSI_GETWINDOW 0x25 // Get Window (O) -#define SCSI_OBJECTPOS 0x31 // Object Postion (O) -#define SCSI_SCAN 0x1B // Scan (O) -#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) - -//*************************************************************************** -// %%% Commands Unique to Optical Memory Devices %%% -//*************************************************************************** -#define SCSI_UpdateBlk 0x3D // Update Block (O) - -//*************************************************************************** -// %%% Commands Unique to Medium Changer Devices %%% -//*************************************************************************** -#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) -#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) -#define SCSI_POSTOELEM 0x2B // Position to Element (O) -#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) -#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) - -//*************************************************************************** -// %%% Commands Unique to Communication Devices %%% -//*************************************************************************** -#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) -#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) -#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) -#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) -#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) -#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) - -//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ -// -// %%% END OF SCSI COMMAND OPCODES %%% -// -///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ - -//*************************************************************************** -// %%% Request Sense Data Format %%% -//*************************************************************************** -typedef struct { - - BYTE ErrorCode; // Error Code (70H or 71H) - BYTE SegmentNum; // Number of current segment descriptor - BYTE SenseKey; // Sense Key(See bit definitions too) - BYTE InfoByte0; // Information MSB - BYTE InfoByte1; // Information MID - BYTE InfoByte2; // Information MID - BYTE InfoByte3; // Information LSB - BYTE AddSenLen; // Additional Sense Length - BYTE ComSpecInf0; // Command Specific Information MSB - BYTE ComSpecInf1; // Command Specific Information MID - BYTE ComSpecInf2; // Command Specific Information MID - BYTE ComSpecInf3; // Command Specific Information LSB - BYTE AddSenseCode; // Additional Sense Code - BYTE AddSenQual; // Additional Sense Code Qualifier - BYTE FieldRepUCode; // Field Replaceable Unit Code - BYTE SenKeySpec15; // Sense Key Specific 15th byte - BYTE SenKeySpec16; // Sense Key Specific 16th byte - BYTE SenKeySpec17; // Sense Key Specific 17th byte - BYTE AddSenseBytes; // Additional Sense Bytes - -} SENSE_DATA_FMT; - -//*************************************************************************** -// %%% REQUEST SENSE ERROR CODE %%% -//*************************************************************************** -#define SERROR_CURRENT 0x70 // Current Errors -#define SERROR_DEFERED 0x71 // Deferred Errors - -//*************************************************************************** -// %%% REQUEST SENSE BIT DEFINITIONS %%% -//*************************************************************************** -#define SENSE_VALID 0x80 // Byte 0 Bit 7 -#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 -#define SENSE_EOM 0x40 // Byte 2 Bit 6 -#define SENSE_ILI 0x20 // Byte 2 Bit 5 - -//*************************************************************************** -// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% -//*************************************************************************** -#define KEY_NOSENSE 0x00 // No Sense -#define KEY_RECERROR 0x01 // Recovered Error -#define KEY_NOTREADY 0x02 // Not Ready -#define KEY_MEDIUMERR 0x03 // Medium Error -#define KEY_HARDERROR 0x04 // Hardware Error -#define KEY_ILLGLREQ 0x05 // Illegal Request -#define KEY_UNITATT 0x06 // Unit Attention -#define KEY_DATAPROT 0x07 // Data Protect -#define KEY_BLANKCHK 0x08 // Blank Check -#define KEY_VENDSPEC 0x09 // Vendor Specific -#define KEY_COPYABORT 0x0A // Copy Abort -#define KEY_EQUAL 0x0C // Equal (Search) -#define KEY_VOLOVRFLW 0x0D // Volume Overflow -#define KEY_MISCOMP 0x0E // Miscompare (Search) -#define KEY_RESERVED 0x0F // Reserved - -//*************************************************************************** -// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% -//*************************************************************************** -#define DTYPE_DASD 0x00 // Disk Device -#define DTYPE_SEQD 0x01 // Tape Device -#define DTYPE_PRNT 0x02 // Printer -#define DTYPE_PROC 0x03 // Processor -#define DTYPE_WORM 0x04 // Write-once read-multiple -#define DTYPE_CROM 0x05 // CD-ROM device -#define DTYPE_CDROM 0x05 // CD-ROM device -#define DTYPE_SCAN 0x06 // Scanner device -#define DTYPE_OPTI 0x07 // Optical memory device -#define DTYPE_JUKE 0x08 // Medium Changer device -#define DTYPE_COMM 0x09 // Communications device -#define DTYPE_RESL 0x0A // Reserved (low) -#define DTYPE_RESH 0x1E // Reserved (high) -#define DTYPE_UNKNOWN 0x1F // Unknown or no device type - -//*************************************************************************** -// %%% ANSI APPROVED VERSION DEFINITIONS %%% -//*************************************************************************** -#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand -#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) -#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 -#define ANSI_RESLO 0x3 // Reserved (low) -#define ANSI_RESHI 0x7 // Reserved (high) +/* Got it from Bochs */ + +///////////////////////////////////////////////////////////////////////// +// $Id: scsidefs.h,v 1.3 2005/07/21 12:49:52 qbix79 Exp $ +///////////////////////////////////////////////////////////////////////// +// +// +// iodev/scsidefs.h +// $Id: scsidefs.h,v 1.3 2005/07/21 12:49:52 qbix79 Exp $ +// +// This file was copied from ... ? +// + +//*************************************************************************** +// +// Name: SCSIDEFS.H +// +// Description: SCSI definitions ('C' Language) +// +//*************************************************************************** + +//*************************************************************************** +// %%% TARGET STATUS VALUES %%% +//*************************************************************************** +#define STATUS_GOOD 0x00 // Status Good +#define STATUS_CHKCOND 0x02 // Check Condition +#define STATUS_CONDMET 0x04 // Condition Met +#define STATUS_BUSY 0x08 // Busy +#define STATUS_INTERM 0x10 // Intermediate +#define STATUS_INTCDMET 0x14 // Intermediate-condition met +#define STATUS_RESCONF 0x18 // Reservation conflict +#define STATUS_COMTERM 0x22 // Command Terminated +#define STATUS_QFULL 0x28 // Queue full + +//*************************************************************************** +// %%% SCSI MISCELLANEOUS EQUATES %%% +//*************************************************************************** +#define MAXLUN 7 // Maximum Logical Unit Id +#define MAXTARG 7 // Maximum Target Id +#define MAX_SCSI_LUNS 64 // Maximum Number of SCSI LUNs +#define MAX_NUM_HA 8 // Maximum Number of SCSI HA's + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Commands for all Device Types %%% +//*************************************************************************** +#define SCSI_CHANGE_DEF 0x40 // Change Definition (Optional) +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_COPY 0x18 // Copy (O) +#define SCSI_COP_VERIFY 0x3A // Copy and Verify (O) +#define SCSI_INQUIRY 0x12 // Inquiry (MANDATORY) +#define SCSI_LOG_SELECT 0x4C // Log Select (O) +#define SCSI_LOG_SENSE 0x4D // Log Sense (O) +#define SCSI_MODE_SEL6 0x15 // Mode Select 6-byte (Device Specific) +#define SCSI_MODE_SEL10 0x55 // Mode Select 10-byte (Device Specific) +#define SCSI_MODE_SEN6 0x1A // Mode Sense 6-byte (Device Specific) +#define SCSI_MODE_SEN10 0x5A // Mode Sense 10-byte (Device Specific) +#define SCSI_READ_BUFF 0x3C // Read Buffer (O) +#define SCSI_REQ_SENSE 0x03 // Request Sense (MANDATORY) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostic (O) +#define SCSI_TST_U_RDY 0x00 // Test Unit Ready (MANDATORY) +#define SCSI_WRITE_BUFF 0x3B // Write Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Direct Access Devices %%% +//*************************************************************************** +#define SCSI_COMPARE 0x39 // Compare (O) +#define SCSI_FORMAT 0x04 // Format Unit (MANDATORY) +#define SCSI_LCK_UN_CAC 0x36 // Lock Unlock Cache (O) +#define SCSI_PREFETCH 0x34 // Prefetch (O) +#define SCSI_MED_REMOVL 0x1E // Prevent/Allow medium Removal (O) +#define SCSI_READ6 0x08 // Read 6-byte (MANDATORY) +#define SCSI_READ10 0x28 // Read 10-byte (MANDATORY) +#define SCSI_RD_CAPAC 0x25 // Read Capacity (MANDATORY) +#define SCSI_RD_DEFECT 0x37 // Read Defect Data (O) +#define SCSI_READ_LONG 0x3E // Read Long (O) +#define SCSI_REASS_BLK 0x07 // Reassign Blocks (O) +#define SCSI_RCV_DIAG 0x1C // Receive Diagnostic Results (O) +#define SCSI_RELEASE 0x17 // Release Unit (MANDATORY) +#define SCSI_REZERO 0x01 // Rezero Unit (O) +#define SCSI_SRCH_DAT_E 0x31 // Search Data Equal (O) +#define SCSI_SRCH_DAT_H 0x30 // Search Data High (O) +#define SCSI_SRCH_DAT_L 0x32 // Search Data Low (O) +#define SCSI_SEEK6 0x0B // Seek 6-Byte (O) +#define SCSI_SEEK10 0x2B // Seek 10-Byte (O) +#define SCSI_SEND_DIAG 0x1D // Send Diagnostics (MANDATORY) +#define SCSI_SET_LIMIT 0x33 // Set Limits (O) +#define SCSI_START_STP 0x1B // Start/Stop Unit (O) +#define SCSI_SYNC_CACHE 0x35 // Synchronize Cache (O) +#define SCSI_VERIFY 0x2F // Verify (O) +#define SCSI_WRITE6 0x0A // Write 6-Byte (MANDATORY) +#define SCSI_WRITE10 0x2A // Write 10-Byte (MANDATORY) +#define SCSI_WRT_VERIFY 0x2E // Write and Verify (O) +#define SCSI_WRITE_LONG 0x3F // Write Long (O) +#define SCSI_WRITE_SAME 0x41 // Write Same (O) + +//*************************************************************************** +// %%% Commands Unique to Sequential Access Devices %%% +//*************************************************************************** +#define SCSI_ERASE 0x19 // Erase (MANDATORY) +#define SCSI_LOAD_UN 0x1B // Load/Unload (O) +#define SCSI_LOCATE 0x2B // Locate (O) +#define SCSI_RD_BLK_LIM 0x05 // Read Block Limits (MANDATORY) +#define SCSI_READ_POS 0x34 // Read Position (O) +#define SCSI_READ_REV 0x0F // Read Reverse (O) +#define SCSI_REC_BF_DAT 0x14 // Recover Buffer Data (O) +#define SCSI_RESERVE 0x16 // Reserve Unit (MANDATORY) +#define SCSI_REWIND 0x01 // Rewind (MANDATORY) +#define SCSI_SPACE 0x11 // Space (MANDATORY) +#define SCSI_VERIFY_T 0x13 // Verify (Tape) (O) +#define SCSI_WRT_FILE 0x10 // Write Filemarks (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Printer Devices %%% +//*************************************************************************** +#define SCSI_PRINT 0x0A // Print (MANDATORY) +#define SCSI_SLEW_PNT 0x0B // Slew and Print (O) +#define SCSI_STOP_PNT 0x1B // Stop Print (O) +#define SCSI_SYNC_BUFF 0x10 // Synchronize Buffer (O) + +//*************************************************************************** +// %%% Commands Unique to Processor Devices %%% +//*************************************************************************** +#define SCSI_RECEIVE 0x08 // Receive (O) +#define SCSI_SEND 0x0A // Send (O) + +//*************************************************************************** +// %%% Commands Unique to Write-Once Devices %%% +//*************************************************************************** +#define SCSI_MEDIUM_SCN 0x38 // Medium Scan (O) +#define SCSI_SRCHDATE10 0x31 // Search Data Equal 10-Byte (O) +#define SCSI_SRCHDATE12 0xB1 // Search Data Equal 12-Byte (O) +#define SCSI_SRCHDATH10 0x30 // Search Data High 10-Byte (O) +#define SCSI_SRCHDATH12 0xB0 // Search Data High 12-Byte (O) +#define SCSI_SRCHDATL10 0x32 // Search Data Low 10-Byte (O) +#define SCSI_SRCHDATL12 0xB2 // Search Data Low 12-Byte (O) +#define SCSI_SET_LIM_10 0x33 // Set Limits 10-Byte (O) +#define SCSI_SET_LIM_12 0xB3 // Set Limits 10-Byte (O) +#define SCSI_VERIFY10 0x2F // Verify 10-Byte (O) +#define SCSI_VERIFY12 0xAF // Verify 12-Byte (O) +#define SCSI_WRITE12 0xAA // Write 12-Byte (O) +#define SCSI_WRT_VER10 0x2E // Write and Verify 10-Byte (O) +#define SCSI_WRT_VER12 0xAE // Write and Verify 12-Byte (O) + +//*************************************************************************** +// %%% Commands Unique to CD-ROM Devices %%% +//*************************************************************************** +#define SCSI_PLAYAUD_10 0x45 // Play Audio 10-Byte (O) +#define SCSI_PLAYAUD_12 0xA5 // Play Audio 12-Byte 12-Byte (O) +#define SCSI_PLAYAUDMSF 0x47 // Play Audio MSF (O) +#define SCSI_PLAYA_TKIN 0x48 // Play Audio Track/Index (O) +#define SCSI_PLYTKREL10 0x49 // Play Track Relative 10-Byte (O) +#define SCSI_PLYTKREL12 0xA9 // Play Track Relative 12-Byte (O) +#define SCSI_READCDCAP 0x25 // Read CD-ROM Capacity (MANDATORY) +#define SCSI_READHEADER 0x44 // Read Header (O) +#define SCSI_SUBCHANNEL 0x42 // Read Subchannel (O) +#define SCSI_READ_TOC 0x43 // Read TOC (O) + +//*************************************************************************** +// %%% Commands Unique to Scanner Devices %%% +//*************************************************************************** +#define SCSI_GETDBSTAT 0x34 // Get Data Buffer Status (O) +#define SCSI_GETWINDOW 0x25 // Get Window (O) +#define SCSI_OBJECTPOS 0x31 // Object Postion (O) +#define SCSI_SCAN 0x1B // Scan (O) +#define SCSI_SETWINDOW 0x24 // Set Window (MANDATORY) + +//*************************************************************************** +// %%% Commands Unique to Optical Memory Devices %%% +//*************************************************************************** +#define SCSI_UpdateBlk 0x3D // Update Block (O) + +//*************************************************************************** +// %%% Commands Unique to Medium Changer Devices %%% +//*************************************************************************** +#define SCSI_EXCHMEDIUM 0xA6 // Exchange Medium (O) +#define SCSI_INITELSTAT 0x07 // Initialize Element Status (O) +#define SCSI_POSTOELEM 0x2B // Position to Element (O) +#define SCSI_REQ_VE_ADD 0xB5 // Request Volume Element Address (O) +#define SCSI_SENDVOLTAG 0xB6 // Send Volume Tag (O) + +//*************************************************************************** +// %%% Commands Unique to Communication Devices %%% +//*************************************************************************** +#define SCSI_GET_MSG_6 0x08 // Get Message 6-Byte (MANDATORY) +#define SCSI_GET_MSG_10 0x28 // Get Message 10-Byte (O) +#define SCSI_GET_MSG_12 0xA8 // Get Message 12-Byte (O) +#define SCSI_SND_MSG_6 0x0A // Send Message 6-Byte (MANDATORY) +#define SCSI_SND_MSG_10 0x2A // Send Message 10-Byte (O) +#define SCSI_SND_MSG_12 0xAA // Send Message 12-Byte (O) + +//\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ +// +// %%% END OF SCSI COMMAND OPCODES %%% +// +///\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ + +//*************************************************************************** +// %%% Request Sense Data Format %%% +//*************************************************************************** +typedef struct { + + BYTE ErrorCode; // Error Code (70H or 71H) + BYTE SegmentNum; // Number of current segment descriptor + BYTE SenseKey; // Sense Key(See bit definitions too) + BYTE InfoByte0; // Information MSB + BYTE InfoByte1; // Information MID + BYTE InfoByte2; // Information MID + BYTE InfoByte3; // Information LSB + BYTE AddSenLen; // Additional Sense Length + BYTE ComSpecInf0; // Command Specific Information MSB + BYTE ComSpecInf1; // Command Specific Information MID + BYTE ComSpecInf2; // Command Specific Information MID + BYTE ComSpecInf3; // Command Specific Information LSB + BYTE AddSenseCode; // Additional Sense Code + BYTE AddSenQual; // Additional Sense Code Qualifier + BYTE FieldRepUCode; // Field Replaceable Unit Code + BYTE SenKeySpec15; // Sense Key Specific 15th byte + BYTE SenKeySpec16; // Sense Key Specific 16th byte + BYTE SenKeySpec17; // Sense Key Specific 17th byte + BYTE AddSenseBytes; // Additional Sense Bytes + +} SENSE_DATA_FMT; + +//*************************************************************************** +// %%% REQUEST SENSE ERROR CODE %%% +//*************************************************************************** +#define SERROR_CURRENT 0x70 // Current Errors +#define SERROR_DEFERED 0x71 // Deferred Errors + +//*************************************************************************** +// %%% REQUEST SENSE BIT DEFINITIONS %%% +//*************************************************************************** +#define SENSE_VALID 0x80 // Byte 0 Bit 7 +#define SENSE_FILEMRK 0x80 // Byte 2 Bit 7 +#define SENSE_EOM 0x40 // Byte 2 Bit 6 +#define SENSE_ILI 0x20 // Byte 2 Bit 5 + +//*************************************************************************** +// %%% REQUEST SENSE SENSE KEY DEFINITIONS %%% +//*************************************************************************** +#define KEY_NOSENSE 0x00 // No Sense +#define KEY_RECERROR 0x01 // Recovered Error +#define KEY_NOTREADY 0x02 // Not Ready +#define KEY_MEDIUMERR 0x03 // Medium Error +#define KEY_HARDERROR 0x04 // Hardware Error +#define KEY_ILLGLREQ 0x05 // Illegal Request +#define KEY_UNITATT 0x06 // Unit Attention +#define KEY_DATAPROT 0x07 // Data Protect +#define KEY_BLANKCHK 0x08 // Blank Check +#define KEY_VENDSPEC 0x09 // Vendor Specific +#define KEY_COPYABORT 0x0A // Copy Abort +#define KEY_EQUAL 0x0C // Equal (Search) +#define KEY_VOLOVRFLW 0x0D // Volume Overflow +#define KEY_MISCOMP 0x0E // Miscompare (Search) +#define KEY_RESERVED 0x0F // Reserved + +//*************************************************************************** +// %%% PERIPHERAL DEVICE TYPE DEFINITIONS %%% +//*************************************************************************** +#define DTYPE_DASD 0x00 // Disk Device +#define DTYPE_SEQD 0x01 // Tape Device +#define DTYPE_PRNT 0x02 // Printer +#define DTYPE_PROC 0x03 // Processor +#define DTYPE_WORM 0x04 // Write-once read-multiple +#define DTYPE_CROM 0x05 // CD-ROM device +#define DTYPE_CDROM 0x05 // CD-ROM device +#define DTYPE_SCAN 0x06 // Scanner device +#define DTYPE_OPTI 0x07 // Optical memory device +#define DTYPE_JUKE 0x08 // Medium Changer device +#define DTYPE_COMM 0x09 // Communications device +#define DTYPE_RESL 0x0A // Reserved (low) +#define DTYPE_RESH 0x1E // Reserved (high) +#define DTYPE_UNKNOWN 0x1F // Unknown or no device type + +//*************************************************************************** +// %%% ANSI APPROVED VERSION DEFINITIONS %%% +//*************************************************************************** +#define ANSI_MAYBE 0x0 // Device may or may not be ANSI approved stand +#define ANSI_SCSI1 0x1 // Device complies to ANSI X3.131-1986 (SCSI-1) +#define ANSI_SCSI2 0x2 // Device complies to SCSI-2 +#define ANSI_RESLO 0x3 // Reserved (low) +#define ANSI_RESHI 0x7 // Reserved (high) diff --git a/src/dosbox.cpp b/src/dosbox.cpp index 5a18410..9438e40 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: dosbox.cpp,v 1.80 2004/09/21 19:32:15 qbix79 Exp $ */ +/* $Id: dosbox.cpp,v 1.99 2006/03/28 10:17:34 qbix79 Exp $ */ #include #include @@ -38,9 +38,11 @@ #include "cross.h" #include "programs.h" #include "support.h" +#include "mapper.h" Config * control; MachineType machine; +SVGACards svgaCard; /* The whole load of startups for all the subfunctions */ void MSG_Init(Section_prop *); @@ -50,7 +52,7 @@ void PAGING_Init(Section *); void IO_Init(Section * ); void CALLBACK_Init(Section*); void PROGRAMS_Init(Section*); -void CREDITS_Init(Section*); +//void CREDITS_Init(Section*); void RENDER_Init(Section*); void VGA_Init(Section*); @@ -80,17 +82,11 @@ void TANDYSOUND_Init(Section*); void DISNEY_Init(Section*); void SERIAL_Init(Section*); -#if C_MODEM -void MODEM_Init(Section*); -#endif #if C_IPX void IPX_Init(Section*); #endif -#if C_DIRECTSERIAL -void DIRECTSERIAL_Init(Section* sec); -#endif void SID_Init(Section* sec); void PIC_Init(Section*); @@ -114,11 +110,15 @@ static LoopHandler * loop; bool SDLNetInited; -Bits RemainTicks; -Bits LastTicks; +static Bit32u ticksRemain; +static Bit32u ticksLast; +static Bit32u ticksAdded; +static Bit32s ticksDone; +static Bit32u ticksScheduled; +bool ticksLocked; static Bitu Normal_Loop(void) { - Bits ret,NewTicks; + Bits ret; while (1) { if (PIC_RunQueue()) { ret=(*cpudecoder)(); @@ -131,27 +131,51 @@ static Bitu Normal_Loop(void) { if (DEBUG_ExitLoop()) return 0; #endif } else { - if (RemainTicks>0) { + GFX_Events(); + if (ticksRemain>0) { TIMER_AddTick(); - RemainTicks--; - GFX_Events(); + ticksRemain--; } else goto increaseticks; } } increaseticks: - NewTicks=GetTicks(); - if (NewTicks>LastTicks) { - RemainTicks=NewTicks-LastTicks; - if (RemainTicks>20) { -// LOG_MSG("Ticks to handle overflow %d",RemainTicks); - RemainTicks=20; + if (GCC_UNLIKELY(ticksLocked)) { + ticksRemain=5; + /* Reset any auto cycle guessing for this frame */ + ticksLast = GetTicks(); + ticksAdded = 0; + ticksDone = 0; + ticksScheduled = 0; + } else { + Bit32u ticksNew; + ticksNew=GetTicks(); + ticksScheduled += ticksAdded; + if (ticksNew > ticksLast) { + ticksRemain = ticksNew-ticksLast; + ticksLast = ticksNew; + ticksDone += ticksRemain; + if ( ticksRemain > 20 ) { + ticksRemain = 20; + } + ticksAdded = ticksRemain; + if (CPU_CycleAuto && (ticksScheduled >= 1000 || ticksDone >= 1000) ) { + /* ratio we are aiming for is around 90% usage*/ + Bits ratio = (ticksScheduled * (90*1024/100)) / ticksDone ; +// LOG_MSG("Done %d schedulded %d ratio %d cycles %d", ticksDone, ticksScheduled, ratio, CPU_CycleMax); + if (ratio <= 1024) + CPU_CycleMax = (CPU_CycleMax * ratio) / 1024; + else + CPU_CycleMax = 1 + (CPU_CycleMax >> 1) + (CPU_CycleMax * ratio) / 2048; + ticksDone = 0; + ticksScheduled = 0; + } + } else { + ticksAdded = 0; + SDL_Delay(1); + ticksDone -= GetTicks() - ticksNew; + if (ticksDone < 0) + ticksDone = 0; } - LastTicks=NewTicks; - } - //TODO Make this selectable in the config file, since it gives some lag */ - if (RemainTicks<=0) { - SDL_Delay(1); - return 0; } return 0; } @@ -171,20 +195,33 @@ void DOSBOX_RunMachine(void){ } while (!ret); } +static void DOSBOX_UnlockSpeed( bool pressed ) { + if (pressed) + ticksLocked = true; + else + ticksLocked = false; +} + static void DOSBOX_RealInit(Section * sec) { Section_prop * section=static_cast(sec); /* Initialize some dosbox internals */ - RemainTicks=0;LastTicks=GetTicks(); + ticksRemain=0; + ticksLast=GetTicks(); + ticksLocked = false; DOSBOX_SetLoop(&Normal_Loop); MSG_Init(section); - machine=MCH_VGA;std::string cmd_machine; + MAPPER_AddHandler(DOSBOX_UnlockSpeed, MK_f12, MMOD2,"speedlock","Speedlock"); + svgaCard = SVGA_S3Trio; + machine=MCH_VGA; + std::string cmd_machine; const char * mtype; if (control->cmdline->FindString("-machine",cmd_machine,true)) mtype=cmd_machine.c_str(); else mtype=section->Get_string("machine"); if (strcasecmp(mtype,"cga")==0) machine=MCH_CGA; else if (strcasecmp(mtype,"tandy")==0) machine=MCH_TANDY; + else if (strcasecmp(mtype,"pcjr")==0) machine=MCH_PCJR; else if (strcasecmp(mtype,"hercules")==0) machine=MCH_HERC; else if (strcasecmp(mtype,"vga")==0) machine=MCH_VGA; else LOG_MSG("DOSBOX:Unknown machine type %s",mtype); @@ -208,39 +245,38 @@ void DOSBOX_Init(void) { LOG_StartUp(); #endif - secprop->AddInitFunction(&IO_Init); - secprop->AddInitFunction(&PAGING_Init); - secprop->AddInitFunction(&MEM_Init); - secprop->AddInitFunction(&HARDWARE_Init); + secprop->AddInitFunction(&IO_Init);//done + secprop->AddInitFunction(&PAGING_Init);//done + secprop->AddInitFunction(&MEM_Init);//done + secprop->AddInitFunction(&HARDWARE_Init);//done secprop->Add_int("memsize",16); secprop->AddInitFunction(&CALLBACK_Init); - secprop->AddInitFunction(&PIC_Init); + secprop->AddInitFunction(&PIC_Init);//done secprop->AddInitFunction(&PROGRAMS_Init); - secprop->AddInitFunction(&TIMER_Init); - secprop->AddInitFunction(&CMOS_Init); - secprop->AddInitFunction(&SERIAL_Init); + secprop->AddInitFunction(&TIMER_Init);//done + secprop->AddInitFunction(&CMOS_Init);//done MSG_Add("DOSBOX_CONFIGFILE_HELP", "language -- Select another language file.\n" "memsize -- Amount of memory dosbox has in megabytes.\n" - "machine -- The type of machine tries to emulate:hercules,cga,tandy,vga.\n" + "machine -- The type of machine tries to emulate:hercules,cga,tandy,pcjr,vga.\n" "captures -- Directory where things like wave,midi,screenshot get captured.\n" ); - secprop=control->AddSection_prop("render",&RENDER_Init); + secprop=control->AddSection_prop("render",&RENDER_Init,true); secprop->Add_int("frameskip",0); secprop->Add_bool("aspect",false); secprop->Add_string("scaler","normal2x"); MSG_Add("RENDER_CONFIGFILE_HELP", "frameskip -- How many frames dosbox skips before drawing one.\n" - "aspect -- Do aspect correction.\n" + "aspect -- Do aspect correction, if your output method doesn't support scaling this can slow things down!.\n" "scaler -- Scaler used to enlarge/enhance low resolution modes.\n" - " Supported are none,normal2x,advmame2x,advmame3x,advinterp2x,interp2x,tv2x.\n" + " Supported are none,normal2x,normal3x,advmame2x,advmame3x,advinterp2x,advinterp3x,tv2x,tv3x,rgb2x,rgb3x,scan2x,scan3x.\n" ); - secprop=control->AddSection_prop("cpu",&CPU_Init); + secprop=control->AddSection_prop("cpu",&CPU_Init,true);//done secprop->Add_string("core","normal"); - secprop->Add_int("cycles",3000); + secprop->Add_string("cycles","3000"); secprop->Add_int("cycleup",500); secprop->Add_int("cycledown",20); MSG_Add("CPU_CONFIGFILE_HELP", @@ -251,17 +287,17 @@ void DOSBOX_Init(void) { ".\n" "cycles -- Amount of instructions dosbox tries to emulate each millisecond.\n" " Setting this higher than your machine can handle is bad!\n" + " You can also let DOSBox guess the correct value by setting it to auto.\n" + " Please note that this guessing feature is still experimental.\n" "cycleup -- Amount of cycles to increase/decrease with keycombo.\n" "cycledown Setting it lower than 100 will be a percentage.\n" ); #if C_FPU secprop->AddInitFunction(&FPU_Init); #endif - secprop->AddInitFunction(&DMA_Init); + secprop->AddInitFunction(&DMA_Init);//done secprop->AddInitFunction(&VGA_Init); secprop->AddInitFunction(&KEYBOARD_Init); - secprop->AddInitFunction(&MOUSE_Init); - secprop->AddInitFunction(&JOYSTICK_Init); secprop=control->AddSection_prop("mixer",&MIXER_Init); secprop->Add_bool("nosound",false); @@ -278,27 +314,27 @@ void DOSBOX_Init(void) { "prebuffer -- How many milliseconds of data to keep on top of the blocksize.\n" ); - secprop=control->AddSection_prop("midi",&MIDI_Init); - secprop->AddInitFunction(&MPU401_Init); - secprop->Add_bool("mpu401",true); - secprop->Add_bool("intelligent",true); + secprop=control->AddSection_prop("midi",&MIDI_Init,true);//done + secprop->AddInitFunction(&MPU401_Init,true);//done + secprop->Add_string("mpu401","intelligent"); secprop->Add_string("device","default"); secprop->Add_string("config",""); MSG_Add("MIDI_CONFIGFILE_HELP", - "mpu401 -- Enable MPU-401 Emulation.\n" - "intelligent -- Operate in Intelligent mode.\n" + "mpu401 -- Type of MPU-401 to emulate: none, uart or intelligent.\n" "device -- Device that will receive the MIDI data from MPU-401.\n" " This can be default,alsa,oss,win32,coreaudio,none.\n" - "config -- Special configuration options for the device.\n" + "config -- Special configuration options for the device. In Windows put\n" + " the id of the device you want to use. See README for details.\n" ); #if C_DEBUG secprop=control->AddSection_prop("debug",&DEBUG_Init); #endif - secprop=control->AddSection_prop("sblaster",&SBLASTER_Init); - secprop->Add_string("type","sb16"); - secprop->Add_hex("base",0x220); + + secprop=control->AddSection_prop("sblaster",&SBLASTER_Init,true);//done + secprop->Add_string("sbtype","sb16"); + secprop->Add_hex("sbbase",0x220); secprop->Add_int("irq",7); secprop->Add_int("dma",1); secprop->Add_int("hdma",5); @@ -307,18 +343,19 @@ void DOSBOX_Init(void) { secprop->Add_int("oplrate",22050); MSG_Add("SBLASTER_CONFIGFILE_HELP", - "type -- Type of sblaster to emulate:none,sb1,sb2,sbpro1,sbpro2,sb16.\n" - "base,irq,dma,hdma -- The IO/IRQ/DMA/High DMA address of the soundblaster.\n" + "sbtype -- Type of sblaster to emulate:none,sb1,sb2,sbpro1,sbpro2,sb16.\n" + "sbbase,irq,dma,hdma -- The IO/IRQ/DMA/High DMA address of the soundblaster.\n" "mixer -- Allow the soundblaster mixer to modify the dosbox mixer.\n" "oplmode -- Type of OPL emulation: auto,cms,opl2,dualopl2,opl3.\n" " On auto the mode is determined by sblaster type.\n" + " All OPL modes are 'Adlib', except for CMS.\n" "oplrate -- Sample rate of OPL music emulation.\n" ); - secprop=control->AddSection_prop("gus",&GUS_Init); + secprop=control->AddSection_prop("gus",&GUS_Init,true); //done secprop->Add_bool("gus",true); - secprop->Add_int("rate",22050); - secprop->Add_hex("base",0x240); + secprop->Add_int("gusrate",22050); + secprop->Add_hex("gusbase",0x240); secprop->Add_int("irq1",5); secprop->Add_int("irq2",5); secprop->Add_int("dma1",3); @@ -327,88 +364,90 @@ void DOSBOX_Init(void) { MSG_Add("GUS_CONFIGFILE_HELP", "gus -- Enable the Gravis Ultrasound emulation.\n" - "base,irq1,irq2,dma1,dma2 -- The IO/IRQ/DMA addresses of the \n" + "gusbase,irq1,irq2,dma1,dma2 -- The IO/IRQ/DMA addresses of the \n" " Gravis Ultrasound. (Same IRQ's and DMA's are OK.)\n" - "rate -- Sample rate of Ultrasound emulation.\n" + "gusrate -- Sample rate of Ultrasound emulation.\n" "ultradir -- Path to Ultrasound directory. In this directory\n" " there should be a MIDI directory that contains\n" " the patch files for GUS playback. Patch sets used\n" " with Timidity should work fine.\n" ); - secprop=control->AddSection_prop("speaker",&PCSPEAKER_Init); + secprop=control->AddSection_prop("speaker",&PCSPEAKER_Init,true);//done secprop->Add_bool("pcspeaker",true); secprop->Add_int("pcrate",22050); - secprop->AddInitFunction(&TANDYSOUND_Init); + secprop->AddInitFunction(&TANDYSOUND_Init,true);//done + secprop->Add_string("tandy","auto"); secprop->Add_int("tandyrate",22050); - secprop->AddInitFunction(&DISNEY_Init); + secprop->AddInitFunction(&DISNEY_Init,true);//done secprop->Add_bool("disney",true); MSG_Add("SPEAKER_CONFIGFILE_HELP", "pcspeaker -- Enable PC-Speaker emulation.\n" "pcrate -- Sample rate of the PC-Speaker sound generation.\n" + "tandy -- Enable Tandy Sound System emulation (off,on,auto).\n" + " For auto Tandysound emulation is present only if machine is set to tandy.\n" "tandyrate -- Sample rate of the Tandy 3-Voice generation.\n" - " Tandysound emulation is present if machine is set to tandy.\n" "disney -- Enable Disney Sound Source emulation.\n" ); - secprop=control->AddSection_prop("bios",&BIOS_Init); + + secprop=control->AddSection_prop("bios",&BIOS_Init,false);//done + MSG_Add("BIOS_CONFIGFILE_HELP", + "joysticktype -- Type of joystick to emulate: none, 2axis, 4axis,\n" + " fcs (Thrustmaster) ,ch (CH Flightstick).\n" + " none disables joystick emulation.\n" + " 2axis is the default and supports two joysticks.\n" + ); + secprop->AddInitFunction(&INT10_Init); + secprop->AddInitFunction(&MOUSE_Init); //Must be after int10 as it uses CurMode + secprop->AddInitFunction(&JOYSTICK_Init); + secprop->Add_string("joysticktype","2axis"); + + // had to rename these to serial due to conflicts in config + secprop=control->AddSection_prop("serial",&SERIAL_Init,true); + secprop->Add_string("serial1","dummy"); + secprop->Add_string("serial2","dummy"); + secprop->Add_string("serial3","disabled"); + secprop->Add_string("serial4","disabled"); + MSG_Add("SERIAL_CONFIGFILE_HELP", + "serial1-4 -- set type of device connected to com port.\n" + " Can be disabled, dummy, modem, directserial.\n" + " Additional parameters must be in the same line in the form of\n" + " parameter:value. Parameters for all types are irq, startbps, bytesize,\n" + " stopbits, parity (all optional).\n" + " for directserial: realport (required).\n" + " for modem: listenport (optional).\n" + " Example: serial1=modem listenport:5000\n" + ); /* All the DOS Related stuff, which will eventually start up in the shell */ //TODO Maybe combine most of the dos stuff in one section like ems,xms - secprop=control->AddSection_prop("dos",&DOS_Init); - secprop->AddInitFunction(&XMS_Init); + secprop=control->AddSection_prop("dos",&DOS_Init,false);//done + secprop->AddInitFunction(&XMS_Init,true);//done secprop->Add_bool("xms",true); - secprop->AddInitFunction(&EMS_Init); + secprop->AddInitFunction(&EMS_Init,true);//done secprop->Add_bool("ems",true); + secprop->Add_string("umb","true"); MSG_Add("DOS_CONFIGFILE_HELP", "xms -- Enable XMS support.\n" "ems -- Enable EMS support.\n" + "umb -- Enable UMB support (false,true,max).\n" ); // Mscdex secprop->AddInitFunction(&MSCDEX_Init); -#if C_MODEM - secprop=control->AddSection_prop("modem",&MODEM_Init); - secprop->Add_bool("modem",false); - secprop->Add_hex("comport",2); - secprop->Add_int("listenport",23); - - MSG_Add("MODEM_CONFIGFILE_HELP", - "modem -- Enable virtual modem emulation.\n" - "comport -- COM Port modem is connected to.\n" - "listenport -- TCP Port the modem listens on for incoming connections.\n" - ); -#endif -#if C_DIRECTSERIAL - secprop=control->AddSection_prop("directserial",&DIRECTSERIAL_Init); - secprop->Add_bool("directserial", false); - secprop->Add_hex("comport",1); - secprop->Add_string("realport", "COM1"); - secprop->Add_int("defaultbps", 1200); - secprop->Add_string("parity", "N"); // Could be N, E, O - secprop->Add_int("bytesize", 8); // Could be 5 to 8 - secprop->Add_int("stopbit", 1); // Could be 1 or 2 - MSG_Add("DIRECTSERIAL_CONFIGFILE_HELP", - "directserial -- Enable serial passthrough support.\n" - "comport -- COM Port inside DOSBox.\n" - "realport -- COM Port on the Host.\n" - "defaultbps -- Default BPS.\n" - "parity -- Parity of the packets. This can be N, E or O.\n" - "bytesize -- Size of each packet. This can be 5 or 8.\n" - "stopbit -- The number of stopbits. This can be 1 or 2.\n" - ); -#endif #if C_IPX - secprop=control->AddSection_prop("ipx",&IPX_Init); + secprop=control->AddSection_prop("ipx",&IPX_Init,true); secprop->Add_bool("ipx", false); MSG_Add("IPX_CONFIGFILE_HELP", "ipx -- Enable ipx over UDP/IP emulation.\n" ); #endif +// secprop->AddInitFunction(&CREDITS_Init); + secline=control->AddSection_line("autoexec",&AUTOEXEC_Init); MSG_Add("AUTOEXEC_CONFIGFILE_HELP", "Lines in this section will be run at startup.\n" ); control->SetStartUp(&SHELL_Init); } - diff --git a/src/dosbox.ico b/src/dosbox.ico new file mode 100644 index 0000000..1602b2a Binary files /dev/null and b/src/dosbox.ico differ diff --git a/src/dosbox.rc b/src/dosbox.rc new file mode 100644 index 0000000..024db97 --- /dev/null +++ b/src/dosbox.rc @@ -0,0 +1 @@ +dosbox_ico ICON dosbox.ico diff --git a/src/fpu/Makefile.am b/src/fpu/Makefile.am index 14c2d3d..d081a68 100644 --- a/src/fpu/Makefile.am +++ b/src/fpu/Makefile.am @@ -1,4 +1,5 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libfpu.a -libfpu_a_SOURCES = fpu.cpp fpu_types.h fpu_instructions.h \ No newline at end of file +libfpu_a_SOURCES = fpu.cpp fpu_types.h fpu_instructions.h \ + fpu_instructions_x86.h diff --git a/src/fpu/Makefile.in b/src/fpu/Makefile.in index 455ded8..d6a5121 100644 --- a/src/fpu/Makefile.in +++ b/src/fpu/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -99,6 +99,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -124,10 +126,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -171,7 +175,9 @@ target_os = @target_os@ target_vendor = @target_vendor@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libfpu.a -libfpu_a_SOURCES = fpu.cpp fpu_types.h fpu_instructions.h +libfpu_a_SOURCES = fpu.cpp fpu_types.h fpu_instructions.h \ + fpu_instructions_x86.h + all: all-am .SUFFIXES: diff --git a/src/fpu/fpu.cpp b/src/fpu/fpu.cpp index 22b931e..1c326f9 100644 --- a/src/fpu/fpu.cpp +++ b/src/fpu/fpu.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: fpu.cpp,v 1.23 2004/10/12 16:19:45 qbix79 Exp $ */ +/* $Id: fpu.cpp,v 1.27 2006/02/09 11:47:48 qbix79 Exp $ */ #include "dosbox.h" #if C_FPU @@ -31,7 +31,7 @@ typedef PhysPt EAPoint; #define TOP fpu.top -#define ST(i) ( (fpu.top+ (i) ) & 7 ) +#define STV(i) ( (fpu.top+ (i) ) & 7 ) #define LoadMb(off) mem_readb(off) #define LoadMw(off) mem_readw(off) @@ -43,22 +43,20 @@ typedef PhysPt EAPoint; #include "fpu_types.h" -struct { - FPU_Reg regs[9]; - FPU_Tag tags[9]; - Bitu cw; - FPU_Round round; - Bitu ex_mask; - Bitu sw; - Bitu top; - +static struct { + FPU_Reg regs[9]; + FPU_P_Reg p_regs[9]; + FPU_Tag tags[9]; + Bit16u cw,cw_mask_all; + Bit16u sw; + Bitu top; + FPU_Round round; } fpu; -INLINE void FPU_SetCW(Bitu word) { +INLINE void FPU_SetCW(Bitu word){ fpu.cw = word; + fpu.cw_mask_all = word | 0x3f; fpu.round = (FPU_Round)((word >> 10) & 3); - // word >>8 &3 is precission - fpu.ex_mask = word & 0x3f; } static Bit16u FPU_GetTag(void){ @@ -68,22 +66,17 @@ static Bit16u FPU_GetTag(void){ return tag; } -static void FPU_SetTag(Bit16u tag) -{ +static void FPU_SetTag(Bit16u tag){ for(Bitu i=0;i<8;i++) fpu.tags[i]= static_cast((tag >>(2*i))&3); } - - - INLINE Bitu FPU_GET_TOP(void){ return (fpu.sw & 0x3800)>>11; } INLINE void FPU_SET_TOP(Bitu val){ fpu.sw &= ~0x3800; fpu.sw |= (val&7)<<11; - return; } INLINE void FPU_SET_C0(Bitu C){ @@ -103,71 +96,54 @@ INLINE void FPU_SET_C3(Bitu C){ if(C) fpu.sw |= 0x4000; } -INLINE Bitu FPU_GET_C0(void){ - return (fpu.sw & 0x0100)>>8; -} -INLINE Bitu FPU_GET_C1(void){ - return (fpu.sw & 0x0200)>>9; -} -INLINE Bitu FPU_GET_C2(void){ - return (fpu.sw & 0x0400)>>10; -} -INLINE Bitu FPU_GET_C3(void){ - return (fpu.sw & 0x4000)>>14; -} - +#if C_FPU_X86 +#include "fpu_instructions_x86.h" +#else #include "fpu_instructions.h" - -/* TODO : ESC6normal => esc4normal+pop or a define as well -*/ +#endif /* WATCHIT : ALWAYS UPDATE REGISTERS BEFORE AND AFTER USING THEM STATUS WORD => FPU_SET_TOP(TOP) BEFORE a read TOP=FPU_GET_TOP() after a write; */ + static void EATREE(Bitu _rm){ Bitu group=(_rm >> 3) & 7; /* data will allready be put in register 8 by caller */ switch(group){ - case 0x00: /* FIADD */ + case 0x00: /* FADD */ FPU_FADD(TOP, 8); break; - case 0x01: /* FIMUL */ + case 0x01: /* FMUL */ FPU_FMUL(TOP, 8); break; - case 0x02: /* FICOM */ + case 0x02: /* FCOM */ FPU_FCOM(TOP,8); break; - case 0x03: /* FICOMP */ + case 0x03: /* FCOMP */ FPU_FCOM(TOP,8); FPU_FPOP(); break; - case 0x04: /* FISUB */ + case 0x04: /* FSUB */ FPU_FSUB(TOP,8); break; - case 0x05: /* FISUBR */ + case 0x05: /* FSUBR */ FPU_FSUBR(TOP,8); break; - case 0x06: /* FIDIV */ + case 0x06: /* FDIV */ FPU_FDIV(TOP, 8); break; - case 0x07: /* FIDIVR */ + case 0x07: /* FDIVR */ FPU_FDIVR(TOP,8); break; default: break; } - } void FPU_ESC0_EA(Bitu rm,PhysPt addr) { - /* REGULAR TREE WITH 32 BITS REALS -> float */ - union { - float f; - Bit32u l; - } blah; - blah.l = mem_readd(addr); - fpu.regs[8].d = static_cast(blah.f); + /* REGULAR TREE WITH 32 BITS REALS */ + FPU_FLD_F32(addr,8); EATREE(rm); } @@ -176,33 +152,32 @@ void FPU_ESC0_Normal(Bitu rm) { Bitu sub=(rm & 7); switch (group){ case 0x00: /* FADD ST,STi */ - FPU_FADD(TOP,ST(sub)); + FPU_FADD(TOP,STV(sub)); break; case 0x01: /* FMUL ST,STi */ - FPU_FMUL(TOP,ST(sub)); + FPU_FMUL(TOP,STV(sub)); break; case 0x02: /* FCOM STi */ - FPU_FCOM(TOP,ST(sub)); + FPU_FCOM(TOP,STV(sub)); break; case 0x03: /* FCOMP STi */ - FPU_FCOM(TOP,ST(sub)); + FPU_FCOM(TOP,STV(sub)); FPU_FPOP(); break; case 0x04: /* FSUB ST,STi */ - FPU_FSUB(TOP,ST(sub)); + FPU_FSUB(TOP,STV(sub)); break; case 0x05: /* FSUBR ST,STi */ - FPU_FSUBR(TOP,ST(sub)); + FPU_FSUBR(TOP,STV(sub)); break; case 0x06: /* FDIV ST,STi */ - FPU_FDIV(TOP,ST(sub)); + FPU_FDIV(TOP,STV(sub)); break; case 0x07: /* FDIVR ST,STi */ - FPU_FDIVR(TOP,ST(sub)); + FPU_FDIVR(TOP,STV(sub)); break; default: break; - } } @@ -212,40 +187,17 @@ void FPU_ESC1_EA(Bitu rm,PhysPt addr) { Bitu sub=(rm & 7); switch(group){ case 0x00: /* FLD float*/ - { - union { - float f; - Bit32u l; - } blah; - blah.l = mem_readd(addr); - FPU_PUSH(static_cast(blah.f)); - } + FPU_PREP_PUSH(); + FPU_FLD_F32(addr,TOP); break; - case 0x01: /* UNKNOWN */ LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); break; case 0x02: /* FST float*/ - { - union { - float f; - Bit32u l; - } blah; - //should depend on rounding method - blah.f = static_cast(fpu.regs[TOP].d); - mem_writed(addr,blah.l); - } + FPU_FST_F32(addr); break; - case 0x03: /* FSTP float*/ - { - union { - float f; - Bit32u l; - } blah; - blah.f = static_cast(fpu.regs[TOP].d); - mem_writed(addr,blah.l); - } + FPU_FST_F32(addr); FPU_FPOP(); break; case 0x04: /* FLDENV */ @@ -253,7 +205,7 @@ void FPU_ESC1_EA(Bitu rm,PhysPt addr) { break; case 0x05: /* FLDCW */ { - Bit16u temp =mem_readw(addr); + Bit16u temp = mem_readw(addr); FPU_SetCW(temp); } break; @@ -267,7 +219,6 @@ void FPU_ESC1_EA(Bitu rm,PhysPt addr) { LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); break; } - } void FPU_ESC1_Normal(Bitu rm) { @@ -275,33 +226,36 @@ void FPU_ESC1_Normal(Bitu rm) { Bitu sub=(rm & 7); switch (group){ case 0x00: /* FLD STi */ - FPU_PUSH(fpu.regs[ST(sub)].d); - break; + { + Bitu reg_from=STV(sub); + FPU_PREP_PUSH(); + FPU_FST(reg_from, TOP); + break; + } case 0x01: /* FXCH STi */ - FPU_FXCH(TOP,ST(sub)); + FPU_FXCH(TOP,STV(sub)); break; case 0x02: /* FNOP */ - FPU_FNOP(); + FPU_FNOP(); break; case 0x03: /* FSTP STi */ - FPU_FST(TOP,ST(sub)); - FPU_FPOP(); + FPU_FST(TOP,STV(sub)); + FPU_FPOP(); break; case 0x04: switch(sub){ case 0x00: /* FCHS */ - fpu.regs[TOP].d = -1.0*(fpu.regs[TOP].d); + FPU_FCHS(); break; case 0x01: /* FABS */ - fpu.regs[TOP].d = fabs(fpu.regs[TOP].d); + FPU_FABS(); break; case 0x02: /* UNKNOWN */ case 0x03: /* ILLEGAL */ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); break; case 0x04: /* FTST */ - fpu.regs[8].d=0.0; - FPU_FCOM(TOP,8); + FPU_FTST(); break; case 0x05: /* FXAM */ FPU_FXAM(); @@ -315,25 +269,25 @@ void FPU_ESC1_Normal(Bitu rm) { case 0x05: switch(sub){ case 0x00: /* FLD1 */ - FPU_PUSH(1.0); + FPU_FLD1(); break; case 0x01: /* FLDL2T */ - FPU_PUSH(L2T); + FPU_FLDL2T(); break; case 0x02: /* FLDL2E */ - FPU_PUSH(L2E); + FPU_FLDL2E(); break; case 0x03: /* FLDPI */ - FPU_PUSH(PI); + FPU_FLDPI(); break; case 0x04: /* FLDLG2 */ - FPU_PUSH(LG2); + FPU_FLDLG2(); break; case 0x05: /* FLDLN2 */ - FPU_PUSH(LN2); + FPU_FLDLN2(); break; case 0x06: /* FLDZ*/ - FPU_PUSH_ZERO(); + FPU_FLDZ(); break; case 0x07: /* ILLEGAL */ LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); @@ -342,24 +296,33 @@ void FPU_ESC1_Normal(Bitu rm) { break; case 0x06: switch(sub){ - case 0x00: /* F2XM1 */ + case 0x00: /* F2XM1 */ FPU_F2XM1(); break; - case 0x01: /* FYL2X */ + case 0x01: /* FYL2X */ FPU_FYL2X(); break; - case 0x02: /* FPTAN */ + case 0x02: /* FPTAN */ FPU_FPTAN(); break; - case 0x03: /* FPATAN */ + case 0x03: /* FPATAN */ FPU_FPATAN(); break; - case 0x04: /* FXTRACT */ + case 0x04: /* FXTRACT */ FPU_FXTRACT(); break; + case 0x05: /* FPREM1 */ + FPU_FPREM1(); + break; + case 0x06: /* FDECSTP */ + TOP = (TOP - 1) & 7; + break; + case 0x07: /* FINCSTP */ + TOP = (TOP + 1) & 7; + break; default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); - break; + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; } break; case 0x07: @@ -367,6 +330,9 @@ void FPU_ESC1_Normal(Bitu rm) { case 0x00: /* FPREM */ FPU_FPREM(); break; + case 0x01: /* FYL2XP1 */ + FPU_FYL2XP1(); + break; case 0x02: /* FSQRT */ FPU_FSQRT(); break; @@ -374,12 +340,7 @@ void FPU_ESC1_Normal(Bitu rm) { FPU_FSINCOS(); break; case 0x04: /* FRNDINT */ - { -//TODO - Bit64s temp= static_cast(FROUND(fpu.regs[TOP].d)); - fpu.regs[TOP].d=static_cast(temp); - } - //TODO + FPU_FRNDINT(); break; case 0x05: /* FSCALE */ FPU_FSCALE(); @@ -390,7 +351,6 @@ void FPU_ESC1_Normal(Bitu rm) { case 0x07: /* FCOS */ FPU_FCOS(); break; - case 0x01: /* FYL2XP1 */ default: LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); break; @@ -399,15 +359,12 @@ void FPU_ESC1_Normal(Bitu rm) { default: LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); } - -// LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); } void FPU_ESC2_EA(Bitu rm,PhysPt addr) { /* 32 bits integer operants */ - Bit32s blah = mem_readd(addr); - fpu.regs[8].d = static_cast(blah); + FPU_FLD_I32(addr,8); EATREE(rm); } @@ -417,8 +374,8 @@ void FPU_ESC2_Normal(Bitu rm) { switch(group){ case 0x05: switch(sub){ - case 0x01: /* FUCOMPP Almost the same as FCOMPP */ - FPU_FCOM(TOP,ST(1)); + case 0x01: /* FUCOMPP */ + FPU_FUCOM(TOP,STV(1)); FPU_FPOP(); FPU_FPOP(); break; @@ -438,31 +395,26 @@ void FPU_ESC3_EA(Bitu rm,PhysPt addr) { Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); switch(group){ - case 0x00: /* FLD */ - { - Bit32s blah = mem_readd(addr); - FPU_PUSH( static_cast(blah)); - } + case 0x00: /* FILD */ + FPU_PREP_PUSH(); + FPU_FLD_I32(addr,TOP); break; - case 0x01: /* FISTTP */ + case 0x01: /* FISTTP */ LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); break; - - case 0x02: /* FIST */ - mem_writed(addr,static_cast(FROUND(fpu.regs[TOP].d))); + case 0x02: /* FIST */ + FPU_FST_I32(addr); break; - case 0x03: /*FISTP */ - mem_writed(addr,static_cast(FROUND(fpu.regs[TOP].d))); + case 0x03: /* FISTP */ + FPU_FST_I32(addr); FPU_FPOP(); break; case 0x05: /* FLD 80 Bits Real */ - { - Real64 val = FPU_FLD80(addr); - FPU_PUSH(val); - } + FPU_PREP_PUSH(); + FPU_FLD_F80(addr); break; case 0x07: /* FSTP 80 Bits Real */ - FPU_ST80(addr,TOP); + FPU_FST_F80(addr); FPU_FPOP(); break; default: @@ -504,41 +456,40 @@ void FPU_ESC3_Normal(Bitu rm) { void FPU_ESC4_EA(Bitu rm,PhysPt addr) { - /* REGULAR TREE WITH 64 BITS REALS: double */ - fpu.regs[8].l.lower=mem_readd(addr); - fpu.regs[8].l.upper=mem_readd(addr+4); + /* REGULAR TREE WITH 64 BITS REALS */ + FPU_FLD_F64(addr,8); EATREE(rm); } void FPU_ESC4_Normal(Bitu rm) { - //LOOKS LIKE number 6 without popping*/ + /* LOOKS LIKE number 6 without popping */ Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); switch(group){ - case 0x00: /*FADDP STi,ST*/ - FPU_FADD(ST(sub),TOP); + case 0x00: /* FADD STi,ST*/ + FPU_FADD(STV(sub),TOP); break; - case 0x01: /* FMULP STi,ST*/ - FPU_FMUL(ST(sub),TOP); + case 0x01: /* FMUL STi,ST*/ + FPU_FMUL(STV(sub),TOP); break; case 0x02: /* FCOM*/ - FPU_FCOM(TOP,ST(sub)); - break; /* TODO IS THIS ALLRIGHT ????????? (maybe reverse operators) */ + FPU_FCOM(TOP,STV(sub)); + break; case 0x03: /* FCOMP*/ - FPU_FCOM(TOP,ST(sub)); + FPU_FCOM(TOP,STV(sub)); FPU_FPOP(); break; case 0x04: /* FSUBR STi,ST*/ - FPU_FSUBR(ST(sub),TOP); + FPU_FSUBR(STV(sub),TOP); break; case 0x05: /* FSUB STi,ST*/ - FPU_FSUB(ST(sub),TOP); + FPU_FSUB(STV(sub),TOP); break; case 0x06: /* FDIVR STi,ST*/ - FPU_FDIVR(ST(sub),TOP); + FPU_FDIVR(STV(sub),TOP); break; case 0x07: /* FDIV STi,ST*/ - FPU_FDIV(ST(sub),TOP); + FPU_FDIV(STV(sub),TOP); break; default: break; @@ -550,28 +501,21 @@ void FPU_ESC5_EA(Bitu rm,PhysPt addr) { Bitu sub=(rm & 7); switch(group){ case 0x00: /* FLD double real*/ - { - FPU_Reg blah; - blah.l.lower=mem_readd(addr); - blah.l.upper=mem_readd(addr+4); - FPU_PUSH(blah.d); - } + FPU_PREP_PUSH(); + FPU_FLD_F64(addr,TOP); break; case 0x01: /* FISTTP longint*/ LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); break; - - case 0x02: /* FIST double real*/ - mem_writed(addr,fpu.regs[TOP].l.lower); - mem_writed(addr+4,fpu.regs[TOP].l.upper); + case 0x02: /* FST double real*/ + FPU_FST_F64(addr); break; - case 0x03: /*FISTP double real*/ - mem_writed(addr,fpu.regs[TOP].l.lower); - mem_writed(addr+4,fpu.regs[TOP].l.upper); + case 0x03: /* FSTP double real*/ + FPU_FST_F64(addr); FPU_FPOP(); break; - case 0x04: /* FSTOR */ - FPU_FSTOR(addr); + case 0x04: /* FRSTOR */ + FPU_FRSTOR(addr); break; case 0x06: /* FSAVE */ FPU_FSAVE(addr); @@ -591,23 +535,23 @@ void FPU_ESC5_Normal(Bitu rm) { Bitu sub=(rm & 7); switch(group){ case 0x00: /* FFREE STi */ - fpu.tags[ST(sub)]=TAG_Empty; + fpu.tags[STV(sub)]=TAG_Empty; break; case 0x01: /* FXCH STi*/ - FPU_FXCH(TOP,ST(sub)); + FPU_FXCH(TOP,STV(sub)); break; case 0x02: /* FST STi */ - FPU_FST(TOP,ST(sub)); + FPU_FST(TOP,STV(sub)); break; case 0x03: /* FSTP STi*/ - FPU_FST(TOP,ST(sub)); + FPU_FST(TOP,STV(sub)); FPU_FPOP(); break; case 0x04: /* FUCOM STi */ - FPU_FUCOM(TOP,ST(sub)); + FPU_FUCOM(TOP,STV(sub)); break; case 0x05: /*FUCOMP STi */ - FPU_FUCOM(TOP,ST(sub)); + FPU_FUCOM(TOP,STV(sub)); FPU_FPOP(); break; default: @@ -619,8 +563,7 @@ void FPU_ESC5_Normal(Bitu rm) { void FPU_ESC6_EA(Bitu rm,PhysPt addr) { /* 16 bit (word integer) operants */ - Bit16s blah = mem_readw(addr); - fpu.regs[8].d = static_cast(blah); + FPU_FLD_I16(addr,8); EATREE(rm); } @@ -631,34 +574,33 @@ void FPU_ESC6_Normal(Bitu rm) { Bitu sub=(rm & 7); switch(group){ case 0x00: /*FADDP STi,ST*/ - FPU_FADD(ST(sub),TOP); + FPU_FADD(STV(sub),TOP); break; case 0x01: /* FMULP STi,ST*/ - FPU_FMUL(ST(sub),TOP); + FPU_FMUL(STV(sub),TOP); break; case 0x02: /* FCOMP5*/ - FPU_FCOM(TOP,ST(sub)); - break; /* TODO IS THIS ALLRIGHT ????????? */ - case 0x03: /* weird*/ /*FCOMPP*/ - if(sub != 1){ - LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",group,sub); - ; - break; + FPU_FCOM(TOP,STV(sub)); + break; /* TODO IS THIS ALLRIGHT ????????? */ + case 0x03: /*FCOMPP*/ + if(sub != 1) { + LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",group,sub); + return; } - FPU_FCOM(TOP,ST(1)); + FPU_FCOM(TOP,STV(1)); FPU_FPOP(); /* extra pop at the bottom*/ break; case 0x04: /* FSUBRP STi,ST*/ - FPU_FSUBR(ST(sub),TOP); + FPU_FSUBR(STV(sub),TOP); break; case 0x05: /* FSUBP STi,ST*/ - FPU_FSUB(ST(sub),TOP); + FPU_FSUB(STV(sub),TOP); break; case 0x06: /* FDIVRP STi,ST*/ - FPU_FDIVR(ST(sub),TOP); + FPU_FDIVR(STV(sub),TOP); break; case 0x07: /* FDIVP STi,ST*/ - FPU_FDIV(ST(sub),TOP); + FPU_FDIV(STV(sub),TOP); break; default: break; @@ -668,55 +610,39 @@ void FPU_ESC6_Normal(Bitu rm) { void FPU_ESC7_EA(Bitu rm,PhysPt addr) { - /* ROUNDING*/ - Bitu group=(rm >> 3) & 7; Bitu sub=(rm & 7); switch(group){ case 0x00: /* FILD Bit16s */ - { - Bit16s blah = mem_readw(addr); - FPU_PUSH( static_cast(blah)); - } + FPU_PREP_PUSH(); + FPU_FLD_I16(addr,TOP); break; - case 0x01: /* FISTTP Bit16s */ + case 0x01: LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); break; - case 0x02: /* FIST Bit16s */ - mem_writew(addr,static_cast(FROUND(fpu.regs[TOP].d))); + FPU_FST_I16(addr); break; case 0x03: /* FISTP Bit16s */ - mem_writew(addr,static_cast(FROUND(fpu.regs[TOP].d))); + FPU_FST_I16(addr); FPU_FPOP(); break; + case 0x04: /* FBLD packed BCD */ + FPU_PREP_PUSH(); + FPU_FBLD(addr,TOP); + break; case 0x05: /* FILD Bit64s */ - { - FPU_Reg blah; - blah.l.lower = mem_readd(addr); - blah.l.upper = mem_readd(addr+4); - FPU_PUSH(static_cast(blah.ll)); - } + FPU_PREP_PUSH(); + FPU_FLD_I64(addr,TOP); break; case 0x06: /* FBSTP packed BCD */ FPU_FBST(addr); FPU_FPOP(); break; case 0x07: /* FISTP Bit64s */ - { - FPU_Reg blah; - blah.ll = static_cast(FROUND(fpu.regs[TOP].d)); - mem_writed(addr,blah.l.lower); - mem_writed(addr+4,blah.l.upper); - } + FPU_FST_I64(addr); FPU_FPOP(); break; - case 0x04: /* FBLD packed BCD */ - { - Real64 in = FPU_FBLD(addr); - FPU_PUSH(in); - } - break; default: LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); break; @@ -728,12 +654,12 @@ void FPU_ESC7_Normal(Bitu rm) { Bitu sub=(rm & 7); switch (group){ case 0x01: /* FXCH STi*/ - FPU_FXCH(TOP,ST(sub)); + FPU_FXCH(TOP,STV(sub)); break; case 0x02: /* FSTP STi*/ case 0x03: /* FSTP STi*/ - FPU_FST(TOP,ST(sub)); - FPU_FPOP(); + FPU_FST(TOP,STV(sub)); + FPU_FPOP(); break; case 0x04: switch(sub){ @@ -742,7 +668,7 @@ void FPU_ESC7_Normal(Bitu rm) { reg_ax = fpu.sw; break; default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); break; } break; @@ -750,7 +676,6 @@ void FPU_ESC7_Normal(Bitu rm) { LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); break; } - } diff --git a/src/fpu/fpu_instructions.h b/src/fpu/fpu_instructions.h index d0b500e..01cfc53 100644 --- a/src/fpu/fpu_instructions.h +++ b/src/fpu/fpu_instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,26 +16,27 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: fpu_instructions.h,v 1.25 2004/11/03 23:13:55 qbix79 Exp $ */ +/* $Id: fpu_instructions.h,v 1.28 2006/02/09 11:47:48 qbix79 Exp $ */ static void FPU_FINIT(void) { FPU_SetCW(0x37F); - fpu.sw=0; + fpu.sw = 0; TOP=FPU_GET_TOP(); - fpu.tags[0]=TAG_Empty; - fpu.tags[1]=TAG_Empty; - fpu.tags[2]=TAG_Empty; - fpu.tags[3]=TAG_Empty; - fpu.tags[4]=TAG_Empty; - fpu.tags[5]=TAG_Empty; - fpu.tags[6]=TAG_Empty; - fpu.tags[7]=TAG_Empty; - fpu.tags[8]=TAG_Valid; // is only used by us + fpu.tags[0] = TAG_Empty; + fpu.tags[1] = TAG_Empty; + fpu.tags[2] = TAG_Empty; + fpu.tags[3] = TAG_Empty; + fpu.tags[4] = TAG_Empty; + fpu.tags[5] = TAG_Empty; + fpu.tags[6] = TAG_Empty; + fpu.tags[7] = TAG_Empty; + fpu.tags[8] = TAG_Valid; // is only used by us } + static void FPU_FCLEX(void){ - fpu.sw&=0x7f00; //should clear exceptions -}; + fpu.sw &= 0x7f00; //should clear exceptions +} static void FPU_FNOP(void){ return; @@ -44,15 +45,17 @@ static void FPU_FNOP(void){ static void FPU_PUSH(double in){ TOP = (TOP - 1) &7; //actually check if empty - fpu.tags[TOP]=TAG_Valid; - fpu.regs[TOP].d=in; + fpu.tags[TOP] = TAG_Valid; + fpu.regs[TOP].d = in; // LOG(LOG_FPU,LOG_ERROR)("Pushed at %d %g to the stack",newtop,in); return; } -static void FPU_PUSH_ZERO(void){ - FPU_PUSH(0.0); - return; //maybe oneday needed + +static void FPU_PREP_PUSH(void){ + TOP = (TOP - 1) &7; + fpu.tags[TOP] = TAG_Valid; } + static void FPU_FPOP(void){ fpu.tags[TOP]=TAG_Empty; //maybe set zero in it as well @@ -61,6 +64,192 @@ static void FPU_FPOP(void){ return; } +static double FROUND(double in){ + switch(fpu.round){ + case ROUND_Nearest: + if (in-floor(in)>0.5) return (floor(in)+1); + else if (in-floor(in)<0.5) return (floor(in)); + else return (((static_cast(floor(in)))&1)!=0)?(floor(in)+1):(floor(in)); + break; + case ROUND_Down: + return (floor(in)); + break; + case ROUND_Up: + return (ceil(in)); + break; + case ROUND_Chop: + return in; //the cast afterwards will do it right maybe cast here + break; + default: + return in; + break; + } +} + +#define BIAS80 16383 +#define BIAS64 1023 + +static Real64 FPU_FLD80(PhysPt addr) { + struct { + Bit16s begin; + FPU_Reg eind; + } test; + test.eind.l.lower = mem_readd(addr); + test.eind.l.upper = mem_readd(addr+4); + test.begin = mem_readw(addr+8); + + Bit64s exp64 = (((test.begin&0x7fff) - BIAS80)); + Bit64s blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + Bit64s exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + Bit64s mant64 = (test.eind.ll >> 11) & LONGTYPE(0xfffffffffffff); + Bit64s sign = (test.begin&0x8000)?1:0; + FPU_Reg result; + result.ll = (sign <<63)|(exp64final << 52)| mant64; + return result.d; + + //mant64= test.mant80/2***64 * 2 **53 +} + +static void FPU_ST80(PhysPt addr,Bitu reg) { + struct { + Bit16s begin; + FPU_Reg eind; + } test; + Bit64s sign80 = (fpu.regs[reg].ll&LONGTYPE(0x8000000000000000))?1:0; + Bit64s exp80 = fpu.regs[reg].ll&LONGTYPE(0x7ff0000000000000); + Bit64s exp80final = (exp80>>52) - BIAS64 + BIAS80; + Bit64s mant80 = fpu.regs[reg].ll&LONGTYPE(0x000fffffffffffff); + Bit64s mant80final = (mant80 << 11); + // Elvira wants the 8 and tcalc doesn't + if(fpu.regs[reg].d != 0) mant80final |= LONGTYPE(0x8000000000000000); + test.begin= (static_cast(sign80)<<15)| static_cast(exp80final); + test.eind.ll = mant80final; + mem_writed(addr,test.eind.l.lower); + mem_writed(addr+4,test.eind.l.upper); + mem_writew(addr+8,test.begin); +} + + +static void FPU_FLD_F32(PhysPt addr,Bitu store_to) { + union { + float f; + Bit32u l; + } blah; + blah.l = mem_readd(addr); + fpu.regs[store_to].d = static_cast(blah.f); +} + +static void FPU_FLD_F64(PhysPt addr,Bitu store_to) { + fpu.regs[store_to].l.lower = mem_readd(addr); + fpu.regs[store_to].l.upper = mem_readd(addr+4); +} + +static void FPU_FLD_F80(PhysPt addr) { + fpu.regs[TOP].d = FPU_FLD80(addr); +} + +static void FPU_FLD_I16(PhysPt addr,Bitu store_to) { + Bit16s blah = mem_readw(addr); + fpu.regs[store_to].d = static_cast(blah); +} + +static void FPU_FLD_I32(PhysPt addr,Bitu store_to) { + Bit32s blah = mem_readd(addr); + fpu.regs[store_to].d = static_cast(blah); +} + +static void FPU_FLD_I64(PhysPt addr,Bitu store_to) { + FPU_Reg blah; + blah.l.lower = mem_readd(addr); + blah.l.upper = mem_readd(addr+4); + fpu.regs[store_to].d = static_cast(blah.ll); +} + +static void FPU_FBLD(PhysPt addr,Bitu store_to) { + Bit64u val = 0; + Bitu in = 0; + Bit64u base = 1; + for(Bitu i = 0;i < 9;i++){ + in = mem_readb(addr + i); + val += ( (in&0xf) * base); //in&0xf shouldn't be higher then 9 + base *= 10; + val += ((( in>>4)&0xf) * base); + base *= 10; + } + + //last number, only now convert to float in order to get + //the best signification + Real64 temp = static_cast(val); + in = mem_readb(addr + 9); + temp += ( (in&0xf) * base ); + if(in&0x80) temp *= -1.0; + fpu.regs[store_to].d = temp; +} + +static void FPU_FST_F32(PhysPt addr) { + union { + float f; + Bit32u l; + } blah; + //should depend on rounding method + blah.f = static_cast(fpu.regs[TOP].d); + mem_writed(addr,blah.l); +} + +static void FPU_FST_F64(PhysPt addr) { + mem_writed(addr,fpu.regs[TOP].l.lower); + mem_writed(addr+4,fpu.regs[TOP].l.upper); +} + +static void FPU_FST_F80(PhysPt addr) { + FPU_ST80(addr,TOP); +} + +static void FPU_FST_I16(PhysPt addr) { + mem_writew(addr,static_cast(FROUND(fpu.regs[TOP].d))); +} + +static void FPU_FST_I32(PhysPt addr) { + mem_writed(addr,static_cast(FROUND(fpu.regs[TOP].d))); +} + +static void FPU_FST_I64(PhysPt addr) { + FPU_Reg blah; + blah.ll = static_cast(FROUND(fpu.regs[TOP].d)); + mem_writed(addr,blah.l.lower); + mem_writed(addr+4,blah.l.upper); +} + +static void FPU_FBST(PhysPt addr) { + FPU_Reg val = fpu.regs[TOP]; + bool sign = false; + if(val.d<0.0){ //sign + sign=true; + val.d=-val.d; + } + //numbers from back to front + Real64 temp=val.d; + Bitu p; + for(Bitu i=0;i<9;i++){ + val.d=temp; + temp = static_cast(static_cast(floor(val.d/10.0))); + p = static_cast(val.d - 10.0*temp); + val.d=temp; + temp = static_cast(static_cast(floor(val.d/10.0))); + p |= (static_cast(val.d - 10.0*temp)<<4); + + mem_writeb(addr+i,p); + } + val.d=temp; + temp = static_cast(static_cast(floor(val.d/10.0))); + p = static_cast(val.d - 10.0*temp); + if(sign) + p|=0x80; + mem_writeb(addr+9,p); +} + + static void FPU_FADD(Bitu op1, Bitu op2){ fpu.regs[op1].d+=fpu.regs[op2].d; //flags and such :) @@ -96,9 +285,8 @@ static void FPU_FSQRT(void){ return; } static void FPU_FPATAN(void){ - fpu.regs[ST(1)].d = atan2(fpu.regs[ST(1)].d,fpu.regs[TOP].d); + fpu.regs[STV(1)].d = atan2(fpu.regs[STV(1)].d,fpu.regs[TOP].d); FPU_FPOP(); - FPU_SET_C2(0); //flags and such :) return; } @@ -154,9 +342,9 @@ static void FPU_FST(Bitu st, Bitu other){ } - static void FPU_FCOM(Bitu st, Bitu other){ - if((fpu.tags[st] != TAG_Valid) || (fpu.tags[other] != TAG_Valid)){ + if(((fpu.tags[st] != TAG_Valid) && (fpu.tags[st] != TAG_Zero)) || + ((fpu.tags[other] != TAG_Valid) && (fpu.tags[other] != TAG_Zero))){ FPU_SET_C3(1);FPU_SET_C2(1);FPU_SET_C0(1);return; } if(fpu.regs[st].d == fpu.regs[other].d){ @@ -174,31 +362,14 @@ static void FPU_FUCOM(Bitu st, Bitu other){ FPU_FCOM(st,other); } -static double FROUND(double in){ - switch(fpu.round){ - case ROUND_Nearest: - if (in-floor(in)>0.5) return (floor(in)+1); - else if (in-floor(in)<0.5) return (floor(in)); - else return (((static_cast(floor(in)))&1)!=0)?(floor(in)+1):(floor(in)); - break; - case ROUND_Down: - return (floor(in)); - break; - case ROUND_Up: - return (ceil(in)); - break; - case ROUND_Chop: - return in; //the cast afterwards will do it right maybe cast here - break; - default: - return in; - break; - } +static void FPU_FRNDINT(void){ + Bit64s temp= static_cast(FROUND(fpu.regs[TOP].d)); + fpu.regs[TOP].d=static_cast(temp); } static void FPU_FPREM(void){ Real64 valtop = fpu.regs[TOP].d; - Real64 valdiv = fpu.regs[ST(1)].d; + Real64 valdiv = fpu.regs[STV(1)].d; Bit64s ressaved = static_cast( (valtop/valdiv) ); // Some backups // Real64 res=valtop - ressaved*valdiv; @@ -210,143 +381,71 @@ static void FPU_FPREM(void){ FPU_SET_C2(0); } +static void FPU_FPREM1(void){ + Real64 valtop = fpu.regs[TOP].d; + Real64 valdiv = fpu.regs[STV(1)].d; + double quot = valtop/valdiv; + double quotf = floor(quot); + Bit64s ressaved; + if (quot-quotf>0.5) ressaved = static_cast(quotf+1); + else if (quot-quotf<0.5) ressaved = static_cast(quotf); + else ressaved = static_cast((((static_cast(quotf))&1)!=0)?(quotf+1):(quotf)); + fpu.regs[TOP].d = valtop - ressaved*valdiv; + FPU_SET_C0(static_cast(ressaved&4)); + FPU_SET_C3(static_cast(ressaved&2)); + FPU_SET_C1(static_cast(ressaved&1)); + FPU_SET_C2(0); +} + static void FPU_FXAM(void){ - if(fpu.tags[TOP] == TAG_Empty) - { - FPU_SET_C3(1);FPU_SET_C0(1); - return; - } if(fpu.regs[TOP].ll & LONGTYPE(0x8000000000000000)) //sign { FPU_SET_C1(1); - } - else + } + else { FPU_SET_C1(0); } + if(fpu.tags[TOP] == TAG_Empty) + { + FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1); + return; + } if(fpu.regs[TOP].d == 0.0) //zero or normalized number. { FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(0); } - else{ + else + { FPU_SET_C3(0);FPU_SET_C2(1);FPU_SET_C0(0); } } -static void FPU_FBST(PhysPt addr) -{ - FPU_Reg val = fpu.regs[TOP]; - bool sign = false; - if(val.d<0.0){ //sign - sign=true; - val.d=-val.d; - } - //numbers from back to front - Real64 temp=val.d; - Bitu p; - for(Bitu i=0;i<9;i++){ - val.d=temp; - temp = static_cast(static_cast(floor(val.d/10.0))); - p = static_cast(val.d - 10.0*temp); - val.d=temp; - temp = static_cast(static_cast(floor(val.d/10.0))); - p |= (static_cast(val.d - 10.0*temp)<<4); - - mem_writeb(addr+i,p); - } - val.d=temp; - temp = static_cast(static_cast(floor(val.d/10.0))); - p = static_cast(val.d - 10.0*temp); - if(sign) - p|=0x80; - mem_writeb(addr+9,p); -} - -static Real64 FPU_FBLD(PhysPt addr) -{ - Bit64u val = 0; - Bitu in = 0; - Bit64u base = 1; - for(Bitu i = 0;i < 9;i++){ - in = mem_readb(addr + i); - val += ( (in&0xf) * base); //in&0xf shouldn't be higher then 9 - base *= 10; - val += ((( in>>4)&0xf) * base); - base *= 10; - } - - //last number, only now convert to float in order to get - //the best signification - Real64 temp = static_cast(val); - in = mem_readb(addr + 9); - temp += ( (in&0xf) * base ); - if(in&0x80) temp *= -1.0; - return temp; -} - - -#define BIAS80 16383 -#define BIAS64 1023 - -static Real64 FPU_FLD80(PhysPt addr) -{ - struct{ - Bit16s begin; - FPU_Reg eind; - } test; - test.eind.l.lower=mem_readd(addr); - test.eind.l.upper =mem_readd(addr+4); - test.begin=mem_readw(addr+8); - - Bit64s exp64= (((test.begin & 0x7fff) - BIAS80)); - Bit64s blah= ((exp64 >0)?exp64:-exp64)&0x3ff; - Bit64s exp64final= ((exp64 >0)?blah:-blah) +BIAS64; - - Bit64s mant64= (test.eind.ll >> 11) & LONGTYPE(0xfffffffffffff); - Bit64s sign = (test.begin &0x8000)?1:0; - FPU_Reg result; - result.ll= (sign <<63)|(exp64final << 52)| mant64; - return result.d; - - //mant64= test.mant80/2***64 * 2 **53 -} - -static void FPU_ST80(PhysPt addr,Bitu reg) -{ - struct{ - Bit16s begin; - FPU_Reg eind; - } test; - Bit64s sign80= (fpu.regs[reg].ll&LONGTYPE(0x8000000000000000))?1:0; - Bit64s exp80 = fpu.regs[reg].ll&LONGTYPE(0x7ff0000000000000); - Bit64s exp80final= (exp80>>52) - BIAS64 + BIAS80; - Bit64s mant80 = fpu.regs[reg].ll&LONGTYPE(0x000fffffffffffff); - Bit64s mant80final= (mant80 << 11); - // Elvira wants the 8 and tcalc doesn't - if(fpu.regs[reg].d != 0) mant80final |= LONGTYPE(0x8000000000000000); - test.begin= (static_cast(sign80)<<15)| static_cast(exp80final); - test.eind.ll=mant80final; - mem_writed(addr,test.eind.l.lower); - mem_writed(addr+4,test.eind.l.upper); - mem_writew(addr+8,test.begin); -} static void FPU_F2XM1(void){ - fpu.regs[TOP].d=pow(2.0,fpu.regs[TOP].d) -1; + fpu.regs[TOP].d = pow(2.0,fpu.regs[TOP].d) - 1; return; } static void FPU_FYL2X(void){ - fpu.regs[ST(1)].d*=log(fpu.regs[TOP].d)/log(static_cast(2.0)); + fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d)/log(static_cast(2.0)); FPU_FPOP(); return; } + +static void FPU_FYL2XP1(void){ + fpu.regs[STV(1)].d*=log(fpu.regs[TOP].d+1.0)/log(static_cast(2.0)); + FPU_FPOP(); + return; +} + static void FPU_FSCALE(void){ - fpu.regs[TOP].d *= pow(2.0,static_cast(static_cast(fpu.regs[ST(1)].d))); + fpu.regs[TOP].d *= pow(2.0,static_cast(static_cast(fpu.regs[STV(1)].d))); return; //2^x where x is chopped. } static void FPU_FSTENV(PhysPt addr){ + FPU_SET_TOP(TOP); if(!cpu.code.big) { mem_writew(addr+0,static_cast(fpu.cw)); mem_writew(addr+2,static_cast(fpu.sw)); @@ -368,29 +467,31 @@ static void FPU_FLDENV(PhysPt addr){ tag = mem_readw(addr+4); } else { cw = mem_readd(addr+0); - fpu.sw = mem_readd(addr+4); + fpu.sw = (Bit16u)mem_readd(addr+4); tagbig = mem_readd(addr+8); tag = static_cast(tagbig); } FPU_SetTag(tag); FPU_SetCW(cw); + TOP = FPU_GET_TOP(); } static void FPU_FSAVE(PhysPt addr){ FPU_FSTENV(addr); - Bitu start=(cpu.code.big?28:14); - for(Bitu i=0;i<8;i++){ - FPU_ST80(addr+start,i); - start+=10; + Bitu start = (cpu.code.big?28:14); + for(Bitu i = 0;i < 8;i++){ + FPU_ST80(addr+start,STV(i)); + start += 10; } + FPU_FINIT(); } -static void FPU_FSTOR(PhysPt addr){ +static void FPU_FRSTOR(PhysPt addr){ FPU_FLDENV(addr); - Bitu start=(cpu.code.big?28:14); - for(Bitu i=0;i<8;i++){ - fpu.regs[i].d=FPU_FLD80(addr+start); - start+=10; + Bitu start = (cpu.code.big?28:14); + for(Bitu i = 0;i < 8;i++){ + fpu.regs[STV(i)].d = FPU_FLD80(addr+start); + start += 10; } } @@ -403,6 +504,55 @@ static void FPU_FXTRACT(void) { Bit64s exp80 = test.ll&LONGTYPE(0x7ff0000000000000); Bit64s exp80final = (exp80>>52) - BIAS64; Real64 mant = test.d / (pow(2.0,static_cast(exp80final))); - fpu.regs[TOP].d=exp80final; + fpu.regs[TOP].d = static_cast(exp80final); FPU_PUSH(mant); } + +static void FPU_FCHS(void){ + fpu.regs[TOP].d = -1.0*(fpu.regs[TOP].d); +} + +static void FPU_FABS(void){ + fpu.regs[TOP].d = fabs(fpu.regs[TOP].d); +} + +static void FPU_FTST(void){ + fpu.regs[8].d = 0.0; + FPU_FCOM(TOP,8); +} + +static void FPU_FLD1(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = 1.0; +} + +static void FPU_FLDL2T(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = L2T; +} + +static void FPU_FLDL2E(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = L2E; +} + +static void FPU_FLDPI(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = PI; +} + +static void FPU_FLDLG2(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = LG2; +} + +static void FPU_FLDLN2(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = LN2; +} + +static void FPU_FLDZ(void){ + FPU_PREP_PUSH(); + fpu.regs[TOP].d = 0.0; + fpu.tags[TOP] = TAG_Zero; +} diff --git a/src/fpu/fpu_instructions_x86.h b/src/fpu/fpu_instructions_x86.h new file mode 100644 index 0000000..a251c0c --- /dev/null +++ b/src/fpu/fpu_instructions_x86.h @@ -0,0 +1,1060 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: fpu_instructions_x86.h,v 1.3 2006/02/09 11:47:48 qbix79 Exp $ */ + + +#define WEAK_EXCEPTIONS + + +#if defined (_MSC_VER) + +#ifdef WEAK_EXCEPTIONS +#define clx +#else +#define clx fclex +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_LOAD(op,szI,szA) \ + __asm { \ + __asm mov eax, 8 \ + __asm shl eax, 4 \ + __asm mov ebx, store_to \ + __asm shl ebx, 4 \ + __asm op szI PTR fpu.p_regs[eax].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } +#else +#define FPUD_LOAD(op,szI,szA) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, 8 \ + __asm shl eax, 4 \ + __asm mov ebx, store_to \ + __asm shl ebx, 4 \ + __asm fclex \ + __asm op szI PTR fpu.p_regs[eax].m1 \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +#define FPUD_STORE(op,szI,szA) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm mov ebx, 8 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op szI PTR fpu.p_regs[ebx].m1 \ + __asm fnstsw new_sw \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsin,fcos,f2xm1,fchs,fabs +#define FPUD_TRIG(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsincos +#define FPUD_SINCOS() \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm fsincos \ + __asm fnstsw new_sw \ + __asm mov cx, new_sw \ + __asm and ch, 0x04 \ + __asm jnz argument_too_large1 \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm jmp end_sincos \ + __asm argument_too_large1: \ + __asm fstp st(0) \ + __asm end_sincos: \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fptan +#define FPUD_PTAN() \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm fptan \ + __asm fnstsw new_sw \ + __asm mov cx, new_sw \ + __asm and ch, 0x04 \ + __asm jnz argument_too_large2 \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm jmp end_ptan \ + __asm argument_too_large2: \ + __asm fstp st(0) \ + __asm end_ptan: \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fxtract +#ifdef WEAK_EXCEPTIONS +#define FPUD_XTRACT \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fxtract \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + FPU_PREP_PUSH(); +#else +#define FPUD_XTRACT \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm dec ebx \ + __asm and ebx, 7 \ + __asm shl eax, 4 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm fxtract \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_PREP_PUSH(); +#endif + +// handles fadd,fmul,fsub,fsubr +#define FPUD_ARITH1(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm clx \ + __asm op st(1), st(0) \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsqrt,frndint +#define FPUD_ARITH2(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fdiv,fdivr +#define FPUD_ARITH3(op) \ + Bit16u new_sw,save_cw; \ + __asm { \ + __asm fnstcw save_cw \ + __asm fldcw fpu.cw_mask_all \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fclex \ + __asm op st(1), st(0) \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fldcw save_cw \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); + +// handles fprem,fprem1,fscale +#define FPUD_REMINDER(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fstp st(0) \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); + +// handles fcom,fucom +#define FPUD_COMPARE(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov ebx, op2 \ + __asm shl ebx, 4 \ + __asm mov eax, op1 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fxam,ftst +#define FPUD_EXAMINE(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm clx \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp st(0) \ + } \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fpatan,fyl2xp1 +#ifdef WEAK_EXCEPTIONS +#define FPUD_WITH_POP(op) \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm op \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + FPU_FPOP(); +#else +#define FPUD_WITH_POP(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); +#endif + +// handles fyl2x +#define FPUD_FYL2X(op) \ + Bit16u new_sw; \ + __asm { \ + __asm mov eax, TOP \ + __asm mov ebx, eax \ + __asm inc ebx \ + __asm and ebx, 7 \ + __asm shl ebx, 4 \ + __asm shl eax, 4 \ + __asm fld TBYTE PTR fpu.p_regs[ebx].m1 \ + __asm fld TBYTE PTR fpu.p_regs[eax].m1 \ + __asm fclex \ + __asm op \ + __asm fnstsw new_sw \ + __asm fstp TBYTE PTR fpu.p_regs[ebx].m1 \ + } \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); + +// load math constants +#define FPUD_LOAD_CONST(op) \ + FPU_PREP_PUSH(); \ + __asm { \ + __asm mov eax, TOP \ + __asm shl eax, 4 \ + __asm clx \ + __asm op \ + __asm fstp TBYTE PTR fpu.p_regs[eax].m1 \ + } \ + +#else + +#ifdef WEAK_EXCEPTIONS +#define clx +#else +#define clx "fclex" +#endif + +#ifdef WEAK_EXCEPTIONS +#define FPUD_LOAD(op,szI,szA) \ + __asm__ volatile ( \ + "movl $8, %%eax \n" \ + "shl $4, %%eax \n" \ + "shl $4, %0 \n" \ + #op #szA " (%1, %%eax) \n" \ + "fstpt (%1, %0) " \ + : \ + : "r" (store_to), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); +#else +#define FPUD_LOAD(op,szI,szA) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl $8, %%eax \n" \ + "shl $4, %%eax \n" \ + "shl $4, %1 \n" \ + "fclex \n" \ + #op #szA " (%2, %%eax) \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %1) " \ + : "=m" (new_sw) \ + : "r" (store_to), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); +#endif + +#define FPUD_STORE(op,szI,szA) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "movl $8, %%eax \n" \ + "shl $4, %%eax \n" \ + "fldt (%3, %2) \n" \ + clx" \n" \ + #op #szA " (%3, %%eax) \n" \ + "fnstsw %0 \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsin,fcos,f2xm1,fchs,fabs +#define FPUD_TRIG(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %1) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsincos +#define FPUD_SINCOS() \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "shll $4, %1 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + "fsincos \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + "movw %0, %%ax \n" \ + "sahf \n" \ + "jp argument_too_large1 \n" \ + "fstpt (%2, %1) \n" \ + "argument_too_large1: " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "cc", "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fptan +#define FPUD_PTAN() \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "shll $4, %1 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + "fptan \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + "movw %0, %%ax \n" \ + "sahf \n" \ + "jp argument_too_large2 \n" \ + "fstpt (%2, %1) \n" \ + "argument_too_large2: " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "cc", "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); \ + if ((new_sw&0x0400)==0) FPU_PREP_PUSH(); + +// handles fxtract +#ifdef WEAK_EXCEPTIONS +#define FPUD_XTRACT \ + __asm__ volatile ( \ + "movl %0, %%eax \n" \ + "shll $4, %0 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%1, %0) \n" \ + "fxtract \n" \ + "fstpt (%1, %%eax) \n" \ + "fstpt (%1, %0) " \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + FPU_PREP_PUSH(); +#else +#define FPUD_XTRACT \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "shll $4, %1 \n" \ + "decl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + "fxtract \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + "fstpt (%2, %1) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_PREP_PUSH(); +#endif + +// handles fadd,fmul,fsub,fsubr +#define FPUD_ARITH1(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %5 \n" \ + "shll $4, %3 \n" \ + "shll $4, %2 \n" \ + "fldt (%4, %3) \n" \ + "fldt (%4, %2) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%4, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fsqrt,frndint +#define FPUD_ARITH2(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %4 \n" \ + "shll $4, %2 \n" \ + "fldt (%3, %2) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%3, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (TOP), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fdiv,fdivr +#define FPUD_ARITH3(op) \ + Bit16u new_sw,save_cw; \ + __asm__ volatile ( \ + "fnstcw %1 \n" \ + "fldcw %5 \n" \ + "shll $4, %3 \n" \ + "shll $4, %2 \n" \ + "fldt (%4, %3) \n" \ + "fldt (%4, %2) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%4, %2) \n" \ + "fldcw %1 " \ + : "=m" (new_sw), "=m" (save_cw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs), "m" (fpu.cw_mask_all) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); + +// handles fprem,fprem1,fscale +#define FPUD_REMINDER(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %%eax) \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %1) \n" \ + "fstp %%st(0) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); + +// handles fcom,fucom +#define FPUD_COMPARE(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %2 \n" \ + "shll $4, %1 \n" \ + "fldt (%3, %2) \n" \ + "fldt (%3, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 " \ + : "=m" (new_sw) \ + : "r" (op1), "r" (op2), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fxam,ftst +#define FPUD_EXAMINE(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "shll $4, %1 \n" \ + "fldt (%2, %1) \n" \ + clx" \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstp %%st(0) " \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "memory" \ + ); \ + fpu.sw=(new_sw&exc_mask)|(fpu.sw&0x80ff); + +// handles fpatan,fyl2xp1 +#ifdef WEAK_EXCEPTIONS +#define FPUD_WITH_POP(op) \ + __asm__ volatile ( \ + "movl %0, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %0 \n" \ + "fldt (%1, %%eax) \n" \ + "fldt (%1, %0) \n" \ + #op" \n" \ + "fstpt (%1, %%eax) \n" \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + FPU_FPOP(); +#else +#define FPUD_WITH_POP(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %%eax) \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); +#endif + +// handles fyl2x +#define FPUD_FYL2X(op) \ + Bit16u new_sw; \ + __asm__ volatile ( \ + "movl %1, %%eax \n" \ + "incl %%eax \n" \ + "andl $7, %%eax \n" \ + "shll $4, %%eax \n" \ + "shll $4, %1 \n" \ + "fldt (%2, %%eax) \n" \ + "fldt (%2, %1) \n" \ + "fclex \n" \ + #op" \n" \ + "fnstsw %0 \n" \ + "fstpt (%2, %%eax) \n" \ + : "=m" (new_sw) \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "eax", "memory" \ + ); \ + fpu.sw=(new_sw&0xffbf)|(fpu.sw&0x80ff); \ + FPU_FPOP(); + +// load math constants +#define FPUD_LOAD_CONST(op) \ + FPU_PREP_PUSH(); \ + __asm__ volatile ( \ + "shll $4, %0 \n" \ + clx" \n" \ + #op" \n" \ + "fstpt (%1, %0) \n" \ + : \ + : "r" (TOP), "r" (fpu.p_regs) \ + : "memory" \ + ); + +#endif + +#ifdef WEAK_EXCEPTIONS +const Bit16u exc_mask=0x7f00; +#else +const Bit16u exc_mask=0xffbf; +#endif + +static void FPU_FINIT(void) { + FPU_SetCW(0x37F); + fpu.sw=0; + TOP=FPU_GET_TOP(); + fpu.tags[0]=TAG_Empty; + fpu.tags[1]=TAG_Empty; + fpu.tags[2]=TAG_Empty; + fpu.tags[3]=TAG_Empty; + fpu.tags[4]=TAG_Empty; + fpu.tags[5]=TAG_Empty; + fpu.tags[6]=TAG_Empty; + fpu.tags[7]=TAG_Empty; + fpu.tags[8]=TAG_Valid; // is only used by us +} + +static void FPU_FCLEX(void){ + fpu.sw&=0x7f00; //should clear exceptions +} + +static void FPU_FNOP(void){ +} + +static void FPU_PREP_PUSH(void){ + TOP = (TOP - 1) &7; + fpu.tags[TOP]=TAG_Valid; +} + +static void FPU_FPOP(void){ + fpu.tags[TOP]=TAG_Empty; + TOP = ((TOP+1)&7); +} + +static void FPU_FLD_F32(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + FPUD_LOAD(fld,DWORD,s) +} + +static void FPU_FLD_F64(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + FPUD_LOAD(fld,QWORD,l) +} + +static void FPU_FLD_F80(PhysPt addr) { + fpu.p_regs[TOP].m1 = mem_readd(addr); + fpu.p_regs[TOP].m2 = mem_readd(addr+4); + fpu.p_regs[TOP].m3 = mem_readw(addr+8); + FPU_SET_C1(0); +} + +static void FPU_FLD_I16(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = (Bit32u)mem_readw(addr); + FPUD_LOAD(fild,WORD,) +} + +static void FPU_FLD_I32(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + FPUD_LOAD(fild,DWORD,l) +} + +static void FPU_FLD_I64(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + FPUD_LOAD(fild,QWORD,q) +} + +static void FPU_FBLD(PhysPt addr,Bitu store_to) { + fpu.p_regs[8].m1 = mem_readd(addr); + fpu.p_regs[8].m2 = mem_readd(addr+4); + fpu.p_regs[8].m3 = mem_readw(addr+8); + FPUD_LOAD(fbld,TBYTE,) +} + +static void FPU_FST_F32(PhysPt addr) { + FPUD_STORE(fstp,DWORD,s) + mem_writed(addr,fpu.p_regs[8].m1); +} + +static void FPU_FST_F64(PhysPt addr) { + FPUD_STORE(fstp,QWORD,l) + mem_writed(addr,fpu.p_regs[8].m1); + mem_writed(addr+4,fpu.p_regs[8].m2); +} + +static void FPU_FST_F80(PhysPt addr) { + mem_writed(addr,fpu.p_regs[TOP].m1); + mem_writed(addr+4,fpu.p_regs[TOP].m2); + mem_writew(addr+8,fpu.p_regs[TOP].m3); + FPU_SET_C1(0); +} + +static void FPU_FST_I16(PhysPt addr) { + FPUD_STORE(fistp,WORD,) + mem_writew(addr,(Bit16u)fpu.p_regs[8].m1); +} + +static void FPU_FST_I32(PhysPt addr) { + FPUD_STORE(fistp,DWORD,l) + mem_writed(addr,fpu.p_regs[8].m1); +} + +static void FPU_FST_I64(PhysPt addr) { + FPUD_STORE(fistp,QWORD,q) + mem_writed(addr,fpu.p_regs[8].m1); + mem_writed(addr+4,fpu.p_regs[8].m2); +} + +static void FPU_FBST(PhysPt addr) { + FPUD_STORE(fbstp,TBYTE,) + mem_writed(addr,fpu.p_regs[8].m1); + mem_writed(addr+4,fpu.p_regs[8].m2); + mem_writew(addr+8,fpu.p_regs[8].m3); +} + + +static void FPU_FSIN(void){ + FPUD_TRIG(fsin) +} + +static void FPU_FSINCOS(void){ + FPUD_SINCOS() +} + +static void FPU_FCOS(void){ + FPUD_TRIG(fcos) +} + +static void FPU_FSQRT(void){ + FPUD_ARITH2(fsqrt) +} + +static void FPU_FPATAN(void){ + FPUD_WITH_POP(fpatan) +} + +static void FPU_FPTAN(void){ + FPUD_PTAN() +} + + +static void FPU_FADD(Bitu op1, Bitu op2){ + FPUD_ARITH1(faddp) +} + +static void FPU_FDIV(Bitu op1, Bitu op2){ + FPUD_ARITH3(fdivp) +} + +static void FPU_FDIVR(Bitu op1, Bitu op2){ + FPUD_ARITH3(fdivrp) +} + +static void FPU_FMUL(Bitu op1, Bitu op2){ + FPUD_ARITH1(fmulp) +} + +static void FPU_FSUB(Bitu op1, Bitu op2){ + FPUD_ARITH1(fsubp) +} + +static void FPU_FSUBR(Bitu op1, Bitu op2){ + FPUD_ARITH1(fsubrp) +} + +static void FPU_FXCH(Bitu stv, Bitu other){ + FPU_Tag tag = fpu.tags[other]; + fpu.tags[other] = fpu.tags[stv]; + fpu.tags[stv] = tag; + + Bit32u m1s = fpu.p_regs[other].m1; + Bit32u m2s = fpu.p_regs[other].m2; + Bit16u m3s = fpu.p_regs[other].m3; + fpu.p_regs[other].m1 = fpu.p_regs[stv].m1; + fpu.p_regs[other].m2 = fpu.p_regs[stv].m2; + fpu.p_regs[other].m3 = fpu.p_regs[stv].m3; + fpu.p_regs[stv].m1 = m1s; + fpu.p_regs[stv].m2 = m2s; + fpu.p_regs[stv].m3 = m3s; + + FPU_SET_C1(0); +} + +static void FPU_FST(Bitu stv, Bitu other){ + fpu.tags[other] = fpu.tags[stv]; + + fpu.p_regs[other].m1 = fpu.p_regs[stv].m1; + fpu.p_regs[other].m2 = fpu.p_regs[stv].m2; + fpu.p_regs[other].m3 = fpu.p_regs[stv].m3; + + FPU_SET_C1(0); +} + + +static void FPU_FCOM(Bitu op1, Bitu op2){ + FPUD_COMPARE(fcompp) +} + +static void FPU_FUCOM(Bitu op1, Bitu op2){ + FPUD_COMPARE(fucompp) +} + +static void FPU_FRNDINT(void){ + FPUD_ARITH2(frndint) +} + +static void FPU_FPREM(void){ + FPUD_REMINDER(fprem) +} + +static void FPU_FPREM1(void){ + FPUD_REMINDER(fprem1) +} + +static void FPU_FXAM(void){ + FPUD_EXAMINE(fxam) + // handle empty registers (C1 set to sign in any way!) + if(fpu.tags[TOP] == TAG_Empty) { + FPU_SET_C3(1);FPU_SET_C2(0);FPU_SET_C0(1); + return; + } +} + +static void FPU_F2XM1(void){ + FPUD_TRIG(f2xm1) +} + +static void FPU_FYL2X(void){ + FPUD_FYL2X(fyl2x) +} + +static void FPU_FYL2XP1(void){ + FPUD_WITH_POP(fyl2xp1) +} + +static void FPU_FSCALE(void){ + FPUD_REMINDER(fscale) +} + + +static void FPU_FSTENV(PhysPt addr){ + FPU_SET_TOP(TOP); + if(!cpu.code.big) { + mem_writew(addr+0,static_cast(fpu.cw)); + mem_writew(addr+2,static_cast(fpu.sw)); + mem_writew(addr+4,static_cast(FPU_GetTag())); + } else { + mem_writed(addr+0,static_cast(fpu.cw)); + mem_writed(addr+4,static_cast(fpu.sw)); + mem_writed(addr+8,static_cast(FPU_GetTag())); + } +} + +static void FPU_FLDENV(PhysPt addr){ + Bit16u tag; + Bit32u tagbig; + Bitu cw; + if(!cpu.code.big) { + cw = mem_readw(addr+0); + fpu.sw = mem_readw(addr+2); + tag = mem_readw(addr+4); + } else { + cw = mem_readd(addr+0); + fpu.sw = (Bit16u)mem_readd(addr+4); + tagbig = mem_readd(addr+8); + tag = static_cast(tagbig); + } + FPU_SetTag(tag); + FPU_SetCW(cw); + TOP=FPU_GET_TOP(); +} + +static void FPU_FSAVE(PhysPt addr){ + FPU_FSTENV(addr); + Bitu start=(cpu.code.big?28:14); + for(Bitu i=0;i<8;i++){ + mem_writed(addr+start,fpu.p_regs[STV(i)].m1); + mem_writed(addr+start+4,fpu.p_regs[STV(i)].m2); + mem_writew(addr+start+8,fpu.p_regs[STV(i)].m3); + start+=10; + } + FPU_FINIT(); +} + +static void FPU_FRSTOR(PhysPt addr){ + FPU_FLDENV(addr); + Bitu start=(cpu.code.big?28:14); + for(Bitu i=0;i<8;i++){ + fpu.p_regs[STV(i)].m1 = mem_readd(addr+start); + fpu.p_regs[STV(i)].m2 = mem_readd(addr+start+4); + fpu.p_regs[STV(i)].m3 = mem_readw(addr+start+8); + start+=10; + } +} + + +static void FPU_FXTRACT(void) { + FPUD_XTRACT +} + +static void FPU_FCHS(void){ + FPUD_TRIG(fchs) +} + +static void FPU_FABS(void){ + FPUD_TRIG(fabs) +} + +static void FPU_FTST(void){ + FPUD_EXAMINE(ftst) +} + +static void FPU_FLD1(void){ + FPUD_LOAD_CONST(fld1) +} + +static void FPU_FLDL2T(void){ + FPUD_LOAD_CONST(fldl2t) +} + +static void FPU_FLDL2E(void){ + FPUD_LOAD_CONST(fldl2e) +} + +static void FPU_FLDPI(void){ + FPUD_LOAD_CONST(fldpi) +} + +static void FPU_FLDLG2(void){ + FPUD_LOAD_CONST(fldlg2) +} + +static void FPU_FLDLN2(void){ + FPUD_LOAD_CONST(fldln2) +} + +static void FPU_FLDZ(void){ + FPUD_LOAD_CONST(fldz) + fpu.tags[TOP]=TAG_Zero; +} diff --git a/src/fpu/fpu_types.h b/src/fpu/fpu_types.h index 16a4d74..aee173b 100644 --- a/src/fpu/fpu_types.h +++ b/src/fpu/fpu_types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: fpu_types.h,v 1.13 2006/02/09 11:47:48 qbix79 Exp $ */ typedef union { double d; #ifndef WORDS_BIGENDIAN @@ -32,6 +33,15 @@ typedef union { Bit64s ll; } FPU_Reg; +typedef struct { + Bit32u m1; + Bit32u m2; + Bit16u m3; + + Bit16u d1; + Bit32u d2; +} FPU_P_Reg; + enum FPU_Tag { TAG_Valid = 0, TAG_Zero = 1, @@ -39,13 +49,13 @@ enum FPU_Tag { TAG_Empty = 3 }; - enum FPU_Round { ROUND_Nearest = 0, ROUND_Down = 1, ROUND_Up = 2, ROUND_Chop = 3 }; + //get pi from a real library #define PI 3.14159265358979323846 #define L2E 1.4426950408889634 diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am index 8d76e38..12695b1 100644 --- a/src/gui/Makefile.am +++ b/src/gui/Makefile.am @@ -1,7 +1,8 @@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libgui.a -libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp \ - render.cpp render_scalers.cpp render_scalers.h render_templates.h \ +libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp dosbox_logo.h \ + render.cpp render_scalers.cpp render_scalers.h \ + render_templates.h render_loops.h render_simple.h \ midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h diff --git a/src/gui/Makefile.in b/src/gui/Makefile.in index f65852e..8ab9d14 100644 --- a/src/gui/Makefile.in +++ b/src/gui/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -100,6 +100,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -125,10 +127,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -172,8 +176,9 @@ target_os = @target_os@ target_vendor = @target_vendor@ AM_CPPFLAGS = -I$(top_srcdir)/include noinst_LIBRARIES = libgui.a -libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp \ - render.cpp render_scalers.cpp render_scalers.h render_templates.h \ +libgui_a_SOURCES = sdlmain.cpp sdl_mapper.cpp dosbox_logo.h \ + render.cpp render_scalers.cpp render_scalers.h \ + render_templates.h render_loops.h render_simple.h \ midi.cpp midi_win32.h midi_oss.h midi_coreaudio.h midi_alsa.h all: all-am diff --git a/src/gui/dosbox_logo.h b/src/gui/dosbox_logo.h new file mode 100644 index 0000000..4a96e0d --- /dev/null +++ b/src/gui/dosbox_logo.h @@ -0,0 +1,541 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: dosbox_logo.h,v 1.3 2006/03/29 12:26:41 qbix79 Exp $ */ + +/* DOSBox icon designed by Ido Beeri */ + +/* Select only one logo at the time */ +#define LOGO_1 1 +//#define LOGO_2 1 +#ifdef LOGO_1 + 65, 44, 25,0, 65, 44, 25,0, 93, 58, 30,0, 93, 58, 30,0 +, 92, 57, 30,0, 92, 57, 30,0, 98, 59, 28,0, 98, 59, 28,0 +, 97, 58, 29,0, 97, 58, 29,0, 97, 60, 30,0, 97, 60, 30,0 +, 97, 60, 30,0, 97, 60, 30,0, 96, 59, 29,0, 96, 59, 29,0 +, 91, 55, 26,0, 91, 55, 26,0, 96, 60, 29,0, 96, 60, 29,0 +, 93, 58, 28,0, 93, 58, 28,0, 93, 57, 27,0, 93, 57, 27,0 +, 93, 56, 27,0, 93, 56, 27,0, 85, 52, 25,0, 85, 52, 25,0 +, 89, 53, 24,0, 89, 53, 24,0, 63, 39, 22,0, 63, 39, 22,0 +, 65, 44, 25,0, 65, 44, 25,0, 93, 58, 30,0, 93, 58, 30,0 +, 92, 57, 30,0, 92, 57, 30,0, 98, 59, 28,0, 98, 59, 28,0 +, 97, 58, 29,0, 97, 58, 29,0, 97, 60, 30,0, 97, 60, 30,0 +, 97, 60, 30,0, 97, 60, 30,0, 96, 59, 29,0, 96, 59, 29,0 +, 91, 55, 26,0, 91, 55, 26,0, 96, 60, 29,0, 96, 60, 29,0 +, 93, 58, 28,0, 93, 58, 28,0, 93, 57, 27,0, 93, 57, 27,0 +, 93, 56, 27,0, 93, 56, 27,0, 85, 52, 25,0, 85, 52, 25,0 +, 89, 53, 24,0, 89, 53, 24,0, 63, 39, 22,0, 63, 39, 22,0 +, 81, 50, 26,0, 81, 50, 26,0,145, 89, 46,0,145, 89, 46,0 +,145, 76, 29,0,145, 76, 29,0,134, 72, 26,0,134, 72, 26,0 +,136, 76, 30,0,136, 76, 30,0,148, 85, 36,0,148, 85, 36,0 +,137, 77, 31,0,137, 77, 31,0,134, 72, 27,0,134, 72, 27,0 +,117, 64, 26,0,117, 64, 26,0,141, 80, 32,0,141, 80, 32,0 +,141, 81, 34,0,141, 81, 34,0,123, 70, 27,0,123, 70, 27,0 +,123, 68, 27,0,123, 68, 27,0,130, 72, 27,0,130, 72, 27,0 +,135, 80, 37,0,135, 80, 37,0, 85, 50, 24,0, 85, 50, 24,0 +, 81, 50, 26,0, 81, 50, 26,0,145, 89, 46,0,145, 89, 46,0 +,145, 76, 29,0,145, 76, 29,0,134, 72, 26,0,134, 72, 26,0 +,136, 76, 30,0,136, 76, 30,0,148, 85, 36,0,148, 85, 36,0 +,137, 77, 31,0,137, 77, 31,0,134, 72, 27,0,134, 72, 27,0 +,117, 64, 26,0,117, 64, 26,0,141, 80, 32,0,141, 80, 32,0 +,141, 81, 34,0,141, 81, 34,0,123, 70, 27,0,123, 70, 27,0 +,123, 68, 27,0,123, 68, 27,0,130, 72, 27,0,130, 72, 27,0 +,135, 80, 37,0,135, 80, 37,0, 85, 50, 24,0, 85, 50, 24,0 +, 80, 48, 24,0, 80, 48, 24,0,146, 76, 29,0,146, 76, 29,0 +,255,227, 30,0,255,227, 30,0,255,237, 75,0,255,237, 75,0 +,125, 98, 52,0,125, 98, 52,0,145,120, 69,0,145,120, 69,0 +,133,105, 55,0,133,105, 55,0,255,231, 48,0,255,231, 48,0 +,255,237, 75,0,255,237, 75,0,127,100, 53,0,127,100, 53,0 +,143,117, 67,0,143,117, 67,0,132,105, 55,0,132,105, 55,0 +,255,232, 54,0,255,232, 54,0,255,236, 76,0,255,236, 76,0 +, 85, 44, 15,0, 85, 44, 15,0, 83, 47, 20,0, 83, 47, 20,0 +, 80, 48, 24,0, 80, 48, 24,0,146, 76, 29,0,146, 76, 29,0 +,255,227, 30,0,255,227, 30,0,255,237, 75,0,255,237, 75,0 +,125, 98, 52,0,125, 98, 52,0,145,120, 69,0,145,120, 69,0 +,133,105, 55,0,133,105, 55,0,255,231, 48,0,255,231, 48,0 +,255,237, 75,0,255,237, 75,0,127,100, 53,0,127,100, 53,0 +,143,117, 67,0,143,117, 67,0,132,105, 55,0,132,105, 55,0 +,255,232, 54,0,255,232, 54,0,255,236, 76,0,255,236, 76,0 +, 85, 44, 15,0, 85, 44, 15,0, 83, 47, 20,0, 83, 47, 20,0 +, 79, 48, 23,0, 79, 48, 23,0,149, 72, 24,0,149, 72, 24,0 +,255,227, 31,0,255,227, 31,0, 82, 56, 21,0, 82, 56, 21,0 +,255,236, 76,0,255,236, 76,0, 97, 72, 30,0, 97, 72, 30,0 +,255,231, 48,0,255,231, 48,0, 16, 12, 5,0, 16, 12, 5,0 +,102, 75, 32,0,102, 75, 32,0,255,237, 75,0,255,237, 75,0 +,107, 80, 36,0,107, 80, 36,0,255,221, 2,0,255,221, 2,0 +, 65, 45, 19,0, 65, 45, 19,0, 48, 38, 19,0, 48, 38, 19,0 +, 66, 32, 6,0, 66, 32, 6,0, 80, 43, 14,0, 80, 43, 14,0 +, 79, 48, 23,0, 79, 48, 23,0,149, 72, 24,0,149, 72, 24,0 +,255,227, 31,0,255,227, 31,0, 82, 56, 21,0, 82, 56, 21,0 +,255,236, 76,0,255,236, 76,0, 97, 72, 30,0, 97, 72, 30,0 +,255,231, 48,0,255,231, 48,0, 16, 12, 5,0, 16, 12, 5,0 +,102, 75, 32,0,102, 75, 32,0,255,237, 75,0,255,237, 75,0 +,107, 80, 36,0,107, 80, 36,0,255,221, 2,0,255,221, 2,0 +, 65, 45, 19,0, 65, 45, 19,0, 48, 38, 19,0, 48, 38, 19,0 +, 66, 32, 6,0, 66, 32, 6,0, 80, 43, 14,0, 80, 43, 14,0 +, 85, 52, 25,0, 85, 52, 25,0,149, 70, 21,0,149, 70, 21,0 +,255,229, 37,0,255,229, 37,0, 16, 12, 3,0, 16, 12, 3,0 +,255,236, 76,0,255,236, 76,0, 62, 48, 12,0, 62, 48, 12,0 +,255,236, 76,0,255,236, 76,0, 27, 21, 8,0, 27, 21, 8,0 +,107, 84, 34,0,107, 84, 34,0,255,237, 75,0,255,237, 75,0 +, 11, 8, 3,0, 11, 8, 3,0,106, 84, 35,0,106, 84, 35,0 +,255,237, 74,0,255,237, 74,0, 98, 75, 35,0, 98, 75, 35,0 +,105, 50, 7,0,105, 50, 7,0, 83, 46, 15,0, 83, 46, 15,0 +, 85, 52, 25,0, 85, 52, 25,0,149, 70, 21,0,149, 70, 21,0 +,255,229, 37,0,255,229, 37,0, 16, 12, 3,0, 16, 12, 3,0 +,255,236, 76,0,255,236, 76,0, 62, 48, 12,0, 62, 48, 12,0 +,255,236, 76,0,255,236, 76,0, 27, 21, 8,0, 27, 21, 8,0 +,107, 84, 34,0,107, 84, 34,0,255,237, 75,0,255,237, 75,0 +, 11, 8, 3,0, 11, 8, 3,0,106, 84, 35,0,106, 84, 35,0 +,255,237, 74,0,255,237, 74,0, 98, 75, 35,0, 98, 75, 35,0 +,105, 50, 7,0,105, 50, 7,0, 83, 46, 15,0, 83, 46, 15,0 +, 81, 49, 23,0, 81, 49, 23,0,142, 67, 20,0,142, 67, 20,0 +,255,230, 45,0,255,230, 45,0, 2, 1, 0,0, 2, 1, 0,0 +,255,236, 76,0,255,236, 76,0, 75, 58, 13,0, 75, 58, 13,0 +,255,236, 76,0,255,236, 76,0, 80, 62, 19,0, 80, 62, 19,0 +, 81, 64, 21,0, 81, 64, 21,0,255,236, 76,0,255,236, 76,0 +, 2, 2, 1,0, 2, 2, 1,0,111, 86, 36,0,111, 86, 36,0 +, 88, 63, 23,0, 88, 63, 23,0,255,236, 76,0,255,236, 76,0 +, 66, 31, 4,0, 66, 31, 4,0, 87, 46, 15,0, 87, 46, 15,0 +, 81, 49, 23,0, 81, 49, 23,0,142, 67, 20,0,142, 67, 20,0 +,255,230, 45,0,255,230, 45,0, 2, 1, 0,0, 2, 1, 0,0 +,255,236, 76,0,255,236, 76,0, 75, 58, 13,0, 75, 58, 13,0 +,255,236, 76,0,255,236, 76,0, 80, 62, 19,0, 80, 62, 19,0 +, 81, 64, 21,0, 81, 64, 21,0,255,236, 76,0,255,236, 76,0 +, 2, 2, 1,0, 2, 2, 1,0,111, 86, 36,0,111, 86, 36,0 +, 88, 63, 23,0, 88, 63, 23,0,255,236, 76,0,255,236, 76,0 +, 66, 31, 4,0, 66, 31, 4,0, 87, 46, 15,0, 87, 46, 15,0 +, 78, 46, 21,0, 78, 46, 21,0,150, 76, 25,0,150, 76, 25,0 +,255,237, 75,0,255,237, 75,0,255,236, 76,0,255,236, 76,0 +, 57, 44, 14,0, 57, 44, 14,0,111, 87, 27,0,111, 87, 27,0 +,104, 80, 30,0,104, 80, 30,0,255,236, 76,0,255,236, 76,0 +,255,236, 76,0,255,236, 76,0, 47, 37, 16,0, 47, 37, 16,0 +,116, 91, 38,0,116, 91, 38,0,255,237, 75,0,255,237, 75,0 +,255,236, 76,0,255,236, 76,0, 38, 30, 13,0, 38, 30, 13,0 +, 56, 26, 4,0, 56, 26, 4,0, 82, 43, 14,0, 82, 43, 14,0 +, 78, 46, 21,0, 78, 46, 21,0,150, 76, 25,0,150, 76, 25,0 +,255,237, 75,0,255,237, 75,0,255,236, 76,0,255,236, 76,0 +, 57, 44, 14,0, 57, 44, 14,0,111, 87, 27,0,111, 87, 27,0 +,104, 80, 30,0,104, 80, 30,0,255,236, 76,0,255,236, 76,0 +,255,236, 76,0,255,236, 76,0, 47, 37, 16,0, 47, 37, 16,0 +,116, 91, 38,0,116, 91, 38,0,255,237, 75,0,255,237, 75,0 +,255,236, 76,0,255,236, 76,0, 38, 30, 13,0, 38, 30, 13,0 +, 56, 26, 4,0, 56, 26, 4,0, 82, 43, 14,0, 82, 43, 14,0 +, 82, 50, 25,0, 82, 50, 25,0,159, 84, 31,0,159, 84, 31,0 +,125,101, 52,0,125,101, 52,0, 57, 46, 20,0, 57, 46, 20,0 +, 66, 51, 23,0, 66, 51, 23,0,140,115, 53,0,140,115, 53,0 +,134,109, 51,0,134,109, 51,0,118, 94, 41,0,118, 94, 41,0 +, 47, 38, 16,0, 47, 38, 16,0, 63, 50, 23,0, 63, 50, 23,0 +,129,105, 46,0,129,105, 46,0,114, 92, 41,0,114, 92, 41,0 +, 71, 57, 25,0, 71, 57, 25,0, 68, 52, 26,0, 68, 52, 26,0 +,111, 51, 7,0,111, 51, 7,0, 84, 47, 17,0, 84, 47, 17,0 +, 82, 50, 25,0, 82, 50, 25,0,159, 84, 31,0,159, 84, 31,0 +,125,101, 52,0,125,101, 52,0, 57, 46, 20,0, 57, 46, 20,0 +, 66, 51, 23,0, 66, 51, 23,0,140,115, 53,0,140,115, 53,0 +,134,109, 51,0,134,109, 51,0,118, 94, 41,0,118, 94, 41,0 +, 47, 38, 16,0, 47, 38, 16,0, 63, 50, 23,0, 63, 50, 23,0 +,129,105, 46,0,129,105, 46,0,114, 92, 41,0,114, 92, 41,0 +, 71, 57, 25,0, 71, 57, 25,0, 68, 52, 26,0, 68, 52, 26,0 +,111, 51, 7,0,111, 51, 7,0, 84, 47, 17,0, 84, 47, 17,0 +, 81, 50, 24,0, 81, 50, 24,0,164, 89, 35,0,164, 89, 35,0 +,130,104, 57,0,130,104, 57,0,121, 97, 46,0,121, 97, 46,0 +,131,109, 52,0,131,109, 52,0,139,116, 57,0,139,116, 57,0 +,137,114, 58,0,137,114, 58,0,123, 98, 47,0,123, 98, 47,0 +,125,101, 49,0,125,101, 49,0,139,115, 59,0,139,115, 59,0 +,141,118, 62,0,141,118, 62,0,137,110, 58,0,137,110, 58,0 +,130,106, 52,0,130,106, 52,0,131,108, 55,0,131,108, 55,0 +,113, 54, 9,0,113, 54, 9,0, 85, 48, 18,0, 85, 48, 18,0 +, 81, 50, 24,0, 81, 50, 24,0,164, 89, 35,0,164, 89, 35,0 +,130,104, 57,0,130,104, 57,0,121, 97, 46,0,121, 97, 46,0 +,131,109, 52,0,131,109, 52,0,139,116, 57,0,139,116, 57,0 +,137,114, 58,0,137,114, 58,0,123, 98, 47,0,123, 98, 47,0 +,125,101, 49,0,125,101, 49,0,139,115, 59,0,139,115, 59,0 +,141,118, 62,0,141,118, 62,0,137,110, 58,0,137,110, 58,0 +,130,106, 52,0,130,106, 52,0,131,108, 55,0,131,108, 55,0 +,113, 54, 9,0,113, 54, 9,0, 85, 48, 18,0, 85, 48, 18,0 +, 76, 45, 21,0, 76, 45, 21,0,150, 75, 26,0,150, 75, 26,0 +,255,228, 34,0,255,228, 34,0,255,237, 75,0,255,237, 75,0 +,118, 90, 42,0,118, 90, 42,0,138,111, 58,0,138,111, 58,0 +,120, 93, 46,0,120, 93, 46,0,255,231, 48,0,255,231, 48,0 +,255,237, 75,0,255,237, 75,0,118, 92, 43,0,118, 92, 43,0 +,118, 91, 42,0,118, 91, 42,0,255,233, 60,0,255,233, 60,0 +,100, 73, 31,0,100, 73, 31,0,255,236, 76,0,255,236, 76,0 +,102, 51, 9,0,102, 51, 9,0, 82, 43, 14,0, 82, 43, 14,0 +, 76, 45, 21,0, 76, 45, 21,0,150, 75, 26,0,150, 75, 26,0 +,255,228, 34,0,255,228, 34,0,255,237, 75,0,255,237, 75,0 +,118, 90, 42,0,118, 90, 42,0,138,111, 58,0,138,111, 58,0 +,120, 93, 46,0,120, 93, 46,0,255,231, 48,0,255,231, 48,0 +,255,237, 75,0,255,237, 75,0,118, 92, 43,0,118, 92, 43,0 +,118, 91, 42,0,118, 91, 42,0,255,233, 60,0,255,233, 60,0 +,100, 73, 31,0,100, 73, 31,0,255,236, 76,0,255,236, 76,0 +,102, 51, 9,0,102, 51, 9,0, 82, 43, 14,0, 82, 43, 14,0 +, 78, 47, 22,0, 78, 47, 22,0,142, 67, 20,0,142, 67, 20,0 +,255,226, 24,0,255,226, 24,0, 82, 56, 20,0, 82, 56, 20,0 +,255,236, 76,0,255,236, 76,0,106, 80, 33,0,106, 80, 33,0 +,255,220, 0,0,255,220, 0,0, 15, 11, 4,0, 15, 11, 4,0 +, 99, 72, 30,0, 99, 72, 30,0,255,237, 74,0,255,237, 74,0 +, 93, 70, 27,0, 93, 70, 27,0,247,212, 0,0,247,212, 0,0 +, 66, 50, 15,0, 66, 50, 15,0,255,236, 76,0,255,236, 76,0 +, 66, 30, 1,0, 66, 30, 1,0, 77, 40, 11,0, 77, 40, 11,0 +, 78, 47, 22,0, 78, 47, 22,0,142, 67, 20,0,142, 67, 20,0 +,255,226, 24,0,255,226, 24,0, 82, 56, 20,0, 82, 56, 20,0 +,255,236, 76,0,255,236, 76,0,106, 80, 33,0,106, 80, 33,0 +,255,220, 0,0,255,220, 0,0, 15, 11, 4,0, 15, 11, 4,0 +, 99, 72, 30,0, 99, 72, 30,0,255,237, 74,0,255,237, 74,0 +, 93, 70, 27,0, 93, 70, 27,0,247,212, 0,0,247,212, 0,0 +, 66, 50, 15,0, 66, 50, 15,0,255,236, 76,0,255,236, 76,0 +, 66, 30, 1,0, 66, 30, 1,0, 77, 40, 11,0, 77, 40, 11,0 +, 86, 52, 25,0, 86, 52, 25,0,136, 64, 18,0,136, 64, 18,0 +,255,230, 45,0,255,230, 45,0,255,236, 76,0,255,236, 76,0 +, 42, 33, 8,0, 42, 33, 8,0, 82, 64, 20,0, 82, 64, 20,0 +,255,237, 74,0,255,237, 74,0, 28, 22, 8,0, 28, 22, 8,0 +,109, 84, 35,0,109, 84, 35,0,255,225, 26,0,255,225, 26,0 +, 35, 26, 9,0, 35, 26, 9,0, 82, 64, 22,0, 82, 64, 22,0 +,255,237, 74,0,255,237, 74,0, 49, 39, 13,0, 49, 39, 13,0 +, 67, 30, 0,0, 67, 30, 0,0, 80, 40, 8,0, 80, 40, 8,0 +, 86, 52, 25,0, 86, 52, 25,0,136, 64, 18,0,136, 64, 18,0 +,255,230, 45,0,255,230, 45,0,255,236, 76,0,255,236, 76,0 +, 42, 33, 8,0, 42, 33, 8,0, 82, 64, 20,0, 82, 64, 20,0 +,255,237, 74,0,255,237, 74,0, 28, 22, 8,0, 28, 22, 8,0 +,109, 84, 35,0,109, 84, 35,0,255,225, 26,0,255,225, 26,0 +, 35, 26, 9,0, 35, 26, 9,0, 82, 64, 22,0, 82, 64, 22,0 +,255,237, 74,0,255,237, 74,0, 49, 39, 13,0, 49, 39, 13,0 +, 67, 30, 0,0, 67, 30, 0,0, 80, 40, 8,0, 80, 40, 8,0 +, 74, 43, 19,0, 74, 43, 19,0,140, 63, 17,0,140, 63, 17,0 +,255,237, 74,0,255,237, 74,0, 14, 11, 3,0, 14, 11, 3,0 +,255,236, 76,0,255,236, 76,0, 82, 63, 15,0, 82, 63, 15,0 +,255,237, 75,0,255,237, 75,0, 80, 63, 19,0, 80, 63, 19,0 +, 86, 67, 22,0, 86, 67, 22,0,255,237, 75,0,255,237, 75,0 +, 67, 52, 16,0, 67, 52, 16,0,255,237, 74,0,255,237, 74,0 +, 43, 34, 8,0, 43, 34, 8,0,255,236, 76,0,255,236, 76,0 +, 66, 29, 0,0, 66, 29, 0,0, 71, 34, 4,0, 71, 34, 4,0 +, 74, 43, 19,0, 74, 43, 19,0,140, 63, 17,0,140, 63, 17,0 +,255,237, 74,0,255,237, 74,0, 14, 11, 3,0, 14, 11, 3,0 +,255,236, 76,0,255,236, 76,0, 82, 63, 15,0, 82, 63, 15,0 +,255,237, 75,0,255,237, 75,0, 80, 63, 19,0, 80, 63, 19,0 +, 86, 67, 22,0, 86, 67, 22,0,255,237, 75,0,255,237, 75,0 +, 67, 52, 16,0, 67, 52, 16,0,255,237, 74,0,255,237, 74,0 +, 43, 34, 8,0, 43, 34, 8,0,255,236, 76,0,255,236, 76,0 +, 66, 29, 0,0, 66, 29, 0,0, 71, 34, 4,0, 71, 34, 4,0 +, 77, 45, 20,0, 77, 45, 20,0,145, 71, 22,0,145, 71, 22,0 +,255,237, 75,0,255,237, 75,0,255,236, 76,0,255,236, 76,0 +, 47, 37, 11,0, 47, 37, 11,0,108, 84, 26,0,108, 84, 26,0 +, 95, 76, 27,0, 95, 76, 27,0,255,236, 76,0,255,236, 76,0 +,255,236, 76,0,255,236, 76,0, 71, 55, 20,0, 71, 55, 20,0 +, 98, 77, 26,0, 98, 77, 26,0,255,236, 76,0,255,236, 76,0 +, 78, 62, 19,0, 78, 62, 19,0,255,236, 76,0,255,236, 76,0 +, 32, 14, 0,0, 32, 14, 0,0, 75, 37, 5,0, 75, 37, 5,0 +, 77, 45, 20,0, 77, 45, 20,0,145, 71, 22,0,145, 71, 22,0 +,255,237, 75,0,255,237, 75,0,255,236, 76,0,255,236, 76,0 +, 47, 37, 11,0, 47, 37, 11,0,108, 84, 26,0,108, 84, 26,0 +, 95, 76, 27,0, 95, 76, 27,0,255,236, 76,0,255,236, 76,0 +,255,236, 76,0,255,236, 76,0, 71, 55, 20,0, 71, 55, 20,0 +, 98, 77, 26,0, 98, 77, 26,0,255,236, 76,0,255,236, 76,0 +, 78, 62, 19,0, 78, 62, 19,0,255,236, 76,0,255,236, 76,0 +, 32, 14, 0,0, 32, 14, 0,0, 75, 37, 5,0, 75, 37, 5,0 +, 79, 46, 24,0, 79, 46, 24,0,132, 76, 31,0,132, 76, 31,0 +,124, 59, 13,0,124, 59, 13,0, 96, 43, 0,0, 96, 43, 0,0 +, 52, 23, 0,0, 52, 23, 0,0,123, 55, 0,0,123, 55, 0,0 +,136, 59, 1,0,136, 59, 1,0,124, 54, 2,0,124, 54, 2,0 +, 96, 43, 0,0, 96, 43, 0,0, 95, 42, 0,0, 95, 42, 0,0 +,124, 57, 0,0,124, 57, 0,0,121, 55, 0,0,121, 55, 0,0 +, 93, 41, 0,0, 93, 41, 0,0, 98, 43, 0,0, 98, 43, 0,0 +, 57, 28, 5,0, 57, 28, 5,0, 79, 43, 12,0, 79, 43, 12,0 +, 79, 46, 24,0, 79, 46, 24,0,132, 76, 31,0,132, 76, 31,0 +,124, 59, 13,0,124, 59, 13,0, 96, 43, 0,0, 96, 43, 0,0 +, 52, 23, 0,0, 52, 23, 0,0,123, 55, 0,0,123, 55, 0,0 +,136, 59, 1,0,136, 59, 1,0,124, 54, 2,0,124, 54, 2,0 +, 96, 43, 0,0, 96, 43, 0,0, 95, 42, 0,0, 95, 42, 0,0 +,124, 57, 0,0,124, 57, 0,0,121, 55, 0,0,121, 55, 0,0 +, 93, 41, 0,0, 93, 41, 0,0, 98, 43, 0,0, 98, 43, 0,0 +, 57, 28, 5,0, 57, 28, 5,0, 79, 43, 12,0, 79, 43, 12,0 +, 66, 43, 24,0, 66, 43, 24,0, 78, 46, 20,0, 78, 46, 20,0 +, 69, 38, 13,0, 69, 38, 13,0, 70, 36, 8,0, 70, 36, 8,0 +, 70, 35, 7,0, 70, 35, 7,0, 69, 35, 7,0, 69, 35, 7,0 +, 71, 39, 10,0, 71, 39, 10,0, 71, 36, 9,0, 71, 36, 9,0 +, 71, 36, 9,0, 71, 36, 9,0, 72, 36, 9,0, 72, 36, 9,0 +, 68, 36, 7,0, 68, 36, 7,0, 67, 33, 7,0, 67, 33, 7,0 +, 67, 33, 6,0, 67, 33, 6,0, 64, 33, 7,0, 64, 33, 7,0 +, 74, 38, 12,0, 74, 38, 12,0, 61, 35, 14,0, 61, 35, 14,0 +, 66, 43, 24,0, 66, 43, 24,0, 78, 46, 20,0, 78, 46, 20,0 +, 69, 38, 13,0, 69, 38, 13,0, 70, 36, 8,0, 70, 36, 8,0 +, 70, 35, 7,0, 70, 35, 7,0, 69, 35, 7,0, 69, 35, 7,0 +, 71, 39, 10,0, 71, 39, 10,0, 71, 36, 9,0, 71, 36, 9,0 +, 71, 36, 9,0, 71, 36, 9,0, 72, 36, 9,0, 72, 36, 9,0 +, 68, 36, 7,0, 68, 36, 7,0, 67, 33, 7,0, 67, 33, 7,0 +, 67, 33, 6,0, 67, 33, 6,0, 64, 33, 7,0, 64, 33, 7,0 +, 74, 38, 12,0, 74, 38, 12,0, 61, 35, 14,0, 61, 35, 14,0 +#endif +#ifdef LOGO_2 + 61, 39, 23,0, 91, 57, 30,0, 85, 53, 28,0, 82, 51, 26,0 +, 83, 52, 28,0, 91, 57, 30,0, 91, 57, 30,0, 91, 57, 30,0 +, 88, 55, 29,0, 91, 57, 30,0, 91, 57, 30,0, 91, 57, 30,0 +, 91, 57, 30,0, 91, 57, 30,0, 91, 57, 30,0, 88, 55, 29,0 +, 80, 50, 25,0, 85, 53, 28,0, 91, 57, 30,0, 91, 57, 30,0 +, 85, 53, 28,0, 88, 55, 29,0, 88, 55, 29,0, 85, 53, 28,0 +, 85, 53, 28,0, 85, 53, 28,0, 82, 51, 26,0, 78, 48, 25,0 +, 78, 48, 25,0, 82, 51, 26,0, 88, 55, 29,0, 61, 39, 23,0 +, 91, 57, 30,0,140, 89, 49,0,166,101, 49,0,161, 97, 49,0 +,157, 96, 49,0,165, 99, 50,0,165, 99, 50,0,161, 99, 50,0 +,170,104, 52,0,170,104, 52,0,170,104, 52,0,157, 96, 49,0 +,161, 97, 49,0,162, 99, 50,0,161, 97, 49,0,148, 89, 46,0 +,156, 95, 48,0,153, 93, 47,0,156, 95, 48,0,156, 95, 47,0 +,166,101, 49,0,166,101, 49,0,159, 98, 50,0,157, 96, 49,0 +,160, 96, 49,0,166,101, 49,0,150, 92, 47,0,148, 89, 46,0 +,148, 89, 46,0,160, 96, 49,0,156, 99, 53,0, 91, 57, 30,0 +, 75, 46, 24,0,150, 92, 47,0,151, 99, 53,0,172,106, 53,0 +,162, 99, 50,0,162, 99, 50,0,159, 98, 50,0,147, 91, 46,0 +,148, 89, 46,0,146, 89, 47,0,150, 92, 47,0,147, 91, 46,0 +,140, 84, 42,0,153, 91, 44,0,153, 91, 44,0,145, 86, 41,0 +,145, 86, 41,0,145, 86, 41,0,150, 92, 47,0,157, 96, 49,0 +,150, 92, 47,0,143, 87, 44,0,144, 89, 45,0,136, 84, 42,0 +,148, 89, 46,0,148, 89, 46,0,156, 95, 48,0,150, 92, 47,0 +,159, 98, 50,0,145, 93, 52,0,170,104, 52,0, 80, 50, 25,0 +, 71, 45, 23,0,140, 84, 42,0,172,106, 53,0,137, 87, 53,0 +,132, 92, 57,0,132, 92, 57,0,140, 97, 61,0,141,101, 64,0 +,141,101, 64,0,141,101, 64,0,140, 97, 61,0,141,101, 64,0 +,132, 88, 51,0,231,192, 61,0,245,209, 66,0,245,209, 66,0 +,245,209, 66,0,246,210, 68,0,243,209, 68,0,136, 97, 62,0 +,141,101, 64,0,136, 97, 62,0,136, 97, 62,0,136, 97, 62,0 +,136, 97, 62,0,132, 92, 57,0,122, 85, 52,0,125, 88, 54,0 +,122, 85, 52,0,168,102, 50,0,161, 97, 49,0, 78, 48, 25,0 +, 75, 46, 24,0,150, 92, 47,0,165, 99, 50,0,122, 85, 52,0 +,132,112, 74,0,130,111, 74,0,130,111, 74,0,154,135, 91,0 +,167,148,101,0,167,148,101,0,168,149,102,0,166,147, 99,0 +,147,124, 78,0,132,107, 61,0,224,185, 54,0,242,206, 67,0 +,156,136, 86,0,151,129, 80,0,242,208, 64,0,244,207, 66,0 +,164,145, 99,0,165,146, 99,0,165,146, 99,0,167,148,101,0 +,154,135, 91,0,132,112, 74,0,131,113, 76,0,134,115, 78,0 +,113, 84, 53,0,156, 95, 48,0,171,103, 50,0, 80, 50, 25,0 +, 72, 44, 22,0,163,102, 51,0,168,102, 50,0,125, 88, 54,0 +,128,110, 73,0,131,113, 76,0,131,113, 76,0,128,110, 73,0 +,148,130, 87,0,164,145, 99,0,167,148,101,0,166,147, 98,0 +,162,143, 92,0,132,107, 61,0,220,180, 55,0,247,212, 70,0 +,155,135, 82,0,152,130, 81,0,243,209, 65,0,246,212, 67,0 +,163,144, 96,0,168,149,102,0,168,149,102,0,150,132, 89,0 +,127,109, 71,0,130,111, 74,0,132,112, 74,0,129,112, 75,0 +,113, 84, 53,0,156, 95, 48,0,178,109, 54,0, 75, 46, 24,0 +, 75, 46, 24,0,150, 92, 47,0,172,106, 53,0,140, 97, 61,0 +,128,111, 74,0,129,112, 75,0,133,113, 75,0,133,113, 75,0 +,132,112, 74,0,150,132, 89,0,166,147, 98,0,163,144, 96,0 +,158,138, 88,0,132,107, 61,0,217,177, 51,0,243,207, 69,0 +,243,207, 69,0,231,192, 61,0,240,205, 65,0,159,140, 90,0 +,163,144, 96,0,167,148,101,0,150,132, 89,0,130,111, 74,0 +,133,114, 76,0,133,113, 75,0,130,111, 74,0,129,112, 75,0 +,123, 93, 58,0,154, 94, 48,0,165, 99, 50,0, 78, 48, 25,0 +, 78, 48, 25,0,144, 88, 45,0,174,108, 52,0,142,101, 62,0 +,161,141, 95,0,128,111, 74,0,130,111, 74,0,133,113, 75,0 +,133,113, 75,0,128,110, 73,0,150,132, 89,0,165,146, 98,0 +,161,142, 93,0,135,112, 64,0,223,183, 55,0,247,212, 70,0 +,155,135, 82,0,144,122, 72,0,240,205, 65,0,245,209, 66,0 +,163,143, 95,0,148,130, 87,0,127,109, 71,0,133,113, 75,0 +,133,113, 75,0,130,111, 74,0,129,112, 75,0,164,145, 99,0 +,126, 96, 62,0,154, 94, 48,0,161, 97, 49,0, 83, 52, 28,0 +, 80, 50, 25,0,147, 91, 46,0,178,109, 54,0,148,103, 65,0 +,166,147,100,0,161,142, 95,0,128,111, 74,0,128,109, 72,0 +,132,112, 74,0,132,112, 74,0,130,110, 73,0,147,128, 85,0 +,153,132, 84,0,137,114, 66,0,224,185, 54,0,245,209, 66,0 +,155,135, 82,0,149,129, 75,0,235,199, 63,0,245,209, 66,0 +,148,130, 87,0,130,111, 74,0,132,112, 74,0,130,111, 74,0 +,128,110, 73,0,128,111, 74,0,161,142, 95,0,168,149,102,0 +,127, 97, 63,0,153, 93, 47,0,162, 99, 50,0, 83, 52, 28,0 +, 82, 51, 26,0,148, 89, 46,0,178,109, 54,0,151,106, 65,0 +,166,147,100,0,167,148,101,0,160,143, 95,0,129,112, 75,0 +,129,112, 75,0,135,115, 77,0,135,115, 77,0,130,109, 69,0 +,129,106, 61,0,210,166, 47,0,210,169, 51,0,231,192, 61,0 +,234,197, 61,0,224,185, 56,0,225,189, 55,0,141,120, 75,0 +,130,111, 74,0,134,116, 78,0,133,114, 76,0,128,110, 73,0 +,132,114, 76,0,163,144, 98,0,168,149,102,0,167,148,101,0 +,127, 97, 63,0,153, 93, 47,0,163,102, 51,0, 84, 52, 27,0 +, 75, 46, 24,0,150, 92, 47,0,170,104, 52,0,147,105, 69,0 +,170,151,105,0,170,151,105,0,166,147,100,0,164,145, 99,0 +,134,116, 78,0,133,114, 76,0,133,114, 76,0,131,110, 71,0 +,116, 94, 54,0,116, 94, 54,0,137,114, 66,0,144,122, 72,0 +,146,125, 75,0,148,127, 78,0,137,117, 73,0,130,110, 73,0 +,134,116, 78,0,134,116, 78,0,133,113, 75,0,134,116, 78,0 +,164,145, 99,0,168,149,102,0,170,151,105,0,167,148,101,0 +,126, 96, 62,0,150, 92, 47,0,172,106, 53,0, 85, 53, 28,0 +, 75, 46, 24,0,147, 91, 46,0,166,101, 49,0,151,106, 65,0 +,165,146, 98,0,165,146, 98,0,165,146, 99,0,165,146, 99,0 +,160,143, 95,0,134,116, 78,0,130,110, 73,0,132,112, 74,0 +,130,109, 69,0,117, 98, 59,0,137,117, 73,0,158,138, 88,0 +,156,136, 86,0,137,117, 73,0,125,105, 65,0,133,114, 76,0 +,135,115, 77,0,130,111, 74,0,134,116, 78,0,164,145, 99,0 +,166,147, 99,0,167,148,101,0,166,147,100,0,166,147,100,0 +,134, 97, 62,0,150, 92, 47,0,162, 99, 50,0, 84, 52, 27,0 +, 75, 46, 24,0,146, 89, 43,0,162, 95, 42,0,234,197, 61,0 +,248,214, 73,0,248,214, 73,0,248,211, 69,0,246,210, 68,0 +,159,140, 93,0,163,144, 96,0,131,113, 76,0,126,107, 69,0 +,125,105, 65,0,125,105, 65,0,247,212, 70,0,248,211, 69,0 +,246,210, 68,0,248,211, 69,0,245,211, 67,0,132,112, 74,0 +,132,112, 74,0,134,116, 78,0,161,141, 95,0,162,142, 94,0 +,247,212, 70,0,247,212, 70,0,248,211, 69,0,247,212, 70,0 +,123, 93, 58,0,148, 89, 46,0,157, 96, 49,0, 84, 52, 27,0 +, 72, 44, 22,0,145, 86, 41,0,158, 87, 33,0,110, 68, 32,0 +,224,185, 56,0,243,209, 68,0,158,138, 88,0,240,205, 65,0 +,244,208, 66,0,167,148,101,0,165,146, 99,0,134,116, 76,0 +,114, 93, 56,0,231,192, 61,0,244,208, 66,0,122,100, 60,0 +,112, 90, 51,0,109, 87, 49,0,241,207, 67,0,244,208, 66,0 +,134,116, 78,0,162,142, 94,0,148,127, 78,0,225,187, 56,0 +,243,209, 65,0,152,130, 81,0,156,136, 86,0,240,205, 65,0 +,245,209, 66,0,153, 93, 47,0,159, 98, 50,0, 80, 50, 25,0 +, 75, 46, 24,0,142, 84, 38,0,157, 88, 35,0,117, 67, 29,0 +,214,174, 48,0,241,206, 62,0,153,133, 80,0,141,118, 71,0 +,239,202, 64,0,243,208, 67,0,166,147, 99,0,163,143, 95,0 +,109, 87, 49,0,221,179, 53,0,241,206, 62,0,124,103, 62,0 +,121, 99, 57,0, 97, 75, 39,0,223,183, 53,0,241,206, 62,0 +,159,140, 93,0,157,139, 89,0,135,112, 64,0,202,161, 42,0 +,232,194, 57,0,241,206, 62,0,153,133, 80,0,159,139, 90,0 +,123, 93, 58,0,127, 79, 39,0,172,106, 53,0, 80, 50, 25,0 +, 78, 48, 25,0,142, 84, 38,0,166, 93, 38,0,117, 67, 29,0 +,221,183, 53,0,245,209, 66,0,149,129, 75,0,140,117, 70,0 +,231,192, 61,0,246,212, 67,0,164,145, 96,0,161,141, 92,0 +,129,106, 61,0,222,184, 56,0,247,212, 70,0,125,105, 65,0 +,124,103, 62,0,100, 77, 41,0,221,183, 53,0,245,211, 67,0 +,161,141, 92,0,155,136, 86,0,134,109, 62,0,123, 98, 52,0 +,217,177, 51,0,240,205, 65,0,245,209, 66,0,157,139, 89,0 +,123, 93, 58,0,137, 83, 40,0,157, 96, 49,0, 84, 52, 27,0 +, 78, 48, 25,0,132, 79, 38,0,166, 93, 38,0,117, 67, 29,0 +,224,185, 54,0,241,206, 62,0,149,129, 75,0,144,122, 72,0 +,232,194, 57,0,241,206, 62,0,155,136, 86,0,156,136, 86,0 +,104, 82, 43,0,214,174, 48,0,241,206, 65,0,130,109, 69,0 +,125,105, 65,0,104, 82, 43,0,224,185, 54,0,241,206, 65,0 +,163,144, 96,0,164,145, 96,0,152,130, 81,0,144,121, 71,0 +,144,121, 71,0,141,121, 70,0,238,201, 61,0,241,206, 62,0 +,241,206, 62,0,137, 83, 40,0,157, 96, 49,0, 85, 53, 28,0 +, 75, 46, 24,0,132, 79, 38,0,160, 87, 33,0,117, 67, 29,0 +,228,191, 59,0,246,209, 65,0,153,133, 80,0,246,210, 68,0 +,244,208, 66,0,157,139, 89,0,158,138, 88,0,125,107, 68,0 +, 97, 75, 39,0,210,166, 47,0,246,209, 65,0,122,100, 60,0 +,122,100, 60,0,112, 90, 51,0,235,199, 63,0,247,212, 70,0 +,134,116, 76,0,164,145, 96,0,152,130, 81,0,231,192, 61,0 +,248,211, 69,0,149,129, 75,0,144,121, 71,0,243,205, 64,0 +,246,210, 68,0,140, 84, 42,0,165, 99, 50,0, 84, 52, 27,0 +, 69, 43, 22,0,145, 86, 41,0,150, 82, 30,0,210,169, 51,0 +,212,172, 53,0,226,190, 63,0,229,191, 61,0,227,189, 57,0 +,155,136, 86,0,161,141, 92,0,131,113, 76,0,125,105, 65,0 +,109, 87, 49,0,100, 77, 41,0,220,180, 55,0,238,201, 61,0 +,239,202, 64,0,225,187, 56,0,227,189, 57,0,125,105, 65,0 +,127,109, 71,0,131,114, 73,0,147,124, 78,0,137,114, 66,0 +,223,183, 55,0,228,191, 59,0,223,183, 55,0,225,187, 56,0 +,113, 84, 53,0,161, 97, 49,0,154, 94, 48,0, 80, 50, 25,0 +, 72, 44, 22,0,145, 86, 41,0,150, 82, 30,0,120, 73, 33,0 +,134,109, 62,0,137,114, 66,0,141,118, 71,0,152,130, 81,0 +,159,139, 90,0,134,116, 78,0,132,112, 76,0,132,112, 74,0 +,125,105, 65,0,107, 86, 49,0,122,100, 60,0,144,122, 72,0 +,141,120, 75,0,123,102, 59,0,117, 98, 59,0,131,110, 71,0 +,132,112, 74,0,126,107, 69,0,125,105, 65,0,134,113, 66,0 +,134,113, 66,0,137,114, 66,0,141,118, 71,0,151,129, 80,0 +,122, 85, 52,0,143, 87, 44,0,162, 99, 50,0, 80, 50, 25,0 +, 71, 45, 23,0,140, 84, 42,0,162, 95, 42,0,144, 98, 56,0 +,161,141, 92,0,163,143, 95,0,164,145, 96,0,163,144, 96,0 +,134,115, 78,0,132,112, 74,0,133,113, 75,0,133,113, 75,0 +,126,107, 69,0,141,120, 75,0,159,139, 90,0,158,138, 88,0 +,161,141, 92,0,156,136, 88,0,143,124, 80,0,131,110, 71,0 +,133,114, 76,0,132,112, 74,0,127,109, 71,0,125,107, 68,0 +,152,133, 84,0,155,136, 86,0,159,139, 90,0,159,140, 93,0 +,134, 97, 62,0,148, 89, 46,0,162, 99, 50,0, 78, 48, 25,0 +, 75, 46, 24,0,134, 83, 41,0,171,103, 50,0,142,101, 62,0 +,164,145, 96,0,167,148,101,0,163,144, 98,0,132,114, 76,0 +,130,111, 74,0,135,115, 77,0,137,116, 77,0,132,112, 74,0 +,137,116, 77,0,243,208, 67,0,243,209, 65,0,162,142, 94,0 +,162,143, 92,0,155,136, 86,0,244,208, 66,0,245,209, 66,0 +,129,112, 75,0,133,114, 76,0,133,113, 75,0,125,107, 68,0 +,127,109, 71,0,157,137, 89,0,161,141, 92,0,167,148,101,0 +,128, 97, 65,0,148, 89, 46,0,159, 98, 50,0, 80, 50, 25,0 +, 81, 51, 29,0,136, 84, 42,0,157, 96, 49,0,148,103, 65,0 +,167,148,101,0,164,145, 99,0,131,113, 76,0,132,112, 74,0 +,132,112, 74,0,133,113, 75,0,128,110, 73,0,145,125, 81,0 +,139,116, 69,0,221,179, 53,0,248,214, 73,0,164,145, 96,0 +,163,143, 95,0,157,137, 89,0,247,212, 70,0,247,212, 70,0 +,147,128, 85,0,130,111, 74,0,133,113, 75,0,132,112, 74,0 +,130,111, 74,0,128,111, 74,0,159,140, 93,0,163,144, 96,0 +,126, 96, 62,0,136, 84, 42,0,161, 97, 49,0, 80, 50, 25,0 +, 80, 50, 25,0,144, 88, 45,0,168,102, 50,0,151,106, 65,0 +,163,144, 98,0,128,111, 74,0,128,110, 73,0,130,111, 74,0 +,130,110, 73,0,127,109, 71,0,148,130, 87,0,163,144, 96,0 +,140,117, 70,0,129,106, 61,0,224,185, 54,0,245,209, 66,0 +,156,136, 86,0,242,208, 64,0,244,208, 66,0,163,143, 95,0 +,165,146, 99,0,150,132, 89,0,128,109, 72,0,132,112, 74,0 +,130,111, 74,0,130,111, 74,0,128,110, 73,0,159,140, 93,0 +,123, 93, 58,0,150, 92, 47,0,156, 95, 48,0, 82, 51, 26,0 +, 75, 46, 24,0,140, 84, 42,0,171,103, 50,0,142,101, 62,0 +,129,112, 75,0,130,111, 74,0,130,111, 74,0,130,111, 74,0 +,128,109, 72,0,147,128, 85,0,161,142, 95,0,159,139, 90,0 +,155,136, 86,0,135,112, 64,0,134,109, 62,0,233,196, 58,0 +,244,208, 66,0,244,208, 66,0,160,139, 90,0,164,145, 96,0 +,166,147,100,0,167,148,101,0,150,132, 89,0,131,113, 76,0 +,134,115, 78,0,134,115, 78,0,132,112, 76,0,131,113, 76,0 +,123, 93, 58,0,146, 89, 47,0,153, 93, 47,0, 80, 50, 25,0 +, 71, 45, 23,0,138, 85, 44,0,168,102, 50,0,122, 85, 52,0 +,128,110, 73,0,130,111, 74,0,128,110, 73,0,128,110, 73,0 +,150,132, 89,0,164,146, 97,0,164,146, 97,0,161,142, 93,0 +,157,139, 89,0,146,125, 75,0,137,114, 66,0,227,189, 57,0 +,235,199, 63,0,245,211, 67,0,160,140, 90,0,165,146, 99,0 +,168,149,102,0,167,148,101,0,165,146, 99,0,150,132, 89,0 +,128,110, 73,0,130,111, 74,0,130,111, 74,0,128,110, 73,0 +,103, 81, 51,0,147, 91, 46,0,156, 95, 48,0, 75, 46, 24,0 +, 69, 43, 22,0,150, 92, 47,0,166,101, 49,0,125, 88, 54,0 +,131,113, 76,0,130,111, 74,0,128,109, 72,0,148,130, 87,0 +,163,144, 96,0,166,147,100,0,166,147, 98,0,161,141, 92,0 +,153,132, 84,0,146,125, 75,0,238,201, 61,0,233,196, 58,0 +,134,109, 62,0,225,187, 56,0,241,206, 62,0,163,143, 95,0 +,163,143, 95,0,165,146, 99,0,166,147,100,0,166,147,100,0 +,154,137, 93,0,130,111, 74,0,130,111, 74,0,130,111, 74,0 +,113, 84, 53,0,153, 93, 47,0,172,106, 53,0, 72, 44, 22,0 +, 71, 45, 23,0,143, 87, 44,0,168,102, 50,0,122, 85, 52,0 +,129,112, 75,0,130,111, 74,0,150,132, 89,0,163,144, 96,0 +,163,144, 96,0,161,142, 95,0,159,140, 93,0,157,137, 89,0 +,141,121, 70,0,225,189, 55,0,246,209, 65,0,149,129, 75,0 +,135,112, 64,0,129,104, 58,0,238,201, 61,0,248,211, 69,0 +,163,144, 96,0,166,147,100,0,168,149,102,0,170,151,105,0 +,167,148,101,0,150,132, 89,0,128,111, 74,0,132,112, 74,0 +,113, 84, 53,0,156, 95, 48,0,168,102, 50,0, 78, 48, 25,0 +, 71, 45, 23,0,138, 85, 44,0,168,102, 50,0,134, 86, 50,0 +,132, 92, 57,0,151,106, 65,0,156,110, 68,0,156,110, 68,0 +,149,107, 67,0,151,106, 65,0,150,104, 59,0,150,104, 59,0 +,127, 79, 39,0,209,167, 48,0,234,197, 61,0,150,104, 59,0 +,151, 99, 53,0,120, 73, 33,0,212,170, 48,0,241,206, 65,0 +,149,107, 67,0,151,106, 65,0,149,107, 67,0,149,107, 67,0 +,156,110, 68,0,151,106, 65,0,147,105, 64,0,132, 92, 57,0 +,122, 85, 52,0,170,104, 52,0,162, 99, 50,0, 78, 48, 25,0 +, 75, 46, 24,0,144, 89, 45,0,145, 93, 52,0,159, 98, 50,0 +,154, 94, 48,0,162, 99, 50,0,153, 93, 47,0,144, 88, 45,0 +,144, 89, 45,0,144, 88, 45,0,148, 89, 46,0,152, 89, 41,0 +,131, 71, 25,0,131, 71, 25,0,146, 83, 34,0,152, 89, 41,0 +,134, 76, 33,0,131, 71, 25,0,131, 71, 25,0,134, 76, 33,0 +,156, 95, 48,0,150, 92, 47,0,156, 95, 48,0,156, 95, 48,0 +,144, 88, 45,0,143, 87, 44,0,150, 92, 47,0,147, 91, 46,0 +,155, 96, 51,0,146, 91, 48,0,170,104, 52,0, 82, 51, 26,0 +, 91, 57, 30,0,117, 75, 42,0,138, 85, 44,0,132, 79, 38,0 +,122, 76, 39,0,124, 77, 40,0,120, 74, 37,0,117, 73, 38,0 +,127, 79, 39,0,124, 77, 40,0,132, 79, 38,0,141, 83, 40,0 +,125, 74, 34,0,119, 70, 32,0,120, 73, 33,0,120, 74, 37,0 +,118, 71, 34,0,119, 70, 32,0,119, 70, 32,0,120, 73, 33,0 +,127, 79, 39,0,127, 79, 39,0,124, 77, 40,0,127, 79, 39,0 +,122, 76, 39,0,122, 76, 39,0,117, 73, 38,0,117, 73, 38,0 +,124, 77, 40,0,138, 85, 44,0,140, 89, 49,0, 91, 57, 30,0 +, 61, 39, 23,0, 88, 55, 29,0, 75, 46, 24,0, 69, 43, 22,0 +, 69, 43, 22,0, 72, 44, 22,0, 71, 45, 23,0, 71, 45, 23,0 +, 71, 45, 23,0, 71, 45, 23,0, 75, 46, 24,0, 72, 44, 22,0 +, 72, 44, 22,0, 75, 46, 24,0, 72, 44, 22,0, 69, 43, 22,0 +, 69, 43, 22,0, 72, 44, 22,0, 75, 46, 24,0, 72, 44, 22,0 +, 69, 43, 22,0, 75, 46, 24,0, 69, 43, 22,0, 69, 43, 22,0 +, 71, 45, 23,0, 69, 43, 22,0, 69, 43, 22,0, 69, 43, 22,0 +, 69, 43, 22,0, 75, 46, 24,0, 88, 55, 29,0, 61, 39, 23,0 +#endif diff --git a/src/gui/midi.cpp b/src/gui/midi.cpp index 80cb3cf..a6ca796 100644 --- a/src/gui/midi.cpp +++ b/src/gui/midi.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -107,86 +107,8 @@ static struct { } sysex; bool available; MidiHandler * handler; - struct { - FILE * handle; - Bit8u buffer[RAWBUF+SYSEX_SIZE]; - bool capturing; - Bitu used,done; - Bit32u last; - } raw; } midi; -static Bit8u midi_header[]={ - 'M','T','h','d', /* Bit32u, Header Chunk */ - 0x0,0x0,0x0,0x6, /* Bit32u, Chunk Length */ - 0x0,0x0, /* Bit16u, Format, 0=single track */ - 0x0,0x1, /* Bit16u, Track Count, 1 track */ - 0x01,0xf4, /* Bit16u, Timing, 2 beats/second with 500 frames */ - 'M','T','r','k', /* Bit32u, Track Chunk */ - 0x0,0x0,0x0,0x0, /* Bit32u, Chunk Length */ - //Track data -}; - -#define ADDBUF(_VAL_) midi.raw.buffer[midi.raw.used++]=(Bit8u)(_VAL_); -static INLINE void RawAddNumber(Bit32u val) { - if (val & 0xfe00000) ADDBUF(0x80|((val >> 21) & 0x7f)); - if (val & 0xfffc000) ADDBUF(0x80|((val >> 14) & 0x7f)); - if (val & 0xfffff80) ADDBUF(0x80|((val >> 7) & 0x7f)); - ADDBUF(val & 0x7f); -} -static INLINE void RawAddDelta(void) { - if (!midi.raw.handle) { - midi.raw.handle=OpenCaptureFile("Raw Midi",".mid"); - if (!midi.raw.handle) { - midi.raw.capturing=false; - return; - } - fwrite(midi_header,1,sizeof(midi_header),midi.raw.handle); - midi.raw.last=PIC_Ticks; - } - Bit32u delta=PIC_Ticks-midi.raw.last; - midi.raw.last=PIC_Ticks; - RawAddNumber(delta); -} - -static INLINE void RawAddData(Bit8u * data,Bitu len) { - for (Bitu i=0;i=RAWBUF) { - fwrite(midi.raw.buffer,1,midi.raw.used,midi.raw.handle); - midi.raw.done+=midi.raw.used; - midi.raw.used=0; - } -} - -static void MIDI_SaveRawEvent(void) { - /* Check for previously opened wave file */ - if (midi.raw.capturing) { - LOG_MSG("Stopping raw midi saving."); - midi.raw.capturing=false; - if (!midi.raw.handle) return; - ADDBUF(0x00);//Delta time - ADDBUF(0xff);ADDBUF(0x2F);ADDBUF(0x00); //End of track event - fwrite(midi.raw.buffer,1,midi.raw.used,midi.raw.handle); - midi.raw.done+=midi.raw.used; - fseek(midi.raw.handle,18, SEEK_SET); - Bit8u size[4]; - size[0]=(Bit8u)(midi.raw.done >> 24); - size[1]=(Bit8u)(midi.raw.done >> 16); - size[2]=(Bit8u)(midi.raw.done >> 8); - size[3]=(Bit8u)(midi.raw.done >> 0); - fwrite(&size,1,4,midi.raw.handle); - fclose(midi.raw.handle); - midi.raw.handle=0; - } else { - LOG_MSG("Preparing for raw midi capture, will start with first data."); - midi.raw.used=0; - midi.raw.done=0; - midi.raw.handle=0; - midi.raw.capturing=true; - } -} - - void MIDI_RawOutByte(Bit8u data) { /* Test for a active sysex tranfer */ if (midi.status==0xf0) { @@ -197,11 +119,8 @@ void MIDI_RawOutByte(Bit8u data) { midi.sysex.buf[midi.sysex.used++]=0xf7; midi.handler->PlaySysex(midi.sysex.buf,midi.sysex.used); LOG(LOG_ALL,LOG_NORMAL)("Sysex message size %d",midi.sysex.used); - if (midi.raw.capturing) { - RawAddDelta(); - ADDBUF(0xf0); - RawAddNumber(midi.sysex.used-1); - RawAddData(&midi.sysex.buf[1],midi.sysex.used-1); + if (CaptureState & CAPTURE_MIDI) { + CAPTURE_AddMidi( true, midi.sysex.used-1, &midi.sysex.buf[1]); } } } @@ -217,9 +136,8 @@ void MIDI_RawOutByte(Bit8u data) { if (midi.cmd_len) { midi.cmd_buf[midi.cmd_pos++]=data; if (midi.cmd_pos >= midi.cmd_len) { - if (midi.raw.capturing) { - RawAddDelta(); - RawAddData(midi.cmd_buf,midi.cmd_len); + if (CaptureState & CAPTURE_MIDI) { + CAPTURE_AddMidi(false, midi.cmd_len, midi.cmd_buf); } midi.handler->PlayMsg(midi.cmd_buf); midi.cmd_pos=1; //Use Running status @@ -231,49 +149,60 @@ bool MIDI_Available(void) { return midi.available; } -static void MIDI_Stop(Section* sec) { - if (midi.raw.handle) MIDI_SaveRawEvent(); -} - -void MIDI_Init(Section * sec) { - Section_prop * section=static_cast(sec); - const char * dev=section->Get_string("device"); - const char * conf=section->Get_string("config"); - /* If device = "default" go for first handler that works */ - MidiHandler * handler; - MAPPER_AddHandler(MIDI_SaveRawEvent,MK_f8,MMOD1|MMOD2,"caprawmidi","Cap MIDI"); - sec->AddDestroyFunction(&MIDI_Stop); - midi.status=0x00; - midi.cmd_pos=0; - midi.cmd_len=0; - midi.raw.capturing=false; - if (!strcasecmp(dev,"default")) goto getdefault; - handler=handler_list; - while (handler) { - if (!strcasecmp(dev,handler->GetName())) { - if (!handler->Open(conf)) { - LOG_MSG("MIDI:Can't open device:%s with config:%s.",dev,conf); - goto getdefault; +class MIDI:public Module_base{ +public: + MIDI(Section* configuration):Module_base(configuration){ + Section_prop * section=static_cast(configuration); + const char * dev=section->Get_string("device"); + const char * conf=section->Get_string("config"); + /* If device = "default" go for first handler that works */ + MidiHandler * handler; +// MAPPER_AddHandler(MIDI_SaveRawEvent,MK_f8,MMOD1|MMOD2,"caprawmidi","Cap MIDI"); + midi.status=0x00; + midi.cmd_pos=0; + midi.cmd_len=0; + if (!strcasecmp(dev,"default")) goto getdefault; + handler=handler_list; + while (handler) { + if (!strcasecmp(dev,handler->GetName())) { + if (!handler->Open(conf)) { + LOG_MSG("MIDI:Can't open device:%s with config:%s.",dev,conf); + goto getdefault; + } + midi.handler=handler; + midi.available=true; + LOG_MSG("MIDI:Opened device:%s",handler->GetName()); + return; } - midi.handler=handler; - midi.available=true; - LOG_MSG("MIDI:Opened device:%s",handler->GetName()); - return; + handler=handler->next; } - handler=handler->next; - } - LOG_MSG("MIDI:Can't find device:%s, finding default handler.",dev); + LOG_MSG("MIDI:Can't find device:%s, finding default handler.",dev); getdefault: - handler=handler_list; - while (handler) { - if (handler->Open(conf)) { - midi.available=true; - midi.handler=handler; - LOG_MSG("MIDI:Opened device:%s",handler->GetName()); - return; + handler=handler_list; + while (handler) { + if (handler->Open(conf)) { + midi.available=true; + midi.handler=handler; + LOG_MSG("MIDI:Opened device:%s",handler->GetName()); + return; + } + handler=handler->next; } - handler=handler->next; + /* This shouldn't be possible */ } - /* This shouldn't be possible */ -} + ~MIDI(){ + if(midi.available) midi.handler->Close(); + midi.available = false; + midi.handler = 0; + } +}; + +static MIDI* test; +void MIDI_Destroy(Section* sec){ + delete test; +} +void MIDI_Init(Section * sec) { + test = new MIDI(sec); + sec->AddDestroyFunction(&MIDI_Destroy,true); +} diff --git a/src/gui/midi_alsa.h b/src/gui/midi_alsa.h index 7246f88..4c0a547 100644 --- a/src/gui/midi_alsa.h +++ b/src/gui/midi_alsa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: midi_alsa.h,v 1.9 2004/08/04 09:12:54 qbix79 Exp $ */ +/* $Id: midi_alsa.h,v 1.13 2006/02/09 11:47:48 qbix79 Exp $ */ #define ALSA_PCM_OLD_HW_PARAMS_API #define ALSA_PCM_OLD_SW_PARAMS_API @@ -112,7 +112,7 @@ public: } break; default: - LOG(LOG_MISC,LOG_WARN)("ALSA:Unknown Command: %08x", (int)msg); + LOG(LOG_MISC,LOG_WARN)("ALSA:Unknown Command: %08lx", (long)msg); send_event(1); break; } @@ -129,7 +129,7 @@ public: // try to use port specified in config file if (conf && conf[0]) { - strncpy(var, conf, 10); + safe_strncpy(var, conf, 10); if (parse_addr(var, &seq_client, &seq_port) < 0) { LOG_MSG("ALSA:Invalid alsa port %s", var); return false; diff --git a/src/gui/midi_coreaudio.h b/src/gui/midi_coreaudio.h index cb519d4..1af883b 100644 --- a/src/gui/midi_coreaudio.h +++ b/src/gui/midi_coreaudio.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/gui/midi_oss.h b/src/gui/midi_oss.h index e0bfc0d..20db394 100644 --- a/src/gui/midi_oss.h +++ b/src/gui/midi_oss.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -29,7 +29,7 @@ public: char * GetName(void) { return "oss";}; bool Open(const char * conf) { char devname[512]; - if (conf && conf[0]) strncpy(devname,conf,512); + if (conf && conf[0]) safe_strncpy(devname,conf,512); else strcpy(devname,"/dev/sequencer"); char * devfind=(strrchr(devname,',')); if (devfind) { diff --git a/src/gui/midi_win32.h b/src/gui/midi_win32.h index 514f498..eb5b3c9 100644 --- a/src/gui/midi_win32.h +++ b/src/gui/midi_win32.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,11 +16,15 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: midi_win32.h,v 1.12 2006/02/09 11:47:48 qbix79 Exp $ */ + #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif #include #include +#include +#include class MidiHandler_win32: public MidiHandler { private: @@ -34,11 +38,26 @@ public: bool Open(const char * conf) { if (isOpen) return false; m_event = CreateEvent (NULL, true, true, NULL); - MMRESULT res = midiOutOpen(&m_out, MIDI_MAPPER, (DWORD)m_event, 0, CALLBACK_EVENT); + MMRESULT res; + if(conf && *conf) { + std::string strconf(conf); + std::istringstream configmidi(strconf); + unsigned int nummer = midiOutGetNumDevs(); + configmidi >> nummer; + if(nummer < midiOutGetNumDevs()){ + MIDIOUTCAPS mididev; + midiOutGetDevCaps(nummer, &mididev, sizeof(MIDIOUTCAPS)); + LOG_MSG("MIDI:win32 selected %s",mididev.szPname); + res = midiOutOpen(&m_out, nummer, (DWORD)m_event, 0, CALLBACK_EVENT); + } + } else { + res = midiOutOpen(&m_out, MIDI_MAPPER, (DWORD)m_event, 0, CALLBACK_EVENT); + } if (res != MMSYSERR_NOERROR) return false; isOpen=true; return true; }; + void Close(void) { if (!isOpen) return; isOpen=false; diff --git a/src/gui/render.cpp b/src/gui/render.cpp index e90b809..27ecf63 100644 --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: render.cpp,v 1.30 2004/08/04 09:12:54 qbix79 Exp $ */ +/* $Id: render.cpp,v 1.45 2006/03/29 14:17:27 qbix79 Exp $ */ #include #include @@ -34,159 +34,48 @@ #include "render_scalers.h" -struct PalData { - struct { - Bit8u red; - Bit8u green; - Bit8u blue; - Bit8u unused; - } rgb[256]; - volatile Bitu first; - volatile Bitu last; -}; - -static struct { - struct { - Bitu width; - Bitu height; - Bitu bpp; - bool dblw,dblh; - double ratio; - } src; - struct { - Bitu width; - Bitu height; - Bitu pitch; - GFX_Modes mode; - RENDER_Operation type; - RENDER_Operation want_type; - RENDER_Line_Handler line_handler; - } op; - struct { - Bitu count; - Bitu max; - } frameskip; - PalData pal; -#if (C_SSHOT) - struct { - Bitu bpp,width,height,rowlen; - Bit8u * buffer,* draw; - bool take,taking; - } shot; -#endif - bool active; - bool aspect; - bool updating; -} render; - -RENDER_Line_Handler RENDER_DrawLine; - -#if (C_SSHOT) -#include - -static void RENDER_ShotDraw(const Bit8u * src) { - memcpy(render.shot.draw,src,render.shot.rowlen); - render.shot.draw+=render.shot.rowlen; - render.op.line_handler(src); -} - -/* Take a screenshot of the data that should be rendered */ -static void TakeScreenShot(Bit8u * bitmap) { - png_structp png_ptr; - png_infop info_ptr; - png_bytep * row_pointers; - png_color palette[256]; - Bitu i; - -/* Find a filename to open */ - /* Open the actual file */ - FILE * fp=OpenCaptureFile("Screenshot",".png"); - if (!fp) return; - /* First try to alloacte the png structures */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); - if (!png_ptr) return; - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { - png_destroy_write_struct(&png_ptr,(png_infopp)NULL); - return; - } - - /* Finalize the initing of png library */ - png_init_io(png_ptr, fp); - png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); - - /* set other zlib parameters */ - png_set_compression_mem_level(png_ptr, 8); - png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); - png_set_compression_window_bits(png_ptr, 15); - png_set_compression_method(png_ptr, 8); - png_set_compression_buffer_size(png_ptr, 8192); - - if (render.shot.bpp==8) { - png_set_IHDR(png_ptr, info_ptr, render.shot.width, render.shot.height, - 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - for (i=0;i<256;i++) { - palette[i].red=render.pal.rgb[i].red; - palette[i].green=render.pal.rgb[i].green; - palette[i].blue=render.pal.rgb[i].blue; - } - png_set_PLTE(png_ptr, info_ptr, palette,256); - } else { - png_set_IHDR(png_ptr, info_ptr, render.shot.width, render.shot.height, - render.shot.bpp, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); - } - /*Allocate an array of scanline pointers*/ - row_pointers=(png_bytep*)malloc(render.shot.height*sizeof(png_bytep)); - for (i=0;irender.pal.last) return; + /* Clean up any previous changed palette data */ + if (render.pal.changed) { + memset(render.pal.modified, 0, sizeof(render.pal.modified)); + render.pal.changed = false; + } + if (render.pal.first>render.pal.last) + return; Bitu i; - switch (render.op.mode) { - case GFX_8: + switch (render.scale.outMode) { + case scalerMode8: GFX_SetPalette(render.pal.first,render.pal.last-render.pal.first+1,(GFX_PalEntry *)&render.pal.rgb[render.pal.first]); break; - case GFX_15: - case GFX_16: + case scalerMode15: + case scalerMode16: for (i=render.pal.first;i<=render.pal.last;i++) { Bit8u r=render.pal.rgb[i].red; Bit8u g=render.pal.rgb[i].green; Bit8u b=render.pal.rgb[i].blue; - Scaler_PaletteLut.b16[i]=GFX_GetRGB(r,g,b); + Bit16u newPal = GFX_GetRGB(r,g,b); + if (newPal != render.pal.lut.b16[i]) { + render.pal.changed = true; + render.pal.modified[i] = 1; + render.pal.lut.b16[i] = newPal; + } } break; - case GFX_32: + case scalerMode32: + default: for (i=render.pal.first;i<=render.pal.last;i++) { Bit8u r=render.pal.rgb[i].red; Bit8u g=render.pal.rgb[i].green; Bit8u b=render.pal.rgb[i].blue; - Scaler_PaletteLut.b32[i]=GFX_GetRGB(r,g,b); + Bit32u newPal = GFX_GetRGB(r,g,b); + if (newPal != render.pal.lut.b32[i]) { + render.pal.changed = true; + render.pal.modified[i] = 1; + render.pal.lut.b32[i] = newPal; + } } break; } @@ -195,11 +84,6 @@ static void Check_Palette(void) { render.pal.last=0; } -static void RENDER_ResetPal(void) { - render.pal.first=0; - render.pal.last=255; -} - void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) { render.pal.rgb[entry].red=red; render.pal.rgb[entry].green=green; @@ -208,63 +92,77 @@ void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue) { if (render.pal.last1.0) gfx_scaleh*=render.src.ratio; - else gfx_scalew*=(1/render.src.ratio); - - Bitu gfx_flags; - ScalerBlock * block; + Bitu gfx_flags, xscale, yscale; + ScalerSimpleBlock_t *simpleBlock = &ScaleNormal1x; + ScalerComplexBlock_t *complexBlock = 0; + if (render.aspect) { + if (render.src.ratio>1.0) { + gfx_scalew = 1; + gfx_scaleh = render.src.ratio; + } else { + gfx_scalew = (1/render.src.ratio); + gfx_scaleh = 1; + } + } else { + gfx_scalew = 1; + gfx_scaleh = 1; + } if (dblh && dblw) { - render.op.type=render.op.want_type; + /* Initialize always working defaults */ + if (render.scale.size == 2) + simpleBlock = &ScaleNormal2x; + else if (render.scale.size == 3) + simpleBlock = &ScaleNormal3x; + else + simpleBlock = &ScaleNormal1x; + /* Maybe override them */ + switch (render.scale.op) { + case scalerOpAdvInterp: + if (render.scale.size == 2) + complexBlock = &ScaleAdvInterp2x; + else if (render.scale.size == 3) + complexBlock = &ScaleAdvInterp3x; + break; + case scalerOpAdvMame: + if (render.scale.size == 2) + complexBlock = &ScaleAdvMame2x; + else if (render.scale.size == 3) + complexBlock = &ScaleAdvMame3x; + break; + case scalerOpTV: + if (render.scale.size == 2) + simpleBlock = &ScaleTV2x; + else if (render.scale.size == 3) + simpleBlock = &ScaleTV3x; + break; + case scalerOpRGB: + if (render.scale.size == 2) + simpleBlock = &ScaleRGB2x; + else if (render.scale.size == 3) + simpleBlock = &ScaleRGB3x; + break; + case scalerOpScan: + if (render.scale.size == 2) + simpleBlock = &ScaleScan2x; + else if (render.scale.size == 3) + simpleBlock = &ScaleScan3x; + break; + } } else if (dblw) { - render.op.type=OP_Normal2x; + simpleBlock = &ScaleNormalDw; } else if (dblh) { - render.op.type=OP_Normal; - gfx_scaleh*=2; + simpleBlock = &ScaleNormalDh; } else { forcenormal: - render.op.type=OP_Normal; + complexBlock = 0; + simpleBlock = &ScaleNormal1x; } - switch (render.op.type) { - case OP_Normal:block=&Normal_8;break; - case OP_Normal2x:block=(dblh) ? &Normal2x_8 : &NormalDbl_8;break; - case OP_AdvMame2x:block=&AdvMame2x_8;break; - case OP_AdvMame3x:block=&AdvMame3x_8;break; - case OP_Interp2x:block=&Interp2x_8;break; - case OP_AdvInterp2x:block=&AdvInterp2x_8;break; - case OP_TV2x:block=&TV2x_8;break; - } - gfx_flags=GFX_GetBestMode(block->flags); - if (!gfx_flags) { - if (render.op.type==OP_Normal) E_Exit("Failed to create a rendering output"); - else goto forcenormal; - } - /* Special test for normal2x to switch to normal with hardware scaling */ - if (gfx_flags & HAVE_SCALING && render.op.type==OP_Normal2x) { - if (dblw) gfx_scalew*=2; - if (dblh) gfx_scaleh*=2; - block=&Normal_8; - render.op.type=OP_Normal; - } - width*=block->xscale; - if (gfx_flags & HAVE_SCALING) { - height=MakeAspectTable(render.src.height,block->yscale,block->miny); + if (complexBlock) { + if ((width >= SCALER_COMPLEXWIDTH - 16) || height >= SCALER_COMPLEXHEIGHT - 16) { + LOG_MSG("Scaler can't handle this resolution, going back to normal"); + goto forcenormal; + } + gfx_flags = complexBlock->gfxFlags; + xscale = complexBlock->xscale; + yscale = complexBlock->yscale; } else { - gfx_scaleh*=block->yscale; - height=MakeAspectTable(render.src.height,gfx_scaleh,block->miny); + gfx_flags = simpleBlock->gfxFlags; + xscale = simpleBlock->xscale; + yscale = simpleBlock->yscale; + } + switch (render.src.bpp) { + case 8: + if (gfx_flags & GFX_CAN_8) + gfx_flags |= GFX_LOVE_8; + else + gfx_flags |= GFX_LOVE_32; + break; + case 15: + gfx_flags |= GFX_LOVE_15; + gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY; + break; + case 16: + gfx_flags |= GFX_LOVE_16; + gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY; + break; + case 32: + gfx_flags |= GFX_LOVE_32; + gfx_flags = (gfx_flags & ~GFX_CAN_8) | GFX_RGBONLY; + break; + } + gfx_flags=GFX_GetBestMode(gfx_flags); + if (!gfx_flags) { + if (!complexBlock && simpleBlock == &ScaleNormal1x) + E_Exit("Failed to create a rendering output"); + else + goto forcenormal; + } + width *= xscale; + if (gfx_flags & GFX_SCALING) { + height = MakeAspectTable(render.src.height, yscale, yscale ); + } else { + if ((gfx_flags & GFX_CAN_RANDOM) && gfx_scaleh > 1) { + gfx_scaleh *= yscale; + height = MakeAspectTable(render.src.height, gfx_scaleh, yscale ); + } else { + gfx_flags &= ~GFX_CAN_RANDOM; //Hardware surface when possible + height = MakeAspectTable(render.src.height, yscale, yscale); + } } /* Setup the scaler variables */ - render.op.mode=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_ReInit);; - if (render.op.mode==GFX_NONE) E_Exit("Failed to create a rendering output"); - render.op.line_handler=block->handlers[render.op.mode]; - render.op.width=width; - render.op.height=height; - Scaler_SrcWidth=render.src.width; - Scaler_SrcHeight=render.src.height; - RENDER_ResetPal(); + gfx_flags=GFX_SetSize(width,height,gfx_flags,gfx_scalew,gfx_scaleh,&RENDER_CallBack); + if (gfx_flags & GFX_CAN_8) + render.scale.outMode = scalerMode8; + else if (gfx_flags & GFX_CAN_15) + render.scale.outMode = scalerMode15; + else if (gfx_flags & GFX_CAN_16) + render.scale.outMode = scalerMode16; + else if (gfx_flags & GFX_CAN_32) + render.scale.outMode = scalerMode32; + else + E_Exit("Failed to create a rendering output"); + ScalerLineBlock_t *lineBlock; + if (gfx_flags & GFX_HARDWARE) { + if (complexBlock) { + lineBlock = &ScalerCache; + render.scale.complexHandler = complexBlock->Linear[ render.scale.outMode ]; + } else { + render.scale.complexHandler = 0; + lineBlock = &simpleBlock->Linear; + } + } else { + if (complexBlock) { + lineBlock = &ScalerCache; + render.scale.complexHandler = complexBlock->Random[ render.scale.outMode ]; + } else { + render.scale.complexHandler = 0; + lineBlock = &simpleBlock->Random; + } + } + switch (render.src.bpp) { + case 8: + render.scale.lineHandler = (*lineBlock)[0][render.scale.outMode]; + render.scale.linePalHandler = (*lineBlock)[4][render.scale.outMode]; + render.scale.inMode = scalerMode8; + render.scale.cachePitch = render.src.width * 1; + break; + case 15: + render.scale.lineHandler = (*lineBlock)[1][render.scale.outMode]; + render.scale.linePalHandler = 0; + render.scale.inMode = scalerMode15; + render.scale.cachePitch = render.src.width * 2; + break; + case 16: + render.scale.lineHandler = (*lineBlock)[2][render.scale.outMode]; + render.scale.linePalHandler = 0; + render.scale.inMode = scalerMode16; + render.scale.cachePitch = render.src.width * 2; + break; + case 32: + render.scale.lineHandler = (*lineBlock)[3][render.scale.outMode]; + render.scale.linePalHandler = 0; + render.scale.inMode = scalerMode32; + render.scale.cachePitch = render.src.width * 4; + break; + default: + E_Exit("RENDER:Wrong source bpp %d", render.src.bpp ); + } + render.scale.blocks = render.src.width / SCALER_BLOCKSIZE; + render.scale.lastBlock = render.src.width % SCALER_BLOCKSIZE; + render.scale.inHeight = render.src.height; + /* Reset the palette change detection to it's initial value */ + render.pal.first= 0; + render.pal.last = 255; + render.pal.changed = false; + memset(render.pal.modified, 0, sizeof(render.pal.modified)); + /* Signal the next frame to first reinit the cache */ + render.scale.clearCache = true; render.active=true; } -void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,double ratio,bool dblw,bool dblh) { - if (!width || !height) { +void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh) { + if (!width || !height || width > SCALER_MAXWIDTH || height > SCALER_MAXHEIGHT) { render.active=false; return; } + RENDER_EndUpdate( false ); render.src.width=width; render.src.height=height; render.src.bpp=bpp; render.src.dblw=dblw; render.src.dblh=dblh; - render.src.ratio=render.aspect ? ratio : 1.0; - RENDER_ReInit(); + render.src.fps=fps; + render.src.ratio=ratio; + RENDER_CallBack( GFX_CallBackReset ); } extern void GFX_SetTitle(Bits cycles, Bits frameskip,bool paused); -static void IncreaseFrameSkip(void) { +static void IncreaseFrameSkip(bool pressed) { + if (!pressed) + return; if (render.frameskip.max<10) render.frameskip.max++; LOG_MSG("Frame Skip at %d",render.frameskip.max); GFX_SetTitle(-1,render.frameskip.max,false); } -static void DecreaseFrameSkip(void) { +static void DecreaseFrameSkip(bool pressed) { + if (!pressed) + return; if (render.frameskip.max>0) render.frameskip.max--; LOG_MSG("Frame Skip at %d",render.frameskip.max); GFX_SetTitle(-1,render.frameskip.max,false); @@ -376,32 +425,46 @@ static void DecreaseFrameSkip(void) { void RENDER_Init(Section * sec) { Section_prop * section=static_cast(sec); + //For restarting the renderer. + static bool running = false; + bool aspect = render.aspect; + scalerOperation_t scaleOp = render.scale.op; + render.pal.first=256; render.pal.last=0; render.aspect=section->Get_bool("aspect"); render.frameskip.max=section->Get_int("frameskip"); render.frameskip.count=0; - render.updating=true; -#if (C_SSHOT) - MAPPER_AddHandler(EnableScreenShot,MK_f5,MMOD1,"scrshot","Screenshot"); -#endif const char * scaler;std::string cline; if (control->cmdline->FindString("-scaler",cline,false)) { scaler=cline.c_str(); } else { scaler=section->Get_string("scaler"); } - if (!strcasecmp(scaler,"none")) render.op.want_type=OP_Normal; - else if (!strcasecmp(scaler,"normal2x")) render.op.want_type=OP_Normal2x; - else if (!strcasecmp(scaler,"advmame2x")) render.op.want_type=OP_AdvMame2x; - else if (!strcasecmp(scaler,"advmame3x")) render.op.want_type=OP_AdvMame3x; - else if (!strcasecmp(scaler,"advinterp2x")) render.op.want_type=OP_AdvInterp2x; - else if (!strcasecmp(scaler,"interp2x")) render.op.want_type=OP_Interp2x; - else if (!strcasecmp(scaler,"tv2x")) render.op.want_type=OP_TV2x; + if (!strcasecmp(scaler,"none")) { render.scale.op = scalerOpNormal;render.scale.size = 1; } + else if (!strcasecmp(scaler,"normal2x")) { render.scale.op = scalerOpNormal;render.scale.size = 2; } + else if (!strcasecmp(scaler,"normal3x")) { render.scale.op = scalerOpNormal;render.scale.size = 3; } + else if (!strcasecmp(scaler,"advmame2x")) { render.scale.op = scalerOpAdvMame;render.scale.size = 2; } + else if (!strcasecmp(scaler,"advmame3x")) { render.scale.op = scalerOpAdvMame;render.scale.size = 3; } + else if (!strcasecmp(scaler,"advinterp2x")) { render.scale.op = scalerOpAdvMame;render.scale.size = 2; } + else if (!strcasecmp(scaler,"advinterp3x")) { render.scale.op = scalerOpAdvMame;render.scale.size = 3; } + else if (!strcasecmp(scaler,"tv2x")) { render.scale.op = scalerOpTV;render.scale.size = 2; } + else if (!strcasecmp(scaler,"tv3x")) { render.scale.op = scalerOpTV;render.scale.size = 3; } + else if (!strcasecmp(scaler,"rgb2x")){ render.scale.op = scalerOpRGB;render.scale.size = 2; } + else if (!strcasecmp(scaler,"rgb3x")){ render.scale.op = scalerOpRGB;render.scale.size = 3; } + else if (!strcasecmp(scaler,"scan2x")){ render.scale.op = scalerOpScan;render.scale.size = 2; } + else if (!strcasecmp(scaler,"scan3x")){ render.scale.op = scalerOpScan;render.scale.size = 3; } else { - render.op.want_type=OP_Normal; + render.scale.op = scalerOpNormal;render.scale.size = 1; LOG_MSG("Illegal scaler type %s,falling back to normal.",scaler); } + + //If something changed that needs a ReInit + if(running && (render.aspect != aspect || render.scale.op != scaleOp)) + RENDER_CallBack( GFX_CallBackReset ); + if(!running) render.updating=true; + running = true; + MAPPER_AddHandler(DecreaseFrameSkip,MK_f7,MMOD1,"decfskip","Dec Fskip"); MAPPER_AddHandler(IncreaseFrameSkip,MK_f8,MMOD1,"incfskip","Inc Fskip"); GFX_SetTitle(-1,render.frameskip.max,false); diff --git a/src/gui/render_loops.h b/src/gui/render_loops.h new file mode 100644 index 0000000..40fb97b --- /dev/null +++ b/src/gui/render_loops.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +#if defined (SCALERLINEAR) +static void conc3d(SCALERNAME,SBPP,L)(void) { +#else +static void conc3d(SCALERNAME,SBPP,R)(void) { +#endif + if (!render.scale.outLine) { + render.scale.outLine++; + return; + } +lastagain: + if (!CC[render.scale.outLine][0]) { +#if defined(SCALERLINEAR) + Bitu scaleLines = SCALERHEIGHT; +#else + Bitu scaleLines = SCALERHEIGHT + Scaler_Aspect[ render.scale.outLine ]; +#endif + render.scale.outWrite += render.scale.outPitch * scaleLines; + if (!(Scaler_ChangedLineIndex & 1)) { + Scaler_ChangedLines[Scaler_ChangedLineIndex] += scaleLines; + } else { + Scaler_ChangedLines[++Scaler_ChangedLineIndex] = scaleLines; + } + if (++render.scale.outLine == render.scale.inHeight) + goto lastagain; + return; + } + /* Clear the complete line marker */ + CC[render.scale.outLine][0] = 0; + const PTYPE * fc = &FC[render.scale.outLine][1]; + PTYPE * line0=(PTYPE *)(render.scale.outWrite); + Bit8u * changed = &CC[render.scale.outLine][1]; + Bitu b; + for (b=0;b 1) + PTYPE * line1; +#endif +#if (SCALERHEIGHT > 2) + PTYPE * line2; +#endif + /* Clear this block being dirty marker */ + const Bitu changeType = changed[b]; + changed[b] = 0; + switch (changeType) { + case 0: + line0 += SCALERWIDTH * SCALER_BLOCKSIZE; + fc += SCALER_BLOCKSIZE; + continue; + case SCALE_LEFT: +#if (SCALERHEIGHT > 1) + line1 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch); +#endif +#if (SCALERHEIGHT > 2) + line2 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch * 2); +#endif + SCALERFUNC; + line0 += SCALERWIDTH * SCALER_BLOCKSIZE; + fc += SCALER_BLOCKSIZE; + break; + case SCALE_LEFT | SCALE_RIGHT: +#if (SCALERHEIGHT > 1) + line1 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch); +#endif +#if (SCALERHEIGHT > 2) + line2 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch * 2); +#endif + SCALERFUNC; + case SCALE_RIGHT: +#if (SCALERHEIGHT > 1) + line1 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch); +#endif +#if (SCALERHEIGHT > 2) + line2 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch * 2); +#endif + line0 += SCALERWIDTH * (SCALER_BLOCKSIZE -1); +#if (SCALERHEIGHT > 1) + line1 += SCALERWIDTH * (SCALER_BLOCKSIZE -1); +#endif +#if (SCALERHEIGHT > 2) + line2 += SCALERWIDTH * (SCALER_BLOCKSIZE -1); +#endif + fc += SCALER_BLOCKSIZE -1; + SCALERFUNC; + line0 += SCALERWIDTH; + fc++; + break; + default: +#if defined(SCALERLINEAR) +#if (SCALERHEIGHT > 1) + line1 = WC[0]; +#endif +#if (SCALERHEIGHT > 2) + line2 = WC[1]; +#endif +#else +#if (SCALERHEIGHT > 1) + line1 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch); +#endif +#if (SCALERHEIGHT > 2) + line2 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch * 2); +#endif +#endif //defined(SCALERLINEAR) + for (Bitu i = 0; i 1) + line1 += SCALERWIDTH; +#endif +#if (SCALERHEIGHT > 2) + line2 += SCALERWIDTH; +#endif + fc++; + } +#if defined(SCALERLINEAR) +#if (SCALERHEIGHT > 1) + BituMove((Bit8u*)(&line0[-SCALER_BLOCKSIZE*SCALERWIDTH])+render.scale.outPitch ,WC[0], SCALER_BLOCKSIZE *SCALERWIDTH*PSIZE); +#endif +#if (SCALERHEIGHT > 2) + BituMove((Bit8u*)(&line0[-SCALER_BLOCKSIZE*SCALERWIDTH])+render.scale.outPitch*2,WC[1], SCALER_BLOCKSIZE *SCALERWIDTH*PSIZE); +#endif +#endif //defined(SCALERLINEAR) + break; + } + } +#if defined(SCALERLINEAR) + Bitu scaleLines = SCALERHEIGHT; + render.scale.outWrite += render.scale.outPitch * scaleLines; +#else + Bitu scaleLines = SCALERHEIGHT; + if ( Scaler_Aspect[ render.scale.outLine ] ) { + scaleLines++; + BituMove( render.scale.outWrite + render.scale.outPitch * SCALERHEIGHT, + render.scale.outWrite + render.scale.outPitch * (SCALERHEIGHT-1), + render.src.width * SCALERWIDTH * PSIZE); + render.scale.outWrite += render.scale.outPitch * (SCALERHEIGHT + 1); + } else { + render.scale.outWrite += render.scale.outPitch * SCALERHEIGHT; + } +#endif + /* Keep track of changed lines */ + if (Scaler_ChangedLineIndex & 1) { + Scaler_ChangedLines[Scaler_ChangedLineIndex] += scaleLines; + } else { + Scaler_ChangedLines[++Scaler_ChangedLineIndex] = scaleLines; + } + if (++render.scale.outLine == render.scale.inHeight) + goto lastagain; +} + +#if !defined(SCALERLINEAR) +#define SCALERLINEAR 1 +#include "render_loops.h" +#undef SCALERLINEAR +#endif diff --git a/src/gui/render_scalers.cpp b/src/gui/render_scalers.cpp index a0cedbc..dc7d084 100644 --- a/src/gui/render_scalers.cpp +++ b/src/gui/render_scalers.cpp @@ -1,40 +1,65 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + + +//TODO: +//Maybe just do the cache checking back into the simple scalers so they can +//just handle it all in one go, but this seems to work well enough for now + #include "dosbox.h" -#include "render_scalers.h" +#include "render.h" +#include -Bitu Scaler_Line; -Bitu Scaler_SrcWidth; -Bitu Scaler_SrcHeight; -Bitu Scaler_DstPitch; -Bit8u * Scaler_DstWrite; -Bit8u * Scaler_Index; -Bit8u Scaler_Data[SCALER_MAXHEIGHT*5]; //5cmds/line -PaletteLut Scaler_PaletteLut; +Bit8u Scaler_Aspect[SCALER_MAXHEIGHT]; +Bit16u Scaler_ChangedLines[SCALER_MAXHEIGHT]; +Bitu Scaler_ChangedLineIndex; -static union { - Bit32u b32 [4][SCALER_MAXWIDTH]; - Bit16u b16 [4][SCALER_MAXWIDTH]; - Bit8u b8 [4][SCALER_MAXWIDTH]; -} line_cache; static union { Bit32u b32 [4][SCALER_MAXWIDTH*3]; Bit16u b16 [4][SCALER_MAXWIDTH*3]; Bit8u b8 [4][SCALER_MAXWIDTH*3]; -} write_cache; - -static Bit8u * ln[3]; +} scalerWriteCache; +//scalerFrameCache_t scalerFrameCache; +scalerSourceCache_t scalerSourceCache; +scalerChangeCache_t scalerChangeCache; #define _conc2(A,B) A ## B #define _conc3(A,B,C) A ## B ## C #define _conc4(A,B,C,D) A ## B ## C ## D #define _conc5(A,B,C,D,E) A ## B ## C ## D ## E +#define _conc7(A,B,C,D,E,F,G) A ## B ## C ## D ## E ## F ## G #define conc2(A,B) _conc2(A,B) #define conc3(A,B,C) _conc3(A,B,C) #define conc4(A,B,C,D) _conc4(A,B,C,D) #define conc2d(A,B) _conc3(A,_,B) #define conc3d(A,B,C) _conc5(A,_,B,_,C) +#define conc4d(A,B,C,D) _conc7(A,_,B,_,C,_,D) -#define BituMove(_DST,_SRC,_SIZE) \ +static INLINE void BituMove( void *_dst, const void * _src, Bitu size) { + Bitu * dst=(Bitu *)(_dst); + const Bitu * src=(Bitu *)(_src); + size/=sizeof(Bitu); + for (Bitu x=0; x0;) { + if (*(Bit32u*)src == *(Bit32u*)cache && !( + render.pal.modified[src[0]] | + render.pal.modified[src[1]] | + render.pal.modified[src[2]] | + render.pal.modified[src[3]] )) { + x-=4; + src+=4; + cache+=4; + line0+=4*SCALERWIDTH; +#else + for (Bits x=render.src.width;x>0;) { + if (*(Bitu*)src == *(Bitu*)cache) { + x-=(sizeof(Bitu)/sizeof(SRCTYPE)); + src+=(sizeof(Bitu)/sizeof(SRCTYPE)); + cache+=(sizeof(Bitu)/sizeof(SRCTYPE)); + line0+=(sizeof(Bitu)/sizeof(SRCTYPE))*SCALERWIDTH; +#endif + } else { +#if defined(SCALERLINEAR) +#if (SCALERHEIGHT > 1) + PTYPE *line1 = WC[0]; +#endif +#if (SCALERHEIGHT > 2) + PTYPE *line2 = WC[1]; +#endif +#else +#if (SCALERHEIGHT > 1) + PTYPE *line1 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch); +#endif +#if (SCALERHEIGHT > 2) + PTYPE *line2 = (PTYPE *)(((Bit8u*)line0)+ render.scale.outPitch * 2); +#endif +#endif //defined(SCALERLINEAR) + hadChange = 1; + for (Bitu i = x > 32 ? 32 : x;i>0;i--,x--) { + const SRCTYPE S = *src; + *cache = S; + src++;cache++; + const PTYPE P = PMAKE(S); + SCALERFUNC; + line0 += SCALERWIDTH; +#if (SCALERHEIGHT > 1) + line1 += SCALERWIDTH; +#endif +#if (SCALERHEIGHT > 2) + line2 += SCALERWIDTH; +#endif + } +#if defined(SCALERLINEAR) +#if (SCALERHEIGHT > 1) + Bitu copyLen = (Bit8u*)line1 - (Bit8u*)WC[0]; + BituMove(((Bit8u*)line0)-copyLen+render.scale.outPitch ,WC[0], copyLen ); +#endif +#if (SCALERHEIGHT > 2) + BituMove(((Bit8u*)line0)-copyLen+render.scale.outPitch*2,WC[1], copyLen ); +#endif +#endif //defined(SCALERLINEAR) + } + } +#if defined(SCALERLINEAR) + Bitu scaleLines = SCALERHEIGHT; + render.scale.outWrite += render.scale.outPitch * scaleLines; +#else + Bitu scaleLines = SCALERHEIGHT; + if ( Scaler_Aspect[ render.scale.outLine++ ] ) { + scaleLines++; + if (hadChange) + BituMove( render.scale.outWrite + render.scale.outPitch * SCALERHEIGHT, + render.scale.outWrite + render.scale.outPitch * (SCALERHEIGHT-1), + render.src.width * SCALERWIDTH * PSIZE); + render.scale.outWrite += render.scale.outPitch * (SCALERHEIGHT + 1); + } else { + render.scale.outWrite += render.scale.outPitch * SCALERHEIGHT; + } + /* Keep track of changed lines */ + if ((Scaler_ChangedLineIndex & 1) == hadChange) { + Scaler_ChangedLines[Scaler_ChangedLineIndex] += scaleLines; + } else { + Scaler_ChangedLines[++Scaler_ChangedLineIndex] = scaleLines; + } +#endif +} + +#if !defined(SCALERLINEAR) +#define SCALERLINEAR 1 +#include "render_simple.h" +#undef SCALERLINEAR +#endif diff --git a/src/gui/render_templates.h b/src/gui/render_templates.h index 67d181e..21631bc 100644 --- a/src/gui/render_templates.h +++ b/src/gui/render_templates.h @@ -1,294 +1,462 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + #if DBPP == 8 #define PSIZE 1 #define PTYPE Bit8u -#define WC write_cache.b8 -#define LC line_cache.b8 -#define redblueMask 0 -#define greenMask 0 +#define WC scalerWriteCache.b8 +//#define FC scalerFrameCache.b8 +#define FC (*(scalerFrameCache_t*)(&scalerSourceCache.b32[400][0])).b8 +#define redMask 0 +#define greenMask 0 +#define blueMask 0 #elif DBPP == 15 || DBPP == 16 #define PSIZE 2 #define PTYPE Bit16u -#define WC write_cache.b16 -#define LC line_cache.b16 +#define WC scalerWriteCache.b16 +//#define FC scalerFrameCache.b16 +#define FC (*(scalerFrameCache_t*)(&scalerSourceCache.b32[400][0])).b16 #if DBPP == 15 -#define redblueMask 0x7C1F -#define greenMask 0x03E0 +#define redMask 0x7C00 +#define greenMask 0x03E0 +#define blueMask 0x001F #elif DBPP == 16 -#define redblueMask 0xF81F -#define greenMask 0x07E0 +#define redMask 0xF800 +#define greenMask 0x07E0 +#define blueMask 0x001F #endif #elif DBPP == 32 #define PSIZE 4 #define PTYPE Bit32u -#define WC write_cache.b32 -#define LC line_cache.b32 -#define redblueMask 0xff00ff -#define greenMask 0xff00 +#define WC scalerWriteCache.b32 +//#define FC scalerFrameCache.b32 +#define FC (*(scalerFrameCache_t*)(&scalerSourceCache.b32[400][0])).b32 +#define redMask 0xff0000 +#define greenMask 0x00ff00 +#define blueMask 0x0000ff #endif -#if SBPP == 8 +#define redblueMask (redMask | blueMask) + + +#if SBPP == 8 || SBPP == 9 +#define SC scalerSourceCache.b8 #if DBPP == 8 -#define PMAKE(_VAL) _VAL +#define PMAKE(_VAL) (_VAL) #elif DBPP == 15 -#define PMAKE(_VAL) Scaler_PaletteLut.b16[_VAL] +#define PMAKE(_VAL) render.pal.lut.b16[_VAL] #elif DBPP == 16 -#define PMAKE(_VAL) Scaler_PaletteLut.b16[_VAL] +#define PMAKE(_VAL) render.pal.lut.b16[_VAL] #elif DBPP == 32 -#define PMAKE(_VAL) Scaler_PaletteLut.b32[_VAL] +#define PMAKE(_VAL) render.pal.lut.b32[_VAL] #endif +#define SRCTYPE Bit8u #endif -#define C0 LC[0][x-1] -#define C1 LC[0][x+0] -#define C2 LC[0][x+1] -#define C3 LC[1][x-1] -#define C4 LC[1][x+0] -#define C5 LC[1][x+1] -#define C6 LC[2][x-1] -#define C7 LC[2][x+0] -#define C8 LC[2][x+1] - -static void conc3d(Normal,SBPP,DBPP) (const Bit8u * src) { - const Bit8u * line; -#if SBPP == DBPP - line=src; - BituMove(Scaler_DstWrite,line,Scaler_SrcWidth*PSIZE); -#else - PTYPE * dst=(PTYPE *)Scaler_DstWrite; - line=line_cache.b8[0]; - for (Bitu x=0;x>1)|(_VAL&31)) +#elif DBPP == 16 +#define PMAKE(_VAL) (_VAL) +#elif DBPP == 32 +#define PMAKE(_VAL) (((_VAL&(31<<11))<<8)|((_VAL&(63<<5))<<5)|((_VAL&31)<<3)) +#endif +#define SRCTYPE Bit16u +#endif + +#if SBPP == 32 +#define SC scalerSourceCache.b32 +#if DBPP == 15 +#define PMAKE(_VAL) (PTYPE)(((_VAL&(31<<19))>>9)|((_VAL&(31<<11))>>6)|((_VAL&(31<<3))>>3)) +#elif DBPP == 16 +#define PMAKE(_VAL) (PTYPE)(((_VAL&(31<<19))>>8)|((_VAL&(63<<10))>>4)|((_VAL&(31<<3))>>3)) +#elif DBPP == 32 +#define PMAKE(_VAL) (_VAL) +#endif +#define SRCTYPE Bit32u +#endif + +#define C0 fc[-1 - SCALER_COMPLEXWIDTH] +#define C1 fc[+0 - SCALER_COMPLEXWIDTH] +#define C2 fc[+1 - SCALER_COMPLEXWIDTH] +#define C3 fc[-1 ] +#define C4 fc[+0 ] +#define C5 fc[+1 ] +#define C6 fc[-1 + SCALER_COMPLEXWIDTH] +#define C7 fc[+0 + SCALER_COMPLEXWIDTH] +#define C8 fc[+1 + SCALER_COMPLEXWIDTH] + +static void conc3d(Cache,SBPP,DBPP) (const void * s) { + const SRCTYPE * src = (SRCTYPE*)s; + PTYPE *fc= &FC[render.scale.inLine+1][1]; + SRCTYPE *sc = (SRCTYPE*)(render.scale.cacheRead); + render.scale.cacheRead += render.scale.cachePitch; + Bitu b; + bool hadChange = false; + /* This should also copy the surrounding pixels but it looks nice enough without */ + for (b=0;b 8) -static void conc3d(TV2x,SBPP,DBPP) (const Bit8u * src) { - PTYPE * dst=(PTYPE *)Scaler_DstWrite; - for (Bitu x=0;x> 3) & redblueMask; - halfpixel|=(((pixel & greenMask) * 7) >> 3) & greenMask; - dst[x*2+0]=dst[x*2+1]=halfpixel; - LC[0][x*2+0]=LC[0][x*2+1]=pixel; - } - Scaler_DstWrite+=Scaler_DstPitch; - for (Bitu lines=*Scaler_Index++;lines;lines--) { - BituMove(Scaler_DstWrite,LC[0],Scaler_SrcWidth*2*PSIZE); - Scaler_DstWrite+=Scaler_DstPitch; - } -} -static void conc3d(Interp2x,SBPP,DBPP) (const Bit8u * src) { - if (!Scaler_Line) { - Scaler_Line++; - for (Bitu tempx=Scaler_SrcWidth;tempx>0;tempx--) { - LC[1][tempx] = LC[2][tempx] = PMAKE(src[tempx]); - } - return; - } -lastagain: - Bitu x=0; - PTYPE * dst=(PTYPE *)Scaler_DstWrite; - C1=C4;C4=C7;C7=PMAKE(src[x]); - C2=C5;C5=C8;C8=PMAKE(src[x+1]); - dst[0] = interp_w2(C4,C1,3,1); - dst[1] = interp_w4(C4,C1,C2,C5,5,1,1,1); - WC[1][0] = interp_w2(C4,C7,3,1); - WC[1][1] = interp_w4(C4,C5,C8,C7,5,1,1,1); - for (x=1;x> 3) & redblueMask; \ + halfpixel|=(((P & greenMask) * 5) >> 3) & greenMask; \ + line0[0]=P; \ + line0[1]=P; \ + line1[0]=halfpixel; \ + line1[1]=halfpixel; \ } +#include "render_simple.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC -static void conc3d(AdvInterp2x,SBPP,DBPP) (const Bit8u * src) { - if (!Scaler_Line) { - Scaler_Line++; - for (Bitu tempx=Scaler_SrcWidth;tempx>0;tempx--) { - LC[1][tempx]=LC[2][tempx]=PMAKE(src[tempx]); - } - return; - } -lastagain: - Bitu x=0; - PTYPE * dst=(PTYPE *)Scaler_DstWrite; - C1=C4;C4=C7;C7=PMAKE(src[x]); - C2=C5;C5=C8;C8=PMAKE(src[x+1]); - dst[0]=C4; - WC[1][0]=C4; - dst[1] = C5 == C1 && C7 != C1 ? C2 : C4; - WC[1][1]= C5 == C7 && C1 != C7 ? C7 : C4; - for (x=1;x0;lines--) { - BituMove(Scaler_DstWrite,&WC[1],2*Scaler_SrcWidth*PSIZE); - Scaler_DstWrite+=Scaler_DstPitch; - } - if (++Scaler_Line==Scaler_SrcHeight) goto lastagain; +#define SCALERNAME TV3x +#define SCALERWIDTH 3 +#define SCALERHEIGHT 3 +#define SCALERFUNC \ +{ \ + Bitu halfpixel=(((P & redblueMask) * 5) >> 3) & redblueMask; \ + halfpixel|=(((P & greenMask) * 5) >> 3) & greenMask; \ + line0[0]=P; \ + line0[1]=P; \ + line0[2]=P; \ + line1[0]=halfpixel; \ + line1[1]=halfpixel; \ + line1[2]=halfpixel; \ + halfpixel=(((P & redblueMask) * 5) >> 4) & redblueMask; \ + halfpixel|=(((P & greenMask) * 5) >> 4) & greenMask; \ + line2[0]=halfpixel; \ + line2[1]=halfpixel; \ + line2[2]=halfpixel; \ } +#include "render_simple.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC -#endif //DBPP > 8 +#define SCALERNAME RGB2x +#define SCALERWIDTH 2 +#define SCALERHEIGHT 2 +#define SCALERFUNC \ + line0[0]=P & redMask; \ + line0[1]=P & greenMask; \ + line1[0]=P & blueMask; \ + line1[1]=P; +#include "render_simple.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC -static void conc3d(AdvMame2x,SBPP,DBPP) (const Bit8u * src) { - if (!Scaler_Line) { - Scaler_Line++; - for (Bitu tempx=Scaler_SrcWidth;tempx>0;tempx--) { - LC[1][tempx]=LC[2][tempx]=PMAKE(src[tempx]); - } - return; - } -lastagain: - Bitu x=0; - PTYPE * dst=(PTYPE *)Scaler_DstWrite; - C1=C4;C4=C7;C7=PMAKE(src[x]); - C2=C5;C5=C8;C8=PMAKE(src[x+1]); - dst[0]=C4; - WC[1][0]=C4; - dst[1] = C5 == C1 && C7 != C1 ? C2 : C4; - WC[1][1]= C5 == C7 && C1 != C7 ? C7 : C4; - for (x=1;x0;lines--) { - BituMove(Scaler_DstWrite,&WC[1],2*Scaler_SrcWidth*PSIZE); - Scaler_DstWrite+=Scaler_DstPitch; - } - if (++Scaler_Line==Scaler_SrcHeight) goto lastagain; -} +#define SCALERNAME RGB3x +#define SCALERWIDTH 3 +#define SCALERHEIGHT 3 +#define SCALERFUNC \ + line0[0]=P; \ + line0[1]=P & greenMask; \ + line0[2]=P & blueMask; \ + line1[0]=P & blueMask; \ + line1[1]=P; \ + line1[2]=P & redMask; \ + line2[0]=P & redMask; \ + line2[1]=P & greenMask; \ + line2[2]=P; +#include "render_simple.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC -static void conc3d(AdvMame3x,SBPP,DBPP) (const Bit8u * src) { - if (!Scaler_Line) { - Scaler_Line++; - for (Bitu tempx=Scaler_SrcWidth;tempx>0;tempx--) { - LC[1][tempx]=LC[2][tempx]=PMAKE(src[tempx]); - } - return; +#define SCALERNAME Scan2x +#define SCALERWIDTH 2 +#define SCALERHEIGHT 2 +#define SCALERFUNC \ + line0[0]=P; \ + line0[1]=P; \ + line1[0]=0; \ + line1[1]=0; +#include "render_simple.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC + +#define SCALERNAME Scan3x +#define SCALERWIDTH 3 +#define SCALERHEIGHT 3 +#define SCALERFUNC \ + line0[0]=P; \ + line0[1]=P; \ + line0[2]=P; \ + line1[0]=0; \ + line1[1]=0; \ + line1[2]=0; \ + line2[0]=0; \ + line2[1]=0; \ + line2[2]=0; +#include "render_simple.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC + +#endif //#if (DBPP > 8) + +/* Complex scalers */ +#if (SBPP == DBPP) + + +#if (DBPP > 8) + +#define SCALERNAME AdvInterp2x +#define SCALERWIDTH 2 +#define SCALERHEIGHT 2 +#define SCALERFUNC \ + if (C1 != C7 && C3 != C5) { \ + line0[0] = C3 == C1 ? interp_w2(C3,C4,5U,3U) : C4; \ + line0[1] = C1 == C5 ? interp_w2(C5,C4,5U,3U) : C4; \ + line1[0] = C3 == C7 ? interp_w2(C3,C4,5U,3U) : C4; \ + line1[1] = C7 == C5 ? interp_w2(C5,C4,5U,3U) : C4; \ + } else { \ + line0[0] = line0[1] = C4; \ + line1[0] = line1[1] = C4; \ } -lastagain: - PTYPE * dst=(PTYPE *)Scaler_DstWrite; - LC[0][0]=LC[1][0];LC[1][0]=LC[2][0];LC[2][0]=PMAKE(src[0]); - LC[0][1]=LC[1][1];LC[1][1]=LC[2][1];LC[2][1]=PMAKE(src[1]); - /* first pixel */ - dst[0] = LC[1][0]; - dst[1] = LC[1][0]; - dst[2] = (LC[1][1] == LC[0][0] && LC[2][0] != LC[0][0]) ? LC[0][0] : LC[1][0]; - WC[1][0] = LC[1][0]; - WC[1][1] = LC[1][0]; - WC[1][2] = (LC[0][0] != LC[2][0]) ? (((LC[1][1] == LC[0][0] && LC[1][0] != LC[2][1]) || (LC[1][1] == LC[2][0] && LC[1][0] != LC[0][1])) ? LC[1][1] : LC[1][0]) : LC[1][0]; - WC[2][0] = LC[1][0]; - WC[2][1] = LC[1][0]; - WC[2][2] = (LC[1][1] == LC[2][0] && LC[0][0] != LC[2][0]) ? LC[2][0] : LC[1][0]; - Bitu x; - for (x=1;x0;lines--) { - BituMove(Scaler_DstWrite,&WC[2],3*Scaler_SrcWidth*PSIZE); - Scaler_DstWrite+=Scaler_DstPitch; +#include "render_loops.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC + +#endif // #if (DBPP > 8) + +#define SCALERNAME AdvMame2x +#define SCALERWIDTH 2 +#define SCALERHEIGHT 2 +#define SCALERFUNC \ + if (C1 != C7 && C3 != C5) { \ + line0[0] = C3 == C1 ? C3 : C4; \ + line0[1] = C1 == C5 ? C5 : C4; \ + line1[0] = C3 == C7 ? C3 : C4; \ + line1[1] = C7 == C5 ? C5 : C4; \ + } else { \ + line0[0] = line0[1] = C4; \ + line1[0] = line1[1] = C4; \ } - if (++Scaler_Line==Scaler_SrcHeight) goto lastagain; -} +#include "render_loops.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC + +#define SCALERNAME AdvMame3x +#define SCALERWIDTH 3 +#define SCALERHEIGHT 3 +#define SCALERFUNC \ + if ((C1 != C7) && (C3 != C5)) { \ + line0[0] = C3 == C1 ? C3 : C4; \ + line0[1] = (C3 == C1 && C4 != C2) || (C5 == C1 && C4 != C0) ? C1 : C4; \ + line0[2] = C5 == C1 ? C5 : C4; \ + line1[0] = (C3 == C1 && C4 != C6) || (C3 == C7 && C4 != C0) ? C3 : C4; \ + line1[1] = C4; \ + line1[2] = (C5 == C1 && C4 != C8) || (C5 == C7 && C4 != C2) ? C5 : C4; \ + line2[0] = C3 == C7 ? C3 : C4; \ + line2[1] = (C3 == C7 && C4 != C8) || (C5 == C7 && C4 != C6) ? C7 : C4; \ + line2[2] = C5 == C7 ? C5 : C4; \ + } else { \ + line0[0] = line0[1] = line0[2] = C4; \ + line1[0] = line1[1] = line1[2] = C4; \ + line2[0] = line2[1] = line2[2] = C4; \ + } + +#include "render_loops.h" +#undef SCALERNAME +#undef SCALERWIDTH +#undef SCALERHEIGHT +#undef SCALERFUNC + + +#endif // (SBPP == DBPP) && !defined (CACHEWITHPAL) #undef PSIZE #undef PTYPE #undef PMAKE #undef WC #undef LC +#undef FC +#undef SC +#undef redMask #undef greenMask +#undef blueMask #undef redblueMask - +#undef SRCTYPE diff --git a/src/gui/sdl_mapper.cpp b/src/gui/sdl_mapper.cpp index eacd33c..eacc3d4 100644 --- a/src/gui/sdl_mapper.cpp +++ b/src/gui/sdl_mapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: sdl_mapper.cpp,v 1.10 2004/10/28 14:46:15 qbix79 Exp $ */ +/* $Id: sdl_mapper.cpp,v 1.21 2006/02/16 20:18:59 c2woody Exp $ */ #define OLD_JOYSTICK 1 @@ -95,7 +95,7 @@ static CBindList holdlist; class CEvent { public: CEvent(char * _entry) { - strncpy(entry,_entry,16); + safe_strncpy(entry,_entry,16); events.push_back(this); bindlist.clear(); activity=0; @@ -209,6 +209,138 @@ protected: }; + +#define MAX_SDLKEYS 323 + +static bool usescancodes; +static Bit8u scancode_map[MAX_SDLKEYS]; + +#define Z SDLK_UNKNOWN + +#if defined (MACOSX) +static SDLKey sdlkey_map[]={ + /* Main block printables */ + /*00-05*/ SDLK_a, SDLK_s, SDLK_d, SDLK_f, SDLK_h, SDLK_g, + /*06-0B*/ SDLK_z, SDLK_x, SDLK_c, SDLK_v, SDLK_WORLD_0, SDLK_b, + /*0C-11*/ SDLK_q, SDLK_w, SDLK_e, SDLK_r, SDLK_y, SDLK_t, + /*12-17*/ SDLK_1, SDLK_2, SDLK_3, SDLK_4, SDLK_6, SDLK_5, + /*18-1D*/ SDLK_EQUALS, SDLK_9, SDLK_7, SDLK_MINUS, SDLK_8, SDLK_0, + /*1E-21*/ SDLK_RIGHTBRACKET, SDLK_o, SDLK_u, SDLK_LEFTBRACKET, + /*22-23*/ SDLK_i, SDLK_p, + /*24-29*/ SDLK_RETURN, SDLK_l, SDLK_j, SDLK_QUOTE, SDLK_k, SDLK_SEMICOLON, + /*2A-29*/ SDLK_BACKSLASH, SDLK_COMMA, SDLK_SLASH, SDLK_n, SDLK_m, + /*2F-2F*/ SDLK_PERIOD, + + /* Spaces, controls, modifiers (dosbox uses LMETA only for + * hotkeys, it's not really mapped to an emulated key) */ + /*30-33*/ SDLK_TAB, SDLK_SPACE, SDLK_BACKQUOTE, SDLK_BACKSPACE, + /*34-37*/ Z, SDLK_ESCAPE, Z, SDLK_LMETA, + /*38-3B*/ SDLK_LSHIFT, SDLK_CAPSLOCK, SDLK_LALT, SDLK_LCTRL, + + /*3C-40*/ Z, Z, Z, Z, Z, + + /* Keypad (KP_EQUALS not supported, NUMLOCK used on what is CLEAR + * in Mac OS X) */ + /*41-46*/ SDLK_KP_PERIOD, Z, SDLK_KP_MULTIPLY, Z, SDLK_PLUS, Z, + /*47-4A*/ SDLK_NUMLOCK /*==SDLK_CLEAR*/, Z, Z, Z, + /*4B-4D*/ SDLK_KP_DIVIDE, SDLK_KP_ENTER, Z, + /*4E-51*/ SDLK_KP_MINUS, Z, Z, SDLK_KP_EQUALS, + /*52-57*/ SDLK_KP0, SDLK_KP1, SDLK_KP2, SDLK_KP3, SDLK_KP4, SDLK_KP5, + /*58-5C*/ SDLK_KP6, SDLK_KP7, Z, SDLK_KP8, SDLK_KP9, + + /*5D-5F*/ Z, Z, Z, + + /* Function keys and cursor blocks (F13-F16 not supported, INSERT + * used on what is HELP in Mac OS X) */ + /*60-64*/ SDLK_F5, SDLK_F6, SDLK_F7, SDLK_F3, SDLK_F8, + /*65-6A*/ SDLK_F9, Z, SDLK_F11, Z, SDLK_F13, (SDLKey)(SDLK_F15+1), + /*6B-71*/ SDLK_F14, Z, SDLK_F10, Z, SDLK_F12, Z, SDLK_F15, + /*72-74*/ SDLK_INSERT /*==SDLK_HELP*/, SDLK_HOME, SDLK_PAGEUP, + /*75-79*/ SDLK_DELETE, SDLK_F4, SDLK_END, SDLK_F2, SDLK_PAGEDOWN, + /*7A-7E*/ SDLK_F1, SDLK_LEFT, SDLK_RIGHT, SDLK_DOWN, SDLK_UP, + + /*7F-7F*/ Z, + + /* 4 extra keys that don't really exist, but are needed for + * round-trip mapping (dosbox uses RMETA only for hotkeys, it's + * not really mapped to an emulated key) */ + SDLK_RMETA, SDLK_RSHIFT, SDLK_RALT, SDLK_RCTRL, +}; +#define MAX_SCANCODES (0x80+4) +/* Make sure that the table above has the expected size. This + expression will raise a compiler error if the condition is false. */ +typedef char assert_right_size [MAX_SCANCODES == (sizeof(sdlkey_map)/sizeof(sdlkey_map[0])) ? 1 : -1]; + +#else // !MACOSX + +#define MAX_SCANCODES 212 +static SDLKey sdlkey_map[MAX_SCANCODES]={SDLK_UNKNOWN,SDLK_ESCAPE, + SDLK_1,SDLK_2,SDLK_3,SDLK_4,SDLK_5,SDLK_6,SDLK_7,SDLK_8,SDLK_9,SDLK_0, + /* 0x0c: */ + SDLK_MINUS,SDLK_EQUALS,SDLK_BACKSPACE,SDLK_TAB, + SDLK_q,SDLK_w,SDLK_e,SDLK_r,SDLK_t,SDLK_y,SDLK_u,SDLK_i,SDLK_o,SDLK_p, + SDLK_LEFTBRACKET,SDLK_RIGHTBRACKET,SDLK_RETURN,SDLK_LCTRL, + SDLK_a,SDLK_s,SDLK_d,SDLK_f,SDLK_g,SDLK_h,SDLK_j,SDLK_k,SDLK_l, + SDLK_SEMICOLON,SDLK_QUOTE,SDLK_BACKQUOTE,SDLK_LSHIFT,SDLK_BACKSLASH, + SDLK_z,SDLK_x,SDLK_c,SDLK_v,SDLK_b,SDLK_n,SDLK_m, + /* 0x33: */ + SDLK_COMMA,SDLK_PERIOD,SDLK_SLASH,SDLK_RSHIFT,SDLK_KP_MULTIPLY, + SDLK_LALT,SDLK_SPACE,SDLK_CAPSLOCK, + SDLK_F1,SDLK_F2,SDLK_F3,SDLK_F4,SDLK_F5,SDLK_F6,SDLK_F7,SDLK_F8,SDLK_F9,SDLK_F10, + /* 0x45: */ + SDLK_NUMLOCK,SDLK_SCROLLOCK, + SDLK_KP7,SDLK_KP8,SDLK_KP9,SDLK_KP_MINUS,SDLK_KP4,SDLK_KP5,SDLK_KP6,SDLK_KP_PLUS, + SDLK_KP1,SDLK_KP2,SDLK_KP3,SDLK_KP0,SDLK_KP_PERIOD, + SDLK_UNKNOWN,SDLK_UNKNOWN, + SDLK_LESS,SDLK_F11,SDLK_F12, + Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z, + Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z, + Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z, + /* 0xb7: */ + Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z,Z + /* 0xd4: ... */ +}; +#endif + +#undef Z + + +SDLKey MapSDLCode(Bitu skey) { + if (usescancodes) { + if (skey SDLK_WORLD_95) +#endif + ) { + /* try to retrieve key from symbolic key as scancode is zero */ + if (keysym.symtype!=SDL_KEYDOWN) return 0; - return CreateKeyBind(event->key.keysym.sym); + return CreateKeyBind((SDLKey)GetKeyCode(event->key.keysym)); }; bool CheckEvent(SDL_Event * event) { if (event->type!=SDL_KEYDOWN && event->type!=SDL_KEYUP) return false; - Bitu key=(Bitu)event->key.keysym.sym; - assert(keykey.keysym); +// LOG_MSG("key type %i is %x [%x %x]",event->type,key,event->key.keysym.sym,event->key.keysym.scancode); + assert(Bitu(event->key.keysym.sym)type==SDL_KEYDOWN) ActivateBindList(&lists[key],0x7fff); else DeactivateBindList(&lists[key]); return 0; } CBind * CreateKeyBind(SDLKey _key) { - assert((Bitu)_keyjbutton.button); } else return 0; } - bool CheckEvent(SDL_Event * event) { + virtual bool CheckEvent(SDL_Event * event) { #if OLD_JOYSTICK SDL_JoyAxisEvent * jaxis = NULL; SDL_JoyButtonEvent * jbutton = NULL; @@ -388,18 +528,19 @@ public: switch(event->type) { case SDL_JOYAXISMOTION: jaxis = &event->jaxis; - if(jaxis->axis == 0) - JOYSTICK_Move_X(stick,(float)(jaxis->value/32768.0)); - else if(jaxis->axis == 1) - JOYSTICK_Move_Y(stick,(float)(jaxis->value/32768.0)); + if(jaxis->which == stick) + if(jaxis->axis == 0) + JOYSTICK_Move_X(emustick,(float)(jaxis->value/32768.0)); + else if(jaxis->axis == 1) + JOYSTICK_Move_Y(emustick,(float)(jaxis->value/32768.0)); break; case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONUP: jbutton = &event->jbutton; bool state; state=jbutton->type==SDL_JOYBUTTONDOWN; - if (jbutton->button<2) { - JOYSTICK_Button(stick,jbutton->button,state); + if ((jbutton->which == stick) && (jbutton->button<2)) { + JOYSTICK_Button(emustick,jbutton->button,state); } break; } @@ -427,11 +568,201 @@ protected: CBindList * neg_axis_lists; CBindList * button_lists; CBindList * hat_lists; - Bitu stick,axes,buttons,hats; + Bitu stick,emustick,axes,buttons,hats; SDL_Joystick * sdl_joystick; char configname[10]; }; +class C4AxisBindGroup : public CStickBindGroup { +public: + C4AxisBindGroup(Bitu _stick) : CStickBindGroup (_stick){ +#if OLD_JOYSTICK + JOYSTICK_Enable(1,true); +#endif + } + bool CheckEvent(SDL_Event * event) { +#if OLD_JOYSTICK + SDL_JoyAxisEvent * jaxis = NULL; + SDL_JoyButtonEvent * jbutton = NULL; + + switch(event->type) { + case SDL_JOYAXISMOTION: + jaxis = &event->jaxis; + if(jaxis->which == stick && jaxis->axis < 4) + if(jaxis->axis & 1) + JOYSTICK_Move_Y(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0)); + else + JOYSTICK_Move_X(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0)); + break; + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + jbutton = &event->jbutton; + bool state; + state=jbutton->type==SDL_JOYBUTTONDOWN; + if ((jbutton->which == stick) && (jbutton->button<4)) { + JOYSTICK_Button((jbutton->button >> 1), + (jbutton->button & 1),state); + } + break; + } +#endif + return false; + } +}; + +class CFCSBindGroup : public CStickBindGroup { +public: + CFCSBindGroup(Bitu _stick) : CStickBindGroup (_stick){ +#if OLD_JOYSTICK + JOYSTICK_Enable(1,true); + JOYSTICK_Move_Y(1,1.0); +#endif + } + bool CheckEvent(SDL_Event * event) { +#if OLD_JOYSTICK + SDL_JoyAxisEvent * jaxis = NULL; + SDL_JoyButtonEvent * jbutton = NULL; + SDL_JoyHatEvent * jhat = NULL; + + switch(event->type) { + case SDL_JOYAXISMOTION: + jaxis = &event->jaxis; + if(jaxis->which == stick) + if(jaxis->axis == 0) + JOYSTICK_Move_X(0,(float)(jaxis->value/32768.0)); + else if(jaxis->axis == 1) + JOYSTICK_Move_Y(0,(float)(jaxis->value/32768.0)); + else if(jaxis->axis == 2) + JOYSTICK_Move_X(1,(float)(jaxis->value/32768.0)); + break; + case SDL_JOYHATMOTION: + jhat = &event->jhat; + if(jhat->which == stick) { + switch(jhat->value) { + case SDL_HAT_CENTERED: + JOYSTICK_Move_Y(1,1.0); + break; + case SDL_HAT_UP: + JOYSTICK_Move_Y(1,-1.0); + break; + case SDL_HAT_RIGHT: + JOYSTICK_Move_Y(1,-0.5); + break; + case SDL_HAT_DOWN: + JOYSTICK_Move_Y(1,0.0); + break; + case SDL_HAT_LEFT: + JOYSTICK_Move_Y(1,0.5); + break; + case SDL_HAT_LEFTUP: + if(JOYSTICK_GetMove_Y(1) < 0) + JOYSTICK_Move_Y(1,0.5); + else + JOYSTICK_Move_Y(1,-1.0); + break; + case SDL_HAT_RIGHTUP: + if(JOYSTICK_GetMove_Y(1) < -0.7) + JOYSTICK_Move_Y(1,-0.5); + else + JOYSTICK_Move_Y(1,-1.0); + break; + case SDL_HAT_RIGHTDOWN: + if(JOYSTICK_GetMove_Y(1) < -0.2) + JOYSTICK_Move_Y(1,0.0); + else + JOYSTICK_Move_Y(1,-0.5); + break; + case SDL_HAT_LEFTDOWN: + if(JOYSTICK_GetMove_Y(1) > 0.2) + JOYSTICK_Move_Y(1,0.0); + else + JOYSTICK_Move_Y(1,0.5); + break; + } + } + + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + jbutton = &event->jbutton; + bool state; + state=jbutton->type==SDL_JOYBUTTONDOWN; + if ((jbutton->which == stick) && (jbutton->button<4)) { + JOYSTICK_Button((jbutton->button >> 1), + (jbutton->button & 1),state); + } + break; + } +#endif + return false; + } +}; + +class CCHBindGroup : public CStickBindGroup { +public: + CCHBindGroup(Bitu _stick) : CStickBindGroup (_stick){ +#if OLD_JOYSTICK + JOYSTICK_Enable(1,true); + button_state=0; +#endif + } + bool CheckEvent(SDL_Event * event) { +#if OLD_JOYSTICK + SDL_JoyAxisEvent * jaxis = NULL; + SDL_JoyButtonEvent * jbutton = NULL; + SDL_JoyHatEvent * jhat = NULL; + static unsigned const button_magic[6]={0x02,0x04,0x10,0x100,0x20,0x200}; + static unsigned const hat_magic[2][5]={{0x8888,0x8000,0x800,0x80,0x08}, + {0x5440,0x4000,0x400,0x40,0x1000}}; + switch(event->type) { + case SDL_JOYAXISMOTION: + jaxis = &event->jaxis; + if(jaxis->which == stick && jaxis->axis < 4) + if(jaxis->axis & 1) + JOYSTICK_Move_Y(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0)); + else + JOYSTICK_Move_X(jaxis->axis>>1 & 1,(float)(jaxis->value/32768.0)); + break; + case SDL_JOYHATMOTION: + jhat = &event->jhat; + if(jhat->which == stick && jhat->hat < 2) { + if(jhat->value == SDL_HAT_CENTERED) + button_state&=~hat_magic[jhat->hat][0]; + if(jhat->value & SDL_HAT_UP) + button_state|=hat_magic[jhat->hat][1]; + if(jhat->value & SDL_HAT_RIGHT) + button_state|=hat_magic[jhat->hat][2]; + if(jhat->value & SDL_HAT_DOWN) + button_state|=hat_magic[jhat->hat][3]; + if(jhat->value & SDL_HAT_LEFT) + button_state|=hat_magic[jhat->hat][4]; + } + break; + case SDL_JOYBUTTONDOWN: + jbutton = &event->jbutton; + if ((jbutton->which == stick) && (jbutton->button<6)) + button_state|=button_magic[jbutton->button]; + break; + case SDL_JOYBUTTONUP: + jbutton = &event->jbutton; + if ((jbutton->which == stick) && (jbutton->button<6)) + button_state&=~button_magic[jbutton->button]; + break; + } + unsigned i; + Bit16u j; + j=button_state; + for(i=0;i<16;i++) if (j & 1) break; else j>>=1; + JOYSTICK_Button(0,0,i&0x01); + JOYSTICK_Button(0,1,i>>1&0x01); + JOYSTICK_Button(1,0,i>>2&0x01); + JOYSTICK_Button(1,1,i>>3&0x01); +#endif + + return false; + } +protected: + Bit16u button_state; +}; static struct { SDL_Surface * surface; @@ -729,7 +1060,7 @@ public: handlergroup.push_back(this); } void Active(bool yesno) { - if (yesno) (*handler)(); + (*handler)(yesno); }; char * ButtonName(void) { return buttonname; @@ -769,12 +1100,13 @@ public: protected: MapKeys defkey; Bitu defmod; - char * buttonname; MAPPER_Handler * handler; +public: + char * buttonname; }; -struct { +static struct { CCaptionButton * event_title; CCaptionButton * bind_title; CCaptionButton * selected; @@ -906,7 +1238,8 @@ static KeyBlock combo_3[12]={ {"\\","backslash",KBD_backslash}, }; -static KeyBlock combo_4[10]={ +static KeyBlock combo_4[11]={ + {"<","lessthan",KBD_extra_lt_gt}, {"z","z",KBD_z}, {"x","x",KBD_x}, {"c","c",KBD_c}, {"v","v",KBD_v}, {"b","b",KBD_b}, {"n","n",KBD_n}, {"m","m",KBD_m}, {",","comma",KBD_comma}, @@ -934,8 +1267,8 @@ static void CreateLayout(void) { AddKeyButtonEvent(PX(0),PY(3),BW*2,BH,"CLCK","capslock",KBD_capslock); for (i=0;i<12;i++) AddKeyButtonEvent(PX(2+i),PY(3),BW,BH,combo_3[i].title,combo_3[i].entry,combo_3[i].key); - AddKeyButtonEvent(PX(0),PY(4),BW*3,BH,"SHIFT","lshift",KBD_leftshift); - for (i=0;i<10;i++) AddKeyButtonEvent(PX(3+i),PY(4),BW,BH,combo_4[i].title,combo_4[i].entry,combo_4[i].key); + AddKeyButtonEvent(PX(0),PY(4),BW*2,BH,"SHIFT","lshift",KBD_leftshift); + for (i=0;i<11;i++) AddKeyButtonEvent(PX(2+i),PY(4),BW,BH,combo_4[i].title,combo_4[i].entry,combo_4[i].key); AddKeyButtonEvent(PX(13),PY(4),BW*3,BH,"SHIFT","rshift",KBD_rightshift); /* Last Row */ @@ -1106,6 +1439,14 @@ static struct { {"kp_divide",SDLK_KP_DIVIDE}, {"kp_multiply",SDLK_KP_MULTIPLY}, {"kp_minus",SDLK_KP_MINUS}, {"kp_plus",SDLK_KP_PLUS}, {"kp_period",SDLK_KP_PERIOD}, {"kp_enter",SDLK_KP_ENTER}, + +#if defined (MACOSX) + /* Intl Mac keyboards in US layout actually put U+00A7 SECTION SIGN here */ + {"lessthan",SDLK_WORLD_0}, +#else + {"lessthan",SDLK_LESS}, +#endif + {0,0} }; @@ -1133,6 +1474,10 @@ static void CreateDefaultBinds(void) { } void MAPPER_AddHandler(MAPPER_Handler * handler,MapKeys key,Bitu mods,char * eventname,char * buttonname) { + //Check if it allready exists=> if so return. + for(CHandlerEventVector_it it=handlergroup.begin();it!=handlergroup.end();it++) + if(strcmp((*it)->buttonname,buttonname) == 0) return; + char tempname[17]; strcpy(tempname,"hand_"); strcat(tempname,eventname); @@ -1209,12 +1554,42 @@ void BIND_MappingEvents(void) { static void CreateBindGroups(void) { bindgroups.clear(); new CKeyBindGroup(SDLK_LAST); - Bitu numsticks=SDL_NumJoysticks(); - if (numsticks) SDL_JoystickEventState(SDL_ENABLE); - for (Bitu i=0;iDeActivateAll(); + } +} + +void MAPPER_Run(bool pressed) { + if (!pressed) + return; /* Deactive all running binds */ for (CEventVector_it evit=events.begin();evit!=events.end();evit++) { (*evit)->DeActivateAll(); @@ -1227,8 +1602,9 @@ void MAPPER_Run(void) { } /* Be sure that there is no update in progress */ - GFX_EndUpdate(); + GFX_EndUpdate( 0 ); mapper.surface=SDL_SetVideoMode(640,480,8,0); + if (mapper.surface == NULL) E_Exit("Could not initialize video mode for mapper: %s",SDL_GetError()); /* Set some palette entries */ SDL_SetPalette(mapper.surface, SDL_LOGPAL|SDL_PHYSPAL, map_pal, 0, 4); @@ -1256,6 +1632,58 @@ void MAPPER_Init(void) { void MAPPER_StartUp(Section * sec) { Section_prop * section=static_cast(sec); + usescancodes=false; + + if (section->Get_bool("usescancodes")) { + usescancodes=true; + + /* Note: table has to be tested/updated for various OSs */ +#if defined (MACOSX) + /* nothing */ +#elif !defined (WIN32) /* => Linux */ + sdlkey_map[0x5a]=SDLK_UP; + sdlkey_map[0x60]=SDLK_DOWN; + sdlkey_map[0x5c]=SDLK_LEFT; + sdlkey_map[0x5e]=SDLK_RIGHT; + sdlkey_map[0x59]=SDLK_HOME; + sdlkey_map[0x5f]=SDLK_END; + sdlkey_map[0x5b]=SDLK_PAGEUP; + sdlkey_map[0x61]=SDLK_PAGEDOWN; + sdlkey_map[0x62]=SDLK_INSERT; + sdlkey_map[0x63]=SDLK_DELETE; + sdlkey_map[0x68]=SDLK_KP_DIVIDE; + sdlkey_map[0x64]=SDLK_KP_ENTER; + sdlkey_map[0x65]=SDLK_RCTRL; + sdlkey_map[0x66]=SDLK_PAUSE; + sdlkey_map[0x67]=SDLK_PRINT; + sdlkey_map[0x69]=SDLK_RALT; +#else + sdlkey_map[0xc8]=SDLK_UP; + sdlkey_map[0xd0]=SDLK_DOWN; + sdlkey_map[0xcb]=SDLK_LEFT; + sdlkey_map[0xcd]=SDLK_RIGHT; + sdlkey_map[0xc7]=SDLK_HOME; + sdlkey_map[0xcf]=SDLK_END; + sdlkey_map[0xc9]=SDLK_PAGEUP; + sdlkey_map[0xd1]=SDLK_PAGEDOWN; + sdlkey_map[0xd2]=SDLK_INSERT; + sdlkey_map[0xd3]=SDLK_DELETE; + sdlkey_map[0xb5]=SDLK_KP_DIVIDE; + sdlkey_map[0x9c]=SDLK_KP_ENTER; + sdlkey_map[0x9d]=SDLK_RCTRL; + sdlkey_map[0xc5]=SDLK_PAUSE; + sdlkey_map[0xb7]=SDLK_PRINT; + sdlkey_map[0xb8]=SDLK_RALT; +#endif + + Bitu i; + for (i=0; iGet_string("mapperfile"); MAPPER_AddHandler(&MAPPER_Run,MK_f1,MMOD1,"mapper","Mapper"); } diff --git a/src/gui/sdlmain.cpp b/src/gui/sdlmain.cpp index 555f2fb..9955798 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: sdlmain.cpp,v 1.81 2004/11/09 21:35:50 qbix79 Exp $ */ +/* $Id: sdlmain.cpp,v 1.113 2006/03/29 12:26:07 qbix79 Exp $ */ #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -40,6 +40,8 @@ #include "support.h" #include "debug.h" #include "mapper.h" +#include "vga.h" +#include "keyboard.h" //#define DISABLE_JOYSTICK @@ -93,7 +95,7 @@ extern char** environ; #define WIN32_LEAN_AND_MEAN #endif #include -#if defined(HAVE_DDRAW_H) +#if (HAVE_DDRAW_H) #include struct private_hwdata { LPDIRECTDRAWSURFACE3 dd_surface; @@ -115,6 +117,12 @@ struct private_hwdata { #define PRIO_TOTAL (PRIO_MAX-PRIO_MIN) #endif +#ifdef OS2 +#define INCL_DOS +#define INCL_WIN +#include +#endif + enum SCREEN_TYPES { SCREEN_SURFACE, SCREEN_SURFACE_DDRAW, @@ -123,6 +131,7 @@ enum SCREEN_TYPES { }; enum PRIORITY_LEVELS { + PRIORITY_LEVEL_LOWEST, PRIORITY_LEVEL_LOWER, PRIORITY_LEVEL_NORMAL, PRIORITY_LEVEL_HIGHER, @@ -136,20 +145,25 @@ struct SDL_Block { struct { Bit32u width; Bit32u height; + Bit32u bpp; Bitu flags; - GFX_Modes mode; double scalex,scaley; - GFX_ResetCallBack reset; + GFX_CallBack_t callback; } draw; bool wait_on_error; struct { - Bit32u width,height,bpp; - bool fixed; + struct { + Bit16u width, height; + bool fixed; + } full; + struct { + Bit16u width, height; + } window; + Bit8u bpp; bool fullscreen; bool doublebuf; SCREEN_TYPES type; SCREEN_TYPES want_type; - double hwscale; } desktop; #if C_OPENGL struct { @@ -166,13 +180,12 @@ struct SDL_Block { #endif } opengl; #endif -#if defined(HAVE_DDRAW_H) && defined(WIN32) struct { SDL_Surface * surface; +#if (HAVE_DDRAW_H) && defined(WIN32) RECT rect; - DDBLTFX fx; - } blit; #endif + } blit; struct { PRIORITY_LEVELS focus; PRIORITY_LEVELS nofocus; @@ -188,12 +201,13 @@ struct SDL_Block { bool locked; Bitu sensitivity; } mouse; + SDL_Rect updateRects[1024]; }; static SDL_Block sdl; -static void CaptureMouse(void); extern char * RunningProgram; +extern bool CPU_CycleAuto; //Globals for keyboard initialisation bool startup_state_numlock=false; bool startup_state_capslock=false; @@ -203,16 +217,21 @@ void GFX_SetTitle(Bits cycles,Bits frameskip,bool paused){ static Bits internal_frameskip=0; if(cycles != -1) internal_cycles = cycles; if(frameskip != -1) internal_frameskip = frameskip; - if(paused) - sprintf(title,"DOSBox %s,Cpu Cycles: %8d, Frameskip %2d, Program: %8s PAUSED",VERSION,internal_cycles,internal_frameskip,RunningProgram); + if(CPU_CycleAuto) + sprintf(title,"DOSBox %s, Cpu Cycles: auto, Frameskip %2d, Program: %8s",VERSION,internal_frameskip,RunningProgram); else - sprintf(title,"DOSBox %s,Cpu Cycles: %8d, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram); + sprintf(title,"DOSBox %s, Cpu Cycles: %8d, Frameskip %2d, Program: %8s",VERSION,internal_cycles,internal_frameskip,RunningProgram); + + if(paused) strcat(title," PAUSED"); SDL_WM_SetCaption(title,VERSION); } -static void PauseDOSBox(void) { +static void PauseDOSBox(bool pressed) { + if (!pressed) + return; GFX_SetTitle(-1,-1,true); bool paused = true; + KEYBOARD_ClrBuffer(); SDL_Delay(500); SDL_Event event; while (SDL_PollEvent(&event)) { @@ -240,47 +259,51 @@ Bitu GFX_GetBestMode(Bitu flags) { case SCREEN_SURFACE: check_surface: /* Check if we can satisfy the depth it loves */ - if (flags & LOVE_8) testbpp=8; - else if (flags & LOVE_16) testbpp=16; - else if (flags & LOVE_32) testbpp=32; + if (flags & GFX_LOVE_8) testbpp=8; + else if (flags & GFX_LOVE_15) testbpp=15; + else if (flags & GFX_LOVE_16) testbpp=16; + else if (flags & GFX_LOVE_32) testbpp=32; check_gotbpp: if (sdl.desktop.fullscreen) gotbpp=SDL_VideoModeOK(640,480,testbpp,SDL_FULLSCREEN|SDL_HWSURFACE|SDL_HWPALETTE); else gotbpp=sdl.desktop.bpp; /* If we can't get our favorite mode check for another working one */ switch (gotbpp) { case 8: - if (flags & CAN_8) flags&=~(CAN_16|CAN_32); + if (flags & GFX_CAN_8) flags&=~(GFX_CAN_15|GFX_CAN_16|GFX_CAN_32); break; case 15: + if (flags & GFX_CAN_15) flags&=~(GFX_CAN_8|GFX_CAN_16|GFX_CAN_32); + break; case 16: - if (flags & CAN_16) flags&=~(CAN_8|CAN_32); + if (flags & GFX_CAN_16) flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_32); break; case 24: case 32: - if (flags & CAN_32) flags&=~(CAN_8|CAN_16); + if (flags & GFX_CAN_32) flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); break; } - /* Not a valid display depth found? Let's just hope sdl provides conversions */ + flags |= GFX_CAN_RANDOM; break; -#if defined(HAVE_DDRAW_H) && defined(WIN32) +#if (HAVE_DDRAW_H) && defined(WIN32) case SCREEN_SURFACE_DDRAW: - if (!(flags&CAN_32|CAN_16)) goto check_surface; - if (flags & LOVE_16) testbpp=16; - else if (flags & LOVE_32) testbpp=32; + if (!(flags&(GFX_CAN_15|GFX_CAN_16|GFX_CAN_32))) goto check_surface; + if (flags & GFX_LOVE_15) testbpp=15; + else if (flags & GFX_LOVE_16) testbpp=16; + else if (flags & GFX_LOVE_32) testbpp=32; else testbpp=0; - flags|=HAVE_SCALING; + flags|=GFX_SCALING; goto check_gotbpp; #endif case SCREEN_OVERLAY: - if (flags & NEED_RGB || !(flags&CAN_32)) goto check_surface; - flags|=HAVE_SCALING; - flags&=~(CAN_8,CAN_16); + if (flags & GFX_RGBONLY || !(flags&GFX_CAN_32)) goto check_surface; + flags|=GFX_SCALING; + flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); break; #if C_OPENGL case SCREEN_OPENGL: - if (flags & NEED_RGB || !(flags&CAN_32)) goto check_surface; - flags|=HAVE_SCALING; - flags&=~(CAN_8,CAN_16); + if (flags & GFX_RGBONLY || !(flags&GFX_CAN_32)) goto check_surface; + flags|=GFX_SCALING; + flags&=~(GFX_CAN_8|GFX_CAN_15|GFX_CAN_16); break; #endif } @@ -290,7 +313,7 @@ check_gotbpp: void GFX_ResetScreen(void) { GFX_Stop(); - if (sdl.draw.reset) (sdl.draw.reset)(); + if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackReset ); GFX_Start(); } @@ -302,89 +325,142 @@ static int int_log2 (int val) { } -static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags,Bit32u bpp) { +static SDL_Surface * GFX_SetupSurfaceScaled(Bit32u sdl_flags, Bit32u bpp) { + Bit16u fixedWidth; + Bit16u fixedHeight; + if (sdl.desktop.fullscreen) { - if (sdl.desktop.fixed) { - double ratio_w=(double)sdl.desktop.width/(sdl.draw.width*sdl.draw.scalex); - double ratio_h=(double)sdl.desktop.height/(sdl.draw.height*sdl.draw.scaley); - if ( ratio_w < ratio_h) { - sdl.clip.w=(Bit16u)sdl.desktop.width; - sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley*ratio_w); - } else { - sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex*ratio_h); - sdl.clip.h=(Bit16u)sdl.desktop.height; - } - sdl.clip.x=(Sint16)((sdl.desktop.width-sdl.clip.w)/2); - sdl.clip.y=(Sint16)((sdl.desktop.height-sdl.clip.h)/2); - return sdl.surface=SDL_SetVideoMode(sdl.desktop.width,sdl.desktop.height,bpp,sdl_flags|SDL_FULLSCREEN|SDL_HWSURFACE); + fixedWidth = sdl.desktop.full.fixed ? sdl.desktop.full.width : 0; + fixedHeight = sdl.desktop.full.fixed ? sdl.desktop.full.height : 0; + sdl_flags |= SDL_FULLSCREEN|SDL_HWSURFACE; + } else { + fixedWidth = sdl.desktop.window.width; + fixedHeight = sdl.desktop.window.height; + sdl_flags |= SDL_HWSURFACE; + } + if (fixedWidth && fixedHeight) { + double ratio_w=(double)fixedWidth/(sdl.draw.width*sdl.draw.scalex); + double ratio_h=(double)fixedHeight/(sdl.draw.height*sdl.draw.scaley); + if ( ratio_w < ratio_h) { + sdl.clip.w=fixedWidth; + sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley*ratio_w); } else { - sdl.clip.x=0;sdl.clip.y=0; - sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex); - sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley); - return sdl.surface=SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,bpp,sdl_flags|SDL_FULLSCREEN|SDL_HWSURFACE); + sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex*ratio_h); + sdl.clip.h=(Bit16u)fixedHeight; } + if (sdl.desktop.fullscreen) + sdl.surface = SDL_SetVideoMode(fixedWidth,fixedHeight,bpp,sdl_flags); + else + sdl.surface = SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,bpp,sdl_flags); + if (sdl.surface && sdl.surface->flags & SDL_FULLSCREEN) { + sdl.clip.x=(Sint16)((sdl.surface->w-sdl.clip.w)/2); + sdl.clip.y=(Sint16)((sdl.surface->h-sdl.clip.h)/2); + } else { + sdl.clip.x = 0; + sdl.clip.y = 0; + } + return sdl.surface; } else { sdl.clip.x=0;sdl.clip.y=0; - sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex*sdl.desktop.hwscale); - sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley*sdl.desktop.hwscale); - return sdl.surface=SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,bpp,sdl_flags|SDL_HWSURFACE); + sdl.clip.w=(Bit16u)(sdl.draw.width*sdl.draw.scalex); + sdl.clip.h=(Bit16u)(sdl.draw.height*sdl.draw.scaley); + sdl.surface=SDL_SetVideoMode(sdl.clip.w,sdl.clip.h,bpp,sdl_flags); + return sdl.surface; } } -GFX_Modes GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_ResetCallBack reset) { - if (sdl.updating) GFX_EndUpdate(); +Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t callback) { + if (sdl.updating) + GFX_EndUpdate( 0 ); + sdl.draw.width=width; sdl.draw.height=height; - sdl.draw.flags=flags; - sdl.draw.mode=GFX_NONE; - sdl.draw.reset=reset; + sdl.draw.callback=callback; sdl.draw.scalex=scalex; sdl.draw.scaley=scaley; Bitu bpp; + Bitu retFlags; + + if (sdl.blit.surface) { + SDL_FreeSurface(sdl.blit.surface); + sdl.blit.surface=0; + } switch (sdl.desktop.want_type) { case SCREEN_SURFACE: dosurface: - if (flags & CAN_8) bpp=8; - if (flags & CAN_16) bpp=16; - if (flags & CAN_32) bpp=32; + if (flags & GFX_CAN_8) bpp=8; + if (flags & GFX_CAN_15) bpp=15; + if (flags & GFX_CAN_16) bpp=16; + if (flags & GFX_CAN_32) bpp=32; sdl.desktop.type=SCREEN_SURFACE; sdl.clip.w=width; sdl.clip.h=height; if (sdl.desktop.fullscreen) { - if (sdl.desktop.fixed) { - sdl.clip.x=(Sint16)((sdl.desktop.width-width)/2); - sdl.clip.y=(Sint16)((sdl.desktop.height-height)/2); - sdl.surface=SDL_SetVideoMode(sdl.desktop.width,sdl.desktop.height,bpp, - SDL_FULLSCREEN|SDL_HWSURFACE|(sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0)|SDL_HWPALETTE); + if (sdl.desktop.full.fixed) { + sdl.clip.x=(Sint16)((sdl.desktop.full.width-width)/2); + sdl.clip.y=(Sint16)((sdl.desktop.full.height-height)/2); + sdl.surface=SDL_SetVideoMode(sdl.desktop.full.width,sdl.desktop.full.height,bpp, + SDL_FULLSCREEN | ((flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE) | + (sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0) | SDL_HWPALETTE); + if (sdl.surface == NULL) E_Exit("Could not set fullscreen video mode %ix%i-%i: %s",sdl.desktop.full.width,sdl.desktop.full.height,bpp,SDL_GetError()); } else { sdl.clip.x=0;sdl.clip.y=0; sdl.surface=SDL_SetVideoMode(width,height,bpp, - SDL_FULLSCREEN|SDL_HWSURFACE|(sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0)|SDL_HWPALETTE); + SDL_FULLSCREEN | ((flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE) | + (sdl.desktop.doublebuf ? SDL_DOUBLEBUF|SDL_ASYNCBLIT : 0)|SDL_HWPALETTE); + if (sdl.surface == NULL) + E_Exit("Could not set fullscreen video mode %ix%i-%i: %s",width,height,bpp,SDL_GetError()); } } else { sdl.clip.x=0;sdl.clip.y=0; - sdl.surface=SDL_SetVideoMode(width,height,bpp,SDL_HWSURFACE); + sdl.surface=SDL_SetVideoMode(width,height,bpp,(flags & GFX_CAN_RANDOM) ? SDL_SWSURFACE : SDL_HWSURFACE); +#ifdef WIN32 + if (sdl.surface == NULL) { + LOG_MSG("Failed to create hardware surface.\nRestarting video subsystem with windib enabled."); + SDL_QuitSubSystem(SDL_INIT_VIDEO); + putenv("SDL_VIDEODRIVER=windib"); + SDL_InitSubSystem(SDL_INIT_VIDEO); + sdl.surface = SDL_SetVideoMode(width,height,bpp,SDL_HWSURFACE); + } +#endif + if (sdl.surface == NULL) + E_Exit("Could not set windowed video mode %ix%i-%i: %s",width,height,bpp,SDL_GetError()); } - if (sdl.surface) switch (sdl.surface->format->BitsPerPixel) { - case 8:sdl.draw.mode=GFX_8;break; - case 15:sdl.draw.mode=GFX_15;break; - case 16:sdl.draw.mode=GFX_16;break; - case 32:sdl.draw.mode=GFX_32;break; - default: + if (sdl.surface) { + switch (sdl.surface->format->BitsPerPixel) { + case 8: + retFlags = GFX_CAN_8; + break; + case 15: + retFlags = GFX_CAN_15; break; + case 16: + retFlags = GFX_CAN_16; + break; + case 32: + retFlags = GFX_CAN_32; + break; + } + if (retFlags && (sdl.surface->flags & SDL_HWSURFACE)) + retFlags |= GFX_HARDWARE; + if (retFlags && (sdl.surface->flags & SDL_DOUBLEBUF)) { + sdl.blit.surface=SDL_CreateRGBSurface(SDL_HWSURFACE, + sdl.draw.width, sdl.draw.height, + sdl.surface->format->BitsPerPixel, + sdl.surface->format->Rmask, + sdl.surface->format->Gmask, + sdl.surface->format->Bmask, + 0); + /* If this one fails be ready for some flickering... */ + } } break; -#if defined(HAVE_DDRAW_H) && defined(WIN32) +#if (HAVE_DDRAW_H) && defined(WIN32) case SCREEN_SURFACE_DDRAW: - if (flags & CAN_16) bpp=16; - if (flags & CAN_32) bpp=32; - if (sdl.blit.surface) { - SDL_FreeSurface(sdl.blit.surface); - sdl.blit.surface=0; - } - memset(&sdl.blit.fx,0,sizeof(DDBLTFX)); - sdl.blit.fx.dwSize=sizeof(DDBLTFX); + if (flags & GFX_CAN_15) bpp=15; + if (flags & GFX_CAN_16) bpp=16; + if (flags & GFX_CAN_32) bpp=32; if (!GFX_SetupSurfaceScaled((sdl.desktop.doublebuf && sdl.desktop.fullscreen) ? SDL_DOUBLEBUF : 0,bpp)) goto dosurface; sdl.blit.rect.top=sdl.clip.y; sdl.blit.rect.left=sdl.clip.x; @@ -401,11 +477,15 @@ dosurface: goto dosurface; } switch (sdl.surface->format->BitsPerPixel) { - case 15:sdl.draw.mode=GFX_15;break; - case 16:sdl.draw.mode=GFX_16;break; - case 32:sdl.draw.mode=GFX_32;break; - default: - break; + case 15: + retFlags = GFX_CAN_15 | GFX_SCALING | GFX_HARDWARE; + break; + case 16: + retFlags = GFX_CAN_16 | GFX_SCALING | GFX_HARDWARE; + break; + case 32: + retFlags = GFX_CAN_32 | GFX_SCALING | GFX_HARDWARE; + break; } sdl.desktop.type=SCREEN_SURFACE_DDRAW; break; @@ -415,7 +495,7 @@ dosurface: SDL_FreeYUVOverlay(sdl.overlay); sdl.overlay=0; } - if (!(flags&CAN_32) || (flags & NEED_RGB)) goto dosurface; + if (!(flags&GFX_CAN_32) || (flags & GFX_RGBONLY)) goto dosurface; if (!GFX_SetupSurfaceScaled(0,0)) goto dosurface; sdl.overlay=SDL_CreateYUVOverlay(width*2,height,SDL_UYVY_OVERLAY,sdl.surface); if (!sdl.overlay) { @@ -423,7 +503,7 @@ dosurface: goto dosurface; } sdl.desktop.type=SCREEN_OVERLAY; - sdl.draw.mode=GFX_32; + retFlags = GFX_CAN_32 | GFX_SCALING | GFX_HARDWARE; break; #if C_OPENGL case SCREEN_OPENGL: @@ -436,7 +516,7 @@ dosurface: free(sdl.opengl.framebuf); } sdl.opengl.framebuf=0; - if (!(flags&CAN_32) || (flags & NEED_RGB)) goto dosurface; + if (!(flags&GFX_CAN_32) || (flags & GFX_RGBONLY)) goto dosurface; int texsize=2 << int_log2(width > height ? width : height); if (texsize>sdl.opengl.max_texsize) { LOG_MSG("SDL:OPENGL:No support for texturesize of %d, falling back to surface",texsize); @@ -510,101 +590,147 @@ dosurface: glEnd(); glEndList(); sdl.desktop.type=SCREEN_OPENGL; - sdl.draw.mode=GFX_32; - break; + retFlags = GFX_CAN_32 | GFX_SCALING; +#if defined(NVIDIA_PixelDataRange) + if (sdl.opengl.pixel_data_range) + retFlags |= GFX_HARDWARE; +#endif + break; }//OPENGL #endif //C_OPENGL }//CASE - if (sdl.draw.mode!=GFX_NONE) GFX_Start(); - return sdl.draw.mode; + if (retFlags) + GFX_Start(); + if (!sdl.mouse.autoenable) SDL_ShowCursor(sdl.mouse.autolock?SDL_DISABLE:SDL_ENABLE); + return retFlags; } -bool mouselocked; //Global variable for mapper -static void CaptureMouse(void) { +void GFX_CaptureMouse(void) { sdl.mouse.locked=!sdl.mouse.locked; if (sdl.mouse.locked) { SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); } else { SDL_WM_GrabInput(SDL_GRAB_OFF); - SDL_ShowCursor(SDL_ENABLE); + if (sdl.mouse.autoenable || !sdl.mouse.autolock) SDL_ShowCursor(SDL_ENABLE); } mouselocked=sdl.mouse.locked; } -void GFX_CaptureMouse(void) { - CaptureMouse(); +bool mouselocked; //Global variable for mapper +static void CaptureMouse(bool pressed) { + if (!pressed) + return; + GFX_CaptureMouse(); } -static void SwitchFullScreen(void) { +void GFX_SwitchFullScreen(void) { sdl.desktop.fullscreen=!sdl.desktop.fullscreen; if (sdl.desktop.fullscreen) { - if (!sdl.mouse.locked) CaptureMouse(); + if (!sdl.mouse.locked) GFX_CaptureMouse(); } else { - if (sdl.mouse.locked) CaptureMouse(); + if (sdl.mouse.locked) GFX_CaptureMouse(); } GFX_ResetScreen(); } -void GFX_SwitchFullScreen(void) { - SwitchFullScreen(); +static void SwitchFullScreen(bool pressed) { + if (!pressed) + return; + GFX_SwitchFullScreen(); } + bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch) { if (!sdl.active || sdl.updating) return false; - sdl.updating=true; switch (sdl.desktop.type) { case SCREEN_SURFACE: - if (SDL_MUSTLOCK(sdl.surface)) { - if (SDL_LockSurface(sdl.surface)) { -// LOG_MSG("SDL Lock failed"); - sdl.updating=false; + if (sdl.blit.surface) { + if (SDL_MUSTLOCK(sdl.blit.surface) && SDL_LockSurface(sdl.blit.surface)) return false; - } + pixels=(Bit8u *)sdl.blit.surface->pixels; + pitch=sdl.blit.surface->pitch; + } else { + if (SDL_MUSTLOCK(sdl.surface) && SDL_LockSurface(sdl.surface)) + return false; + pixels=(Bit8u *)sdl.surface->pixels; + pixels+=sdl.clip.y*sdl.surface->pitch; + pixels+=sdl.clip.x*sdl.surface->format->BytesPerPixel; + pitch=sdl.surface->pitch; } - pixels=(Bit8u *)sdl.surface->pixels; - pixels+=sdl.clip.y*sdl.surface->pitch; - pixels+=sdl.clip.x*sdl.surface->format->BytesPerPixel; - pitch=sdl.surface->pitch; + sdl.updating=true; return true; -#if defined(HAVE_DDRAW_H) && defined(WIN32) +#if (HAVE_DDRAW_H) && defined(WIN32) case SCREEN_SURFACE_DDRAW: if (SDL_LockSurface(sdl.blit.surface)) { // LOG_MSG("SDL Lock failed"); - sdl.updating=false; return false; } pixels=(Bit8u *)sdl.blit.surface->pixels; pitch=sdl.blit.surface->pitch; + sdl.updating=true; return true; #endif case SCREEN_OVERLAY: SDL_LockYUVOverlay(sdl.overlay); pixels=(Bit8u *)*(sdl.overlay->pixels); pitch=*(sdl.overlay->pitches); + sdl.updating=true; return true; #if C_OPENGL case SCREEN_OPENGL: pixels=(Bit8u *)sdl.opengl.framebuf; pitch=sdl.opengl.pitch; + sdl.updating=true; return true; #endif } return false; } -void GFX_EndUpdate(void) { + +void GFX_EndUpdate( const Bit16u *changedLines ) { int ret; if (!sdl.updating) return; sdl.updating=false; switch (sdl.desktop.type) { case SCREEN_SURFACE: if (SDL_MUSTLOCK(sdl.surface)) { - SDL_UnlockSurface(sdl.surface); + if (sdl.blit.surface) { + SDL_UnlockSurface(sdl.blit.surface); + int Blit = SDL_BlitSurface( sdl.blit.surface, 0, sdl.surface, &sdl.clip ); + LOG(LOG_MISC,LOG_WARN)("BlitSurface returned %d",Blit); + } else { + SDL_UnlockSurface(sdl.surface); + } + SDL_Flip(sdl.surface); + } else if (changedLines) { + Bitu y = 0, index = 0, rectCount = 0; + while (y < sdl.draw.height) { + if (!(index & 1)) { + y += changedLines[index]; + } else { + SDL_Rect *rect = &sdl.updateRects[rectCount++]; + rect->x = sdl.clip.x; + rect->y = sdl.clip.y + y; + rect->w = (Bit16u)sdl.draw.width; + rect->h = changedLines[index]; +#if 0 + if (rect->h + rect->y > sdl.surface->h) { + LOG_MSG("WTF"); + } +#endif + y += changedLines[index]; + } + index++; + } + if (rectCount) + SDL_UpdateRects( sdl.surface, rectCount, sdl.updateRects ); + } else { + SDL_Flip(sdl.surface); } - SDL_Flip(sdl.surface); break; -#if defined(HAVE_DDRAW_H) && defined(WIN32) +#if (HAVE_DDRAW_H) && defined(WIN32) case SCREEN_SURFACE_DDRAW: if (SDL_MUSTLOCK(sdl.blit.surface)) { SDL_UnlockSurface(sdl.blit.surface); @@ -618,6 +744,7 @@ void GFX_EndUpdate(void) { break; case DDERR_SURFACELOST: IDirectDrawSurface3_Restore(sdl.blit.surface->hwdata->dd_surface); + IDirectDrawSurface3_Restore(sdl.surface->hwdata->dd_surface); break; default: LOG_MSG("DDRAW:Failed to blit, error %X",ret); @@ -631,12 +758,35 @@ void GFX_EndUpdate(void) { break; #if C_OPENGL case SCREEN_OPENGL: - glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, - sdl.draw.width, sdl.draw.height, GL_BGRA_EXT, - GL_UNSIGNED_INT_8_8_8_8_REV, sdl.opengl.framebuf); - glCallList(sdl.opengl.displaylist); - SDL_GL_SwapBuffers(); +#if defined(NVIDIA_PixelDataRange) + if (sdl.opengl.pixel_data_range) { + glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + sdl.draw.width, sdl.draw.height, GL_BGRA_EXT, + GL_UNSIGNED_INT_8_8_8_8_REV, sdl.opengl.framebuf); + glCallList(sdl.opengl.displaylist); + SDL_GL_SwapBuffers(); + } else +#endif + if (changedLines) { + Bitu y = 0, index = 0; + glBindTexture(GL_TEXTURE_2D, sdl.opengl.texture); + while (y < sdl.draw.height) { + if (!(index & 1)) { + y += changedLines[index]; + } else { + Bit8u *pixels = (Bit8u *)sdl.opengl.framebuf + y * sdl.opengl.pitch; + Bitu height = changedLines[index]; + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, y, + sdl.draw.width, height, GL_BGRA_EXT, + GL_UNSIGNED_INT_8_8_8_8_REV, pixels ); + y += height; + } + index++; + } + glCallList(sdl.opengl.displaylist); + SDL_GL_SwapBuffers(); + } break; #endif @@ -682,7 +832,8 @@ Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue) { } void GFX_Stop() { - if (sdl.updating) GFX_EndUpdate(); + if (sdl.updating) + GFX_EndUpdate( 0 ); sdl.active=false; } @@ -692,11 +843,14 @@ void GFX_Start() { static void GUI_ShutDown(Section * sec) { GFX_Stop(); - if (sdl.mouse.locked) CaptureMouse(); - if (sdl.desktop.fullscreen) SwitchFullScreen(); + if (sdl.draw.callback) (sdl.draw.callback)( GFX_CallBackStop ); + if (sdl.mouse.locked) GFX_CaptureMouse(); + if (sdl.desktop.fullscreen) GFX_SwitchFullScreen(); } -static void KillSwitch(void){ +static void KillSwitch(bool pressed) { + if (!pressed) + return; throw 1; } @@ -712,6 +866,9 @@ static void SetPriority(PRIORITY_LEVELS level) { #endif switch (level) { #ifdef WIN32 + case PRIORITY_LEVEL_LOWEST: + SetPriorityClass(GetCurrentProcess(),IDLE_PRIORITY_CLASS); + break; case PRIORITY_LEVEL_LOWER: SetPriorityClass(GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS); break; @@ -726,6 +883,9 @@ static void SetPriority(PRIORITY_LEVELS level) { break; #elif C_SET_PRIORITY /* Linux use group as dosbox has mulitple threads under linux */ + case PRIORITY_LEVEL_LOWEST: + setpriority (PRIO_PGRP, 0,PRIO_MAX); + break; case PRIORITY_LEVEL_LOWER: setpriority (PRIO_PGRP, 0,PRIO_MAX-(PRIO_TOTAL/3)); break; @@ -744,17 +904,32 @@ static void SetPriority(PRIORITY_LEVELS level) { } } +static unsigned char logo[32*32*4]= { +#include "dosbox_logo.h" +}; + static void GUI_StartUp(Section * sec) { sec->AddDestroyFunction(&GUI_ShutDown); Section_prop * section=static_cast(sec); sdl.active=false; sdl.updating=false; + + /* Set Icon (must be done before any sdl_setvideomode call) */ +#if WORDS_BIGENDIAN + SDL_Surface* logos= SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0xff000000,0x00ff0000,0x0000ff00,0); +#else + SDL_Surface* logos= SDL_CreateRGBSurfaceFrom((void*)logo,32,32,32,128,0x000000ff,0x0000ff00,0x00ff0000,0); +#endif + SDL_WM_SetIcon(logos,NULL); + sdl.desktop.fullscreen=section->Get_bool("fullscreen"); sdl.wait_on_error=section->Get_bool("waitonerror"); const char * priority=section->Get_string("priority"); if (priority && priority[0]) { Bitu next; - if (!strncasecmp(priority,"lower",5)) { + if (!strncasecmp(priority,"lowest",6)) { + sdl.priority.focus=PRIORITY_LEVEL_LOWEST;next=6; + } else if (!strncasecmp(priority,"lower",5)) { sdl.priority.focus=PRIORITY_LEVEL_LOWER;next=5; } else if (!strncasecmp(priority,"normal",6)) { sdl.priority.focus=PRIORITY_LEVEL_NORMAL;next=6; @@ -768,7 +943,9 @@ static void GUI_StartUp(Section * sec) { priority=&priority[next]; if (next && priority[0]==',' && priority[1]) { priority++; - if (!strncasecmp(priority,"lower",5)) { + if (!strncasecmp(priority,"lowest",6)) { + sdl.priority.nofocus=PRIORITY_LEVEL_LOWEST; + } else if (!strncasecmp(priority,"lower",5)) { sdl.priority.nofocus=PRIORITY_LEVEL_LOWER; } else if (!strncasecmp(priority,"normal",6)) { sdl.priority.nofocus=PRIORITY_LEVEL_NORMAL; @@ -788,53 +965,64 @@ static void GUI_StartUp(Section * sec) { sdl.mouse.locked=false; mouselocked=false; //Global for mapper sdl.mouse.requestlock=false; - sdl.desktop.fixed=section->Get_bool("fullfixed"); + sdl.desktop.full.fixed=false; const char* fullresolution=section->Get_string("fullresolution"); + sdl.desktop.full.width = 0; + sdl.desktop.full.height = 0; if(fullresolution && *fullresolution) { - char res[100]= { 0 }; - strcpy(res,fullresolution); + char res[100]; + strncpy( res, fullresolution, sizeof( res )); fullresolution = lowcase (res);//so x and X are allowed - - char* height = strchr(fullresolution,'x'); - if(height && * height) { - *height = 0; - sdl.desktop.height = atoi(height+1); - sdl.desktop.width = atoi(res); - } else { - sdl.desktop.width = 0; - sdl.desktop.height = 0; + if(strcmp(fullresolution,"original")) { + sdl.desktop.full.fixed = true; + char* height = const_cast(strchr(fullresolution,'x')); + if(height && * height) { + *height = 0; + sdl.desktop.full.height = atoi(height+1); + sdl.desktop.full.width = atoi(res); + } + } + } + + sdl.desktop.window.width = 0; + sdl.desktop.window.height = 0; + const char* windowresolution=section->Get_string("windowresolution"); + if(windowresolution && *windowresolution) { + char res[100]; + strncpy( res,windowresolution, sizeof( res )); + windowresolution = lowcase (res);//so x and X are allowed + if(strcmp(windowresolution,"original")) { + char* height = const_cast(strchr(windowresolution,'x')); + if(height && *height) { + *height = 0; + sdl.desktop.window.height = atoi(height+1); + sdl.desktop.window.width = atoi(res); + } } - } else { - sdl.desktop.width = 0; - sdl.desktop.height = 0; } sdl.desktop.doublebuf=section->Get_bool("fulldouble"); - sdl.desktop.hwscale=section->Get_float("hwscale"); - if (sdl.desktop.hwscale<0.1f) { - LOG_MSG("SDL:Can't hwscale lower than 0.1"); - sdl.desktop.hwscale=0.1f; - } - if (!sdl.desktop.width) { + if (!sdl.desktop.full.width) { #ifdef WIN32 - sdl.desktop.width=GetSystemMetrics(SM_CXSCREEN); + sdl.desktop.full.width=GetSystemMetrics(SM_CXSCREEN); #else - sdl.desktop.width=1024; + sdl.desktop.full.width=1024; #endif } - if (!sdl.desktop.height) { + if (!sdl.desktop.full.height) { #ifdef WIN32 - sdl.desktop.height=GetSystemMetrics(SM_CYSCREEN); + sdl.desktop.full.height=GetSystemMetrics(SM_CYSCREEN); #else - sdl.desktop.height=768; + sdl.desktop.full.height=768; #endif } sdl.mouse.autoenable=section->Get_bool("autolock"); + if (!sdl.mouse.autoenable) SDL_ShowCursor(SDL_DISABLE); sdl.mouse.autolock=false; sdl.mouse.sensitivity=section->Get_int("sensitivity"); const char * output=section->Get_string("output"); if (!strcasecmp(output,"surface")) { sdl.desktop.want_type=SCREEN_SURFACE; -#if defined(HAVE_DDRAW_H) && defined(WIN32) +#if (HAVE_DDRAW_H) && defined(WIN32) } else if (!strcasecmp(output,"ddraw")) { sdl.desktop.want_type=SCREEN_SURFACE_DDRAW; #endif @@ -857,6 +1045,10 @@ static void GUI_StartUp(Section * sec) { #if C_OPENGL if(sdl.desktop.want_type==SCREEN_OPENGL){ /* OPENGL is requested */ sdl.surface=SDL_SetVideoMode(640,400,0,SDL_OPENGL); + if (sdl.surface == NULL) { + LOG_MSG("Could not initialize OpenGL, switching back to surface"); + sdl.desktop.want_type=SCREEN_SURFACE; + } else { sdl.opengl.framebuf=0; sdl.opengl.texture=0; sdl.opengl.displaylist=0; @@ -873,15 +1065,18 @@ static void GUI_StartUp(Section * sec) { #if defined(NVIDIA_PixelDataRange) sdl.opengl.pixel_data_range=(strstr(gl_ext,"GL_NV_pixel_data_range") >0 ) && glPixelDataRangeNV && db_glAllocateMemoryNV && db_glFreeMemoryNV; + sdl.opengl.pixel_data_range = 0; #endif } else { sdl.opengl.packed_pixel=sdl.opengl.paletted_texture=false; } + } } /* OPENGL is requested end */ #endif //OPENGL /* Initialize screen for first time */ sdl.surface=SDL_SetVideoMode(640,400,0,0); + if (sdl.surface == NULL) E_Exit("Could not initialize video: %s",SDL_GetError()); sdl.desktop.bpp=sdl.surface->format->BitsPerPixel; if (sdl.desktop.bpp==24) { LOG_MSG("SDL:You are running in 24 bpp mode, this will slow down things!"); @@ -894,7 +1089,7 @@ static void GUI_StartUp(Section * sec) { #if C_DEBUG /* Pause binds with activate-debugger */ #else - MAPPER_AddHandler(PauseDOSBox,MK_pause,0,"pause","Pause"); + MAPPER_AddHandler(PauseDOSBox,MK_pause,MMOD2,"pause","Pause"); #endif /* Get Keyboard state of numlock and capslock */ SDLMod keystate = SDL_GetModState(); @@ -904,23 +1099,30 @@ static void GUI_StartUp(Section * sec) { void Mouse_AutoLock(bool enable) { sdl.mouse.autolock=enable; - if (enable && sdl.mouse.autoenable) sdl.mouse.requestlock=true; - else sdl.mouse.requestlock=false; + if (sdl.mouse.autoenable) sdl.mouse.requestlock=enable; + else { + SDL_ShowCursor(enable?SDL_DISABLE:SDL_ENABLE); + sdl.mouse.requestlock=false; + } } static void HandleMouseMotion(SDL_MouseMotionEvent * motion) { - if (sdl.mouse.locked) - Mouse_CursorMoved((float)motion->xrel*sdl.mouse.sensitivity/100,(float)motion->yrel*sdl.mouse.sensitivity/100); + if (sdl.mouse.locked || !sdl.mouse.autoenable) + Mouse_CursorMoved((float)motion->xrel*sdl.mouse.sensitivity/100,(float)motion->yrel*sdl.mouse.sensitivity/100,(float)(motion->x-sdl.clip.x)/(sdl.clip.w-1)*sdl.mouse.sensitivity/100,(float)(motion->y-sdl.clip.y)/(sdl.clip.h-1)*sdl.mouse.sensitivity/100.0,sdl.mouse.locked); } static void HandleMouseButton(SDL_MouseButtonEvent * button) { switch (button->state) { case SDL_PRESSED: if (sdl.mouse.requestlock && !sdl.mouse.locked) { - CaptureMouse(); + GFX_CaptureMouse(); // Dont pass klick to mouse handler break; } + if (!sdl.mouse.autoenable && sdl.mouse.autolock && button->button == SDL_BUTTON_MIDDLE) { + GFX_CaptureMouse(); + break; + } switch (button->button) { case SDL_BUTTON_LEFT: Mouse_ButtonPressed(0); @@ -952,7 +1154,6 @@ static void HandleMouseButton(SDL_MouseButtonEvent * button) { static Bit8u laltstate = SDL_KEYUP; static Bit8u raltstate = SDL_KEYUP; - void GFX_Events() { SDL_Event event; while (SDL_PollEvent(&event)) { @@ -961,12 +1162,21 @@ void GFX_Events() { if (event.active.state & SDL_APPINPUTFOCUS) { if (event.active.gain) { if (sdl.desktop.fullscreen && !sdl.mouse.locked) - CaptureMouse(); + GFX_CaptureMouse(); SetPriority(sdl.priority.focus); } else { - if (sdl.mouse.locked) - CaptureMouse(); + if (sdl.mouse.locked) { +#ifdef WIN32 + if (sdl.desktop.fullscreen) { + VGA_KillDrawing(); + sdl.desktop.fullscreen=false; + GFX_ResetScreen(); + } +#endif + GFX_CaptureMouse(); + } SetPriority(sdl.priority.nofocus); + MAPPER_LosingFocus(); } } break; @@ -983,6 +1193,9 @@ void GFX_Events() { case SDL_QUIT: throw(0); break; + case SDL_VIDEOEXPOSE: + if (sdl.draw.callback) sdl.draw.callback( GFX_CallBackRedraw ); + break; #ifdef WIN32 case SDL_KEYDOWN: case SDL_KEYUP: @@ -992,7 +1205,6 @@ void GFX_Events() { if (((event.key.keysym.sym==SDLK_TAB)) && ((laltstate==SDL_KEYDOWN) || (raltstate==SDL_KEYDOWN))) break; #endif - default: void MAPPER_CheckEvent(SDL_Event * event); MAPPER_CheckEvent(&event); @@ -1000,6 +1212,10 @@ void GFX_Events() { } } +/* static variable to show wether there is not a valid stdout. + * Fixes some bugs when -noconsole is used in a read only directory */ +static bool no_stdout = false; + void GFX_ShowMsg(char * format,...) { char buf[512]; va_list msg; @@ -1007,7 +1223,7 @@ void GFX_ShowMsg(char * format,...) { vsprintf(buf,format,msg); strcat(buf,"\n"); va_end(msg); - printf(buf); + if(!no_stdout) printf(buf); }; int main(int argc, char* argv[]) { @@ -1027,7 +1243,8 @@ int main(int argc, char* argv[]) { if (control->cmdline->FindExist("-noconsole")) { FreeConsole(); /* Redirect standard input and standard output */ - freopen(STDOUT_FILE, "w", stdout); + if(freopen(STDOUT_FILE, "w", stdout) == NULL) + no_stdout = true; // No stdout so don't write messages freopen(STDERR_FILE, "w", stderr); setvbuf(stdout, NULL, _IOLBF, BUFSIZ); /* Line buffered */ setbuf(stderr, NULL); /* No buffering */ @@ -1040,51 +1257,62 @@ int main(int argc, char* argv[]) { freopen("CONOUT$","w",stdout); freopen("CONOUT$","w",stderr); } + SetConsoleTitle("DOSBox Status Window"); } #endif //defined(WIN32) && !(C_DEBUG) #if C_DEBUG DEBUG_SetupConsole(); #endif + +#ifdef OS2 + PPIB pib; + PTIB tib; + DosGetInfoBlocks(&tib, &pib); + if (pib->pib_ultype == 2) pib->pib_ultype = 3; + setbuf(stdout, NULL); + setbuf(stderr, NULL); +#endif + if ( SDL_Init( SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_CDROM + |SDL_INIT_NOPARACHUTE #ifndef DISABLE_JOYSTICK |SDL_INIT_JOYSTICK - #endif ) < 0 ) E_Exit("Can't init SDL %s",SDL_GetError()); Section_prop * sdl_sec=control->AddSection_prop("sdl",&GUI_StartUp); sdl_sec->AddInitFunction(&MAPPER_StartUp); sdl_sec->Add_bool("fullscreen",false); sdl_sec->Add_bool("fulldouble",false); - sdl_sec->Add_bool("fullfixed",false); - sdl_sec->Add_string("fullresolution","1024x768"); + sdl_sec->Add_string("fullresolution","original"); + sdl_sec->Add_string("windowresolution","original"); sdl_sec->Add_string("output","surface"); - sdl_sec->Add_float("hwscale",1.0); sdl_sec->Add_bool("autolock",true); sdl_sec->Add_int("sensitivity",100); sdl_sec->Add_bool("waitonerror",true); sdl_sec->Add_string("priority","higher,normal"); sdl_sec->Add_string("mapperfile","mapper.txt"); + sdl_sec->Add_bool("usescancodes",true); MSG_Add("SDL_CONFIGFILE_HELP", "fullscreen -- Start dosbox directly in fullscreen.\n" "fulldouble -- Use double buffering in fullscreen.\n" - "fullfixed -- Don't resize the screen when in fullscreen.\n" - "fullresolution -- What resolution to use for fullscreen, use together with fullfixed.\n" + "fullresolution -- What resolution to use for fullscreen: original or fixed size (e.g. 1024x768).\n" + "windowresolution -- Scale the window to this size IF the output device supports hardware scaling.\n" "output -- What to use for output: surface,overlay" #if C_OPENGL ",opengl,openglnb" #endif -#if defined(HAVE_DDRAW_H) && defined(WIN32) +#if (HAVE_DDRAW_H) && defined(WIN32) ",ddraw" #endif ".\n" - "hwscale -- Extra scaling of window if the output device supports hardware scaling.\n" "autolock -- Mouse will automatically lock, if you click on the screen.\n" "sensitiviy -- Mouse sensitivity.\n" "waitonerror -- Wait before closing the console if dosbox has an error.\n" - "priority -- Priority levels for dosbox: lower,normal,higher,highest.\n" + "priority -- Priority levels for dosbox: lowest,lower,normal,higher,highest.\n" " Second entry behind the comma is for when dosbox is not focused/minimized.\n" "mapperfile -- File used to load/save the key/event mappings from.\n" + "usescancodes -- Avoid usage of symkeys, might not work on all operating systems.\n" ); /* Init all the dosbox subsystems */ DOSBOX_Init(); @@ -1115,23 +1343,25 @@ int main(int argc, char* argv[]) { /* Some extra SDL Functions */ if (control->cmdline->FindExist("-fullscreen") || sdl_sec->Get_bool("fullscreen")) { if(!sdl.desktop.fullscreen) { //only switch if not allready in fullscreen - SwitchFullScreen(); + GFX_SwitchFullScreen(); } } /* Init the keyMapper */ MAPPER_Init(); - if (control->cmdline->FindExist("-startmapper")) MAPPER_Run(); + if (control->cmdline->FindExist("-startmapper")) MAPPER_Run(true); /* Start up main machine */ control->StartUp(); /* Shutdown everything */ } catch (char * error) { - LOG_MSG("Exit to error: %s",error); + GFX_ShowMsg("Exit to error: %s",error); + fflush(NULL); if(sdl.wait_on_error) { //TODO Maybe look for some way to show message in linux? #if (C_DEBUG) - LOG_MSG("Press enter to continue"); + GFX_ShowMsg("Press enter to continue"); + fflush(NULL); fgetc(stdin); #elif defined(WIN32) Sleep(5000); diff --git a/src/hardware/Makefile.am b/src/hardware/Makefile.am index f51dc2a..c733621 100644 --- a/src/hardware/Makefile.am +++ b/src/hardware/Makefile.am @@ -1,5 +1,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include +SUBDIRS = serialport + EXTRA_DIST = fmopl.c fmopl.h ymf262.h ymf262.c noinst_LIBRARIES = libhardware.a @@ -7,10 +9,7 @@ noinst_LIBRARIES = libhardware.a libhardware_a_SOURCES = adlib.cpp dma.cpp gameblaster.cpp hardware.cpp iohandler.cpp joystick.cpp keyboard.cpp \ memory.cpp mixer.cpp pcspeaker.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \ vga.cpp vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_gfx.cpp vga_other.cpp \ - vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp cmos.cpp disney.cpp \ - gus.cpp mpu401.cpp serialport.cpp softmodem.cpp ipx.cpp ipxserver.cpp \ - directserial_win32.cpp - - + vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp vga_s3.cpp \ + cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp diff --git a/src/hardware/Makefile.in b/src/hardware/Makefile.in index 2a0ec36..a1d0f27 100644 --- a/src/hardware/Makefile.in +++ b/src/hardware/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -62,10 +62,9 @@ am_libhardware_a_OBJECTS = adlib.$(OBJEXT) dma.$(OBJEXT) \ vga.$(OBJEXT) vga_attr.$(OBJEXT) vga_crtc.$(OBJEXT) \ vga_dac.$(OBJEXT) vga_draw.$(OBJEXT) vga_gfx.$(OBJEXT) \ vga_other.$(OBJEXT) vga_memory.$(OBJEXT) vga_misc.$(OBJEXT) \ - vga_seq.$(OBJEXT) vga_xga.$(OBJEXT) cmos.$(OBJEXT) \ - disney.$(OBJEXT) gus.$(OBJEXT) mpu401.$(OBJEXT) \ - serialport.$(OBJEXT) softmodem.$(OBJEXT) ipx.$(OBJEXT) \ - ipxserver.$(OBJEXT) directserial_win32.$(OBJEXT) + vga_seq.$(OBJEXT) vga_xga.$(OBJEXT) vga_s3.$(OBJEXT) \ + cmos.$(OBJEXT) disney.$(OBJEXT) gus.$(OBJEXT) mpu401.$(OBJEXT) \ + ipx.$(OBJEXT) ipxserver.$(OBJEXT) libhardware_a_OBJECTS = $(am_libhardware_a_OBJECTS) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp @@ -77,8 +76,15 @@ CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ SOURCES = $(libhardware_a_SOURCES) DIST_SOURCES = $(libhardware_a_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive ETAGS = etags CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ @@ -106,6 +112,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -131,10 +139,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -177,16 +187,16 @@ target_cpu = @target_cpu@ target_os = @target_os@ target_vendor = @target_vendor@ AM_CPPFLAGS = -I$(top_srcdir)/include +SUBDIRS = serialport EXTRA_DIST = fmopl.c fmopl.h ymf262.h ymf262.c noinst_LIBRARIES = libhardware.a libhardware_a_SOURCES = adlib.cpp dma.cpp gameblaster.cpp hardware.cpp iohandler.cpp joystick.cpp keyboard.cpp \ memory.cpp mixer.cpp pcspeaker.cpp pic.cpp sblaster.cpp tandy_sound.cpp timer.cpp \ vga.cpp vga_attr.cpp vga_crtc.cpp vga_dac.cpp vga_draw.cpp vga_gfx.cpp vga_other.cpp \ - vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp cmos.cpp disney.cpp \ - gus.cpp mpu401.cpp serialport.cpp softmodem.cpp ipx.cpp ipxserver.cpp \ - directserial_win32.cpp + vga_memory.cpp vga_misc.cpp vga_seq.cpp vga_xga.cpp vga_s3.cpp \ + cmos.cpp disney.cpp gus.cpp mpu401.cpp ipx.cpp ipxserver.cpp -all: all-am +all: all-recursive .SUFFIXES: .SUFFIXES: .cpp .o .obj @@ -235,7 +245,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/adlib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmos.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/directserial_win32.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disney.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dma.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gameblaster.Po@am__quote@ @@ -252,8 +261,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcspeaker.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sblaster.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serialport.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/softmodem.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tandy_sound.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga.Po@am__quote@ @@ -265,6 +272,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga_memory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga_misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga_other.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga_s3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga_seq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vga_xga.Po@am__quote@ @@ -283,6 +291,77 @@ distclean-compile: @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` uninstall-info-am: +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ @@ -293,10 +372,23 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) mkid -fID $$unique tags: TAGS -TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ @@ -309,7 +401,7 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $$tags $$unique; \ fi ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) tags=; \ here=`pwd`; \ @@ -358,19 +450,35 @@ distdir: $(DISTFILES) || exit 1; \ fi; \ done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done check-am: all-am -check: check-am +check: check-recursive all-am: Makefile $(LIBRARIES) -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am -installcheck: installcheck-am +installcheck: installcheck-recursive install-strip: $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ @@ -386,23 +494,23 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -clean: clean-am +clean: clean-recursive clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am -distclean: distclean-am +distclean: distclean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags -dvi: dvi-am +dvi: dvi-recursive dvi-am: -html: html-am +html: html-recursive -info: info-am +info: info-recursive info-am: @@ -410,41 +518,45 @@ install-data-am: install-exec-am: -install-info: install-info-am +install-info: install-info-recursive install-man: installcheck-am: -maintainer-clean: maintainer-clean-am +maintainer-clean: maintainer-clean-recursive -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic -mostlyclean: mostlyclean-am +mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic -pdf: pdf-am +pdf: pdf-recursive pdf-am: -ps: ps-am +ps: ps-recursive ps-am: uninstall-am: uninstall-info-am -.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ - clean-noinstLIBRARIES ctags distclean distclean-compile \ - distclean-generic distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-exec install-exec-am install-info \ - install-info-am install-man install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ - uninstall-am uninstall-info-am +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-noinstLIBRARIES clean-recursive \ + ctags ctags-recursive distclean distclean-compile \ + distclean-generic distclean-recursive distclean-tags distdir \ + dvi dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-exec install-exec-am \ + install-info install-info-am install-man install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-recursive pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am uninstall-info-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index ea6274e..9cdba65 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -283,7 +283,9 @@ static void OPL_RawAdd(Bitu index,Bitu val) { if (opl.raw.used>=RAW_SIZE) OPL_RawEmptyBuffer(); } -static void OPL_SaveRawEvent(void) { +static void OPL_SaveRawEvent(bool pressed) { + if (!pressed) + return; /* Check for previously opened wave file */ if (opl.raw.handle) { OPL_RawEmptyBuffer(); @@ -312,37 +314,61 @@ static void OPL_SaveRawEvent(void) { } } -static void OPL_Stop(Section* sec) { - if (opl.raw.handle) OPL_SaveRawEvent(); -} +class OPL: public Module_base { +private: + IO_ReadHandleObject ReadHandler[3]; + IO_WriteHandleObject WriteHandler[3]; + MixerObject MixerChan; +public: + static OPL_Mode oplmode; -void OPL_Init(Section* sec,Bitu base,OPL_Mode oplmode,Bitu rate) { - Section_prop * section=static_cast(sec); - if (OPL2::YM3812Init(2,OPL2_INTERNAL_FREQ,rate)) { - E_Exit("Can't create OPL2 Emulator"); - }; - OPL2::YM3812SetTimerHandler(0,OPL2::TimerHandler,0); - OPL2::YM3812SetTimerHandler(1,OPL2::TimerHandler,256); - if (THEOPL3::YMF262Init(1,OPL3_INTERNAL_FREQ,rate)) { - E_Exit("Can't create OPL3 Emulator"); - }; - THEOPL3::YMF262SetTimerHandler(0,THEOPL3::TimerHandler,0); - IO_RegisterWriteHandler(0x388,OPL_Write,IO_MB,4); - IO_RegisterReadHandler(0x388,OPL_Read,IO_MB,4); - if (oplmode>=OPL_dualopl2) { - IO_RegisterWriteHandler(base,OPL_Write,IO_MB,4); - IO_RegisterReadHandler(base,OPL_Read,IO_MB,4); + OPL(Section* configuration):Module_base(configuration) { + Section_prop * section=static_cast(configuration); + Bitu base = section->Get_hex("sbbase"); + Bitu rate = section->Get_int("oplrate"); + if (OPL2::YM3812Init(2,OPL2_INTERNAL_FREQ,rate)) { + E_Exit("Can't create OPL2 Emulator"); + }; + OPL2::YM3812SetTimerHandler(0,OPL2::TimerHandler,0); + OPL2::YM3812SetTimerHandler(1,OPL2::TimerHandler,256); + if (THEOPL3::YMF262Init(1,OPL3_INTERNAL_FREQ,rate)) { + E_Exit("Can't create OPL3 Emulator"); + }; + THEOPL3::YMF262SetTimerHandler(0,THEOPL3::TimerHandler,0); + WriteHandler[0].Install(0x388,OPL_Write,IO_MB,4); + ReadHandler[0].Install(0x388,OPL_Read,IO_MB,4); + if (oplmode>=OPL_dualopl2) { + WriteHandler[1].Install(base,OPL_Write,IO_MB,4); + ReadHandler[1].Install(base,OPL_Read,IO_MB,4); + } + + WriteHandler[2].Install(base+8,OPL_Write,IO_MB,2); + ReadHandler[2].Install(base+8,OPL_Read,IO_MB,2); + + opl.active=false; + opl.last_used=0; + opl.mode=oplmode; + memset(&opl.raw,0,sizeof(opl.raw)); + opl.chan=MixerChan.Install(OPL_CallBack,rate,"FM"); + MAPPER_AddHandler(OPL_SaveRawEvent,MK_f7,MMOD1|MMOD2,"caprawopl","Cap OPL"); + } + ~OPL() { + if (opl.raw.handle) OPL_SaveRawEvent(true); + OPL2::YM3812Shutdown(); + THEOPL3::YMF262Shutdown(); } - - IO_RegisterWriteHandler(base+8,OPL_Write,IO_MB,2); - IO_RegisterReadHandler(base+8,OPL_Read,IO_MB,2); - - opl.active=false; - opl.last_used=0; - opl.mode=oplmode; - memset(&opl.raw,0,sizeof(opl.raw)); - opl.chan=MIXER_AddChannel(OPL_CallBack,rate,"FM"); - MAPPER_AddHandler(OPL_SaveRawEvent,MK_f7,MMOD1|MMOD2,"caprawopl","Cap OPL"); - sec->AddDestroyFunction(&OPL_Stop); }; +static OPL* test; + +//Initialize static members +OPL_Mode OPL::oplmode=OPL_none; + +void OPL_Init(Section* sec,OPL_Mode oplmode) { + OPL::oplmode = oplmode; + test = new OPL(sec); +} + +void OPL_ShutDown(Section* sec){ + delete test; +} diff --git a/src/hardware/cmos.cpp b/src/hardware/cmos.cpp index 59cf9eb..0596ec2 100644 --- a/src/hardware/cmos.cpp +++ b/src/hardware/cmos.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -24,6 +24,7 @@ #include "inout.h" #include "mem.h" #include "bios.h" +#include "setup.h" static struct { Bit8u regs[0x40]; @@ -45,7 +46,10 @@ static struct { static void cmos_timerevent(Bitu val) { PIC_ActivateIRQ(8); - if (cmos.timer.enabled) PIC_AddEvent(cmos_timerevent,cmos.timer.delay); + if (cmos.timer.enabled) { + PIC_AddEvent(cmos_timerevent,cmos.timer.delay); + cmos.regs[0xc] = 0xC0;//Contraption Zack (music) + } } static void cmos_checktimer(void) { @@ -71,6 +75,7 @@ static void cmos_writereg(Bitu port,Bitu val,Bitu iolen) { case 0x07: /* Date of month */ case 0x08: /* Month */ case 0x09: /* Year */ + case 0x32: /* Century */ /* Ignore writes to change alarm */ break; case 0x01: /* Seconds Alarm */ @@ -92,6 +97,9 @@ static void cmos_writereg(Bitu port,Bitu val,Bitu iolen) { if (val&0x10) LOG(LOG_BIOS,LOG_ERROR)("CMOS:Updated ended interrupt not supported yet"); cmos_checktimer(); break; + case 0x0d:/* Status reg D */ + cmos.regs[cmos.reg]=val & 0x80; /*Bit 7=1:RTC Pown on*/ + break; case 0x0f: /* Shutdown status byte */ cmos.regs[cmos.reg]=val & 0x7f; break; @@ -102,7 +110,7 @@ static void cmos_writereg(Bitu port,Bitu val,Bitu iolen) { } -#define MAKE_RETURN(_VAL) (cmos.bcd ? (((_VAL / 10) << 4) | (_VAL % 10)) : _VAL); +#define MAKE_RETURN(_VAL) (cmos.bcd ? ((((_VAL) / 10) << 4) | ((_VAL) % 10)) : (_VAL)); static Bitu cmos_readreg(Bitu port,Bitu iolen) { if (cmos.reg>0x3f) { @@ -113,7 +121,6 @@ static Bitu cmos_readreg(Bitu port,Bitu iolen) { Bit8u hdparm; time_t curtime; struct tm *loctime; - /* Get the current time. */ curtime = time (NULL); @@ -128,18 +135,20 @@ static Bitu cmos_readreg(Bitu port,Bitu iolen) { case 0x04: /* Hours */ return MAKE_RETURN(loctime->tm_hour); case 0x06: /* Day of week */ - return MAKE_RETURN(loctime->tm_wday); + return MAKE_RETURN(loctime->tm_wday + 1); case 0x07: /* Date of month */ return MAKE_RETURN(loctime->tm_mday); case 0x08: /* Month */ - return MAKE_RETURN(loctime->tm_mon); + return MAKE_RETURN(loctime->tm_mon + 1); case 0x09: /* Year */ - return MAKE_RETURN(loctime->tm_year); + return MAKE_RETURN(loctime->tm_year % 100); + case 0x32: /* Century */ + return MAKE_RETURN(loctime->tm_year / 100 + 19); case 0x01: /* Seconds Alarm */ case 0x03: /* Minutes Alarm */ case 0x05: /* Hours Alarm */ return cmos.regs[cmos.reg]; - case 0x0a: /* Status register C */ + case 0x0a: /* Status register A */ if (PIC_TickIndex()<0.002) { return (cmos.regs[0x0a]&0x7f) | 0x80; } else { @@ -245,38 +254,64 @@ static Bitu cmos_readreg(Bitu port,Bitu iolen) { case 0x0b: /* Status register B */ + case 0x0d: /* Status register D */ case 0x0f: /* Shutdown status byte */ + case 0x14: /* Equipment */ + case 0x15: /* Base Memory KB Low Byte */ + case 0x16: /* Base Memory KB High Byte */ case 0x17: /* Extended memory in KB Low Byte */ case 0x18: /* Extended memory in KB High Byte */ case 0x30: /* Extended memory in KB Low Byte */ case 0x31: /* Extended memory in KB High Byte */ -// LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %F : %04X",cmos.reg,cmos.regs[cmos.reg]); +// LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %X : %04X",cmos.reg,cmos.regs[cmos.reg]); return cmos.regs[cmos.reg]; default: - LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %F",cmos.reg); + LOG(LOG_BIOS,LOG_NORMAL)("CMOS:Read from reg %X",cmos.reg); return cmos.regs[cmos.reg]; } } -void CMOS_SetRegister(Bitu regNr, Bit8u val) -{ +void CMOS_SetRegister(Bitu regNr, Bit8u val) { cmos.regs[regNr] = val; }; -void CMOS_Init(Section* sec) { - IO_RegisterWriteHandler(0x70,cmos_selreg,IO_MB); - IO_RegisterWriteHandler(0x71,cmos_writereg,IO_MB); - IO_RegisterReadHandler(0x71,cmos_readreg,IO_MB); - cmos.timer.enabled=false; - cmos.reg=0xa; - cmos_writereg(0x71,0x26,1); - cmos.reg=0xb; - cmos_writereg(0x71,0,1); - /* Fill in extended memory size */ - Bitu exsize=(MEM_TotalPages()*4)-1024; - cmos.regs[0x17]=(Bit8u)exsize; - cmos.regs[0x18]=(Bit8u)(exsize >> 8); - cmos.regs[0x30]=(Bit8u)exsize; - cmos.regs[0x31]=(Bit8u)(exsize >> 8); + +class CMOS:public Module_base{ +private: + IO_ReadHandleObject ReadHandler[2]; + IO_WriteHandleObject WriteHandler[2]; +public: + CMOS(Section* configuration):Module_base(configuration){ + WriteHandler[0].Install(0x70,cmos_selreg,IO_MB); + WriteHandler[1].Install(0x71,cmos_writereg,IO_MB); + ReadHandler[0].Install(0x71,cmos_readreg,IO_MB); + cmos.timer.enabled=false; + cmos.reg=0xa; + cmos_writereg(0x71,0x26,1); + cmos.reg=0xb; + cmos_writereg(0x71,0x2,1); //Struct tm *loctime is of 24 hour format, + cmos.reg=0xd; + cmos_writereg(0x71,0x80,1); /* RTC power on */ + // Equipment is updated from bios.cpp and bios_disk.cpp + /* Fill in base memory size, it is 640K always */ + cmos.regs[0x15]=(Bit8u)0x80; + cmos.regs[0x16]=(Bit8u)0x02; + /* Fill in extended memory size */ + Bitu exsize=(MEM_TotalPages()*4)-1024; + cmos.regs[0x17]=(Bit8u)exsize; + cmos.regs[0x18]=(Bit8u)(exsize >> 8); + cmos.regs[0x30]=(Bit8u)exsize; + cmos.regs[0x31]=(Bit8u)(exsize >> 8); + } +}; + +static CMOS* test; + +void CMOS_Destroy(Section* sec){ + delete test; } +void CMOS_Init(Section* sec) { + test = new CMOS(sec); + sec->AddDestroyFunction(&CMOS_Destroy,true); +} diff --git a/src/hardware/directserial_win32.cpp b/src/hardware/directserial_win32.cpp deleted file mode 100644 index 04c1615..0000000 --- a/src/hardware/directserial_win32.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2002-2004 The DOSBox Team - * - * 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. - */ - -/* $Id: directserial_win32.cpp,v 1.4 2004/08/04 13:21:20 qbix79 Exp $ */ - -#include "dosbox.h" - -#if C_DIRECTSERIAL - -/* Windows version */ -#if defined (WIN32) - -#include -#include -#include - -#include "setup.h" -#include "serialport.h" - -// Win32 related headers -#include - -/* This is a serial passthrough class. Its amazingly simple to */ -/* write now that the serial ports themselves were abstracted out */ - - -class CDirectSerial : public CSerial { -public: - HANDLE hCom; - DCB dcb; - BOOL fSuccess; - - CDirectSerial(char * realPort, Bit16u baseAddr, Bit8u initIrq, Bit32u initBps, Bit16u bytesize, char *parity, Bit16u stopbits ) : CSerial(baseAddr, initIrq, initBps) { - LOG_MSG("Opening Windows serial port"); - hCom = CreateFile(realPort, GENERIC_READ | GENERIC_WRITE, - 0, // must be opened with exclusive-access - NULL, // no security attributes - OPEN_EXISTING, // must use OPEN_EXISTING - 0, // non overlapped I/O - NULL // hTemplate must be NULL for comm devices - ); - - if (hCom == INVALID_HANDLE_VALUE) - { - LOG_MSG("CreateFile failed with error %d.\n", GetLastError()); - hCom = 0; - return; - } - - fSuccess = GetCommState(hCom, &dcb); - - if (!fSuccess) - { - // Handle the error. - LOG_MSG("GetCommState failed with error %d.\n", GetLastError()); - return; - } - - - dcb.BaudRate = initBps; // set the baud rate - dcb.ByteSize = bytesize; // data size, xmit, and rcv - if(parity[0] == 'N') - dcb.Parity = NOPARITY; // no parity bit - if(parity[1] == 'E') - dcb.Parity = EVENPARITY; // even parity bit - if(parity[2] == 'O') - dcb.Parity = ODDPARITY; // odd parity bit - - - if(stopbits == 1) - dcb.StopBits = ONESTOPBIT; // one stop bit - if(stopbits == 2) - dcb.StopBits = TWOSTOPBITS; // two stop bits - - fSuccess = SetCommState(hCom, &dcb); - - // Configure timeouts to effectively use polling - COMMTIMEOUTS ct; - ct.ReadIntervalTimeout = MAXDWORD; - ct.ReadTotalTimeoutConstant = 0; - ct.ReadTotalTimeoutMultiplier = 0; - ct.WriteTotalTimeoutConstant = 0; - ct.WriteTotalTimeoutMultiplier = 0; - SetCommTimeouts(hCom, &ct); - - } - - ~CDirectSerial() { - if(hCom != INVALID_HANDLE_VALUE) CloseHandle(hCom); - } - - bool CanRecv(void) { return true; } - bool CanSend(void) { return true; } - - void Send(Bit8u val) { tqueue->addb(val); } - - Bit8u Recv(Bit8u val) { return rqueue->getb(); } - - void updatestatus(void) { - Bit8u ms=0; - DWORD stat = 0; - GetCommModemStatus(hCom, &stat); - - //Check for data carrier - if(stat & MS_RLSD_ON) ms|=MS_DCD; - if (stat & MS_RING_ON) ms|=MS_RI; - if (stat & MS_DSR_ON) ms|=MS_DSR; - if (stat & MS_CTS_ON) ms|=MS_CTS; - SetModemStatus(ms); - } - - void Timer(void) { - DWORD dwRead; - Bit8u chRead; - - if (ReadFile(hCom, &chRead, 1, &dwRead, NULL)) { - if(dwRead != 0) { - if(!rqueue->isFull()) rqueue->addb(chRead); - } - } - - updatestatus(); - - Bit8u txval; - - Bitu tx_size=tqueue->inuse(); - while (tx_size--) { - txval = tqueue->getb(); - DWORD bytesWritten; - BOOL result; - result = WriteFile(hCom, &txval, 1, &bytesWritten, NULL); - if (!result) - { - // Handle the error. - LOG_MSG("WriteFile failed with error %d.\n", GetLastError()); - return; - } - - } - } - -}; - -CDirectSerial *cds; - -void DIRECTSERIAL_Init(Section* sec) { - - unsigned long args = 1; - Section_prop * section=static_cast(sec); - - - if(!section->Get_bool("directserial")) return; - - Bit16u comport = section->Get_int("comport"); - Bit32u bps = section->Get_int("defaultbps"); - switch (comport) { - case 1: - cds = new CDirectSerial((char *)section->Get_string("realport"), 0x3f0, 4, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); - break; - case 2: - cds = new CDirectSerial((char *)section->Get_string("realport"), 0x2f0, 3, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); - break; - case 3: - cds = new CDirectSerial((char *)section->Get_string("realport"), 0x3e0, 4, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); - break; - case 4: - cds = new CDirectSerial((char *)section->Get_string("realport"), 0x2e0, 3, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); - break; - default: - cds = new CDirectSerial((char *)section->Get_string("realport"), 0x3f0, 4, bps, section->Get_int("bytesize"), (char *)section->Get_string("parity"), section->Get_int("stopbit")); - break; - - } - - - - seriallist.push_back(cds); -} -#else /*linux and others oneday maybe */ - -#endif -#endif - diff --git a/src/hardware/disney.cpp b/src/hardware/disney.cpp index 36d36ef..e33e46e 100644 --- a/src/hardware/disney.cpp +++ b/src/hardware/disney.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -98,20 +98,36 @@ static void DISNEY_CallBack(Bitu len) { } } +class DISNEY: public Module_base { +private: + IO_ReadHandleObject ReadHandler; + IO_WriteHandleObject WriteHandler; + MixerObject MixerChan; +public: + DISNEY(Section* configuration):Module_base(configuration) { + Section_prop * section=static_cast(configuration); + if(!section->Get_bool("disney")) return; + + WriteHandler.Install(DISNEY_BASE,disney_write,IO_MB,3); + ReadHandler.Install(DISNEY_BASE,disney_read,IO_MB,3); + + disney.chan=MixerChan.Install(&DISNEY_CallBack,7000,"DISNEY"); + + disney.status=0x84; + disney.control=0; + disney.used=0; + disney.last_used=0; + } + ~DISNEY(){ } +}; -void DISNEY_Init(Section* sec) { - MSG_Add("DISNEY_CONFIGFILE_HELP","Nothing to setup yet!\n"); - Section_prop * section=static_cast(sec); - if(!section->Get_bool("disney")) return; +static DISNEY* test; - IO_RegisterWriteHandler(DISNEY_BASE,disney_write,IO_MB,3); - IO_RegisterReadHandler(DISNEY_BASE,disney_read,IO_MB,3); - - disney.chan=MIXER_AddChannel(&DISNEY_CallBack,7000,"DISNEY"); - - disney.status=0x84; - disney.control=0; - disney.used=0; - disney.last_used=0; +static void DISNEY_ShutDown(Section* sec){ + delete test; } +void DISNEY_Init(Section* sec) { + test = new DISNEY(sec); + sec->AddDestroyFunction(&DISNEY_ShutDown,true); +} diff --git a/src/hardware/dma.cpp b/src/hardware/dma.cpp index 0c63a3a..02a2337 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -22,18 +22,122 @@ #include "inout.h" #include "dma.h" #include "pic.h" +#include "paging.h" +#include "setup.h" -DmaChannel *DmaChannels[8]; DmaController *DmaControllers[2]; -static void DMA_WriteControllerReg(DmaController * cont,Bitu reg,Bitu val,Bitu len) { +#define EMM_PAGEFRAME4K ((0xE000*16)/4096) +Bit32u ems_board_mapping[LINK_START]; + +static void UpdateEMSMapping(void) { + /* if EMS is not present, this will result in a 1:1 mapping */ + Bitu i; + for (i=0;i<0x10;i++) { + ems_board_mapping[EMM_PAGEFRAME4K+i]=paging.firstmb[EMM_PAGEFRAME4K+i]; + } +} + +/* read a block from physical memory */ +static void DMA_BlockRead(PhysPt pt,void * data,Bitu size) { + Bit8u * write=(Bit8u *) data; + for ( ; size ; size--, pt++) { + Bitu page = pt >> 12; + /* care for EMS pageframe etc. */ + if (page < EMM_PAGEFRAME4K) page = paging.firstmb[page]; + else if (page < EMM_PAGEFRAME4K+0x10) page = ems_board_mapping[page]; + else if (page < LINK_START) page = paging.firstmb[page]; + *write++=phys_readb(page*4096 + (pt & 4095)); + } +} + +/* write a block into physical memory */ +static void DMA_BlockWrite(PhysPt pt,void * data,Bitu size) { + Bit8u * read=(Bit8u *) data; + for ( ; size ; size--, pt++) { + Bitu page = pt >> 12; + /* care for EMS pageframe etc. */ + if (page < EMM_PAGEFRAME4K) page = paging.firstmb[page]; + else if (page < EMM_PAGEFRAME4K+0x10) page = ems_board_mapping[page]; + else if (page < LINK_START) page = paging.firstmb[page]; + phys_writeb(page*4096 + (pt & 4095), *read++); + } +} + +DmaChannel * GetDMAChannel(Bit8u chan) { + if (chan<4) { + /* channel on first DMA controller */ + if (DmaControllers[0]) return DmaControllers[0]->GetChannel(chan); + } else if (chan<8) { + /* channel on second DMA controller */ + if (DmaControllers[1]) return DmaControllers[1]->GetChannel(chan-4); + } + return NULL; +} + +/* remove the second DMA controller (ports are removed automatically) */ +void CloseSecondDMAController(void) { + if (DmaControllers[1]) { + delete DmaControllers[1]; + DmaControllers[1]=NULL; + } +} + +/* check availability of second DMA controller, needed for SB16 */ +bool SecondDMAControllerAvailable(void) { + if (DmaControllers[1]) return true; + else return false; +} + +static void DMA_Write_Port(Bitu port,Bitu val,Bitu iolen) { + if (port<0x10) { + /* write to the first DMA controller (channels 0-3) */ + DmaControllers[0]->WriteControllerReg(port,val,1); + } else if (port>=0xc0 && port <=0xdf) { + /* write to the second DMA controller (channels 4-7) */ + DmaControllers[1]->WriteControllerReg((port-0xc0) >> 1,val,1); + } else { + UpdateEMSMapping(); + switch (port) { + /* write DMA page register */ + case 0x81:GetDMAChannel(2)->SetPage(val);break; + case 0x82:GetDMAChannel(3)->SetPage(val);break; + case 0x83:GetDMAChannel(1)->SetPage(val);break; + case 0x89:GetDMAChannel(6)->SetPage(val);break; + case 0x8a:GetDMAChannel(7)->SetPage(val);break; + case 0x8b:GetDMAChannel(5)->SetPage(val);break; + } + } +} + +static Bitu DMA_Read_Port(Bitu port,Bitu iolen) { + if (port<0x10) { + /* read from the first DMA controller (channels 0-3) */ + return DmaControllers[0]->ReadControllerReg(port,iolen); + } else if (port>=0xc0 && port <=0xdf) { + /* read from the second DMA controller (channels 4-7) */ + return DmaControllers[1]->ReadControllerReg((port-0xc0) >> 1,iolen); + } else switch (port) { + /* read DMA page register */ + case 0x81:return GetDMAChannel(2)->pagenum; + case 0x82:return GetDMAChannel(3)->pagenum; + case 0x83:return GetDMAChannel(1)->pagenum; + case 0x89:return GetDMAChannel(6)->pagenum; + case 0x8a:return GetDMAChannel(7)->pagenum; + case 0x8b:return GetDMAChannel(5)->pagenum; + } + return 0; +} + +void DmaController::WriteControllerReg(Bitu reg,Bitu val,Bitu len) { DmaChannel * chan;Bitu i; - Bitu base=cont->chanbase; switch (reg) { + /* set base address of DMA transfer (1st byte low part, 2nd byte high part) */ case 0x0:case 0x2:case 0x4:case 0x6: - chan=DmaChannels[base+(reg >> 1)]; - cont->flipflop=!cont->flipflop; - if (cont->flipflop) { + UpdateEMSMapping(); + chan=GetChannel(reg >> 1); + flipflop=!flipflop; + if (flipflop) { chan->baseaddr=(chan->baseaddr&0xff00)|val; chan->curraddr=(chan->curraddr&0xff00)|val; } else { @@ -41,10 +145,12 @@ static void DMA_WriteControllerReg(DmaController * cont,Bitu reg,Bitu val,Bitu l chan->curraddr=(chan->curraddr&0x00ff)|(val << 8); } break; + /* set DMA transfer count (1st byte low part, 2nd byte high part) */ case 0x1:case 0x3:case 0x5:case 0x7: - chan=DmaChannels[base+(reg >> 1)]; - cont->flipflop=!cont->flipflop; - if (cont->flipflop) { + UpdateEMSMapping(); + chan=GetChannel(reg >> 1); + flipflop=!flipflop; + if (flipflop) { chan->basecnt=(chan->basecnt&0xff00)|val; chan->currcnt=(chan->currcnt&0xff00)|val; } else { @@ -58,121 +164,98 @@ static void DMA_WriteControllerReg(DmaController * cont,Bitu reg,Bitu val,Bitu l //TODO Warning? break; case 0xa: /* Mask Register */ - chan=DmaChannels[base+(val & 3 )]; + if ((val & 0x4)==0) UpdateEMSMapping(); + chan=GetChannel(val & 3); chan->SetMask((val & 0x4)>0); break; case 0xb: /* Mode Register */ - chan=DmaChannels[base+(val & 3 )]; + UpdateEMSMapping(); + chan=GetChannel(val & 3); chan->autoinit=(val & 0x10) > 0; chan->increment=(val & 0x20) > 0; //TODO Maybe other bits? break; case 0xc: /* Clear Flip/Flip */ - cont->flipflop=false; + flipflop=false; break; case 0xd: /* Master Clear/Reset */ for (i=0;i<4;i++) { - DmaChannels[base+i]->SetMask(true); - DmaChannels[base+i]->tcount=false; + chan=GetChannel(i); + chan->SetMask(true); + chan->tcount=false; } - cont->flipflop=false; + flipflop=false; break; case 0xe: /* Clear Mask register */ + UpdateEMSMapping(); for (i=0;i<4;i++) { - DmaChannels[base+i]->SetMask(false); + chan=GetChannel(i); + chan->SetMask(false); } break; case 0xf: /* Multiple Mask register */ + UpdateEMSMapping(); for (i=0;i<4;i++) { - DmaChannels[base+i]->SetMask(val & 1); + chan=GetChannel(i); + chan->SetMask(val & 1); val>>=1; } break; } } -static Bitu DMA_ReadControllerReg(DmaController * cont,Bitu reg,Bitu len) { +Bitu DmaController::ReadControllerReg(Bitu reg,Bitu len) { DmaChannel * chan;Bitu i,ret; - Bitu base=cont->chanbase; switch (reg) { + /* read base address of DMA transfer (1st byte low part, 2nd byte high part) */ case 0x0:case 0x2:case 0x4:case 0x6: - chan=DmaChannels[base+(reg >> 1)]; - cont->flipflop=!cont->flipflop; - if (cont->flipflop) { + chan=GetChannel(reg >> 1); + flipflop=!flipflop; + if (flipflop) { return chan->curraddr & 0xff; } else { return (chan->curraddr >> 8) & 0xff; } + /* read DMA transfer count (1st byte low part, 2nd byte high part) */ case 0x1:case 0x3:case 0x5:case 0x7: - chan=DmaChannels[base+(reg >> 1)]; - cont->flipflop=!cont->flipflop; - if (cont->flipflop) { + chan=GetChannel(reg >> 1); + flipflop=!flipflop; + if (flipflop) { return chan->currcnt & 0xff; } else { return (chan->currcnt >> 8) & 0xff; } - case 0x8: + case 0x8: /* Status Register */ ret=0; for (i=0;i<4;i++) { - chan=DmaChannels[base+i]; + chan=GetChannel(i); if (chan->tcount) ret|=1 << i; chan->tcount=false; if (chan->callback) ret|=1 << (i+4); } return ret; default: - LOG_MSG("Trying to read undefined DMA Red %x",reg); + LOG(LOG_DMA,LOG_NORMAL)("Trying to read undefined DMA port %x",reg); + break; } return 0xffffffff; } - -static void DMA_Write_Port(Bitu port,Bitu val,Bitu iolen) { - if (port<0x10) { - DMA_WriteControllerReg(DmaControllers[0],port,val,1); - } else if (port>=0xc0 && port <=0xdf) { - DMA_WriteControllerReg(DmaControllers[1],(port-0xc0) >> 1,val,1); - } else switch (port) { - case 0x81:DmaChannels[2]->SetPage(val);break; - case 0x82:DmaChannels[3]->SetPage(val);break; - case 0x83:DmaChannels[1]->SetPage(val);break; - case 0x89:DmaChannels[6]->SetPage(val);break; - case 0x8a:DmaChannels[7]->SetPage(val);break; - case 0x8b:DmaChannels[5]->SetPage(val);break; - } -} - -static Bitu DMA_Read_Port(Bitu port,Bitu iolen) { - if (port<0x10) { - return DMA_ReadControllerReg(DmaControllers[0],port,iolen); - } else if (port>=0xc0 && port <=0xdf) { - return DMA_ReadControllerReg(DmaControllers[1],(port-0xc0) >> 1,iolen); - } else switch (port) { - case 0x81:return DmaChannels[2]->pagenum; - case 0x82:return DmaChannels[3]->pagenum; - case 0x83:return DmaChannels[1]->pagenum; - case 0x89:return DmaChannels[6]->pagenum; - case 0x8a:return DmaChannels[7]->pagenum; - case 0x8b:return DmaChannels[5]->pagenum; - } - return 0; -} - DmaChannel::DmaChannel(Bit8u num, bool dma16) { - masked = true; - callback = NULL; - if(num == 4) return; - channum = num; - DMA16 = dma16 ? 0x1 : 0x0; - pagenum = 0; - pagebase = 0; - baseaddr = 0; - curraddr = 0; - basecnt = 0; - currcnt = 0; - increment = true; - autoinit = false; - tcount = false; + masked = true; + callback = NULL; + if(num == 4) return; + channum = num; + DMA16 = dma16 ? 0x1 : 0x0; + pagenum = 0; + pagebase = 0; + baseaddr = 0; + curraddr = 0; + basecnt = 0; + currcnt = 0; + increment = true; + autoinit = false; + tcount = false; } Bitu DmaChannel::Read(Bitu want, Bit8u * buffer) { @@ -180,12 +263,12 @@ Bitu DmaChannel::Read(Bitu want, Bit8u * buffer) { again: Bitu left=(currcnt+1); if (want=4); - } +class DMA:public Module_base{ +public: + DMA(Section* configuration):Module_base(configuration){ + Bitu i; + DmaControllers[0] = new DmaController(0); + if (machine==MCH_VGA) DmaControllers[1] = new DmaController(1); - for (i=0;i<0x10;i++) { - Bitu mask=IO_MB; - if (i<8) mask|=IO_MW; - IO_RegisterWriteHandler(i,DMA_Write_Port,mask); - IO_RegisterReadHandler(i,DMA_Read_Port,mask); + for (i=0;i<0x10;i++) { + Bitu mask=IO_MB; + if (i<8) mask|=IO_MW; + /* install handler for first DMA controller ports */ + DmaControllers[0]->DMA_WriteHandler[i].Install(i,DMA_Write_Port,mask); + DmaControllers[0]->DMA_ReadHandler[i].Install(i,DMA_Read_Port,mask); + if (machine==MCH_VGA) { + /* install handler for second DMA controller ports */ + DmaControllers[1]->DMA_WriteHandler[i].Install(0xc0+i*2,DMA_Write_Port,mask); + DmaControllers[1]->DMA_ReadHandler[i].Install(0xc0+i*2,DMA_Read_Port,mask); + } + } + /* install handlers for ports 0x81-0x83 (on the first DMA controller) */ + DmaControllers[0]->DMA_WriteHandler[0x10].Install(0x81,DMA_Write_Port,IO_MB,3); + DmaControllers[0]->DMA_ReadHandler[0x10].Install(0x81,DMA_Read_Port,IO_MB,3); + if (machine==MCH_VGA) { - IO_RegisterWriteHandler(0xc0+i*2,DMA_Write_Port,mask); - IO_RegisterReadHandler(0xc0+i*2,DMA_Read_Port,mask); + /* install handlers for ports 0x81-0x83 (on the second DMA controller) */ + DmaControllers[1]->DMA_WriteHandler[0x10].Install(0x89,DMA_Write_Port,IO_MB,3); + DmaControllers[1]->DMA_ReadHandler[0x10].Install(0x89,DMA_Read_Port,IO_MB,3); } } - IO_RegisterWriteHandler(0x81,DMA_Write_Port,IO_MB,3); - IO_RegisterWriteHandler(0x89,DMA_Write_Port,IO_MB,3); + ~DMA(){ + if (DmaControllers[0]) { + delete DmaControllers[0]; + DmaControllers[0]=NULL; + } + if (DmaControllers[1]) { + delete DmaControllers[1]; + DmaControllers[1]=NULL; + } + } +}; - IO_RegisterReadHandler(0x81,DMA_Read_Port,IO_MB,3); - IO_RegisterReadHandler(0x89,DMA_Read_Port,IO_MB,3); +static DMA* test; + +void DMA_Destroy(Section* sec){ + delete test; +} +void DMA_Init(Section* sec) { + test = new DMA(sec); + sec->AddDestroyFunction(&DMA_Destroy); + Bitu i; + for (i=0;iEnable(true); + if (last_command + 1000 < PIC_Ticks) if(cms_chan) cms_chan->Enable(true); last_command = PIC_Ticks; switch (port) { case 0x0220: @@ -415,25 +415,45 @@ static void write_cms(Bitu port,Bitu val,Bitu iolen) { else *stream=(Bit16s)right; stream++; } - cms_chan->AddSamples_s16(len,(Bit16s *)MixTemp); - if (last_command + 10000 < PIC_Ticks) cms_chan->Enable(false); + if(cms_chan) cms_chan->AddSamples_s16(len,(Bit16s *)MixTemp); + if (last_command + 10000 < PIC_Ticks) if(cms_chan) cms_chan->Enable(false); } - void CMS_Init(Section* sec,Bitu base,Bitu rate) { - Section_prop * section=static_cast(sec); - sample_rate=rate; +class CMS:public Module_base { +private: + IO_WriteHandleObject WriteHandler; + MixerObject MixerChan; - IO_RegisterWriteHandler(base,write_cms,IO_MB,4); - -/* Register the Mixer CallBack */ +public: + CMS(Section* configuration):Module_base(configuration) { + Section_prop * section = static_cast(configuration); + Bitu sample_rate_temp = section->Get_int("oplrate"); + sample_rate = static_cast(sample_rate_temp); + Bitu base = section->Get_hex("sbbase"); + WriteHandler.Install(base,write_cms,IO_MB,4); - cms_chan=MIXER_AddChannel(CMS_CallBack,rate,"CMS"); - last_command=PIC_Ticks; + /* Register the Mixer CallBack */ + cms_chan = MixerChan.Install(CMS_CallBack,sample_rate_temp,"CMS"); - for (int s=0;s<2;s++) { - struct SAA1099 *saa = &saa1099[s]; - memset(saa, 0, sizeof(struct SAA1099)); + last_command = PIC_Ticks; + + for (int s=0;s<2;s++) { + struct SAA1099 *saa = &saa1099[s]; + memset(saa, 0, sizeof(struct SAA1099)); + } } -} + ~CMS() { + cms_chan = 0; + } +}; + +static CMS* test; + +void CMS_Init(Section* sec) { + test = new CMS(sec); +} +void CMS_ShutDown(Section* sec) { + delete test; +} diff --git a/src/hardware/gus.cpp b/src/hardware/gus.cpp index 5da7390..6395325 100644 --- a/src/hardware/gus.cpp +++ b/src/hardware/gus.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -23,7 +23,7 @@ #include "dma.h" #include "pic.h" #include "setup.h" -#include "programs.h" +#include "shell.h" #include "math.h" #include "regs.h" @@ -83,8 +83,8 @@ struct GFGus { } timers[2]; Bit32u rate; Bit16u portbase; - Bit16u dma1; - Bit16u dma2; + Bit8u dma1; + Bit8u dma2; Bit16u irq1; Bit16u irq2; @@ -568,7 +568,7 @@ static void ExecuteGlobRegister(void) { break; case 0x41: // Dma control register myGUS.DMAControl = (Bit8u)(myGUS.gRegData>>8); - DmaChannels[myGUS.dma1]->Register_Callback( + GetDMAChannel(myGUS.dma1)->Register_Callback( (myGUS.DMAControl & 0x1) ? GUS_DMA_Callback : 0); break; case 0x42: // Gravis DRAM DMA address register @@ -597,7 +597,7 @@ static void ExecuteGlobRegister(void) { break; case 0x49: // DMA sampling control register myGUS.SampControl = (Bit8u)(myGUS.gRegData>>8); - DmaChannels[myGUS.dma1]->Register_Callback( + GetDMAChannel(myGUS.dma1)->Register_Callback( (myGUS.SampControl & 0x1) ? GUS_DMA_Callback : 0); break; case 0x4c: // GUS reset register @@ -791,72 +791,106 @@ static void MakeTables(void) { } } -void GUS_Init(Section* sec) { - if(machine!=MCH_VGA) return; - Section_prop * section=static_cast(sec); - if(!section->Get_bool("gus")) return; - - memset(&myGUS,0,sizeof(myGUS)); - memset(GUSRam,0,1024*1024); - - myGUS.rate=section->Get_int("rate"); - - myGUS.portbase = section->Get_hex("base") - 0x200; - myGUS.dma1 = section->Get_int("dma1"); - myGUS.dma2 = section->Get_int("dma2"); - myGUS.irq1 = section->Get_int("irq1"); - myGUS.irq2 = section->Get_int("irq2"); - strcpy(&myGUS.ultradir[0], section->Get_string("ultradir")); - - // We'll leave the MIDI interface to the MPU-401 - // Ditto for the Joystick - // GF1 Synthesizer - - IO_RegisterWriteHandler(0x302 + GUS_BASE,write_gus,IO_MB); - IO_RegisterReadHandler(0x302 + GUS_BASE,read_gus,IO_MB); - - IO_RegisterWriteHandler(0x303 + GUS_BASE,write_gus,IO_MB); - IO_RegisterReadHandler(0x303 + GUS_BASE,read_gus,IO_MB); - - IO_RegisterWriteHandler(0x304 + GUS_BASE,write_gus,IO_MB|IO_MW); - IO_RegisterReadHandler(0x304 + GUS_BASE,read_gus,IO_MB|IO_MW); - - IO_RegisterWriteHandler(0x305 + GUS_BASE,write_gus,IO_MB); - IO_RegisterReadHandler(0x305 + GUS_BASE,read_gus,IO_MB); - - IO_RegisterReadHandler(0x206 + GUS_BASE,read_gus,IO_MB); - - IO_RegisterWriteHandler(0x208 + GUS_BASE,write_gus,IO_MB); - IO_RegisterReadHandler(0x208 + GUS_BASE,read_gus,IO_MB); - - IO_RegisterWriteHandler(0x209 + GUS_BASE,write_gus,IO_MB); - - IO_RegisterWriteHandler(0x307 + GUS_BASE,write_gus,IO_MB); - IO_RegisterReadHandler(0x307 + GUS_BASE,read_gus,IO_MB); - - // Board Only - - IO_RegisterWriteHandler(0x200 + GUS_BASE,write_gus,IO_MB); - IO_RegisterReadHandler(0x20A + GUS_BASE,read_gus,IO_MB); - IO_RegisterWriteHandler(0x20B + GUS_BASE,write_gus,IO_MB); - -// DmaChannels[myGUS.dma1]->Register_TC_Callback(GUS_DMA_TC_Callback); - - MakeTables(); - - int i; - for(i=0;i<32;i++) { - guschan[i] = new GUSChannels(i); +class GUS:public Module_base{ +private: + IO_ReadHandleObject ReadHandler[8]; + IO_WriteHandleObject WriteHandler[9]; + AutoexecObject autoexecline[2]; + MixerObject MixerChan; +public: + GUS(Section* configuration):Module_base(configuration){ + if(machine!=MCH_VGA) return; + Section_prop * section=static_cast(configuration); + if(!section->Get_bool("gus")) return; + + memset(&myGUS,0,sizeof(myGUS)); + memset(GUSRam,0,1024*1024); + + myGUS.rate=section->Get_int("gusrate"); + + myGUS.portbase = section->Get_hex("gusbase") - 0x200; + myGUS.dma1 = section->Get_int("dma1"); + myGUS.dma2 = section->Get_int("dma2"); + myGUS.irq1 = section->Get_int("irq1"); + myGUS.irq2 = section->Get_int("irq2"); + strcpy(&myGUS.ultradir[0], section->Get_string("ultradir")); + + // We'll leave the MIDI interface to the MPU-401 + // Ditto for the Joystick + // GF1 Synthesizer + ReadHandler[0].Install(0x302 + GUS_BASE,read_gus,IO_MB); + WriteHandler[0].Install(0x302 + GUS_BASE,write_gus,IO_MB); + + WriteHandler[1].Install(0x303 + GUS_BASE,write_gus,IO_MB); + ReadHandler[1].Install(0x303 + GUS_BASE,read_gus,IO_MB); + + WriteHandler[2].Install(0x304 + GUS_BASE,write_gus,IO_MB|IO_MW); + ReadHandler[2].Install(0x304 + GUS_BASE,read_gus,IO_MB|IO_MW); + + WriteHandler[3].Install(0x305 + GUS_BASE,write_gus,IO_MB); + ReadHandler[3].Install(0x305 + GUS_BASE,read_gus,IO_MB); + + ReadHandler[4].Install(0x206 + GUS_BASE,read_gus,IO_MB); + + WriteHandler[4].Install(0x208 + GUS_BASE,write_gus,IO_MB); + ReadHandler[5].Install(0x208 + GUS_BASE,read_gus,IO_MB); + + WriteHandler[5].Install(0x209 + GUS_BASE,write_gus,IO_MB); + + WriteHandler[6].Install(0x307 + GUS_BASE,write_gus,IO_MB); + ReadHandler[6].Install(0x307 + GUS_BASE,read_gus,IO_MB); + + // Board Only + + WriteHandler[7].Install(0x200 + GUS_BASE,write_gus,IO_MB); + ReadHandler[7].Install(0x20A + GUS_BASE,read_gus,IO_MB); + WriteHandler[8].Install(0x20B + GUS_BASE,write_gus,IO_MB); + + // DmaChannels[myGUS.dma1]->Register_TC_Callback(GUS_DMA_TC_Callback); + + MakeTables(); + + int i; + for(i=0;i<32;i++) { + guschan[i] = new GUSChannels(i); + } + // Register the Mixer CallBack + gus_chan=MixerChan.Install(GUS_CallBack,GUS_RATE,"GUS"); + myGUS.gRegData=0x1; + GUSReset(); + myGUS.gRegData=0x0; + int portat = 0x200+GUS_BASE; + // ULTRASND=Port,DMA1,DMA2,IRQ1,IRQ2 + autoexecline[0].Install("SET ULTRASND=%3X,%d,%d,%d,%d",portat,myGUS.dma1,myGUS.dma2,myGUS.irq1,myGUS.irq2); + autoexecline[1].Install("SET ULTRADIR=%s", myGUS.ultradir); } - // Register the Mixer CallBack - gus_chan=MIXER_AddChannel(GUS_CallBack,GUS_RATE,"GUS"); - myGUS.gRegData=0x1; - GUSReset(); - myGUS.gRegData=0x0; - int portat = 0x200+GUS_BASE; - // ULTRASND=Port,DMA1,DMA2,IRQ1,IRQ2 - SHELL_AddAutoexec("SET ULTRASND=%3X,%d,%d,%d,%d",portat,myGUS.dma1,myGUS.dma2,myGUS.irq1,myGUS.irq2); - SHELL_AddAutoexec("SET ULTRADIR=%s", myGUS.ultradir); + + + ~GUS() { + if(machine!=MCH_VGA) return; + Section_prop * section=static_cast(m_configuration); + if(!section->Get_bool("gus")) return; + + myGUS.gRegData=0x1; + GUSReset(); + myGUS.gRegData=0x0; + + for(Bitu i=0;i<32;i++) { + delete guschan[i]; + } + + memset(&myGUS,0,sizeof(myGUS)); + memset(GUSRam,0,1024*1024); + } +}; + +static GUS* test; + +void GUS_ShutDown(Section* sec) { + delete test; } - +void GUS_Init(Section* sec) { + test = new GUS(sec); + sec->AddDestroyFunction(&GUS_ShutDown,true); +} diff --git a/src/hardware/hardware.cpp b/src/hardware/hardware.cpp index 39c6bf8..00cd395 100644 --- a/src/hardware/hardware.cpp +++ b/src/hardware/hardware.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,19 +16,70 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* - This could do with a serious revision :) -*/ +/* $Id: hardware.cpp,v 1.16 2006/03/29 13:51:58 harekiet Exp $ */ #include #include +#include +#include #include "dosbox.h" #include "hardware.h" #include "setup.h" #include "support.h" +#include "mem.h" +#include "mapper.h" +#include "pic.h" +#include "render.h" + +#if (C_SSHOT) +#include +#include "../libs/zmbv/zmbv.cpp" +#endif static char * capturedir; extern char * RunningProgram; +Bitu CaptureState; + +#define WAVE_BUF 16*1024 +#define MIDI_BUF 4*1024 +#define AVI_HEADER_SIZE 500 + +static struct { + struct { + FILE * handle; + Bit16s buf[WAVE_BUF][2]; + Bitu used; + Bit32u length; + Bit32u freq; + } wave; + struct { + FILE * handle; + Bit8u buffer[MIDI_BUF]; + Bitu used,done; + Bit32u last; + } midi; + struct { + Bitu rowlen; + } image; +#if (C_SSHOT) + struct { + FILE *handle; + Bitu frames; + Bit16s audiobuf[WAVE_BUF][2]; + Bitu audioused; + Bitu audiorate; + Bitu audiowritten; + VideoCodec *codec; + Bitu width, height, bpp; + Bitu written; + float fps; + int bufSize; + void *buf; + Bit8u *index; + Bitu indexsize, indexused; + } video; +#endif +} capture; FILE * OpenCaptureFile(const char * type,const char * ext) { Bitu last=0; @@ -42,6 +93,7 @@ FILE * OpenCaptureFile(const char * type,const char * ext) { return 0; } strcpy(file_start,RunningProgram); + lowcase(file_start); strcat(file_start,"_"); while ((dir_ent=readdir(dir))) { char tempname[CROSS_LEN]; @@ -55,7 +107,6 @@ FILE * OpenCaptureFile(const char * type,const char * ext) { } closedir(dir); sprintf(file_name,"%s%c%s%03d%s",capturedir,CROSS_FILESPLIT,file_start,last,ext); - lowcase(file_name); /* Open the actual file */ FILE * handle=fopen(file_name,"wb"); if (handle) { @@ -66,9 +117,628 @@ FILE * OpenCaptureFile(const char * type,const char * ext) { return handle; } +#if (C_SSHOT) +static void CAPTURE_AddAviChunk(const char * tag, Bit32u size, void * data, Bit32u flags) { + Bit8u chunk[8];Bit8u *index;Bit32u pos, writesize; -void HARDWARE_Init(Section * sec) { - Section_prop * section=static_cast(sec); - capturedir=(char *)section->Get_string("captures"); + chunk[0] = tag[0];chunk[1] = tag[1];chunk[2] = tag[2];chunk[3] = tag[3]; + host_writed(&chunk[4], size); + /* Write the actual data */ + fwrite(chunk,1,8,capture.video.handle); + writesize = (size+1)&~1; + fwrite(data,1,writesize,capture.video.handle); + pos = capture.video.written + 4; + capture.video.written += writesize + 8; + if (capture.video.indexused + 16 >= capture.video.indexsize ) { + capture.video.index = (Bit8u*)realloc( capture.video.index, capture.video.indexsize + 16 * 4096); + if (!capture.video.index) + E_Exit("Ran out of memory during AVI capturing"); + capture.video.indexsize += 16*4096; + } + index = capture.video.index+capture.video.indexused; + capture.video.indexused += 16; + index[0] = tag[0]; + index[1] = tag[1]; + index[2] = tag[2]; + index[3] = tag[3]; + host_writed(index+4, flags); + host_writed(index+8, pos); + host_writed(index+12, size); +} +#endif + +static void CAPTURE_VideoEvent(bool pressed) { + if (!pressed) + return; +#if (C_SSHOT) + if (CaptureState & CAPTURE_VIDEO) { + /* Close the video */ + CaptureState &= ~CAPTURE_VIDEO; + LOG_MSG("Stopped capturing video."); + + Bit8u avi_header[AVI_HEADER_SIZE]; + Bitu main_list; + Bitu header_pos=0; +#define AVIOUT4(_S_) memcpy(&avi_header[header_pos],_S_,4);header_pos+=4; +#define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2; +#define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4; + /* Try and write an avi header */ + AVIOUT4("RIFF"); // Riff header + AVIOUTd(AVI_HEADER_SIZE + capture.video.written - 8 + capture.video.indexused); + AVIOUT4("AVI "); + AVIOUT4("LIST"); // List header + main_list = header_pos; + AVIOUTd(0); // TODO size of list + AVIOUT4("hdrl"); + + AVIOUT4("avih"); + AVIOUTd(56); /* # of bytes to follow */ + AVIOUTd((Bit32u)(1000000 / capture.video.fps)); /* Microseconds per frame */ + AVIOUTd(0); + AVIOUTd(0); /* PaddingGranularity (whatever that might be) */ + AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */ + AVIOUTd(capture.video.frames); /* TotalFrames */ + AVIOUTd(0); /* InitialFrames */ + AVIOUTd(2); /* Stream count */ + AVIOUTd(0); /* SuggestedBufferSize */ + AVIOUTd(capture.video.width); /* Width */ + AVIOUTd(capture.video.height); /* Height */ + AVIOUTd(0); /* TimeScale: Unit used to measure time */ + AVIOUTd(0); /* DataRate: Data rate of playback */ + AVIOUTd(0); /* StartTime: Starting time of AVI data */ + AVIOUTd(0); /* DataLength: Size of AVI data chunk */ + + /* Video stream list */ + AVIOUT4("LIST"); + AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */ + AVIOUT4("strl"); + /* video stream header */ + AVIOUT4("strh"); + AVIOUTd(56); /* # of bytes to follow */ + AVIOUT4("vids"); /* Type */ + AVIOUT4(CODEC_4CC); /* Handler */ + AVIOUTd(0); /* Flags */ + AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ + AVIOUTd(0); /* InitialFrames */ + AVIOUTd(1000000); /* Scale */ + AVIOUTd((Bit32u)(1000000 * capture.video.fps)); /* Rate: Rate/Scale == samples/second */ + AVIOUTd(0); /* Start */ + AVIOUTd(capture.video.frames); /* Length */ + AVIOUTd(0); /* SuggestedBufferSize */ + AVIOUTd(~0); /* Quality */ + AVIOUTd(0); /* SampleSize */ + AVIOUTd(0); /* Frame */ + AVIOUTd(0); /* Frame */ + /* The video stream format */ + AVIOUT4("strf"); + AVIOUTd(40); /* # of bytes to follow */ + AVIOUTd(40); /* Size */ + AVIOUTd(capture.video.width); /* Width */ + AVIOUTd(capture.video.height); /* Height */ +// OUTSHRT(1); OUTSHRT(24); /* Planes, Count */ + AVIOUTd(0); + AVIOUT4(CODEC_4CC); /* Compression */ + AVIOUTd(capture.video.width * capture.video.height*4); /* SizeImage (in bytes?) */ + AVIOUTd(0); /* XPelsPerMeter */ + AVIOUTd(0); /* YPelsPerMeter */ + AVIOUTd(0); /* ClrUsed: Number of colors used */ + AVIOUTd(0); /* ClrImportant: Number of colors important */ + + /* Audio stream list */ + AVIOUT4("LIST"); + AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */ + AVIOUT4("strl"); + /* The audio stream header */ + AVIOUT4("strh"); + AVIOUTd(56); /* # of bytes to follow */ + AVIOUT4("auds"); + AVIOUTd(0); /* Format (Optionally) */ + AVIOUTd(0); /* Flags */ + AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */ + AVIOUTd(0); /* InitialFrames */ + AVIOUTd(4); /* Scale */ + AVIOUTd(capture.video.audiorate*4); /* Rate, actual rate is scale/rate */ + AVIOUTd(0); /* Start */ + if (!capture.video.audiorate) + capture.video.audiorate = 1; + AVIOUTd(capture.video.audiowritten/4); /* Length */ + AVIOUTd(0); /* SuggestedBufferSize */ + AVIOUTd(~0); /* Quality */ + AVIOUTd(4); /* SampleSize */ + AVIOUTd(0); /* Frame */ + AVIOUTd(0); /* Frame */ + /* The audio stream format */ + AVIOUT4("strf"); + AVIOUTd(16); /* # of bytes to follow */ + AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */ + AVIOUTw(2); /* Number of channels */ + AVIOUTd(capture.video.audiorate); /* SamplesPerSec */ + AVIOUTd(capture.video.audiorate*4); /* AvgBytesPerSec*/ + AVIOUTw(4); /* BlockAlign */ + AVIOUTw(16); /* BitsPerSample */ + int nmain = header_pos - main_list - 4; + /* Finish stream list, i.e. put number of bytes in the list to proper pos */ + + int njunk = AVI_HEADER_SIZE - 8 - 12 - header_pos; + AVIOUT4("JUNK"); + AVIOUTd(njunk); + /* Fix the size of the main list */ + header_pos = main_list; + AVIOUTd(nmain); + header_pos = AVI_HEADER_SIZE - 12; + AVIOUT4("LIST"); + AVIOUTd(capture.video.written+4); /* Length of list in bytes */ + AVIOUT4("movi"); + /* First add the index table to the end */ + memcpy(capture.video.index, "idx1", 4); + host_writed( capture.video.index+4, capture.video.indexused - 8 ); + fwrite( capture.video.index, 1, capture.video.indexused, capture.video.handle); + fseek(capture.video.handle, 0, SEEK_SET); + fwrite(&avi_header, 1, AVI_HEADER_SIZE, capture.video.handle); + fclose( capture.video.handle ); + free( capture.video.index ); + free( capture.video.buf ); + delete capture.video.codec; + capture.video.handle = 0; + } else { + CaptureState |= CAPTURE_VIDEO; + } +#endif } +void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, float fps, Bit8u * data, Bit8u * pal) { + Bitu i; +#if (C_SSHOT) + Bit8u doubleRow[SCALER_MAXWIDTH*4]; + Bitu countWidth = width; + + if (flags & CAPTURE_FLAG_DBLH) + height *= 2; + if (flags & CAPTURE_FLAG_DBLW) + width *= 2; + + if (height > SCALER_MAXHEIGHT) + return; + if (width > SCALER_MAXWIDTH) + return; + + if (CaptureState & CAPTURE_IMAGE) { + png_structp png_ptr; + png_infop info_ptr; + png_color palette[256]; + + CaptureState &= ~CAPTURE_IMAGE; + /* Open the actual file */ + FILE * fp=OpenCaptureFile("Screenshot",".png"); + if (!fp) goto skip_shot; + /* First try to alloacte the png structures */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,NULL, NULL); + if (!png_ptr) goto skip_shot; + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + png_destroy_write_struct(&png_ptr,(png_infopp)NULL); + goto skip_shot; + } + + /* Finalize the initing of png library */ + png_init_io(png_ptr, fp); + png_set_compression_level(png_ptr,Z_BEST_COMPRESSION); + + /* set other zlib parameters */ + png_set_compression_mem_level(png_ptr, 8); + png_set_compression_strategy(png_ptr,Z_DEFAULT_STRATEGY); + png_set_compression_window_bits(png_ptr, 15); + png_set_compression_method(png_ptr, 8); + png_set_compression_buffer_size(png_ptr, 8192); + + if (bpp==8) { + png_set_IHDR(png_ptr, info_ptr, width, height, + 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + for (i=0;i<256;i++) { + palette[i].red=pal[i*4+0]; + palette[i].green=pal[i*4+1]; + palette[i].blue=pal[i*4+2]; + } + png_set_PLTE(png_ptr, info_ptr, palette,256); + } else { + png_set_bgr( png_ptr ); + png_set_IHDR(png_ptr, info_ptr, width, height, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + } + png_write_info(png_ptr, info_ptr); + for (i=0;i> 1)*pitch); + else + srcLine=(data+(i >> 0)*pitch); + rowPointer=srcLine; + switch (bpp) { + case 8: + if (flags & CAPTURE_FLAG_DBLW) { + for (Bitu x=0;x> 2; + doubleRow[x*6+1] = doubleRow[x*6+4] = ((pixel& 0x03e0) * 0x21) >> 7; + doubleRow[x*6+2] = doubleRow[x*6+5] = ((pixel& 0x7c00) * 0x21) >> 12; + } + } else { + for (Bitu x=0;x> 2; + doubleRow[x*3+1] = ((pixel& 0x03e0) * 0x21) >> 7; + doubleRow[x*3+2] = ((pixel& 0x7c00) * 0x21) >> 12; + } + } + rowPointer = doubleRow; + break; + case 16: + if (flags & CAPTURE_FLAG_DBLW) { + for (Bitu x=0;x> 2; + doubleRow[x*6+1] = doubleRow[x*6+4] = ((pixel& 0x07e0) * 0x41) >> 9; + doubleRow[x*6+2] = doubleRow[x*6+5] = ((pixel& 0xf800) * 0x21) >> 13; + } + } else { + for (Bitu x=0;x> 2; + doubleRow[x*3+1] = ((pixel& 0x07e0) * 0x41) >> 9; + doubleRow[x*3+2] = ((pixel& 0xf800) * 0x21) >> 13; + } + } + rowPointer = doubleRow; + break; + case 32: + if (flags & CAPTURE_FLAG_DBLW) { + for (Bitu x=0;xSetupCompress( width, height)) + goto skip_video; + capture.video.bufSize = capture.video.codec->NeededSize(width, height, format); + capture.video.buf = malloc( capture.video.bufSize ); + if (!capture.video.buf) + goto skip_video; + capture.video.index = (Bit8u*)malloc( 16*4096 ); + if (!capture.video.buf) + goto skip_video; + capture.video.indexsize = 16*4096; + capture.video.indexused = 8; + + capture.video.width = width; + capture.video.height = height; + capture.video.bpp = bpp; + capture.video.fps = fps; + for (i=0;iPrepareCompressFrame( codecFlags, format, (char *)pal, capture.video.buf, capture.video.bufSize)) + goto skip_video; + + for (i=0;i> 1; + if (flags & CAPTURE_FLAG_DBLH) + srcLine=(data+(i >> 1)*pitch); + else + srcLine=(data+(i >> 0)*pitch); + switch ( bpp) { + case 8: + for (x=0;x> 1)*pitch); + else + rowPointer=(data+(i >> 0)*pitch); + } + capture.video.codec->CompressLines( 1, &rowPointer ); + } + int written = capture.video.codec->FinishCompressFrame(); + if (written < 0) + goto skip_video; + CAPTURE_AddAviChunk( "00dc", written, capture.video.buf, codecFlags & 1 ? 0x10 : 0x0); + capture.video.frames++; +// LOG_MSG("Frame %d video %d audio %d",capture.video.frames, written, capture.video.audioused *4 ); + if ( capture.video.audioused ) { + CAPTURE_AddAviChunk( "01wb", capture.video.audioused * 4, capture.video.audiobuf, 0); + capture.video.audiowritten = capture.video.audioused*4; + capture.video.audioused = 0; + } + + /* Everything went okay, set flag again for next frame */ + CaptureState |= CAPTURE_VIDEO; + } +skip_video: +#endif + return; +} + + +static void CAPTURE_ScreenShotEvent(bool pressed) { + if (!pressed) + return; + CaptureState |= CAPTURE_IMAGE; +} + + +/* WAV capturing */ +static Bit8u wavheader[]={ + 'R','I','F','F', 0x0,0x0,0x0,0x0, /* Bit32u Riff Chunk ID / Bit32u riff size */ + 'W','A','V','E', 'f','m','t',' ', /* Bit32u Riff Format / Bit32u fmt chunk id */ + 0x10,0x0,0x0,0x0, 0x1,0x0,0x2,0x0, /* Bit32u fmt size / Bit16u encoding/ Bit16u channels */ + 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, /* Bit32u freq / Bit32u byterate */ + 0x4,0x0,0x10,0x0, 'd','a','t','a', /* Bit16u byte-block / Bit16u bits / Bit16u data chunk id */ + 0x0,0x0,0x0,0x0, /* Bit32u data size */ +}; + +void CAPTURE_AddWave(Bit32u freq, Bit32u len, Bit16s * data) { +#if (C_SSHOT) + if (CaptureState & CAPTURE_VIDEO) { + Bitu left = WAVE_BUF - capture.video.audioused; + if (left > len) + left = len; + memcpy( &capture.video.audiobuf[capture.video.audioused], data, left*4); + capture.video.audioused += left; + capture.video.audiorate = freq; + } +#endif + if (CaptureState & CAPTURE_WAVE) { + if (!capture.wave.handle) { + capture.wave.handle=OpenCaptureFile("Wave Output",".wav"); + if (!capture.wave.handle) { + CaptureState &= ~CAPTURE_WAVE; + return; + } + capture.wave.length = 0; + capture.wave.used = 0; + capture.wave.freq = freq; + fwrite(wavheader,1,sizeof(wavheader),capture.wave.handle); + } + Bit16s * read = data; + while (len > 0 ) { + Bitu left = WAVE_BUF - capture.wave.used; + if (!left) { + fwrite(capture.wave.buf,1,4*WAVE_BUF,capture.wave.handle); + capture.wave.length += 4*WAVE_BUF; + capture.wave.used = 0; + left = WAVE_BUF; + } + if (left > len) + left = len; + memcpy( &capture.wave.buf[capture.wave.used], read, left*4); + capture.wave.used += left; + read += left*2; + len -= left; + } + } +} +static void CAPTURE_WaveEvent(bool pressed) { + if (!pressed) + return; + /* Check for previously opened wave file */ + if (capture.wave.handle) { + LOG_MSG("Stopped capturing wave output."); + /* Write last piece of audio in buffer */ + fwrite(capture.wave.buf,1,capture.wave.used*4,capture.wave.handle); + capture.wave.length+=capture.wave.used*4; + /* Fill in the header with useful information */ + host_writed(&wavheader[0x04],capture.wave.length+sizeof(wavheader)-8); + host_writed(&wavheader[0x18],capture.wave.freq); + host_writed(&wavheader[0x1C],capture.wave.freq*4); + host_writed(&wavheader[0x28],capture.wave.length); + + fseek(capture.wave.handle,0,0); + fwrite(wavheader,1,sizeof(wavheader),capture.wave.handle); + fclose(capture.wave.handle); + capture.wave.handle=0; + CaptureState |= CAPTURE_WAVE; + } + CaptureState ^= CAPTURE_WAVE; +} + +/* MIDI capturing */ + +static Bit8u midi_header[]={ + 'M','T','h','d', /* Bit32u, Header Chunk */ + 0x0,0x0,0x0,0x6, /* Bit32u, Chunk Length */ + 0x0,0x0, /* Bit16u, Format, 0=single track */ + 0x0,0x1, /* Bit16u, Track Count, 1 track */ + 0x01,0xf4, /* Bit16u, Timing, 2 beats/second with 500 frames */ + 'M','T','r','k', /* Bit32u, Track Chunk */ + 0x0,0x0,0x0,0x0, /* Bit32u, Chunk Length */ + //Track data +}; + + +static void RawMidiAdd(Bit8u data) { + capture.midi.buffer[capture.midi.used++]=data; + if (capture.midi.used >= MIDI_BUF ) { + capture.midi.done += capture.midi.used; + fwrite(capture.midi.buffer,1,MIDI_BUF,capture.midi.handle); + capture.midi.used = 0; + } +} + +static void RawMidiAddNumber(Bit32u val) { + if (val & 0xfe00000) RawMidiAdd((Bit8u)(0x80|((val >> 21) & 0x7f))); + if (val & 0xfffc000) RawMidiAdd((Bit8u)(0x80|((val >> 14) & 0x7f))); + if (val & 0xfffff80) RawMidiAdd((Bit8u)(0x80|((val >> 7) & 0x7f))); + RawMidiAdd((Bit8u)(val & 0x7f)); +} + +void CAPTURE_AddMidi(bool sysex, Bitu len, Bit8u * data) { + if (!capture.midi.handle) { + capture.midi.handle=OpenCaptureFile("Raw Midi",".mid"); + if (!capture.midi.handle) { + return; + } + fwrite(midi_header,1,sizeof(midi_header),capture.midi.handle); + capture.midi.last=PIC_Ticks; + } + Bit32u delta=PIC_Ticks-capture.midi.last; + capture.midi.last=PIC_Ticks; + RawMidiAddNumber(delta); + if (sysex) { + RawMidiAdd( 0xf0 ); + RawMidiAddNumber( len ); + } + for (Bitu i=0;i> 24); + size[1]=(Bit8u)(capture.midi.done >> 16); + size[2]=(Bit8u)(capture.midi.done >> 8); + size[3]=(Bit8u)(capture.midi.done >> 0); + fwrite(&size,1,4,capture.midi.handle); + fclose(capture.midi.handle); + capture.midi.handle=0; + CaptureState &= ~CAPTURE_MIDI; + return; + } + CaptureState ^= CAPTURE_MIDI; + if (CaptureState & CAPTURE_MIDI) { + LOG_MSG("Preparing for raw midi capture, will start with first data."); + capture.midi.used=0; + capture.midi.done=0; + capture.midi.handle=0; + } else { + LOG_MSG("Stopped capturing raw midi before any data arrived."); + } +} + +class HARDWARE:public Module_base{ +public: + HARDWARE(Section* configuration):Module_base(configuration){ + Section_prop * section = static_cast(configuration); + capturedir = (char *)section->Get_string("captures"); + CaptureState = 0; + MAPPER_AddHandler(CAPTURE_WaveEvent,MK_f6,MMOD1,"recwave","Rec Wave"); + MAPPER_AddHandler(CAPTURE_MidiEvent,MK_f8,MMOD1|MMOD2,"caprawmidi","Cap MIDI"); +#if (C_SSHOT) + MAPPER_AddHandler(CAPTURE_ScreenShotEvent,MK_f5,MMOD1,"scrshot","Screenshot"); + MAPPER_AddHandler(CAPTURE_VideoEvent,MK_f5,MMOD1|MMOD2,"video","Video"); +#endif + } + ~HARDWARE(){ + if (capture.wave.handle) CAPTURE_WaveEvent(true); + if (capture.midi.handle) CAPTURE_MidiEvent(true); + } +}; + +static HARDWARE* test; + +void HARDWARE_Destroy(Section * sec) { + delete test; +} + +void HARDWARE_Init(Section * sec) { + test = new HARDWARE(sec); + sec->AddDestroyFunction(&HARDWARE_Destroy,true); +} diff --git a/src/hardware/iohandler.cpp b/src/hardware/iohandler.cpp index 904af71..0c0a5d3 100644 --- a/src/hardware/iohandler.cpp +++ b/src/hardware/iohandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,14 +16,21 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: iohandler.cpp,v 1.20 2006/02/09 11:47:49 qbix79 Exp $ */ + +#include #include "dosbox.h" #include "inout.h" +#include "setup.h" +#include "cpu.h" +#include "../src/cpu/lazyflags.h" +#include "callback.h" IO_WriteHandler * io_writehandlers[3][IO_MAX]; IO_ReadHandler * io_readhandlers[3][IO_MAX]; static Bitu IO_ReadBlocked(Bitu port,Bitu iolen) { - return (Bitu)-1; + return ~0; } static void IO_WriteBlocked(Bitu port,Bitu val,Bitu iolen) { } @@ -98,11 +105,283 @@ void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range) { } } - -void IO_Init(Section * sect) { - IO_FreeReadHandler(0,IO_MA,IO_MAX); - IO_FreeWriteHandler(0,IO_MA,IO_MAX); +void IO_ReadHandleObject::Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range) { + if(!installed) { + installed=true; + m_port=port; + m_mask=mask; + m_range=range; + IO_RegisterReadHandler(port,handler,mask,range); + } else E_Exit("IO_readHandler allready installed port %x",port); } +IO_ReadHandleObject::~IO_ReadHandleObject(){ + if(!installed) return; + IO_FreeReadHandler(m_port,m_mask,m_range); +} +void IO_WriteHandleObject::Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range) { + if(!installed) { + installed=true; + m_port=port; + m_mask=mask; + m_range=range; + IO_RegisterWriteHandler(port,handler,mask,range); + } else E_Exit("IO_writeHandler allready installed port %x",port); +} +IO_WriteHandleObject::~IO_WriteHandleObject(){ + if(!installed) return; + IO_FreeWriteHandler(m_port,m_mask,m_range); + //LOG_MSG("FreeWritehandler called with port %X",m_port); +} + +struct IOF_Entry { + Bitu cs; + Bitu eip; +}; + +#define IOF_QUEUESIZE 16 +static struct { + Bitu used; + IOF_Entry entries[IOF_QUEUESIZE]; +} iof_queue; + +static Bits IOFaultCore(void) { + CPU_CycleLeft+=CPU_Cycles; + CPU_Cycles=1; + Bitu ret=CPU_Core_Full_Run(); + CPU_CycleLeft+=CPU_Cycles; + if (ret<0) E_Exit("Got a dosbox close machine in IO-fault core?"); + if (ret) + return ret; + if (!iof_queue.used) E_Exit("IO-faul Core without IO-faul"); + IOF_Entry * entry=&iof_queue.entries[iof_queue.used-1]; + if (entry->cs == SegValue(cs) && entry->eip==reg_eip) + return -1; + return 0; +} + +Bitu DEBUG_EnableDebugger(); + +void IO_WriteB(Bitu port,Bitu val) { + if (GETFLAG(VM) && (CPU_IO_Exception(port,1))) { + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&IOFaultCore; + IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; + entry->cs=SegValue(cs); + entry->eip=reg_eip; + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + Bit8u old_al = reg_al; + Bit16u old_dx = reg_dx; + reg_al = val; + reg_dx = port; + RealPt icb = CALLBACK_RealPointer(call_priv_io); + SegSet16(cs,RealSeg(icb)); + reg_eip = RealOff(icb)+0x08; + FillFlags(); + CPU_Exception(cpu.exception.which,cpu.exception.error); + + DOSBOX_RunMachine(); + iof_queue.used--; + + reg_al = old_al; + reg_dx = old_dx; + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; + } + else io_writehandlers[0][port](port,val,1); +}; + +void IO_WriteW(Bitu port,Bitu val) { + if (GETFLAG(VM) && (CPU_IO_Exception(port,2))) { + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&IOFaultCore; + IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; + entry->cs=SegValue(cs); + entry->eip=reg_eip; + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + Bit16u old_ax = reg_ax; + Bit16u old_dx = reg_dx; + reg_al = val; + reg_dx = port; + RealPt icb = CALLBACK_RealPointer(call_priv_io); + SegSet16(cs,RealSeg(icb)); + reg_eip = RealOff(icb)+0x0a; + FillFlags(); + CPU_Exception(cpu.exception.which,cpu.exception.error); + + DOSBOX_RunMachine(); + iof_queue.used--; + + reg_ax = old_ax; + reg_dx = old_dx; + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; + } + else io_writehandlers[1][port](port,val,2); +}; + +void IO_WriteD(Bitu port,Bitu val) { + if (GETFLAG(VM) && (CPU_IO_Exception(port,4))) { + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&IOFaultCore; + IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; + entry->cs=SegValue(cs); + entry->eip=reg_eip; + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + Bit32u old_eax = reg_eax; + Bit16u old_dx = reg_dx; + reg_al = val; + reg_dx = port; + RealPt icb = CALLBACK_RealPointer(call_priv_io); + SegSet16(cs,RealSeg(icb)); + reg_eip = RealOff(icb)+0x0c; + FillFlags(); + CPU_Exception(cpu.exception.which,cpu.exception.error); + + DOSBOX_RunMachine(); + iof_queue.used--; + + reg_eax = old_eax; + reg_dx = old_dx; + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; + } + else io_writehandlers[2][port](port,val,4); +}; + +Bitu IO_ReadB(Bitu port) { + if (GETFLAG(VM) && (CPU_IO_Exception(port,1))) { + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&IOFaultCore; + IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; + entry->cs=SegValue(cs); + entry->eip=reg_eip; + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + Bit16u old_dx = reg_dx; + reg_dx = port; + RealPt icb = CALLBACK_RealPointer(call_priv_io); + SegSet16(cs,RealSeg(icb)); + reg_eip = RealOff(icb)+0x00; + FillFlags(); + CPU_Exception(cpu.exception.which,cpu.exception.error); + + DOSBOX_RunMachine(); + iof_queue.used--; + + Bitu retval = reg_al; + + reg_dx = old_dx; + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; + return retval; + } + else return io_readhandlers[0][port](port,1); +}; + +Bitu IO_ReadW(Bitu port) { + if (GETFLAG(VM) && (CPU_IO_Exception(port,2))) { + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&IOFaultCore; + IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; + entry->cs=SegValue(cs); + entry->eip=reg_eip; + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + Bit16u old_dx = reg_dx; + reg_dx = port; + RealPt icb = CALLBACK_RealPointer(call_priv_io); + SegSet16(cs,RealSeg(icb)); + reg_eip = RealOff(icb)+0x02; + FillFlags(); + CPU_Exception(cpu.exception.which,cpu.exception.error); + + DOSBOX_RunMachine(); + iof_queue.used--; + + Bitu retval = reg_ax; + + reg_dx = old_dx; + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; + return retval; + } + else return io_readhandlers[1][port](port,2); +}; + +Bitu IO_ReadD(Bitu port) { + if (GETFLAG(VM) && (CPU_IO_Exception(port,4))) { + LazyFlags old_lflags; + memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); + CPU_Decoder * old_cpudecoder; + old_cpudecoder=cpudecoder; + cpudecoder=&IOFaultCore; + IOF_Entry * entry=&iof_queue.entries[iof_queue.used++]; + entry->cs=SegValue(cs); + entry->eip=reg_eip; + CPU_Push16(SegValue(cs)); + CPU_Push16(reg_ip); + Bit16u old_dx = reg_dx; + reg_dx = port; + RealPt icb = CALLBACK_RealPointer(call_priv_io); + SegSet16(cs,RealSeg(icb)); + reg_eip = RealOff(icb)+0x04; + FillFlags(); + CPU_Exception(cpu.exception.which,cpu.exception.error); + + DOSBOX_RunMachine(); + iof_queue.used--; + + Bitu retval = reg_eax; + + reg_dx = old_dx; + memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); + cpudecoder=old_cpudecoder; + return retval; + } + else return io_readhandlers[2][port](port,4); +}; + +class IO :public Module_base { +public: + IO(Section* configuration):Module_base(configuration){ + iof_queue.used=0; + IO_FreeReadHandler(0,IO_MA,IO_MAX); + IO_FreeWriteHandler(0,IO_MA,IO_MAX); + } + ~IO() + { + //Same as the constructor ? + } +}; + +static IO* test; + +void IO_Destroy(Section* sec) { + delete test; +} + +void IO_Init(Section * sect) { + test = new IO(sect); + sect->AddDestroyFunction(&IO_Destroy); +} diff --git a/src/hardware/ipx.cpp b/src/hardware/ipx.cpp index a60ac38..1cc3ae2 100644 --- a/src/hardware/ipx.cpp +++ b/src/hardware/ipx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: ipx.cpp,v 1.10 2006/02/26 13:46:31 qbix79 Exp $ */ + #include "dosbox.h" #if C_IPX @@ -26,7 +28,6 @@ #include "cross.h" #include "support.h" #include "cpu.h" -#include "SDL_net.h" #include "regs.h" #include "inout.h" #include "setup.h" @@ -39,46 +40,33 @@ #include "timer.h" #include "SDL_net.h" #include "programs.h" +#include "pic.h" #define SOCKTABLESIZE 150 // DOS IPX driver was limited to 150 open sockets -#define DOS_MEMSEG 0xd000; - -Bit32u tcpPort; -bool isIpxServer; -bool isIpxConnected; -IPaddress ipxClientIp; // IPAddress for client connection to server -IPaddress ipxServConnIp; // IPAddress for client connection to server -TCPsocket ipxTCPClientSocket; -UDPsocket ipxClientSocket; -int UDPChannel; // Channel used by UDP connection -Bit8u recvBuffer[IPXBUFFERSIZE]; // Incoming packet buffer -Bitu call_ipx; // Callback of RETF entrypoint -Bitu call_ipxint; // Callback of INT 7A entrypoint -Bitu call_ipxesr1; // Callback of ESR init routine -Bitu call_ipxesr2; // Callback of ESR return routine -Bit16u dospage; -static RealPt ipx_callback; -static RealPt ipx_intcallback; -static RealPt ipx_esrcallback; -static RealPt ipx_esrptraddr; -static RealPt processedECB; - -SDLNet_SocketSet clientSocketSet; -static bool inESR; struct ipxnetaddr { Uint8 netnum[4]; // Both are big endian Uint8 netnode[6]; } localIpxAddr; -struct fragmentDescriptor { - Bit16u offset; - Bit16u segment; - Bit16u size; -}; +Bit32u tcpPort; +bool isIpxServer; +bool isIpxConnected; +IPaddress ipxClientIp; // IPAddress for client connection to server +IPaddress ipxServConnIp; // IPAddress for client connection to server +UDPsocket ipxClientSocket; +int UDPChannel; // Channel used by UDP connection +Bit8u recvBuffer[IPXBUFFERSIZE]; // Incoming packet buffer + +static RealPt ipx_callback; + +SDLNet_SocketSet clientSocketSet; packetBuffer incomingPacket; +static Bit16u socketCount; +static Bit16u opensockets[SOCKTABLESIZE]; + static Bit16u swapByte(Bit16u sockNum) { return (((sockNum>> 8)) | (sockNum << 8)); } @@ -93,113 +81,156 @@ void PackIP(IPaddress ipAddr, PackedIP *ipPack) { ipPack->port = ipAddr.port; } -class ECBClass { -public: - RealPt ECBAddr; - - ECBClass *prevECB; - ECBClass *nextECB; - - Bit16u getSocket(void) { - return swapByte(real_readw(RealSeg(ECBAddr), RealOff(ECBAddr) + 0xa)); - } - - Bit8u getInUseFlag(void) { - return real_readb(RealSeg(ECBAddr), RealOff(ECBAddr) + 0x8); - } - - void setInUseFlag(Bit8u flagval) { - real_writeb(RealSeg(ECBAddr), RealOff(ECBAddr) + 0x8, flagval); - } - - void setCompletionFlag(Bit8u flagval) { - real_writeb(RealSeg(ECBAddr), RealOff(ECBAddr) + 0x9, flagval); - } - - Bit16u getFragCount(void) { - return real_readw(RealSeg(ECBAddr), RealOff(ECBAddr) + 34); - } - - void getFragDesc(Bit16u descNum, fragmentDescriptor *fragDesc) { - Bit16u memoff = RealOff(ECBAddr) + 30 + ((descNum+1) * 6); - fragDesc->offset = real_readw(RealSeg(ECBAddr), memoff); - memoff+=2; - fragDesc->segment = real_readw(RealSeg(ECBAddr), memoff); - memoff+=2; - fragDesc->size = real_readw(RealSeg(ECBAddr), memoff); - } - - RealPt getESRAddr(void) { - return RealMake(real_readw(RealSeg(ECBAddr), RealOff(ECBAddr)+6), real_readw(RealSeg(ECBAddr), RealOff(ECBAddr)+4)); - } - - void NotifyESR(void) { - RealPt tmpAddr = getESRAddr(); - if(tmpAddr == 0) return; - if(!inESR) { - //LOG_MSG("Calling ESR"); - processedECB = ECBAddr; - inESR = true; - //LOG_MSG("Write %x to %x", real_readd(RealSeg(ECBAddr), RealOff(ECBAddr)+4), RealMake(RealSeg(ipx_esrptraddr), RealOff(ipx_esrptraddr))); - real_writed(RealSeg(ipx_esrptraddr), RealOff(ipx_esrptraddr),real_readd(RealSeg(ECBAddr), RealOff(ECBAddr)+4)); - CPU_CALL(false, RealSeg(ipx_esrcallback), RealOff(ipx_esrcallback),0); - } - } - - void setImmAddress(Bit8u *immAddr) { - Bits i; - for(i=0;i<6;i++) { - real_writeb(RealSeg(ECBAddr), RealOff(ECBAddr)+28, immAddr[i]); - } - } - -}; - ECBClass *ECBList; // Linked list of ECB's +ECBClass* ESRList; // ECBs waiting to be ESR notified -ECBClass * CreateECB(RealPt useAddr) { - ECBClass *tmpECB; - tmpECB = new ECBClass(); +#ifdef IPX_DEBUGMSG +Bitu ECBSerialNumber = 0; +Bitu ECBAmount = 0; +#endif + + +ECBClass::ECBClass(Bit16u segment, Bit16u offset) { + ECBAddr = RealMake(segment, offset); - tmpECB->ECBAddr = useAddr; - tmpECB->prevECB = NULL; - tmpECB->nextECB = NULL; +#ifdef IPX_DEBUGMSG + SerialNumber = ECBSerialNumber; + ECBSerialNumber++; + ECBAmount++; + + LOG_MSG("ECB: SN%7d created. Number of ECBs: %3d, ESR %4x:%4x, ECB %4x:%4x", + SerialNumber,ECBAmount, + real_readw(RealSeg(ECBAddr), + RealOff(ECBAddr)+6), + real_readw(RealSeg(ECBAddr), + RealOff(ECBAddr)+4),segment,offset); +#endif + isInESRList = false; + prevECB = NULL; + nextECB = NULL; - if (ECBList == NULL) { - ECBList = tmpECB; - } else { + if (ECBList == NULL) + ECBList = this; + else { // Transverse the list until we hit the end - ECBClass *useECB; - useECB = ECBList; - while(useECB->nextECB != NULL) { + ECBClass *useECB = ECBList; + + while(useECB->nextECB != NULL) useECB = useECB->nextECB; + + useECB->nextECB = this; + this->prevECB = useECB; + } +} + +Bit16u ECBClass::getSocket(void) { + return swapByte(real_readw(RealSeg(ECBAddr), RealOff(ECBAddr) + 0xa)); +} + +Bit8u ECBClass::getInUseFlag(void) { + return real_readb(RealSeg(ECBAddr), RealOff(ECBAddr) + 0x8); +} + +void ECBClass::setInUseFlag(Bit8u flagval) { + iuflag = flagval; + real_writeb(RealSeg(ECBAddr), RealOff(ECBAddr) + 0x8, flagval); +} + +void ECBClass::setCompletionFlag(Bit8u flagval) { + real_writeb(RealSeg(ECBAddr), RealOff(ECBAddr) + 0x9, flagval); +} + +Bit16u ECBClass::getFragCount(void) { + return real_readw(RealSeg(ECBAddr), RealOff(ECBAddr) + 34); +} + +void ECBClass::getFragDesc(Bit16u descNum, fragmentDescriptor *fragDesc) { + Bit16u memoff = RealOff(ECBAddr) + 30 + ((descNum+1) * 6); + fragDesc->offset = real_readw(RealSeg(ECBAddr), memoff); + memoff += 2; + fragDesc->segment = real_readw(RealSeg(ECBAddr), memoff); + memoff += 2; + fragDesc->size = real_readw(RealSeg(ECBAddr), memoff); +} + +RealPt ECBClass::getESRAddr(void) { + return RealMake(real_readw(RealSeg(ECBAddr), + RealOff(ECBAddr)+6), + real_readw(RealSeg(ECBAddr), + RealOff(ECBAddr)+4)); +} + +void ECBClass::NotifyESR(void) { + Bit32u ESRval = real_readd(RealSeg(ECBAddr), RealOff(ECBAddr)+4); + if(ESRval) { +#ifdef IPX_DEBUGMSG + LOG_MSG("ECB: SN%7d to be notified.", SerialNumber); +#endif + // take the ECB out of the current list + if(prevECB == NULL) { // was the first in the list + ECBList = nextECB; + if(ECBList != NULL) ECBList->prevECB = NULL; + } else { // not the first + prevECB->nextECB = nextECB; + if(nextECB != NULL) nextECB->prevECB = prevECB; } - useECB->nextECB = tmpECB; - tmpECB->prevECB = useECB; - } - return tmpECB; + nextECB = NULL; + // put it to the notification queue + if(ESRList==NULL) { + ESRList = this; + prevECB = NULL; + } else {// put to end of ESR list + ECBClass* useECB = ESRList; + + while(useECB->nextECB != NULL) + useECB = useECB->nextECB; + + useECB->nextECB = this; + prevECB = useECB; + } + isInESRList = true; + //LOG_MSG("ECB put to notification list"); + PIC_ActivateIRQ(11); + } + // this one does not want to be notified, delete it right away + else delete this; } -void DeleteECB(ECBClass * useECB) { - if(useECB == NULL) return; +void ECBClass::setImmAddress(Bit8u *immAddr) { + for(Bitu i=0;i<6;i++) + real_writeb(RealSeg(ECBAddr), RealOff(ECBAddr)+28+i, immAddr[i]); +} - if(useECB->prevECB == NULL) { - ECBList = useECB->nextECB; - if(ECBList != NULL) ECBList->prevECB = NULL; +void ECBClass::getImmAddress(Bit8u* immAddr) { + for(Bitu i=0;i<6;i++) + immAddr[i] = real_readb(RealSeg(ECBAddr), RealOff(ECBAddr)+28+i); +} + +ECBClass::~ECBClass() { +#ifdef IPX_DEBUGMSG + ECBAmount--; + LOG_MSG("ECB: SN%7d destroyed. Remaining ECBs: %3d", SerialNumber,ECBAmount); +#endif + + if(isInESRList) { + // in ESR list, always the first element is deleted. + ESRList=nextECB; } else { - useECB->prevECB->nextECB = useECB->nextECB; - if(useECB->nextECB != NULL) useECB->nextECB->prevECB = useECB->prevECB; + if(prevECB == NULL) { // was the first in the list + ECBList = nextECB; + if(ECBList != NULL) ECBList->prevECB = NULL; + } else { // not the first + prevECB->nextECB = nextECB; + if(nextECB != NULL) nextECB->prevECB = prevECB; + } } - delete useECB; } -Bit16u socketCount; -Bit16u opensockets[SOCKTABLESIZE]; + static bool sockInUse(Bit16u sockNum) { - Bit16u i; - for(i=0;i= SOCKTABLESIZE) { @@ -236,11 +267,12 @@ static void OpenSocket(void) { reg_al = 0x00; // Success reg_dx = swapByte(sockNum); // Convert back to big-endian - } static void CloseSocket(void) { Bit16u sockNum, i; + ECBClass* tmpECB = ECBList; + ECBClass* tmp2ECB = ECBList; sockNum = swapByte(reg_dx); if(!sockInUse(sockNum)) return; @@ -253,76 +285,149 @@ static void CloseSocket(void) { } } --socketCount; + + // delete all ECBs of that socket + while(tmpECB!=0) { + tmp2ECB = tmpECB->nextECB; + if(tmpECB->getSocket()==sockNum) { + tmpECB->setCompletionFlag(COMP_CANCELLED); + tmpECB->setInUseFlag(USEFLAG_AVAILABLE); + delete tmpECB; + } + tmpECB = tmp2ECB; + } } -static bool IPX_Multiplex(void) -{ +//static RealPt IPXVERpointer; + +static bool IPX_Multiplex(void) { if(reg_ax != 0x7a00) return false; reg_al = 0xff; SegSet16(es,RealSeg(ipx_callback)); reg_di = RealOff(ipx_callback); + + //reg_bx = RealOff(IPXVERpointer); + //reg_cx = RealSeg(ipx_callback); return true; } +static void sendPacket(ECBClass* sendecb); + static void handleIpxRequest(void) { ECBClass *tmpECB; switch (reg_bx) { case 0x0000: // Open socket OpenSocket(); +#ifdef IPX_DEBUGMSG LOG_MSG("IPX: Open socket %4x", swapByte(reg_dx)); +#endif break; case 0x0001: // Close socket +#ifdef IPX_DEBUGMSG LOG_MSG("IPX: Close socket %4x", swapByte(reg_dx)); +#endif CloseSocket(); break; + case 0x0002: // get local target + // es:si + // Currently no support for multiple networks + + for(Bitu i = 0; i < 6; i++) + real_writeb(SegValue(es),reg_di+i,real_readb(SegValue(es),reg_si+i+4)); + + reg_cx=1; // time ticks expected + reg_al=0x00;//success + break; + case 0x0003: // Send packet if(!incomingPacket.connected) { - tmpECB = CreateECB(RealMake(SegValue(es), reg_si)); + tmpECB = new ECBClass(SegValue(es),reg_si); tmpECB->setInUseFlag(USEFLAG_AVAILABLE); tmpECB->setCompletionFlag(COMP_UNDELIVERABLE); - DeleteECB(tmpECB); + delete tmpECB; // not notify? reg_al = 0xff; // Failure } else { - tmpECB = CreateECB(RealMake(SegValue(es), reg_si)); + tmpECB = new ECBClass(SegValue(es),reg_si); tmpECB->setInUseFlag(USEFLAG_SENDING); + //LOG_MSG("IPX: Sending packet on %4x", tmpECB->getSocket()); reg_al = 0x00; // Success + sendPacket(tmpECB); } - //LOG_MSG("IPX: Sending packet on %4x", tmpECB->getSocket()); + break; case 0x0004: // Listen for packet - tmpECB = CreateECB(RealMake(SegValue(es), reg_si)); - if(!sockInUse(tmpECB->getSocket())) { - reg_al = 0xff; // Socket is not open + tmpECB = new ECBClass(SegValue(es),reg_si); + if(!sockInUse(tmpECB->getSocket())) { // Socket is not open + reg_al = 0xff; tmpECB->setInUseFlag(USEFLAG_AVAILABLE); tmpECB->setCompletionFlag(COMP_HARDWAREERROR); - DeleteECB(tmpECB); + delete tmpECB; } else { reg_al = 0x00; // Success tmpECB->setInUseFlag(USEFLAG_LISTENING); - //LOG_MSG("IPX: Listen for packet on 0x%4x - ESR address %4x:%4x", tmpECB->getSocket(), RealSeg(tmpECB->getESRAddr()), RealOff(tmpECB->getESRAddr())); + /*LOG_MSG("IPX: Listen for packet on 0x%4x - ESR address %4x:%4x", + tmpECB->getSocket(), + RealSeg(tmpECB->getESRAddr()), + RealOff(tmpECB->getESRAddr()));*/ } break; + case 0x0006: // cancel operation + { + RealPt ecbaddress = RealMake(SegValue(es),reg_si); + ECBClass* tmpECB= ECBList; + ECBClass* tmp2ECB; + while(tmpECB) { + tmp2ECB=tmpECB->nextECB; + if(tmpECB->ECBAddr == ecbaddress) { + tmpECB->setInUseFlag(USEFLAG_AVAILABLE); + tmpECB->setCompletionFlag(COMP_CANCELLED); + delete tmpECB; + reg_al=0; // Success +#ifdef IPX_DEBUGMSG + LOG_MSG("IPX: ECB canceled."); +#endif + return; + } + tmpECB=tmp2ECB; + } + reg_al=0xff; // Fail + break; + } case 0x0008: // Get interval marker // ???? break; case 0x0009: // Get internetwork address { +#ifdef IPX_DEBUGMSG LOG_MSG("IPX: Get internetwork address %2x:%2x:%2x:%2x:%2x:%2x", localIpxAddr.netnode[5], localIpxAddr.netnode[4], localIpxAddr.netnode[3], localIpxAddr.netnode[2], localIpxAddr.netnode[1], localIpxAddr.netnode[0]); - Bit8u * addrptr; - Bits i; - - addrptr = (Bit8u *)&localIpxAddr; - for(i=0;i<10;i++) { - real_writeb(SegValue(es),reg_si+i,addrptr[i]); +#endif + Bit8u * addrptr = (Bit8u *)&localIpxAddr; + for(Bit16u i=0;i<10;i++) { + real_writeb(SegValue(es),reg_si+i,addrptr[i]); } break; } case 0x000a: // Relinquish control // Idle thingy break; + case 0x000b: // Disconnect from Target + // We don't even connect + break; + + case 0x0010: // SPX install check + { + reg_al=0; // SPX not installed + break; + } + case 0x001a: // get driver maximum packet size + { + reg_cx=0; // retry count + reg_ax=IPXBUFFERSIZE; // max packet size + break; + } default: LOG_MSG("Unhandled IPX function: %4x", reg_bx); break; @@ -342,15 +447,6 @@ Bitu IPX_IntHandler(void) { return CBRET_NONE; } -static void disconnectServer(bool unexpected) { - - // There is no Timer remove code, hence this has to be done manually - incomingPacket.connected = false; - - if(unexpected) LOG_MSG("IPX: Server disconnected unexpectedly"); - -} - static void pingAck(IPaddress retAddr) { IPXHeader regHeader; UDPpacket regPacket; @@ -375,7 +471,6 @@ static void pingAck(IPaddress retAddr) { regPacket.channel = UDPChannel; result = SDLNet_UDP_Send(ipxClientSocket, regPacket.channel, ®Packet); - } static void pingSend(void) { @@ -406,7 +501,6 @@ static void pingSend(void) { if(!result) { LOG_MSG("IPX: SDLNet_UDP_Send: %s\n", SDLNet_GetError()); } - } static void receivePacket(Bit8u *buffer, Bit16s bufSize) { @@ -424,7 +518,7 @@ static void receivePacket(Bit8u *buffer, Bit16s bufSize) { // Check to see if ping packet if(useSocket == 0x2) { // Is this a broadcast? - if((tmpHeader->dest.addr.byIP.host == 0xffffffff) && (tmpHeader->dest.addr.byIP.port = 0xffff)) { + if((tmpHeader->dest.addr.byIP.host == 0xffffffff) && (tmpHeader->dest.addr.byIP.port == 0xffff)) { // Yes. We should return the ping back to the sender IPaddress tmpAddr; UnpackIP(tmpHeader->src.addr.byIP, &tmpAddr); @@ -433,9 +527,9 @@ static void receivePacket(Bit8u *buffer, Bit16s bufSize) { } } - useECB = ECBList; - while(useECB != NULL) { + while(useECB != NULL) + { nextECB = useECB->nextECB; if(useECB->getInUseFlag() == USEFLAG_LISTENING) { if(useECB->getSocket() == useSocket) { @@ -451,10 +545,10 @@ static void receivePacket(Bit8u *buffer, Bit16s bufSize) { useECB->setCompletionFlag(COMP_SUCCESS); useECB->setImmAddress(&buffer[22]); // Write in source node hostaddr = *((Bit32u *)&buffer[24]); - - //LOG_MSG("IPX: Received packet of %d bytes from %d.%d.%d.%d (%x CRC)", bufSize, CONVIP(hostaddr), packetCRC(&buffer[30], bufSize-30)); +#ifdef IPX_DEBUGMSG + LOG_MSG("IPX: Received packet of %d bytes from %d.%d.%d.%d (%x CRC)", bufSize, CONVIP(hostaddr), packetCRC(&buffer[30], bufSize-30)); +#endif useECB->NotifyESR(); - DeleteECB(useECB); return; } } @@ -462,158 +556,18 @@ static void receivePacket(Bit8u *buffer, Bit16s bufSize) { if(bufoffset < bufSize) { useECB->setCompletionFlag(COMP_MALFORMED); useECB->NotifyESR(); - DeleteECB(useECB); return; } } } useECB = nextECB; } - +#ifdef IPX_DEBUGMSG + LOG_MSG("IPX: RX Packet loss!"); +#endif } -static void sendPacketsTCP(void) { - ECBClass *useECB; - ECBClass *nextECB; - char outbuffer[IPXBUFFERSIZE]; - fragmentDescriptor tmpFrag; - Bit16u i, fragCount,t; - Bit16s packetsize; - Bit16u *wordptr; - Bits result; - - useECB = ECBList; - while(useECB != NULL) { - nextECB = useECB->nextECB; - if(useECB->getInUseFlag() == USEFLAG_SENDING) { - useECB->setInUseFlag(USEFLAG_AVAILABLE); - packetsize = 0; - fragCount = useECB->getFragCount(); - for(i=0;igetFragDesc(i,&tmpFrag); - if(i==0) { - // Fragment containing IPX header - // Must put source address into header - Bit8u * addrptr; - Bits m; - - addrptr = (Bit8u *)&localIpxAddr.netnode; - for(m=0;m<6;m++) { - real_writeb(tmpFrag.segment,tmpFrag.offset+m+22,addrptr[m]); - } - } - for(t=0;t=IPXBUFFERSIZE) { - LOG_MSG("IPX: Packet size to be sent greater than %d bytes.", IPXBUFFERSIZE); - useECB->setCompletionFlag(COMP_MALFORMED); - useECB->NotifyESR(); - DeleteECB(useECB); - goto nextECB; - } - } - } - result = SDLNet_TCP_Send(ipxTCPClientSocket, &packetsize, 2); - if(result != 2) { - useECB->setCompletionFlag(COMP_UNDELIVERABLE); - useECB->NotifyESR(); - DeleteECB(useECB); - disconnectServer(true); - return; - } - - // Add length and source socket to IPX header - wordptr = (Bit16u *)&outbuffer[0]; - // Blank CRC - wordptr[0] = 0xffff; - // Length - wordptr[1] = swapByte(packetsize); - // Source socket - wordptr[14] = swapByte(useECB->getSocket()); - - result = SDLNet_TCP_Send(ipxTCPClientSocket, &outbuffer[0], packetsize); - if(result != packetsize) { - useECB->setCompletionFlag(COMP_UNDELIVERABLE); - useECB->NotifyESR(); - DeleteECB(useECB); - disconnectServer(true); - return; - } - useECB->setInUseFlag(USEFLAG_AVAILABLE); - useECB->setCompletionFlag(COMP_SUCCESS); - useECB->NotifyESR(); - DeleteECB(useECB); - - } -nextECB: - - useECB = nextECB; - } - -} - - -static void IPX_TCPClientLoop(void) { - Bits result; - - // Check for incoming packets - SDLNet_CheckSockets(clientSocketSet,0); - - if(SDLNet_SocketReady(ipxClientSocket)) { - if(!incomingPacket.inPacket) { - if(!incomingPacket.waitsize) { - result = SDLNet_TCP_Recv(ipxTCPClientSocket, &incomingPacket.packetSize, 2); - if(result!=2) { - if(result>0) { - incomingPacket.waitsize = true; - goto finishReceive; - } else { - disconnectServer(true); - goto finishReceive; - } - } - incomingPacket.packetRead = 0; - } else { - Bit8u * nextchar; - nextchar = (Bit8u *)&incomingPacket.packetSize; - nextchar++; - result = SDLNet_TCP_Recv(ipxTCPClientSocket, nextchar, 1); - if(result!=1) { - if(result>0) { - LOG_MSG("IPX: Packet overrun"); - } else { - disconnectServer(true); - goto finishReceive; - } - } - incomingPacket.waitsize = false; - incomingPacket.packetRead = 0; - } - incomingPacket.inPacket = true; - } - result = SDLNet_TCP_Recv(ipxTCPClientSocket, &incomingPacket.buffer[incomingPacket.packetRead], incomingPacket.packetSize); - if (result>0) { - incomingPacket.packetRead+=result; - incomingPacket.packetSize-=result; - if(incomingPacket.packetSize<=0) { - // IPX packet is complete. Now interpret IPX header and try to match to listening ECB - receivePacket(&incomingPacket.buffer[0], incomingPacket.packetRead); - incomingPacket.inPacket = false; - } - } else { - // Clost active socket - disconnectServer(true); - } - - } - -finishReceive:; - - -} - -static void IPX_UDPClientLoop(void) { +static void IPX_ClientLoop(void) { int numrecv; UDPpacket inPacket; inPacket.data = (Uint8 *)recvBuffer; @@ -622,105 +576,122 @@ static void IPX_UDPClientLoop(void) { // Its amazing how much simpler UDP is than TCP numrecv = SDLNet_UDP_Recv(ipxClientSocket, &inPacket); - if(numrecv) { - receivePacket(inPacket.data, inPacket.len); - } - + if(numrecv) receivePacket(inPacket.data, inPacket.len); } -static void sendPackets() { - ECBClass *useECB; - ECBClass *nextECB; - char outbuffer[IPXBUFFERSIZE]; + +void DisconnectFromServer(bool unexpected) { + if(unexpected) LOG_MSG("IPX: Server disconnected unexpectedly"); + if(incomingPacket.connected) { + incomingPacket.connected = false; + TIMER_DelTickHandler(&IPX_ClientLoop); + SDLNet_UDP_Close(ipxClientSocket); + } +} + +static void sendPacket(ECBClass* sendecb) { + Bit8u outbuffer[IPXBUFFERSIZE]; fragmentDescriptor tmpFrag; Bit16u i, fragCount,t; Bit16s packetsize; Bit16u *wordptr; Bits result; UDPpacket outPacket; - - useECB = ECBList; - while(useECB != NULL) { - nextECB = useECB->nextECB; - if(useECB->getInUseFlag() == USEFLAG_SENDING) { - useECB->setInUseFlag(USEFLAG_AVAILABLE); - packetsize = 0; - fragCount = useECB->getFragCount(); - for(i=0;igetFragDesc(i,&tmpFrag); - if(i==0) { - // Fragment containing IPX header - // Must put source address into header - Bit8u * addrptr; - Bits m; - - addrptr = (Bit8u *)&localIpxAddr.netnode; - for(m=0;m<6;m++) { - real_writeb(tmpFrag.segment,tmpFrag.offset+m+22,addrptr[m]); - } - } - for(t=0;t=IPXBUFFERSIZE) { - LOG_MSG("IPX: Packet size to be sent greater than %d bytes.", IPXBUFFERSIZE); - useECB->setCompletionFlag(COMP_UNDELIVERABLE); - useECB->NotifyESR(); - DeleteECB(useECB); - goto nextECB; - } - } - } + + sendecb->setInUseFlag(USEFLAG_AVAILABLE); + packetsize = 0; + fragCount = sendecb->getFragCount(); + for(i=0;igetFragDesc(i,&tmpFrag); + if(i==0) { + // Fragment containing IPX header + // Must put source address into header + Bit8u * addrptr; - // Add length and source socket to IPX header - wordptr = (Bit16u *)&outbuffer[0]; - // Blank CRC - wordptr[0] = 0xffff; - // Length - wordptr[1] = swapByte(packetsize); - // Source socket - wordptr[14] = swapByte(useECB->getSocket()); - - outPacket.channel = UDPChannel; - outPacket.data = (Uint8 *)&outbuffer[0]; - outPacket.len = packetsize; - outPacket.maxlen = packetsize; - // Since we're using a channel, we won't send the IP address again - result = SDLNet_UDP_Send(ipxClientSocket, UDPChannel, &outPacket); - if(result == 0) { - LOG_MSG("IPX: Could not send packet: %s", SDLNet_GetError()); - useECB->setCompletionFlag(COMP_UNDELIVERABLE); - useECB->NotifyESR(); - DeleteECB(useECB); - disconnectServer(true); + addrptr = (Bit8u *)&localIpxAddr.netnum; + for(Bit16u m=0;m<4;m++) { + real_writeb(tmpFrag.segment,tmpFrag.offset+m+18,addrptr[m]); + } + addrptr = (Bit8u *)&localIpxAddr.netnode; + for(Bit16u m=0;m<6;m++) { + real_writeb(tmpFrag.segment,tmpFrag.offset+m+22,addrptr[m]); + } + } + for(t=0;t=IPXBUFFERSIZE) { + LOG_MSG("IPX: Packet size to be sent greater than %d bytes.", IPXBUFFERSIZE); + sendecb->setCompletionFlag(COMP_UNDELIVERABLE); + sendecb->NotifyESR(); return; } - useECB->setInUseFlag(USEFLAG_AVAILABLE); - useECB->setCompletionFlag(COMP_SUCCESS); - useECB->NotifyESR(); - DeleteECB(useECB); - } -nextECB: + } + + // Add length and source socket to IPX header + wordptr = (Bit16u *)&outbuffer[0]; + // Blank CRC + wordptr[0] = 0xffff; + // Length + wordptr[1] = swapByte(packetsize); + // Source socket + wordptr[14] = swapByte(sendecb->getSocket()); - useECB = nextECB; + Bit8u immedAddr[6]; + sendecb->getImmAddress(immedAddr); + // filter out broadcasts and local loopbacks + // Real implementation uses the ImmedAddr to check wether this is a broadcast + + bool islocalbroadcast=true; + bool isloopback=true; + + Bit8u * addrptr; + + addrptr = (Bit8u *)&localIpxAddr.netnum; + for(Bitu m=0;m<4;m++) { + if(addrptr[m]!=outbuffer[m+0x6])isloopback=false; + } + addrptr = (Bit8u *)&localIpxAddr.netnode; + for(Bitu m=0;m<6;m++) { + if(addrptr[m]!=outbuffer[m+0xa])isloopback=false; + if(immedAddr[m]!=0xff) islocalbroadcast=false; } + if(!isloopback) { + outPacket.channel = UDPChannel; + outPacket.data = (Uint8 *)&outbuffer[0]; + outPacket.len = packetsize; + outPacket.maxlen = packetsize; + // Since we're using a channel, we won't send the IP address again + result = SDLNet_UDP_Send(ipxClientSocket, UDPChannel, &outPacket); + + if(result == 0) { + LOG_MSG("IPX: Could not send packet: %s", SDLNet_GetError()); + sendecb->setCompletionFlag(COMP_HARDWAREERROR); + sendecb->NotifyESR(); + DisconnectFromServer(true); + return; + } else { + sendecb->setCompletionFlag(COMP_SUCCESS); +#ifdef IPX_DEBUGMSG + LOG_MSG("Packet sent: size: %d",packetsize); +#endif + } + } + if(isloopback||islocalbroadcast) { + receivePacket(&outbuffer[0],packetsize); +#ifdef IPX_DEBUGMSG + LOG_MSG("Packet back: loopback:%d, broadcast:%d",isloopback,isbroadcast); +#endif + } + sendecb->NotifyESR(); } -static void IPX_ClientLoop(void) { - IPX_UDPClientLoop(); - - // Send outgoing packets - sendPackets(); -} - - static bool pingCheck(IPXHeader * outHeader) { char buffer[1024]; Bits result; UDPpacket regPacket; - IPXHeader *regHeader; regPacket.data = (Uint8 *)buffer; regPacket.maxlen = sizeof(buffer); @@ -733,8 +704,6 @@ static bool pingCheck(IPXHeader * outHeader) { return true; } return false; - - } bool ConnectToServer(char *strAddr) { @@ -743,7 +712,12 @@ bool ConnectToServer(char *strAddr) { IPXHeader regHeader; if(!SDLNet_ResolveHost(&ipxServConnIp, strAddr, (Bit16u)tcpPort)) { - + // Generate the MAC address. This is made by zeroing out the first two + // octets and then using the actual IP address for the last 4 octets. + // This idea is from the IPX over IP implementation as specified in RFC 1234: + // http://www.faqs.org/rfcs/rfc1234.html + + // Select an anonymous UDP port ipxClientSocket = SDLNet_UDP_Open(0); if(ipxClientSocket) { @@ -802,14 +776,12 @@ bool ConnectToServer(char *strAddr) { LOG_MSG("IPX: Connected to server. IPX address is %d:%d:%d:%d:%d:%d", CONVIPX(localIpxAddr.netnode)); - incomingPacket.connected = true; TIMER_AddTickHandler(&IPX_ClientLoop); return true; } } else { LOG_MSG("IPX: Unable to open socket"); - } } else { LOG_MSG("IPX: Unable resolve connection to server"); @@ -817,45 +789,21 @@ bool ConnectToServer(char *strAddr) { return false; } -void DisconnectFromServer(void) { +void IPX_NetworkInit() { - if(incomingPacket.connected) { - incomingPacket.connected = false; - TIMER_DelTickHandler(&IPX_ClientLoop); - SDLNet_UDP_Close(ipxClientSocket); - } -} - -bool IPX_NetworkInit() { - - localIpxAddr.netnum[0] = 0x0; localIpxAddr.netnum[1] = 0x0; localIpxAddr.netnum[2] = 0x0; localIpxAddr.netnum[3] = 0x1; - - /* - if(SDLNet_ResolveHost(&ipxClientIp, localhostname, tcpPort)) { - LOG_MSG("IPX: Unable to resolve localname: \"%s\". IPX disabled.", localhostname); - return false; - } else { - LOG_MSG("IPX: Using localname: %s IP is: %d.%d.%d.%d", localhostname, CONVIP(ipxClientIp.host)); - } - */ - - // Generate the MAC address. This is made by zeroing out the first two octets and then using the actual IP address for - // the last 4 octets. This idea is from the IPX over IP implementation as specified in RFC 1234: - // http://www.faqs.org/rfcs/rfc1234.html + localIpxAddr.netnum[0] = 0x0; + localIpxAddr.netnum[1] = 0x0; + localIpxAddr.netnum[2] = 0x0; + localIpxAddr.netnum[3] = 0x1; localIpxAddr.netnode[0] = 0x00; localIpxAddr.netnode[1] = 0x00; - //localIpxAddr.netnode[5] = (ipxClientIp.host >> 24) & 0xff; - //localIpxAddr.netnode[4] = (ipxClientIp.host >> 16) & 0xff; - //localIpxAddr.netnode[3] = (ipxClientIp.host >> 8) & 0xff; - //localIpxAddr.netnode[2] = (ipxClientIp.host & 0xff); - //To be filled in on response from server localIpxAddr.netnode[2] = 0x00; localIpxAddr.netnode[3] = 0x00; localIpxAddr.netnode[4] = 0x00; localIpxAddr.netnode[5] = 0x00; socketCount = 0; - return true; + return; } class IPXNET : public Program { @@ -972,7 +920,7 @@ public: WriteOut("IPX Tunneling Server not running in this DosBox session.\n"); } else { isIpxServer = false; - DisconnectFromServer(); + DisconnectFromServer(false); IPX_StopServer(); WriteOut("IPX Tunneling Server stopped."); // Don't know how to stop the timer just yet. @@ -1013,7 +961,7 @@ public: // TODO: Send a packet to the server notifying of disconnect WriteOut("IPX Tunneling Client disconnected from server.\n"); - DisconnectFromServer(); + DisconnectFromServer(false); return; } @@ -1061,23 +1009,7 @@ public: } return; } - - - } - - /* - WriteOut("IPX Status\n\n"); - if(!incomingPacket.connected) { - WriteOut("IPX tunneling client not presently connected"); - return; - } - if(isIpxServer) { - WriteOut("This DosBox session is an IPX tunneling server running on port %d", tcpPort); - } else { - WriteOut("This DosBox session is an IPX tunneling client connected to: %s",SDLNet_ResolveIP(&ipxServConnIp)); - } - */ } }; @@ -1086,103 +1018,147 @@ static void IPXNET_ProgramStart(Program * * make) { } Bitu IPX_ESRHandler1(void) { - CPU_Push32(reg_flags); - CPU_Push32(reg_eax);CPU_Push32(reg_ecx);CPU_Push32(reg_edx);CPU_Push32(reg_ebx); - CPU_Push32(reg_ebp);CPU_Push32(reg_esi);CPU_Push32(reg_edi); - CPU_Push16(SegValue(ds)); CPU_Push16(SegValue(es)); - - SegSet16(es, RealSeg(processedECB)); - reg_si = RealOff(processedECB); - reg_al = 0xff; - //LOG_MSG("ESR Callback 1"); +#ifdef IPX_DEBUGMSG + LOG_MSG("ESRhandler entered" ); +#endif + while(ESRList!=NULL) { +#ifdef IPX_DEBUGMSG + LOG_MSG("ECB: SN%7d notified.", ESRList->SerialNumber); +#endif + + // setup registers + SegSet16(es, RealSeg(ESRList->ECBAddr)); + reg_si = RealOff(ESRList->ECBAddr); + reg_al = 0xff; + CALLBACK_RunRealFar(RealSeg(ESRList->getESRAddr()), RealOff(ESRList->getESRAddr())); + delete ESRList; + } // while + IO_WriteB(0xa0,0x63); //EOI11 + IO_WriteB(0x20,0x62); //EOI2 + +#ifdef IPX_DEBUGMSG + LOG_MSG("ESR loop done."); +#endif + return CBRET_NONE; } -Bitu IPX_ESRHandler2(void) { - SegSet16(es, CPU_Pop16()); SegSet16(ds, CPU_Pop16()); - reg_edi=CPU_Pop32();reg_esi=CPU_Pop32();reg_ebp=CPU_Pop32(); - reg_ebx=CPU_Pop32();reg_edx=CPU_Pop32();reg_ecx=CPU_Pop32();reg_eax=CPU_Pop32(); - reg_flags=CPU_Pop32(); +void VFILE_Remove(const char *name); - //LOG_MSG("Leaving ESR"); - inESR = false; +class IPX: public Module_base { +private: + CALLBACK_HandlerObject callback_ipx; + CALLBACK_HandlerObject callback_esr; + CALLBACK_HandlerObject callback_ipxint; + RealPt old_73_vector; + static Bit16u dospage; +public: + IPX(Section* configuration):Module_base(configuration) { + Section_prop * section = static_cast(configuration); + if(!section->Get_bool("ipx")) return; + if(!SDLNetInited) { + if(SDLNet_Init() == -1){ + LOG_MSG("SDLNet_Init failed: %s\n", SDLNet_GetError()); + return; + } + SDLNetInited = true; + } - return CBRET_NONE; -} + ECBList = NULL; + ESRList = NULL; + isIpxServer = false; + isIpxConnected = false; + IPX_NetworkInit(); -bool IPX_ESRSetupHook(Bitu callback1, CallBack_Handler handler1, Bitu callback2, CallBack_Handler handler2, RealPt *ptrAddr) { - PhysPt phyDospage; - phyDospage = PhysMake(dospage,0); + DOS_AddMultiplexHandler(IPX_Multiplex); - // Inital callback routine (should save registers, etc.) - phys_writeb(phyDospage+0,(Bit8u)0xFA); //CLI - phys_writeb(phyDospage+1,(Bit8u)0xFE); //GRP 4 - phys_writeb(phyDospage+2,(Bit8u)0x38); //Extra Callback instruction - phys_writew(phyDospage+3,callback1); //The immediate word - phys_writeb(phyDospage+5,(Bit8u)0x9a); //CALL Ap - // 0x6, 0x7, 0x8, 0x9 = address of called routine - *ptrAddr = RealMake(dospage, 6); - phys_writed(phyDospage+6,(Bit32u)0x00000000); // Called address - phys_writeb(phyDospage+0xa,(Bit8u)0xFE); //GRP 4 - phys_writeb(phyDospage+0xb,(Bit8u)0x38); //Extra Callback instruction - phys_writew(phyDospage+0xc,callback2); //The immediate word - phys_writeb(phyDospage+0xe,(Bit8u)0xFB); //STI - phys_writeb(phyDospage+0xf,(Bit8u)0xCB); //A RETF Instruction + callback_ipx.Install(&IPX_Handler,CB_RETF,"IPX Handler"); + ipx_callback = callback_ipx.Get_RealPointer(); - CallBack_Handlers[callback1]=handler1; - CallBack_Handlers[callback2]=handler2; - return true; + callback_ipxint.Install(&IPX_IntHandler,CB_IRET,"IPX (int 7a)"); + callback_ipxint.Set_RealVec(0x7a); + + callback_esr.Allocate(&IPX_ESRHandler1,"IPX_ESR"); + Bit16u call_ipxesr1 = callback_esr.Get_callback(); + + if(!dospage) dospage = DOS_GetMemory(2); // can not be freed yet + + PhysPt phyDospage = PhysMake(dospage,0); + +#ifdef IPX_DEBUGMSG + LOG_MSG("IPX INT address: %x", ipx_intcallback); + LOG_MSG("ESR callback address: %x, HandlerID %d", phyDospage,call_ipxesr1); +#endif + //save registers + phys_writeb(phyDospage+0,(Bit8u)0xFA); // CLI + phys_writeb(phyDospage+1,(Bit8u)0x60); // PUSHA + phys_writeb(phyDospage+2,(Bit8u)0x1E); // PUSH DS + phys_writeb(phyDospage+3,(Bit8u)0x06); // PUSH ES + phys_writew(phyDospage+4,(Bit16u)0xA00F); // PUSH FS + phys_writew(phyDospage+6,(Bit16u)0xA80F); // PUSH GS + + // callback + phys_writeb(phyDospage+8,(Bit8u)0xFE); // GRP 4 + phys_writeb(phyDospage+9,(Bit8u)0x38); // Extra Callback instruction + phys_writew(phyDospage+10,call_ipxesr1); // Callback identifier + + // register recreation + phys_writew(phyDospage+12,(Bit16u)0xA90F); // POP GS + phys_writew(phyDospage+14,(Bit16u)0xA10F); // POP FS + phys_writeb(phyDospage+16,(Bit8u)0x07); // POP ES + phys_writeb(phyDospage+17,(Bit8u)0x1F); // POP DS + phys_writeb(phyDospage+18,(Bit8u)0x61); // POPA + phys_writeb(phyDospage+19,(Bit8u)0xCF); // IRET: restores flags, CS, IP + + // IPX version 2.12 + //phys_writeb(phyDospage+27,(Bit8u)0x2); + //phys_writeb(phyDospage+28,(Bit8u)0x12); + //IPXVERpointer = RealMake(dospage,27); + + RealPt ESRRoutineBase = RealMake(dospage, 0); + + // Interrupt enabling + RealSetVec(0x73,ESRRoutineBase,old_73_vector); // IRQ11 + IO_WriteB(0xa1,IO_ReadB(0xa1)&(~8)); // enable IRQ11 + + PROGRAMS_MakeFile("IPXNET.COM",IPXNET_ProgramStart); + } + + ~IPX() { + Section_prop * section = static_cast(m_configuration); + if(!section->Get_bool("ipx")) return; + + if(isIpxServer) { + isIpxServer = false; + IPX_StopServer(); + } + DisconnectFromServer(false); + + DOS_DelMultiplexHandler(IPX_Multiplex); + RealSetVec(0x73,old_73_vector); + IO_WriteB(0xa1,IO_ReadB(0xa1)|8); // disable IRQ11 + + PhysPt phyDospage = PhysMake(dospage,0); + for(Bitu i = 0;i < 32;i++) + phys_writeb(phyDospage+i,(Bit8u)0x00); + + VFILE_Remove("IPXNET.COM"); + } +}; + +static IPX* test; + +void IPX_ShutDown(Section* sec) { + delete test; } void IPX_Init(Section* sec) { - Section_prop * section=static_cast(sec); - - if(!section->Get_bool("ipx")) return; - - if(!SDLNetInited) { - if(SDLNet_Init()==-1) { - LOG_MSG("SDLNet_Init failed: %s\n", SDLNet_GetError()); - return; - } - SDLNetInited = true; - } - - ECBList = NULL; - - isIpxServer = false; - isIpxConnected = false; - - IPX_NetworkInit(); - - inESR = false; - - DOS_AddMultiplexHandler(IPX_Multiplex); - call_ipx=CALLBACK_Allocate(); - CALLBACK_Setup(call_ipx,&IPX_Handler,CB_RETF); - ipx_callback=CALLBACK_RealPointer(call_ipx); - - call_ipxint=CALLBACK_Allocate(); - CALLBACK_Setup(call_ipxint,&IPX_IntHandler,CB_IRET); - ipx_intcallback=CALLBACK_RealPointer(call_ipxint); - - call_ipxesr1=CALLBACK_Allocate(); - call_ipxesr2=CALLBACK_Allocate(); - //CALLBACK_SetupFarCall(call_ipxesr1, &IPX_ESRHandler1, call_ipxesr2, &IPX_ESRHandler2, &ipx_esrptraddr); - dospage = DOS_GetMemory(1); - IPX_ESRSetupHook(call_ipxesr1, &IPX_ESRHandler1, call_ipxesr2, &IPX_ESRHandler2, &ipx_esrptraddr); - // Allocate 16 bytes of memory from the DOS system area at 0xd000 - ipx_esrcallback=RealMake(dospage,0); - //CALLBACK_RealPointer(call_ipxesr1); - - RealSetVec(0x7a,ipx_intcallback); - PROGRAMS_MakeFile("IPXNET.COM",IPXNET_ProgramStart); - - //if(isIpxServer) { - // Auto-connect to server - // ConnectToServer("localhost"); - //} - + test = new IPX(sec); + sec->AddDestroyFunction(&IPX_ShutDown,true); } +//Initialize static members; +Bit16u IPX::dospage = 0; + #endif diff --git a/src/hardware/ipxserver.cpp b/src/hardware/ipxserver.cpp index 5e9f956..7a002d9 100644 --- a/src/hardware/ipxserver.cpp +++ b/src/hardware/ipxserver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: ipxserver.cpp,v 1.7 2006/02/09 11:47:49 qbix79 Exp $ */ + #include "dosbox.h" #if C_IPX @@ -85,7 +87,7 @@ static void sendIPXPacket(Bit8u *buffer, Bit16s bufSize) { if(desthost == 0xffffffff) { // Broadcast for(i=0;idest.socket) == 0x2) { - - // Null destination node means its a server registration packet if(tmpHeader->dest.addr.byIP.host == 0x0) { UnpackIP(tmpHeader->src.addr.byIP, &tmpAddr); @@ -197,8 +197,6 @@ static void IPX_ServerLoop() { return; } } - - } } diff --git a/src/hardware/joystick.cpp b/src/hardware/joystick.cpp index 1013d25..7be693c 100644 --- a/src/hardware/joystick.cpp +++ b/src/hardware/joystick.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,18 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: joystick.cpp,v 1.14 2006/02/09 11:47:49 qbix79 Exp $ */ + +#include #include "dosbox.h" #include "inout.h" +#include "setup.h" +#include "joystick.h" +#include "pic.h" +#include "support.h" #define RANGE 64 +#define TIMEOUT 10 struct JoyStick { bool enabled; @@ -28,11 +36,23 @@ struct JoyStick { bool button[2]; }; - +JoystickType joytype; static JoyStick stick[2]; +static Bit32u last_write = 0; +static bool write_active = false; static Bitu read_p201(Bitu port,Bitu iolen) { + /* Reset Joystick to 0 after TIMEOUT ms */ + if(write_active && ((PIC_Ticks - last_write) > TIMEOUT)) { + write_active = false; + stick[0].xcount = 0; + stick[1].xcount = 0; + stick[0].ycount = 0; + stick[1].ycount = 0; +// LOG_MSG("reset by time %d %d",PIC_Ticks,last_write); + } + /** Format of the byte to be returned: ** | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ** +-------------------------------+ @@ -59,6 +79,9 @@ static Bitu read_p201(Bitu port,Bitu iolen) { } static void write_p201(Bitu port,Bitu val,Bitu iolen) { + /* Store writetime index */ + write_active = true; + last_write = PIC_Ticks; if (stick[0].enabled) { stick[0].xcount=(Bitu)((stick[0].xpos*RANGE)+RANGE); stick[0].ycount=(Bitu)((stick[0].ypos*RANGE)+RANGE); @@ -114,11 +137,33 @@ float JOYSTICK_GetMove_Y(Bitu which) return 0.0f; }; -void JOYSTICK_Init(Section* sec) { - IO_RegisterReadHandler(0x201,read_p201,IO_MB); - IO_RegisterWriteHandler(0x201,write_p201,IO_MB); - stick[0].enabled=false; - stick[1].enabled=false; +class JOYSTICK:public Module_base{ +private: + IO_ReadHandleObject ReadHandler; + IO_WriteHandleObject WriteHandler; +public: + JOYSTICK(Section* configuration):Module_base(configuration){ + Section_prop * section=static_cast(configuration); + const char * type=section->Get_string("joysticktype"); + if (!strcasecmp(type,"none")) joytype=JOY_NONE; + else if (!strcasecmp(type,"2axis")) joytype=JOY_2AXIS; + else if (!strcasecmp(type,"4axis")) joytype=JOY_4AXIS; + else if (!strcasecmp(type,"fcs")) joytype=JOY_FCS; + else if (!strcasecmp(type,"ch")) joytype=JOY_CH; + else joytype=JOY_2AXIS; + ReadHandler.Install(0x201,read_p201,IO_MB); + WriteHandler.Install(0x201,write_p201,IO_MB); + stick[0].enabled=false; + stick[1].enabled=false; + } +}; +static JOYSTICK* test; + +void JOYSTICK_Destroy(Section* sec) { + delete test; } - +void JOYSTICK_Init(Section* sec) { + test = new JOYSTICK(sec); + sec->AddDestroyFunction(&JOYSTICK_Destroy,true); +} diff --git a/src/hardware/keyboard.cpp b/src/hardware/keyboard.cpp index 2f66e8c..3ff84c0 100644 --- a/src/hardware/keyboard.cpp +++ b/src/hardware/keyboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,11 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: keyboard.cpp,v 1.29 2004/10/12 16:21:22 qbix79 Exp $ */ - -#include -#include -#include +/* $Id: keyboard.cpp,v 1.35 2006/02/09 11:47:49 qbix79 Exp $ */ #include "dosbox.h" #include "keyboard.h" @@ -28,6 +24,7 @@ #include "pic.h" #include "mem.h" #include "mixer.h" +#include "timer.h" #define KEYBUFSIZE 32 #define KEYDELAY 0.300f //Considering 20-30 khz serial clock and 11 bits/char @@ -59,7 +56,8 @@ static struct { static void KEYBOARD_SetPort60(Bit8u val) { keyb.p60changed=true; keyb.p60data=val; - PIC_ActivateIRQ(1); + if (machine==MCH_PCJR) PIC_ActivateIRQ(6); + else PIC_ActivateIRQ(1); } static void KEYBOARD_TransferBuffer(Bitu val) { @@ -75,7 +73,7 @@ static void KEYBOARD_TransferBuffer(Bitu val) { } -static void KEYBOARD_ClrBuffer(void) { +void KEYBOARD_ClrBuffer(void) { keyb.used=0; keyb.pos=0; PIC_RemoveEvents(KEYBOARD_TransferBuffer); @@ -312,6 +310,7 @@ void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed) { case KBD_kp0:ret=82;break; case KBD_kpperiod:ret=83;break; + case KBD_extra_lt_gt:ret=86;break; case KBD_f11:ret=87;break; case KBD_f12:ret=88;break; @@ -332,6 +331,10 @@ void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed) { case KBD_insert:extend=true;ret=82;break; case KBD_delete:extend=true;ret=83;break; case KBD_pause: + KEYBOARD_AddBuffer(0xe1); + KEYBOARD_AddBuffer(29|(pressed?0:0x80)); + KEYBOARD_AddBuffer(69|(pressed?0:0x80)); + return; case KBD_printscreen: /* Not handled yet. But usuable in mapper for special events */ return; diff --git a/src/hardware/memory.cpp b/src/hardware/memory.cpp index a4e206c..c97ab9c 100644 --- a/src/hardware/memory.cpp +++ b/src/hardware/memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,17 +16,16 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#include -#include -#include +/* $Id: memory.cpp,v 1.44 2006/02/09 11:47:49 qbix79 Exp $ */ #include "dosbox.h" #include "mem.h" #include "inout.h" #include "setup.h" #include "paging.h" -#include "vga.h" +#include "regs.h" + +#include #define PAGES_IN_BLOCK ((1024*1024)/MEM_PAGE_SIZE) #define MAX_MEMORY 64 @@ -48,7 +47,7 @@ static struct MemoryBlock { Bitu start_page; Bitu end_page; Bitu pages; - HostPt address; + PageHandler *handler; } lfb; struct { bool enabled; @@ -64,14 +63,11 @@ public: flags=PFLAG_INIT|PFLAG_NOCODE; } Bitu readb(PhysPt addr) { - LOG_MSG("Illegal read from %x",addr); + LOG_MSG("Illegal read from %x, CS:IP %8x:%8x",addr,SegValue(cs),reg_eip); return 0; } void writeb(PhysPt addr,Bitu val) { - LOG_MSG("Illegal write to %x",addr); - } - HostPt GetHostPt(Bitu phys_page) { - return 0; + LOG_MSG("Illegal write to %x, CS:IP %8x:%8x",addr,SegValue(cs),reg_eip); } }; @@ -80,7 +76,10 @@ public: RAMPageHandler() { flags=PFLAG_READABLE|PFLAG_WRITEABLE; } - HostPt GetHostPt(Bitu phys_page) { + HostPt GetHostReadPt(Bitu phys_page) { + return MemBase+phys_page*MEM_PAGESIZE; + } + HostPt GetHostWritePt(Bitu phys_page) { return MemBase+phys_page*MEM_PAGESIZE; } }; @@ -91,34 +90,24 @@ public: flags=PFLAG_READABLE|PFLAG_HASROM; } void writeb(PhysPt addr,Bitu val){ - LOG_MSG("Write %x to rom at %x",val,addr); + LOG(LOG_CPU,LOG_ERROR)("Write %x to rom at %x",val,addr); } void writew(PhysPt addr,Bitu val){ - LOG_MSG("Write %x to rom at %x",val,addr); + LOG(LOG_CPU,LOG_ERROR)("Write %x to rom at %x",val,addr); } void writed(PhysPt addr,Bitu val){ - LOG_MSG("Write %x to rom at %x",val,addr); + LOG(LOG_CPU,LOG_ERROR)("Write %x to rom at %x",val,addr); } }; -class LFBPageHandler : public RAMPageHandler { -public: - LFBPageHandler() { - flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE; - } - HostPt GetHostPt(Bitu phys_page) { - return memory.lfb.address+(phys_page-memory.lfb.start_page)*4096; - } -}; static IllegalPageHandler illegal_page_handler; static RAMPageHandler ram_page_handler; static ROMPageHandler rom_page_handler; -static LFBPageHandler lfb_page_handler; -void MEM_SetLFB(Bitu page,Bitu pages,HostPt pt) { - memory.lfb.address=pt; +void MEM_SetLFB(Bitu page, Bitu pages, PageHandler *handler) { + memory.lfb.handler=handler; memory.lfb.start_page=page; memory.lfb.end_page=page+pages; memory.lfb.pages=pages; @@ -129,7 +118,7 @@ PageHandler * MEM_GetPageHandler(Bitu phys_page) { if (phys_page=memory.lfb.start_page) && (phys_page>=8; + if (mem_writeb_checked_x86(address+1,(Bit8u)(val & 0xff))) return true; + return false; +} + +bool mem_unalignedwrited_checked_x86(PhysPt address,Bit32u val) { + if (mem_writeb_checked_x86(address,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked_x86(address+1,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked_x86(address+2,(Bit8u)(val & 0xff))) return true;val>>=8; + if (mem_writeb_checked_x86(address+3,(Bit8u)(val & 0xff))) return true; + return false; +} + Bit8u mem_readb(PhysPt address) { return mem_readb_inline(address); } @@ -473,50 +494,76 @@ static Bitu read_p92(Bitu port,Bitu iolen) { return memory.a20.controlport | (memory.a20.enabled ? 0x02 : 0); } +HostPt GetMemBase(void) { return MemBase; } +class MEMORY:public Module_base{ +private: + IO_ReadHandleObject ReadHandler; + IO_WriteHandleObject WriteHandler; +public: + MEMORY(Section* configuration):Module_base(configuration){ + Bitu i; + Section_prop * section=static_cast(configuration); + + /* Setup the Physical Page Links */ + Bitu memsize=section->Get_int("memsize"); + + if (memsize < 1) memsize = 1; + /* max 63 to solve problems with certain xms handlers */ + if (memsize > MAX_MEMORY-1) { + LOG_MSG("Maximum memory size is %d MB",MAX_MEMORY - 1); + memsize = MAX_MEMORY-1; + } + MemBase = new Bit8u[memsize*1024*1024]; + if (!MemBase) E_Exit("Can't allocate main memory of %d MB",memsize); + /* Clear the memory, as new doesn't always give zeroed memory + * (Visual C debug mode). We want zeroed memory though. */ + memset((void*)MemBase,0,memsize*1024*1024); + memory.pages = (memsize*1024*1024)/4096; + /* Allocate the data for the different page information blocks */ + memory.phandlers=new PageHandler * [memory.pages]; + memory.mhandles=new MemHandle [memory.pages]; + for (i = 0;i < memory.pages;i++) { + memory.phandlers[i] = &ram_page_handler; + memory.mhandles[i] = 0; //Set to 0 for memory allocation + } + /* Setup rom at 0xc0000-0xc8000 */ + for (i=0xc0;i<0xc8;i++) { + memory.phandlers[i] = &rom_page_handler; + } + /* Setup rom at 0xf0000-0x100000 */ + for (i=0xf0;i<0x100;i++) { + memory.phandlers[i] = &rom_page_handler; + } + if (machine==MCH_PCJR) { + /* Setup cartridge rom at 0xe0000-0xf0000 */ + for (i=0xe0;i<0xf0;i++) { + memory.phandlers[i] = &rom_page_handler; + } + } + /* Reset some links */ + memory.links.used = 0; + // A20 Line - PS/2 system control port A + WriteHandler.Install(0x92,write_p92,IO_MB); + ReadHandler.Install(0x92,read_p92,IO_MB); + MEM_A20_Enable(false); + } + ~MEMORY(){ + delete [] MemBase; + delete [] memory.phandlers; + delete [] memory.mhandles; + } +}; + + +static MEMORY* test; + static void MEM_ShutDown(Section * sec) { - free(MemBase); + delete test; } void MEM_Init(Section * sec) { - Bitu i; - Section_prop * section=static_cast(sec); - - /* Setup the Physical Page Links */ - Bitu memsize=section->Get_int("memsize"); - - if (memsize<1) memsize=1; - /* max 63 to solve problems with certain xms handlers */ - if (memsize>MAX_MEMORY - 1) { - LOG_MSG("Maximum memory size is %d MB",MAX_MEMORY - 1); - memsize=MAX_MEMORY - 1; - } - MemBase=(HostPt)malloc(memsize*1024*1024); - if (!MemBase) E_Exit("Can't allocate main memory of %d MB",memsize); - memory.pages=(memsize*1024*1024)/4096; - /* Allocate the data for the different page information blocks */ - memory.phandlers=new PageHandler * [memory.pages]; - memory.mhandles=new MemHandle [memory.pages]; - for (i=0;iAddDestroyFunction(&MEM_ShutDown); } - - diff --git a/src/hardware/mixer.cpp b/src/hardware/mixer.cpp index ae763f7..3934388 100644 --- a/src/hardware/mixer.cpp +++ b/src/hardware/mixer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: mixer.cpp,v 1.39 2006/03/27 19:41:55 qbix79 Exp $ */ + /* Remove the sdl code from here and have it handeld in the sdlmain. That should call the mixer start from there or something. @@ -26,6 +28,15 @@ #include #include +#if defined (WIN32) +//Midi listing +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#endif + #include "SDL.h" #include "mem.h" #include "pic.h" @@ -42,10 +53,15 @@ #define MIXER_SSIZE 4 #define MIXER_SHIFT 14 #define MIXER_REMAIN ((1<MAX_AUDIO) ? (Bit16s)MAX_AUDIO : (SAMP MIN_AUDIO) + return SAMP; + else return MIN_AUDIO; + } else return MAX_AUDIO; +} struct MIXER_Channel { double vol_main[2]; @@ -61,31 +77,16 @@ struct MIXER_Channel { MIXER_Channel * next; }; -static Bit8u wavheader[]={ - 'R','I','F','F', 0x0,0x0,0x0,0x0, /* Bit32u Riff Chunk ID / Bit32u riff size */ - 'W','A','V','E', 'f','m','t',' ', /* Bit32u Riff Format / Bit32u fmt chunk id */ - 0x10,0x0,0x0,0x0, 0x1,0x0,0x2,0x0, /* Bit32u fmt size / Bit16u encoding/ Bit16u channels */ - 0x0,0x0,0x0,0x0, 0x0,0x0,0x0,0x0, /* Bit32u freq / Bit32u byterate */ - 0x4,0x0,0x10,0x0, 'd','a','t','a', /* Bit16u byte-block / Bit16u bits / Bit16u data chunk id */ - 0x0,0x0,0x0,0x0, /* Bit32u data size */ -}; - static struct { Bit32s work[MIXER_BUFSIZE][2]; Bitu pos,done; - Bitu needed,min_needed; + Bitu needed, min_needed, max_needed; + Bit32u tick_add,tick_remain; float mastervol[2]; MixerChannel * channels; bool nosound; - Bitu freq; - Bitu blocksize; - Bitu tick_add,tick_remain; - struct { - FILE * handle; - Bit16s buf[MIXER_WAVESIZE][2]; - Bitu used; - Bit32u length; - } wave; + Bit32u freq; + Bit32u blocksize; } mixer; Bit8u MixTemp[MIXER_BUFSIZE]; @@ -111,6 +112,20 @@ MixerChannel * MIXER_FindChannel(const char * name) { return chan; } +void MIXER_DelChannel(MixerChannel* delchan) { + MixerChannel * chan=mixer.channels; + MixerChannel * * where=&mixer.channels; + while (chan) { + if (chan==delchan) { + *where=chan->next; + delete delchan; + return; + } + where=&chan->next; + chan=chan->next; + } +} + void MixerChannel::UpdateVolume(void) { volmul[0]=(Bits)((1 << MIXER_VOLSHIFT)*volmain[0]*mixer.mastervol[0]); volmul[1]=(Bits)((1 << MIXER_VOLSHIFT)*volmain[1]*mixer.mastervol[1]); @@ -167,6 +182,7 @@ INLINE void MixerChannel::AddSamples(Bitu len,void * data) { Bitu mixpos=mixer.pos+done; freq_index&=MIXER_REMAIN; Bitu pos=0;Bitu new_pos; + goto thestart; while (1) { new_pos=freq_index >> MIXER_SHIFT; @@ -255,6 +271,13 @@ void MixerChannel::FillUp(void) { SDL_UnlockAudio(); } +extern bool ticksLocked; +static inline bool Mixer_irq_important(void) { + /* In some states correct timing of the irqs is more important then + * non stuttering audo */ + return (ticksLocked || (CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO))); +} + /* Mix a certain amount of new samples */ static void MIXER_MixData(Bitu needed) { MixerChannel * chan=mixer.channels; @@ -262,23 +285,25 @@ static void MIXER_MixData(Bitu needed) { chan->Mix(needed); chan=chan->next; } - if (mixer.wave.handle) { + if (CaptureState & (CAPTURE_WAVE|CAPTURE_VIDEO)) { + Bit16s convert[1024][2]; Bitu added=needed-mixer.done; + if (added>1024) + added=1024; Bitu readpos=(mixer.pos+mixer.done)&MIXER_BUFMASK; - while (added--) { + for (Bitu i=0;i> MIXER_VOLSHIFT; - mixer.wave.buf[mixer.wave.used][0]=MIXER_CLIP(sample); + convert[i][0]=MIXER_CLIP(sample); sample=mixer.work[readpos][1] >> MIXER_VOLSHIFT; - mixer.wave.buf[mixer.wave.used][1]=MIXER_CLIP(sample); + convert[i][1]=MIXER_CLIP(sample); readpos=(readpos+1)&MIXER_BUFMASK; - if (++mixer.wave.used==MIXER_WAVESIZE) { - mixer.wave.length+=MIXER_WAVESIZE*MIXER_SSIZE; - mixer.wave.used=0; - fwrite(mixer.wave.buf,MIXER_WAVESIZE*MIXER_SSIZE,1,mixer.wave.handle); - } } + CAPTURE_AddWave( mixer.freq, added, (Bit16s*)convert ); } - mixer.done=needed; + //Reset the the tick_add for constant speed + if( Mixer_irq_important() ) + mixer.tick_add = ((mixer.freq) << MIXER_SHIFT)/1000; + mixer.done = needed; } static void MIXER_Mix(void) { @@ -310,67 +335,112 @@ static void MIXER_Mix_NoSound(void) { mixer.done=0; } - static void MIXER_CallBack(void * userdata, Uint8 *stream, int len) { Bitu need=(Bitu)len/MIXER_SSIZE; - if (need>mixer.done) { -// LOG_MSG("Buffer underrun"); - return; + Bit16s * output=(Bit16s *)stream; + Bitu reduce; + Bitu pos, index, index_add; + Bits sample; + /* Enough room in the buffer ? */ + if (mixer.done < need) { +// LOG_MSG("Full underrun need %d, have %d, min %d", need, mixer.done, mixer.min_needed); + if((need - mixer.done) > (need >>7) ) //Max 1 procent stretch. + return; + reduce = mixer.done; + index_add = (reduce << MIXER_SHIFT) / need; + mixer.tick_add = ((mixer.freq+mixer.min_needed) << MIXER_SHIFT)/1000; + } else if (mixer.done < mixer.max_needed) { + Bitu left = mixer.done - need; + if (left < mixer.min_needed) { + if( !Mixer_irq_important() ) { + Bitu needed = mixer.needed - need; + Bitu diff = (mixer.min_needed>needed?mixer.min_needed:needed) - left; + mixer.tick_add = ((mixer.freq+(diff*3)) << MIXER_SHIFT)/1000; + left = 0; //No stretching as we compensate with the tick_add value + } else { + left = (mixer.min_needed - left); + left = 1 + (2*left) / mixer.min_needed; //left=1,2,3 + } +// LOG_MSG("needed underrun need %d, have %d, min %d, left %d", need, mixer.done, mixer.min_needed, left); + reduce = need - left; + index_add = (reduce << MIXER_SHIFT) / need; + } else { + reduce = need; + index_add = (1 << MIXER_SHIFT); +// LOG_MSG("regular run need %d, have %d, min %d, left %d", need, mixer.done, mixer.min_needed, left); + + /* Mixer tick value being updated: + * 3 cases: + * 1) A lot too high. >division by 5. but maxed by 2* min to prevent too fast drops. + * 2) A little too high > division by 8 + * 3) A little to nothing above the min_needed buffer > go to default value + */ + Bitu diff = left - mixer.min_needed; + if(diff > (mixer.min_needed<<1)) diff = mixer.min_needed<<1; + if(diff > (mixer.min_needed>>1)) + mixer.tick_add = ((mixer.freq-(diff/5)) << MIXER_SHIFT)/1000; + else if (diff > (mixer.min_needed>>4)) + mixer.tick_add = ((mixer.freq-(diff>>3)) << MIXER_SHIFT)/1000; + else + mixer.tick_add = (mixer.freq<< MIXER_SHIFT)/1000; + } + } else { + /* There is way too much data in the buffer */ +// LOG_MSG("overflow run need %d, have %d, min %d", need, mixer.done, mixer.min_needed); + if (mixer.done > MIXER_BUFSIZE) + index_add = MIXER_BUFSIZE - 2*mixer.min_needed; + else + index_add = mixer.done - 2*mixer.min_needed; + index_add = (index_add << MIXER_SHIFT) / need; + reduce = mixer.done - 2* mixer.min_needed; + mixer.tick_add = ((mixer.freq-(mixer.min_needed/5)) << MIXER_SHIFT)/1000; } /* Reduce done count in all channels */ for (MixerChannel * chan=mixer.channels;chan;chan=chan->next) { - if (chan->done>need) chan->done-=need; + if (chan->done>need) chan->done-=reduce; else chan->done=0; } - mixer.done-=need; - mixer.needed-=need; - if (mixer.done>mixer.min_needed) { - Bitu diff=mixer.done-mixer.min_needed; - mixer.tick_add=((mixer.freq-(diff>>2)) << MIXER_SHIFT)/1000; - } else { - Bitu diff=mixer.needed-mixer.done; - mixer.tick_add=((mixer.freq+diff*3) << MIXER_SHIFT)/1000; - } - Bit16s * output=(Bit16s *)stream; - while (need--) { - Bits sample=mixer.work[mixer.pos][0]>>MIXER_VOLSHIFT; - *output++=MIXER_CLIP(sample); - mixer.work[mixer.pos][0]=0; - sample=mixer.work[mixer.pos][1]>>MIXER_VOLSHIFT; - *output++=MIXER_CLIP(sample); - mixer.work[mixer.pos][1]=0; - mixer.pos=(mixer.pos+1)&MIXER_BUFMASK; - } -} + + // Reset mixer.tick_add when irqs are important + if( Mixer_irq_important() ) + mixer.tick_add=(mixer.freq<< MIXER_SHIFT)/1000; -static void MIXER_WaveEvent(void) { - /* Check for previously opened wave file */ - if (mixer.wave.handle) { - LOG_MSG("Stopped capturing wave output."); - /* Write last piece of audio in buffer */ - fwrite(mixer.wave.buf,1,mixer.wave.used*MIXER_SSIZE,mixer.wave.handle); - mixer.wave.length+=mixer.wave.used*MIXER_SSIZE; - /* Fill in the header with useful information */ - host_writed(&wavheader[0x04],mixer.wave.length+sizeof(wavheader)-8); - host_writed(&wavheader[0x18],mixer.freq); - host_writed(&wavheader[0x1C],mixer.freq*4); - host_writed(&wavheader[0x28],mixer.wave.length); - - fseek(mixer.wave.handle,0,0); - fwrite(wavheader,1,sizeof(wavheader),mixer.wave.handle); - fclose(mixer.wave.handle); - mixer.wave.handle=0; + mixer.done -= reduce; + mixer.needed -= reduce; + pos = mixer.pos; + mixer.pos = (mixer.pos + reduce) & MIXER_BUFMASK; + index = 0; + if(need != reduce) { + while (need--) { + Bitu i = (pos + (index >> MIXER_SHIFT )) & MIXER_BUFMASK; + index += index_add; + sample=mixer.work[i][0]>>MIXER_VOLSHIFT; + *output++=MIXER_CLIP(sample); + sample=mixer.work[i][1]>>MIXER_VOLSHIFT; + *output++=MIXER_CLIP(sample); + } + /* Clean the used buffer */ + while (reduce--) { + pos &= MIXER_BUFMASK; + mixer.work[pos][0]=0; + mixer.work[pos][1]=0; + pos++; + } } else { - mixer.wave.handle=OpenCaptureFile("Wave Output",".wav"); - if (!mixer.wave.handle) return; - mixer.wave.length=0; - mixer.wave.used=0; - fwrite(wavheader,1,sizeof(wavheader),mixer.wave.handle); + while (reduce--) { + pos &= MIXER_BUFMASK; + sample=mixer.work[pos][0]>>MIXER_VOLSHIFT; + *output++=MIXER_CLIP(sample); + sample=mixer.work[pos][1]>>MIXER_VOLSHIFT; + *output++=MIXER_CLIP(sample); + mixer.work[pos][0]=0; + mixer.work[pos][1]=0; + pos++; + } } } static void MIXER_Stop(Section* sec) { - if (mixer.wave.handle) MIXER_WaveEvent(); } class MIXER : public Program { @@ -399,13 +469,12 @@ public: } if (!w) vol1=vol0; } - void ShowVolume(char * name,float vol0,float vol1) { - WriteOut("%-8s %3.0f:%-3.0f %+3.2f:%-+3.2f \n",name, - vol0*100,vol1*100, - 20*log(vol0)/log(10.0f),20*log(vol1)/log(10.0f) - ); - } + void Run(void) { + if(cmd->FindExist("/LISTMIDI")) { + ListMidi(); + return; + } if (cmd->FindString("MASTER",temp_line,false)) { MakeVolume((char *)temp_line.c_str(),mixer.mastervol[0],mixer.mastervol[1]); } @@ -424,14 +493,53 @@ public: for (chan=mixer.channels;chan;chan=chan->next) ShowVolume(chan->name,chan->volmain[0],chan->volmain[1]); } +private: + void ShowVolume(char * name,float vol0,float vol1) { + WriteOut("%-8s %3.0f:%-3.0f %+3.2f:%-+3.2f \n",name, + vol0*100,vol1*100, + 20*log(vol0)/log(10.0f),20*log(vol1)/log(10.0f) + ); + } + + void ListMidi(){ +#if defined (WIN32) + unsigned int total = midiOutGetNumDevs(); + for(unsigned int i=0;i 31) E_Exit("Too long mixer channel name"); + safe_strncpy(m_name,name,32); + installed = true; + return MIXER_AddChannel(handler,freq,name); + } else { + E_Exit("allready added mixer channel."); + return 0; //Compiler happy + } +} + +MixerObject::~MixerObject(){ + if(!installed) return; + MIXER_DelChannel(MIXER_FindChannel(m_name)); +} + + void MIXER_Init(Section* sec) { sec->AddDestroyFunction(&MIXER_Stop); + Section_prop * section=static_cast(sec); /* Read out config section */ mixer.freq=section->Get_int("rate"); @@ -443,8 +551,6 @@ void MIXER_Init(Section* sec) { mixer.pos=0; mixer.done=0; memset(mixer.work,0,sizeof(mixer.work)); - mixer.wave.handle=0; - mixer.wave.used=0; mixer.mastervol[0]=1.0f; mixer.mastervol[1]=1.0f; @@ -465,6 +571,7 @@ void MIXER_Init(Section* sec) { mixer.tick_add=((mixer.freq) << MIXER_SHIFT)/1000; TIMER_AddTickHandler(MIXER_Mix_NoSound); } else if (SDL_OpenAudio(&spec, &obtained) <0 ) { + mixer.nosound = true; LOG_MSG("MIXER:Can't open audio: %s , running in nosound mode.",SDL_GetError()); mixer.tick_add=((mixer.freq) << MIXER_SHIFT)/1000; TIMER_AddTickHandler(MIXER_Mix_NoSound); @@ -478,8 +585,7 @@ void MIXER_Init(Section* sec) { mixer.min_needed=section->Get_int("prebuffer"); if (mixer.min_needed>100) mixer.min_needed=100; mixer.min_needed=(mixer.freq*mixer.min_needed)/1000; + mixer.max_needed=mixer.blocksize * 2 + 2*mixer.min_needed; mixer.needed=mixer.min_needed+1; - MAPPER_AddHandler(MIXER_WaveEvent,MK_f6,MMOD1,"recwave","Rec Wave"); PROGRAMS_MakeFile("MIXER.COM",MIXER_ProgramStart); } - diff --git a/src/hardware/mpu401.cpp b/src/hardware/mpu401.cpp index 412ef88..ab1c5df 100644 --- a/src/hardware/mpu401.cpp +++ b/src/hardware/mpu401.cpp @@ -1,184 +1,74 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: mpu401.cpp,v 1.20 2006/03/19 10:24:59 qbix79 Exp $ */ + #include #include "dosbox.h" #include "inout.h" #include "pic.h" #include "setup.h" #include "cpu.h" -#include "callback.h" +#include "support.h" void MIDI_RawOutByte(Bit8u data); bool MIDI_Available(void); -static Bitu call_irq9; static void MPU401_Event(Bitu); static void MPU401_Reset(void); static void MPU401_EOIHandler(void); -#define MPU_QUEUE 32 -#define TIMECONSTANT (60000000/1000.0f) +#define MPU401_VERSION 0x15 +#define MPU401_REVISION 0x01 +#define MPU401_QUEUE 32 +#define MPU401_TIMECONSTANT (60000000/1000.0f) -enum MpuMode { M_UART,M_INTELLIGENT } ; +enum MpuMode { M_UART,M_INTELLIGENT }; enum MpuDataType {OVERFLOW,MARK,MIDI_SYS,MIDI_NORM,COMMAND}; -///////////////////////////////////////////////////////////////////////////// -// I/O -///////////////////////////////////////////////////////////////////////////// +/* Messages sent to MPU-401 from host */ +#define MSG_EOX 0xf7 +#define MSG_OVERFLOW 0xf8 +#define MSG_MARK 0xfc -#define MPU_STATUS_DSR (1 << 7) -#define MPU_STATUS_DRR (1 << 6) -#define MPU_STATUS_PAD (0xff & (~(MPU_STATUS_DRR | MPU_STATUS_DSR))) - -#define MK_MPU_STATUS(dsr, drr)\ - (((dsr) ? 0 : MPU_STATUS_DSR) | ((drr) ? 0 : MPU_STATUS_DRR) | MPU_STATUS_PAD) - - -///////////////////////////////////////////////////////////////////////////// -// Commands -///////////////////////////////////////////////////////////////////////////// - -/** Copyright notice for MPU-401 intelligent-mode command constants ********* - - MPU-401 MIDI Interface Module v1.0 - Copyright (c) 1991, Robin Davies. All Rights Reserved. - - Robin Davies - 224 3rd Avenue - Ottawa, Ontario - Canada. K1S 2K3. - - updated by: - - Larry Troxler, Compuserve 73520,1736 - - - 15.02.2004: updated and implemented intelligent mode - -****************************************************************************/ - -// Start/Stop Commands - -#define CMD_MIDI_STOP 0x01 -#define CMD_MIDI_START 0x02 -#define CMD_MIDI_CONTINUE 0x03 - -#define CMD_PLAY_STOP 0x04 -#define CMD_PLAY_START 0x08 -#define CMD_PLAY_CONTINUE 0x0c - -#define CMD_RECORD_STOP 0x10 -#define CMD_RECORD_START 0x20 - -// Commands - -#define CMD_DISABLE_ALL_NOTES_OFF 0x30 -#define CMD_DISABLE_REAL_TIME_OUT 0x32 -#define CMD_DISABLE_ALL_THRU_OFF 0x33 -#define CMD_TIMING_BYTE_ALWAYS 0x34 -#define CMD_MODE_MESS_ON 0x35 -#define CMD_EXCLUSIVE_THRU_ON 0x37 -#define CMD_COMMON_TO_HOST_ON 0x38 -#define CMD_REAL_TIME_TO_HOST_ON 0x39 -#define CMD_UART_MODE 0x3f - -#define CMD_INT_CLOCK 0x80 -#define CMD_FSK_CLOCK 0x81 -#define CMD_MIDI_CLOCK 0x82 -#define CMD_METRONOME_ON 0x83 -#define CMD_METRONOME_OFF 0x84 -#define CMD_METRONOME_W_ACCENTS 0x85 -#define CMD_BENDER_OFF 0x86 -#define CMD_BENDER_ON 0x87 -#define CMD_MIDI_THRU_OFF 0x88 -#define CMD_MIDI_THRU_ON 0x89 -#define CMD_DATA_IN_STOP_MODE_OFF 0x8a -#define CMD_DATA_IN_STOP_MODE_ON 0x8b -#define CMD_SEND_MEASURE_END_OFF 0x8c -#define CMD_SEND_MEASURE_END_ON 0x8d -#define CMD_CONDUCTOR_OFF 0x8e -#define CMD_CONDUCTOR_ON 0x8f -#define CMD_REAL_TIME_AFFECTION_OFF 0x90 -#define CMD_REAL_TIME_AFFECTION_ON 0x91 -#define CMD_FSK_TO_INTERNAL 0x92 -#define CMD_FSK_TO_MIDI 0x93 -#define CMD_CLOCK_TO_HOST_OFF 0x94 -#define CMD_CLOCK_TO_HOST_ON 0x95 -#define CMD_EXCLUSIVE_TO_HOST_OFF 0x96 -#define CMD_EXCLUSIVE_TO_HOST_ON 0x97 - -#define CMD_RESET_RELATIVE_TEMPO 0xb1 -#define CMD_CLEAR_PLAY_COUNTERS 0xb8 -#define CMD_CLEAR_PLAY_MAP 0xb9 -#define CMD_CLEAR_RECORD_COUNTER 0xba -#define CMD_TIMEBASE_48 0xc2 -#define CMD_TIMEBASE_72 0xc3 -#define CMD_TIMEBASE_96 0xc4 -#define CMD_TIMEBASE_120 0xc5 -#define CMD_TIMEBASE_144 0xc6 -#define CMD_TIMEBASE_168 0xc7 -#define CMD_TIMEBASE_192 0xc8 - -#define CMD_REQUEST_TO_SEND_DATA 0xd0 /* + track #! */ -#define CMD_REQUEST_TO_SEND_SYSTEM_MSG 0xdf - -#define CMD_SET_TEMPO 0xe0 -#define CMD_RELATIVE_TEMPO 0xe1 -#define CMD_RELATIVE_TEMPO_GRADUATION 0xe2 -#define CMD_MIDI_METRONOME 0xe4 -#define CMD_MEASURE_LENGTH 0xe6 -#define CMD_INTERNAL_CLOCK_LENGTH_TO_HOST 0xe7 -#define CMD_ACTIVE_TRACK_MASK 0xec -#define CMD_SEND_PLAY_COUNTER_MASK 0xed -#define CMD_MIDI_CHANNEL_MASK_LO 0xee -#define CMD_MIDI_CHANNEL_MASK_HI 0xef - -#define CMD_EOX 0xf7 -#define CMD_TIMING_OVERFLOW 0xf8 -#define CMD_MPU_MARK 0xfc -#define CMD_RESET 0xff - -// Commands that return data - -#define CMD_REQUEST_PLAY_COUNTER 0xa0 /* + track # */ -#define CMD_REQUEST_AND_CLEAR_REC_COUNTER 0xab -#define CMD_REQUEST_VERSION 0xac -#define CMD_REQUEST_REVISION 0xad -#define CMD_REQUEST_TEMPO 0xaf - - -///////////////////////////////////////////////////////////////////////////// -// Messages -///////////////////////////////////////////////////////////////////////////// - -#define MSG_TIMING_OVERFLOW 0xf8 -#define MSG_ALL_END 0xfc -#define MSG_CLOCK_TO_HOST 0xfd -#define MSG_CMD_ACK 0xfe -#define MSG_REQUEST_DATA 0xf0 -#define MSG_REQUEST_COMMAND 0xf9 - -#define MPU_VERSION 0x15 -#define MPU_REVISION 0x01 - -///////////////////////////////////////////////////////////////////////////// +/* Messages sent to host from MPU-401 */ +#define MSG_MPU_OVERFLOW 0xf8 +#define MSG_MPU_COMMAND_REQ 0xf9 +#define MSG_MPU_END 0xfc +#define MSG_MPU_CLOCK 0xfd +#define MSG_MPU_ACK 0xfe static struct { bool intelligent; MpuMode mode; Bitu irq; - Bit8u queue[MPU_QUEUE]; + Bit8u queue[MPU401_QUEUE]; Bitu queue_pos,queue_used; struct track { Bits counter; - Bit8u value[8]; + Bit8u value[8],sys_val; Bit8u vlength,length; MpuDataType type; } playbuf[8],condbuf; struct { bool conductor,cond_req,cond_set; - bool allnotes,realtime,allthru; - bool playing; + bool playing,reset; bool wsd,wsm,wsd_start; - bool midi_thru; bool run_irq,irq_pending; bool send_now; Bits data_onoff; @@ -186,7 +76,7 @@ static struct { Bit8u tmask,cmask,amask; Bit16u midi_mask; Bit16u req_mask; - Bit8u channel; + Bit8u channel,old_chan; } state; struct { Bit8u timebase,old_timebase; @@ -200,10 +90,14 @@ static struct { static void QueueByte(Bit8u data) { - if (mpu.queue_used=MPU_QUEUE) mpu.queue_pos-=MPU_QUEUE; - if (pos>=MPU_QUEUE) pos-=MPU_QUEUE; + if (mpu.queue_pos>=MPU401_QUEUE) mpu.queue_pos-=MPU401_QUEUE; + if (pos>=MPU401_QUEUE) pos-=MPU401_QUEUE; mpu.queue_used++; mpu.queue[pos]=data; } else LOG(LOG_MISC,LOG_NORMAL)("MPU401:Data queue full"); @@ -221,130 +115,111 @@ static Bitu MPU401_ReadStatus(Bitu port,Bitu iolen) { } static void MPU401_WriteCommand(Bitu port,Bitu val,Bitu iolen) { - LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Command %x",val); + mpu.state.reset=0; if (val && val<=0x2f) { - switch (val&3) { + switch (val&3) { /* MIDI stop, start, continue */ case 1: {MIDI_RawOutByte(0xfc);break;} case 2: {MIDI_RawOutByte(0xfa);break;} case 3: {MIDI_RawOutByte(0xfb);break;} } if (val&0x20) LOG(LOG_MISC,LOG_ERROR)("MPU-401:Unhandled Recording Command %x",val); switch (val&0xc) { - case 0x4: /* Stop */ + case 0x4: /* Stop */ PIC_RemoveEvents(MPU401_Event); mpu.state.playing=false; - for (Bitu i=0xb0;i<0xbf;i++) {//All notes off + for (Bitu i=0xb0;i<0xbf;i++) { /* All notes off */ MIDI_RawOutByte(i); MIDI_RawOutByte(0x7b); MIDI_RawOutByte(0); } - ClrQueue(); break; - case 0x8: /* Play */ + case 0x8: /* Play */ + LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Intelligent mode playback started"); mpu.state.playing=true; PIC_RemoveEvents(MPU401_Event); - PIC_AddEvent(MPU401_Event,TIMECONSTANT/(mpu.clock.tempo*mpu.clock.timebase)); - mpu.state.irq_pending=false; + PIC_AddEvent(MPU401_Event,MPU401_TIMECONSTANT/(mpu.clock.tempo*mpu.clock.timebase)); + ClrQueue(); break; } } - else if (val>=0xa0 && val<=0xa7) {/* Request play counter */ + else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ if (mpu.state.cmask&(1<<(val&7))) QueueByte(mpu.playbuf[val&7].counter); } - else if (val>=0xd0 && val<=0xd7) { /* Request to send data */ + else if (val>=0xd0 && val<=0xd7) { /* Send data */ + mpu.state.old_chan=mpu.state.channel; mpu.state.channel=val&7; mpu.state.wsd=true; mpu.state.wsm=false; mpu.state.wsd_start=true; - } + } else switch (val) { - case CMD_REQUEST_TO_SEND_SYSTEM_MSG: + case 0xdf: /* Send system message */ mpu.state.wsd=false; mpu.state.wsm=true; mpu.state.wsd_start=true; break; - case CMD_CONDUCTOR_ON: - mpu.state.cond_set=true; - break; - case CMD_CONDUCTOR_OFF: + case 0x8e: /* Conductor */ mpu.state.cond_set=false; break; - case CMD_CLOCK_TO_HOST_OFF: + case 0x8f: + mpu.state.cond_set=true; + break; + case 0x94: /* Clock to host */ mpu.clock.clock_to_host=false; break; - case CMD_CLOCK_TO_HOST_ON: + case 0x95: mpu.clock.clock_to_host=true; break; - case CMD_REAL_TIME_AFFECTION_OFF: - break; - case CMD_REAL_TIME_AFFECTION_ON: - LOG(LOG_MISC,LOG_ERROR)("MPU401:Unimplemented:Realtime affection:ON"); - break; - case CMD_MIDI_THRU_OFF: - mpu.state.midi_thru=false; - break; - case CMD_MIDI_THRU_ON: - mpu.state.midi_thru=true; - break; - case CMD_TIMEBASE_48: /* Internal clock resolution per beat */ + case 0xc2: /* Internal timebase */ mpu.clock.timebase=48; break; - case CMD_TIMEBASE_72: + case 0xc3: mpu.clock.timebase=72; break; - case CMD_TIMEBASE_96: + case 0xc4: mpu.clock.timebase=96; break; - case CMD_TIMEBASE_120: + case 0xc5: mpu.clock.timebase=120; break; - case CMD_TIMEBASE_144: + case 0xc6: mpu.clock.timebase=144; break; - case CMD_TIMEBASE_168: + case 0xc7: mpu.clock.timebase=168; break; - case CMD_TIMEBASE_192: + case 0xc8: mpu.clock.timebase=192; break; /* Commands with data byte */ - case CMD_MIDI_METRONOME: - case CMD_MEASURE_LENGTH: - case CMD_RELATIVE_TEMPO: - case CMD_SET_TEMPO: - case CMD_RELATIVE_TEMPO_GRADUATION: - case CMD_INTERNAL_CLOCK_LENGTH_TO_HOST: - case CMD_ACTIVE_TRACK_MASK: - case CMD_SEND_PLAY_COUNTER_MASK: - case CMD_MIDI_CHANNEL_MASK_LO: - case CMD_MIDI_CHANNEL_MASK_HI: + case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: + case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: mpu.state.command_byte=val; break; - /* Commands Returning Data */ - case CMD_REQUEST_VERSION: - QueueByte(MSG_CMD_ACK); - QueueByte(MPU_VERSION); - return; - case CMD_REQUEST_REVISION: - QueueByte(MSG_CMD_ACK); - QueueByte(MPU_REVISION); - return; - case CMD_REQUEST_TEMPO: - QueueByte(MSG_CMD_ACK); - QueueByte(mpu.clock.tempo); - return; - case CMD_REQUEST_AND_CLEAR_REC_COUNTER: - QueueByte(MSG_CMD_ACK); + /* Commands 0xa# returning data */ + case 0xab: /* Request and clear recording counter */ + QueueByte(MSG_MPU_ACK); QueueByte(0); return; - case CMD_RESET_RELATIVE_TEMPO: + case 0xac: /* Request version */ + QueueByte(MSG_MPU_ACK); + QueueByte(MPU401_VERSION); + return; + case 0xad: /* Request revision */ + QueueByte(MSG_MPU_ACK); + QueueByte(MPU401_REVISION); + return; + case 0xaf: /* Request tempo */ + QueueByte(MSG_MPU_ACK); + QueueByte(mpu.clock.tempo); + return; + case 0xb1: /* Reset relative tempo */ mpu.clock.tempo_rel=40; break; - case CMD_CLEAR_PLAY_MAP: - mpu.state.tmask=0; - case CMD_CLEAR_PLAY_COUNTERS: - for (Bitu i=0xb0;i<0xbf;i++) {//All notes off + case 0xb9: /* Clear play map */ + case 0xb8: /* Clear play counters */ + for (Bitu i=0xb0;i<0xbf;i++) { /* All notes off */ MIDI_RawOutByte(i); MIDI_RawOutByte(0x7b); MIDI_RawOutByte(0); @@ -358,51 +233,44 @@ static void MPU401_WriteCommand(Bitu port,Bitu val,Bitu iolen) { if (!(mpu.state.conductor=mpu.state.cond_set)) mpu.state.cond_req=0; mpu.state.amask=mpu.state.tmask; mpu.state.req_mask=0; + mpu.state.irq_pending=true; break; - case CMD_RESET: /* Reset MPU401 */ + case 0xff: /* Reset MPU-401 */ + LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Reset %X",val); + mpu.state.reset=1; MPU401_Reset(); - if (mpu.intelligent) { - QueueByte(MSG_CMD_ACK); //additional ACK for interrupt routine - mpu.state.irq_pending=true; - PIC_ActivateIRQ(mpu.irq); //UNDOCUMENTED - } break; - /* Initialization Commands */ - case CMD_UART_MODE: + case 0x3f: /* UART mode */ + LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Set UART mode %X",val); mpu.mode=M_UART; break; - case CMD_DISABLE_ALL_NOTES_OFF: - mpu.state.allnotes=false; - break; - case CMD_DISABLE_REAL_TIME_OUT: - mpu.state.realtime=false; - break; - case CMD_DISABLE_ALL_THRU_OFF: - mpu.state.allthru=false; - break; - default: - LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val); + default:; + //LOG(LOG_MISC,LOG_NORMAL)("MPU-401:Unhandled command %X",val); } - QueueByte(MSG_CMD_ACK); + QueueByte(MSG_MPU_ACK); } static Bitu MPU401_ReadData(Bitu port,Bitu iolen) { - Bit8u ret=MSG_CMD_ACK; + Bit8u ret=MSG_MPU_ACK; if (mpu.queue_used) { ret=mpu.queue[mpu.queue_pos]; - if (mpu.queue_pos>=MPU_QUEUE) mpu.queue_pos-=MPU_QUEUE; + if (mpu.queue_pos>=MPU401_QUEUE) mpu.queue_pos-=MPU401_QUEUE; mpu.queue_pos++;mpu.queue_used--; } - if (ret>=0xf0 && ret<=0xf7) { + if (!mpu.intelligent) return ret; + + if (mpu.queue_used == 0) PIC_DeActivateIRQ(mpu.irq); + + if (ret>=0xf0 && ret<=0xf7) { /* MIDI data request */ mpu.state.channel=ret&7; mpu.state.data_onoff=0; mpu.state.cond_req=false; } - if (ret==MSG_REQUEST_COMMAND) { + if (ret==MSG_MPU_COMMAND_REQ) { mpu.state.data_onoff=0; mpu.state.cond_req=true; } - if (ret==MSG_ALL_END || ret==MSG_CLOCK_TO_HOST) { + if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) { mpu.state.data_onoff=-1; MPU401_EOIHandler(); } @@ -411,46 +279,48 @@ static Bitu MPU401_ReadData(Bitu port,Bitu iolen) { static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { if (mpu.mode==M_UART) {MIDI_RawOutByte(val);return;} - if (mpu.state.command_byte) MPU401_EOIHandler(); /* S101, Time Quest */ - switch (mpu.state.command_byte) { - case 0: + switch (mpu.state.command_byte) { /* 0xe# command data */ + case 0x00: break; - case CMD_SET_TEMPO: + case 0xe0: /* Set tempo */ mpu.state.command_byte=0; mpu.clock.tempo=val; return; - case CMD_INTERNAL_CLOCK_LENGTH_TO_HOST: + case 0xe1: /* Set relative tempo */ + mpu.state.command_byte=0; + LOG(LOG_MISC,LOG_ERROR)("MPU-401:Relative tempo not implemented"); + return; + case 0xe7: /* Set internal clock to host interval */ mpu.state.command_byte=0; mpu.clock.cth_rate=val>>2; return; - case CMD_ACTIVE_TRACK_MASK: + case 0xec: /* Set active track mask */ mpu.state.command_byte=0; mpu.state.tmask=val; return; - case CMD_SEND_PLAY_COUNTER_MASK: + case 0xed: /* Set play counter mask */ mpu.state.command_byte=0; mpu.state.cmask=val; return; - case CMD_MIDI_CHANNEL_MASK_LO: + case 0xee: /* Set 1-8 MIDI channel mask */ mpu.state.command_byte=0; mpu.state.midi_mask&=0xff00; mpu.state.midi_mask|=val; return; - case CMD_MIDI_CHANNEL_MASK_HI: + case 0xef: /* Set 9-16 MIDI channel mask */ mpu.state.command_byte=0; mpu.state.midi_mask&=0x00ff; mpu.state.midi_mask|=((Bit16u)val)<<8; return; - //case CMD_RELATIVE_TEMPO: - //case CMD_RELATIVE_TEMPO_GRADUATION: - //case CMD_MIDI_METRONOME: - //case CMD_MIDI_MEASURE: + //case 0xe2: /* Set graduation for relative tempo */ + //case 0xe4: /* Set metronome */ + //case 0xe6: /* Set metronome measure length */ default: mpu.state.command_byte=0; return; } static Bitu length,cnt,posd; - if (mpu.state.wsd) { + if (mpu.state.wsd) { /* Directly send MIDI message */ if (mpu.state.wsd_start) { mpu.state.wsd_start=0; cnt=0; @@ -466,6 +336,7 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { case 0xf0: LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal WSD byte"); mpu.state.wsd=0; + mpu.state.channel=mpu.state.old_chan; return; default: /* MIDI with running status */ cnt++; @@ -473,11 +344,14 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { } } if (cnt0xf7) { mpu.playbuf[mpu.state.channel].type=MARK; + mpu.playbuf[mpu.state.channel].sys_val=val; length=1; } else { LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message"); mpu.playbuf[mpu.state.channel].type=MIDI_SYS; + mpu.playbuf[mpu.state.channel].sys_val=val; length=1; } break; @@ -572,7 +447,7 @@ static void MPU401_WriteData(Bitu port,Bitu val,Bitu iolen) { break; } } - mpu.playbuf[mpu.state.channel].value[posd-1]=val; + if (!(posd==1 && val>=0xf0)) mpu.playbuf[mpu.state.channel].value[posd-1]=val; if (posd==length) MPU401_EOIHandler(); } } @@ -583,14 +458,14 @@ static void MPU401_IntelligentOut(Bit8u chan) { case OVERFLOW: break; case MARK: - val=mpu.playbuf[chan].value[0]; + val=mpu.playbuf[chan].sys_val; if (val==0xfc) { MIDI_RawOutByte(val); mpu.state.amask&=~(1<=500) { - CPU_CycleLeft+=CPU_Cycles-500; - CPU_Cycles=500; - } - #endif - PIC_ActivateIRQ(mpu.irq); - mpu.state.irq_pending=true; -} - -static Bitu INT71_Handler() { - CALLBACK_RunRealInt(0xa); - IO_Write(0xa0,0x61); -return CBRET_NONE; } static void MPU401_Reset(void) { @@ -692,9 +551,6 @@ static void MPU401_Reset(void) { mpu.state.conductor=false; mpu.state.cond_req=false; mpu.state.cond_set=false; - mpu.state.allnotes=true; - mpu.state.allthru=true; - mpu.state.realtime=true; mpu.state.playing=false; mpu.state.run_irq=false; mpu.state.irq_pending=false; @@ -717,26 +573,55 @@ static void MPU401_Reset(void) { for (Bitu i=0;i<8;i++) {mpu.playbuf[i].type=OVERFLOW;mpu.playbuf[i].counter=0;} } -void MPU401_Init(Section* sec) { - call_irq9=CALLBACK_Allocate(); //allocate handler for irq 9 - CALLBACK_Setup(call_irq9,&INT71_Handler,CB_IRET,"irq 9 mpu"); - RealSetVec(0x71,CALLBACK_RealPointer(call_irq9)); +class MPU401:public Module_base{ +private: + IO_ReadHandleObject ReadHandler[2]; + IO_WriteHandleObject WriteHandler[2]; + bool installed; /*as it can fail to install by 2 ways (config and no midi)*/ +public: + MPU401(Section* configuration):Module_base(configuration){ + installed = false; + Section_prop * section=static_cast(configuration); + const char* s_mpu = section->Get_string("mpu401"); + if(strcasecmp(s_mpu,"none") == 0) return; + if(strcasecmp(s_mpu,"off") == 0) return; + if(strcasecmp(s_mpu,"false") == 0) return; + if (!MIDI_Available()) return; + /*Enabled and there is a Midi */ + installed = true; + + WriteHandler[0].Install(0x330,&MPU401_WriteData,IO_MB); + WriteHandler[1].Install(0x331,&MPU401_WriteCommand,IO_MB); + ReadHandler[0].Install(0x330,&MPU401_ReadData,IO_MB); + ReadHandler[1].Install(0x331,&MPU401_ReadStatus,IO_MB); + + mpu.queue_used=0; + mpu.queue_pos=0; + mpu.mode=M_UART; + mpu.irq=9; /* Princess Maker 2 wants it on irq 9 */ - Section_prop * section=static_cast(sec); - if(!section->Get_bool("mpu401")) return; + mpu.intelligent = true; //Default is on + if(strcasecmp(s_mpu,"uart") == 0) mpu.intelligent = false; + if (!mpu.intelligent) return; + /*Set IRQ and unmask it(for timequest/princess maker 2) */ + PIC_SetIRQMask(mpu.irq,false); + MPU401_Reset(); + } + ~MPU401(){ + if(!installed) return; + Section_prop * section=static_cast(m_configuration); + if(strcasecmp(section->Get_string("mpu401"),"intelligent")) return; + PIC_SetIRQMask(mpu.irq,true); + } +}; - if (!MIDI_Available()) return; +static MPU401* test; - IO_RegisterWriteHandler(0x330,&MPU401_WriteData,IO_MB); - IO_RegisterWriteHandler(0x331,&MPU401_WriteCommand,IO_MB); - IO_RegisterReadHandler(0x330,&MPU401_ReadData,IO_MB); - IO_RegisterReadHandler(0x331,&MPU401_ReadStatus,IO_MB); - - mpu.queue_used=0; - mpu.queue_pos=0; - mpu.mode=M_UART; - - if (!(mpu.intelligent=section->Get_bool("intelligent"))) return; - mpu.irq=2; - MPU401_Reset(); +void MPU401_Destroy(Section* sec){ + delete test; +} + +void MPU401_Init(Section* sec) { + test = new MPU401(sec); + sec->AddDestroyFunction(&MPU401_Destroy,true); } diff --git a/src/hardware/pcspeaker.cpp b/src/hardware/pcspeaker.cpp index 732d332..b71d4c9 100644 --- a/src/hardware/pcspeaker.cpp +++ b/src/hardware/pcspeaker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -15,6 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + + /* $Id: pcspeaker.cpp,v 1.22 2006/02/09 11:47:49 qbix79 Exp $ */ #include #include "dosbox.h" @@ -158,7 +160,7 @@ static void ForwardPIT(float newindex) { void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) { if (!spkr.last_ticks) { - spkr.chan->Enable(true); + if(spkr.chan) spkr.chan->Enable(true); spkr.last_index=0; } spkr.last_ticks=PIC_Ticks; @@ -213,7 +215,7 @@ void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode) { void PCSPEAKER_SetType(Bitu mode) { if (!spkr.last_ticks) { - spkr.chan->Enable(true); + if(spkr.chan) spkr.chan->Enable(true); spkr.last_index=0; } spkr.last_ticks=PIC_Ticks; @@ -221,7 +223,7 @@ void PCSPEAKER_SetType(Bitu mode) { ForwardPIT(newindex); switch (mode) { case 0: - spkr.mode=SPKR_OFF; + spkr.mode=SPKR_OFF; AddDelayEntry(newindex,-SPKR_VOLUME); break; case 1: @@ -296,26 +298,52 @@ static void PCSPEAKER_CallBack(Bitu len) { } *stream++=(Bit16s)(value/sample_add); } - spkr.chan->AddSamples_m16(len,(Bit16s*)MixTemp); - if ((spkr.last_ticks+10000)AddSamples_m16(len,(Bit16s*)MixTemp); + + //Turn off speaker after 10 seconds of idle or one second idle when in off mode + Bitu test_ticks = PIC_Ticks; + if ((spkr.last_ticks+10000)Enable(false); + if(spkr.chan) spkr.chan->Enable(false); + } + if((spkr.mode == SPKR_OFF) && ((spkr.last_ticks+1000) Enable(false); } } +class PCSPEAKER:public Module_base { +private: + MixerObject MixerChan; +public: + PCSPEAKER(Section* configuration):Module_base(configuration){ + spkr.chan=0; + Section_prop * section=static_cast(configuration); + if(!section->Get_bool("pcspeaker")) return; + spkr.mode=SPKR_OFF; + spkr.last_ticks=0; + spkr.last_index=0; + spkr.rate=section->Get_int("pcrate"); + spkr.pit_max=(1000.0f/PIT_TICK_RATE)*65535; + spkr.pit_half=spkr.pit_max/2; + spkr.pit_new_max=spkr.pit_max; + spkr.pit_new_half=spkr.pit_half; + spkr.pit_index=0; + spkr.used=0; + /* Register the sound channel */ + spkr.chan=MixerChan.Install(&PCSPEAKER_CallBack,spkr.rate,"SPKR"); + } + ~PCSPEAKER(){ + Section_prop * section=static_cast(m_configuration); + if(!section->Get_bool("pcspeaker")) return; + } +}; +static PCSPEAKER* test; + +void PCSPEAKER_ShutDown(Section* sec){ + delete test; +} void PCSPEAKER_Init(Section* sec) { - Section_prop * section=static_cast(sec); - if(!section->Get_bool("pcspeaker")) return; - spkr.mode=SPKR_OFF; - spkr.last_ticks=0; - spkr.last_index=0; - spkr.rate=section->Get_int("pcrate"); - spkr.pit_max=(1000.0f/PIT_TICK_RATE)*65535; - spkr.pit_half=spkr.pit_max/2; - spkr.pit_new_max=spkr.pit_max; - spkr.pit_new_half=spkr.pit_half; - spkr.pit_index=0; - spkr.used=0; - /* Register the sound channel */ - spkr.chan=MIXER_AddChannel(&PCSPEAKER_CallBack,spkr.rate,"SPKR"); + test = new PCSPEAKER(sec); + sec->AddDestroyFunction(&PCSPEAKER_ShutDown,true); } diff --git a/src/hardware/pic.cpp b/src/hardware/pic.cpp index 9263e3f..3adebb7 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,15 +16,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: pic.cpp,v 1.25 2004/11/15 14:56:55 qbix79 Exp $ */ +/* $Id: pic.cpp,v 1.34 2006/03/12 21:14:45 qbix79 Exp $ */ #include #include "dosbox.h" #include "inout.h" #include "cpu.h" +#include "callback.h" #include "pic.h" #include "timer.h" +#include "setup.h" #define PIC_QUEUESIZE 128 @@ -44,6 +46,8 @@ struct PIC_Controller { bool special; bool auto_eoi; + bool rotate_on_auto_eoi; + bool single; bool request_issr; Bit8u vector_base; }; @@ -55,7 +59,7 @@ Bitu PIC_IRQActive; static IRQ_Block irqs[16]; static PIC_Controller pics[2]; - +static bool PIC_Special_Mode = false; //Saves one compare in the pic_run_irqloop struct PICEntry { float index; Bitu value; @@ -73,92 +77,105 @@ static void write_command(Bitu port,Bitu val,Bitu iolen) { PIC_Controller * pic=&pics[port==0x20 ? 0 : 1]; Bitu irq_base=port==0x20 ? 0 : 8; Bitu i; - Bit16u IRQ_priority_table[16] = - { 0,1,2,9,10,11,12,13,14,15,3,4,5,6,7,8 }; - switch (val) { - case 0x0A: /* select read interrupt request register */ - pic->request_issr=false; - break; - case 0x0B: /* select read interrupt in-service register */ - pic->request_issr=true; - break; - case 0x10: /* ICW1 */ - pic->icw_index=1; - pic->icw_words=2; - break; - case 0x11: /* ICW1 + need for ICW4 */ - pic->icw_index=1; - pic->icw_words=3; - break; - case 0x20:case 0x21:case 0x22:case 0x23:case 0x24:case 0x25:case 0x26:case 0x27: - if (PIC_IRQActive<(irq_base+8)) { - irqs[PIC_IRQActive].inservice=false; - PIC_IRQActive=PIC_NOIRQ; - for (i=0; i<=15; i++){ - if(irqs[IRQ_priority_table[i]].inservice) { - PIC_IRQActive=IRQ_priority_table[i]; - break; - } + static Bit16u IRQ_priority_table[16] = + { 0,1,2,8,9,10,11,12,13,14,15,3,4,5,6,7 }; + if (GCC_UNLIKELY(val&0x10)) { // ICW1 issued + if (val&0x04) E_Exit("PIC: 4 byte interval not handled"); + if (val&0x08) E_Exit("PIC: level triggered mode not handled"); + if (val&0xe0) E_Exit("PIC: 8080/8085 mode not handled"); + pic->single=val&0x02; + pic->icw_index=1; // next is ICW2 + pic->icw_words=2 + (val&0x01); // =3 if ICW4 needed + } else if (GCC_UNLIKELY(val&0x08)) { // OCW3 issued + if (val&0x04) E_Exit("PIC: poll command not handled"); + if (val&0x02) { // function select + if (val&0x01) pic->request_issr=true; /* select read interrupt in-service register */ + else pic->request_issr=false; /* select read interrupt request register */ + } + if (val&0x40) { // special mask select + if (val&0x20) pic->special=true; + else pic->special=false; + if(pic[0].special || pics[1].special) + PIC_Special_Mode = true; else + PIC_Special_Mode = false; + if (PIC_IRQCheck) { //Recheck irqs + CPU_CycleLeft += CPU_Cycles; + CPU_Cycles = 0; } - } //TODO Warnings? - break; - case 0x4a: /* OCW3 select read interrupt request register */ - LOG(LOG_PIC,LOG_NORMAL)("port %X : special OFF",port); - pic->special = false; - pic->request_issr = false; - break; - case 0x60:case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:case 0x67: - /* Spefific EOI 0-7 */ - if (PIC_IRQActive==(irq_base+val-0x60U)) { - irqs[PIC_IRQActive].inservice=false; - PIC_IRQActive=PIC_NOIRQ; - for (i=0; i<=15; i++) { - if (irqs[IRQ_priority_table[i]].inservice) { - PIC_IRQActive=IRQ_priority_table[i]; - break; + LOG(LOG_PIC,LOG_NORMAL)("port %X : special mask %s",port,(pic->special)?"ON":"OFF"); + } + } else { // OCW2 issued + if (val&0x20) { // EOI commands + if (GCC_UNLIKELY(val&0x80)) E_Exit("rotate mode not supported"); + if (val&0x40) { // specific EOI + if (PIC_IRQActive==(irq_base+val-0x60U)) { + irqs[PIC_IRQActive].inservice=false; + PIC_IRQActive=PIC_NOIRQ; + for (i=0; i<=15; i++) { + if (irqs[IRQ_priority_table[i]].inservice) { + PIC_IRQActive=IRQ_priority_table[i]; + break; + } + } } + if (val&0x80); // perform rotation + } else { // nonspecific EOI + if (PIC_IRQActive<(irq_base+8)) { + irqs[PIC_IRQActive].inservice=false; + PIC_IRQActive=PIC_NOIRQ; + for (i=0; i<=15; i++){ + if(irqs[IRQ_priority_table[i]].inservice) { + PIC_IRQActive=IRQ_priority_table[i]; + break; + } + } + } + if (val&0x80); // perform rotation } - }//TODO Warnings? - break; - case 0x68:/* OCW3 select */ - pic->special=true; - LOG(LOG_PIC,LOG_NORMAL)("port %X : special ON",port); - break; - case 0x6b: /* OCW3 select read interrupt in-service register */ - LOG(LOG_PIC,LOG_NORMAL)("port %X : special ON",port); - pic->special = true; - pic->request_issr = true; - break; - case 0xC0:case 0xC1:case 0xC2:case 0xC3:case 0xC4:case 0xC5:case 0xC6:case 0xC7: - /* Priority order, no need for it */ - break; - case 0x00:case 0x80: /* Rotate stuff in eoi mode */ - /* We can live without it for now. (7 cities of gold) */ - LOG(LOG_PIC,LOG_NORMAL)("port %X : ignoring rotate stuff.",port); - break; - default: - E_Exit("PIC:Unhandled command %02X",val); - } + } else { + if ((val&0x40)==0) { // rotate in auto EOI mode + if (val&0x80) pic->rotate_on_auto_eoi=true; + else pic->rotate_on_auto_eoi=false; + } else if (val&0x80) { + LOG(LOG_PIC,LOG_NORMAL)("set priority command not handled"); + } // else NOP command + } + } // end OCW2 } static void write_data(Bitu port,Bitu val,Bitu iolen) { PIC_Controller * pic=&pics[port==0x21 ? 0 : 1]; Bitu irq_base=(port==0x21) ? 0 : 8; Bitu i; + bool old_irq2_mask = irqs[2].masked; switch(pic->icw_index) { case 0: /* mask register */ LOG(LOG_PIC,LOG_NORMAL)("%d mask %X",port==0x21 ? 0 : 1,val); for (i=0;i<=7;i++) { irqs[i+irq_base].masked=(val&(1<0; - if (irqs[i+irq_base].active && !irqs[i+irq_base].masked) PIC_IRQCheck|=(1 << (i+irq_base)); - else PIC_IRQCheck&=~(1 << (i+irq_base)); - }; -#if 0 + if(port==0x21) { + if (irqs[i+irq_base].active && !irqs[i+irq_base].masked) PIC_IRQCheck|=(1 << (i+irq_base)); + else PIC_IRQCheck&=~(1 << (i+irq_base)); + } else { + if (irqs[i+irq_base].active && !irqs[i+irq_base].masked && !irqs[2].masked) PIC_IRQCheck|=(1 << (i+irq_base)); + else PIC_IRQCheck&=~(1 << (i+irq_base)); + } + } + if (machine==MCH_PCJR) { + /* irq6 cannot be disabled as it serves as pseudo-NMI */ + irqs[6].masked=false; + } + if(irqs[2].masked != old_irq2_mask) { + /* Irq 2 mask has changed recheck second pic */ + for(i=8;i<=15;i++) { + if (irqs[i].active && !irqs[i].masked && !irqs[2].masked) PIC_IRQCheck|=(1 << (i)); + else PIC_IRQCheck&=~(1 << (i)); + } + } if (PIC_IRQCheck) { CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=0; } -#endif break; case 1: /* icw2 */ LOG(LOG_PIC,LOG_NORMAL)("%d:Base vector %X",port==0x21 ? 0 : 1,val); @@ -166,6 +183,7 @@ static void write_data(Bitu port,Bitu val,Bitu iolen) { irqs[i+irq_base].vector=(val&0xf8)+i; }; if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; + else if(pic->single) pic->icw_index=3; /* skip ICW3 in single mode */ break; case 2: /* icw 3 */ LOG(LOG_PIC,LOG_NORMAL)("%d:ICW 3 %X",port==0x21 ? 0 : 1,val); @@ -174,7 +192,7 @@ static void write_data(Bitu port,Bitu val,Bitu iolen) { case 3: /* icw 4 */ /* 0 1 8086/8080 0 mcs-8085 mode - 1 1 Auto EOI 1 Normal EOI + 1 1 Auto EOI 0 Normal EOI 2-3 0x Non buffer Mode 10 Buffer Mode Slave 11 Buffer mode Master @@ -183,9 +201,13 @@ static void write_data(Bitu port,Bitu val,Bitu iolen) { pic->auto_eoi=(val & 0x2)>0; LOG(LOG_PIC,LOG_NORMAL)("%d:ICW 4 %X",port==0x21 ? 0 : 1,val); + + if ((val&0x01)==0) E_Exit("PIC:ICW4: %x, 8085 mode not handled",val); + if ((val&0x10)!=0) E_Exit("PIC:ICW4: %x, special fully-nested mode not handled",val); + if(pic->icw_index++ >= pic->icw_words) pic->icw_index=0; break; - default: /* icw 3, and 4*/ + default: LOG(LOG_PIC,LOG_NORMAL)("ICW HUH? %X",val); } } @@ -222,11 +244,16 @@ static Bitu read_data(Bitu port,Bitu iolen) { void PIC_ActivateIRQ(Bitu irq) { - if (irq<16) { - irqs[irq].active=true; + if( irq < 8 ) { + irqs[irq].active = true; if (!irqs[irq].masked) { PIC_IRQCheck|=(1 << irq); } + } else if (irq < 16) { + irqs[irq].active = true; + if (!irqs[irq].masked && !irqs[2].masked) { + PIC_IRQCheck|=(1 << irq); + } } } @@ -236,39 +263,86 @@ void PIC_DeActivateIRQ(Bitu irq) { PIC_IRQCheck&=~(1 << irq); } } +static inline bool PIC_startIRQ(Bitu i) { + /* irqs on second pic only if irq 2 isn't masked */ + if( i > 7 && irqs[2].masked) return false; + irqs[i].active = false; + PIC_IRQCheck&= ~(1 << i); + CPU_HW_Interrupt(irqs[i].vector); + Bitu pic=(i&8)>>3; + if (!pics[pic].auto_eoi) { //irq 0-7 => pic 0 else pic 1 + PIC_IRQActive = i; + irqs[i].inservice = true; + } else if (pics[pic].rotate_on_auto_eoi) { + E_Exit("rotate on auto EOI not handled"); + } + return true; +} void PIC_runIRQs(void) { - Bitu i; if (!GETFLAG(IF)) return; if (!PIC_IRQCheck) return; - Bit16u IRQ_priority_lookup[17] = + + static Bitu IRQ_priority_order[16] = + { 0,1,2,8,9,10,11,12,13,14,15,3,4,5,6,7 }; + static Bit16u IRQ_priority_lookup[17] = { 0,1,2,11,12,13,14,15,3,4,5,6,7,8,9,10,16 }; Bit16u activeIRQ = PIC_IRQActive; - if (activeIRQ==PIC_NOIRQ) activeIRQ = 16; - for (i=0;i<=15;i++) { - if ((IRQ_priority_lookup[i]>3) ].special) ) { + if (!irqs[i].masked && irqs[i].active) { + /* the irq line is active. it's not masked and + * the irq is allowed priority wise. So let's start it */ + /* If started succesfully return, else go for the next */ + if(PIC_startIRQ(i)) return; } - return; } } } } void PIC_SetIRQMask(Bitu irq, bool masked) { + if(irqs[irq].masked == masked) return; /* Do nothing if mask doesn't change */ + bool old_irq2_mask = irqs[2].masked; irqs[irq].masked=masked; - if (irqs[irq].active && !irqs[irq].masked) { - PIC_IRQCheck|=(1 << (irq)); - } else { - PIC_IRQCheck&=~(1 << (irq)); - }; + if(irq < 8) { + if (irqs[irq].active && !irqs[irq].masked) { + PIC_IRQCheck|=(1 << (irq)); + } else { + PIC_IRQCheck&=~(1 << (irq)); + } + } else { + if (irqs[irq].active && !irqs[irq].masked && !irqs[2].masked) { + PIC_IRQCheck|=(1 << (irq)); + } else { + PIC_IRQCheck&=~(1 << (irq)); + } + } + if(irqs[2].masked != old_irq2_mask) { + /* Irq 2 mask has changed recheck second pic */ + for(Bitu i=8;i<=15;i++) { + if (irqs[i].active && !irqs[i].masked && !irqs[2].masked) PIC_IRQCheck|=(1 << (i)); + else PIC_IRQCheck&=~(1 << (i)); + } + } if (PIC_IRQCheck) { CPU_CycleLeft+=CPU_Cycles; CPU_Cycles=0; @@ -378,6 +452,20 @@ bool PIC_RunQueue(void) { return true; } +//Irq 9-2 calling code +static Bitu INT71_Handler() { + IO_Write(0xa0,0x61); + CALLBACK_RunRealInt(0xa); + return CBRET_NONE; +} + +static Bitu INT0A_Handler() { + IO_Write(0x20,0x62); + return CBRET_NONE; +} + + + /* The TIMER Part */ struct TickerBlock { TIMER_TickHandler handler; @@ -430,54 +518,81 @@ void TIMER_AddTick(void) { } +class PIC:public Module_base{ +private: + IO_ReadHandleObject ReadHandler[4]; + IO_WriteHandleObject WriteHandler[4]; + CALLBACK_HandlerObject callback[2]; +public: + PIC(Section* configuration):Module_base(configuration){ + /* Setup pic0 and pic1 with initial values like DOS has normally */ + PIC_IRQCheck=0; + PIC_IRQActive=PIC_NOIRQ; + PIC_Ticks=0; + Bitu i; + for (i=0;i<2;i++) { + pics[i].masked=0xff; + pics[i].active=0; + pics[i].inservice=0; + pics[i].auto_eoi=false; + pics[i].rotate_on_auto_eoi=false; + pics[i].request_issr=false; + pics[i].special=false; + pics[i].single=false; + pics[i].icw_index=0; + pics[i].icw_words=0; + } + for (i=0;i<=7;i++) { + irqs[i].active=false; + irqs[i].masked=true; + irqs[i].inservice=false; + irqs[i+8].active=false; + irqs[i+8].masked=true; + irqs[i+8].inservice=false; + irqs[i].vector=0x8+i; + irqs[i+8].vector=0x70+i; + } + irqs[0].masked=false; /* Enable system timer */ + irqs[1].masked=false; /* Enable Keyboard IRQ */ + irqs[2].masked=false; /* Enable second pic */ + irqs[8].masked=false; /* Enable RTC IRQ */ + if (machine==MCH_PCJR) { + /* Enable IRQ6 (replacement for the NMI for PCJr) */ + irqs[6].masked=false; + } + ReadHandler[0].Install(0x20,read_command,IO_MB); + ReadHandler[1].Install(0x21,read_data,IO_MB); + WriteHandler[0].Install(0x20,write_command,IO_MB); + WriteHandler[1].Install(0x21,write_data,IO_MB); + ReadHandler[2].Install(0xa0,read_command,IO_MB); + ReadHandler[3].Install(0xa1,read_data,IO_MB); + WriteHandler[2].Install(0xa0,write_command,IO_MB); + WriteHandler[3].Install(0xa1,write_data,IO_MB); + /* Initialize the pic queue */ + for (i=0;iAddDestroyFunction(&PIC_Destroy); } - - diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index 319f2b9..444d719 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include +/* $Id: sblaster.cpp,v 1.53 2006/03/13 20:01:55 qbix79 Exp $ */ + #include #include #include "dosbox.h" @@ -27,7 +28,10 @@ #include "hardware.h" #include "setup.h" #include "support.h" -#include "programs.h" +#include "shell.h" + +void MIDI_RawOutByte(Bit8u data); +bool MIDI_Available(void); #define SB_PIC_EVENTS 0 @@ -95,10 +99,10 @@ struct SB_INFO { Bitu remain_size; } dma; bool speaker; + bool midi; Bit8u time_constant; DSP_MODES mode; SB_TYPES type; - OPL_Mode oplmode; struct { bool pending_8bit; bool pending_16bit; @@ -128,6 +132,7 @@ struct SB_INFO { bool stereo; bool enabled; bool filtered; + Bit8u unhandled[0x48]; } mixer; struct { Bit8u reference; @@ -156,7 +161,7 @@ static Bit8u DSP_cmd_len[256] = { 0,0,0,0, 0,2,0,0, 0,0,0,0, 0,0,0,0, // 0x00 1,0,0,0, 2,0,2,2, 0,0,0,0, 0,0,0,0, // 0x10 0,0,0,0, 2,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30 + 0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0, // 0x30 1,2,2,0, 0,0,0,0, 2,0,0,0, 0,0,0,0, // 0x40 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50 @@ -197,6 +202,7 @@ static void GenerateDMASound(Bitu size); static void DSP_SetSpeaker(bool how) { if (sb.speaker==how) return; sb.speaker=how; + if (sb.type==SBT_16) return; sb.chan->Enable(how); if (sb.speaker) { PIC_RemoveEvents(DMA_Silent_Event); @@ -243,54 +249,108 @@ static void DSP_DMA_CallBack(DmaChannel * chan, DMAEvent event) { } } -#define MIN_ADAPTIVE_STEP_SIZE 511 +#define MIN_ADAPTIVE_STEP_SIZE 0 #define MAX_ADAPTIVE_STEP_SIZE 32767 #define DC_OFFSET_FADE 254 -static INLINE Bits Clip(Bits sample) { - if (sample>MAX_AUDIO) return MAX_AUDIO; - if (sample 63)) { + LOG(LOG_SB,LOG_ERROR)("Bad ADPCM-4 sample"); + if(samp < 0 ) samp = 0; + if(samp > 63) samp = 63; } - scale = max(2, min(6, scaleMap[sample & 0x07])); + + Bits ref = reference + scaleMap[samp]; + if (ref > 0xff) reference = 0xff; + else if (ref < 0x00) reference = 0x00; + else reference = ref; + scale = (scale + adjustMap[samp]) & 0xff; + return reference; } static INLINE Bit8u decode_ADPCM_2_sample(Bit8u sample,Bit8u & reference,Bits& scale) { - static Bits scaleMap[8] = { -2, -1, 0, 0, 1, 1, 1, 1 }; + static const Bit8s scaleMap[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 + }; + static const Bit8u adjustMap[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 + }; - if (sample & 0x02) { - reference = max(0x00, reference - ((sample & 0x01) << (scale+2))); - } else { - reference = min(0xff, reference + ((sample & 0x01) << (scale+2))); + Bits samp = sample + scale; + if ((samp < 0) || (samp > 23)) { + LOG(LOG_SB,LOG_ERROR)("Bad ADPCM-2 sample"); + if(samp < 0 ) samp = 0; + if(samp > 23) samp = 23; } - scale = max(2, min(6, scaleMap[sample & 0x07])); + + Bits ref = reference + scaleMap[samp]; + if (ref > 0xff) reference = 0xff; + else if (ref < 0x00) reference = 0x00; + else reference = ref; + scale = (scale + adjustMap[samp]) & 0xff; + return reference; } INLINE Bit8u decode_ADPCM_3_sample(Bit8u sample,Bit8u & reference,Bits& scale) { - static Bits scaleMap[8] = { -2, -1, 0, 0, 1, 1, 1, 1 }; + static const Bit8s scaleMap[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 + }; + static const Bit8u adjustMap[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 + }; - if (sample & 0x04) { - reference = max(0x00, reference - ((sample & 0x03) << (scale+1))); - } else { - reference = min(0xff, reference + ((sample & 0x03) << (scale+1))); + Bits samp = sample + scale; + if ((samp < 0) || (samp > 39)) { + LOG(LOG_SB,LOG_ERROR)("Bad ADPCM-3 sample"); + if(samp < 0 ) samp = 0; + if(samp > 39) samp = 39; } - scale = max(2, min(6, scaleMap[sample & 0x07])); + + Bits ref = reference + scaleMap[samp]; + if (ref > 0xff) reference = 0xff; + else if (ref < 0x00) reference = 0x00; + else reference = ref; + scale = (scale + adjustMap[samp]) & 0xff; + return reference; } static void GenerateDMASound(Bitu size) { - Bitu read;Bitu done=0;Bitu i=0; + Bitu read=0;Bitu done=0;Bitu i=0; if (sb.dma.left<=sb.dma.min) { size=sb.dma.left; } @@ -322,7 +382,7 @@ static void GenerateDMASound(Bitu size) { for (;i> 5) & 0x7,sb.adpcm.reference,sb.adpcm.stepsize); MixTemp[done++]=decode_ADPCM_3_sample((sb.dma.buf.b8[i] >> 2) & 0x7,sb.adpcm.reference,sb.adpcm.stepsize); - MixTemp[done++]=decode_ADPCM_2_sample((sb.dma.buf.b8[i] >> 0) & 0x3,sb.adpcm.reference,sb.adpcm.stepsize); + MixTemp[done++]=decode_ADPCM_3_sample((sb.dma.buf.b8[i] & 0x3) << 1,sb.adpcm.reference,sb.adpcm.stepsize); } sb.chan->AddSamples_m8(done,MixTemp); break; @@ -442,7 +502,7 @@ static void END_DMA_Event(Bitu val) { static void CheckDMAEnd(void) { if (!sb.dma.left) return; - if (!sb.speaker) { + if (!sb.speaker && sb.type!=SBT_16) { Bitu bigger=(sb.dma.left > sb.dma.min) ? sb.dma.min : sb.dma.left; float delay=(bigger*1000.0f)/sb.dma.rate; PIC_AddEvent(DMA_Silent_Event,delay,bigger); @@ -464,7 +524,7 @@ static void DSP_RaiseIRQEvent(Bitu val) { SB_RaiseIRQ(SB_IRQ_8); } -static void DSP_DoDMATranfser(DMA_MODES mode,Bitu freq,bool stereo) { +static void DSP_DoDMATransfer(DMA_MODES mode,Bitu freq,bool stereo) { char * type; sb.mode=MODE_DMA_MASKED; sb.chan->FillUp(); @@ -522,8 +582,8 @@ static void DSP_DoDMATranfser(DMA_MODES mode,Bitu freq,bool stereo) { static void DSP_PrepareDMA_Old(DMA_MODES mode,bool autoinit) { sb.dma.autoinit=autoinit; if (!autoinit) sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8); - sb.dma.chan=DmaChannels[sb.hw.dma8]; - DSP_DoDMATranfser(mode,sb.freq / (sb.mixer.stereo ? 2 : 1),sb.mixer.stereo); + sb.dma.chan=GetDMAChannel(sb.hw.dma8); + DSP_DoDMATransfer(mode,sb.freq / (sb.mixer.stereo ? 2 : 1),sb.mixer.stereo); } static void DSP_PrepareDMA_New(DMA_MODES mode,Bitu length,bool autoinit,bool stereo) { @@ -531,14 +591,14 @@ static void DSP_PrepareDMA_New(DMA_MODES mode,Bitu length,bool autoinit,bool ste sb.dma.total=length; sb.dma.autoinit=autoinit; if (mode==DSP_DMA_16) { - if (sb.hw.dma16!=0xff) sb.dma.chan=DmaChannels[sb.hw.dma16]; + if (sb.hw.dma16!=0xff) sb.dma.chan=GetDMAChannel(sb.hw.dma16); else { - sb.dma.chan=DmaChannels[sb.hw.dma8]; + sb.dma.chan=GetDMAChannel(sb.hw.dma8); mode=DSP_DMA_16_ALIASED; freq/=2; } - } else sb.dma.chan=DmaChannels[sb.hw.dma8]; - DSP_DoDMATranfser(mode,freq,stereo); + } else sb.dma.chan=GetDMAChannel(sb.hw.dma8); + DSP_DoDMATransfer(mode,freq,stereo); } @@ -576,7 +636,7 @@ static void DSP_Reset(void) { sb.irq.pending_8bit=false; sb.irq.pending_16bit=false; sb.chan->SetFreq(22050); - DSP_SetSpeaker(false); +// DSP_SetSpeaker(false); PIC_RemoveEvents(END_DMA_Event); } @@ -596,23 +656,28 @@ static void DSP_DoReset(Bit8u val) { static void DSP_E2_DMA_CallBack(DmaChannel * chan, DMAEvent event) { if (event==DMA_UNMASKED) { Bit8u val=sb.e2.value; - DmaChannels[sb.hw.dma8]->Register_Callback(0); - DmaChannels[sb.hw.dma8]->Write(1,&val); + DmaChannel * chan=GetDMAChannel(sb.hw.dma8); + chan->Register_Callback(0); + chan->Write(1,&val); } } static void DSP_ADC_CallBack(DmaChannel * chan, DMAEvent event) { if (event!=DMA_UNMASKED) return; Bit8u val=128; + DmaChannel * ch=GetDMAChannel(sb.hw.dma8); while (sb.dma.left--) { - DmaChannels[sb.hw.dma8]->Write(1,&val); + ch->Write(1,&val); } SB_RaiseIRQ(SB_IRQ_8); - DmaChannels[sb.hw.dma8]->Register_Callback(0); + ch->Register_Callback(0); } Bitu DEBUG_EnableDebugger(void); +#define DSP_SB16_ONLY if (sb.type != SBT_16) { LOG(LOG_SB,LOG_ERROR)("DSP:Command %2X requires SB16",sb.dsp.cmd); break; } +#define DSP_SB2_ABOVE if (sb.type <= SBT_1) { LOG(LOG_SB,LOG_ERROR)("DSP:Command %2X requires SB2 or above",sb.dsp.cmd); break; } + static void DSP_DoCommand(void) { // LOG_MSG("DSP Command %X",sb.dsp.cmd); switch (sb.dsp.cmd) { @@ -630,16 +695,21 @@ static void DSP_DoCommand(void) { case 0x24: /* Singe Cycle 8-Bit DMA ADC */ sb.dma.left=sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8); LOG(LOG_SB,LOG_ERROR)("DSP:Faked ADC for %d bytes",sb.dma.total); - DmaChannels[sb.hw.dma8]->Register_Callback(DSP_ADC_CallBack); + GetDMAChannel(sb.hw.dma8)->Register_Callback(DSP_ADC_CallBack); break; case 0x14: /* Singe Cycle 8-Bit DMA DAC */ case 0x91: /* Singe Cycle 8-Bit DMA High speed DAC */ + /* Note: 0x91 is documented only for DSP ver.2.x and 3.x, not 4.x */ DSP_PrepareDMA_Old(DSP_DMA_8,false); break; case 0x90: /* Auto Init 8-bit DMA High Speed */ case 0x1c: /* Auto Init 8-bit DMA */ + DSP_SB2_ABOVE; /* Note: 0x90 is documented only for DSP ver.2.x and 3.x, not 4.x */ DSP_PrepareDMA_Old(DSP_DMA_8,true); break; + case 0x38: /* Write to SB MIDI Output */ + if (sb.midi == true) MIDI_RawOutByte(sb.dsp.in.data[0]); + break; case 0x40: /* Set Timeconstant */ sb.freq=(1000000 / (256 - sb.dsp.in.data[0])); /* Nasty kind of hack to allow runtime changing of frequency */ @@ -649,15 +719,17 @@ static void DSP_DoCommand(void) { break; case 0x41: /* Set Output Samplerate */ case 0x42: /* Set Input Samplerate */ + DSP_SB16_ONLY; sb.freq=(sb.dsp.in.data[0] << 8) | sb.dsp.in.data[1]; break; case 0x48: /* Set DMA Block Size */ + DSP_SB2_ABOVE; //TODO Maybe check limit for new irq? sb.dma.total=1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8); break; - case 0x75: /* 075h : Single Cycle 4-bit ADPCM Reference */ + case 0x75: /* 075h : Single Cycle 4-bit ADPCM Reference */ sb.adpcm.haveref=true; - case 0x74: /* 074h : Single Cycle 4-bit ADPCM */ + case 0x74: /* 074h : Single Cycle 4-bit ADPCM */ DSP_PrepareDMA_Old(DSP_DMA_4,false); break; case 0x77: /* 077h : Single Cycle 3-bit(2.6bit) ADPCM Reference*/ @@ -674,10 +746,13 @@ static void DSP_DoCommand(void) { PIC_AddEvent(&DSP_RaiseIRQEvent, (1000.0f*(1+sb.dsp.in.data[0]+(sb.dsp.in.data[1] << 8))/sb.freq)); break; - case 0xb0: case 0xb2: case 0xb4: case 0xb6: - case 0xc0: case 0xc2: case 0xc4: case 0xc6: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: + DSP_SB16_ONLY; /* Generic 8/16 bit DMA */ - DSP_SetSpeaker(true); //SB16 always has speaker enabled +// DSP_SetSpeaker(true); //SB16 always has speaker enabled sb.dma.sign=(sb.dsp.in.data[0] & 0x10) > 0; DSP_PrepareDMA_New((sb.dsp.cmd & 0x10) ? DSP_DMA_16 : DSP_DMA_8, 1+sb.dsp.in.data[1]+(sb.dsp.in.data[2] << 8), @@ -685,8 +760,9 @@ static void DSP_DoCommand(void) { (sb.dsp.in.data[0] & 0x20) > 0 ); break; - case 0xd0: /* Halt 8-bit DMA */ case 0xd5: /* Halt 16-bit DMA */ + DSP_SB16_ONLY; + case 0xd0: /* Halt 8-bit DMA */ // DSP_ChangeMode(MODE_NONE); // Games sometimes already program a new dma before stopping, gives noise sb.mode=MODE_DMA_PAUSE; @@ -698,14 +774,24 @@ static void DSP_DoCommand(void) { case 0xd3: /* Disable Speaker */ DSP_SetSpeaker(false); break; - case 0xd4: /* Continue DMA 8-bit*/ + case 0xd8: /* Speaker status */ + DSP_SB2_ABOVE; + DSP_FlushData(); + if (sb.speaker) DSP_AddData(0xff); + else DSP_AddData(0x00); + break; case 0xd6: /* Continue DMA 16-bit */ + DSP_SB16_ONLY; + case 0xd4: /* Continue DMA 8-bit*/ if (sb.mode==MODE_DMA_PAUSE) { sb.mode=MODE_DMA_MASKED; sb.dma.chan->Register_Callback(DSP_DMA_CallBack); } break; + case 0xd9: /* Exit Autoinitialize 16-bit */ + DSP_SB16_ONLY; case 0xda: /* Exit Autoinitialize 8-bit */ + DSP_SB2_ABOVE; /* Set mode to single transfer so it ends with current block */ sb.dma.autoinit=false; //Should stop itself break; @@ -735,7 +821,7 @@ static void DSP_DoCommand(void) { if ((sb.dsp.in.data[0] >> i) & 0x01) sb.e2.value += E2_incr_table[sb.e2.count % 4][i]; sb.e2.value += E2_incr_table[sb.e2.count % 4][8]; sb.e2.count++; - DmaChannels[sb.hw.dma8]->Register_Callback(DSP_E2_DMA_CallBack); + GetDMAChannel(sb.hw.dma8)->Register_Callback(DSP_E2_DMA_CallBack); } break; case 0xe3: /* DSP Copyright */ @@ -756,8 +842,29 @@ static void DSP_DoCommand(void) { case 0xf2: /* Trigger 8bit IRQ */ SB_RaiseIRQ(SB_IRQ_8); break; + case 0xf8: /* Undocumented, pre-SB16 only */ + DSP_FlushData(); + DSP_AddData(0); + break; + case 0x30: case 0x31: + LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented MIDI I/O command %2X",sb.dsp.cmd); + break; + case 0x34: case 0x35: case 0x36: case 0x37: + DSP_SB2_ABOVE; + LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented MIDI UART command %2X",sb.dsp.cmd); + break; + case 0x7d: case 0x7f: case 0x1f: + DSP_SB2_ABOVE; + LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented auto-init DMA ADPCM command %2X",sb.dsp.cmd); + break; + case 0x20: + case 0x2c: + case 0x98: case 0x99: /* Documented only for DSP 2.x and 3.x */ + case 0xa0: case 0xa8: /* Documented only for DSP 3.x */ + LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented input command %2X",sb.dsp.cmd); + break; default: - LOG(LOG_SB,LOG_ERROR)("DSP:Unhandled command %2X",sb.dsp.cmd); + LOG(LOG_SB,LOG_ERROR)("DSP:Unhandled (undocumented) command %2X",sb.dsp.cmd); break; } sb.dsp.cmd=DSP_NO_COMMAND; @@ -781,7 +888,8 @@ static void DSP_DoWrite(Bit8u val) { } static Bit8u DSP_ReadData(void) { - Bit8u data=0; +/* Static so it repeats the last value on succesive reads (JANGLE DEMO) */ + static Bit8u data = 0; if (sb.dsp.out.used) { data=sb.dsp.out.data[sb.dsp.out.pos]; sb.dsp.out.pos++; @@ -816,6 +924,10 @@ static void CTMIXER_Reset(void) { static void CTMIXER_Write(Bit8u val) { switch (sb.mixer.index) { + case 0x00: /* Reset */ + CTMIXER_Reset(); + LOG(LOG_SB,LOG_WARN)("Mixer reset value %x",val); + break; case 0x02: /* Master Voulme (SBPRO) Obsolete? */ case 0x22: /* Master Volume (SBPRO) */ SETPROVOL(sb.mixer.master,val); @@ -825,9 +937,11 @@ static void CTMIXER_Write(Bit8u val) { CTMIXER_UpdateVolumes(); break; case 0x06: /* FM output selection, Somewhat obsolete with dual OPL SBpro */ - SETPROVOL(sb.mixer.fm,val); - sb.mixer.fm[1]=sb.mixer.fm[0]; + //SETPROVOL(sb.mixer.fm,val); + //volume controls both channels + sb.mixer.fm[0]=sb.mixer.fm[1] = 0x1| ((val&0x0f)<<1); CTMIXER_UpdateVolumes(); + if(val&0x60) LOG(LOG_SB,LOG_WARN)("Turned FM one channel off. not implemented %X",val); //TODO Change FM Mode if only 1 fm channel is selected break; case 0x0a: /* Mic Level */ @@ -867,6 +981,10 @@ static void CTMIXER_Write(Bit8u val) { LOG(LOG_SB,LOG_NORMAL)("Mixer select dma8:%x dma16:%x",sb.hw.dma8,sb.hw.dma16); break; default: + if ((sb.type == SBT_2 && sb.mixer.index==0x08) || /* CD volume on SB2 */ + ((sb.type == SBT_PRO1 || sb.type == SBT_PRO2) && sb.mixer.index==0x0c) || /* Input control on SBPro */ + (sb.type == SBT_16 && sb.mixer.index >= 0x30 && sb.mixer.index <= 0x47)) /* New SB16 registers */ + sb.mixer.unhandled[sb.mixer.index] = val; LOG(LOG_SB,LOG_WARN)("MIXER:Write %X to unhandled index %X",val,sb.mixer.index); } } @@ -884,7 +1002,7 @@ static Bit8u CTMIXER_Read(void) { case 0x22: /* Master Volume (SBPRO) */ return MAKEPROVOL(sb.mixer.master); case 0x04: /* DAC Volume (SBPRO) */ - return MAKEPROVOL(sb.mixer.dac); + return MAKEPROVOL(sb.mixer.dac); // case 0x06: /* FM output selection, Somewhat obsolete with dual OPL SBpro */ case 0x0a: /* Mic Level (SBPRO) */ return (sb.mixer.mic >> 1); @@ -920,8 +1038,13 @@ static Bit8u CTMIXER_Read(void) { return (sb.irq.pending_8bit ? 0x1 : 0) | (sb.irq.pending_16bit ? 0x2 : 0); default: /* IRQ Status */ + if ((sb.type == SBT_2 && sb.mixer.index==0x08) || /* CD volume on SB2 */ + ((sb.type == SBT_PRO1 || sb.type == SBT_PRO2) && sb.mixer.index==0x0c) || /* Input control on SBPro */ + (sb.type == SBT_16 && sb.mixer.index >= 0x30 && sb.mixer.index <= 0x47)) /* New SB16 registers */ + ret = sb.mixer.unhandled[sb.mixer.index]; + else + ret=0xa; LOG(LOG_SB,LOG_WARN)("MIXER:Read from unhandled index %X",sb.mixer.index); - ret=0xa; } return ret; } @@ -1012,80 +1135,142 @@ static void SBLASTER_CallBack(Bitu len) { break; } } +class SBLASTER: public Module_base { +private: + /* Data */ + IO_ReadHandleObject ReadHandler[0x10]; + IO_WriteHandleObject WriteHandler[0x10]; + AutoexecObject autoexecline; + MixerObject MixerChan; -void SBLASTER_Init(Section* sec) { - Bitu i; - Section_prop * section=static_cast(sec); - const char * sbtype=section->Get_string("type"); - sb.hw.base=section->Get_hex("base"); - sb.hw.irq=section->Get_int("irq"); - sb.hw.dma8=section->Get_int("dma"); - sb.hw.dma16=section->Get_int("hdma"); - sb.mixer.enabled=section->Get_bool("mixer"); - sb.mixer.stereo=false; - if (!strcasecmp(sbtype,"sb1")) sb.type=SBT_1; - else if (!strcasecmp(sbtype,"sb2")) sb.type=SBT_2; - else if (!strcasecmp(sbtype,"sbpro1")) sb.type=SBT_PRO1; - else if (!strcasecmp(sbtype,"sbpro2")) sb.type=SBT_PRO2; - else if (!strcasecmp(sbtype,"sb16")) sb.type=SBT_16; - else if (!strcasecmp(sbtype,"none")) sb.type=SBT_NONE; - else sb.type=SBT_16; - - if (machine!=MCH_VGA && sb.type==SBT_16) sb.type=SBT_PRO2; + /* Support Functions */ + void Find_Type_And_Opl(Section_prop* config,SB_TYPES& type, OPL_Mode& opl_mode){ + const char * sbtype=config->Get_string("sbtype"); + if (!strcasecmp(sbtype,"sb1")) type=SBT_1; + else if (!strcasecmp(sbtype,"sb2")) type=SBT_2; + else if (!strcasecmp(sbtype,"sbpro1")) type=SBT_PRO1; + else if (!strcasecmp(sbtype,"sbpro2")) type=SBT_PRO2; + else if (!strcasecmp(sbtype,"sb16")) type=SBT_16; + else if (!strcasecmp(sbtype,"none")) type=SBT_NONE; + else type=SBT_16; - /* OPL/CMS Init */ - const char * omode=section->Get_string("oplmode"); - Bitu oplrate=section->Get_int("oplrate"); - OPL_Mode opl_mode; - if (!strcasecmp(omode,"none")) opl_mode=OPL_none; - else if (!strcasecmp(omode,"cms")) opl_mode=OPL_cms; - else if (!strcasecmp(omode,"opl2")) opl_mode=OPL_opl2; - else if (!strcasecmp(omode,"dualopl2")) opl_mode=OPL_dualopl2; - else if (!strcasecmp(omode,"opl3")) opl_mode=OPL_opl3; - /* Else assume auto */ - else { - switch (sb.type) { - case SBT_NONE:opl_mode=OPL_none;break; - case SBT_1:opl_mode=OPL_opl2;break; - case SBT_2:opl_mode=OPL_opl2;break; - case SBT_PRO1:opl_mode=OPL_dualopl2;break; - case SBT_PRO2: - case SBT_16: - opl_mode=OPL_opl3;break; + if (type==SBT_16) { + if ((machine!=MCH_VGA) || !SecondDMAControllerAvailable()) type=SBT_PRO2; } + + /* OPL/CMS Init */ + const char * omode=config->Get_string("oplmode"); + if (!strcasecmp(omode,"none")) opl_mode=OPL_none; + else if (!strcasecmp(omode,"cms")) opl_mode=OPL_cms; + else if (!strcasecmp(omode,"opl2")) opl_mode=OPL_opl2; + else if (!strcasecmp(omode,"dualopl2")) opl_mode=OPL_dualopl2; + else if (!strcasecmp(omode,"opl3")) opl_mode=OPL_opl3; + /* Else assume auto */ + else { + switch (type) { + case SBT_NONE:opl_mode=OPL_none;break; + case SBT_1:opl_mode=OPL_opl2;break; + case SBT_2:opl_mode=OPL_opl2;break; + case SBT_PRO1:opl_mode=OPL_dualopl2;break; + case SBT_PRO2: + case SBT_16: + opl_mode=OPL_opl3;break; + } + } } - switch (opl_mode) { - case OPL_none: - IO_RegisterWriteHandler(0x388,adlib_gusforward,IO_MB); - break; - case OPL_cms: - IO_RegisterWriteHandler(0x388,adlib_gusforward,IO_MB); - CMS_Init(section,sb.hw.base,oplrate); - break; - case OPL_opl2: - CMS_Init(section,sb.hw.base,oplrate); - case OPL_dualopl2: - case OPL_opl3: - OPL_Init(section,sb.hw.base,opl_mode,oplrate); - break; - } - if (sb.type==SBT_NONE) return; - sb.chan=MIXER_AddChannel(&SBLASTER_CallBack,22050,"SB"); - sb.dsp.state=DSP_S_NORMAL; +public: + SBLASTER(Section* configuration):Module_base(configuration) { + Bitu i; + Section_prop * section=static_cast(configuration); + sb.hw.base=section->Get_hex("sbbase"); + sb.hw.irq=section->Get_int("irq"); + sb.hw.dma8=section->Get_int("dma"); + sb.hw.dma16=section->Get_int("hdma"); + sb.mixer.enabled=section->Get_bool("mixer"); + Bitu oplrate=section->Get_int("oplrate"); + sb.mixer.stereo=false; + OPL_Mode opl_mode; + Find_Type_And_Opl(section,sb.type,opl_mode); + + switch (opl_mode) { + case OPL_none: + WriteHandler[0].Install(0x388,adlib_gusforward,IO_MB); + break; + case OPL_cms: + WriteHandler[0].Install(0x388,adlib_gusforward,IO_MB); + CMS_Init(section); + break; + case OPL_opl2: + CMS_Init(section); + case OPL_dualopl2: + case OPL_opl3: + OPL_Init(section,opl_mode); + break; + } + if (sb.type==SBT_NONE) return; + sb.chan=MixerChan.Install(&SBLASTER_CallBack,22050,"SB"); + sb.dsp.state=DSP_S_NORMAL; - for (i=4;i<=0xf;i++) { - if (i==8 || i==9) continue; - //Disable mixer ports for lower soundblaster - if ((sb.type==SBT_1 || sb.type==SBT_2) && (i==4 || i==5)) continue; - IO_RegisterReadHandler(sb.hw.base+i,read_sb,IO_MB); - IO_RegisterWriteHandler(sb.hw.base+i,write_sb,IO_MB); - } - DSP_Reset(); - CTMIXER_Reset(); - char hdma[8]=""; - if (sb.type==SBT_16) { - sprintf(hdma,"H%d ",sb.hw.dma16); - } - SHELL_AddAutoexec("SET BLASTER=A%3X I%d D%d %sT%d",sb.hw.base,sb.hw.irq,sb.hw.dma8,hdma,sb.type); + for (i=4;i<=0xf;i++) { + if (i==8 || i==9) continue; + //Disable mixer ports for lower soundblaster + if ((sb.type==SBT_1 || sb.type==SBT_2) && (i==4 || i==5)) continue; + ReadHandler[i].Install(sb.hw.base+i,read_sb,IO_MB); + WriteHandler[i].Install(sb.hw.base+i,write_sb,IO_MB); + } + DSP_Reset(); + CTMIXER_Reset(); + // The documentation does not specify if SB gets initialized with the speaker enabled + // or disabled. Real SBPro2 has it disabled. + sb.speaker=false; + // On SB16 the speaker flag does not affect actual speaker state. + if (sb.type == SBT_16) sb.chan->Enable(true); + else sb.chan->Enable(false); + + char hdma[8]=""; + if (sb.type==SBT_16) { + sprintf(hdma,"H%d ",sb.hw.dma16); + } + autoexecline.Install("SET BLASTER=A%3X I%d D%d %sT%d",sb.hw.base,sb.hw.irq,sb.hw.dma8,hdma,sb.type); + + /* Soundblaster midi interface */ + if (!MIDI_Available()) sb.midi = false; + else sb.midi = true; + } + + ~SBLASTER() { + Section_prop * section=static_cast(m_configuration); + OPL_Mode opl_mode; + Find_Type_And_Opl(section,sb.type,opl_mode); + + switch (opl_mode) { + case OPL_none: + + break; + case OPL_cms: + + CMS_ShutDown(m_configuration); + break; + case OPL_opl2: + CMS_ShutDown(m_configuration); + case OPL_dualopl2: + case OPL_opl3: + OPL_ShutDown(m_configuration); + break; + } + + if (sb.type==SBT_NONE) return; + DSP_Reset();//Stop everything + } +}; //End of SBLASTER class + + +static SBLASTER* test; +void SBLASTER_ShutDown(Section* sec) { + delete test; } +void SBLASTER_Init(Section* sec) { + test = new SBLASTER(sec); + sec->AddDestroyFunction(&SBLASTER_ShutDown,true); +} diff --git a/src/hardware/serialport.cpp b/src/hardware/serialport.cpp deleted file mode 100644 index 6020b54..0000000 --- a/src/hardware/serialport.cpp +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2002-2004 The DOSBox Team - * - * 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 - -#include "dosbox.h" -#include "inout.h" -#include "mixer.h" -#include "pic.h" -#include "setup.h" -#include "timer.h" -#include "math.h" -#include "regs.h" -#include "serialport.h" - -#define SERIALBASERATE 115200 -#define LOG_UART LOG_MSG - -CSerialList seriallist; - -void CSerial::UpdateBaudrate(void) { - Bitu divsize=(divisor_msb << 8) | divisor_lsb; - if (divsize) { - bps = SERIALBASERATE / divsize; - } -} - - -void CSerial::Timer(void) { - dotxint=true; - checkint(); -} - -void CSerial::checkint(void) { - /* Check which irq to activate */ - //TODO Check for line status changes, but we can't get errors anyway - //Since we only check once every millisecond, we just ignore the fifosize parameter - if ((ier & 0x1) && rqueue->inuse()) { -// LOG_MSG("RX IRQ with %d",rqueue->inuse()); - iir=0x4; - } else if ((ier & 0x2) && !tqueue->inuse() && dotxint) { - iir=0x2; - } else if ((ier & 0x8) && (mstatus & 0x0f)) { - iir=0x0; - } else { - iir=0x1; - PIC_DeActivateIRQ(irq); - return; - } - if (mctrl & 0x8) PIC_ActivateIRQ(irq); - else PIC_DeActivateIRQ(irq); -} - -void CSerial::write_reg(Bitu reg, Bitu val) { -// if (port!=9 && port!=8) LOG_MSG("Serial write %X val %x %c",port,val,val); - switch(reg) { - case 0x8: // Transmit holding buffer + Divisor LSB - if (dlab) { - divisor_lsb = val; - UpdateBaudrate(); - return; - } - if (local_loopback) rqueue->addb(val); - else tqueue->addb(val); - break; - case 0x9: // Interrupt enable register + Divisor MSB - if (dlab) { - divisor_msb = val; - UpdateBaudrate(); - return; - } else { - ier = val; - dotxint=true; - } - break; - case 0xa: // FIFO Control register - FIFOenabled = (val & 0x1) > 0; - if (val & 0x2) rqueue->clear(); //Clear receiver FIFO - if (val & 0x4) tqueue->clear(); //Clear transmit FIFO - if (val & 0x8) LOG(LOG_MISC,LOG_WARN)("UART:Enabled DMA mode"); - switch (val >> 6) { - case 0:FIFOsize = 1;break; - case 1:FIFOsize = 4;break; - case 2:FIFOsize = 8;break; - case 3:FIFOsize = 14;break; - } - break; - case 0xb: // Line control register - linectrl = val; - dlab = (val & 0x80); - break; - case 0xc: // Modem control register - mctrl=val; - local_loopback = (val & 0x10); - break; - case 0xf: // Scratch register - scratch = val; - break; - default: - LOG_UART("Modem: Write to 0x%x, with 0x%x '%c'\n", reg,val,val); - break; - } -} - -static void WriteSerial(Bitu port,Bitu val,Bitu iolen) { - Bitu check=port&~0xf; - for (CSerial_it it=seriallist.begin();it!=seriallist.end();it++){ - CSerial * serial=(*it); - if (check==serial->base) { - serial->write_reg(port&0xf,val); - return; - } - } -} - -static Bitu ReadSerial(Bitu port,Bitu iolen) { - Bitu check=port&~0xf; - - for (CSerial_it it=seriallist.begin();it!=seriallist.end();it++){ - CSerial * serial=(*it); - if (check==serial->base) { - - return serial->read_reg(port&0xf); - } - } - return 0; -} - -void SERIAL_Update(void) { - for (CSerial_it it=seriallist.begin();it!=seriallist.end();it++){ - CSerial * serial=(*it); - serial->Timer(); - } -} - - - -Bitu CSerial::read_reg(Bitu reg) { - Bitu retval; -// if (port!=0xd && port!=0xa) LOG_MSG("REad from port %x",reg); - switch(reg) { - case 0x8: // Receive buffer + Divisor LSB - if (dlab) { - return divisor_lsb ; - } else { - retval=rqueue->getb(); - //LOG_MSG("Received char %x %c",retval,retval); - checkint(); - return retval; - } - case 0x9: // Interrupt enable register + Divisor MSB - if (dlab) { - return divisor_msb ; - } else { - return ier; - } - case 0xa: // Interrupt identification register - retval=iir; - if (iir==2) { - dotxint=false; - iir=1; - } -// LOG_MSG("Read iir %d after %d",retval,iir); - return retval | ((FIFOenabled) ? (3 << 6) : 0); - case 0xb: // Line control register - return linectrl; - case 0xC: // Modem control register - return mctrl; - case 0xD: // Line status register - retval = 0x40; - if (!tqueue->inuse()) retval|=0x20; - if (rqueue->inuse()) retval|= 1; -// LOG_MSG("Read from line status %x",retval); - return retval; - case 0xE: // modem status register - retval=mstatus; - mstatus&=0xf0; - checkint(); - return retval; - case 0xF: // Scratch register - return scratch; - default: - //LOG_DEBUG("Modem: Read from 0x%x\n", port); - break; - } - return 0x00; -} - - -void CSerial::SetModemStatus(Bit8u status) { - status&=0xf; - Bit8u oldstatus=mstatus >> 4; - if (oldstatus ^ status ) { - mstatus=(mstatus & 0xf) | status << 4; - mstatus|=(oldstatus ^ status) & ((status & 0x4) | (0xf-0x4)); - } -} - - -CSerial::CSerial (Bit16u initbase, Bit8u initirq, Bit32u initbps) { - - Bitu i; - Bit16u initdiv; - - base=initbase; - irq=initirq; - bps=initbps; - - local_loopback = 0; - ier = 0; - iir = 1; - - FIFOenabled = false; - FIFOsize = 1; - dlab = 0; - mstatus = 0; - - initdiv = SERIALBASERATE / bps; - UpdateBaudrate(); - - for (i=base;i<=(base+8);i++) { - IO_RegisterWriteHandler(i+8,WriteSerial,IO_MB); - IO_RegisterReadHandler(i+8,ReadSerial,IO_MB); - } - - rqueue=new CFifo(QUEUE_SIZE); - tqueue=new CFifo(QUEUE_SIZE); -}; - -CSerial::~CSerial(void) -{ - -}; - - -void SERIAL_Init(Section* sec) { - unsigned long args = 1; - Section_prop * section=static_cast(sec); - -// if(!section->Get_bool("enabled")) return; - - TIMER_AddTickHandler(&SERIAL_Update); -} - diff --git a/src/hardware/serialport/Makefile.am b/src/hardware/serialport/Makefile.am new file mode 100644 index 0000000..4ae53b2 --- /dev/null +++ b/src/hardware/serialport/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include + +noinst_LIBRARIES = libserial.a + +libserial_a_SOURCES = directserial_win32.cpp directserial_win32.h \ + serialdummy.cpp serialdummy.h serialport.cpp \ + softmodem.cpp softmodem.h \ + directserial_os2.h directserial_os2.cpp diff --git a/src/hardware/serialport/Makefile.in b/src/hardware/serialport/Makefile.in new file mode 100644 index 0000000..4f23a8f --- /dev/null +++ b/src/hardware/serialport/Makefile.in @@ -0,0 +1,418 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +SOURCES = $(libserial_a_SOURCES) + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/hardware/serialport +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libserial_a_AR = $(AR) $(ARFLAGS) +libserial_a_LIBADD = +am_libserial_a_OBJECTS = directserial_win32.$(OBJEXT) \ + serialdummy.$(OBJEXT) serialport.$(OBJEXT) softmodem.$(OBJEXT) \ + directserial_os2.$(OBJEXT) +libserial_a_OBJECTS = $(am_libserial_a_OBJECTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libserial_a_SOURCES) +DIST_SOURCES = $(libserial_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_CONFIG = @SDL_CONFIG@ +SDL_LIBS = @SDL_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +AM_CPPFLAGS = -I$(top_srcdir)/include +noinst_LIBRARIES = libserial.a +libserial_a_SOURCES = directserial_win32.cpp directserial_win32.h \ + serialdummy.cpp serialdummy.h serialport.cpp \ + softmodem.cpp softmodem.h \ + directserial_os2.h directserial_os2.cpp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/hardware/serialport/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/hardware/serialport/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libserial.a: $(libserial_a_OBJECTS) $(libserial_a_DEPENDENCIES) + -rm -f libserial.a + $(libserial_a_AR) libserial.a $(libserial_a_OBJECTS) $(libserial_a_LIBADD) + $(RANLIB) libserial.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/directserial_os2.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/directserial_win32.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serialdummy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serialport.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/softmodem.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/hardware/serialport/directserial_os2.cpp b/src/hardware/serialport/directserial_os2.cpp new file mode 100644 index 0000000..7c47ec6 --- /dev/null +++ b/src/hardware/serialport/directserial_os2.cpp @@ -0,0 +1,418 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: directserial_os2.cpp,v 1.2 2006/02/09 11:47:54 qbix79 Exp $ */ + +#include "dosbox.h" + +#if C_DIRECTSERIAL + + +#if defined(OS2) +#include "serialport.h" +#include "directserial_os2.h" + +// OS/2 related headers +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#define INCL_DOSDEVICES +#define INCL_DOSDEVIOCTL +#define INCL_DOSPROCESS +#include + +/* This is a serial passthrough class. Its amazingly simple to */ +/* write now that the serial ports themselves were abstracted out */ + +CDirectSerial::CDirectSerial (IO_ReadHandler * rh, IO_WriteHandler * wh, + TIMER_TickHandler th, Bit16u baseAddr, Bit8u initIrq, + Bit32u initBps, Bit8u bytesize, const char *parity, + Bit8u stopbits,const char *realPort) + :CSerial (rh, wh, th,baseAddr,initIrq, initBps, + bytesize, parity,stopbits) { + InstallationSuccessful = false; + InstallTimerHandler(th); + lastChance = 0; + LOG_MSG ("OS/2 Serial port at %x: Opening %s", base, realPort); + LOG_MSG("Opening OS2 serial port"); + + ULONG ulAction = 0; + APIRET rc = DosOpen((unsigned char*)realPort, &hCom, &ulAction, 0L, FILE_NORMAL, FILE_OPEN, + OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | OPEN_FLAGS_SEQUENTIAL, 0L); + if (rc != NO_ERROR) + { + LOG_MSG ("Serial port \"%s\" could not be opened.", realPort); + if (rc == 2) { + LOG_MSG ("The specified port does not exist."); + } else if (rc == 99) { + LOG_MSG ("The specified port is already in use."); + } else { + LOG_MSG ("OS/2 error %d occurred.", rc); + } + + hCom = 0; + return; + } + + DCBINFO dcb; + ULONG ulParmLen = sizeof(DCBINFO); + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0, &dcb, ulParmLen, &ulParmLen); + if ( rc != NO_ERROR) + { + DosClose(hCom); + hCom = 0; + return; + } + dcb.usWriteTimeout = 0; + dcb.usReadTimeout = 0; //65535; + dcb.fbTimeout |= 6; + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, ulParmLen, &ulParmLen, 0, 0, 0); + if ( rc != NO_ERROR) + { + DosClose(hCom); + hCom = 0; + return; + } + + CSerial::Init_Registers (initBps, bytesize, parity, stopbits); + InstallationSuccessful = true; + //LOG_MSG("InstSuccess"); +} + +CDirectSerial::~CDirectSerial () { + if (hCom != 0) + DosClose (hCom); +} + +Bitu lastChance; + +void CDirectSerial::RXBufferEmpty () { + ULONG dwRead; + Bit8u chRead; + USHORT errors = 0; + ULONG ulParmLen = sizeof(errors); + + if (lastChance > 0) { + receiveByte (ChanceChar); + lastChance = 0; + } else { + // update RX + if (DosRead (hCom, &chRead, 1, &dwRead) != NO_ERROR) { + if (dwRead != 0) { + //LOG_MSG("UART 0x%x: RX 0x%x", base,chRead); + receiveByte (chRead); + } + } + } + // check for errors + Bit8u errreg = 0; + APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMERROR, 0, 0, 0, &errors, ulParmLen, &ulParmLen); + if (rc != NO_ERROR && errors) + { + if (errors & 8) { + LOG_MSG ("Serial port at 0x%x: line error: framing error.", base); + errreg |= LSR_FRAMING_ERROR_MASK; + } + if (errors & 4) { + LOG_MSG ("Serial port at 0x%x: line error: parity error.", base); + errreg |= LSR_PARITY_ERROR_MASK; + } + } + errors = 0; + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, 0, 0, 0, &errors, ulParmLen, &ulParmLen); + if (rc != NO_ERROR && errors) + { + if (errors & 6) { + LOG_MSG ("Serial port at 0x%x: line error: break received.", base); + errreg |= LSR_RX_BREAK_MASK; + } + } + if (errreg != 0) + { + receiveError (errreg); + } + +} + +/*****************************************************************************/ +/* updatePortConfig is called when emulated app changes the serial port **/ +/* parameters baudrate, stopbits, number of databits, parity. **/ +/*****************************************************************************/ +void CDirectSerial::updatePortConfig (Bit8u dll, Bit8u dlm, Bit8u lcr) { + Bit8u parity = 0; + Bit8u bytelength = 0; + Bit16u baudrate = 0, baud = 0; + + // baud + baudrate = dlm; + baudrate = baudrate << 8; + baudrate |= dll; + if (baudrate <= 0x1) + baud = 115200; + else if (baudrate <= 0x2) + baud = 57600; + else if (baudrate <= 0x3) + baud = 38400; + else if (baudrate <= 0x6) + baud = 19200; + else if (baudrate <= 0xc) + baud = 9600; + else if (baudrate <= 0x18) + baud = 4800; + else if (baudrate <= 0x30) + baud = 2400; + else if (baudrate <= 0x60) + baud = 1200; + else if (baudrate <= 0xc0) + baud = 600; + else if (baudrate <= 0x180) + baud = 300; + else if (baudrate <= 0x417) + baud = 110; + + // I read that windows can handle nonstandard baudrates: + else + baud = 115200 / baudrate; + +#ifdef SERIALPORT_DEBUGMSG + LOG_MSG ("Serial port at %x: new baud rate: %d", base, dcb.BaudRate); +#endif + + struct { + ULONG baud; + BYTE fraction; + } setbaud; + setbaud.baud = baud; + setbaud.fraction = 0; + ULONG ulParmLen = sizeof(setbaud); + APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE, &setbaud, ulParmLen, &ulParmLen, 0, 0, 0); + if (rc != NO_ERROR) + { + } + + + struct { + UCHAR data; + UCHAR parity; + UCHAR stop; + } paramline; + + // byte length + bytelength = lcr & 0x3; + bytelength += 5; + paramline.data = bytelength; + + // parity + parity = lcr & 0x38; + parity = parity >> 3; + switch (parity) { + case 0x1: + paramline.parity = 1; + break; + case 0x3: + paramline.parity = 2; + break; + case 0x5: + paramline.parity = 3; + break; + case 0x7: + paramline.parity = 4; + break; + default: + paramline.parity = 0; + break; + } + + // stopbits + if (lcr & 0x4) { + if (bytelength == 5) + paramline.stop = 1; + else + paramline.stop = 2; + } else { + paramline.stop = 0; + } + + + ulParmLen = sizeof(paramline); + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETLINECTRL, ¶mline, ulParmLen, &ulParmLen, 0, 0, 0); + if ( rc != NO_ERROR) + { + LOG_MSG ("Serial port at 0x%x: API did not like the new values.", base); + } + +} + +void CDirectSerial::updateMSR () { + Bit8u newmsr = 0; + UCHAR dptr = 0; + ULONG ulParmLen = sizeof(dptr); + + APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETMODEMINPUT, &dptr, ulParmLen, &ulParmLen, 0, 0, 0); + if (rc != NO_ERROR) { +#ifdef SERIALPORT_DEBUGMSG +// LOG_MSG ("Serial port at %x: GetCommModemStatus failed!", base); +#endif + //return; + } + if (dptr & 16) + newmsr |= MSR_CTS_MASK; + if (dptr & 32) + newmsr |= MSR_DSR_MASK; + if (dptr & 64) + newmsr |= MSR_RI_MASK; + if (dptr & 128) + newmsr |= MSR_CD_MASK; + changeMSR (newmsr); +} + +void CDirectSerial::transmitByte (Bit8u val) { + // mean bug: with break = 1, WriteFile will never return. + ULONG bytesWritten = 0; + APIRET rc = DosWrite (hCom, &val, 1, &bytesWritten); + if (rc == NO_ERROR && bytesWritten > 0) { + ByteTransmitted (); + //LOG_MSG("UART 0x%x: TX 0x%x", base,val); + } else { + LOG_MSG ("UART 0x%x: NO BYTE WRITTEN!", base); + } +} + +/*****************************************************************************/ +/* setBreak(val) switches break on or off **/ +/*****************************************************************************/ + +void CDirectSerial::setBreak (bool value) { + //#ifdef SERIALPORT_DEBUGMSG + //LOG_MSG("UART 0x%x: Break toggeled: %d", base, value); + //#endif + USHORT error; + ULONG ulParmLen = sizeof(error); + if (value) + DosDevIOCtl (hCom, IOCTL_ASYNC, ASYNC_SETBREAKON, 0,0,0, &error, ulParmLen, &ulParmLen); + else + DosDevIOCtl (hCom, IOCTL_ASYNC, ASYNC_SETBREAKOFF, 0,0,0, &error, ulParmLen, &ulParmLen); +} + +/*****************************************************************************/ +/* updateModemControlLines(mcr) sets DTR and RTS. **/ +/*****************************************************************************/ +void CDirectSerial::updateModemControlLines ( /*Bit8u mcr */ ) { + bool change = false; + DCBINFO dcb; + ULONG ulParmLen = sizeof(dcb); + + DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETDCBINFO, 0, 0, 0, &dcb, ulParmLen, &ulParmLen); + + /*** DTR ***/ + if (CSerial::getDTR ()) { // DTR on + if (dcb.fbCtlHndShake && 3 == 0) { // DTR disabled + dcb.fbCtlHndShake |= 1; + change = true; + } + } else { + if (dcb.fbCtlHndShake && 3 == 1) { // DTR enabled + dcb.fbCtlHndShake &= ~3; + change = true; + } + } + /*** RTS ***/ + if (CSerial::getRTS ()) { // RTS on + if (dcb.fbFlowReplace && 192 == 0) { //RTS disabled + dcb.fbFlowReplace |= 64; + change = true; + } + } else { + if (dcb.fbFlowReplace && 192 == 1) { // RTS enabled + dcb.fbFlowReplace &= ~192; + change = true; + } + } + if (change) + DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_SETDCBINFO, &dcb, ulParmLen, &ulParmLen, 0, 0, 0); +} + +void CDirectSerial::Timer2(void) { + ULONG dwRead = 0; + USHORT errors = 0; + Bit8u chRead = 0; + ULONG ulParmLen = sizeof(errors); + + + if (lastChance == 0) { // lastChance = 0 + if (CanReceiveByte ()) { + if (DosRead (hCom, &chRead, 1, &dwRead)) { + if (dwRead) + receiveByte (chRead); + } + } else { + if (DosRead (hCom, &chRead, 1, &dwRead)) { + if (dwRead) { + ChanceChar = chRead; + lastChance++; + } + } + } + } else if (lastChance > 10) { + receiveByte (0); // this causes RX Overrun now + lastChance = 0; + // empty serial buffer + dwRead = 1; + while (dwRead > 0) { // throw away bytes in buffer + DosRead (hCom, &chRead, 1, &dwRead); + } + } else { // lastChance>0 // already one waiting + if (CanReceiveByte ()) { // chance used + receiveByte (ChanceChar); + lastChance = 0; + } else + lastChance++; + } + + // check for errors + Bit8u errreg = 0; + APIRET rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMERROR, 0, 0, 0, &errors, ulParmLen, &ulParmLen); + if (rc != NO_ERROR && errors) + { + if (errors & 8) { + LOG_MSG ("Serial port at 0x%x: line error: framing error.", base); + errreg |= LSR_FRAMING_ERROR_MASK; + } + if (errors & 4) { + LOG_MSG ("Serial port at 0x%x: line error: parity error.", base); + errreg |= LSR_PARITY_ERROR_MASK; + } + } + errors = 0; + rc = DosDevIOCtl(hCom, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, 0, 0, 0, &errors, ulParmLen, &ulParmLen); + if (rc != NO_ERROR && errors) + { + if (errors & 6) { + LOG_MSG ("Serial port at 0x%x: line error: break received.", base); + errreg |= LSR_RX_BREAK_MASK; + } + } + if (errreg != 0) + { + receiveError (errreg); + } + // update Modem input line states + updateMSR (); +} + +#endif +#endif diff --git a/src/hardware/serialport/directserial_os2.h b/src/hardware/serialport/directserial_os2.h new file mode 100644 index 0000000..9dbf785 --- /dev/null +++ b/src/hardware/serialport/directserial_os2.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: directserial_os2.h,v 1.2 2006/02/09 11:47:54 qbix79 Exp $ */ + +// include guard +#ifndef DOSBOX_DIRECTSERIAL_OS2_H +#define DOSBOX_DIRECTSERIAL_OS2_H + +#include "dosbox.h" + +#if C_DIRECTSERIAL +#if defined(OS2) +#define DIRECTSERIAL_AVAILIBLE +#include "serialport.h" +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#define INCL_DOSDEVICES +#define INCL_DOSDEVIOCTL +#define INCL_DOSPROCESS +#include + +class CDirectSerial : public CSerial { +public: + HFILE hCom; + BOOL fSuccess; + + CDirectSerial( + IO_ReadHandler* rh, + IO_WriteHandler* wh, + TIMER_TickHandler th, + Bit16u baseAddr, + Bit8u initIrq, + Bit32u initBps, + Bit8u bytesize, + const char *parity, + Bit8u stopbits, + const char * realPort + ); + + + ~CDirectSerial(); + + + Bitu lastChance; // If there is no space for new + // received data, it gets a little chance + Bit8u ChanceChar; + + bool CanRecv(void); + bool CanSend(void); + + bool InstallationSuccessful; // check after constructing. If + // something was wrong, delete it right away. + + void RXBufferEmpty(); + + + void updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr); + void updateMSR(); + void transmitByte(Bit8u val); + void setBreak(bool value); + void updateModemControlLines(/*Bit8u mcr*/); + void Timer2(void); + + +}; +#endif // IFDEF + +#endif // C_DIRECTSERIAL +#endif // include guard + diff --git a/src/hardware/serialport/directserial_win32.cpp b/src/hardware/serialport/directserial_win32.cpp new file mode 100644 index 0000000..7464d4e --- /dev/null +++ b/src/hardware/serialport/directserial_win32.cpp @@ -0,0 +1,378 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: directserial_win32.cpp,v 1.3 2006/02/09 11:47:54 qbix79 Exp $ */ + +#include "dosbox.h" + +#if C_DIRECTSERIAL + +/* Windows version */ +#if defined (WIN32) + +#include "serialport.h" +#include "directserial_win32.h" + +// Win32 related headers +#include + +/* This is a serial passthrough class. Its amazingly simple to */ +/* write now that the serial ports themselves were abstracted out */ + +CDirectSerial::CDirectSerial (IO_ReadHandler * rh, IO_WriteHandler * wh, + TIMER_TickHandler th, Bit16u baseAddr, Bit8u initIrq, + Bit32u initBps, Bit8u bytesize, const char *parity, + Bit8u stopbits,const char *realPort) + :CSerial (rh, wh, th,baseAddr,initIrq, initBps, + bytesize, parity,stopbits) { + InstallationSuccessful = false; + InstallTimerHandler(th); + lastChance = 0; + LOG_MSG ("Serial port at %x: Opening %s", base, realPort); + hCom = CreateFile (realPort, GENERIC_READ | GENERIC_WRITE, 0, // must be opened with exclusive-access + NULL, // no security attributes + OPEN_EXISTING, // must use OPEN_EXISTING + 0, // non overlapped I/O + NULL // hTemplate must be NULL for comm devices + ); + + if (hCom == INVALID_HANDLE_VALUE) { + int error = GetLastError (); + LOG_MSG ("Serial port \"%s\" could not be opened.", realPort); + if (error == 2) { + LOG_MSG ("The specified port does not exist."); + } else if (error == 5) { + LOG_MSG ("The specified port is already in use."); + } else { + LOG_MSG ("Windows error %d occurred.", error); + } + + hCom = 0; + return; + } + + fSuccess = GetCommState (hCom, &dcb); + + if (!fSuccess) { + // Handle the error. + LOG_MSG ("GetCommState failed with error %d.\n", GetLastError ()); + hCom = 0; + return; + } + // Configure timeouts to effectively use polling + COMMTIMEOUTS ct; + ct.ReadIntervalTimeout = MAXDWORD; + ct.ReadTotalTimeoutConstant = 0; + ct.ReadTotalTimeoutMultiplier = 0; + ct.WriteTotalTimeoutConstant = 0; + ct.WriteTotalTimeoutMultiplier = 0; + SetCommTimeouts (hCom, &ct); + + CSerial::Init_Registers (initBps, bytesize, parity, stopbits); + InstallationSuccessful = true; + //LOG_MSG("InstSuccess"); +} + +CDirectSerial::~CDirectSerial () { + if (hCom != INVALID_HANDLE_VALUE) + CloseHandle (hCom); +} + +Bitu lastChance; + +void CDirectSerial::RXBufferEmpty () { + DWORD dwRead; + DWORD errors; + Bit8u chRead; + if (lastChance > 0) { + receiveByte (ChanceChar); + lastChance = 0; + } else { + // update RX + if (ReadFile (hCom, &chRead, 1, &dwRead, NULL)) { + if (dwRead != 0) { + //LOG_MSG("UART 0x%x: RX 0x%x", base,chRead); + receiveByte (chRead); + } + } + } + // check for errors + if (ClearCommError (hCom, &errors, NULL)) + if (errors & (CE_BREAK | CE_FRAME | CE_RXPARITY)) { + Bit8u errreg = 0; + if (errors & CE_BREAK) { + LOG_MSG ("Serial port at 0x%x: line error: break received.", base); + errreg |= LSR_RX_BREAK_MASK; + } + if (errors & CE_FRAME) { + LOG_MSG ("Serial port at 0x%x: line error: framing error.", base); + errreg |= LSR_FRAMING_ERROR_MASK; + } + if (errors & CE_RXPARITY) { + LOG_MSG ("Serial port at 0x%x: line error: parity error.", base); + errreg |= LSR_PARITY_ERROR_MASK; + } + receiveError (errreg); + } +} + +/*****************************************************************************/ +/* updatePortConfig is called when emulated app changes the serial port **/ +/* parameters baudrate, stopbits, number of databits, parity. **/ +/*****************************************************************************/ +void CDirectSerial::updatePortConfig (Bit8u dll, Bit8u dlm, Bit8u lcr) { + Bit8u parity = 0; + Bit8u bytelength = 0; + Bit16u baudrate = 0; + + // baud + baudrate = dlm; + baudrate = baudrate << 8; + baudrate |= dll; + if (baudrate <= 0x1) + dcb.BaudRate = CBR_115200; + else if (baudrate <= 0x2) + dcb.BaudRate = CBR_57600; + else if (baudrate <= 0x3) + dcb.BaudRate = CBR_38400; + else if (baudrate <= 0x6) + dcb.BaudRate = CBR_19200; + else if (baudrate <= 0xc) + dcb.BaudRate = CBR_9600; + else if (baudrate <= 0x18) + dcb.BaudRate = CBR_4800; + else if (baudrate <= 0x30) + dcb.BaudRate = CBR_2400; + else if (baudrate <= 0x60) + dcb.BaudRate = CBR_1200; + else if (baudrate <= 0xc0) + dcb.BaudRate = CBR_600; + else if (baudrate <= 0x180) + dcb.BaudRate = CBR_300; + else if (baudrate <= 0x417) + dcb.BaudRate = CBR_110; + + // I read that windows can handle nonstandard baudrates: + else + dcb.BaudRate = 115200 / baudrate; + +#ifdef SERIALPORT_DEBUGMSG + LOG_MSG ("Serial port at %x: new baud rate: %d", base, dcb.BaudRate); +#endif + + // byte length + bytelength = lcr & 0x3; + bytelength += 5; + dcb.ByteSize = bytelength; + + // parity + parity = lcr & 0x38; + parity = parity >> 3; + switch (parity) { + case 0x1: + dcb.Parity = ODDPARITY; + break; + case 0x3: + dcb.Parity = EVENPARITY; + break; + case 0x5: + dcb.Parity = MARKPARITY; + break; + case 0x7: + dcb.Parity = SPACEPARITY; + break; + default: + dcb.Parity = NOPARITY; + break; + } + + // stopbits + if (lcr & 0x4) { + if (bytelength == 5) + dcb.StopBits = ONE5STOPBITS; + else + dcb.StopBits = TWOSTOPBITS; + } else { + dcb.StopBits = ONESTOPBIT; + } + + if (!SetCommState (hCom, &dcb)) + LOG_MSG ("Serial port at 0x%x: API did not like the new values.", base); + //LOG_MSG("Serial port at 0x%x: Port params changed: %d Baud", base,dcb.BaudRate); +} + +void CDirectSerial::updateMSR () { + Bit8u newmsr = 0; + DWORD dptr = 0; + + if (!GetCommModemStatus (hCom, &dptr)) { +#ifdef SERIALPORT_DEBUGMSG +// LOG_MSG ("Serial port at %x: GetCommModemStatus failed!", base); +#endif + //return; + } + if (dptr & MS_CTS_ON) + newmsr |= MSR_CTS_MASK; + if (dptr & MS_DSR_ON) + newmsr |= MSR_DSR_MASK; + if (dptr & MS_RING_ON) + newmsr |= MSR_RI_MASK; + if (dptr & MS_RLSD_ON) + newmsr |= MSR_CD_MASK; + changeMSR (newmsr); +} + +void CDirectSerial::transmitByte (Bit8u val) { + // mean bug: with break = 1, WriteFile will never return. + if((LCR&LCR_BREAK_MASK) == 0) { + + DWORD bytesWritten = 0; + WriteFile (hCom, &val, 1, &bytesWritten, NULL); + if (bytesWritten > 0) { + ByteTransmitted (); + //LOG_MSG("UART 0x%x: TX 0x%x", base,val); + } else { + LOG_MSG ("UART 0x%x: NO BYTE WRITTEN! PORT HANGS NOW!", base); + } + } else { + // have a delay here, it's the only sense of sending + // data with break=1 + Bitu ticks; + Bitu elapsed = 0; + ticks = GetTicks(); + + while(elapsed < 10) { + elapsed = GetTicks() - ticks; + } + ByteTransmitted(); + } +} + +/*****************************************************************************/ +/* setBreak(val) switches break on or off **/ +/*****************************************************************************/ + +void CDirectSerial::setBreak (bool value) { + //#ifdef SERIALPORT_DEBUGMSG + //LOG_MSG("UART 0x%x: Break toggeled: %d", base, value); + //#endif + if (value) + SetCommBreak (hCom); + else + ClearCommBreak (hCom); +} + +/*****************************************************************************/ +/* updateModemControlLines(mcr) sets DTR and RTS. **/ +/*****************************************************************************/ +void CDirectSerial::updateModemControlLines ( /*Bit8u mcr */ ) { + bool change = false; + + /*** DTR ***/ + if (CSerial::getDTR ()) { // DTR on + if (dcb.fDtrControl == DTR_CONTROL_DISABLE) { + dcb.fDtrControl = DTR_CONTROL_ENABLE; + change = true; + } + } else { + if (dcb.fDtrControl == DTR_CONTROL_ENABLE) { + dcb.fDtrControl = DTR_CONTROL_DISABLE; + change = true; + } + } + /*** RTS ***/ + if (CSerial::getRTS ()) { // RTS on + if (dcb.fRtsControl == RTS_CONTROL_DISABLE) { + dcb.fRtsControl = RTS_CONTROL_ENABLE; + change = true; + } + } else { + if (dcb.fRtsControl == RTS_CONTROL_ENABLE) { + dcb.fRtsControl = RTS_CONTROL_DISABLE; + change = true; + } + } + if (change) + SetCommState (hCom, &dcb); +} + +void CDirectSerial::Timer2(void) { + DWORD dwRead = 0; + DWORD errors = 0; + Bit8u chRead = 0; + + + if (lastChance == 0) { // lastChance = 0 + if (CanReceiveByte ()) { + if (ReadFile (hCom, &chRead, 1, &dwRead, NULL)) { + if (dwRead) + receiveByte (chRead); + } + } else { + if (ReadFile (hCom, &chRead, 1, &dwRead, NULL)) { + if (dwRead) { + ChanceChar = chRead; + lastChance++; + } + } + } + } else if (lastChance > 10) { + receiveByte (0); // this causes RX Overrun now + lastChance = 0; + // empty serial buffer + dwRead = 1; + while (dwRead > 0) { // throw away bytes in buffer + ReadFile (hCom, &chRead, 1, &dwRead, NULL); + } + } else { // lastChance>0 // already one waiting + if (CanReceiveByte ()) { // chance used + receiveByte (ChanceChar); + lastChance = 0; + } else + lastChance++; + } + + // check for errors + if (ClearCommError (hCom, &errors, NULL)) + if (errors & (CE_BREAK | CE_FRAME | CE_RXPARITY)) { + Bit8u errreg = 0; + + if (errors & CE_BREAK) { + LOG_MSG ("Serial port at 0x%x: line error: break received.", base); + errreg |= LSR_RX_BREAK_MASK; + } + if (errors & CE_FRAME) { + LOG_MSG ("Serial port at 0x%x: line error: framing error.", base); + errreg |= LSR_FRAMING_ERROR_MASK; + } + if (errors & CE_RXPARITY) { + LOG_MSG ("Serial port at 0x%x: line error: parity error.", base); + errreg |= LSR_PARITY_ERROR_MASK; + } + + receiveError (errreg); + } + // update Modem input line states + updateMSR (); +} + + +#else /*linux and others oneday maybe */ + +#endif +#endif diff --git a/src/hardware/serialport/directserial_win32.h b/src/hardware/serialport/directserial_win32.h new file mode 100644 index 0000000..6025f92 --- /dev/null +++ b/src/hardware/serialport/directserial_win32.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: directserial_win32.h,v 1.2 2006/02/09 11:47:54 qbix79 Exp $ */ + +// include guard +#ifndef DOSBOX_DIRECTSERIAL_WIN32_H +#define DOSBOX_DIRECTSERIAL_WIN32_H + +#include "dosbox.h" + +#if C_DIRECTSERIAL +#ifdef WIN32 + + + +#define DIRECTSERIAL_AVAILIBLE +#include "serialport.h" +#include + +class CDirectSerial : public CSerial { +public: + HANDLE hCom; + DCB dcb; + BOOL fSuccess; + + CDirectSerial( + IO_ReadHandler* rh, + IO_WriteHandler* wh, + TIMER_TickHandler th, + Bit16u baseAddr, + Bit8u initIrq, + Bit32u initBps, + Bit8u bytesize, + const char *parity, + Bit8u stopbits, + const char * realPort + ); + + + ~CDirectSerial(); + + + Bitu lastChance; // If there is no space for new + // received data, it gets a little chance + Bit8u ChanceChar; + + bool CanRecv(void); + bool CanSend(void); + + bool InstallationSuccessful; // check after constructing. If + // something was wrong, delete it right away. + + void RXBufferEmpty(); + + + void updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr); + void updateMSR(); + void transmitByte(Bit8u val); + void setBreak(bool value); + void updateModemControlLines(/*Bit8u mcr*/); + void Timer2(void); + + +}; + +#endif // WIN32 +#endif // C_DIRECTSERIAL +#endif // include guard diff --git a/src/hardware/serialport/serialdummy.cpp b/src/hardware/serialport/serialdummy.cpp new file mode 100644 index 0000000..75636bb --- /dev/null +++ b/src/hardware/serialport/serialdummy.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: serialdummy.cpp,v 1.2 2006/02/09 11:47:54 qbix79 Exp $ */ + +#include "dosbox.h" + +#include "setup.h" +#include "serialdummy.h" +#include "serialport.h" + + +CSerialDummy::CSerialDummy( + IO_ReadHandler* rh, + IO_WriteHandler* wh, + TIMER_TickHandler th, + Bit16u baseAddr, + Bit8u initIrq, + Bit32u initBps, + Bit8u bytesize, + const char* parity, + Bit8u stopbits + ) : CSerial( + rh, wh, th, + baseAddr,initIrq,initBps,bytesize,parity,stopbits) + { + CSerial::Init_Registers(initBps,bytesize,parity,stopbits); + } + +CSerialDummy::~CSerialDummy() { +} + +void CSerialDummy::RXBufferEmpty() { +// no external buffer, not used here +} + +/*****************************************************************************/ +/* updatePortConfig is called when emulated app changes the serial port **/ +/* parameters baudrate, stopbits, number of databits, parity. **/ +/*****************************************************************************/ +void CSerialDummy::updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr) { + //LOG_MSG("Serial port at 0x%x: Port params changed: %d Baud", base,dcb.BaudRate); +} + +void CSerialDummy::updateMSR() { + changeMSR(0); +} + +void CSerialDummy::transmitByte(Bit8u val) { + ByteTransmitted(); + //LOG_MSG("UART 0x%x: TX 0x%x", base,val); +} + +/*****************************************************************************/ +/* setBreak(val) switches break on or off **/ +/*****************************************************************************/ + +void CSerialDummy::setBreak(bool value) { + //LOG_MSG("UART 0x%x: Break toggeled: %d", base, value); +} + +/*****************************************************************************/ +/* updateModemControlLines(mcr) sets DTR and RTS. **/ +/*****************************************************************************/ +void CSerialDummy::updateModemControlLines(/*Bit8u mcr*/) { +} + +void CSerialDummy::Timer2(void) { +} + diff --git a/src/hardware/serialport/serialdummy.h b/src/hardware/serialport/serialdummy.h new file mode 100644 index 0000000..78e9a8c --- /dev/null +++ b/src/hardware/serialport/serialdummy.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: serialdummy.h,v 1.2 2006/02/09 11:47:55 qbix79 Exp $ */ + +#ifndef INCLUDEGUARD_SERIALDUMMY_H +#define INCLUDEGUARD_SERIALDUMMY_H + +#include "serialport.h" + +class CSerialDummy : public CSerial { +public: + + CSerialDummy( + IO_ReadHandler* rh, + IO_WriteHandler* wh, + TIMER_TickHandler th, + Bit16u baseAddr, + Bit8u initIrq, + Bit32u initBps, + Bit8u bytesize, + const char* parity, + Bit8u stopbits + ); + + + ~CSerialDummy(); + bool CanRecv(void); + bool CanSend(void); + void RXBufferEmpty(); + void updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr); + void updateMSR(); + void transmitByte(Bit8u val); + void setBreak(bool value); + void updateModemControlLines(/*Bit8u mcr*/); + void Timer2(void); +}; + +#endif // INCLUDEGUARD diff --git a/src/hardware/serialport/serialport.cpp b/src/hardware/serialport/serialport.cpp new file mode 100644 index 0000000..ed4694f --- /dev/null +++ b/src/hardware/serialport/serialport.cpp @@ -0,0 +1,1100 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: serialport.cpp,v 1.4 2006/02/09 11:47:55 qbix79 Exp $ */ + +#include +#include + +#include "dosbox.h" + +#include "support.h" +#include "inout.h" +#include "pic.h" +#include "setup.h" +#include "timer.h" + +#include "serialport.h" +#include "directserial_win32.h" +#include "directserial_os2.h" +#include "serialdummy.h" +#include "softmodem.h" + +#define LOG_UART LOG_MSG + + +// COM1 - COM4 objects +static CSerial *serial1 = 0; +static CSerial *serial2 = 0; +static CSerial *serial3 = 0; +static CSerial *serial4 = 0; +//static CSerial** serialPortObjects[] = {NULL, &serial1,&serial2,&serial3,&serial4}; + +Bit8u serialGetComnumberByBaseAddress (Bit16u base) { + if (base == COM1_BASE) + return 1; + else if (base == COM2_BASE) + return 2; + else if (base == COM3_BASE) + return 3; + else if (base == COM4_BASE) + return 4; + else + return 255; // send thispointer to nirwana ;) +} + +// Usage of FastDelegates (http://www.codeproject.com/cpp/FastDelegate.asp) +// as I/O-Array would make many of these unneccessary. (member function pointer) + +//Some defines for repeated functions + +#define SERIAL_UPDATE(number) \ +void SERIAL##number##_Update(void) { \ + serial##number->Timer (); \ +} + +#define SERIAL_WRITE_TREE(number) \ +static void SERIAL##number##_Write (Bitu port, Bitu val, Bitu iolen) { \ + switch (port & 0x7) { \ + case THR_OFFSET: \ + serial##number ->Write_THR (val); \ + return; \ + case IER_OFFSET: \ + serial##number ->Write_IER (val); \ + return; \ + case LCR_OFFSET: \ + serial##number ->Write_LCR (val); \ + return; \ + case MCR_OFFSET: \ + serial##number ->Write_MCR (val); \ + return; \ + case MSR_OFFSET: \ + serial##number ->Write_MSR (val); \ + return; \ + case SPR_OFFSET: \ + serial##number ->Write_SPR (val); \ + return; \ + default: \ + serial##number ->Write_reserved (val, port & 0x7); \ + } \ +} + +#define SERIAL_READ_TREE(number) \ +static Bitu SERIAL##number##_Read (Bitu port, Bitu iolen) { \ + switch (port & 0x7) { \ + case RHR_OFFSET: \ + return serial##number ->Read_RHR (); \ + case IER_OFFSET: \ + return serial##number ->Read_IER (); \ + case ISR_OFFSET: \ + return serial##number ->Read_ISR (); \ + case LCR_OFFSET: \ + return serial##number ->Read_LCR (); \ + case MCR_OFFSET: \ + return serial##number ->Read_MCR (); \ + case LSR_OFFSET: \ + return serial##number ->Read_LSR (); \ + case MSR_OFFSET: \ + return serial##number ->Read_MSR (); \ + case SPR_OFFSET: \ + return serial##number ->Read_SPR (); \ + } \ + return 0; \ +} + +//The Functions + +SERIAL_UPDATE(1); +SERIAL_UPDATE(2); +SERIAL_UPDATE(3); +SERIAL_UPDATE(4); + +SERIAL_WRITE_TREE(1); +SERIAL_WRITE_TREE(2); +SERIAL_WRITE_TREE(3); +SERIAL_WRITE_TREE(4); + +SERIAL_READ_TREE(1); +SERIAL_READ_TREE(2); +SERIAL_READ_TREE(3); +SERIAL_READ_TREE(4); + +#undef SERIAL_UPDATE +#undef SERIAL_WRITE_TREE +#undef SERIAL_READ_TREE + +void CSerial::Timer (void) { + //LOG_UART("Serial port at %x: Timer", base); + if (loopback_pending) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Loopback sent back", base); +#endif + loopback_pending = false; + receiveByte (loopback_data); + ByteTransmitted (); + } + Timer2 (); +} + +/*****************************************************************************/ +/* Interrupt control routines **/ +/*****************************************************************************/ +void CSerial::rise (Bit8u priority) { + //LOG_UART("Serial port at %x: Rise priority 0x%x", base, priority); + waiting_interrupts |= priority; + WriteRealIER (IER); +} + +// clears the pending interrupt, triggers other waiting interrupt +void CSerial::clear (Bit8u priority) { + //LOG_UART("Serial port at %x: cleared priority 0x%x", base, priority); + waiting_interrupts &= (~priority); + WriteRealIER (IER); +} + +void CSerial::WriteRealIER (Bit8u data) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: write IER, value 0x%x", base, data); +#endif + data = data & 0xF; // THE UPPER ONES ALWAYS READ 0! NOTHIN' ELSE! + Bit8u old_pending_interrupts = pending_interrupts; + Bit8u difference_pending_interrupts; + + // rise TX AGAIN when present and is being enabled + if ((data & TX_PRIORITY) && (!(IER & TX_PRIORITY))) + if (LSR & LSR_TX_HOLDING_EMPTY_MASK) + waiting_interrupts |= TX_PRIORITY; + + pending_interrupts = waiting_interrupts & data; + if ((difference_pending_interrupts = (pending_interrupts ^ old_pending_interrupts))) { // something in pending interrupts has changed + if (difference_pending_interrupts & pending_interrupts) { // some new bits were set + if (!current_priority) { // activate interrupt.. + if (pending_interrupts & ERROR_PRIORITY) { + current_priority = ERROR_PRIORITY; + ISR = ISR_ERROR_VAL; + } else if (pending_interrupts & RX_PRIORITY) { + current_priority = RX_PRIORITY; + ISR = ISR_RX_VAL; + } else if (pending_interrupts & TX_PRIORITY) { + current_priority = TX_PRIORITY; + ISR = ISR_TX_VAL; + } else if (pending_interrupts & MSR_PRIORITY) { + current_priority = MSR_PRIORITY; + ISR = ISR_MSR_VAL; + } +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Interrupt activated: priority %d", base, current_priority); +#endif + PIC_ActivateIRQ (irq); + }// else the new interrupts were already + // written into pending_interrupts + }// else no new bits were set + + if (difference_pending_interrupts & (~pending_interrupts)) { // some bits were reset + if (pending_interrupts) { // some more are waiting + if (!(current_priority & pending_interrupts)) { // the current interrupt has been cleared + // choose the next one + if (pending_interrupts & ERROR_PRIORITY) { + current_priority = ERROR_PRIORITY; + ISR = ISR_ERROR_VAL; + } else if (pending_interrupts & RX_PRIORITY) { + current_priority = RX_PRIORITY; + ISR = ISR_RX_VAL; + } else if (pending_interrupts & TX_PRIORITY) { + current_priority = TX_PRIORITY; + ISR = ISR_TX_VAL; + } else if (pending_interrupts & MSR_PRIORITY) { + current_priority = MSR_PRIORITY; + ISR = ISR_MSR_VAL; + } + } + } else { + current_priority = NONE_PRIORITY; + ISR = ISR_CLEAR_VAL; + PIC_DeActivateIRQ (irq); +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Interrupt deactivated.", base); +#endif + } + } + } + IER = data; +} + + + +/*****************************************************************************/ +/* Internal register modification **/ +/*****************************************************************************/ +void CSerial::changeMSR (Bit8u data) { + if (!(MCR & MCR_LOOPBACK_Enable_MASK)) { + // see if something changed + if ((MSR & MSR_LINE_MASK) != data) { + Bit8u change = (MSR & MSR_LINE_MASK) ^ data; + // set new deltas + MSR |= (change >> 4); + // set new line states + MSR &= MSR_delta_MASK; + MSR |= data; + rise (MSR_PRIORITY); + } + } +} + +void CSerial::changeMSR_Loopback (Bit8u data) { + // see if something changed + if ((MSR & MSR_LINE_MASK) != data) { + Bit8u change = (MSR & MSR_LINE_MASK) ^ data; + // set new deltas + MSR |= (change >> 4); + // set new line states + MSR &= MSR_delta_MASK; + MSR |= data; + rise (MSR_PRIORITY); + } + +/* + Bit8u temp=MSR; + // look for signal changes + if(temp|=((data&MSR_LINE_MASK)^(MSR&MSR_LINE_MASK))>>4) + { // some signals changed + temp&=MSR_delta_MASK;// clear line states + temp|=(data&MSR_LINE_MASK); // set new line states + + MSR=temp; + rise(MSR_PRIORITY); + } + // else nothing happened*/ +} + +/*****************************************************************************/ +/* Can a byte be received? **/ +/*****************************************************************************/ +bool CSerial::CanReceiveByte() { + return (LSR & LSR_RX_DATA_READY_MASK) == 0; +} + +/*****************************************************************************/ +/* A byte was received **/ +/*****************************************************************************/ +void CSerial::receiveByte (Bit8u data) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: byte received: %d", base, data); +#endif + + if (LSR & LSR_RX_DATA_READY_MASK) { // Overrun error ;o + LOG_UART ("Serial port at %x: RX Overrun!", base, data); + LSR |= LSR_OVERRUN_ERROR_MASK; + rise (ERROR_PRIORITY); + } else { + RHR = data; + LSR |= LSR_RX_DATA_READY_MASK; + rise (RX_PRIORITY); + } +} + +/*****************************************************************************/ +/* A line error was received **/ +/*****************************************************************************/ +void CSerial::receiveError (Bit8u errorword) { + LSR |= errorword; + + rise (ERROR_PRIORITY); +} + +/*****************************************************************************/ +/* ByteTransmitted: When a byte was sent, notify here. **/ +/*****************************************************************************/ +void CSerial::ByteTransmitted () { + if (LSR & LSR_TX_HOLDING_EMPTY_MASK) { // one space was empty + // now both are + LSR |= LSR_TX_EMPTY_MASK; + } else { // both were full, now 1 is empty + if (MCR & MCR_LOOPBACK_Enable_MASK) { // loopback mode + transmitLoopbackByte (THR); + } else { // direct "real" mode + transmitByte (THR); + } + LSR |= LSR_TX_HOLDING_EMPTY_MASK; + } + rise (TX_PRIORITY); +} + +/*****************************************************************************/ +/* Transmit Holding Register, also LSB of Divisor Latch (r/w) **/ +/*****************************************************************************/ +void CSerial::Write_THR (Bit8u data) { + if ((LCR & LCR_DIVISOR_Enable_MASK)) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to DLL value 0x%x", base, data); +#endif + // write to DLL + DLL = data; + updatePortConfig (DLL, DLM, LCR); + } else { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to THR value 0x%x", base, data); +#endif + + // write to THR + clear (TX_PRIORITY); + + if (LSR & LSR_TX_HOLDING_EMPTY_MASK) { // one is empty + if (LSR & LSR_TX_EMPTY_MASK) { // both are empty + LSR &= (~LSR_TX_EMPTY_MASK); + + if (MCR & MCR_LOOPBACK_Enable_MASK) { // loopback mode + transmitLoopbackByte (data); + } else { // direct "real" mode + transmitByte (data); + } + rise (TX_PRIORITY); + } else { // only THR is empty; add byte and clear holding bit + LSR &= (~LSR_TX_HOLDING_EMPTY_MASK); + THR = data; + } + } else { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: TX Overflow!", base); +#endif + // TX overflow; how does real hardware respond to that... I do nothing + } + } +} + + +/*****************************************************************************/ +/* Receive Holding Register, also LSB of Divisor Latch (r/w) **/ +/*****************************************************************************/ +Bitu CSerial::Read_RHR () { + Bit8u retval; + if ((LCR & LCR_DIVISOR_Enable_MASK)) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from DLL value 0x%x", base, DLL); +#endif + return DLL; + } else { + clear (RX_PRIORITY); + LSR &= (~LSR_RX_DATA_READY_MASK); + retval = RHR; + RXBufferEmpty (); // <--- this one changes RHR + +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from RHR value 0x%x", base, retval); +#endif + + return retval; + } +} + +/*****************************************************************************/ +/* Interrupt Enable Register, also MSB of Divisor Latch (r/w) **/ +/*****************************************************************************/ +// Modified by: +// - writing to it. +Bitu CSerial::Read_IER () { + if ((LCR & LCR_DIVISOR_Enable_MASK)) { // IER or MSB? +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from DLM value 0x%x", base, DLM); +#endif + return DLM; + } else { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from IER value 0x%x", base, IER); +#endif + return IER; + } +} + +void CSerial::Write_IER (Bit8u data) { + if ((LCR & LCR_DIVISOR_Enable_MASK)) { // write to DLM +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to DLM value 0x%x", base, data); +#endif + + DLM = data; + updatePortConfig (DLL, DLM, LCR); + } else { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to IER value 0x%x", base, data); +#endif + WriteRealIER (data); + } +} + +/*****************************************************************************/ +/* Interrupt Status Register (r) **/ +/*****************************************************************************/ +// modified by: +// - incoming interrupts +// - loopback mode +Bitu CSerial::Read_ISR () { + Bit8u retval = ISR; + + // clear changes ISR!! mean.. + clear (TX_PRIORITY); +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from ISR value 0x%x", base, retval); +#endif + return retval; +} + +/*****************************************************************************/ +/* Line Control Register (r/w) **/ +/*****************************************************************************/ +// signal decoder configuration: +// - parity, stopbits, word length +// - send break +// - switch between RHR/THR and baud rate registers +// Modified by: +// - writing to it. +Bitu CSerial::Read_LCR () { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from LCR value 0x%x", base, LCR); +#endif + return LCR; +} + +void CSerial::Write_LCR (Bit8u data) { + Bit8u lcr_old = LCR; + LCR = data; +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to LCR value 0x%x", base, data); + + // for debug output + if (((data ^ lcr_old) & LCR_DIVISOR_Enable_MASK) != 0) { + if ((data & LCR_DIVISOR_Enable_MASK) != 0) + LOG_UART ("Serial port at %x: Divisor-mode entered", base); + + else + LOG_UART ("Serial port at %x: Divisor-mode exited", base); + } +#endif + if (((data ^ lcr_old) & LCR_PORTCONFIG_MASK) != 0) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: comm parameters changed", base); +#endif + updatePortConfig (DLL, DLM, LCR); + } + if (((data ^ lcr_old) & LCR_BREAK_MASK) != 0) { + setBreak ((LCR & LCR_BREAK_MASK) != 0); + +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: break toggled: %d", base, + (LCR & LCR_BREAK_MASK) != 0); +#endif + } +} + +/*****************************************************************************/ +/* Modem Control Register (r/w) **/ +/*****************************************************************************/ +// Set levels of RTS and DTR, as well as loopback-mode. +// Modified by: +// - writing to it. +Bitu CSerial::Read_MCR () { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from MCR value 0x%x", base, MCR); +#endif + return MCR; +} + +void CSerial::Write_MCR (Bit8u data) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to MCR value 0x%x", base, data); +#endif + data &= 0x1F; // UPPER BITS ALWAYS 0!!! + + if (MCR & MCR_LOOPBACK_Enable_MASK) + if (data & MCR_LOOPBACK_Enable_MASK) { // was on, is now on + Bit8u param = 0; + + // RTS->CD + // DTR->RI + // OP1->DSR + // OP2->CTS + + if (data & MCR_RTS_MASK) + param |= MSR_CD_MASK; + if (data & MCR_DTR_MASK) + param |= MSR_RI_MASK; + if (data & MCR_OP1_MASK) + param |= MSR_DSR_MASK; + if (data & MCR_OP2_MASK) + param |= MSR_CTS_MASK; + + changeMSR_Loopback (param); + + } else { + MCR = data; + updateModemControlLines (); + // is switched off now + } else { + if (data & MCR_LOOPBACK_Enable_MASK) { // is switched on: + Bit8u par = 0; + if (data & MCR_RTS_MASK) + par |= MSR_CD_MASK; + if (data & MCR_DTR_MASK) + par |= MSR_RI_MASK; + if (data & MCR_OP1_MASK) + par |= MSR_DSR_MASK; + if (data & MCR_OP2_MASK) + par |= MSR_CTS_MASK; + + changeMSR_Loopback (par); + + // go back to empty state + LSR &= (LSR_TX_EMPTY_MASK | LSR_TX_HOLDING_EMPTY_MASK); + + } else { + MCR = data; + updateModemControlLines (); + // loopback is off + } + } + MCR = data; +} + +/*****************************************************************************/ +/* Line Status Register (r) **/ +/*****************************************************************************/ +// errors, tx registers status, rx register status +// modified by: +// - event from real serial port +// - loopback +Bitu CSerial::Read_LSR () { + Bitu retval = LSR; + LSR &= (~LSR_ERROR_MASK); // clear error bits on read + clear (ERROR_PRIORITY); + +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from LSR value 0x%x", base, retval); +#endif + return retval; +} + +void CSerial::Write_MSR (Bit8u val) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to MSR, value 0x%x", base, val); +#endif + MSR &= MSR_LINE_MASK; + MSR |= val & MSR_delta_MASK; +} + +/*****************************************************************************/ +/* Modem Status Register (r) **/ +/*****************************************************************************/ +// Contains status of the control input lines (CD, RI, DSR, CTS) and +// their "deltas": if level changed since last read delta = 1. +// modified by: +// - real values +// - write operation to MCR in loopback mode +Bitu CSerial::Read_MSR () { + Bit8u retval; + if (!(MCR & MCR_LOOPBACK_Enable_MASK)) { + updateMSR (); + } + retval = MSR; + clear (MSR_PRIORITY); + // clear deltas + MSR &= MSR_LINE_MASK; +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from MSR value 0x%x", base, retval); +#endif + return retval; +} + +/*****************************************************************************/ +/* Scratchpad Register (r/w) **/ +/*****************************************************************************/ +// Just a memory register. Not much to do here. +Bitu CSerial::Read_SPR () { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Read from SPR value 0x%x", base, SPR); +#endif + return SPR; +} + +void CSerial::Write_SPR (Bit8u data) { +#ifdef SERIALPORT_DEBUGMSG + LOG_UART ("Serial port at %x: Write to SPR value 0x%x", base, data); +#endif + SPR = data; +} + +/*****************************************************************************/ +/* Write_reserved **/ +/*****************************************************************************/ +void CSerial::Write_reserved (Bit8u data, Bit8u address) { + LOG_UART("Serial port at %x: Write to reserved register, value 0x%x, register %x", base, data, address); +} + +/*****************************************************************************/ +/* Loopback: add byte to loopback buffer; it is received next time Timer **/ +/* function is invoked; (time needed is not emulated correctly, but I don't **/ +/* think this is sooooo important....) **/ +/*****************************************************************************/ +void CSerial::transmitLoopbackByte (Bit8u val) { + //LOG_MSG("Serial port at %x: Loopback requested", base); + loopback_pending = true; + loopback_data = val; +} + +/*****************************************************************************/ +/* MCR Access: returns cirquit state as boolean. **/ +/*****************************************************************************/ +bool CSerial::getDTR () { + return (MCR & MCR_DTR_MASK) != 0; +} + +bool CSerial::getRTS () { + return (MCR & MCR_RTS_MASK) != 0; +} + +/*****************************************************************************/ +/* MSR Access **/ +/*****************************************************************************/ +bool CSerial::getRI () { + return (MSR & MSR_RI_MASK) != 0; +} + +bool CSerial::getCD () { + return (MSR & MSR_CD_MASK) != 0; +} + +bool CSerial::getDSR () { + return (MSR & MSR_DSR_MASK) != 0; +} + +bool CSerial::getCTS () { + return (MSR & MSR_CTS_MASK) != 0; +} + +// these give errors if invoked while loopback mode... but who cares. +void CSerial::setRI (bool value) { + bool compare = ((MSR & MSR_RI_MASK) != 0); + if (value != compare) { + if (value) + MSR |= MSR_RI_MASK; + else + MSR &= (~MSR_RI_MASK); + MSR |= MSR_dRI_MASK; + rise (MSR_PRIORITY); + } + //else no change +} +void CSerial::setDSR (bool value) { + bool compare = ((MSR & MSR_DSR_MASK) != 0); + if (value != compare) { + if (value) + MSR |= MSR_DSR_MASK; + else + MSR &= (~MSR_DSR_MASK); + MSR |= MSR_dDSR_MASK; + rise (MSR_PRIORITY); + } + //else no change +} +void CSerial::setCD (bool value) { + bool compare = ((MSR & MSR_CD_MASK) != 0); + if (value != compare) { + if (value) + MSR |= MSR_CD_MASK; + else + MSR &= (~MSR_CD_MASK); + MSR |= MSR_dCD_MASK; + rise (MSR_PRIORITY); + } + //else no change +} +void CSerial::setCTS (bool value) { + bool compare = ((MSR & MSR_CTS_MASK) != 0); + if (value != compare) { + if (value) + MSR |= MSR_CTS_MASK; + else + MSR &= (~MSR_CTS_MASK); + MSR |= MSR_dCTS_MASK; + rise (MSR_PRIORITY); + } + //else no change +} + +/*****************************************************************************/ +/* Initialisation **/ +/*****************************************************************************/ +void CSerial::Init_Registers (Bit32u initbps, Bit8u bytesize, + const char *parity, Bit8u stopbits) { + Bit8u lcrresult = 0; + Bit16u baudresult = 0; + + RHR = 0; + THR = 0; + IER = 0; + ISR = 0x1; + LCR = 0; + MCR = 0; + LSR = 0x60; + MSR = 0; + + SPR = 0xFF; + + DLL = 0x0; + DLM = 0x0; + + pending_interrupts = 0x0; + current_priority = 0x0; + waiting_interrupts = 0x0; + loopback_pending = false; + + + // make lcr: byte size, parity, stopbits, baudrate + + if (bytesize == 5) + lcrresult |= LCR_DATABITS_5; + else if (bytesize == 6) + lcrresult |= LCR_DATABITS_6; + else if (bytesize == 7) + lcrresult |= LCR_DATABITS_7; + else + lcrresult |= LCR_DATABITS_8; + + if (parity[0] == 'O' || parity[0] == 'o') + lcrresult |= LCR_PARITY_ODD; + else if (parity[0] == 'E' || parity[0] == 'e') + lcrresult |= LCR_PARITY_EVEN; + else if (parity[0] == 'M' || parity[0] == 'm') + lcrresult |= LCR_PARITY_MARK; + else if (parity[0] == 'S' || parity[0] == 's') + lcrresult |= LCR_PARITY_SPACE; + else + lcrresult |= LCR_PARITY_NONE; + + if (stopbits == 2) + lcrresult |= LCR_STOPBITS_MORE_THAN_1; + else + lcrresult |= LCR_STOPBITS_1; + + // baudrate + + if (initbps > 0) + baudresult = (Bit16u) (115200 / initbps); + else + baudresult = 12; // = 9600 baud + + Write_LCR (LCR_DIVISOR_Enable_MASK); + Write_THR ((Bit8u) baudresult & 0xff); + Write_IER ((Bit8u) (baudresult >> 8)); + Write_LCR (lcrresult); +} + +CSerial::CSerial(IO_ReadHandler * rh, IO_WriteHandler * wh, TIMER_TickHandler, + Bit16u initbase, Bit8u initirq, Bit32u initbps, Bit8u bytesize, + const char *parity, Bit8u stopbits) { + base = initbase; + irq = initirq; + TimerHnd = NULL; + //TimerHnd = th; // for destructor + //TIMER_AddTickHandler(TimerHnd); + + for (Bitu i = 0; i <= 7; i++) { + WriteHandler[i].Install (i + base, wh, IO_MB); + ReadHandler[i].Install (i + base, rh, IO_MB); + } +}; + +CSerial::~CSerial(void) { + + if(TimerHnd) TIMER_DelTickHandler(TimerHnd); +}; + +void CSerial::InstallTimerHandler(TIMER_TickHandler th) +{ + if(TimerHnd==NULL) { + TimerHnd=th; + TIMER_AddTickHandler(th); + } +} + +bool getParameter(char *input, char *buffer, const char *parametername, + Bitu buffersize) { + Bitu outputPos = 0; + Bitu currentState = 0; // 0 = before '=' 1 = after '=' 2 = in word + Bitu startInputPos; + Bitu inputPos; + char *res1 = strstr(input, parametername); + if (res1 == 0) + return false; + inputPos = res1 - input; + inputPos += strlen (parametername); + startInputPos = inputPos; + while (input[inputPos] != 0 && outputPos + 2 < buffersize) { + if (currentState == 0) { + if (input[inputPos] == ' ') + inputPos++; + else if (input[inputPos] == ':') { + currentState = 1; + inputPos++; + } else + return false; + } else if (currentState == 1) { + if (input[inputPos] == ' ') + inputPos++; + else { + currentState = 2; + buffer[outputPos] = input[inputPos]; + outputPos++; + inputPos++; + } + + } else { + if (input[inputPos] == ' ') { + buffer[outputPos] = 0; + return true; + } else { + buffer[outputPos] = input[inputPos]; + outputPos++; + inputPos++; + } + } + } + buffer[outputPos] = 0; + if (inputPos == startInputPos) + return false; + return true; +} + +// functions for parsing the config line +bool scanNumber (char *scan, Bitu * retval) { + *retval = 0; + + while (char c = *scan) { + if (c >= '0' && c <= '9') { + *retval *= 10; + *retval += c - '0'; + scan++; + } else + return false; + } + return true; +} + +bool getFirstWord (char *input, char *buffer, Bitu buffersize) { + Bitu outputPointer = 0; + Bitu currentState = 0; // 0 = scanning spaces 1 = in word + Bitu currentPos = 0; + while (input[currentPos] != 0 && outputPointer + 2 < buffersize) { + if (currentState == 0) { + if (input[currentPos] != ' ') { + currentState = 1; + buffer[outputPointer] = input[currentPos]; + outputPointer++; + } + } else { + if (input[currentPos] == ' ') { + buffer[outputPointer] = 0; + return true; + } else { + buffer[outputPointer] = input[currentPos]; + outputPointer++; + } + } + currentPos++; + } + buffer[outputPointer] = 0; // end of string + if (currentState == 0) + return false; + else + return true; +} + +void BIOS_SetComPorts (Bit16u baseaddr[]); + +class SERIALPORTS:public Module_base { +public: + CSerial ** serialPortObjects[4]; + SERIALPORTS (Section * configuration):Module_base (configuration) { + // put handlers into arrays + IO_ReadHandler *serialReadHandlers[] = { + &SERIAL1_Read, &SERIAL2_Read, &SERIAL3_Read, &SERIAL4_Read + }; + IO_WriteHandler *serialWriteHandlers[] = { + &SERIAL1_Write, &SERIAL2_Write, &SERIAL3_Write, &SERIAL4_Write + }; + TIMER_TickHandler serialTimerHandlers[] = { + &SERIAL1_Update, &SERIAL2_Update, &SERIAL3_Update, &SERIAL4_Update + }; + + // default ports & interrupts + Bit16u addresses[] = { COM1_BASE, COM2_BASE, COM3_BASE, COM4_BASE }; + Bit8u defaultirq[] = { 4, 3, 4, 3 }; + Bit16u biosParameter[4] = { 0, 0, 0, 0 }; + Section_prop *section = static_cast (configuration); + char tmpbuffer[15]; + + const char *configstringsconst[4] = { + section->Get_string ("serial1"), + section->Get_string ("serial2"), + section->Get_string ("serial3"), + section->Get_string ("serial4") + }; + /* Create copies so they can be modified */ + char *configstrings[4] = { 0 }; + for(Bitu i = 0;i < 4;i++) { + size_t len = strlen(configstringsconst[i]); + configstrings[i] = new char[len+1]; + strcpy(configstrings[i],configstringsconst[i]); + configstrings[i] = upcase(configstrings[i]); + } + + serialPortObjects[0] = &serial1; + serialPortObjects[1] = &serial2; + serialPortObjects[2] = &serial3; + serialPortObjects[3] = &serial4; + + // iterate through all 4 com ports + for (Bitu i = 0; i < 4; i++) { + Bit16u baseAddress = addresses[i]; + Bitu irq = defaultirq[i]; + Bitu bps = 9600; + Bitu bytesize = 8; + Bitu stopbits = 1; + char parity = 'N'; + biosParameter[i] = baseAddress; + + // parameter: irq + if (getParameter(configstrings[i], tmpbuffer, "IRQ", sizeof (tmpbuffer))) { + if (scanNumber (tmpbuffer, &irq)) { + if (irq < 0 || irq == 2 || irq > 15) + irq = defaultirq[i]; + } else + irq = defaultirq[i]; + } + // parameter: bps + if (getParameter(configstrings[i], tmpbuffer, "STARTBPS", sizeof (tmpbuffer))) { + if (scanNumber (tmpbuffer, &bps)) { + if (bps <= 0) + bps = 9600; + } else + bps = 9600; + } + // parameter: bytesize + if (getParameter(configstrings[i], tmpbuffer, "BYTESIZE", sizeof (tmpbuffer))) { + if (scanNumber (tmpbuffer, &bytesize)) { + if (bytesize < 5 || bytesize > 8) + bytesize = 8; + } else + bytesize = 8; + } + // parameter: stopbits + if (getParameter(configstrings[i], tmpbuffer, "STOPBITS", sizeof (tmpbuffer))) { + if (scanNumber (tmpbuffer, &stopbits)) { + if (stopbits < 1 || stopbits > 2) + stopbits = 1; + } else + stopbits = 1; + } + // parameter: parity + if (getParameter(configstrings[i], tmpbuffer, "PARITY", sizeof (tmpbuffer))) { + if (!(tmpbuffer[0] == 'N' || tmpbuffer[0] == 'O' || tmpbuffer[0] == 'E' + || tmpbuffer[0] == 'M' || tmpbuffer[0] == 'S')) + tmpbuffer[0] = 'N'; + parity = tmpbuffer[0]; + } + //LOG_MSG("COM%d: %s",i+1,configstrings[i]); + if (getFirstWord (configstrings[i], tmpbuffer, sizeof (tmpbuffer))) { + //LOG_MSG("COM%d: %s",i+1,tmpbuffer); + if (!strcmp (tmpbuffer, "DUMMY")) { + *serialPortObjects[i] = new CSerialDummy (serialReadHandlers[i], serialWriteHandlers[i],serialTimerHandlers[i], baseAddress, irq, bps,bytesize, &parity, stopbits); + } +#ifdef DIRECTSERIAL_AVAILIBLE + else if (!strcmp (tmpbuffer, "DIRECTSERIAL")) { + // parameter: realport + if (getParameter (configstrings[i], tmpbuffer, "REALPORT", sizeof (tmpbuffer))) { // realport is required + CDirectSerial *cdstemp = new CDirectSerial (serialReadHandlers[i], serialWriteHandlers[i], serialTimerHandlers[i], baseAddress, irq, bps,bytesize, &parity,stopbits,tmpbuffer); + + if (cdstemp->InstallationSuccessful) { + *serialPortObjects[i] = cdstemp; + } else { // serial port name was wrong or already in use + delete cdstemp; + *serialPortObjects[i] = NULL; + biosParameter[i] = 0; + } + + } else { + *serialPortObjects[i] = NULL; + biosParameter[i] = 0; + } + } +#endif +#if C_MODEM + else if (!strcmp (tmpbuffer, "MODEM")) { + Bitu listenport = 23; + // parameter: listenport + if (getParameter(configstrings[i], tmpbuffer, "LISTENPORT", sizeof (tmpbuffer))) { + if (scanNumber (tmpbuffer, &listenport)) { + if (listenport <= 0 || listenport > 65535) + listenport = 23; + } else + listenport = 23; + } + + *serialPortObjects[i] = new CSerialModem (serialReadHandlers[i], serialWriteHandlers[i], serialTimerHandlers[i], baseAddress, irq, bps,bytesize, &parity, stopbits, 0, listenport); + } +#endif + else if (!strcmp (tmpbuffer, "DISABLED")) { + *serialPortObjects[i] = NULL; + biosParameter[i] = 0; + } else { + LOG_MSG ("Invalid type for COM%d.", i + 1); + *serialPortObjects[i] = NULL; + biosParameter[i] = 0; + } + } else { + *serialPortObjects[i] = NULL; + biosParameter[i] = 0; + } + } + + delete [] configstrings[0];delete [] configstrings[1]; + delete [] configstrings[2];delete [] configstrings[3]; + BIOS_SetComPorts (biosParameter); + } + + ~SERIALPORTS () { + for (Bitu i = 0; i < 4; i++) + if (*serialPortObjects[i]) { + delete *(serialPortObjects[i]); + *(serialPortObjects[i]) = 0; + } + } +}; + +static SERIALPORTS *testSerialPortsBaseclass; + +void SERIAL_Destroy (Section * sec) { + delete testSerialPortsBaseclass; + testSerialPortsBaseclass = NULL; +} + +void SERIAL_Init (Section * sec) { + // should never happen + if (testSerialPortsBaseclass) delete testSerialPortsBaseclass; + testSerialPortsBaseclass = new SERIALPORTS (sec); + sec->AddDestroyFunction (&SERIAL_Destroy, true); +} diff --git a/src/hardware/serialport/softmodem.cpp b/src/hardware/serialport/softmodem.cpp new file mode 100644 index 0000000..cfcadb9 --- /dev/null +++ b/src/hardware/serialport/softmodem.cpp @@ -0,0 +1,799 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: softmodem.cpp,v 1.5 2006/03/24 17:11:35 qbix79 Exp $ */ + +#include "dosbox.h" + +#if C_MODEM + +#include +#include +#include + +#include "SDL_net.h" + +#include "support.h" +#include "timer.h" +#include "serialport.h" +#include "softmodem.h" + +//#include "mixer.h" + + +CSerialModem::CSerialModem( + IO_ReadHandler* rh, + IO_WriteHandler* wh, + TIMER_TickHandler th, + Bit16u baseAddr, + Bit8u initIrq, + Bit32u initBps, + Bit8u bytesize, + const char* parity, + Bit8u stopbits, + const char *remotestr, + Bit16u lport) + : CSerial(rh, wh, th, + baseAddr, initIrq, initBps, bytesize, parity, stopbits) { + socket=0; + incomingsocket=0; + InstallTimerHandler(th); + + if(!SDLNetInited) { + if(SDLNet_Init()==-1) { + LOG_MSG("SDLNet_Init failed: %s\n", SDLNet_GetError()); + return; + } + SDLNetInited = true; + } + rqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE); + tqueue=new CFifo(MODEM_BUFFER_QUEUE_SIZE); + + /* Default to direct null modem connection. Telnet mode interprets IAC codes */ + telnetmode = false; + + /* Initialize the sockets and setup the listening port */ + socketset = SDLNet_AllocSocketSet(1); + listensocketset = SDLNet_AllocSocketSet(1); + if (!socketset || !listensocketset) { + LOG_MSG("MODEM:Can't open socketset:%s",SDLNet_GetError()); + //TODO Should probably just exit + return; + } + socket=0; + listenport=lport; + if (listenport) { + IPaddress listen_ip; + SDLNet_ResolveHost(&listen_ip, NULL, listenport); + listensocket=SDLNet_TCP_Open(&listen_ip); + if (!listensocket) LOG_MSG("MODEM:Can't open listen port: %s",SDLNet_GetError()); + + else LOG_MSG("MODEM: Port listener installed at port %d",listenport); + + } + else listensocket=0; + + // TODO: Fix dialtones if requested + //mhd.chan=MIXER_AddChannel((MIXER_MixHandler)this->MODEM_CallBack,8000,"MODEM"); + //MIXER_Enable(mhd.chan,false); + //MIXER_SetMode(mhd.chan,MIXER_16MONO); + + Reset(); + //EnterIdleState(); + CSerial::Init_Registers(initBps,bytesize,parity,stopbits); + } + + CSerialModem::~CSerialModem() { + if(socket) { + SDLNet_TCP_DelSocket(socketset,socket); + SDLNet_TCP_Close(socket); + } + + if(listensocket) SDLNet_TCP_Close(listensocket); + if(socketset) SDLNet_FreeSocketSet(socketset); + + delete rqueue; + delete tqueue; + } + +void CSerialModem::SendLine(const char *line) { + rqueue->addb(0xd); + rqueue->addb(0xa); + rqueue->adds((Bit8u *)line,strlen(line)); + rqueue->addb(0xd); + rqueue->addb(0xa); +} + +// only for numbers < 1000... +void CSerialModem::SendNumber(Bitu val) { + rqueue->addb(0xd); + rqueue->addb(0xa); + + rqueue->addb(val/100+'0'); + val = val%100; + rqueue->addb(val/10+'0'); + val = val%10; + rqueue->addb(val+'0'); + + rqueue->addb(0xd); + rqueue->addb(0xa); +} + +void CSerialModem::SendRes(ResTypes response) { + char * string;Bitu code; + switch (response) + { + case ResNONE: return; + case ResOK: string="OK"; code=0; break; + case ResERROR: string="ERROR"; code=4; break; + case ResRING: string="RING"; code=2; break; + case ResNODIALTONE: string="NO DIALTONE"; code=6; break; + case ResNOCARRIER: string="NO CARRIER" ;code=3; break; + case ResCONNECT: string="CONNECT 57600"; code=1; break; + } + + if(doresponse!=1) { + if(doresponse==2 && (response==ResRING || + response == ResCONNECT || response==ResNOCARRIER)) return; + if(numericresponse) SendNumber(code); + else SendLine(string); + + //if(CSerial::CanReceiveByte()) // very fast response + // if(rqueue->inuse() && CSerial::getRTS()) + // { Bit8u rbyte =rqueue->getb(); + // CSerial::receiveByte(rbyte); + // LOG_MSG("Modem: sending byte %2x back to UART2",rbyte); + // } + + LOG_MSG("Modem response: %s", string); + } +} + +void CSerialModem::openConnection(void) { + if (socket) { + LOG_MSG("Huh? already connected"); + SDLNet_TCP_DelSocket(socketset,socket); + SDLNet_TCP_Close(socket); + } + socket = SDLNet_TCP_Open(&openip); +} + +bool CSerialModem::Dial(char * host) { + + /* Scan host for port */ + Bit16u port; + char * hasport=strrchr(host,':'); + if (hasport) { + *hasport++=0; + port=(Bit16u)atoi(hasport); + } + else port=MODEM_DEFAULT_PORT; + /* Resolve host we're gonna dial */ + LOG_MSG("Connecting to host %s port %d",host,port); + if (!SDLNet_ResolveHost(&openip,host,port)) { + openConnection(); + EnterConnectedState(); + return true; + } else { + LOG_MSG("Failed to resolve host %s: %s",host,SDLNet_GetError()); + SendRes(ResNODIALTONE); + EnterIdleState(); + return false; + } +} + +void CSerialModem::AcceptIncomingCall(void) { +// assert(!socket); + socket=incomingsocket; + SDLNet_TCP_AddSocket(socketset,socket); + incomingsocket = 0; + EnterConnectedState(); +} + +Bitu CSerialModem::ScanNumber(char * & scan) { + Bitu ret=0; + while (char c=*scan) { + if (c>='0' && c<='9') { + ret*=10; + ret+=c-'0'; + scan++; + } else break; + } + return ret; +} + +void CSerialModem::Reset(){ + EnterIdleState(); + cmdpos = 0; + cmdbuf[0]=0; + oldDTRstate = getDTR(); + flowcontrol = 0; + plusinc = 0; + incomingsocket = 0; + memset(®,0,sizeof(reg)); + reg[MREG_AUTOANSWER_COUNT]=0; // no autoanswer + reg[MREG_RING_COUNT] = 1; + reg[MREG_ESCAPE_CHAR]='+'; + reg[MREG_CR_CHAR]='\r'; + reg[MREG_LF_CHAR]='\n'; + reg[MREG_BACKSPACE_CHAR]='\b'; + + cmdpause = 0; + echo = true; + doresponse = 0; + numericresponse = false; + + /* Default to direct null modem connection. Telnet mode interprets IAC codes */ + telnetmode = false; +} + +void CSerialModem::EnterIdleState(void){ + connected=false; + ringing=false; + + if(socket) { // clear current socket + SDLNet_TCP_DelSocket(socketset,socket); + SDLNet_TCP_Close(socket); + socket=0; + } + if(incomingsocket) { // clear current incoming socket + SDLNet_TCP_DelSocket(socketset,incomingsocket); + SDLNet_TCP_Close(incomingsocket); + } + // get rid of everything + if(listensocket) { + while(incomingsocket=SDLNet_TCP_Accept(listensocket)) { + SDLNet_TCP_DelSocket(socketset,incomingsocket); + SDLNet_TCP_Close(incomingsocket); + } + } + incomingsocket=0; + + commandmode = true; + CSerial::setCD(false); + CSerial::setRI(false); + CSerial::setDSR(true); + CSerial::setCTS(true); + tqueue->clear(); +} + +void CSerialModem::EnterConnectedState(void) { + if(socket) { + SDLNet_TCP_AddSocket(socketset,socket); + SendRes(ResCONNECT); + commandmode = false; + memset(&telClient, 0, sizeof(telClient)); + connected = true; + ringing = false; + CSerial::setCD(true); + CSerial::setRI(false); + } else { + SendRes(ResNOCARRIER); + EnterIdleState(); + } +} + +void CSerialModem::DoCommand() { + cmdbuf[cmdpos] = 0; + cmdpos = 0; //Reset for next command + upcase(cmdbuf); + LOG_MSG("Command sent to modem: ->%s<-\n", cmdbuf); + /* Check for empty line, stops dialing and autoanswer */ + if (!cmdbuf[0]) { + reg[0]=0; // autoanswer off + return; + // } + //else { + //MIXER_Enable(mhd.chan,false); + // dialing = false; + // SendRes(ResNOCARRIER); + // goto ret_none; + // } + } + /* AT command set interpretation */ + + if ((cmdbuf[0] != 'A') || (cmdbuf[1] != 'T')) { + SendRes(ResERROR); + return;//goto ret_error; + } + + if (strstr(cmdbuf,"NET0")) { + telnetmode = false; + SendRes(ResOK); + return; + } + else if (strstr(cmdbuf,"NET1")) { + telnetmode = true; + SendRes(ResOK); + return; + } + + /* Check for dial command */ + if(strncmp(cmdbuf,"ATD3",3)==0) { + char * foundstr=&cmdbuf[3]; + if (*foundstr=='T' || *foundstr=='P') foundstr++; + /* Small protection against empty line */ + if (!foundstr[0]) { + SendRes(ResERROR);//goto ret_error; + return; + } + char* helper; + // scan for and remove spaces; weird bug: with leading spaces in the string, + // SDLNet_ResolveHost will return no error but not work anyway (win) + while(foundstr[0]==' ') foundstr++; + helper=foundstr; + helper+=strlen(foundstr); + while(helper[0]==' ') { + helper[0]=0; + helper--; + } + + if (strlen(foundstr) >= 12) { + // Check if supplied parameter only consists of digits + bool isNum = true; + for (Bitu i=0; i '9') + isNum = false; + if (isNum) { + // Parameter is a number with at least 12 digits => this cannot be a valid IP/name + // Transform by adding dots + char buffer[128]; + Bitu j = 0; + for (Bitu i=0; i12) + buffer[j++] = ':'; + } + buffer[j] = 0; + foundstr = buffer; + } + } + Dial(foundstr); + return; + } + char * scanbuf; + scanbuf=&cmdbuf[2]; + char chr; + Bitu num; + while (chr=*scanbuf++) { + switch (chr) { + case 'I': //Some strings about firmware + switch (num=ScanNumber(scanbuf)) { + case 3:SendLine("DosBox Emulated Modem Firmware V1.00");break; + case 4:SendLine("Modem compiled for DosBox version " VERSION);break; + };break; + case 'E': //Echo on/off + switch (num=ScanNumber(scanbuf)) { + case 0:echo = false;break; + case 1:echo = true;break; + };break; + case 'V': + switch (num=ScanNumber(scanbuf)) { + case 0:numericresponse = true;break; + case 1:numericresponse = false;break; + };break; + case 'H': //Hang up + switch (num=ScanNumber(scanbuf)) { + case 0: + if (connected) { + SendRes(ResNOCARRIER); + EnterIdleState(); + return;//goto ret_none; + } + //Else return ok + };break; + case 'O': //Return to data mode + switch (num=ScanNumber(scanbuf)) + { + case 0: + if (socket) { + commandmode = false; + return;//goto ret_none; + } else { + SendRes(ResERROR); + return;//goto ret_none; + } + };break; + case 'T': //Tone Dial + case 'P': //Pulse Dial + break; + case 'M': //Monitor + case 'L': //Volume + ScanNumber(scanbuf); + break; + case 'A': //Answer call + if (incomingsocket) { + AcceptIncomingCall(); + } else { + SendRes(ResERROR); + return;//goto ret_none; + } + return;//goto ret_none; + case 'Z': //Reset and load profiles + { + // scan the number away, if any + ScanNumber(scanbuf); + if (socket) SendRes(ResNOCARRIER); + Reset(); + break; + } + case ' ': //Space just skip + break; + case 'Q': // Response options + { // 0 = all on, 1 = all off, + // 2 = no ring and no connect/carrier in answermode + Bitu val = ScanNumber(scanbuf); + if(!(val>2)) { + doresponse=val; + break; + } else { + SendRes(ResERROR); + return; + } + } + case 'S': //Registers + { + Bitu index=ScanNumber(scanbuf); + if(index>=SREGS) { + SendRes(ResERROR); + return; //goto ret_none; + } + + while(scanbuf[0]==' ') scanbuf++; // skip spaces + + if(scanbuf[0]=='=') { // set register + scanbuf++; + while(scanbuf[0]==' ') scanbuf++; // skip spaces + Bitu val = ScanNumber(scanbuf); + reg[index]=val; + break; + } + else if(scanbuf[0]=='?') { // get register + SendNumber(reg[index]); + scanbuf++; + break; + } + //else LOG_MSG("print reg %d with %d",index,reg[index]); + } + break; + case '&': + { + if(scanbuf[0]!=0) { + char ch = scanbuf[0]; + scanbuf++; + switch(ch) { + case 'K': + { + Bitu val = ScanNumber(scanbuf); + if(val<5) flowcontrol=val; + else { + SendRes(ResERROR); + return; + } + break; + } + default: + { + scanbuf++; + LOG_MSG("Modem: Unhandled command: &%c%d",ch,ScanNumber(scanbuf)); + break; + } + } + } else { + SendRes(ResERROR); + return; + } + } + break; + + default: + LOG_MSG("Modem: Unhandled command: %c%d",chr,ScanNumber(scanbuf)); + } + } + + SendRes(ResOK); + return; + } + +void CSerialModem::TelnetEmulation(Bit8u * data, Bitu size) { + Bitu i; + Bit8u c; + for(i=0;i250) { + /* Reject anything we don't recognize */ + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(c); /* We won't do crap! */ + } + } + switch(telClient.command) { + case 251: /* Will */ + if(c == 0) telClient.binary[TEL_SERVER] = true; + if(c == 1) telClient.echo[TEL_SERVER] = true; + if(c == 3) telClient.supressGA[TEL_SERVER] = true; + break; + case 252: /* Won't */ + if(c == 0) telClient.binary[TEL_SERVER] = false; + if(c == 1) telClient.echo[TEL_SERVER] = false; + if(c == 3) telClient.supressGA[TEL_SERVER] = false; + break; + case 253: /* Do */ + if(c == 0) { + telClient.binary[TEL_CLIENT] = true; + tqueue->addb(0xff); + tqueue->addb(251); + tqueue->addb(0); /* Will do binary transfer */ + } + if(c == 1) { + telClient.echo[TEL_CLIENT] = false; + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(1); /* Won't echo (too lazy) */ + } + if(c == 3) { + telClient.supressGA[TEL_CLIENT] = true; + tqueue->addb(0xff); + tqueue->addb(251); + tqueue->addb(3); /* Will Suppress GA */ + } + break; + case 254: /* Don't */ + if(c == 0) { + telClient.binary[TEL_CLIENT] = false; + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(0); /* Won't do binary transfer */ + } + if(c == 1) { + telClient.echo[TEL_CLIENT] = false; + tqueue->addb(0xff); + tqueue->addb(252); + tqueue->addb(1); /* Won't echo (fine by me) */ + } + if(c == 3) { + telClient.supressGA[TEL_CLIENT] = true; + tqueue->addb(0xff); + tqueue->addb(251); + tqueue->addb(3); /* Will Suppress GA (too lazy) */ + } + break; + default: + LOG_MSG("MODEM: Telnet client sent IAC %d", telClient.command); + break; + } + + telClient.inIAC = false; + telClient.recCommand = false; + continue; + + } else { + if(c==249) { + /* Go Ahead received */ + telClient.inIAC = false; + continue; + } + telClient.command = c; + telClient.recCommand = true; + + if((telClient.binary[TEL_SERVER]) && (c == 0xff)) { + /* Binary data with value of 255 */ + telClient.inIAC = false; + telClient.recCommand = false; + rqueue->addb(0xff); + continue; + } + + } + } else { + if(c == 0xff) { + telClient.inIAC = true; + continue; + } + rqueue->addb(c); + } + } + } + +void CSerialModem::Timer2(void) { + int result =0; + unsigned long args = 1; + bool sendbyte = true; + Bitu usesize; + Bit8u txval; + Bitu txbuffersize =0; + Bitu testres = 0; + + // check for bytes to be sent to port + if(CSerial::CanReceiveByte()) + if(rqueue->inuse() && (CSerial::getRTS()||(flowcontrol!=3))) { + Bit8u rbyte = rqueue->getb(); + //LOG_MSG("Modem: sending byte %2x back to UART3",rbyte); + CSerial::receiveByte(rbyte); + } + /* Check for eventual break command */ + if (!commandmode) cmdpause++; + /* Handle incoming data from serial port, read as much as available */ + //Bitu tx_size=tqueue->inuse(); + //Bitu tx_first = tx_size; // TODO:comment out + CSerial::setCTS(true); // buffer will get 'emptier', new data can be received + while (/*tx_size--*/tqueue->inuse()) { + txval = tqueue->getb(); + if (commandmode) { + if (echo) { + rqueue->addb(txval); + //LOG_MSG("Echo back to queue: %x",txval); + } + if (txval==0xa) continue; //Real modem doesn't seem to skip this? + else if (txval==0x8 && (cmdpos > 0)) --cmdpos; // backspace + else if (txval==0xd) DoCommand(); // return + else if (txval != '+') { + if(cmdpos<99) { + cmdbuf[cmdpos] = txval; + cmdpos++; + } + } + } + else {// + character + /* 1000 ticks have passed, can check for pause command */ + if (cmdpause > 1000) { + if(txval ==/* '+')*/reg[MREG_ESCAPE_CHAR]) + { + plusinc++; + if(plusinc>=3) { + LOG_MSG("Modem: Entering command mode(escape sequence)"); + commandmode = true; + SendRes(ResOK); + plusinc = 0; + } + sendbyte=false; + } else { + plusinc=0; + } + //If not a special pause command, should go for bigger blocks to send + } + tmpbuf[txbuffersize] = txval; + txbuffersize++; + } + } // while loop + + if (socket && sendbyte && txbuffersize) { + // down here it saves a lot of network traffic + SDLNet_TCP_Send(socket, tmpbuf,txbuffersize); + //TODO error testing + } + SDLNet_CheckSockets(socketset,0); + /* Handle incoming to the serial port */ + if(!commandmode && socket) { + if(rqueue->left() && SDLNet_SocketReady(socket) /*&& CSerial::getRTS()*/) + { + usesize = rqueue->left(); + if (usesize>16) usesize=16; + result = SDLNet_TCP_Recv(socket, tmpbuf, usesize); + if (result>0) { + if(telnetmode) { + /* Filter telnet commands */ + TelnetEmulation(tmpbuf, result); + } else { + rqueue->adds(tmpbuf,result); + } + cmdpause = 0; + } else { + SendRes(ResNOCARRIER); + EnterIdleState(); + } + } + } + /* Check for incoming calls */ + if (!connected && !incomingsocket && listensocket) { + incomingsocket = SDLNet_TCP_Accept(listensocket); + if (incomingsocket) { + SDLNet_TCP_AddSocket(listensocketset, incomingsocket); + + if(!CSerial::getDTR()) { + // accept no calls with DTR off; TODO: AT &Dn + EnterIdleState(); + } else { + ringing=true; + SendRes(ResRING); + CSerial::setRI(!CSerial::getRI()); + //MIXER_Enable(mhd.chan,true); + ringtimer = 3000; + reg[1] = 0; //Reset ring counter reg + } + } + } + if (ringing) { + if (ringtimer <= 0) { + reg[1]++; + if ((reg[0]>0) && (reg[0]>=reg[1])) { + AcceptIncomingCall(); + return; + } + SendRes(ResRING); + CSerial::setRI(!CSerial::getRI()); + + //MIXER_Enable(mhd.chan,true); + ringtimer = 3000; + } + --ringtimer; + } +} + + +//TODO +void CSerialModem::RXBufferEmpty() { + // see if rqueue has some more bytes + if(rqueue->inuse() && (CSerial::getRTS()||(flowcontrol!=3))){ + Bit8u rbyte = rqueue->getb(); + //LOG_MSG("Modem: sending byte %2x back to UART1",rbyte); + CSerial::receiveByte(rbyte); + } +} + +void CSerialModem::transmitByte(Bit8u val) { + //LOG_MSG("MODEM: Byte %x to be transmitted",val); + if(tqueue->left()) { + tqueue->addb(val); + if(tqueue->left() < 2) { + CSerial::setCTS(false); + } + } else LOG_MSG("MODEM: TX Buffer overflow!"); + CSerial::ByteTransmitted(); +} + +void CSerialModem::updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr) { +// nothing to do here right? +} + +void CSerialModem::updateMSR() { + // think it is not needed +} + +void CSerialModem::setBreak(bool) { + // TODO: handle this +} + +void CSerialModem::updateModemControlLines() { + //bool txrdy=tqueue->left(); + //if(CSerial::getRTS() && txrdy) CSerial::setCTS(true); + //else CSerial::setCTS(tqueue->left()); + + // If DTR goes low, hang up. + if(connected) + if(oldDTRstate) + if(!getDTR()) { + SendRes(ResNOCARRIER); + EnterIdleState(); + LOG_MSG("Modem: Hang up due to dropped DTR."); + } + + oldDTRstate = getDTR(); +} + + +#endif + diff --git a/src/hardware/serialport/softmodem.h b/src/hardware/serialport/softmodem.h new file mode 100644 index 0000000..c9803cd --- /dev/null +++ b/src/hardware/serialport/softmodem.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: softmodem.h,v 1.5 2006/02/26 13:48:06 qbix79 Exp $ */ + +#ifndef DOSBOX_SERIALMODEM_H +#define DOSBOX_SERIALMODEM_H + +#include "dosbox.h" +#if C_MODEM +#include "SDL_net.h" +#include "serialport.h" + +#define MODEMSPD 57600 +#define SREGS 100 + +//If it's too high you overflow terminal clients buffers i think +#define MODEM_BUFFER_QUEUE_SIZE 1024 + +#define MODEM_DEFAULT_PORT 23 + +enum ResTypes { + ResNONE, + ResOK,ResERROR, + ResCONNECT,ResRING, + ResBUSY,ResNODIALTONE,ResNOCARRIER, +}; + +#define TEL_CLIENT 0 +#define TEL_SERVER 1 + +class CFifo { +public: + CFifo(Bitu _size) { + size=_size; + pos=used=0; + data=new Bit8u[size]; + } + ~CFifo() { + delete[] data; + } + INLINE Bitu left(void) { + return size-used; + } + INLINE Bitu inuse(void) { + return used; + } + void clear(void) { + used=pos=0; + } + + void addb(Bit8u _val) { + if(used>=size) { + LOG_MSG("FIFO Overflow!"); + return; + } + //assert(used=size) where-=size; + data[where]=_val; + //LOG_MSG("+%x",_val); + used++; + } + void adds(Bit8u * _str,Bitu _len) { + if((used+_len)>size) { + LOG_MSG("FIFO Overflow!"); + return; + } + + //assert((used+_len)<=size); + Bitu where=pos+used; + used+=_len; + while (_len--) { + if (where>=size) where-=size; + //LOG_MSG("+%x",*_str); + data[where++]=*_str++; + } + } + Bit8u getb(void) { + if (!used) { + LOG_MSG("MODEM: FIFO UNDERFLOW!"); + return data[pos]; + } + Bitu where=pos; + if (++pos>=size) pos-=size; + used--; + //LOG_MSG("-%x",data[where]); + return data[where]; + } + void gets(Bit8u * _str,Bitu _len) { + if (!used) { + LOG_MSG("MODEM: FIFO UNDERFLOW!"); + return; + } + //assert(used>=_len); + used-=_len; + while (_len--) { + //LOG_MSG("-%x",data[pos]); + *_str++=data[pos]; + if (++pos>=size) pos-=size; + } + } +private: + Bit8u * data; + Bitu size,pos,used; + //Bit8u tmpbuf[MODEM_BUFFER_QUEUE_SIZE]; + + +}; +#define MREG_AUTOANSWER_COUNT 0 +#define MREG_RING_COUNT 1 +#define MREG_ESCAPE_CHAR 2 +#define MREG_CR_CHAR 3 +#define MREG_LF_CHAR 4 +#define MREG_BACKSPACE_CHAR 5 + + +class CSerialModem : public CSerial { +public: + + CFifo *rqueue; + CFifo *tqueue; + + CSerialModem( + IO_ReadHandler* rh, + IO_WriteHandler* wh, + TIMER_TickHandler th, + Bit16u baseAddr, + Bit8u initIrq, + Bit32u initBps, + Bit8u bytesize, + const char* parity, + Bit8u stopbits, + + const char *remotestr = NULL, + Bit16u lport = 23); + + ~CSerialModem(); + + void Reset(); + + void SendLine(const char *line); + void SendRes(ResTypes response); + void SendNumber(Bitu val); + + void EnterIdleState(); + void EnterConnectedState(); + + void openConnection(void); + bool Dial(char * host); + void AcceptIncomingCall(void); + Bitu ScanNumber(char * & scan); + + void DoCommand(); + + void MC_Changed(Bitu new_mc); + + void TelnetEmulation(Bit8u * data, Bitu size); + + void Timer2(void); + + void RXBufferEmpty(); + + void transmitByte(Bit8u val); + void updatePortConfig(Bit8u dll, Bit8u dlm, Bit8u lcr); + void updateMSR(); + + void setBreak(bool); + + void updateModemControlLines(/*Bit8u mcr*/); + +protected: + char cmdbuf[255]; + bool commandmode; // true: interpret input as commands + bool echo; // local echo on or off + + bool oldDTRstate; + bool ringing; + //bool response; + bool numericresponse; // true: send control response as number. + // false: send text (i.e. NO DIALTONE) + bool telnetmode; // true: process IAC commands. + + bool connected; + Bitu doresponse; + + + + Bitu cmdpause; + Bits ringtimer; + Bits ringcount; + Bitu plusinc; + Bitu cmdpos; + Bitu flowcontrol; + + //Bit8u mctrl; + Bit8u tmpbuf[MODEM_BUFFER_QUEUE_SIZE]; + + Bitu listenport; + Bit8u reg[SREGS]; + IPaddress openip; + TCPsocket incomingsocket; + TCPsocket socket; + + TCPsocket listensocket; + SDLNet_SocketSet socketset; + SDLNet_SocketSet listensocketset; + + struct { + bool binary[2]; + bool echo[2]; + bool supressGA[2]; + bool timingMark[2]; + + bool inIAC; + bool recCommand; + Bit8u command; + } telClient; + struct { + bool active; + double f1, f2; + Bitu len,pos; + char str[256]; + } dial; +}; +#endif +#endif diff --git a/src/hardware/softmodem.cpp b/src/hardware/softmodem.cpp deleted file mode 100644 index 0db2814..0000000 --- a/src/hardware/softmodem.cpp +++ /dev/null @@ -1,746 +0,0 @@ -/* - * Copyright (C) 2002-2004 The DOSBox Team - * - * 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 "dosbox.h" - -#if C_MODEM - -#include -#include -#include -#include "SDL_net.h" - -#include "inout.h" -#include "mixer.h" -#include "pic.h" -#include "setup.h" -#include "programs.h" -#include "debug.h" -#include "timer.h" -#include "callback.h" -#include "math.h" -#include "regs.h" -#include "serialport.h" - -#define MODEMSPD 57600 -#define SREGS 100 - - -static Bit8u tmpbuf[QUEUE_SIZE]; - -struct ModemHd { - char cmdbuf[QUEUE_SIZE]; - bool commandmode; - bool answermode; - bool echo,response,numericresponse; - bool telnetmode; - Bitu cmdpause; - Bits ringtimer; - Bits ringcount; - Bitu plusinc; - Bitu cmdpos; - - Bit8u reg[SREGS]; - TCPsocket incomingsocket; - TCPsocket socket; - TCPsocket listensocket; - SDLNet_SocketSet socketset; - - IPaddress openip; - - Bitu comport; - Bitu listenport; - - char remotestr[4096]; - - bool dialing; - double f1, f2; - Bitu diallen; - Bitu dialpos; - char dialstr[256]; - // TODO: Re-enable dialtons - //MIXER_Channel * chan; -}; - -enum ResTypes { - ResNONE, - ResOK,ResERROR, - ResCONNECT,ResRING, - ResBUSY,ResNODIALTONE,ResNOCARRIER, -}; - -#define TEL_CLIENT 0 -#define TEL_SERVER 1 - -struct telnetClient { - bool binary[2]; - bool echo[2]; - bool supressGA[2]; - bool timingMark[2]; - - bool inIAC; - bool recCommand; - Bit8u command; -}; - - -#if 1 - -static void toUpcase(char *buffer) { - Bitu i=0; - while (buffer[i] != 0) { - buffer[i] = toupper(buffer[i]); - i++; - } -} - - - -class CSerialModem : public CSerial { -public: - ModemHd mhd; - - CSerialModem(Bit16u baseAddr, Bit8u initIrq, Bit32u initBps, const char *remotestr = NULL, Bit16u lport = 27) - : CSerial(baseAddr, initIrq, initBps) - { - - - mhd.cmdpos = 0; - mhd.commandmode = true; - mhd.plusinc = 0; - mhd.incomingsocket = 0; - mhd.answermode = false; - memset(&mhd.reg,0,sizeof(mhd.reg)); - mhd.cmdpause = 0; - mhd.echo = true; - mhd.response = true; - mhd.numericresponse = false; - - /* Default to direct null modem connection. Telnet mode interprets IAC codes */ - mhd.telnetmode = false; - - /* Bind the modem to the correct serial port */ - //strcpy(mhd.remotestr, remotestr); - - /* Initialize the sockets and setup the listening port */ - mhd.socketset = SDLNet_AllocSocketSet(1); - if (!mhd.socketset) { - LOG_MSG("MODEM:Can't open socketset:%s",SDLNet_GetError()); - //TODO Should probably just exit - return; - } - mhd.socket=0; - mhd.listenport=lport; - if (mhd.listenport) { - IPaddress listen_ip; - SDLNet_ResolveHost(&listen_ip, NULL, mhd.listenport); - mhd.listensocket=SDLNet_TCP_Open(&listen_ip); - if (!mhd.listensocket) LOG_MSG("MODEM:Can't open listen port:%s",SDLNet_GetError()); - } else mhd.listensocket=0; - - // TODO: Fix dialtones if requested - //mhd.chan=MIXER_AddChannel((MIXER_MixHandler)this->MODEM_CallBack,8000,"MODEM"); - //MIXER_Enable(mhd.chan,false); - //MIXER_SetMode(mhd.chan,MIXER_16MONO); - - } - - - - void SendLine(const char *line) { - rqueue->addb(0xd); - rqueue->addb(0xa); - rqueue->adds((Bit8u *)line,strlen(line)); - rqueue->addb(0xd); - rqueue->addb(0xa); - - } - - void SendRes(ResTypes response) { - char * string;char * code; - switch (response) { - case ResNONE: - return; - case ResOK:string="OK";code="0";break; - case ResERROR:string="ERROR";code="4";break; - case ResRING:string="RING";code="2"; - case ResNODIALTONE:string="NO DIALTONE";code="6";break; - case ResNOCARRIER:string="NO CARRIER";code="3";break; - case ResCONNECT:string="CONNECT 57600";code="1";break; - } - - rqueue->addb(0xd);rqueue->addb(0xa); - rqueue->adds((Bit8u *)string,strlen(string)); - rqueue->addb(0xd);rqueue->addb(0xa); - } - - void Send(Bit8u val) { - tqueue->addb(val); - } - - Bit8u Recv(Bit8u val) { - return rqueue->getb(); - - } - - void openConnection(void) { - if (mhd.socket) { - LOG_MSG("Huh? already connected"); - SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); - SDLNet_TCP_Close(mhd.socket); - } - mhd.socket = SDLNet_TCP_Open(&openip); - if (mhd.socket) { - SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); - SendRes(ResCONNECT); - mhd.commandmode = false; - memset(&telClient, 0, sizeof(telClient)); - updatemstatus(); - } else { - SendRes(ResNODIALTONE); - } - } - - void updatemstatus(void) { - Bit8u ms=0; - //Check for data carrier, a connection that is - if (mhd.incomingsocket) ms|=MS_RI; - if (mhd.socket) ms|=MS_DCD; - if (!mhd.commandmode) ms|=MS_DSR; - //Check for DTR reply with DSR - // if (cport->mctrl & MC_DTR) ms|=MS_DSR; - //Check for RTS reply with CTS - if (mctrl & MC_RTS) ms|=MS_CTS; - SetModemStatus(ms); - } - - bool Dial(char * host) { - /* Scan host for port */ - Bit16u port; - char * hasport=strrchr(host,':'); - if (hasport) { - *hasport++=0; - port=(Bit16u)atoi(hasport); - } else port=23; - /* Resolve host we're gonna dial */ - LOG_MSG("host %s port %x",host,port); - if (!SDLNet_ResolveHost(&openip,host,port)) { - openConnection(); - return true; - } else { - LOG_MSG("Failed to resolve host %s:%s",host,SDLNet_GetError()); - SendRes(ResNOCARRIER); - return false; - } - } - - void AcceptIncomingCall(void) { - assert(!mhd.socket); - mhd.socket=mhd.incomingsocket; - SDLNet_TCP_AddSocket(mhd.socketset,mhd.socket); - SendRes(ResCONNECT); - LOG_MSG("Connected!\n"); - - mhd.incomingsocket = 0; - mhd.commandmode = false; - } - - Bitu ScanNumber(char * & scan) { - Bitu ret=0; - while (char c=*scan) { - if (c>='0' && c<='9') { - ret*=10; - ret+=c-'0'; - scan++; - } else break; - } - return ret; - } - - - void HangUp(void) { - SendRes(ResNOCARRIER); - SDLNet_TCP_DelSocket(mhd.socketset,mhd.socket); - SDLNet_TCP_Close(mhd.socket); - mhd.socket=0; - mhd.commandmode = true; - updatemstatus(); - } - - void DoCommand() { - mhd.cmdbuf[mhd.cmdpos] = 0; - mhd.cmdpos = 0; //Reset for next command - toUpcase(mhd.cmdbuf); - LOG_MSG("Modem Sent Command: %s\n", mhd.cmdbuf); - /* Check for empty line, stops dialing and autoanswer */ - if (!mhd.cmdbuf[0]) { - if(!mhd.dialing) { - mhd.answermode = false; - goto ret_none; - } else { - //MIXER_Enable(mhd.chan,false); - mhd.dialing = false; - SendRes(ResNOCARRIER); - goto ret_none; - } - } - /* AT command set interpretation */ - if ((mhd.cmdbuf[0] != 'A') || (mhd.cmdbuf[1] != 'T')) goto ret_error; - /* Check for dial command */ - if(strncmp(mhd.cmdbuf,"ATD3",3)==0) { - char * foundstr=&mhd.cmdbuf[3]; - if (*foundstr=='T' || *foundstr=='P') foundstr++; - /* Small protection against empty line */ - if (!foundstr[0]) goto ret_error; - if (strlen(foundstr) >= 12){ - // Check if supplied parameter only consists of digits - bool isNum = true; - for (Bitu i=0; i '9') - isNum = false; - if (isNum) { - // Parameter is a number with at least 12 digits => this cannot be a valid IP/name - // Transform by adding dots - char buffer[128]; - Bitu j = 0; - for (Bitu i=0; i12) - buffer[j++] = ':'; - } - buffer[j] = 0; - foundstr = buffer; - } - } - Dial(foundstr); - goto ret_none; - } - char * scanbuf; - scanbuf=&mhd.cmdbuf[2];char chr;Bitu num; - while (chr=*scanbuf++) { - switch (chr) { - case 'I': //Some strings about firmware - switch (num=ScanNumber(scanbuf)) { - case 3:SendLine("DosBox Emulated Modem Firmware V1.00");break; - case 4:SendLine("Modem compiled for DosBox version " VERSION);break; - };break; - case 'E': //Echo on/off - switch (num=ScanNumber(scanbuf)) { - case 0:mhd.echo = false;break; - case 1:mhd.echo = true;break; - };break; - case 'V': - switch (num=ScanNumber(scanbuf)) { - case 0:mhd.numericresponse = true;break; - case 1:mhd.numericresponse = false;break; - };break; - case 'H': //Hang up - switch (num=ScanNumber(scanbuf)) { - case 0: - if (mhd.socket) { - HangUp(); - goto ret_none; - } - //Else return ok - };break; - case 'O': //Return to data mode - switch (num=ScanNumber(scanbuf)) { - case 0: - if (mhd.socket) { - mhd.commandmode = false; - goto ret_none; - } else { - goto ret_error; - } - };break; - case 'T': //Tone Dial - case 'P': //Pulse Dial - break; - case 'M': //Monitor - case 'L': //Volume - ScanNumber(scanbuf); - break; - case 'A': //Answer call - if (mhd.incomingsocket) { - AcceptIncomingCall(); - } else { - mhd.answermode = true; - } - goto ret_none; - case 'Z': //Reset and load profiles - num=ScanNumber(scanbuf); - break; - case ' ': //Space just skip - break; - case 'S': //Registers - { - Bitu index=ScanNumber(scanbuf); - bool hasequal=(*scanbuf == '='); - if (hasequal) scanbuf++; - Bitu val=ScanNumber(scanbuf); - if (index>=SREGS) goto ret_error; - if (hasequal) mhd.reg[index]=val; - else LOG_MSG("print reg %d with %d",index,mhd.reg[index]); - };break; - default: - LOG_MSG("Unhandled cmd %c%d",chr,ScanNumber(scanbuf)); - } - } - #if 0 - if (strstr(mhd.cmdbuf,"S0=1")) { - mhd.autoanswer = true; - } - if (strstr(mhd.cmdbuf,"S0=0")) { - mhd.autoanswer = false; - } - - if (strstr(mhd.cmdbuf,"NET0")) { - mhd.telnetmode = false; - } - if (strstr(mhd.cmdbuf,"NET1")) { - mhd.telnetmode = true; - } - #endif - LOG_MSG("Sending OK"); - SendRes(ResOK); - return; - ret_error: - LOG_MSG("Sending ERROR"); - SendRes(ResERROR); - ret_none: - return; - - } - - void MC_Changed(Bitu new_mc) { - LOG_MSG("New MC %x",new_mc ); - if (!(new_mc & 1) && mhd.socket) HangUp(); - updatemstatus(); - } - - void TelnetEmulation(Bit8u * data, Bitu size) { - Bitu i; - Bit8u c; - for(i=0;i250) { - /* Reject anything we don't recognize */ - tqueue->addb(0xff); - tqueue->addb(252); - tqueue->addb(c); /* We won't do crap! */ - } - } - switch(telClient.command) { - case 251: /* Will */ - if(c == 0) telClient.binary[TEL_SERVER] = true; - if(c == 1) telClient.echo[TEL_SERVER] = true; - if(c == 3) telClient.supressGA[TEL_SERVER] = true; - break; - case 252: /* Won't */ - if(c == 0) telClient.binary[TEL_SERVER] = false; - if(c == 1) telClient.echo[TEL_SERVER] = false; - if(c == 3) telClient.supressGA[TEL_SERVER] = false; - break; - case 253: /* Do */ - if(c == 0) { - telClient.binary[TEL_CLIENT] = true; - tqueue->addb(0xff); - tqueue->addb(251); - tqueue->addb(0); /* Will do binary transfer */ - } - if(c == 1) { - telClient.echo[TEL_CLIENT] = false; - tqueue->addb(0xff); - tqueue->addb(252); - tqueue->addb(1); /* Won't echo (too lazy) */ - } - if(c == 3) { - telClient.supressGA[TEL_CLIENT] = true; - tqueue->addb(0xff); - tqueue->addb(251); - tqueue->addb(3); /* Will Suppress GA */ - } - break; - case 254: /* Don't */ - if(c == 0) { - telClient.binary[TEL_CLIENT] = false; - tqueue->addb(0xff); - tqueue->addb(252); - tqueue->addb(0); /* Won't do binary transfer */ - } - if(c == 1) { - telClient.echo[TEL_CLIENT] = false; - tqueue->addb(0xff); - tqueue->addb(252); - tqueue->addb(1); /* Won't echo (fine by me) */ - } - if(c == 3) { - telClient.supressGA[TEL_CLIENT] = true; - tqueue->addb(0xff); - tqueue->addb(251); - tqueue->addb(3); /* Will Suppress GA (too lazy) */ - } - break; - default: - LOG_MSG("MODEM: Telnet client sent IAC %d", telClient.command); - break; - } - - telClient.inIAC = false; - telClient.recCommand = false; - continue; - - } else { - if(c==249) { - /* Go Ahead received */ - telClient.inIAC = false; - continue; - } - telClient.command = c; - telClient.recCommand = true; - - if((telClient.binary[TEL_SERVER]) && (c == 0xff)) { - /* Binary data with value of 255 */ - telClient.inIAC = false; - telClient.recCommand = false; - rqueue->addb(0xff); - continue; - } - - } - } else { - if(c == 0xff) { - telClient.inIAC = true; - continue; - } - rqueue->addb(c); - } - } - } - - void Timer(void) { - int result =0; - unsigned long args = 1; - bool sendbyte = true; - Bitu usesize; - Bit8u txval; - - /* Check for eventual break command */ - if (!mhd.commandmode) mhd.cmdpause++; - /* Handle incoming data from serial port, read as much as available */ - Bitu tx_size=tqueue->inuse(); - while (tx_size--) { - txval = tqueue->getb(); - if (mhd.commandmode) { - if (mhd.echo) rqueue->addb(txval); - if (txval==0xa) continue; //Real modem doesn't seem to skip this? - else if (txval==0x8 && (mhd.cmdpos > 0)) --mhd.cmdpos; - else if (txval==0xd) DoCommand(); - else if (txval != '+') { - if(mhd.cmdpos 1000) { - if(txval == '+') { - mhd.plusinc++; - if(mhd.plusinc>=3) { - LOG_MSG("Entering command mode"); - mhd.commandmode = true; - SendRes(ResOK); - mhd.plusinc = 0; - } - sendbyte=false; - } else { - mhd.plusinc=0; - } - //If not a special pause command, should go for bigger blocks to send - } - - tmpbuf[0] = txval; - tmpbuf[1] = 0x0; - - if (mhd.socket && sendbyte) { - SDLNet_TCP_Send(mhd.socket, tmpbuf,1); - //TODO error testing - } - } - } - - SDLNet_CheckSockets(mhd.socketset,0); - /* Handle incoming to the serial port */ - if(!mhd.commandmode && mhd.socket) { - if(rqueue->left() && SDLNet_SocketReady(mhd.socket) && (mctrl & MC_RTS)) { - usesize = rqueue->left(); - if (usesize>16) usesize=16; - result = SDLNet_TCP_Recv(mhd.socket, tmpbuf, usesize); - if (result>0) { - if(mhd.telnetmode) { - /* Filter telnet commands */ - TelnetEmulation(tmpbuf, result); - } else { - rqueue->adds(tmpbuf,result); - } - mhd.cmdpause = 0; - } else HangUp(); - } - } - /* Check for incoming calls */ - if (!mhd.socket && !mhd.incomingsocket && mhd.listensocket) { - mhd.incomingsocket = SDLNet_TCP_Accept(mhd.listensocket); - if (mhd.incomingsocket) { - mhd.diallen = 12000; - mhd.dialpos = 0; - SendRes(ResRING); - //MIXER_Enable(mhd.chan,true); - mhd.ringtimer = 3000; - mhd.reg[1] = 0; //Reset ring counter reg - } - } - if (mhd.incomingsocket) { - if (mhd.ringtimer <= 0) { - mhd.reg[1]++; - if (mhd.answermode || (mhd.reg[0]==mhd.reg[1])) { - AcceptIncomingCall(); - return; - } - SendRes(ResRING); - mhd.diallen = 12000; - mhd.dialpos = 0; - //MIXER_Enable(mhd.chan,true); - mhd.ringtimer = 3000; - } - --mhd.ringtimer; - } - updatemstatus(); - } - - bool CanSend(void) { - return true; - } - - bool CanRecv(void) { - return true; - } - - -protected: - char cmdbuf[QUEUE_SIZE]; - bool commandmode; - bool answermode; - bool echo; - bool telnetmode; - Bitu cmdpause; - Bits ringtimer; - Bits ringcount; - Bitu plusinc; - Bitu cmdpos; - - Bit8u reg[SREGS]; - IPaddress openip; - TCPsocket incomingsocket; - TCPsocket socket; - TCPsocket listensocket; - SDLNet_SocketSet socketset; - - struct { - bool binary[2]; - bool echo[2]; - bool supressGA[2]; - bool timingMark[2]; - - bool inIAC; - bool recCommand; - Bit8u command; - } telClient; - struct { - bool active; - double f1, f2; - Bitu len,pos; - char str[256]; - } dial; -}; - -#endif - - - -CSerialModem *csm; - - -void MODEM_Init(Section* sec) { - - unsigned long args = 1; - Section_prop * section=static_cast(sec); - - if(!section->Get_bool("modem")) return; - - if(SDLNet_Init()==-1) { - LOG_MSG("SDLNet_Init failed: %s\n", SDLNet_GetError()); - return; - } - - if(!SDLNetInited) { - if(SDLNet_Init()==-1) { - LOG_MSG("SDLNet_Init failed: %s\n", SDLNet_GetError()); - return; - } - SDLNetInited = true; - } - - Bit16u comport = section->Get_int("comport"); - - csm = NULL; - - switch (comport) { - case 1: - csm = new CSerialModem(0x3f0, 4, 57600, section->Get_string("remote"), section->Get_int("listenport")); - break; - case 2: - csm = new CSerialModem(0x2f0, 3, 57600, section->Get_string("remote"), section->Get_int("listenport")); - break; - case 3: - csm = new CSerialModem(0x3e0, 4, 57600, section->Get_string("remote"), section->Get_int("listenport")); - break; - case 4: - csm = new CSerialModem(0x2e0, 3, 57600, section->Get_string("remote"), section->Get_int("listenport")); - break; - default: - // Default to COM2 - csm = new CSerialModem(0x2f0, 3, 57600, section->Get_string("remote"), section->Get_int("listenport")); - break; - - } - - if(csm != NULL) seriallist.push_back(csm); -} - - -#endif - diff --git a/src/hardware/tandy_sound.cpp b/src/hardware/tandy_sound.cpp index 0983a28..84f34df 100644 --- a/src/hardware/tandy_sound.cpp +++ b/src/hardware/tandy_sound.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -27,6 +27,7 @@ #include "mem.h" #include "setup.h" #include "pic.h" +#include "dma.h" #define DAC_CLOCK 3570000 #define MAX_OUTPUT 0x7fff @@ -306,40 +307,74 @@ static void SN76496_set_gain(int gain) } +class TANDYSOUND: public Module_base { +private: + IO_WriteHandleObject WriteHandler[3]; + MixerObject MixerChan; +public: + TANDYSOUND(Section* configuration):Module_base(configuration){ + Section_prop * section=static_cast(configuration); + real_writeb(0x40,0xd4,0x00); + if (IS_TANDY_ARCH) { + /* enable tandy sound if tandy=true/auto */ + if ((strcmp(section->Get_string("tandy"),"true")!=0) && + (strcmp(section->Get_string("tandy"),"on")!=0) && + (strcmp(section->Get_string("tandy"),"auto")!=0)) return; + } else { + /* only enable tandy sound if tandy=true */ + if ((strcmp(section->Get_string("tandy"),"true")!=0) && + (strcmp(section->Get_string("tandy"),"on")!=0)) return; -void TANDYSOUND_Init(Section* sec) { - if (machine!=MCH_TANDY) return; - Section_prop * section=static_cast(sec); + /* ports from second DMA controller conflict with tandy ports */ + CloseSecondDMAController(); - IO_RegisterWriteHandler(0xc0,SN76496Write,IO_MB,2); - IO_RegisterWriteHandler(0xc4,TandyDACWrite,IO_MB,4); + WriteHandler[2].Install(0x1e0,SN76496Write,IO_MB,2); + } + + WriteHandler[0].Install(0xc0,SN76496Write,IO_MB,2); + WriteHandler[1].Install(0xc4,TandyDACWrite,IO_MB,4); + + + Bit32u sample_rate = section->Get_int("tandyrate"); + tandy.chan=MixerChan.Install(&SN76496Update,sample_rate,"TANDY"); + + tandy.enabled=false; + real_writeb(0x40,0xd4,0xff); /* tandy DAC initialization value */ - - Bit32u sample_rate = section->Get_int("tandyrate"); - tandy.chan=MIXER_AddChannel(&SN76496Update,sample_rate,"TANDY"); - - tandy.enabled=false; - - Bitu i; - struct SN76496 *R = &sn; - R->SampleRate = sample_rate; - SN76496_set_clock(2386360); - for (i = 0;i < 4;i++) R->Volume[i] = 0; - R->LastRegister = 0; - for (i = 0;i < 8;i+=2) - { - R->Register[i] = 0; - R->Register[i + 1] = 0x0f; /* volume = 0 */ + Bitu i; + struct SN76496 *R = &sn; + R->SampleRate = sample_rate; + SN76496_set_clock(3579545); + for (i = 0;i < 4;i++) R->Volume[i] = 0; + R->LastRegister = 0; + for (i = 0;i < 8;i+=2) + { + R->Register[i] = 0; + R->Register[i + 1] = 0x0f; /* volume = 0 */ + } + + for (i = 0;i < 4;i++) + { + R->Output[i] = 0; + R->Period[i] = R->Count[i] = R->UpdateStep; + } + R->RNG = NG_PRESET; + R->Output[3] = R->RNG & 1; + SN76496_set_gain(0x1); } + ~TANDYSOUND(){ } +}; - for (i = 0;i < 4;i++) - { - R->Output[i] = 0; - R->Period[i] = R->Count[i] = R->UpdateStep; - } - R->RNG = NG_PRESET; - R->Output[3] = R->RNG & 1; - SN76496_set_gain(0x1); + + +static TANDYSOUND* test; + +void TANDYSOUND_ShutDown(Section* sec) { + delete test; } +void TANDYSOUND_Init(Section* sec) { + test = new TANDYSOUND(sec); + sec->AddDestroyFunction(&TANDYSOUND_ShutDown,true); +} diff --git a/src/hardware/timer.cpp b/src/hardware/timer.cpp index 8a3eb45..97a0b30 100644 --- a/src/hardware/timer.cpp +++ b/src/hardware/timer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,17 +16,16 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: timer.cpp,v 1.30 2004/11/13 11:59:46 qbix79 Exp $ */ +/* $Id: timer.cpp,v 1.35 2006/02/27 20:16:49 qbix79 Exp $ */ +#include #include "dosbox.h" #include "inout.h" #include "pic.h" -#include "bios.h" #include "mem.h" -#include "dosbox.h" #include "mixer.h" #include "timer.h" -#include "math.h" +#include "setup.h" static INLINE void BIN2BCD(Bit16u& val) { Bit16u temp=val%10 + (((val/10)%10)<<4)+ (((val/100)%10)<<8) + (((val/1000)%10)<<12); @@ -122,6 +121,7 @@ static void counter_latch(Bitu counter) { static void write_latch(Bitu port,Bitu val,Bitu iolen) { +//LOG(LOG_PIT,LOG_ERROR)("port %X write:%X state:%X",port,val,pit[port-0x40].write_state); Bitu counter=port-0x40; PIT_Block * p=&pit[counter]; if(p->bcd == true) BIN2BCD(p->write_latch); @@ -153,7 +153,7 @@ static void write_latch(Bitu port,Bitu val,Bitu iolen) { switch (counter) { case 0x00: /* Timer hooked to IRQ 0 */ if (p->new_mode || p->mode == 0 ) { - p->new_mode=false; + p->new_mode=false; PIC_AddEvent(PIT0_Event,p->delay); } else LOG(LOG_PIT,LOG_NORMAL)("PIT 0 Timer set without new control word"); LOG(LOG_PIT,LOG_NORMAL)("PIT 0 Timer at %.2f Hz mode %d",1000.0/p->delay,p->mode); @@ -169,6 +169,7 @@ static void write_latch(Bitu port,Bitu val,Bitu iolen) { } static Bitu read_latch(Bitu port,Bitu iolen) { +//LOG(LOG_PIT,LOG_ERROR)("port read %X",port); Bit32u counter=port-0x40; if (pit[counter].go_read_latch == true) counter_latch(counter); @@ -205,6 +206,7 @@ static Bitu read_latch(Bitu port,Bitu iolen) { } static void write_p43(Bitu port,Bitu val,Bitu iolen) { +//LOG(LOG_PIT,LOG_ERROR)("port 43 %X",val); Bitu latch=(val >> 6) & 0x03; switch (latch) { case 0: @@ -221,15 +223,31 @@ static void write_p43(Bitu port,Bitu val,Bitu iolen) { } else { pit[latch].read_state = (val >> 4) & 0x03; pit[latch].write_state = (val >> 4) & 0x03; - pit[latch].mode = (val >> 1) & 0x07; - if (pit[latch].mode>5) - pit[latch].mode-=4; //6,7 become 2 and 3 - if (latch==0) { + Bit8u mode = (val >> 1) & 0x07; + if (mode > 5) + mode -= 4; //6,7 become 2 and 3 + + /* Don't set it directly so counter_output uses the old mode */ + /* That's theory. It breaks panic. So set it here again */ + if(!pit[latch].mode) pit[latch].mode = mode; + + /* If the line goes from low to up => generate irq. + * ( BUT needs to stay up until acknowlegded by the cpu!!! therefore: ) + * If the line goes to low => disable irq. + * Mode 0 starts with a low line. (so always disable irq) + * Mode 2,3 start with a high line. + * counter_output tells if the current counter is high or low + * So actually a mode 2 timer enables and disables irq al the time. (not handled) */ + + if (latch == 0) { PIC_RemoveEvents(PIT0_Event); - if (!counter_output(0) && pit[latch].mode) + if (!counter_output(0) && mode) PIC_ActivateIRQ(0); + if(!mode) + PIC_DeActivateIRQ(0); } - pit[latch].new_mode = true; + pit[latch].new_mode = true; + pit[latch].mode = mode; //Set the correct mode (here) } break; case 3: @@ -245,44 +263,61 @@ static void write_p43(Bitu port,Bitu val,Bitu iolen) { } -void TIMER_Init(Section* sect) { - IO_RegisterWriteHandler(0x40,write_latch,IO_MB); -// IO_RegisterWriteHandler(0x41,write_latch,IO_MB); - IO_RegisterWriteHandler(0x42,write_latch,IO_MB); - IO_RegisterWriteHandler(0x43,write_p43,IO_MB); - IO_RegisterReadHandler(0x40,read_latch,IO_MB); - IO_RegisterReadHandler(0x41,read_latch,IO_MB); - IO_RegisterReadHandler(0x42,read_latch,IO_MB); - /* Setup Timer 0 */ - pit[0].cntr=0x10000; - pit[0].write_state = 3; - pit[0].read_state = 3; - pit[0].read_latch=0; - pit[0].write_latch=0; - pit[0].mode=3; - pit[0].bcd = false; - pit[0].go_read_latch = true; +class TIMER:public Module_base{ +private: + IO_ReadHandleObject ReadHandler[4]; + IO_WriteHandleObject WriteHandler[4]; +public: + TIMER(Section* configuration):Module_base(configuration){ + WriteHandler[0].Install(0x40,write_latch,IO_MB); + // WriteHandler[1].Install(0x41,write_latch,IO_MB); + WriteHandler[2].Install(0x42,write_latch,IO_MB); + WriteHandler[3].Install(0x43,write_p43,IO_MB); + ReadHandler[0].Install(0x40,read_latch,IO_MB); + ReadHandler[1].Install(0x41,read_latch,IO_MB); + ReadHandler[2].Install(0x42,read_latch,IO_MB); + /* Setup Timer 0 */ + pit[0].cntr=0x10000; + pit[0].write_state = 3; + pit[0].read_state = 3; + pit[0].read_latch=0; + pit[0].write_latch=0; + pit[0].mode=3; + pit[0].bcd = false; + pit[0].go_read_latch = true; + + pit[1].bcd = false; + pit[1].write_state = 1; + pit[1].read_state = 1; + pit[1].go_read_latch = true; + pit[1].cntr = 18; + pit[1].mode = 2; + pit[1].write_state = 3; + + pit[2].read_latch=0; /* MadTv1 */ + pit[2].write_state = 3; /* Chuck Yeager */ + pit[2].read_state = 3; + pit[2].mode=3; + pit[2].bcd=false; + pit[2].cntr=1320; + pit[2].go_read_latch=true; + + pit[0].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[0].cntr)); + pit[1].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[1].cntr)); + pit[2].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[2].cntr)); + + PIC_AddEvent(PIT0_Event,pit[0].delay); + } + ~TIMER(){ + PIC_RemoveEvents(PIT0_Event); + } +}; +static TIMER* test; - pit[1].bcd = false; - pit[1].write_state = 1; - pit[1].read_state = 1; - pit[1].go_read_latch = true; - pit[1].cntr = 18; - pit[1].mode = 2; - pit[1].write_state = 3; - - pit[2].read_latch=0; /* MadTv1 */ - pit[2].write_state = 3; /* Chuck Yeager */ - pit[2].read_state = 3; - pit[2].mode=3; - pit[2].bcd=false; - pit[2].cntr=1320; - pit[2].go_read_latch=true; - - pit[0].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[0].cntr)); - pit[1].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[1].cntr)); - pit[2].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[2].cntr)); - - PIC_AddEvent(PIT0_Event,pit[0].delay); +void TIMER_Destroy(Section* sec){ + delete test; +} +void TIMER_Init(Section* sec) { + test = new TIMER(sec); + sec->AddDestroyFunction(&TIMER_Destroy); } - diff --git a/src/hardware/vga.cpp b/src/hardware/vga.cpp index a5f6d63..696a5be 100644 --- a/src/hardware/vga.cpp +++ b/src/hardware/vga.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,20 +16,17 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include #include "dosbox.h" #include "video.h" #include "pic.h" -#include "timer.h" #include "vga.h" -#include "inout.h" VGA_Type vga; Bit32u CGA_2_Table[16]; Bit32u CGA_4_Table[256]; +Bit32u CGA_4_HiRes_Table[256]; Bit32u CGA_16_Table[256]; Bit32u TXT_Font_Table[16]; Bit32u TXT_FG_Table[16]; @@ -53,15 +50,22 @@ void VGA_DetermineMode(void) { if (vga.s3.misc_control_2 & 0xf0) { switch (vga.s3.misc_control_2 >> 4) { case 1:VGA_SetMode(M_LIN8);break; + case 3:VGA_SetMode(M_LIN15);break; + case 5:VGA_SetMode(M_LIN16);break; + case 13:VGA_SetMode(M_LIN32);break; } /* Test for graphics or alphanumeric mode */ } else if (vga.attr.mode_control & 1) { - if (!(vga.crtc.mode_control & 0x1)) { - if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4); - else VGA_SetMode(M_CGA2); - } else if (vga.attr.mode_control & 0x40) { - VGA_SetMode(M_VGA); - } else VGA_SetMode(M_EGA16); + if (vga.gfx.mode & 0x40) VGA_SetMode(M_VGA); + else if (vga.gfx.mode & 0x20) VGA_SetMode(M_CGA4); + else if ((vga.gfx.miscellaneous & 0x0c)==0x0c) VGA_SetMode(M_CGA2); + else { + if (vga.s3.reg_31 & 0x8) + VGA_SetMode(M_LIN4); + else + VGA_SetMode(M_EGA); + + } } else { VGA_SetMode(M_TEXT); } @@ -131,9 +135,18 @@ void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3) { #else (total[(i >> 6) & 3] << 0 ) | (total[(i >> 4) & 3] << 8 ) | (total[(i >> 2) & 3] << 16 ) | (total[(i >> 0) & 3] << 24 ); +#endif + CGA_4_HiRes_Table[i]= +#ifdef WORDS_BIGENDIAN + (total[((i >> 0) & 1) | ((i >> 3) & 2)] << 0 ) | (total[((i >> 1) & 1) | ((i >> 4) & 2)] << 8 ) | + (total[((i >> 2) & 1) | ((i >> 5) & 2)] << 16 ) | (total[((i >> 3) & 1) | ((i >> 6) & 2)] << 24 ); +#else + (total[((i >> 3) & 1) | ((i >> 6) & 2)] << 0 ) | (total[((i >> 2) & 1) | ((i >> 5) & 2)] << 8 ) | + (total[((i >> 1) & 1) | ((i >> 4) & 2)] << 16 ) | (total[((i >> 0) & 1) | ((i >> 3) & 2)] << 24 ); #endif } } + void VGA_Init(Section* sec) { vga.draw.resizing=false; vga.mode=M_ERROR; //For first init @@ -199,4 +212,3 @@ void VGA_Init(Section* sec) { } } } - diff --git a/src/hardware/vga_attr.cpp b/src/hardware/vga_attr.cpp index 344c91f..1f2f1f9 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -27,7 +27,11 @@ void VGA_ATTR_SetPalette(Bit8u index,Bit8u val) { else val=(val & 63) | (vga.attr.color_select & 0xc) << 4; VGA_DAC_CombineColor(index,val); } - +Bitu read_p3c0(Bitu port,Bitu iolen) { +//Wcharts + return 0x0; +} + void write_p3c0(Bitu port,Bitu val,Bitu iolen) { if (!vga.internal.attrindex) { attr(index)=val & 0x1F; @@ -117,6 +121,7 @@ void write_p3c0(Bitu port,Bitu val,Bitu iolen) { case M_LIN8: vga.config.pel_panning=(val & 0x7)/2; break; + case M_LIN16: default: vga.config.pel_panning=(val & 0x7); } @@ -157,7 +162,7 @@ void write_p3c0(Bitu port,Bitu val,Bitu iolen) { } Bitu read_p3c1(Bitu port,Bitu iolen) { - vga.internal.attrindex=false; +// vga.internal.attrindex=false; switch (attr(index)) { /* Palette */ case 0x00: case 0x01: case 0x02: case 0x03: @@ -188,6 +193,7 @@ Bitu read_p3c1(Bitu port,Bitu iolen) { void VGA_SetupAttr(void) { if (machine==MCH_VGA) { + IO_RegisterReadHandler(0x3c0,read_p3c0,IO_MB); IO_RegisterWriteHandler(0x3c0,write_p3c0,IO_MB); IO_RegisterReadHandler(0x3c1,read_p3c1,IO_MB); } diff --git a/src/hardware/vga_crtc.cpp b/src/hardware/vga_crtc.cpp index f764781..cf47441 100644 --- a/src/hardware/vga_crtc.cpp +++ b/src/hardware/vga_crtc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -21,6 +21,7 @@ #include "vga.h" #include "debug.h" #include "cpu.h" +#include "video.h" #define crtc(blah) vga.crtc.blah @@ -28,18 +29,18 @@ void VGA_MapMMIO(void); void VGA_UnmapMMIO(void); -void write_p3d5_vga(Bitu port,Bitu val,Bitu iolen); +void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen); Bitu DEBUG_EnableDebugger(void); -void write_p3d4_vga(Bitu port,Bitu val,Bitu iolen) { +void vga_write_p3d4(Bitu port,Bitu val,Bitu iolen) { crtc(index)=val; } -Bitu read_p3d4_vga(Bitu port,Bitu iolen) { +Bitu vga_read_p3d4(Bitu port,Bitu iolen) { return crtc(index); } -void write_p3d5_vga(Bitu port,Bitu val,Bitu iolen) { +void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen) { // if (crtc(index)>0x18) LOG_MSG("VGA CRCT write %X to reg %X",val,crtc(index)); switch(crtc(index)) { case 0x00: /* Horizontal Total Register */ @@ -288,287 +289,19 @@ void write_p3d5_vga(Bitu port,Bitu val,Bitu iolen) { Bit 9 is found in 3d4h index 9 bit 6. */ break; -/* S3 specific group */ - case 0x31: /* CR31 Memory Configuration */ -//TODO Base address - vga.s3.reg_31=val; - break; - /* - 0 Enable Base Address Offset (CPUA BASE). Enables bank operation if - set, disables if clear. - 1 Two Page Screen Image. If set enables 2048 pixel wide screen setup - 2 VGA 16bit Memory Bus Width. Set for 16bit, clear for 8bit - 3 Use Enhanced Mode Memory Mapping (ENH MAP). Set to enable access to - video memory above 256k. - 4-5 Bit 16-17 of the Display Start Address. For the 801/5,928 see index - 51h, for the 864/964 see index 69h. - 6 High Speed Text Display Font Fetch Mode. If set enables Page Mode - for Alpha Mode Font Access. - 7 (not 864/964) Extended BIOS ROM Space Mapped out. If clear the area - C6800h-C7FFFh is mapped out, if set it is accessible. - */ - case 0x35: /* CR35 CRT Register Lock */ - if (vga.s3.reg_lock1 != 0x48) return; //Needed for uvconfig detection - vga.s3.reg_35=val & 0xf0; - if ((vga.s3.bank & 0xf) ^ (val & 0xf)) { - vga.s3.bank&=0xf0; - vga.s3.bank|=val & 0xf; - VGA_SetupHandlers(); - } - break; - /* - 0-3 CPU Base Address. 64k bank number. For the 801/5 and 928 see 3d4h - index 51h bits 2-3. For the 864/964 see index 6Ah. - 4 Lock Vertical Timing Registers (LOCK VTMG). Locks 3d4h index 6, 7 - (bits 0,2,3,5,7), 9 bit 5, 10h, 11h bits 0-3, 15h, 16h if set - 5 Lock Horizontal Timing Registers (LOCK HTMG). Locks 3d4h index - 0,1,2,3,4,5,17h bit 2 if set - 6 (911/924) Lock VSync Polarity. - 7 (911/924) Lock HSync Polarity. - */ - case 0x38: /* CR38 Register Lock 1 */ - vga.s3.reg_lock1=val; - break; - case 0x39: /* CR39 Register Lock 2 */ - vga.s3.reg_lock2=val; - break; - case 0x40: /* CR40 System Config */ - vga.s3.reg_40 = val; - break; - case 0x43: /* CR43 Extended Mode */ - vga.s3.reg_43=val & ~0x4; - if (((val & 0x4) ^ (vga.config.scan_len >> 6)) & 0x4) { - vga.config.scan_len&=0x2ff; - vga.config.scan_len|=(val & 0x4) << 6; - VGA_CheckScanLength(); - } - break; - /* - 2 Logical Screen Width bit 8. Bit 8 of the Display Offset Register/ - (3d4h index 13h). (801/5,928) Only active if 3d4h index 51h bits 4-5 - are 0 - */ - case 0x45: /* Hardware cursor mode */ - vga.s3.hgc.curmode = val; - break; - case 0x46: - vga.s3.hgc.originx = (vga.s3.hgc.originx & 0x00ff) | (val << 8); - break; - case 0x47: /* HGC orgX */ - vga.s3.hgc.originx = (vga.s3.hgc.originx & 0xff00) | val; - break; - case 0x48: - vga.s3.hgc.originy = (vga.s3.hgc.originy & 0x00ff) | (val << 8); - break; - case 0x49: /* HGC orgY */ - vga.s3.hgc.originy = (vga.s3.hgc.originy & 0xff00) | val; - break; - case 0x4A: /* HGC foreground stack */ - if (vga.s3.hgc.fstackpos > 2) vga.s3.hgc.fstackpos = 0; - vga.s3.hgc.forestack[vga.s3.hgc.fstackpos] = val; - vga.s3.hgc.fstackpos++; - break; - case 0x4B: /* HGC background stack */ - if (vga.s3.hgc.bstackpos > 2) vga.s3.hgc.bstackpos = 0; - vga.s3.hgc.backstack[vga.s3.hgc.bstackpos] = val; - vga.s3.hgc.bstackpos++; - break; - case 0x4c: /* HGC start address high byte*/ - vga.s3.hgc.startaddr = vga.s3.hgc.startaddr | ((val & 0xff) << 8); - break; - case 0x4d: /* HGC start address low byte*/ - vga.s3.hgc.startaddr = vga.s3.hgc.startaddr | (val & 0xff); - break; - case 0x4e: /* HGC pattern start X */ - vga.s3.hgc.posx = val; - break; - case 0x4f: /* HGC pattern start X */ - vga.s3.hgc.posy = val; - break; - case 0x51: /* Extended System Control 2 */ - vga.s3.reg_51=val & 0xc0; //Only store bits 6,7 - //TODO Display start - vga.config.display_start&=0xFCFFFF; - vga.config.display_start|=(val & 3) << 16; - if ((vga.s3.bank&0xcf) ^ ((val&0xc)<<2)) { - vga.s3.bank&=0xcf; - vga.s3.bank|=(val&0xc)<<2; - VGA_SetupHandlers(); - } - if (((val & 0x30) ^ (vga.config.scan_len >> 4)) & 0x30) { - vga.config.scan_len&=0xff; - vga.config.scan_len|=(val & 0x30) << 4; - VGA_CheckScanLength(); - } - break; - /* - 0 (80x) Display Start Address bit 18 - 0-1 (928 +) Display Start Address bit 18-19 - Bits 16-17 are in index 31h bits 4-5, Bits 0-15 are in 3d4h index - 0Ch,0Dh. For the 864/964 see 3d4h index 69h - 2 (80x) CPU BASE. CPU Base Address Bit 18. - 2-3 (928 +) Old CPU Base Address Bits 19-18. - 64K Bank register bits 4-5. Bits 0-3 are in 3d4h index 35h. - For the 864/964 see 3d4h index 6Ah - 4-5 Logical Screen Width Bit [8-9]. Bits 8-9 of the CRTC Offset register - (3d4h index 13h). If this field is 0, 3d4h index 43h bit 2 is active - 6 (928,964) DIS SPXF. Disable Split Transfers if set. Spilt Transfers - allows transferring one half of the VRAM shift register data while - the other half is being output. For the 964 Split Transfers - must be enabled in enhanced modes (4AE8h bit 0 set). Guess: They - probably can't time the VRAM load cycle closely enough while the - graphics engine is running. - 7 (not 864/964) Enable EPROM Write. If set enables flash memory write - control to the BIOS ROM address - */ - case 0x53: - if((val & 0x10) != (vga.s3.ext_mem_ctrl & 0x10)) { - /* Map or unmap MMIO */ - if ((val & 0x10) != 0) { - LOG_MSG("VGA: Mapping Memory Mapped I/O to 0xA0000"); - VGA_MapMMIO(); - } else { - VGA_UnmapMMIO(); - } - } - vga.s3.ext_mem_ctrl = val; - break; - case 0x55: /* Extended Video DAC Control */ - vga.s3.reg_55=val; - break; - /* - 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the - RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. - If this field is 0, 3d4h index 43h bit 1 is active. - 2 Enable General Input Port Read. If set DAC reads are disabled and the - STRD strobe for reading the General Input Port is enabled for reading - while DACRD is active, if clear DAC reads are enabled. - 3 (928) Enable External SID Operation if set. If set video data is - passed directly from the VRAMs to the DAC rather than through the - VGA chip - 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11 - mode, if clear in MS-Windows mode - 5 (80x,928) Hardware Cursor External Operation Mode. If set the two - bits of cursor data ,is output on the HC[0-1] pins for the video DAC - The SENS pin becomes HC1 and the MID2 pin becomes HC0. - 6 ?? - 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated. - (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri - -stated if set - */ - case 0x58: /* Linear Address Window Control */ - vga.s3.reg_58=val; - break; - /* - 0-1 Linear Address Window Size. Must be less than or equal to video - memory size. 0: 64K, 1: 1MB, 2: 2MB, 3: 4MB (928)/8Mb (864/964) - 2 (not 864/964) Enable Read Ahead Cache if set - 3 (80x,928) ISA Latch Address. If set latches address during every ISA - cycle, unlatches during every ISA cycle if clear. - (864/964) LAT DEL. Address Latch Delay Control (VL-Bus only). If set - address latching occours in the T1 cycle, if clear in the T2 cycle - (I.e. one clock cycle delayed). - 4 ENB LA. Enable Linear Addressing if set. - 5 (not 864/964) Limit Entry Depth for Write-Post. If set limits Write - -Post Entry Depth to avoid ISA bus timeout due to wait cycle limit. - 6 (928,964) Serial Access Mode (SAM) 256 Words Control. If set SAM - control is 256 words, if clear 512 words. - 7 (928) RAS 6-MCLK. If set the random read/write cycle time is 6MCLKs, - if clear 7MCLKs - */ - case 0x59: /* Linear Address Window Position High */ - if ((vga.s3.la_window&0xff00) ^ (val << 8)) { - vga.s3.la_window=(vga.s3.la_window&0x00ff) | (val << 8); - VGA_StartUpdateLFB(); - } - break; - case 0x5a: /* Linear Address Window Position Low */ - if ((vga.s3.la_window&0x00ff) ^ val) { - vga.s3.la_window=(vga.s3.la_window&0xff00) | val; - VGA_StartUpdateLFB(); - } - break; - case 0x5D: /* Extended Horizontal Overflow */ - if ((val & vga.s3.ex_hor_overflow) ^ 3) { - vga.s3.ex_hor_overflow=val; - VGA_StartResize(); - } else vga.s3.ex_hor_overflow=val; - break; - /* - 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h - index 0) - 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End - register (3d4h index 1) - 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking - register (3d4h index 2). - 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse - is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or - does it really extend by 64 ? - 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start - Retrace register (3d4h index 4). - 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse - is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or - does it really extend by 32 ? - 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer - Position register (3d4h index 3Bh) - 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant - Termination register (3d4h index 5Fh). - */ - case 0x5e: /* Extended Vertical Overflow */ - vga.config.line_compare=(vga.config.line_compare & 0x3ff) | (val & 0x40) << 4; - if ((val ^ vga.s3.ex_ver_overflow) & 0x3) { - vga.s3.ex_ver_overflow=val; - VGA_StartResize(); - } else vga.s3.ex_ver_overflow=val; - break; - /* - 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h - index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. - 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End - register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1 - and 6 - 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking - register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9 - in 3d4h index 9 bit 5 - 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace - register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2 - and 7. - 6 Line Compare Position bit 10. Bit 10 of the Line Compare register - (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h - index 9 bit 6. - */ - case 0x67: /* Extended Miscellaneous Control 2 */ - /* - 0 VCLK PHS. VCLK Phase With Respect to DCLK. If clear VLKC is inverted - DCLK, if set VCLK = DCLK. - 4-7 Pixel format. - 0 Mode 0: 8bit (1 pixel/VCLK) - 1 Mode 8: 8bit (2 pixels/VCLK) - 3 Mode 9: 15bit (1 pixel/VCLK) - 5 Mode 10: 16bit (1 pixel/VCLK) - 7 Mode 11: 24/32bit (2 VCLKs/pixel) - 13 (732/764) 32bit (1 pixel/VCLK) - */ - vga.s3.misc_control_2=val; - VGA_DetermineMode(); - break; - case 0x69: /* Extended System Control 3 */ - if (((vga.config.display_start & 0x1f0000)>>16) ^ (val & 0x1f)) { - vga.config.display_start&=0xffff; - vga.config.display_start|=(val & 0x1f) << 16; - } - break; - case 0x6a: /* Extended System Control 4 */ - vga.s3.bank=val & 0x3f; - VGA_SetupHandlers(); - break; - default: - LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Write %X to unknown index %2X",val,crtc(index)); + switch (svgaCard) { + case SVGA_S3Trio: + SVGA_S3_WriteCRTC( crtc(index), val, iolen); + break; + default: + break; + } + break; } } -Bitu read_p3d5_vga(Bitu port,Bitu iolen) { +Bitu vga_read_p3d5(Bitu port,Bitu iolen) { // LOG_MSG("VGA CRCT read from reg %X",crtc(index)); switch(crtc(index)) { case 0x00: /* Horizontal Total Register */ @@ -621,72 +354,15 @@ Bitu read_p3d5_vga(Bitu port,Bitu iolen) { return crtc(mode_control); case 0x18: /* Line Compare Register */ return crtc(line_compare); - - -/* Additions for S3 SVGA Support */ - case 0x2d: /* Extended Chip ID. */ - return 0x88; - // Always 88h ? - case 0x2e: /* New Chip ID */ - return 0x11; - //Trio 64 id - case 0x2f: /* Revision */ - return 0x00; - case 0x30: /* CR30 Chip ID/REV register */ - return 0xe0; //Trio+ dual byte - // Trio32/64 has 0xe0. extended - case 0x31: /* CR31 Memory Configuration */ -//TODO mix in bits from baseaddress; - return vga.s3.reg_31; - case 0x35: /* CR35 CRT Register Lock */ - return vga.s3.reg_35|(vga.s3.bank & 0xf); - case 0x36: /* CR36 Reset State Read 1 */ - //return 0x8f; - return 0x8e; /* PCI version */ - //2 Mb PCI and some bios settings - case 0x37: /* Reset state read 2 */ - return 0x2b; - case 0x38: /* CR38 Register Lock 1 */ - return vga.s3.reg_lock1; - case 0x39: /* CR39 Register Lock 2 */ - return vga.s3.reg_lock2; - case 0x40: /* CR40 system config */ - return vga.s3.reg_40; - case 0x43: /* CR43 Extended Mode */ - return vga.s3.reg_43|((vga.config.scan_len>>6)&0x4); - case 0x45: /* Hardware cursor mode */ - vga.s3.hgc.bstackpos = 0; - vga.s3.hgc.fstackpos = 0; - return vga.s3.hgc.curmode; - case 0x51: /* Extended System Control 2 */ - return ((vga.config.display_start >> 16) & 3 ) | - ((vga.s3.bank & 0x30) >> 2) | - ((vga.config.scan_len & 0x300) >> 4) | - vga.s3.reg_51; - case 0x53: - return vga.s3.ext_mem_ctrl; - case 0x55: /* Extended Video DAC Control */ - return vga.s3.reg_55; - case 0x58: /* Linear Address Window Control */ - return vga.s3.reg_58; - case 0x59: /* Linear Address Window Position High */ - return (vga.s3.la_window >> 8); - case 0x5a: /* Linear Address Window Position Low */ - return (vga.s3.la_window & 0xff); - case 0x5D: /* Extended Horizontal Overflow */ - return vga.s3.ex_hor_overflow; - case 0x5e: /* Extended Vertical Overflow */ - return vga.s3.ex_ver_overflow; - case 0x67: /* Extended Miscellaneous Control 2 */ - return vga.s3.misc_control_2; - case 0x69: /* Extended System Control 3 */ - return (Bit8u)((vga.config.display_start & 0x1f0000)>>16); - case 0x6a: /* Extended System Control 4 */ - return (Bit8u)(vga.s3.bank & 0x3f); default: - LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Read from unknown index %X",crtc(index)); + switch (svgaCard) { + case SVGA_S3Trio: + return SVGA_S3_ReadCRTC( crtc(index), iolen ); + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:CRTC:Read from unknown index %X",crtc(index)); + return 0x0; + } } - return 0x0; } diff --git a/src/hardware/vga_dac.cpp b/src/hardware/vga_dac.cpp index cae4696..b6648e3 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -66,7 +66,7 @@ static void write_p3c7(Bitu port,Bitu val,Bitu iolen) { vga.dac.read_index=val; vga.dac.pel_index=0; vga.dac.state=DAC_READ; - + vga.dac.write_index= val + 1; } static Bitu read_p3c7(Bitu port,Bitu iolen) { @@ -80,6 +80,10 @@ static void write_p3c8(Bitu port,Bitu val,Bitu iolen) { vga.dac.state=DAC_WRITE; } +static Bitu read_p3c8(Bitu port, Bitu iolen){ + return vga.dac.write_index; +} + static void write_p3c9(Bitu port,Bitu val,Bitu iolen) { val&=0x3f; switch (vga.dac.pel_index) { @@ -96,6 +100,7 @@ static void write_p3c9(Bitu port,Bitu val,Bitu iolen) { switch (vga.mode) { case M_VGA: case M_LIN8: + case M_LIN16: RENDER_SetPal(vga.dac.write_index, vga.dac.rgb[vga.dac.write_index].red << 2, vga.dac.rgb[vga.dac.write_index].green << 2, @@ -114,6 +119,7 @@ static void write_p3c9(Bitu port,Bitu val,Bitu iolen) { } } vga.dac.write_index++; +// vga.dac.read_index = vga.dac.write_index - 1;//disabled as it breaks Wari vga.dac.pel_index=0; break; default: @@ -136,6 +142,7 @@ static Bitu read_p3c9(Bitu port,Bitu iolen) { ret=vga.dac.rgb[vga.dac.read_index].blue; vga.dac.read_index++; vga.dac.pel_index=0; +// vga.dac.write_index=vga.dac.read_index+1;//disabled as it breaks wari break; default: LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:DAC:Illegal Pel Index"); //If this can actually happen that will be the day @@ -149,6 +156,7 @@ void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal) { switch (vga.mode) { case M_VGA: case M_LIN8: + case M_LIN16: break; default: RENDER_SetPal(attr, @@ -166,6 +174,7 @@ void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue) { switch (vga.mode) { case M_VGA: case M_LIN8: + case M_LIN16: return; } for (Bitu i=0;i<16;i++) @@ -187,10 +196,9 @@ void VGA_SetupDAC(void) { IO_RegisterReadHandler(0x3c6,read_p3c6,IO_MB); IO_RegisterWriteHandler(0x3c7,write_p3c7,IO_MB); IO_RegisterReadHandler(0x3c7,read_p3c7,IO_MB); + IO_RegisterReadHandler(0x3c8,read_p3c8,IO_MB); IO_RegisterWriteHandler(0x3c8,write_p3c8,IO_MB); IO_RegisterWriteHandler(0x3c9,write_p3c9,IO_MB); IO_RegisterReadHandler(0x3c9,read_p3c9,IO_MB); } }; - - diff --git a/src/hardware/vga_draw.cpp b/src/hardware/vga_draw.cpp index 3fcf67e..1aac305 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -21,21 +21,26 @@ #include "dosbox.h" #include "video.h" #include "render.h" +#include "../gui/render_scalers.h" #include "vga.h" #include "pic.h" #define VGA_PARTS 4 typedef Bit8u * (* VGA_Line_Handler)(Bitu vidstart,Bitu panning,Bitu line); +typedef void (* VGA_FrameStart_Handler)(); static VGA_Line_Handler VGA_DrawLine; -static Bit8u TempLine[1280]; +static VGA_FrameStart_Handler VGA_FrameStart; +static Bit8u TempLine[SCALER_MAXWIDTH * 4]; static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart,Bitu panning,Bitu line) { line*=8*1024;Bit32u * draw=(Bit32u *)TempLine; for (Bitu x=vga.draw.blocks;x>0;x--) { - Bitu val=vga.mem.linear[vidstart+line]; - vidstart=(vidstart+1)&0x1dfff; + Bitu val=vga.gfxmem_start[vidstart+line]; + vidstart++; + if((vga.crtc.mode_control & 0x01) == 0) // CGA compatible addressing + vidstart &= 0x1dfff; *draw++=CGA_2_Table[val >> 4]; *draw++=CGA_2_Table[val & 0xf]; } @@ -45,38 +50,81 @@ static Bit8u * VGA_Draw_1BPP_Line(Bitu vidstart,Bitu panning,Bitu line) { static Bit8u * VGA_Draw_2BPP_Line(Bitu vidstart,Bitu panning,Bitu line) { line*=8*1024;Bit32u * draw=(Bit32u *)TempLine; for (Bitu x=0;x>4)|(val2&0xf0)]; + *draw++=CGA_4_HiRes_Table[(val1&0x0f)|((val2&0x0f)<<4)]; + } + return TempLine; +} + +static Bitu temp[643]={0}; static Bit8u * VGA_Draw_CGA16_Line(Bitu vidstart,Bitu panning,Bitu line) { - Bit8u * reader=&vga.mem.linear[vidstart + (line * 8 * 1024)]; + const Bit8u * reader=&vga.mem.linear[vidstart + (line * 8 * 1024)]; Bit32u * draw=(Bit32u *)TempLine; + //Generate a temporary bitline to calculate the avarage + //over bit-2 bit-1 bit bit+1. + //Combine this number with the current colour to get + //an unigue index in the pallete. Or it with bit 7 as they are stored + //in the upperpart to keep them from interfering the regular cga stuff + + for(Bitu x = 0; x < 640; x++) + temp[x+2] = (( reader[(x>>3)] >> (7-(x&7)) )&1) << 4; + //shift 4 as that is for the index. + Bitu i = 0,temp1,temp2,temp3,temp4; for (Bitu x=0;x> 4]; - *draw++=(val1 << 0) | - (val1 << 8) | - (val2 << 16) | - (val2 << 24); + Bitu val1 = *reader++; + Bitu val2 = val1&0xf; + val1 >>= 4; + + temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + + *draw++ = 0x80808080|(temp1|val1) | + ((temp2|val1) << 8) | + ((temp3|val1) <<16) | + ((temp4|val1) <<24); + temp1 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + temp2 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + temp3 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + temp4 = temp[i] + temp[i+1] + temp[i+2] + temp[i+3]; i++; + *draw++ = 0x80808080|(temp1|val2) | + ((temp2|val2) << 8) | + ((temp3|val2) <<16) | + ((temp4|val2) <<24); } return TempLine; } static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart,Bitu panning,Bitu line) { - Bit8u * reader=&vga.mem.linear[vidstart + (line * 8 * 1024)]; - Bit32u * draw=(Bit32u *)TempLine; + line*=8*1024;Bit32u * draw=(Bit32u *)TempLine; for (Bitu x=0;x> 4 | (val2 & 0x0f) << 24 | @@ -86,43 +134,78 @@ static Bit8u * VGA_Draw_4BPP_Line(Bitu vidstart,Bitu panning,Bitu line) { } static Bit8u * VGA_Draw_4BPP_Line_Double(Bitu vidstart,Bitu panning,Bitu line) { - Bit8u * reader=&vga.mem.linear[vidstart + (line * 8 * 1024)]; - Bit32u * draw=(Bit32u *)TempLine; + line*=8*1024;Bit32u * draw=(Bit32u *)TempLine; for (Bitu x=0;x> 4 | - (val2 & 0x0f) << 24 | - (val2 & 0xf0) << 12; + if((vga.crtc.mode_control & 0x01) == 0) // CGA compatible addressing + vidstart &= 0x1dfff; + Bitu val=vga.gfxmem_start[vidstart+line]; + vidstart++; + *draw++=(val & 0xf0) >> 4 | + (val & 0xf0) << 4 | + (val & 0x0f) << 16 | + (val & 0x0f) << 24; } return TempLine; } - +static Bit8u * VGA_Draw_LIN4_Line(Bitu vidstart,Bitu panning,Bitu line) { + return &vga.mem.linear[512*1024+vidstart*8+panning]; +} static Bit8u * VGA_Draw_EGA_Line(Bitu vidstart,Bitu panning,Bitu line) { return &vga.mem.linear[512*1024+vidstart*8+panning]; } static Bit8u * VGA_Draw_VGA_Line(Bitu vidstart,Bitu panning,Bitu line) { return &vga.mem.linear[vidstart*4+panning]; } +static Bit8u * VGA_Draw_LIN16_Line(Bitu vidstart,Bitu panning,Bitu line) { + return &vga.mem.linear[vidstart*4+panning]; +} +static Bit8u * VGA_Draw_LIN32_Line(Bitu vidstart,Bitu panning,Bitu line) { + return &vga.mem.linear[vidstart*4+panning]; +} + +static Bit8u * VGA_Draw_VGAChained_Line(Bitu vidstart,Bitu panning,Bitu line) { + return &vga.mem.linear[512*1024+((vidstart*4+panning)&0xffff)]; +} + +static void VGA_StartFrame_VGA() { + if(vga.config.compatible_chain4 && (vga.crtc.underline_location & 0x40)) + VGA_DrawLine=VGA_Draw_VGAChained_Line; + else + VGA_DrawLine = VGA_Draw_VGA_Line; +} static Bit8u * VGA_Draw_VGA_Line_HWMouse(Bitu vidstart, Bitu panning, Bitu line) { if(vga.s3.hgc.curmode & 0x1) { - Bitu lineat = vidstart / 160; - if((lineat < vga.s3.hgc.originy) || (lineat > (vga.s3.hgc.originy + 63))) { + Bitu lineat = vidstart / ((160 * vga.draw.height) / 480); + if((lineat < vga.s3.hgc.originy) || (lineat > (vga.s3.hgc.originy + 63U))) { return VGA_Draw_VGA_Line(vidstart, panning, line); } else { - memcpy(TempLine, VGA_Draw_VGA_Line(vidstart, panning, line), 640); + memcpy(TempLine, VGA_Draw_VGA_Line(vidstart, panning, line), vga.draw.width); /* Draw mouse cursor */ Bits moff = ((Bits)lineat - (Bits)vga.s3.hgc.originy) + (Bits)vga.s3.hgc.posy; - if(moff>63) moff=moff-64; + if(moff>63) return VGA_Draw_VGA_Line(vidstart, panning, line); if(moff<0) moff+=64; Bitu xat = vga.s3.hgc.originx; - Bitu m, mat; - mat = vga.s3.hgc.posx; + Bitu m, mapat; + Bits r, z; + mapat = 0; - for(m=0;m<64;m++) { - switch(vga.s3.hgc.mc[moff][mat]) { + Bitu mouseaddr = (Bit32u)vga.s3.hgc.startaddr * (Bit32u)1024; + mouseaddr+=(moff * 16); + + Bit16u bitsA, bitsB; + Bit8u mappoint; + for(m=0;m<4;m++) { + bitsA = *(Bit16u *)&vga.mem.linear[mouseaddr]; + mouseaddr+=2; + bitsB = *(Bit16u *)&vga.mem.linear[mouseaddr]; + mouseaddr+=2; + z = 7; + for(r=15;r>=0;--r) { + mappoint = (((bitsA >> z) & 0x1) << 1) | ((bitsB >> z) & 0x1); + if(mapat >= vga.s3.hgc.posx) { + switch(mappoint) { case 0: TempLine[xat] = vga.s3.hgc.backstack[0]; break; @@ -133,11 +216,16 @@ static Bit8u * VGA_Draw_VGA_Line_HWMouse(Bitu vidstart, Bitu panning, Bitu line) //Transparent break; case 3: + // Invert screen data + TempLine[xat] = ~TempLine[xat]; break; } xat++; - mat++; - if(mat>63) mat=0; + } + mapat++; + --z; + if(z<0) z=15; + } } return TempLine; } @@ -149,8 +237,9 @@ static Bit8u * VGA_Draw_VGA_Line_HWMouse(Bitu vidstart, Bitu panning, Bitu line) static Bit32u FontMask[2]={0xffffffff,0x0}; static Bit8u * VGA_TEXT_Draw_Line(Bitu vidstart,Bitu panning,Bitu line) { + Bitu font_addr; Bit32u * draw=(Bit32u *)TempLine; - Bit8u * vidmem=&vga.mem.linear[vidstart]; + Bit8u * vidmem=&vga.gfxmem_start[vidstart]; for (Bitu cx=0;cx> 1; if (font_addr>=0 && font_addrvga.draw.cursor.eline) goto skip_cursor; draw=(Bit32u *)&TempLine[font_addr*8]; - Bit32u att=TXT_FG_Table[vga.mem.linear[vga.draw.cursor.address+1]&0xf]; + Bit32u att=TXT_FG_Table[vga.gfxmem_start[vga.draw.cursor.address+1]&0xf]; *draw++=att;*draw++=att; } skip_cursor: @@ -177,7 +266,7 @@ skip_cursor: static void VGA_VerticalDisplayEnd(Bitu val) { vga.config.retrace=true; - vga.config.real_start=vga.config.display_start; + vga.config.real_start=vga.config.display_start & ((2*1024*1024)-1); } static void VGA_HorizontalTimer(void) { @@ -195,7 +284,9 @@ static void VGA_DrawPart(Bitu lines) { vga.draw.address+=vga.draw.address_add; } if (vga.draw.split_line==vga.draw.lines_done) { - vga.draw.address=0;vga.draw.panning=0; + vga.draw.address=0; + if(vga.attr.mode_control&0x20) + vga.draw.panning=0; vga.draw.address_line=0; } } @@ -203,7 +294,7 @@ static void VGA_DrawPart(Bitu lines) { PIC_AddEvent(VGA_DrawPart,vga.draw.delay.parts, (vga.draw.parts_left!=1) ? vga.draw.parts_lines : (vga.draw.lines_total - vga.draw.lines_done)); } else { - RENDER_EndUpdate(); + RENDER_EndUpdate( true ); } } @@ -223,17 +314,21 @@ void VGA_SetBlinking(Bitu enabled) { } static void VGA_VerticalTimer(Bitu val) { + if (VGA_FrameStart) + VGA_FrameStart(); vga.config.retrace=false; PIC_AddEvent(VGA_VerticalTimer,vga.draw.delay.vtotal); PIC_AddEvent(VGA_VerticalDisplayEnd,vga.draw.delay.vend); - if (RENDER_StartUpdate()) { + bool bDoDraw = RENDER_StartUpdate(); + if (bDoDraw) { +// if (RENDER_StartUpdate()) { vga.draw.parts_left=vga.draw.parts_total; vga.draw.lines_done=0; vga.draw.address=vga.config.real_start; vga.draw.address_line=vga.config.hlines_skip; vga.draw.split_line=(vga.config.line_compare/vga.draw.lines_scaled); vga.draw.panning=vga.config.pel_panning; - PIC_AddEvent(VGA_DrawPart,vga.draw.delay.parts,vga.draw.parts_lines); +// PIC_AddEvent(VGA_DrawPart,vga.draw.delay.parts,vga.draw.parts_lines); } switch (vga.mode) { case M_TEXT: @@ -251,17 +346,24 @@ static void VGA_VerticalTimer(Bitu val) { vga.draw.address=(vga.draw.address*2)&0x1fff; break; } - if (machine==MCH_TANDY) { + if (IS_TANDY_ARCH) { vga.draw.address+=vga.tandy.disp_bank << 14; vga.draw.cursor.address+=vga.tandy.disp_bank << 14; } + if (bDoDraw) +// VGA_DrawPart(vga.draw.parts_lines); + PIC_AddEvent(VGA_DrawPart,vga.draw.delay.parts/2,vga.draw.parts_lines); //Else tearline in Tyrian and second reality } void VGA_CheckScanLength(void) { switch (vga.mode) { - case M_EGA16: + case M_EGA: case M_VGA: + case M_LIN4: case M_LIN8: + case M_LIN15: + case M_LIN16: + case M_LIN32: vga.draw.address_add=vga.config.scan_len*2; break; case M_TEXT: @@ -276,7 +378,7 @@ void VGA_CheckScanLength(void) { vga.draw.address_add=vga.draw.blocks/4; break; case M_TANDY4: - vga.draw.address_add=vga.draw.blocks/2; + vga.draw.address_add=vga.draw.blocks; break; case M_TANDY16: vga.draw.address_add=vga.draw.blocks; @@ -293,6 +395,14 @@ void VGA_CheckScanLength(void) { } } +void VGA_ActivateHardwareCursor(void) { + if(vga.s3.hgc.curmode & 0x1) { + VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse; + } else { + VGA_DrawLine=VGA_Draw_VGA_Line; + } +} + void VGA_SetupDrawing(Bitu val) { if (vga.mode==M_ERROR) { PIC_RemoveEvents(VGA_VerticalTimer); @@ -320,8 +430,21 @@ void VGA_SetupDrawing(Bitu val) { if (hbstart> 2) & 3; - clock=1000*S3_CLOCK(vga.s3.clk[clock].m,vga.s3.clk[clock].n,vga.s3.clk[clock].r); + switch (svgaCard) { + case SVGA_S3Trio: + clock = SVGA_S3_GetClock(); + break; + default: + switch ((vga.misc_output >> 2) & 3) { + case 0: + clock = 25175000; + break; + case 1: + clock = 28322000; + break; + } + break; + } /* Check for 8 for 9 character clock mode */ if (vga.seq.clocking_mode & 1 ) clock/=8; else clock/=9; /* Check for pixel doubling, master clock/2 */ @@ -343,7 +466,7 @@ void VGA_SetupDrawing(Bitu val) { vga.draw.double_scan=false; switch (machine) { case MCH_CGA: - case MCH_TANDY: + case TANDY_ARCH_CASE: clock=((vga.tandy.mode_control & 1) ? 14318180 : (14318180/2))/8; break; case MCH_HERC: @@ -372,33 +495,70 @@ void VGA_SetupDrawing(Bitu val) { vga.draw.resizing=false; Bitu width=hdispend; Bitu height=vdispend; + Bitu bpp=8; bool doubleheight=false; bool doublewidth=false; + VGA_FrameStart = NULL; switch (vga.mode) { case M_VGA: doublewidth=true; width<<=2; - VGA_DrawLine=VGA_Draw_VGA_Line; +// Proper line handler is selected at the beginning of the frame +// VGA_DrawLine=VGA_Draw_VGAChained_Line; + VGA_FrameStart=VGA_StartFrame_VGA; break; case M_LIN8: width<<=3; - /* Use HW mouse cursor drawer if enabled */ - if(vga.s3.hgc.curmode & 0x1) { - VGA_DrawLine=VGA_Draw_VGA_Line_HWMouse; - } else { - VGA_DrawLine=VGA_Draw_VGA_Line; + if (vga.crtc.mode_control & 0x8) { + doublewidth = true; + width >>= 1; } + /* Use HW mouse cursor drawer if enabled */ + VGA_ActivateHardwareCursor(); break; - case M_EGA16: + case M_LIN15: + bpp = 15; + width<<=3; + if (vga.crtc.mode_control & 0x8) { + doublewidth = true; + width >>= 1; + } + VGA_DrawLine=VGA_Draw_LIN16_Line; + break; + case M_LIN16: + bpp = 16; + width<<=3; + if (vga.crtc.mode_control & 0x8) { + doublewidth = true; + width >>= 1; + } + VGA_DrawLine=VGA_Draw_LIN16_Line; + break; + case M_LIN32: + bpp = 32; + width<<=3; + if (vga.crtc.mode_control & 0x8) { + doublewidth = true; + width >>= 1; + } + VGA_DrawLine=VGA_Draw_LIN32_Line; + break; + case M_LIN4: doublewidth=(vga.seq.clocking_mode & 0x8) > 0; + vga.draw.blocks = width; + width<<=3; + VGA_DrawLine=VGA_Draw_LIN4_Line; + break; + case M_EGA: + doublewidth=(vga.seq.clocking_mode & 0x8) > 0; + vga.draw.blocks = width; width<<=3; VGA_DrawLine=VGA_Draw_EGA_Line; break; case M_CGA16: - doublewidth=true; doubleheight=true; vga.draw.blocks=width*2; - width<<=3; + width<<=4; VGA_DrawLine=VGA_Draw_CGA16_Line; break; case M_CGA4: @@ -409,8 +569,8 @@ void VGA_SetupDrawing(Bitu val) { break; case M_CGA2: doubleheight=true; - vga.draw.blocks=width; - width<<=4; + vga.draw.blocks=2*width; + width<<=3; VGA_DrawLine=VGA_Draw_1BPP_Line; break; case M_TEXT: @@ -429,7 +589,8 @@ void VGA_SetupDrawing(Bitu val) { case M_TANDY2: aspect_ratio=1.2; doubleheight=true; - doublewidth=(vga.tandy.mode_control & 0x10)==0; + if (machine==MCH_PCJR) doublewidth=(vga.tandy.gfx_control & 0x8)==0x00; + else doublewidth=(vga.tandy.mode_control & 0x10)==0; vga.draw.blocks=width * (doublewidth ? 4:8); width=vga.draw.blocks*2; VGA_DrawLine=VGA_Draw_1BPP_Line; @@ -437,18 +598,26 @@ void VGA_SetupDrawing(Bitu val) { case M_TANDY4: aspect_ratio=1.2; doubleheight=true; - doublewidth=(vga.tandy.mode_control & 0x10)==0; - vga.draw.blocks=width * (doublewidth ? 4:8); - width=vga.draw.blocks*2; - VGA_DrawLine=VGA_Draw_2BPP_Line; + if (machine==MCH_TANDY) doublewidth=(vga.tandy.mode_control & 0x10)==0; + else doublewidth=(vga.tandy.mode_control & 0x01)==0x00; + vga.draw.blocks=width * 2; + width=vga.draw.blocks*4; + if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) || + (machine==MCH_PCJR && (vga.tandy.mode_control==0x0b))) VGA_DrawLine=VGA_Draw_2BPPHiRes_Line; + else VGA_DrawLine=VGA_Draw_2BPP_Line; break; case M_TANDY16: aspect_ratio=1.2; doubleheight=true; - doublewidth=(vga.tandy.mode_control & 0x10)==0; - vga.draw.blocks=width * (doublewidth ? 2:4); - width=vga.draw.blocks*2; - VGA_DrawLine=VGA_Draw_4BPP_Line; + doublewidth=true; + vga.draw.blocks=width*2; + if (vga.tandy.mode_control & 0x1) { + width=vga.draw.blocks*2; + VGA_DrawLine=VGA_Draw_4BPP_Line; + } else { + width=vga.draw.blocks*4; + VGA_DrawLine=VGA_Draw_4BPP_Line_Double; + } break; case M_TANDY_TEXT: doublewidth=(vga.tandy.mode_control & 0x1)==0; @@ -475,7 +644,8 @@ void VGA_SetupDrawing(Bitu val) { } vga.draw.lines_total=height; vga.draw.parts_lines=vga.draw.lines_total/vga.draw.parts_total; - if (( width != vga.draw.width) || (height != vga.draw.height)) { + if (( width != vga.draw.width) || (height != vga.draw.height) || (vga.mode != vga.lastmode)) { + vga.lastmode = vga.mode; PIC_RemoveEvents(VGA_VerticalTimer); PIC_RemoveEvents(VGA_VerticalDisplayEnd); PIC_RemoveEvents(VGA_DrawPart); @@ -490,7 +660,11 @@ void VGA_SetupDrawing(Bitu val) { LOG(LOG_VGA,LOG_NORMAL)("%s width, %s height aspect %f", doublewidth ? "double":"normal",doubleheight ? "double":"normal",aspect_ratio); #endif - RENDER_SetSize(width,height,8,aspect_ratio,doublewidth,doubleheight); + RENDER_SetSize(width,height,bpp,fps,aspect_ratio,doublewidth,doubleheight); PIC_AddEvent(VGA_VerticalTimer,vga.draw.delay.vtotal); } }; + +void VGA_KillDrawing(void) { + PIC_RemoveEvents(VGA_DrawPart); +} diff --git a/src/hardware/vga_gfx.cpp b/src/hardware/vga_gfx.cpp index 5a1725e..7a8190b 100644 --- a/src/hardware/vga_gfx.cpp +++ b/src/hardware/vga_gfx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/hardware/vga_memory.cpp b/src/hardware/vga_memory.cpp index 490297f..6138229 100644 --- a/src/hardware/vga_memory.cpp +++ b/src/hardware/vga_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -26,22 +26,7 @@ #include "inout.h" void VGA_MapMMIO(void); - -static Bitu VGA_NormalReadHandler(PhysPt start) { - vga.latch.d=vga.mem.latched[start].d; - switch (vga.config.read_mode) { - case 0: - return (vga.latch.b[vga.config.read_map_select]); - case 1: - VGA_Latch templatch; - templatch.d=(vga.latch.d & FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care]; - return (Bit8u)~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]); - } - return 0; -} - //Nice one from DosEmu - INLINE static Bit32u RasterOp(Bit32u input,Bit32u mask) { switch (vga.config.raster_op) { case 0x00: /* None */ @@ -61,6 +46,7 @@ INLINE static Bit32u ModeOperation(Bit8u val) { switch (vga.config.write_mode) { case 0x00: // Write Mode 0: In this mode, the host data is first rotated as per the Rotate Count field, then the Enable Set/Reset mechanism selects data from this or the Set/Reset field. Then the selected Logical Operation is performed on the resulting data and the data in the latch register. Then the Bit Mask field is used to select which bits come from the resulting data and which come from the latch register. Finally, only the bit planes enabled by the Memory Plane Write Enable field are written to memory. + val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate))); full=ExpandTable[val]; full=(full & vga.config.full_not_enable_set_reset) | vga.config.full_enable_and_set_reset; full=RasterOp(full,vga.config.full_bit_mask); @@ -83,47 +69,6 @@ INLINE static Bit32u ModeOperation(Bit8u val) { return full; } -static void VGA_GFX_16_WriteHandler(PhysPt start,Bit8u val) { - val=((val >> vga.config.data_rotate) | (val << (8-vga.config.data_rotate))); - Bit32u data=ModeOperation(val); - /* Update video memory and the pixel buffer */ - VGA_Latch pixels; - pixels.d=vga.mem.latched[start].d; - pixels.d&=vga.config.full_not_map_mask; - pixels.d|=(data & vga.config.full_map_mask); - vga.mem.latched[start].d=pixels.d; - Bit8u * write_pixels=&vga.mem.linear[512*1024+(start<<3)]; - - Bit32u colors0_3, colors4_7; - VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f; - colors0_3 = - Expand16Table[0][temp.b[0]] | - Expand16Table[1][temp.b[1]] | - Expand16Table[2][temp.b[2]] | - Expand16Table[3][temp.b[3]]; - *(Bit32u *)write_pixels=colors0_3; - *(Bit32u *)(write_pixels+512*1024)=colors0_3; - temp.d=pixels.d & 0x0f0f0f0f; - colors4_7 = - Expand16Table[0][temp.b[0]] | - Expand16Table[1][temp.b[1]] | - Expand16Table[2][temp.b[2]] | - Expand16Table[3][temp.b[3]]; - *(Bit32u *)(write_pixels+4)=colors4_7; - *(Bit32u *)(write_pixels+512*1024+4)=colors4_7; - -} - -static void VGA_GFX_256U_WriteHandler(PhysPt start,Bit8u val) { - Bit32u data=ModeOperation(val); - VGA_Latch pixels; - pixels.d=vga.mem.latched[start].d; - pixels.d&=vga.config.full_not_map_mask; - pixels.d|=(data & vga.config.full_map_mask); - vga.mem.latched[start].d=pixels.d; - vga.mem.latched[start+64*1024].d=pixels.d; -} - /* Gonna assume that whoever maps vga memory, maps it on 32/64kb boundary */ #define VGA_PAGES (128/4) @@ -132,74 +77,238 @@ static void VGA_GFX_256U_WriteHandler(PhysPt start,Bit8u val) { #define VGA_PAGE_B8 (0xB8000/4096) static struct { - Bitu base,mask; + Bitu base, mask; } vgapages; -class VGARead_PageHandler : public PageHandler { +class VGA_UnchainedRead_Handler : public PageHandler { +public: + Bitu readHandler(PhysPt start) { + vga.latch.d=vga.mem.latched[start].d; + switch (vga.config.read_mode) { + case 0: + return (vga.latch.b[vga.config.read_map_select]); + case 1: + VGA_Latch templatch; + templatch.d=(vga.latch.d & FillTable[vga.config.color_dont_care]) ^ FillTable[vga.config.color_compare & vga.config.color_dont_care]; + return (Bit8u)~(templatch.b[0] | templatch.b[1] | templatch.b[2] | templatch.b[3]); + } + return 0; + } public: Bitu readb(PhysPt addr) { - addr&=0xffff; - return VGA_NormalReadHandler(addr); + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + return readHandler(addr); } Bitu readw(PhysPt addr) { - addr&=0xffff; + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; return - (VGA_NormalReadHandler(addr+0) << 0) | - (VGA_NormalReadHandler(addr+1) << 8); + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8); } Bitu readd(PhysPt addr) { - addr&=0xffff; + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; return - (VGA_NormalReadHandler(addr+0) << 0) | - (VGA_NormalReadHandler(addr+1) << 8) | - (VGA_NormalReadHandler(addr+2) << 16) | - (VGA_NormalReadHandler(addr+3) << 24); + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8) | + (readHandler(addr+2) << 16) | + (readHandler(addr+3) << 24); } }; -class VGA_16_PageHandler : public VGARead_PageHandler { -public: - VGA_16_PageHandler() { - flags=PFLAG_NOCODE; +class VGA_Chained_ReadHandler : public PageHandler { +public: + Bitu readHandler(PhysPt addr) { + if(vga.mode == M_VGA) + return vga.mem.linear[((addr&~3)<<2)|(addr&3)]; + return vga.mem.linear[addr]; } - void writeb(PhysPt addr,Bitu val) { - addr&=0xffff; - VGA_GFX_16_WriteHandler(addr+0,(Bit8u)(val >> 0)); +public: + Bitu readb(PhysPt addr) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + return readHandler(addr); } - void writew(PhysPt addr,Bitu val) { - addr&=0xffff; - VGA_GFX_16_WriteHandler(addr+0,(Bit8u)(val >> 0)); - VGA_GFX_16_WriteHandler(addr+1,(Bit8u)(val >> 8)); + Bitu readw(PhysPt addr) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + return + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8); } - void writed(PhysPt addr,Bitu val) { - addr&=0xffff; - VGA_GFX_16_WriteHandler(addr+0,(Bit8u)(val >> 0)); - VGA_GFX_16_WriteHandler(addr+1,(Bit8u)(val >> 8)); - VGA_GFX_16_WriteHandler(addr+2,(Bit8u)(val >> 16)); - VGA_GFX_16_WriteHandler(addr+3,(Bit8u)(val >> 24)); + Bitu readd(PhysPt addr) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + return + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8) | + (readHandler(addr+2) << 16) | + (readHandler(addr+3) << 24); } }; -class VGA_256_PageHandler : public VGARead_PageHandler { +class VGA_ChainedEGA_Handler : public VGA_Chained_ReadHandler { +public: + void writeHandler(PhysPt start, Bit8u val) { + Bit32u data=ModeOperation(val); + /* Update video memory and the pixel buffer */ + VGA_Latch pixels; + vga.mem.linear[start] = val; + start >>= 2; + pixels.d=vga.mem.latched[start].d; + + Bit8u * write_pixels=&vga.mem.linear[512*1024+(start<<3)]; + + Bit32u colors0_3, colors4_7; + VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f; + colors0_3 = + Expand16Table[0][temp.b[0]] | + Expand16Table[1][temp.b[1]] | + Expand16Table[2][temp.b[2]] | + Expand16Table[3][temp.b[3]]; + *(Bit32u *)write_pixels=colors0_3; + temp.d=pixels.d & 0x0f0f0f0f; + colors4_7 = + Expand16Table[0][temp.b[0]] | + Expand16Table[1][temp.b[1]] | + Expand16Table[2][temp.b[2]] | + Expand16Table[3][temp.b[3]]; + *(Bit32u *)(write_pixels+4)=colors4_7; + } public: - VGA_256_PageHandler() { + VGA_ChainedEGA_Handler() { flags=PFLAG_NOCODE; } void writeb(PhysPt addr,Bitu val) { - addr&=0xffff; - VGA_GFX_256U_WriteHandler(addr+0,(Bit8u)(val >> 0)); + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); } void writew(PhysPt addr,Bitu val) { - addr&=0xffff; - VGA_GFX_256U_WriteHandler(addr+0,(Bit8u)(val >> 0)); - VGA_GFX_256U_WriteHandler(addr+1,(Bit8u)(val >> 8)); + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); } void writed(PhysPt addr,Bitu val) { - addr&=0xffff; - VGA_GFX_256U_WriteHandler(addr+0,(Bit8u)(val >> 0)); - VGA_GFX_256U_WriteHandler(addr+1,(Bit8u)(val >> 8)); - VGA_GFX_256U_WriteHandler(addr+2,(Bit8u)(val >> 16)); - VGA_GFX_256U_WriteHandler(addr+3,(Bit8u)(val >> 24)); + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + writeHandler(addr+2,(Bit8u)(val >> 16)); + writeHandler(addr+3,(Bit8u)(val >> 24)); + } +}; + +class VGA_UnchainedEGA_Handler : public VGA_UnchainedRead_Handler { +public: + void writeHandler(PhysPt start, Bit8u val) { + Bit32u data=ModeOperation(val); + /* Update video memory and the pixel buffer */ + VGA_Latch pixels; + pixels.d=vga.mem.latched[start].d; + pixels.d&=vga.config.full_not_map_mask; + pixels.d|=(data & vga.config.full_map_mask); + vga.mem.latched[start].d=pixels.d; + Bit8u * write_pixels=&vga.mem.linear[512*1024+(start<<3)]; + + Bit32u colors0_3, colors4_7; + VGA_Latch temp;temp.d=(pixels.d>>4) & 0x0f0f0f0f; + colors0_3 = + Expand16Table[0][temp.b[0]] | + Expand16Table[1][temp.b[1]] | + Expand16Table[2][temp.b[2]] | + Expand16Table[3][temp.b[3]]; + *(Bit32u *)write_pixels=colors0_3; + *(Bit32u *)(write_pixels+512*1024)=colors0_3; + temp.d=pixels.d & 0x0f0f0f0f; + colors4_7 = + Expand16Table[0][temp.b[0]] | + Expand16Table[1][temp.b[1]] | + Expand16Table[2][temp.b[2]] | + Expand16Table[3][temp.b[3]]; + *(Bit32u *)(write_pixels+4)=colors4_7; + *(Bit32u *)(write_pixels+512*1024+4)=colors4_7; + } +public: + VGA_UnchainedEGA_Handler() { + flags=PFLAG_NOCODE; + } + void writeb(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + } + void writew(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + } + void writed(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + writeHandler(addr+2,(Bit8u)(val >> 16)); + writeHandler(addr+3,(Bit8u)(val >> 24)); + } +}; + + +class VGA_ChainedVGA_Handler : public VGA_Chained_ReadHandler { +public: + void writeHandler(PhysPt addr, Bitu val) { + // No need to check for compatible chains here, this one is only enabled if that bit is set + vga.mem.linear[((addr&~3)<<2)|(addr&3)] = val; + // Linearized version for faster rendering + vga.mem.linear[512*1024+addr] = val; + // And replicate the first line + if (addr < 320) + vga.mem.linear[512*1024+addr+64*1024] = val; + } +public: + VGA_ChainedVGA_Handler() { + flags=PFLAG_NOCODE; + } + void writeb(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + } + void writew(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + } + void writed(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + writeHandler(addr+2,(Bit8u)(val >> 16)); + writeHandler(addr+3,(Bit8u)(val >> 24)); + } +}; + +class VGA_UnchainedVGA_Handler : public VGA_UnchainedRead_Handler { +public: + void writeHandler( PhysPt addr, Bit8u val ) { + Bit32u data=ModeOperation(val); + VGA_Latch pixels; + pixels.d=vga.mem.latched[addr].d; + pixels.d&=vga.config.full_not_map_mask; + pixels.d|=(data & vga.config.full_map_mask); + vga.mem.latched[addr].d=pixels.d; + vga.mem.latched[addr+64*1024].d=pixels.d; + } +public: + VGA_UnchainedVGA_Handler() { + flags=PFLAG_NOCODE; + } + void writeb(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + } + void writew(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + } + void writed(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) & 0xffff; + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + writeHandler(addr+2,(Bit8u)(val >> 16)); + writeHandler(addr+3,(Bit8u)(val >> 24)); } }; @@ -209,11 +318,11 @@ public: flags=PFLAG_NOCODE; } Bitu readb(PhysPt addr) { - addr&=vgapages.mask; + addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; return vga.draw.font[addr]; } void writeb(PhysPt addr,Bitu val){ - addr&=vgapages.mask; + addr = PAGING_GetPhysicalAddress(addr) & vgapages.mask; if (vga.seq.map_mask & 0x4) { vga.draw.font[addr]=(Bit8u)val; } @@ -225,37 +334,188 @@ public: VGA_MAP_PageHandler() { flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE; } - HostPt GetHostPt(Bitu phys_page) { + HostPt GetHostReadPt(Bitu phys_page) { + phys_page-=vgapages.base; + return &vga.mem.linear[vga.s3.bank*64*1024+phys_page*4096]; + } + HostPt GetHostWritePt(Bitu phys_page) { phys_page-=vgapages.base; return &vga.mem.linear[vga.s3.bank*64*1024+phys_page*4096]; } }; -class VGA_MMIO_PageHandler : public PageHandler { + +class VGA_LIN4Linear_Handler : public VGA_UnchainedEGA_Handler { +public: + VGA_LIN4Linear_Handler() { + flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE; + } + void writeb(PhysPt addr,Bitu val) { + addr = (PAGING_GetPhysicalAddress(addr) - vga.lfb.addr) & (512*1024-1); + writeHandler(addr+0,(Bit8u)(val >> 0)); + } + void writew(PhysPt addr,Bitu val) { + addr = (PAGING_GetPhysicalAddress(addr) - vga.lfb.addr) & (512*1024-1); + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + } + void writed(PhysPt addr,Bitu val) { + addr = (PAGING_GetPhysicalAddress(addr) - vga.lfb.addr) & (512*1024-1); + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + writeHandler(addr+2,(Bit8u)(val >> 16)); + writeHandler(addr+3,(Bit8u)(val >> 24)); + } + Bitu readb(PhysPt addr) { + addr = (PAGING_GetPhysicalAddress(addr) - vga.lfb.addr) & (512*1024-1); + return readHandler(addr); + } + Bitu readw(PhysPt addr) { + addr = (PAGING_GetPhysicalAddress(addr) - vga.lfb.addr) & (512*1024-1); + return + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8); + } + Bitu readd(PhysPt addr) { + addr = (PAGING_GetPhysicalAddress(addr) - vga.lfb.addr) & (512*1024-1); + return + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8) | + (readHandler(addr+2) << 16) | + (readHandler(addr+3) << 24); + } +}; + +class VGA_LIN4Banked_Handler : public VGA_UnchainedEGA_Handler { +public: + VGA_LIN4Banked_Handler() { + flags=PFLAG_NOCODE; + } + void writeb(PhysPt addr,Bitu val) { + addr = vga.s3.bank*64*1024 + (PAGING_GetPhysicalAddress(addr) & 0xffff); + addr &= (512*1024-1); + writeHandler(addr+0,(Bit8u)(val >> 0)); + } + void writew(PhysPt addr,Bitu val) { + addr = vga.s3.bank*64*1024 + (PAGING_GetPhysicalAddress(addr) & 0xffff); + addr &= (512*1024-1); + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + } + void writed(PhysPt addr,Bitu val) { + addr = vga.s3.bank*64*1024 + (PAGING_GetPhysicalAddress(addr) & 0xffff); + addr &= (512*1024-1); + writeHandler(addr+0,(Bit8u)(val >> 0)); + writeHandler(addr+1,(Bit8u)(val >> 8)); + writeHandler(addr+2,(Bit8u)(val >> 16)); + writeHandler(addr+3,(Bit8u)(val >> 24)); + } + Bitu readb(PhysPt addr) { + addr = vga.s3.bank*64*1024 + (PAGING_GetPhysicalAddress(addr) & 0xffff); + addr &= (512*1024-1); + return readHandler(addr); + } + Bitu readw(PhysPt addr) { + addr = vga.s3.bank*64*1024 + (PAGING_GetPhysicalAddress(addr) & 0xffff); + addr &= (512*1024-1); + return + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8); + } + Bitu readd(PhysPt addr) { + addr = vga.s3.bank*64*1024 + (PAGING_GetPhysicalAddress(addr) & 0xffff); + addr &= (512*1024-1); + return + (readHandler(addr+0) << 0) | + (readHandler(addr+1) << 8) | + (readHandler(addr+2) << 16) | + (readHandler(addr+3) << 24); + } +}; + + +class VGA_LFBChanges_Handler : public PageHandler { +public: + VGA_LFBChanges_Handler() { + flags=PFLAG_NOCODE; + } + Bitu readb(PhysPt addr) { + addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr; + return *(Bit8u*)(&vga.mem.linear[addr]); + } + Bitu readw(PhysPt addr) { + addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr; + return *(Bit16u*)(&vga.mem.linear[addr]); + } + Bitu readd(PhysPt addr) { + addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr; + return *(Bit32u*)(&vga.mem.linear[addr]); + } + void writeb(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr; + *(Bit8u*)(&vga.mem.linear[addr]) = val; + vga.changed[addr >> VGA_CHANGE_SHIFT] = 1; + } + void writew(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr; + *(Bit16u*)(&vga.mem.linear[addr]) = val; + vga.changed[addr >> VGA_CHANGE_SHIFT] = 1; + } + void writed(PhysPt addr,Bitu val) { + addr = PAGING_GetPhysicalAddress(addr) - vga.lfb.addr; + *(Bit32u*)(&vga.mem.linear[addr]) = val; + vga.changed[addr >> VGA_CHANGE_SHIFT] = 1; + } +}; + +class VGA_LFB_Handler : public PageHandler { +public: + VGA_LFB_Handler() { + flags=PFLAG_READABLE|PFLAG_WRITEABLE|PFLAG_NOCODE; + } + HostPt GetHostReadPt( Bitu phys_page ) { + phys_page -= vga.lfb.page; + return &vga.mem.linear[phys_page * 4096]; + } + HostPt GetHostWritePt( Bitu phys_page ) { + return GetHostReadPt( phys_page ); + } +}; + +class VGA_MMIO_Handler : public PageHandler { public: Bit16u regmem[16384]; - - VGA_MMIO_PageHandler() { + VGA_MMIO_Handler() { flags=PFLAG_NOCODE; //memset(®mem[0], 0, sizeof(regmem)); } void writeb(PhysPt addr,Bitu val) { - Bitu port = addr & 0xffff; + Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; if(port >= 0x82E8) IO_WriteB(port, val); - LOG_MSG("MMIO: Write byte to %x with %x", addr, val); + if(port <= 0x4000) { + if(port == 0x0000) { + IO_WriteB(0xe2e0, val); + } else { + IO_WriteB(0xe2e8, val); + } + } + //LOG_MSG("MMIO: Write byte to %x with %x", addr, val); } void writew(PhysPt addr,Bitu val) { - Bitu port = addr & 0xffff; + Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; if(port >= 0x82E8) IO_WriteW(port, val); if(port == 0x8118) IO_WriteW(0x9ae8, val); - if(port <= 0x0020) { + if(port <= 0x4000) { + if(port == 0x0000) { + IO_WriteW(0xe2e0, val); + } else { IO_WriteW(0xe2e8, val); } - - LOG_MSG("MMIO: Write word to %x with %x", addr, val); + } + //LOG_MSG("MMIO: Write word to %x with %x", addr, val); } void writed(PhysPt addr,Bitu val) { - Bitu port = addr & 0xffff; + Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; if(port >= 0x82E8) IO_WriteD(port, val); if(port == 0x8100) { IO_WriteW(0x86e8, (val >> 16)); @@ -265,27 +525,32 @@ public: IO_WriteW(0x96e8, (val >> 16)); IO_WriteW(0xbee8, (val & 0xffff)); } - if(port <= 0x0020) { - IO_WriteW(0xe2e8, (val & 0xffff)); - IO_WriteW(0xe2e8, (val >> 16)); + if(port <= 0x4000) { + if(port == 0x0000) { + IO_WriteW(0xe2e0, (val & 0xffff)); + IO_WriteW(0xe2e8, (val >> 16)); + } else { + IO_WriteW(0xe2e8, (val & 0xffff)); + IO_WriteW(0xe2e8, (val >> 16)); + } } - LOG_MSG("MMIO: Write dword to %x with %x", addr, val); + //LOG_MSG("MMIO: Write dword to %x with %x", addr, val); } Bitu readb(PhysPt addr) { - LOG_MSG("MMIO: Read byte from %x", addr); + //LOG_MSG("MMIO: Read byte from %x", addr); return 0x00; } Bitu readw(PhysPt addr) { - Bitu port = addr & 0xffff; + Bitu port = PAGING_GetPhysicalAddress(addr) & 0xffff; if(port >= 0x82E8) return IO_ReadW(port); - LOG_MSG("MMIO: Read word from %x", addr); + //LOG_MSG("MMIO: Read word from %x", addr); return 0x00; } Bitu readd(PhysPt addr) { - LOG_MSG("MMIO: Read dword from %x", addr); + //LOG_MSG("MMIO: Read dword from %x", addr); return 0x00; } @@ -297,25 +562,50 @@ public: flags=PFLAG_READABLE|PFLAG_WRITEABLE; // |PFLAG_NOCODE; } - HostPt GetHostPt(Bitu phys_page) { + HostPt GetHostReadPt(Bitu phys_page) { if (phys_page>=0xb8) { phys_page-=0xb8; return &vga.mem.linear[(vga.tandy.mem_bank << 14)+(phys_page * 4096)]; } else { - phys_page-=0x80; + if (machine==MCH_TANDY) phys_page-=0x80; return &vga.mem.linear[phys_page * 4096]; } } + HostPt GetHostWritePt(Bitu phys_page) { + return GetHostReadPt( phys_page ); + } +}; + +class VGA_PCJR_PageHandler : public PageHandler { +public: + VGA_PCJR_PageHandler() { + flags=PFLAG_READABLE|PFLAG_WRITEABLE; + } + HostPt GetHostReadPt(Bitu phys_page) { + phys_page-=0xb8; + if (!vga.tandy.is_32k_mode) phys_page&=0x03; + return MemBase+(vga.tandy.mem_bank << 14)+(phys_page * 4096); + } + HostPt GetHostWritePt(Bitu phys_page) { + return GetHostReadPt( phys_page ); + } }; static struct vg { - VGA_MAP_PageHandler hmap; - VGA_TEXT_PageHandler htext; - VGA_TANDY_PageHandler htandy; - VGA_256_PageHandler h256; - VGA_16_PageHandler h16; - VGA_MMIO_PageHandler mmio; + VGA_MAP_PageHandler map; + VGA_TEXT_PageHandler text; + VGA_TANDY_PageHandler tandy; + VGA_ChainedEGA_Handler cega; + VGA_ChainedVGA_Handler cvga; + VGA_UnchainedEGA_Handler uega; + VGA_UnchainedVGA_Handler uvga; + VGA_PCJR_PageHandler hpcjr; + VGA_LIN4Banked_Handler l4banked; + VGA_LIN4Linear_Handler l4linear; + VGA_LFB_Handler lfb; + VGA_LFBChanges_Handler lfbchanges; + VGA_MMIO_Handler mmio; } vgaph; @@ -323,41 +613,57 @@ void VGA_SetupHandlers(void) { PageHandler * range_handler; switch (machine) { case MCH_CGA: - range_handler=&vgaph.hmap; + range_handler=&vgaph.map; goto range_b800; case MCH_HERC: - range_handler=&vgaph.hmap; + range_handler=&vgaph.map; if (vga.herc.mode_control&0x80) goto range_b800; else goto range_b000; case MCH_TANDY: - range_handler=&vgaph.htandy; + range_handler=&vgaph.tandy; MEM_SetPageHandler(0x80,32,range_handler); goto range_b800; + case MCH_PCJR: + range_handler=&vgaph.hpcjr; +// MEM_SetPageHandler(vga.tandy.mem_bank<<2,vga.tandy.is_32k_mode ? 0x08 : 0x04,range_handler); + goto range_b800; } switch (vga.mode) { case M_ERROR: return; + case M_LIN4: + range_handler=&vgaph.l4banked; + break; case M_LIN8: - range_handler=&vgaph.hmap; + case M_LIN15: + case M_LIN16: + case M_LIN32: + range_handler=&vgaph.map; break; case M_VGA: if (vga.config.chained) { - range_handler=&vgaph.hmap; + if(vga.config.compatible_chain4) + range_handler = &vgaph.cvga; + else + range_handler=&vgaph.map; } else { - range_handler=&vgaph.h256; + range_handler=&vgaph.uvga; } break; - case M_EGA16: - range_handler=&vgaph.h16; + case M_EGA: + if (vga.config.chained) + range_handler=&vgaph.cega; + else + range_handler=&vgaph.uega; break; case M_TEXT: /* Check if we're not in odd/even mode */ - if (vga.gfx.miscellaneous & 0x2) range_handler=&vgaph.hmap; - else range_handler=&vgaph.htext; + if (vga.gfx.miscellaneous & 0x2) range_handler=&vgaph.map; + else range_handler=&vgaph.text; break; case M_CGA4: case M_CGA2: - range_handler=&vgaph.hmap; + range_handler=&vgaph.map; break; } switch ((vga.gfx.miscellaneous >> 2) & 3) { @@ -390,28 +696,28 @@ range_b800: break; } - if(((vga.s3.ext_mem_ctrl & 0x10) != 0x00) && (vga.mode == M_LIN8)) MEM_SetPageHandler(VGA_PAGE_A0, 16, &vgaph.mmio); + if(((vga.s3.ext_mem_ctrl & 0x10) != 0x00) && (vga.mode == M_LIN8)) + MEM_SetPageHandler(VGA_PAGE_A0, 16, &vgaph.mmio); PAGING_ClearTLB(); } -static bool lfb_update; - -static void VGA_DoUpdateLFB(Bitu val) { - lfb_update=false; - MEM_SetLFB(vga.s3.la_window << 4 ,sizeof(vga.mem.linear)/4096,&vga.mem.linear[0]); -} - void VGA_StartUpdateLFB(void) { - if (!lfb_update) { - lfb_update=true; - PIC_AddEvent(VGA_DoUpdateLFB,0.100f); //100 microseconds later + vga.lfb.page = vga.s3.la_window << 4; + vga.lfb.addr = vga.s3.la_window << 16; + switch (vga.mode) { + case M_LIN4: + vga.lfb.handler = &vgaph.l4linear; + break; + default: + vga.lfb.handler = &vgaph.lfbchanges; + break; } + MEM_SetLFB(vga.s3.la_window << 4 ,sizeof(vga.mem.linear)/4096, vga.lfb.handler ); } void VGA_MapMMIO(void) { MEM_SetPageHandler(VGA_PAGE_A0, 16, &vgaph.mmio); - } void VGA_UnmapMMIO(void) { @@ -421,4 +727,9 @@ void VGA_UnmapMMIO(void) { void VGA_SetupMemory() { memset((void *)&vga.mem,0,512*1024*4); + if (machine==MCH_PCJR) { + /* PCJr does not have dedicated graphics memory but uses + conventional memory below 128k */ + vga.gfxmem_start=GetMemBase(); + } else vga.gfxmem_start=&vga.mem.linear[0]; } diff --git a/src/hardware/vga_misc.cpp b/src/hardware/vga_misc.cpp index 037a581..141bfba 100644 --- a/src/hardware/vga_misc.cpp +++ b/src/hardware/vga_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -23,13 +23,14 @@ static Bit8u flip=0; -void write_p3d4_vga(Bitu port,Bitu val,Bitu iolen); -Bitu read_p3d4_vga(Bitu port,Bitu iolen); -void write_p3d5_vga(Bitu port,Bitu val,Bitu iolen); -Bitu read_p3d5_vga(Bitu port,Bitu iolen); +void vga_write_p3d4(Bitu port,Bitu val,Bitu iolen); +Bitu vga_read_p3d4(Bitu port,Bitu iolen); +void vga_write_p3d5(Bitu port,Bitu val,Bitu iolen); +Bitu vga_read_p3d5(Bitu port,Bitu iolen); -static Bitu read_p3da(Bitu port,Bitu iolen) { +static Bitu vga_read_p3da(Bitu port,Bitu iolen) { vga.internal.attrindex=false; + vga.tandy.pcjr_flipflop=false; if (vga.config.retrace) { switch (machine) { case MCH_HERC: @@ -52,23 +53,26 @@ static Bitu read_p3da(Bitu port,Bitu iolen) { static void write_p3c2(Bitu port,Bitu val,Bitu iolen) { vga.misc_output=val; if (val & 0x1) { - IO_RegisterWriteHandler(0x3d4,write_p3d4_vga,IO_MB); - IO_RegisterReadHandler(0x3d4,read_p3d4_vga,IO_MB); - IO_RegisterWriteHandler(0x3d5,write_p3d5_vga,IO_MB); - IO_RegisterReadHandler(0x3d5,read_p3d5_vga,IO_MB); - IO_RegisterReadHandler(0x3da,read_p3da,IO_MB); - + IO_RegisterWriteHandler(0x3d4,vga_write_p3d4,IO_MB); + IO_RegisterReadHandler(0x3d4,vga_read_p3d4,IO_MB); + IO_RegisterReadHandler(0x3da,vga_read_p3da,IO_MB); + + IO_RegisterWriteHandler(0x3d5,vga_write_p3d5,IO_MB); + IO_RegisterReadHandler(0x3d5,vga_read_p3d5,IO_MB); + IO_FreeWriteHandler(0x3b4,IO_MB); IO_FreeReadHandler(0x3b4,IO_MB); IO_FreeWriteHandler(0x3b5,IO_MB); IO_FreeReadHandler(0x3b5,IO_MB); IO_FreeReadHandler(0x3ba,IO_MB); } else { - IO_RegisterWriteHandler(0x3b4,write_p3d4_vga,IO_MB); - IO_RegisterReadHandler(0x3b4,read_p3d4_vga,IO_MB); - IO_RegisterWriteHandler(0x3b5,write_p3d5_vga,IO_MB); - IO_RegisterReadHandler(0x3b5,read_p3d5_vga,IO_MB); - IO_RegisterReadHandler(0x3ba,read_p3da,IO_MB); + IO_RegisterWriteHandler(0x3b4,vga_write_p3d4,IO_MB); + IO_RegisterReadHandler(0x3b4,vga_read_p3d4,IO_MB); + IO_RegisterReadHandler(0x3ba,vga_read_p3da,IO_MB); + + IO_RegisterWriteHandler(0x3b5,vga_write_p3d5,IO_MB); + IO_RegisterReadHandler(0x3b5,vga_read_p3d5,IO_MB); + IO_FreeWriteHandler(0x3d4,IO_MB); IO_FreeReadHandler(0x3d4,IO_MB); @@ -94,18 +98,36 @@ static Bitu read_p3cc(Bitu port,Bitu iolen) { return vga.misc_output; } +/* +Test 13: Hardware: General Registers + Mode 00h, General -- Feat Ctrl: IBM=00h Current=FFh + Mode 00h, General -- Input Status 0: IBM=70h Current=FFh + .. & modes 1,2,3,4,5,6,d,e,10,11,12,13 + +following read handlers silence the above vgatest errors. + +*/ + +static Bitu read_p3ca(Bitu port,Bitu iolen) { + return 0; +} + +static Bitu read_p3c2(Bitu port,Bitu iolen) { + return 0x70; +} void VGA_SetupMisc(void) { if (machine==MCH_VGA) { + IO_RegisterReadHandler(0x3ca,read_p3ca,IO_MB); + IO_RegisterReadHandler(0x3c2,read_p3c2,IO_MB); IO_RegisterWriteHandler(0x3c2,write_p3c2,IO_MB); IO_RegisterReadHandler(0x3cc,read_p3cc,IO_MB); - } else if (machine==MCH_CGA || machine==MCH_TANDY) { - IO_RegisterReadHandler(0x3da,read_p3da,IO_MB); + } else if (machine==MCH_CGA || IS_TANDY_ARCH) { + IO_RegisterReadHandler(0x3da,vga_read_p3da,IO_MB); } else if (machine==MCH_HERC) { - IO_RegisterReadHandler(0x3ba,read_p3da,IO_MB); + IO_RegisterReadHandler(0x3ba,vga_read_p3da,IO_MB); } - } diff --git a/src/hardware/vga_other.cpp b/src/hardware/vga_other.cpp index 807d7ab..3cbf5b3 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,10 +16,15 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: vga_other.cpp,v 1.18 2006/02/12 23:55:53 harekiet Exp $ */ + #include +#include #include "dosbox.h" #include "inout.h" #include "vga.h" +#include "render.h" +#include "mapper.h" static void write_crtc_index_other(Bitu port,Bitu val,Bitu iolen) { vga.other.index=val; @@ -123,6 +128,87 @@ static Bitu read_crtc_data_other(Bitu port,Bitu iolen) { return (Bitu)-1; } +static double hue_offset = 0.0; +static Bit8u cga16_val = 0; +static void update_cga16_color(void); + +static void cga16_color_select(Bit8u val) { + cga16_val = val; + update_cga16_color(); +} + +static void update_cga16_color(void) { +// Algorithm provided by NewRisingSun +// His/Her algorithm is more complex and gives better results than the one below +// However that algorithm doesn't fit in our vga pallette. +// Therefore a simple variant is used, but the colours are bit lighter. + +// It uses an avarage over the bits to give smooth transitions from colour to colour +// This is represented by the j variable. The i variable gives the 16 colours +// The draw handler calculates the needed avarage and combines this with the colour +// to match an entry that is generated here. + + int baseR=0, baseG=0, baseB=0; + double sinhue,coshue,hue,basehue = 50.0; + double I,Q,Y,pixelI,pixelQ,R,G,B; + Bitu colorBit1,colorBit2,colorBit3,colorBit4,index; + + if (cga16_val & 0x01) baseB += 0xa8; + if (cga16_val & 0x02) baseG += 0xa8; + if (cga16_val & 0x04) baseR += 0xa8; + if (cga16_val & 0x08) { baseR += 0x57; baseG += 0x57; baseB += 0x57; } + if (cga16_val & 0x20) basehue = 35.0; + + hue = (basehue + hue_offset)*0.017453239; + sinhue = sin(hue); + coshue = cos(hue); + + for(Bitu i = 0; i < 16;i++) { + for(Bitu j = 0;j < 5;j++) { + index = 0x80|(j << 4)|i; //use upperpart of vga pallette + colorBit4 = (i&1)>>0; + colorBit3 = (i&2)>>1; + colorBit2 = (i&4)>>2; + colorBit1 = (i&8)>>3; + + //calculate lookup table + I = 0; Q = 0; + I += (double) colorBit1; + Q += (double) colorBit2; + I -= (double) colorBit3; + Q -= (double) colorBit4; + Y = (double) j / 4.0; //calculated avarage is over 4 bits + + pixelI = I * 1.0 / 3.0; //I* tvSaturnation / 3.0 + pixelQ = Q * 1.0 / 3.0; //Q* tvSaturnation / 3.0 + I = pixelI*coshue + pixelQ*sinhue; + Q = pixelQ*coshue - pixelI*sinhue; + + R = Y + 0.956*I + 0.621*Q; if (R < 0.0) R = 0.0; if (R > 1.0) R = 1.0; + G = Y - 0.272*I - 0.647*Q; if (G < 0.0) G = 0.0; if (G > 1.0) G = 1.0; + B = Y - 1.105*I + 1.702*Q; if (B < 0.0) B = 0.0; if (B > 1.0) B = 1.0; + + RENDER_SetPal(index,static_cast(R*baseR),static_cast(G*baseG),static_cast(B*baseB)); + } + } +} + +static void IncreaseHue(bool pressed) { + if (!pressed) + return; + hue_offset += 5.0; + update_cga16_color(); + LOG_MSG("Hue at %f",hue_offset); +} + +static void DecreaseHue(bool pressed) { + if (!pressed) + return; + hue_offset -= 5.0; + update_cga16_color(); + LOG_MSG("Hue at %f",hue_offset); +} + static void write_color_select(Bit8u val) { vga.tandy.color_select=val; switch (vga.mode) { @@ -131,21 +217,24 @@ static void write_color_select(Bit8u val) { break; case M_TANDY4: { - if (machine == MCH_TANDY && (vga.tandy.gfx_control & 0x8)) { + if ((machine==MCH_TANDY && (vga.tandy.gfx_control & 0x8)) || + (machine==MCH_PCJR && (vga.tandy.mode_control==0x0b))) { VGA_SetCGA4Table(0,1,2,3); return; } Bit8u base=(val & 0x10) ? 0x08 : 0; /* Check for BW Mode */ if (vga.tandy.mode_control & 0x4) { - if (val & 0x20) VGA_SetCGA4Table(val & 0xf,3+base,4+base,7+base); - else VGA_SetCGA4Table(val & 0xf,2+base,4+base,6+base); + VGA_SetCGA4Table(val & 0xf,3+base,4+base,7+base); } else { if (val & 0x20) VGA_SetCGA4Table(val & 0xf,3+base,5+base,7+base); else VGA_SetCGA4Table(val & 0xf,2+base,4+base,6+base); } } break; + case M_CGA16: + cga16_color_select(val); + break; case M_TEXT: case M_TANDY16: break; @@ -177,14 +266,39 @@ static void TANDY_FindMode(void) { } } +static void PCJr_FindMode(void) { + if (vga.tandy.mode_control & 0x2) { + if (vga.tandy.mode_control & 0x10) { + /* bit4 of mode control 1 signals 16 colour graphics mode */ + VGA_SetMode(M_TANDY16); + } else if (vga.tandy.gfx_control & 0x08) { + /* bit3 of mode control 2 signals 2 colour graphics mode */ + VGA_SetMode(M_TANDY2); + } else { + /* otherwise some 4-colour graphics mode */ + VGA_SetMode(M_TANDY4); + } + write_color_select(vga.tandy.color_select); + } else { + VGA_SetMode(M_TANDY_TEXT); + } +} + static void write_tandy_reg(Bit8u val) { switch (vga.tandy.reg_index) { + case 0x0: + if (machine==MCH_PCJR) { + vga.tandy.mode_control=val; + VGA_SetBlinking(val & 0x20); + PCJr_FindMode(); + } else LOG(LOG_VGAMISC,LOG_NORMAL)("Unhandled Write %2X to tandy reg %X",val,vga.tandy.reg_index); case 0x2: /* Border color */ vga.tandy.border_color=val; break; case 0x3: /* More control */ vga.tandy.gfx_control=val; - TANDY_FindMode(); + if (machine==MCH_TANDY) TANDY_FindMode(); + else PCJr_FindMode(); break; /* palette colors */ case 0x10: case 0x11: case 0x12: case 0x13: @@ -204,7 +318,7 @@ static void write_cga(Bitu port,Bitu val,Bitu iolen) { vga.tandy.mode_control=val; if (vga.tandy.mode_control & 0x2) { if (vga.tandy.mode_control & 0x10) { - if (val & 0x8 && machine==MCH_CGA) { + if (!(val & 0x4) && machine==MCH_CGA) { VGA_SetMode(M_CGA16); //Video burst 16 160x200 color mode } else { VGA_SetMode(M_TANDY2); @@ -239,6 +353,7 @@ static void write_tandy(Bitu port,Bitu val,Bitu iolen) { write_tandy_reg(val); break; case 0x3df: + vga.tandy.is_32k_mode=(val & 0x80)==0x80; vga.tandy.disp_bank=val & ((val & 0x80) ? 0x6 : 0x7); vga.tandy.mem_bank=(val >> 3) & ((val & 0x80) ? 0x6 : 0x7); VGA_SetupHandlers(); @@ -246,6 +361,25 @@ static void write_tandy(Bitu port,Bitu val,Bitu iolen) { } } +static void write_pcjr(Bitu port,Bitu val,Bitu iolen) { + switch (port) { + case 0x3d9: + write_color_select(val); + break; + case 0x3da: + if (vga.tandy.pcjr_flipflop) write_tandy_reg(val); + else vga.tandy.reg_index=val; + vga.tandy.pcjr_flipflop=!vga.tandy.pcjr_flipflop; + break; + case 0x3df: + vga.tandy.is_32k_mode=(val & 0x80)==0x80; + vga.tandy.disp_bank=val & (vga.tandy.is_32k_mode ? 0x6 : 0x7); + vga.tandy.mem_bank=(val >> 3) & 0x7; + VGA_SetupHandlers(); + break; + } +} + static void write_hercules(Bitu port,Bitu val,Bitu iolen) { switch (port) { case 0x3b8: @@ -277,7 +411,7 @@ static Bitu read_hercules(Bitu port,Bitu iolen) { void VGA_SetupOther(void) { Bitu i; - if (machine==MCH_CGA || machine==MCH_TANDY) { + if (machine==MCH_CGA || IS_TANDY_ARCH) { extern Bit8u int10_font_08[256 * 8]; for (i=0;i<256;i++) memcpy(&vga.draw.font[i*32],&int10_font_08[i*8],8); vga.draw.font_tables[0]=vga.draw.font_tables[1]=vga.draw.font; @@ -290,6 +424,8 @@ void VGA_SetupOther(void) { if (machine==MCH_CGA) { IO_RegisterWriteHandler(0x3d8,write_cga,IO_MB); IO_RegisterWriteHandler(0x3d9,write_cga,IO_MB); + MAPPER_AddHandler(IncreaseHue,MK_f11,MMOD2,"inchue","Inc Hue"); + MAPPER_AddHandler(DecreaseHue,MK_f11,0,"dechue","Dec Hue"); } if (machine==MCH_HERC) { vga.herc.enable_bits=0; @@ -298,13 +434,21 @@ void VGA_SetupOther(void) { IO_RegisterWriteHandler(0x3bf,write_hercules,IO_MB); } if (machine==MCH_TANDY) { + vga.tandy.is_32k_mode=false; IO_RegisterWriteHandler(0x3d8,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3d9,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3de,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3df,write_tandy,IO_MB); IO_RegisterWriteHandler(0x3da,write_tandy,IO_MB); } - if (machine==MCH_CGA || machine==MCH_HERC || machine==MCH_TANDY) { + if (machine==MCH_PCJR) { + vga.tandy.mem_bank=7;vga.tandy.disp_bank=7; + vga.tandy.is_32k_mode=false;vga.tandy.pcjr_flipflop=false; + IO_RegisterWriteHandler(0x3d9,write_pcjr,IO_MB); + IO_RegisterWriteHandler(0x3da,write_pcjr,IO_MB); + IO_RegisterWriteHandler(0x3df,write_pcjr,IO_MB); + } + if (machine==MCH_CGA || machine==MCH_HERC || IS_TANDY_ARCH) { Bitu base=machine==MCH_HERC ? 0x3b4 : 0x3d4; IO_RegisterWriteHandler(base,write_crtc_index_other,IO_MB); IO_RegisterWriteHandler(base+1,write_crtc_data_other,IO_MB); diff --git a/src/hardware/vga_s3.cpp b/src/hardware/vga_s3.cpp new file mode 100644 index 0000000..1d1ee4a --- /dev/null +++ b/src/hardware/vga_s3.cpp @@ -0,0 +1,435 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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. + */ + +/* $Id: vga_s3.cpp,v 1.3 2006/02/14 12:44:38 qbix79 Exp $ */ + +#include "dosbox.h" +#include "inout.h" +#include "vga.h" + +void SVGA_S3_WriteCRTC(Bitu reg,Bitu val,Bitu iolen) { + switch (reg) { + case 0x31: /* CR31 Memory Configuration */ +//TODO Base address + vga.s3.reg_31 = val; + VGA_DetermineMode(); + break; + /* + 0 Enable Base Address Offset (CPUA BASE). Enables bank operation if + set, disables if clear. + 1 Two Page Screen Image. If set enables 2048 pixel wide screen setup + 2 VGA 16bit Memory Bus Width. Set for 16bit, clear for 8bit + 3 Use Enhanced Mode Memory Mapping (ENH MAP). Set to enable access to + video memory above 256k. + 4-5 Bit 16-17 of the Display Start Address. For the 801/5,928 see index + 51h, for the 864/964 see index 69h. + 6 High Speed Text Display Font Fetch Mode. If set enables Page Mode + for Alpha Mode Font Access. + 7 (not 864/964) Extended BIOS ROM Space Mapped out. If clear the area + C6800h-C7FFFh is mapped out, if set it is accessible. + */ + case 0x35: /* CR35 CRT Register Lock */ + if (vga.s3.reg_lock1 != 0x48) return; //Needed for uvconfig detection + vga.s3.reg_35=val & 0xf0; + if ((vga.s3.bank & 0xf) ^ (val & 0xf)) { + vga.s3.bank&=0xf0; + vga.s3.bank|=val & 0xf; + VGA_SetupHandlers(); + } + break; + /* + 0-3 CPU Base Address. 64k bank number. For the 801/5 and 928 see 3d4h + index 51h bits 2-3. For the 864/964 see index 6Ah. + 4 Lock Vertical Timing Registers (LOCK VTMG). Locks 3d4h index 6, 7 + (bits 0,2,3,5,7), 9 bit 5, 10h, 11h bits 0-3, 15h, 16h if set + 5 Lock Horizontal Timing Registers (LOCK HTMG). Locks 3d4h index + 0,1,2,3,4,5,17h bit 2 if set + 6 (911/924) Lock VSync Polarity. + 7 (911/924) Lock HSync Polarity. + */ + case 0x38: /* CR38 Register Lock 1 */ + vga.s3.reg_lock1=val; + break; + case 0x39: /* CR39 Register Lock 2 */ + vga.s3.reg_lock2=val; + break; + case 0x40: /* CR40 System Config */ + vga.s3.reg_40 = val; + break; + case 0x43: /* CR43 Extended Mode */ + vga.s3.reg_43=val & ~0x4; + if (((val & 0x4) ^ (vga.config.scan_len >> 6)) & 0x4) { + vga.config.scan_len&=0x2ff; + vga.config.scan_len|=(val & 0x4) << 6; + VGA_CheckScanLength(); + } + break; + /* + 2 Logical Screen Width bit 8. Bit 8 of the Display Offset Register/ + (3d4h index 13h). (801/5,928) Only active if 3d4h index 51h bits 4-5 + are 0 + */ + case 0x45: /* Hardware cursor mode */ + vga.s3.hgc.curmode = val; + // Activate hardware cursor code if needed + VGA_ActivateHardwareCursor(); + break; + case 0x46: + vga.s3.hgc.originx = (vga.s3.hgc.originx & 0x00ff) | (val << 8); + break; + case 0x47: /* HGC orgX */ + vga.s3.hgc.originx = (vga.s3.hgc.originx & 0xff00) | val; + break; + case 0x48: + vga.s3.hgc.originy = (vga.s3.hgc.originy & 0x00ff) | (val << 8); + break; + case 0x49: /* HGC orgY */ + vga.s3.hgc.originy = (vga.s3.hgc.originy & 0xff00) | val; + break; + case 0x4A: /* HGC foreground stack */ + if (vga.s3.hgc.fstackpos > 2) vga.s3.hgc.fstackpos = 0; + vga.s3.hgc.forestack[vga.s3.hgc.fstackpos] = val; + vga.s3.hgc.fstackpos++; + break; + case 0x4B: /* HGC background stack */ + if (vga.s3.hgc.bstackpos > 2) vga.s3.hgc.bstackpos = 0; + vga.s3.hgc.backstack[vga.s3.hgc.bstackpos] = val; + vga.s3.hgc.bstackpos++; + break; + case 0x4c: /* HGC start address high byte*/ + vga.s3.hgc.startaddr = vga.s3.hgc.startaddr | ((val & 0xff) << 8); + break; + case 0x4d: /* HGC start address low byte*/ + vga.s3.hgc.startaddr = vga.s3.hgc.startaddr | (val & 0xff); + break; + case 0x4e: /* HGC pattern start X */ + vga.s3.hgc.posx = val; + break; + case 0x4f: /* HGC pattern start X */ + vga.s3.hgc.posy = val; + break; + case 0x51: /* Extended System Control 2 */ + vga.s3.reg_51=val & 0xc0; //Only store bits 6,7 + //TODO Display start + vga.config.display_start&=0xFCFFFF; + vga.config.display_start|=(val & 3) << 16; + if ((vga.s3.bank&0xcf) ^ ((val&0xc)<<2)) { + vga.s3.bank&=0xcf; + vga.s3.bank|=(val&0xc)<<2; + VGA_SetupHandlers(); + } + if (((val & 0x30) ^ (vga.config.scan_len >> 4)) & 0x30) { + vga.config.scan_len&=0xff; + vga.config.scan_len|=(val & 0x30) << 4; + VGA_CheckScanLength(); + } + break; + /* + 0 (80x) Display Start Address bit 18 + 0-1 (928 +) Display Start Address bit 18-19 + Bits 16-17 are in index 31h bits 4-5, Bits 0-15 are in 3d4h index + 0Ch,0Dh. For the 864/964 see 3d4h index 69h + 2 (80x) CPU BASE. CPU Base Address Bit 18. + 2-3 (928 +) Old CPU Base Address Bits 19-18. + 64K Bank register bits 4-5. Bits 0-3 are in 3d4h index 35h. + For the 864/964 see 3d4h index 6Ah + 4-5 Logical Screen Width Bit [8-9]. Bits 8-9 of the CRTC Offset register + (3d4h index 13h). If this field is 0, 3d4h index 43h bit 2 is active + 6 (928,964) DIS SPXF. Disable Split Transfers if set. Spilt Transfers + allows transferring one half of the VRAM shift register data while + the other half is being output. For the 964 Split Transfers + must be enabled in enhanced modes (4AE8h bit 0 set). Guess: They + probably can't time the VRAM load cycle closely enough while the + graphics engine is running. + 7 (not 864/964) Enable EPROM Write. If set enables flash memory write + control to the BIOS ROM address + */ + case 0x53: + if((val & 0x10) != (vga.s3.ext_mem_ctrl & 0x10)) { + /* Map or unmap MMIO */ + if ((val & 0x10) != 0) { + //LOG_MSG("VGA: Mapping Memory Mapped I/O to 0xA0000"); +// VGA_MapMMIO(); + } else { +// VGA_UnmapMMIO(); + } + } + vga.s3.ext_mem_ctrl = val; + break; + case 0x55: /* Extended Video DAC Control */ + vga.s3.reg_55=val; + break; + /* + 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the + RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs. + If this field is 0, 3d4h index 43h bit 1 is active. + 2 Enable General Input Port Read. If set DAC reads are disabled and the + STRD strobe for reading the General Input Port is enabled for reading + while DACRD is active, if clear DAC reads are enabled. + 3 (928) Enable External SID Operation if set. If set video data is + passed directly from the VRAMs to the DAC rather than through the + VGA chip + 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11 + mode, if clear in MS-Windows mode + 5 (80x,928) Hardware Cursor External Operation Mode. If set the two + bits of cursor data ,is output on the HC[0-1] pins for the video DAC + The SENS pin becomes HC1 and the MID2 pin becomes HC0. + 6 ?? + 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated. + (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri + -stated if set + */ + case 0x58: /* Linear Address Window Control */ + vga.s3.reg_58=val; + break; + /* + 0-1 Linear Address Window Size. Must be less than or equal to video + memory size. 0: 64K, 1: 1MB, 2: 2MB, 3: 4MB (928)/8Mb (864/964) + 2 (not 864/964) Enable Read Ahead Cache if set + 3 (80x,928) ISA Latch Address. If set latches address during every ISA + cycle, unlatches during every ISA cycle if clear. + (864/964) LAT DEL. Address Latch Delay Control (VL-Bus only). If set + address latching occours in the T1 cycle, if clear in the T2 cycle + (I.e. one clock cycle delayed). + 4 ENB LA. Enable Linear Addressing if set. + 5 (not 864/964) Limit Entry Depth for Write-Post. If set limits Write + -Post Entry Depth to avoid ISA bus timeout due to wait cycle limit. + 6 (928,964) Serial Access Mode (SAM) 256 Words Control. If set SAM + control is 256 words, if clear 512 words. + 7 (928) RAS 6-MCLK. If set the random read/write cycle time is 6MCLKs, + if clear 7MCLKs + */ + case 0x59: /* Linear Address Window Position High */ + if ((vga.s3.la_window&0xff00) ^ (val << 8)) { + vga.s3.la_window=(vga.s3.la_window&0x00ff) | (val << 8); + VGA_StartUpdateLFB(); + } + break; + case 0x5a: /* Linear Address Window Position Low */ + if ((vga.s3.la_window&0x00ff) ^ val) { + vga.s3.la_window=(vga.s3.la_window&0xff00) | val; + VGA_StartUpdateLFB(); + } + break; + case 0x5D: /* Extended Horizontal Overflow */ + if ((val & vga.s3.ex_hor_overflow) ^ 3) { + vga.s3.ex_hor_overflow=val; + VGA_StartResize(); + } else vga.s3.ex_hor_overflow=val; + break; + /* + 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h + index 0) + 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End + register (3d4h index 1) + 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking + register (3d4h index 2). + 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse + is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or + does it really extend by 64 ? + 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start + Retrace register (3d4h index 4). + 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse + is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or + does it really extend by 32 ? + 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer + Position register (3d4h index 3Bh) + 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant + Termination register (3d4h index 5Fh). + */ + case 0x5e: /* Extended Vertical Overflow */ + vga.config.line_compare=(vga.config.line_compare & 0x3ff) | (val & 0x40) << 4; + if ((val ^ vga.s3.ex_ver_overflow) & 0x3) { + vga.s3.ex_ver_overflow=val; + VGA_StartResize(); + } else vga.s3.ex_ver_overflow=val; + break; + /* + 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h + index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5. + 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End + register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1 + and 6 + 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking + register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9 + in 3d4h index 9 bit 5 + 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace + register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2 + and 7. + 6 Line Compare Position bit 10. Bit 10 of the Line Compare register + (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h + index 9 bit 6. + */ + case 0x67: /* Extended Miscellaneous Control 2 */ + /* + 0 VCLK PHS. VCLK Phase With Respect to DCLK. If clear VLKC is inverted + DCLK, if set VCLK = DCLK. + 4-7 Pixel format. + 0 Mode 0: 8bit (1 pixel/VCLK) + 1 Mode 8: 8bit (2 pixels/VCLK) + 3 Mode 9: 15bit (1 pixel/VCLK) + 5 Mode 10: 16bit (1 pixel/VCLK) + 7 Mode 11: 24/32bit (2 VCLKs/pixel) + 13 (732/764) 32bit (1 pixel/VCLK) + */ + vga.s3.misc_control_2=val; + VGA_DetermineMode(); + break; + case 0x69: /* Extended System Control 3 */ + if (((vga.config.display_start & 0x1f0000)>>16) ^ (val & 0x1f)) { + vga.config.display_start&=0xffff; + vga.config.display_start|=(val & 0x1f) << 16; + } + break; + case 0x6a: /* Extended System Control 4 */ + vga.s3.bank=val & 0x3f; + VGA_SetupHandlers(); + break; + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Write to illegal index %2X", reg ); + break; + } +} + +Bitu SVGA_S3_ReadCRTC( Bitu reg, Bitu iolen) { + switch (reg) { + case 0x2d: /* Extended Chip ID. */ + return 0x88; + // Always 88h ? + case 0x2e: /* New Chip ID */ + return 0x11; + //Trio 64 id + case 0x2f: /* Revision */ + return 0x00; + case 0x30: /* CR30 Chip ID/REV register */ + return 0xe0; //Trio+ dual byte + // Trio32/64 has 0xe0. extended + case 0x31: /* CR31 Memory Configuration */ +//TODO mix in bits from baseaddress; + return vga.s3.reg_31; + case 0x35: /* CR35 CRT Register Lock */ + return vga.s3.reg_35|(vga.s3.bank & 0xf); + case 0x36: /* CR36 Reset State Read 1 */ + //return 0x8f; + return 0x8e; /* PCI version */ + //2 Mb PCI and some bios settings + case 0x37: /* Reset state read 2 */ + return 0x2b; + case 0x38: /* CR38 Register Lock 1 */ + return vga.s3.reg_lock1; + case 0x39: /* CR39 Register Lock 2 */ + return vga.s3.reg_lock2; + case 0x40: /* CR40 system config */ + return vga.s3.reg_40; + case 0x43: /* CR43 Extended Mode */ + return vga.s3.reg_43|((vga.config.scan_len>>6)&0x4); + case 0x45: /* Hardware cursor mode */ + vga.s3.hgc.bstackpos = 0; + vga.s3.hgc.fstackpos = 0; + return vga.s3.hgc.curmode; + case 0x51: /* Extended System Control 2 */ + return ((vga.config.display_start >> 16) & 3 ) | + ((vga.s3.bank & 0x30) >> 2) | + ((vga.config.scan_len & 0x300) >> 4) | + vga.s3.reg_51; + case 0x53: + return vga.s3.ext_mem_ctrl; + case 0x55: /* Extended Video DAC Control */ + return vga.s3.reg_55; + case 0x58: /* Linear Address Window Control */ + return vga.s3.reg_58; + case 0x59: /* Linear Address Window Position High */ + return (vga.s3.la_window >> 8); + case 0x5a: /* Linear Address Window Position Low */ + return (vga.s3.la_window & 0xff); + case 0x5D: /* Extended Horizontal Overflow */ + return vga.s3.ex_hor_overflow; + case 0x5e: /* Extended Vertical Overflow */ + return vga.s3.ex_ver_overflow; + case 0x67: /* Extended Miscellaneous Control 2 */ + return vga.s3.misc_control_2; + case 0x69: /* Extended System Control 3 */ + return (Bit8u)((vga.config.display_start & 0x1f0000)>>16); + case 0x6a: /* Extended System Control 4 */ + return (Bit8u)(vga.s3.bank & 0x3f); + default: + return 0x00; + } +} + +void SVGA_S3_WriteSEQ(Bitu reg,Bitu val,Bitu iolen) { + switch (reg) { + case 0x08: + vga.s3.pll.lock=val; + break; + case 0x10: /* Memory PLL Data Low */ + vga.s3.mclk.n=val & 0x1f; + vga.s3.mclk.r=val >> 5; + break; + case 0x11: /* Memory PLL Data High */ + vga.s3.mclk.m=val & 0x7f; + break; + case 0x12: /* Video PLL Data Low */ + vga.s3.clk[3].n=val & 0x1f; + vga.s3.clk[3].r=val >> 5; + break; + case 0x13: /* Video PLL Data High */ + vga.s3.clk[3].m=val & 0x7f; + break; + case 0x15: + vga.s3.pll.cmd=val; + VGA_StartResize(); + break; + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:S3:SEQ:Write to illegal index %2X", reg ); + break; + } +} + +Bitu SVGA_S3_ReadSEQ(Bitu reg,Bitu iolen) { + /* S3 specific group */ + switch (reg) { + case 0x08: /* PLL Unlock */ + return vga.s3.pll.lock; + case 0x10: /* Memory PLL Data Low */ + return vga.s3.mclk.n || (vga.s3.mclk.r << 5); + case 0x11: /* Memory PLL Data High */ + return vga.s3.mclk.m; + case 0x12: /* Video PLL Data Low */ + return vga.s3.clk[3].n || (vga.s3.clk[3].r << 5); + case 0x13: /* Video Data High */ + return vga.s3.clk[3].m; + case 0x15: + return vga.s3.pll.cmd; + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:S3:SEQ:Read from illegal index %2X", reg); + return 0; + } +} + +Bitu SVGA_S3_GetClock(void) { + Bitu clock = (vga.misc_output >> 2) & 3; + if (clock == 0) + clock = 25175000; + else if (clock == 1) + clock = 28322000; + else + clock=1000*S3_CLOCK(vga.s3.clk[clock].m,vga.s3.clk[clock].n,vga.s3.clk[clock].r); + return clock; +} + diff --git a/src/hardware/vga_seq.cpp b/src/hardware/vga_seq.cpp index 12db7b6..406baba 100644 --- a/src/hardware/vga_seq.cpp +++ b/src/hardware/vga_seq.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -98,33 +98,16 @@ void write_p3c5(Bitu port,Bitu val,Bitu iolen) { else vga.config.chained=false; VGA_SetupHandlers(); break; -/* S3 specific group */ - case 0x08: - vga.s3.pll.lock=val; - break; - case 0x10: /* Memory PLL Data Low */ - vga.s3.mclk.n=val & 0x1f; - vga.s3.mclk.r=val >> 5; - break; - case 0x11: /* Memory PLL Data High */ - vga.s3.mclk.m=val & 0x7f; - break; - case 0x12: /* Video PLL Data Low */ - vga.s3.clk[3].n=val & 0x1f; - vga.s3.clk[3].r=val >> 5; - break; - case 0x13: /* Video PLL Data High */ - vga.s3.clk[3].m=val & 0x7f; - break; - case 0x15: - vga.s3.pll.cmd=val; - VGA_StartResize(); - break; - default: - LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Write to illegal index %2X",seq(index)); - }; -}; + switch (svgaCard) { + case SVGA_S3Trio: + SVGA_S3_WriteSEQ( seq(index), val, iolen ); + break; + default: + LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Write to illegal index %2X",seq(index)); + } + } +} Bitu read_p3c5(Bitu port,Bitu iolen) { @@ -145,25 +128,14 @@ Bitu read_p3c5(Bitu port,Bitu iolen) { break; case 4: /* Memory Mode */ return seq(memory_mode); - /* S3 specific group */ - case 0x08: /* PLL Unlock */ - return vga.s3.pll.lock; - case 0x10: /* Memory PLL Data Low */ - return vga.s3.mclk.n || (vga.s3.mclk.r << 5); - case 0x11: /* Memory PLL Data High */ - return vga.s3.mclk.m; - case 0x12: /* Video PLL Data Low */ - return vga.s3.clk[3].n || (vga.s3.clk[3].r << 5); - case 0x13: /* Video Data High */ - return vga.s3.clk[3].m; - case 0x15: - return vga.s3.pll.cmd; - default: - LOG(LOG_VGAMISC,LOG_NORMAL)("VGA:SEQ:Read from illegal index %2X",seq(index)); - }; + switch (svgaCard) { + case SVGA_S3Trio: + return SVGA_S3_ReadSEQ( seq(index), iolen ); + } + } return 0; -}; +} void VGA_SetupSEQ(void) { diff --git a/src/hardware/vga_xga.cpp b/src/hardware/vga_xga.cpp index 0abb4ba..c998eae 100644 --- a/src/hardware/vga_xga.cpp +++ b/src/hardware/vga_xga.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -20,8 +20,13 @@ #include "dosbox.h" #include "inout.h" #include "vga.h" +#include #include +#define XGA_SCREEN_WIDTH vga.draw.width + +#define XGA_SHOW_COMMAND_TRACE 0 + struct XGAStatus { struct scissorreg { Bit16u x1, y1, x2, y2; @@ -30,14 +35,18 @@ struct XGAStatus { Bit32u readmask; Bit32u writemask; - Bit32u forecolor; - Bit32u backcolor; + Bit8u forecolor; + Bit8u backcolor; + + Bitu curcommand; Bit16u foremix; + Bit16u backmix; Bit16u curx, cury; Bit16u destx, desty; + Bit16u ErrTerm; Bit16u MIPcount; Bit16u MAPcount; @@ -45,16 +54,15 @@ struct XGAStatus { Bit16u read_sel; struct XGA_WaitCmd { + bool newline; bool wait; Bit16u cmd; Bit16u curx, cury; - Bit16u x1, y1, x2, y2; + Bit16u x1, y1, x2, y2, sizex, sizey; } waitcmd; } xga; -Bit8u tmpvram[2048 * 1024]; - void XGA_Write_Multifunc(Bitu val, Bitu len) { Bitu regselect = val >> 12; Bitu dataval = val & 0xfff; @@ -87,13 +95,22 @@ void XGA_Write_Multifunc(Bitu val, Bitu len) { } void XGA_DrawPoint8(Bitu x, Bitu y, Bit8u c) { - Bit32u memaddr = (y * 640) + x; + + if(!(xga.curcommand & 0x1)) return; + if(!(xga.curcommand & 0x10)) return; + + if(x < xga.scissors.x1) return; + if(x > xga.scissors.x2) return; + if(y < xga.scissors.y1) return; + if(y > xga.scissors.y2) return; + + Bit32u memaddr = (y * XGA_SCREEN_WIDTH) + x; vga.mem.linear[memaddr] = c; } Bit8u XGA_GetPoint8(Bitu x, Bitu y) { - Bit32u memaddr = (y * 640) + x; + Bit32u memaddr = (y * XGA_SCREEN_WIDTH) + x; return vga.mem.linear[memaddr]; @@ -101,85 +118,413 @@ Bit8u XGA_GetPoint8(Bitu x, Bitu y) { void XGA_DrawPoint16(Bitu x, Bitu y, Bit16u c) { Bit16u *memptr; - Bit32u memaddr = (y * 640) + x; + Bit32u memaddr = (y * XGA_SCREEN_WIDTH) + x; memptr = (Bit16u *)&vga.mem.linear[memaddr]; *memptr = c; } -void XGA_DrawRectangle(Bitu x1, Bitu y1, Bitu x2, Bitu y2) { - Bit32u xat, yat; - Bit32u xmass, xmod, xdist; - Bit32u *memptr; - Bit8u *smallptr; - Bit32u c; - Bit8u smallc; - - xdist = (x2 -x1); - xmass = (xdist) & 0xfffffffb; - xmod = (xdist) & 0x3; - - smallc = (xga.forecolor & 0xff); - c = (smallc) | ((smallc) << 8) | ((smallc) << 16) | ((smallc) << 24); - - for(yat=y1;yat<=y2;yat++) { - Bit32u memaddr = (yat * (Bit32u)640) + x1; - smallptr = &vga.mem.linear[memaddr]; - for(xat=0;xat> 5) & 0x7) { + case 0x00: /* 0 degrees */ + sx = 1; + sy = 0; + break; + case 0x01: /* 45 degrees */ + sx = 1; + sy = -1; + break; + case 0x02: /* 90 degrees */ + sx = 0; + sy = -1; + break; + case 0x03: /* 135 degrees */ + sx = -1; + sy = -1; + break; + case 0x04: /* 180 degrees */ + sx = -1; + sy = 0; + break; + case 0x05: /* 225 degrees */ + sx = -1; + sy = 1; + break; + case 0x06: /* 270 degrees */ + sx = 0; + sy = 1; + break; + case 0x07: /* 315 degrees */ + sx = 1; + sy = 1; + break; + default: // Should never get here + sx = 0; + sy = 0; + break; + } + + //for(yat=y1;yat<=y2;yat++) { + // for(xat=x1;xat<=x2;xat++) { + for (i=0;i<=dx;i++) { + Bitu mixmode = (xga.pix_cntl >> 6) & 0x3; + switch (mixmode) { + case 0x00: /* FOREMIX always used */ + mixmode = xga.foremix; + switch((mixmode >> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + //srcval = tmpval; + LOG_MSG("XGA: DrawRect: Wants data from PIX_TRANS register"); + break; + case 0x03: /* Src is bitmap data */ + LOG_MSG("XGA: DrawRect: Wants data from srcdata"); + //srcval = srcdata; + break; + default: + LOG_MSG("XGA: DrawRect: Shouldn't be able to get here!"); + break; + } + dstdata = XGA_GetPoint8(xat,yat); + + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + XGA_DrawPoint8(xat,yat, destval); + break; + default: + LOG_MSG("XGA: DrawLine: Needs mixmode %x", mixmode); + break; } + xat += sx; + yat += sy; } - */ - LOG_MSG("XGA: Draw rect (%d, %d)-(%d, %d), %d", x1, y1, x2, y2, xga.forecolor); + + xga.curx = xat-1; + xga.cury = yat; + // } + //} + +} + +void XGA_DrawLineBresenham(Bitu val) { + Bits xat, yat; + Bit8u srcval; + Bit8u destval; + Bit8u dstdata; + Bits i; + Bits tmpswap; + bool steep; + +#define SWAP(a,b) tmpswap = a; a = b; b = tmpswap; + + Bits dx, sx, dy, sy, e, dmajor, dminor; + + // Probably a lot easier way to do this, but this works. + + dminor = (Bits)((Bit16s)xga.desty) >> 1; + dmajor = -((Bits)((Bit16s)xga.destx) - (dminor << 1)) >> 1; + + dx = dmajor; + if((val >> 5) & 0x1) { + sx = 1; + } else { + sx = -1; + } + dy = dminor; + if((val >> 7) & 0x1) { + sy = 1; + } else { + sy = -1; + } + e = (Bits)((Bit16s)xga.ErrTerm); + xat = xga.curx; + yat = xga.cury; + + if((val >> 6) & 0x1) { + steep = false; + SWAP(xat, yat); + SWAP(sx, sy); + } else { + steep = true; + } + + //LOG_MSG("XGA: Bresenham: ASC %d, LPDSC %d, sx %d, sy %d, err %d, steep %d, length %d, dmajor %d, dminor %d", dx, dy, sx, sy, e, steep, xga.MAPcount, dmajor, dminor); + + //for(yat=y1;yat<=y2;yat++) { + // for(xat=x1;xat<=x2;xat++) { + for (i=0;i<=xga.MAPcount;i++) { + Bitu mixmode = (xga.pix_cntl >> 6) & 0x3; + switch (mixmode) { + case 0x00: /* FOREMIX always used */ + mixmode = xga.foremix; + switch((mixmode >> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + //srcval = tmpval; + LOG_MSG("XGA: DrawRect: Wants data from PIX_TRANS register"); + break; + case 0x03: /* Src is bitmap data */ + LOG_MSG("XGA: DrawRect: Wants data from srcdata"); + //srcval = srcdata; + break; + default: + LOG_MSG("XGA: DrawRect: Shouldn't be able to get here!"); + break; + } + + if(steep) { + dstdata = XGA_GetPoint8(xat,yat); + } else { + dstdata = XGA_GetPoint8(yat,xat); + } + + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + if(steep) { + XGA_DrawPoint8(xat,yat, destval); + } else { + XGA_DrawPoint8(yat,xat, destval); + } + + break; + default: + LOG_MSG("XGA: DrawLine: Needs mixmode %x", mixmode); + break; + } + while (e >= 0) { + yat += sy; + e -= (dx << 1); + } + xat += sx; + e += (dy << 1); + } + + if(steep) { + xga.curx = xat; + xga.cury = yat; + } else { + xga.curx = yat; + xga.cury = xat; + } + // } + //} + +} + +void XGA_DrawRectangle(Bitu val) { + Bit32u xat, yat; + Bit8u srcval; + Bit8u destval; + Bit8u dstdata; + + Bits srcx, srcy, dx, dy; + + dx = -1; + dy = -1; + + if(((val >> 5) & 0x01) != 0) dx = 1; + if(((val >> 7) & 0x01) != 0) dy = 1; + + srcy = xga.cury; + + for(yat=0;yat<=xga.MIPcount;yat++) { + srcx = xga.curx; + for(xat=0;xat<=xga.MAPcount;xat++) { + Bitu mixmode = (xga.pix_cntl >> 6) & 0x3; + switch (mixmode) { + case 0x00: /* FOREMIX always used */ + mixmode = xga.foremix; + switch((mixmode >> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + //srcval = tmpval; + LOG_MSG("XGA: DrawRect: Wants data from PIX_TRANS register"); + break; + case 0x03: /* Src is bitmap data */ + LOG_MSG("XGA: DrawRect: Wants data from srcdata"); + //srcval = srcdata; + break; + default: + LOG_MSG("XGA: DrawRect: Shouldn't be able to get here!"); + break; + } + dstdata = XGA_GetPoint8(srcx,srcy); + + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + XGA_DrawPoint8(srcx,srcy, destval); + break; + default: + LOG_MSG("XGA: DrawRect: Needs mixmode %x", mixmode); + break; + } + srcx += dx; + } + srcy += dy; + } + xga.curx = srcx; + xga.cury = srcy; + + //LOG_MSG("XGA: Draw rect (%d, %d)-(%d, %d), %d", x1, y1, x2, y2, xga.forecolor); } bool XGA_CheckX(void) { bool newline = false; + if(!xga.waitcmd.newline) { if(xga.waitcmd.curx > xga.waitcmd.x2) { xga.waitcmd.curx = xga.waitcmd.x1; xga.waitcmd.cury++; newline = true; + xga.waitcmd.newline = true; if(xga.waitcmd.cury > xga.waitcmd.y2) xga.waitcmd.wait = false; } + } else { + xga.waitcmd.newline = false; + } return newline; } + void XGA_DrawWait(Bitu val, Bitu len) { if(!xga.waitcmd.wait) return; + + //if(!(xga.curcommand & 0x2)) return; + Bitu mixmode = (xga.pix_cntl >> 6) & 0x3; + Bit8u srcval; + Bit8u destval; + Bit8u dstdata; + Bitu tmpval; + Bits bitneed; switch(xga.waitcmd.cmd) { case 2: /* Rectangle */ - if(mixmode == 0) { /* FOREMIX always used */ - switch(len) { - case 1: - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, val); + switch(mixmode) { + case 0x00: /* FOREMIX always used */ + mixmode = xga.foremix; + Bitu t; + for(t=0;t> (8 * t)) & 0xff; + switch((mixmode >> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + srcval = tmpval; + //LOG_MSG("XGA: DrawBlitWait: Wants data from PIX_TRANS register"); break; - case 2: - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, (val & 0xff)); - XGA_CheckX(); - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, (val >> 8)); + case 0x03: /* Src is bitmap data */ + LOG_MSG("XGA: DrawBlitWait: Wants data from srcdata"); + //srcval = srcdata; break; - case 4: - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, (val & 0xff)); - XGA_CheckX(); - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, ((val >> 8) & 0xff)); - XGA_CheckX(); - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, ((val >> 16) & 0xff)); - XGA_CheckX(); - XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, ((val >> 24) & 0xff)); + default: + LOG_MSG("XGA: DrawBlitWait: Shouldn't be able to get here!"); break; } - XGA_CheckX(); + + + + dstdata = XGA_GetPoint8(xga.waitcmd.curx, xga.waitcmd.cury); + + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + //LOG_MSG("XGA: DrawPattern: Mixmode: %x srcval: %x", mixmode, srcval); + + XGA_DrawPoint8(xga.waitcmd.curx++, xga.waitcmd.cury, destval); + + XGA_CheckX(); + if(xga.waitcmd.newline) break; } - if(mixmode == 2) { /* Data from PIX_TRANS selects the mix */ + break; + case 0x02: /* Data from PIX_TRANS selects the mix */ Bitu bitcount; int i; switch(len) { @@ -196,20 +541,70 @@ void XGA_DrawWait(Bitu val, Bitu len) { } - Bits bitneed = ((Bits)xga.waitcmd.x2 - (Bits)xga.waitcmd.x1) + 1; - xga.waitcmd.curx = xga.waitcmd.x1; - i = 15; + bitneed = ((Bits)xga.waitcmd.x2 - (Bits)xga.waitcmd.curx) ; + //xga.waitcmd.curx = xga.waitcmd.x1; + xga.waitcmd.newline = false; + + + i = bitcount -1 ; + //bitneed = i; + for(;bitneed>=0;--bitneed) { + //for(;i>=0;--i) { Bitu bitval = (val >> i) & 0x1; + //Bitu bitval = (val >> bitneed) & 0x1; + //XGA_DrawPoint8(xga.waitcmd.curx, xga.waitcmd.cury, i); - if(bitval != 0) XGA_DrawPoint8(xga.waitcmd.curx, xga.waitcmd.cury, xga.forecolor); + Bitu mixmode = 0x67; + + if(bitval) { + mixmode = xga.foremix; + } else { + mixmode = xga.backmix; + } + + switch((mixmode >> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + LOG_MSG("XGA: DrawBlitWait: Wants data from PIX_TRANS register"); + break; + case 0x03: /* Src is bitmap data */ + LOG_MSG("XGA: DrawBlitWait: Wants data from srcdata"); + //srcval = srcdata; + break; + default: + LOG_MSG("XGA: DrawBlitWait: Shouldn't be able to get here!"); + break; + } + + Bit8u dstdata = XGA_GetPoint8(xga.waitcmd.curx, xga.waitcmd.cury); + + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + XGA_DrawPoint8(xga.waitcmd.curx, xga.waitcmd.cury, destval); + --i; + if(i < 0) break; + //--bitneed; + //if(bitneed < 0) break; + xga.waitcmd.curx++; + XGA_CheckX(); + if(xga.waitcmd.newline) break; } - xga.waitcmd.cury++; + //xga.waitcmd.cury++; if(xga.waitcmd.cury > xga.waitcmd.y2) xga.waitcmd.wait = false; + break; + default: + LOG_MSG("XGA: DrawBlitWait: Unhandled mixmode: %d", mixmode); + break; } break; default: @@ -221,84 +616,198 @@ void XGA_DrawWait(Bitu val, Bitu len) { void XGA_BlitRect(Bitu val) { Bit32u xat, yat; - Bit32u xmass, xmod, xdist, memrec; - Bit8u *srcptr; - Bit8u *destptr; - Bit8u *destline; - Bit8u *srcline; +// Bit32u xmass, xmod, xdist, memrec; + //Bit8u *srcptr; + //Bit8u *destptr; + //Bit8u *destline; + //Bit8u *srcline; + Bit8u srcdata; + Bit8u dstdata; - Bit32u c; - Bit8u smallc; - Bit8u tmpclr; - bool incx = false; - bool incy = false; + Bit8u srcval; + Bit8u destval; - if((val >> 5) != 0) incx = true; - if((val >> 7) != 0) incy = true; + Bits srcx, srcy, tarx, tary, dx, dy; + //bool incx = false; + //bool incy = false; - xdist = xga.MAPcount; + dx = -1; + dy = -1; - smallc = (xga.forecolor & 0xff); - memrec = 0; - Bit32u srcaddr = (xga.cury * (Bit32u)640) + xga.curx; - Bit32u destaddr = (xga.desty * (Bit32u)640) + xga.destx; + //if(((val >> 5) & 0x01) != 0) incx = true; + //if(((val >> 7) & 0x01) != 0) incy = true; + + if(((val >> 5) & 0x01) != 0) dx = 1; + if(((val >> 7) & 0x01) != 0) dy = 1; + + //Bit32u srcaddr = (xga.cury * (Bit32u)XGA_SCREEN_WIDTH) + xga.curx; + //Bit32u destaddr = (xga.desty * (Bit32u)XGA_SCREEN_WIDTH) + xga.destx; + srcx = xga.curx; + srcy = xga.cury; + tarx = xga.destx; + tary = xga.desty; + + //srcptr = &vga.mem.linear[srcaddr]; + //destptr = &vga.mem.linear[destaddr]; + + Bitu mixselect = (xga.pix_cntl >> 6) & 0x3; + Bitu mixmode = 0x67; /* Source is bitmap data, mix mode is src */ + switch(mixselect) { + case 0x00: /* Foreground mix is always used */ + mixmode = xga.foremix; + break; + case 0x02: /* CPU Data determines mix used */ + LOG_MSG("XGA: DrawPattern: Mixselect data from PIX_TRANS register"); + break; + case 0x03: /* Video memory determines mix */ + //LOG_MSG("XGA: Srcdata: %x, Forecolor %x, Backcolor %x, Foremix: %x Backmix: %x", srcdata, xga.forecolor, xga.backcolor, xga.foremix, xga.backmix); + break; + default: + LOG_MSG("XGA: DrawPattern: Unknown mix select register"); + break; + } - srcptr = &vga.mem.linear[srcaddr]; - destptr = &vga.mem.linear[destaddr]; /* Copy source to video ram */ for(yat=0;yat<=xga.MIPcount ;yat++) { - srcline = srcptr; - destline = destptr; - for(xat=0;xat> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + LOG_MSG("XGA: DrawPattern: Wants data from PIX_TRANS register"); + break; + case 0x03: /* Src is bitmap data */ + srcval = srcdata; + break; + default: + LOG_MSG("XGA: DrawPattern: Shouldn't be able to get here!"); + break; } - LOG_MSG("XGA: Blit (%d, %d)-(%d, %d) to (%d, %d)-(%d, %d), incx %d, incy %d", xga.curx, xga.cury, xga.curx + xdist, xga.cury + xga.MIPcount, xga.destx, xga.desty, xga.destx + xdist, xga.desty + xga.MIPcount, incx, incy); + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + //LOG_MSG("XGA: DrawPattern: Mixmode: %x Mixselect: %x", mixmode, mixselect); + + //*smallptr++ = destval; + XGA_DrawPoint8(tarx, tary, destval); + + srcx += dx; + tarx += dx; + } + srcy += dy; + tary += dy; + } } -void XGA_DrawPattern(void) { - Bit32u xat, yat, y1, y2, sx, sy, addx, addy; - Bit32u xmass, xmod, xdist; - Bit32u *memptr; - Bit8u *smallptr; - Bit8u smallc; +void XGA_DrawPattern(Bitu val) { + Bit8u srcdata; + Bit8u dstdata; - y1 = xga.desty; - y2 = xga.desty + xga.MIPcount; - xdist = xga.MAPcount; - sx = xga.curx; - sy = xga.cury; - addx = 0; - addy = 0; + Bit8u srcval; + Bit8u destval; - for(yat=y1;yat<=y2;yat++) { - Bit32u memaddr = (yat * (Bit32u)640) + xga.destx; - smallptr = &vga.mem.linear[memaddr]; - for(xat=0;xat7) addx=0; + Bits xat, yat, srcx, srcy, tarx, tary, dx, dy; + + dx = -1; + dy = -1; + + if(((val >> 5) & 0x01) != 0) dx = 1; + if(((val >> 7) & 0x01) != 0) dy = 1; + + srcx = xga.curx; + srcy = xga.cury; + + tary = xga.desty; + + Bitu mixselect = (xga.pix_cntl >> 6) & 0x3; + Bitu mixmode = 0x67; /* Source is bitmap data, mix mode is src */ + switch(mixselect) { + case 0x00: /* Foreground mix is always used */ + mixmode = xga.foremix; + break; + case 0x02: /* CPU Data determines mix used */ + LOG_MSG("XGA: DrawPattern: Mixselect data from PIX_TRANS register"); + break; + case 0x03: /* Video memory determines mix */ + //LOG_MSG("XGA: Srcdata: %x, Forecolor %x, Backcolor %x, Foremix: %x Backmix: %x", srcdata, xga.forecolor, xga.backcolor, xga.foremix, xga.backmix); + break; + default: + LOG_MSG("XGA: DrawPattern: Unknown mix select register"); + break; + } + + for(yat=0;yat<=xga.MIPcount;yat++) { + tarx = xga.destx; + for(xat=0;xat<=xga.MAPcount;xat++) { + + srcdata = XGA_GetPoint8(srcx + (tarx & 0x7), srcy + (tary & 0x7)); + dstdata = XGA_GetPoint8(tarx, tary); + + + if(mixselect == 0x3) { + if(srcdata == xga.forecolor) { + mixmode = xga.foremix; + } else { + if(srcdata == xga.backcolor) { + mixmode = xga.backmix; + } else { + /* Best guess otherwise */ + mixmode = 0x67; /* Source is bitmap data, mix mode is src */ + } + } + } + + switch((mixmode >> 5) & 0x03) { + case 0x00: /* Src is background color */ + srcval = xga.backcolor; + break; + case 0x01: /* Src is foreground color */ + srcval = xga.forecolor; + break; + case 0x02: /* Src is pixel data from PIX_TRANS register */ + LOG_MSG("XGA: DrawPattern: Wants data from PIX_TRANS register"); + break; + case 0x03: /* Src is bitmap data */ + srcval = srcdata; + break; + default: + LOG_MSG("XGA: DrawPattern: Shouldn't be able to get here!"); + break; + } + + destval = XGA_GetMixResult(mixmode, srcval, dstdata); + + XGA_DrawPoint8(tarx, tary, destval); + + tarx += dx; } - addy++; - if(addy>7) addy=0; + tary += dy; + } } @@ -306,30 +815,65 @@ void XGA_DrawPattern(void) { void XGA_DrawCmd(Bitu val, Bitu len) { Bit16u cmd; cmd = val >> 13; +#if XGA_SHOW_COMMAND_TRACE == 1 LOG_MSG("XGA: Draw command %x", cmd); +#endif + xga.curcommand = val; switch(cmd) { + case 1: /* Draw line */ + if((val & 0x100) == 0) { + if((val & 0x8) == 0) { +#if XGA_SHOW_COMMAND_TRACE == 1 + LOG_MSG("XGA: Drawing Bresenham line"); +#endif + XGA_DrawLineBresenham(val); + } else { +#if XGA_SHOW_COMMAND_TRACE == 1 + LOG_MSG("XGA: Drawing vector line"); +#endif + XGA_DrawLineVector(val); + } + } else { + LOG_MSG("XGA: Wants line drawn from PIX_TRANS register!"); + } + break; case 2: /* Rectangle fill */ if((val & 0x100) == 0) { xga.waitcmd.wait = false; - XGA_DrawRectangle(xga.curx, xga.cury, xga.curx + xga.MAPcount, xga.cury + xga.MIPcount); + XGA_DrawRectangle(val); +#if XGA_SHOW_COMMAND_TRACE == 1 + LOG_MSG("XGA: Draw immediate rect"); +#endif } else { + + xga.waitcmd.newline = true; xga.waitcmd.wait = true; xga.waitcmd.curx = xga.curx; xga.waitcmd.cury = xga.cury; xga.waitcmd.x1 = xga.curx; xga.waitcmd.y1 = xga.cury; xga.waitcmd.x2 = xga.curx + xga.MAPcount; - xga.waitcmd.y2 = xga.cury + xga.MIPcount; + xga.waitcmd.y2 = xga.cury + xga.MIPcount + 1; + xga.waitcmd.sizex = xga.MAPcount; + xga.waitcmd.sizey = xga.MIPcount + 1; xga.waitcmd.cmd = 2; - LOG_MSG("XGA: Draw wait rect (%d, %d)-(%d, %d)", xga.waitcmd.x1, xga.waitcmd.y1, xga.waitcmd.x2, xga.waitcmd.y2); + +#if XGA_SHOW_COMMAND_TRACE == 1 + LOG_MSG("XGA: Draw wait rect, width %d, heigth %d", xga.MAPcount, xga.MIPcount+1); +#endif } break; case 6: /* BitBLT */ XGA_BlitRect(val); +#if XGA_SHOW_COMMAND_TRACE == 1 + LOG_MSG("XGA: Blit Rect"); +#endif break; case 7: /* Pattern fill */ - XGA_DrawPattern(); - LOG_MSG("XGA: Pattern fill (%d, %d)-(%d, %d) to (%d, %d)-(%d, %d)", xga.curx, xga.cury, xga.curx + 8, xga.cury + 8, xga.destx, xga.desty, xga.destx + xga.MAPcount, xga.desty + xga.MIPcount); + XGA_DrawPattern(val); +#if XGA_SHOW_COMMAND_TRACE == 1 + LOG_MSG("XGA: Pattern fill"); +#endif break; default: LOG_MSG("XGA: Unhandled draw command %x", cmd); @@ -340,6 +884,9 @@ void XGA_DrawCmd(Bitu val, Bitu len) { void XGA_Write(Bitu port, Bitu val, Bitu len) { switch(port) { + case 0x92e8: + xga.ErrTerm = val; + break; case 0x96e8: xga.MAPcount = val; break; @@ -370,13 +917,27 @@ void XGA_Write(Bitu port, Bitu val, Bitu len) { case 0x8ee8: xga.destx = val; break; + case 0xb6e8: + xga.backmix = val; + break; case 0xbae8: xga.foremix = val; break; case 0xbee8: XGA_Write_Multifunc(val, len); break; + case 0x0e2e0: + if(!xga.waitcmd.newline) { + xga.waitcmd.curx = xga.waitcmd.x1; + xga.waitcmd.cury++; + xga.waitcmd.newline = true; + } + + XGA_DrawWait(val, len); + if(xga.waitcmd.cury > xga.waitcmd.y2) xga.waitcmd.wait = false; + break; case 0xe2e8: + xga.waitcmd.newline = false; XGA_DrawWait(val, len); break; default: @@ -387,7 +948,7 @@ void XGA_Write(Bitu port, Bitu val, Bitu len) { } Bitu XGA_Read(Bitu port, Bitu len) { - LOG_MSG("XGA: Read from port %x, len %x", port, len); + //LOG_MSG("XGA: Read from port %x, len %x", port, len); switch(port) { case 0x9ae8: return 0x0; @@ -405,34 +966,6 @@ Bitu XGA_Read(Bitu port, Bitu len) { } } -void XGA_UpdateHWC(void) { - Bitu mouseaddr = (Bit32u)vga.s3.hgc.startaddr * (Bit32u)1024; - Bits x, y, t, m, xat, r, z; - x = vga.s3.hgc.originx; - y = vga.s3.hgc.originy; - Bit16u bitsA, bitsB; - Bit16u ab, bb; - - /* Read mouse cursor */ - for(t=0;t<64;t++) { - xat = 0; - for(m=0;m<4;m++) { - bitsA = *(Bit16u *)&vga.mem.linear[mouseaddr]; - mouseaddr+=2; - bitsB = *(Bit16u *)&vga.mem.linear[mouseaddr]; - mouseaddr+=2; - z = 7; - for(r=15;r>=0;--r) { - vga.s3.hgc.mc[t][xat] = (((bitsA >> z) & 0x1) << 1) | ((bitsB >> z) & 0x1); - xat++; - --z; - if(z<0) z=15; - } - } - } - -} - void VGA_SetupXGA(void) { if (machine!=MCH_VGA) return; @@ -521,6 +1054,9 @@ void VGA_SetupXGA(void) { IO_RegisterWriteHandler(0xe2e8,&XGA_Write,IO_MB | IO_MW | IO_MD); IO_RegisterReadHandler(0xe2e8,&XGA_Read,IO_MB | IO_MW | IO_MD); + IO_RegisterWriteHandler(0xe2e0,&XGA_Write,IO_MB | IO_MW | IO_MD); + IO_RegisterReadHandler(0xe2e0,&XGA_Read,IO_MB | IO_MW | IO_MD); + IO_RegisterWriteHandler(0xe2ea,&XGA_Write,IO_MB | IO_MW | IO_MD); IO_RegisterReadHandler(0xe2ea,&XGA_Read,IO_MB | IO_MW | IO_MD); diff --git a/src/ints/Makefile.in b/src/ints/Makefile.in index 67757ac..e228636 100644 --- a/src/ints/Makefile.in +++ b/src/ints/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -104,6 +104,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -129,10 +131,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/ints/bios.cpp b/src/ints/bios.cpp index f3982d6..d14acb8 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,24 +16,27 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: bios.cpp,v 1.36 2004/10/23 15:15:06 qbix79 Exp $ */ +/* $Id: bios.cpp,v 1.57 2006/02/09 11:47:55 qbix79 Exp $ */ -#include #include "dosbox.h" +#include "mem.h" #include "bios.h" #include "regs.h" #include "cpu.h" #include "callback.h" #include "inout.h" -#include "mem.h" #include "pic.h" #include "joystick.h" -#include "dos_inc.h" #include "mouse.h" +#include "setup.h" -static Bitu call_int1a,call_int11,call_int8,call_int17,call_int12,call_int15,call_int1c; -static Bitu call_int1,call_int70,call_int14; + +/* if mem_systems 0 then size_extended is reported as the real size else + * zero is reported. ems and xms can increase or decrease the other_memsystems + * counter using the BIOS_ZeroExtendedSize call */ static Bit16u size_extended; +static Bits other_memsystems=0; +void CMOS_SetRegister(Bitu regNr, Bit8u val); //For setting equipment word static Bitu INT70_Handler(void) { /* Acknowledge irq with cmos */ @@ -59,6 +62,209 @@ static Bitu INT70_Handler(void) { return 0; } +CALLBACK_HandlerObject* tandy_DAC_callback; +static struct { + Bit16u port; + Bit8u irq; + Bit8u dma; +} tandy_sb; + +static bool Tandy_ProbeSBPort(Bit16u sbport) { + IO_Write(sbport+0x6,1); + IO_Write(sbport+0x6,0); + while (!(IO_Read(sbport+0xe)&0x80)) ; + if (IO_Read(sbport+0xa)==0xaa) return true; + else return false; +} + +static bool Tandy_InitializeSB() { + /* see if soundblaster module available and at what port */ + if (Tandy_ProbeSBPort(0x220)) tandy_sb.port=0x220; + else if (Tandy_ProbeSBPort(0x230)) tandy_sb.port=0x230; + else if (Tandy_ProbeSBPort(0x210)) tandy_sb.port=0x210; + else if (Tandy_ProbeSBPort(0x240)) tandy_sb.port=0x240; + else if (Tandy_ProbeSBPort(0x250)) tandy_sb.port=0x250; + else if (Tandy_ProbeSBPort(0x260)) tandy_sb.port=0x260; + else { + /* no soundblaster accessible, disable Tandy DAC */ + tandy_sb.port=0; + return false; + } + + /* try to detect IRQ setting */ + IO_Write(tandy_sb.port+0x4,0x80); + Bit8u rval=IO_Read(tandy_sb.port+0x5); + if (rval && (rval!=0xff)) { + if (rval&1) tandy_sb.irq=0x02; + else if (rval&2) tandy_sb.irq=0x05; + else if (rval&4) tandy_sb.irq=0x07; + else tandy_sb.irq=0x10; + } else tandy_sb.irq=0x07; /* assume irq=7 for older soundblaster settings */ + + /* try to detect DMA setting */ + IO_Write(tandy_sb.port+0x4,0x81); + rval=IO_Read(tandy_sb.port+0x5); + if (rval && (rval!=0xff)) { + if (rval&1) tandy_sb.dma=0x00; + else if (rval&2) tandy_sb.dma=0x01; + else tandy_sb.dma=0x03; + } else tandy_sb.dma=0x01; /* assume dma=1 for older soundblaster settings */ + + return true; +} + +/* check if Tandy DAC is still playing */ +static bool Tandy_TransferInProgress(void) { + if (real_readw(0x40,0xd0)) return true; /* not yet done */ + if (real_readb(0x40,0xd4)==0xff) return false; /* still in init-state */ + + IO_Write(0x0c,0x00); + Bit16u datalen=IO_ReadB(tandy_sb.dma*2+1); + datalen|=(IO_ReadB(tandy_sb.dma*2+1)<<8); + if (datalen==0xffff) return false; /* no DMA transfer */ + else if ((datalen<0x10) && (real_readb(0x40,0xd4)==0x0f) && (real_readw(0x40,0xd2)==0x1c)) { + /* stop already requested */ + return false; + } + return true; +} + +static void Tandy_SetupTransfer(PhysPt bufpt,bool isplayback) { + Bitu length=real_readw(0x40,0xd0); + if (length==0) return; /* nothing to do... */ + + if (tandy_sb.port==0) return; + + /* revector IRQ-handler if necessary */ + RealPt current_irq=RealGetVec(tandy_sb.irq+8); + if (current_irq!=tandy_DAC_callback->Get_RealPointer()) { + real_writed(0x40,0xd6,current_irq); + RealSetVec(tandy_sb.irq+8,tandy_DAC_callback->Get_RealPointer()); + } + + IO_Write(tandy_sb.port+0xc,0xd0); /* stop DMA transfer */ + IO_Write(0x21,IO_Read(0x21)&(~(1<>16)&0xff); + IO_Write(tandy_sb.dma*2,(Bit8u)(bufpt&0xff)); + IO_Write(tandy_sb.dma*2,(Bit8u)((bufpt>>8)&0xff)); + switch (tandy_sb.dma) { + case 0: IO_Write(0x87,bufpage); break; + case 1: IO_Write(0x83,bufpage); break; + case 2: IO_Write(0x81,bufpage); break; + case 3: IO_Write(0x82,bufpage); break; + } + real_writeb(0x40,0xd4,bufpage); + + /* calculate transfer size (respects segment boundaries) */ + Bit32u tlength=length; + if (tlength+(bufpt&0xffff)>0x10000) tlength=0x10000-(bufpt&0xffff); + real_writew(0x40,0xd0,(Bit16u)(length-tlength)); /* remaining buffer length */ + tlength--; + + /* set transfer size */ + IO_Write(tandy_sb.dma*2+1,(Bit8u)(tlength&0xff)); + IO_Write(tandy_sb.dma*2+1,(Bit8u)((tlength>>8)&0xff)); + IO_Write(0x0a,tandy_sb.dma); /* enable DMA channel */ + + Bitu delay=real_readw(0x40,0xd2)&0xfff; + /* set frequency */ + IO_Write(tandy_sb.port+0xc,0x40); + IO_Write(tandy_sb.port+0xc,256-delay*100/358); + /* set playback type to 8bit */ + if (isplayback) IO_Write(tandy_sb.port+0xc,0x14); + else IO_Write(tandy_sb.port+0xc,0x24); + /* set transfer size */ + IO_Write(tandy_sb.port+0xc,(Bit8u)(tlength&0xff)); + IO_Write(tandy_sb.port+0xc,(Bit8u)((tlength>>8)&0xff)); + + if (!isplayback) { + /* mark transfer as recording operation */ + real_writew(0x40,0xd2,delay|0x1000); + } +} + +static Bitu IRQ_TandyDAC(void) { + if (real_readw(0x40,0xd0)) { /* play/record next buffer */ + /* acknowledge IRQ */ + IO_Write(0x20,0x20); + IO_Read(tandy_sb.port+0xe); + + /* buffer starts at the next page */ + Bit8u npage=real_readb(0x40,0xd4)+1; + real_writeb(0x40,0xd4,npage); + + Bitu rb=real_readb(0x40,0xd3); + if (rb&0x10) { + /* start recording */ + real_writeb(0x40,0xd3,rb&0xef); + Tandy_SetupTransfer(npage<<16,false); + } else { + /* start playback */ + Tandy_SetupTransfer(npage<<16,true); + } + } else { /* playing/recording is finished */ + RealSetVec(tandy_sb.irq+8,real_readd(0x40,0xd6)); + + /* turn off speaker and acknowledge soundblaster IRQ */ + IO_Write(tandy_sb.port+0xc,0xd3); + IO_Read(tandy_sb.port+0xe); + + /* issue BIOS tandy sound device busy callout */ + Bit16u oldax=reg_ax; + reg_ax=0x91fb; + CALLBACK_RunRealInt(0x15); + reg_ax = oldax; + + IO_Write(0x20,0x20); + } + return CBRET_NONE; +} + +static void TandyDAC_Handler(Bit8u tfunction) { + if (!tandy_sb.port) return; + switch (tfunction) { + case 0x81: /* Tandy sound system check */ + reg_ax=0xc4; + CALLBACK_SCF(Tandy_TransferInProgress()); + break; + case 0x82: /* Tandy sound system start recording */ + case 0x83: /* Tandy sound system start playback */ + if (Tandy_TransferInProgress()) { + /* cannot play yet as the last transfer isn't finished yet */ + reg_ah=0x00; + CALLBACK_SCF(true); + break; + } + /* store buffer length */ + real_writew(0x40,0xd0,reg_cx); + /* store delay and volume */ + real_writew(0x40,0xd2,(reg_dx&0xfff)|((reg_al&7)<<13)); + Tandy_SetupTransfer(PhysMake(SegValue(es),reg_bx),reg_ah==0x83); + reg_ah=0x00; + CALLBACK_SCF(false); + break; + case 0x84: /* Tandy sound system stop playing */ + reg_ah=0x00; + + /* setup for a small buffer with silence */ + real_writew(0x40,0xd0,0x0a); + real_writew(0x40,0xd2,0x1c); + Tandy_SetupTransfer(PhysMake(0xf000,0xa084),true); + CALLBACK_SCF(false); + break; + case 0x85: /* Tandy sound system reset */ + reg_ah=0x00; + CALLBACK_SCF(false); + break; + } +} + static Bitu INT1A_Handler(void) { switch (reg_ah) { case 0x00: /* Get System time */ @@ -79,37 +285,30 @@ static Bitu INT1A_Handler(void) { reg_cl=IO_Read(0x71); IO_Write(0x70,0x00); //Seconds reg_dh=IO_Read(0x71); - reg_dl=0; //Daylight saving disabled + reg_dl=0; //Daylight saving disabled + CALLBACK_SCF(false); + break; + case 0x04: /* GET REAL-TIME ClOCK DATE (AT,XT286,PS) */ + IO_Write(0x70,0x32); //Centuries + reg_ch=IO_Read(0x71); + IO_Write(0x70,0x09); //Years + reg_cl=IO_Read(0x71); + IO_Write(0x70,0x08); //Months + reg_dh=IO_Read(0x71); + IO_Write(0x70,0x07); //Days + reg_dl=IO_Read(0x71); CALLBACK_SCF(false); break; - case 0x04: /* GET REAL-TIME ClOCK DATA (AT,XT286,PS) */ - reg_dx=0; - reg_cx=0x2003; - CALLBACK_SCF(false); - LOG(LOG_BIOS,LOG_ERROR)("INT1A:04:Faked RTC get date call"); - break; -// reg_dx=reg_cx=0; -// CALLBACK_SCF(false); -// LOG(LOG_BIOS,LOG_ERROR)("INT1A:04:Faked RTC get date call"); -// break; case 0x80: /* Pcjr Setup Sound Multiplexer */ LOG(LOG_BIOS,LOG_ERROR)("INT1A:80:Setup tandy sound multiplexer to %d",reg_al); break; - case 0x81: /* Tandy sound system checks */ - if (machine!=MCH_TANDY) break; - reg_ax=0xc4; - CALLBACK_SCF(false); + case 0x81: /* Tandy sound system check */ + case 0x82: /* Tandy sound system start recording */ + case 0x83: /* Tandy sound system start playback */ + case 0x84: /* Tandy sound system stop playing */ + case 0x85: /* Tandy sound system reset */ + TandyDAC_Handler(reg_ah); break; -/* - INT 1A - Tandy 2500, Tandy 1000L series - DIGITAL SOUND - INSTALLATION CHECK - AX = 8100h - Return: AL > 80h if supported - AX = 00C4h if supported (1000SL/TL) - CF set if sound chip is busy - CF clear if sound chip is free - Note: the value of CF is not definitive; call this function until CF is - clear on return, then call AH=84h"Tandy" - */ case 0xb1: /* PCI Bios Calls */ LOG(LOG_BIOS,LOG_ERROR)("INT1A:PCI bios call %2X",reg_al); CALLBACK_SCF(true); @@ -130,7 +329,7 @@ static Bitu INT8_Handler(void) { mem_writed(BIOS_TIMER,mem_readd(BIOS_TIMER)+1); /* decrease floppy motor timer */ Bit8u val = mem_readb(BIOS_DISK_MOTOR_TIMEOUT); - if (val>0) mem_writeb(BIOS_DISK_MOTOR_TIMEOUT,val-1); + if (val) mem_writeb(BIOS_DISK_MOTOR_TIMEOUT,val-1); /* and running drive */ mem_writeb(BIOS_DRIVE_RUNNING,mem_readb(BIOS_DRIVE_RUNNING) & 0xF0); // Save ds,dx,ax @@ -174,14 +373,179 @@ static Bitu INT17_Handler(void) { return CBRET_NONE; } -static Bitu INT14_Handler(void) { - switch (reg_ah) { +static Bitu INT14_Handler(void) +{ + Bit16u port = real_readw(0x40,reg_dx*2); // DX is always port number + if(reg_dx > 0x3 || port==0) // no more than 4 serial ports + { + LOG_MSG("BIOS INT14: port %d does not exist.",reg_dx); + return CBRET_NONE; + } + switch (reg_ah) + { case 0x00: /* Init port */ + // Parameters: + // AL: port parameters + // Return: + // AH: line status + // AL: modem status { - Bitu port=real_readw(0x40,reg_dx*2); + // set baud rate + Bitu baudrate = 9600; + Bit16u baudresult; + Bitu rawbaud=reg_al>>5; + + if(rawbaud==0){ baudrate=110;} + else if (rawbaud==1){ baudrate=150;} + else if (rawbaud==2){ baudrate=300;} + else if (rawbaud==3){ baudrate=600;} + else if (rawbaud==4){ baudrate=1200;} + else if (rawbaud==5){ baudrate=2400;} + else if (rawbaud==6){ baudrate=4800;} + else if (rawbaud==7){ baudrate=9600;} + + baudresult = (Bit16u)(115200 / baudrate); + + IO_WriteB(port+3, 0x80); // enable divider access + IO_WriteB(port,(Bit8u)baudresult&0xff); + IO_WriteB(port+1,(Bit8u)(baudresult>>8)); + + // set line parameters, disable divider access + IO_WriteB(port+3, reg_al&0x1F);//LCR + + // disable interrupts + IO_WriteB(port+1, 0); + IO_ReadB(port+2); + // put RTS and DTR on + IO_WriteB(port+4,0x3); + + // get result + reg_ah=IO_ReadB(port+5); + reg_al=IO_ReadB(port+6); + } + break; + case 0x01: /* Write character */ + // Parameters: + // AL: character + // Return: + // AH: line status + // AL: modem status + { + if((IO_ReadB(port+5)&&0x20)==0) + { + // TODO: should wait until they become empty->timeout + LOG_MSG("BIOS INT14: port %d: transmit register not empty.",reg_dx); + reg_ah = IO_ReadB(port+5)|0x80; + return CBRET_NONE; + } + // transmit it + IO_WriteB(port,reg_al); + + if((IO_ReadB(port+5)&&0x60)==0) + { + // TODO: should wait until they become empty->timeout + LOG_MSG("BIOS INT14: port %d: transmit register not empty after write.",reg_dx); + reg_ah = IO_ReadB(port+5)|0x80; + return CBRET_NONE; + } + + // get result + reg_ah=IO_ReadB(port+5); + reg_al=IO_ReadB(port+6); + } + break; + + case 0x02: /* Read character */ + { + if((IO_ReadB(port+5)&0x1)!=0) + { + reg_al=IO_ReadB(port); + } + else + { + // TODO: should wait until timeout + LOG_MSG("BIOS INT14: port %d: nothing received.",reg_dx); + reg_ah = IO_ReadB(port+5)|0x80; + return CBRET_NONE; + } + reg_ah=IO_ReadB(port+5); + } + break; + case 0x03: // get status + { + reg_ah=IO_ReadB(port+5); + //LOG_MSG("status reg_ah: %x",reg_ah); + reg_al=IO_ReadB(port+6); + } + break; + case 0x04: // extended initialisation + // Parameters: + // AL: break + // BH: parity + // BL: stopbit + // CH: word length + // CL: baudrate + { + Bit8u lcr = 0; + + // baud rate + Bitu baudrate = 9600; + Bit16u baudresult; + Bitu rawbaud=reg_cl; + + if(rawbaud==0){ baudrate=110;} + else if (rawbaud==1){ baudrate=150;} + else if (rawbaud==2){ baudrate=300;} + else if (rawbaud==3){ baudrate=600;} + else if (rawbaud==4){ baudrate=1200;} + else if (rawbaud==5){ baudrate=2400;} + else if (rawbaud==6){ baudrate=4800;} + else if (rawbaud==7){ baudrate=9600;} + else if (rawbaud==8){ baudrate=19200;} + + baudresult = (Bit16u)(115200 / baudrate); + + IO_WriteB(port+3, 0x80); // enable divider access + IO_WriteB(port,(Bit8u)baudresult&0xff); + IO_WriteB(port+1,(Bit8u)(baudresult>>8)); + + // line configuration + // break + if(reg_al!=0) lcr=0x40; + // parity + if(reg_bh!=0) + { + if(reg_bh==1)lcr|=0x8;// odd + else if(reg_bh==2)lcr|=0x18;// even + else if(reg_bh==3)lcr|=0x28;// mark + else if(reg_bh==4)lcr|=0x38;// mark + } + // stopbit + if(reg_bl!=0) + { + lcr|=0x4; + } + // data length + lcr|=(reg_ch&0x3); + IO_WriteB(port+3,lcr); + + reg_ah=IO_ReadB(port+5); + reg_al=IO_ReadB(port+6); + } + break; + case 0x05: // modem control + { + if(reg_al==0) // read MCR + { + reg_bl=IO_ReadB(port+4); + } + else if(reg_al==1) // write MCR + { + IO_WriteB(port+4,reg_bl); + } + else LOG_MSG("BIOS INT14: port %d, function 5: invalid subfunction.",reg_dx); reg_ah=IO_ReadB(port+5); reg_al=IO_ReadB(port+6); - LOG_MSG("AX %X DX %X",reg_ax,reg_dx); } break; default: @@ -201,15 +565,29 @@ static Bitu INT15_Handler(void) { { if (biosConfigSeg==0) biosConfigSeg = DOS_GetMemory(1); //We have 16 bytes PhysPt data = PhysMake(biosConfigSeg,0); - mem_writew(data,8); // 3 Bytes following - mem_writeb(data+2,0xFC); // Model ID - mem_writeb(data+3,0x00); // Submodel ID - mem_writeb(data+4,0x01); // Bios Revision - mem_writeb(data+5,(1<<6)|(1<<5)|(1<<4));// Feature Byte 1 + mem_writew(data,8); // 8 Bytes following + if (IS_TANDY_ARCH) { + if (machine==MCH_TANDY) { + // Model ID (Tandy) + mem_writeb(data+2,0xFF); + } else { + // Model ID (PCJR) + mem_writeb(data+2,0xFD); + } + mem_writeb(data+3,0x0A); // Submodel ID + mem_writeb(data+4,0x10); // Bios Revision + /* Tandy doesn't have a 2nd PIC, left as is for now */ + mem_writeb(data+5,(1<<6)|(1<<5)|(1<<4)); // Feature Byte 1 + } else { + mem_writeb(data+2,0xFC); // Model ID (PC) + mem_writeb(data+3,0x00); // Submodel ID + mem_writeb(data+4,0x01); // Bios Revision + mem_writeb(data+5,(1<<6)|(1<<5)|(1<<4)); // Feature Byte 1 + } mem_writeb(data+6,(1<<6)); // Feature Byte 2 mem_writeb(data+7,0); // Feature Byte 3 mem_writeb(data+8,0); // Feature Byte 4 - mem_writeb(data+9,0); // Feature Byte 4 + mem_writeb(data+9,0); // Feature Byte 5 CPU_SetSegGeneral(es,biosConfigSeg); reg_bx = 0; reg_ah = 0; @@ -238,26 +616,35 @@ static Bitu INT15_Handler(void) { } break; case 0x84: /* BIOS - JOYSTICK SUPPORT (XT after 11/8/82,AT,XT286,PS) */ - if (reg_dx==0x0000) { + if (reg_dx == 0x0000) { // Get Joystick button status if (JOYSTICK_IsEnabled(0) || JOYSTICK_IsEnabled(1)) { - reg_al = (JOYSTICK_GetButton(0,0)<<7)|(JOYSTICK_GetButton(0,1)<<6); - reg_al |= (JOYSTICK_GetButton(1,0)<<5)|(JOYSTICK_GetButton(1,1)<<4); + reg_al = IO_ReadB(0x201)&0xf0; CALLBACK_SCF(false); } else { // dos values reg_ax = 0x00f0; reg_dx = 0x0201; CALLBACK_SCF(true); } - } else if (reg_dx==0x0001) { - if (JOYSTICK_IsEnabled(0) || JOYSTICK_IsEnabled(1)) { - reg_ax = (Bit16u)JOYSTICK_GetMove_X(0); - reg_bx = (Bit16u)JOYSTICK_GetMove_Y(0); - reg_cx = (Bit16u)JOYSTICK_GetMove_X(1); - reg_dx = (Bit16u)JOYSTICK_GetMove_Y(1); + } else if (reg_dx == 0x0001) { + if (JOYSTICK_IsEnabled(0)) { + reg_ax = (Bit16u)(JOYSTICK_GetMove_X(0)*127+128); + reg_bx = (Bit16u)(JOYSTICK_GetMove_Y(0)*127+128); + if(JOYSTICK_IsEnabled(1)) { + reg_cx = (Bit16u)(JOYSTICK_GetMove_X(1)*127+128); + reg_dx = (Bit16u)(JOYSTICK_GetMove_Y(1)*127+128); + } + else { + reg_cx = reg_dx = 0; + } + CALLBACK_SCF(false); + } else if (JOYSTICK_IsEnabled(1)) { + reg_ax = reg_bx = 0; + reg_cx = (Bit16u)(JOYSTICK_GetMove_X(1)*127+128); + reg_dx = (Bit16u)(JOYSTICK_GetMove_Y(1)*127+128); CALLBACK_SCF(false); } else { - reg_ax=reg_bx=reg_cx=reg_dx=0; + reg_ax = reg_bx = reg_cx = reg_dx = 0; CALLBACK_SCF(true); } } else { @@ -266,8 +653,6 @@ static Bitu INT15_Handler(void) { break; case 0x86: /* BIOS - WAIT (AT,PS) */ { - //TODO Perhaps really wait :) - Bit32u micro=(reg_cx<<16)|reg_dx; if (mem_readb(BIOS_WAIT_FLAG_ACTIVE)) { reg_ah=0x83; CALLBACK_SCF(true); @@ -300,7 +685,7 @@ static Bitu INT15_Handler(void) { break; } case 0x88: /* SYSTEM - GET EXTENDED MEMORY SIZE (286+) */ - reg_ax=size_extended; + reg_ax=other_memsystems?0:size_extended; LOG(LOG_BIOS,LOG_NORMAL)("INT15:Function 0x88 Remaining %04X kb",reg_ax); CALLBACK_SCF(false); break; @@ -342,19 +727,27 @@ static Bitu INT15_Handler(void) { reg_ah=0; CALLBACK_SCF(false); } else if (reg_bh==0x01) { //enable - Mouse_SetPS2State(true); + if (!Mouse_SetPS2State(true)) { + reg_ah=5; + CALLBACK_SCF(true); + break; + } reg_ah=0; CALLBACK_SCF(false); - } else CALLBACK_SCF(true); + } else { + CALLBACK_SCF(true); + reg_ah=1; + } break; case 0x01: // reset reg_bx=0x00aa; // mouse - CALLBACK_SCF(false); - break; - case 0x02: // set sampling rate + // fall through + case 0x05: // initialize + Mouse_SetPS2State(false); CALLBACK_SCF(false); reg_ah=0; break; + case 0x02: // set sampling rate case 0x03: // set resolution CALLBACK_SCF(false); reg_ah=0; @@ -364,20 +757,23 @@ static Bitu INT15_Handler(void) { CALLBACK_SCF(false); reg_ah=0; break; - case 0x05: // initialize - CALLBACK_SCF(false); - reg_ah=0; - break; case 0x06: // extended commands - if ((reg_bh==0x01) || (reg_bh==0x02)) { CALLBACK_SCF(false); reg_ah=0;} - else CALLBACK_SCF(true); + if ((reg_bh==0x01) || (reg_bh==0x02)) { + CALLBACK_SCF(false); + reg_ah=0; + } else { + CALLBACK_SCF(true); + reg_ah=1; + } break; case 0x07: // set callback Mouse_ChangePS2Callback(SegValue(es),reg_bx); CALLBACK_SCF(false); + reg_ah=0; break; default: CALLBACK_SCF(true); + reg_ah=1; break; } break; @@ -393,117 +789,266 @@ static Bitu INT15_Handler(void) { return CBRET_NONE; } -static Bitu INT1_Single_Step(void) { - static bool warned=false; - if (!warned) { - warned=true; - LOG(LOG_CPU,LOG_NORMAL)("INT 1:Single Step called"); - } - return CBRET_NONE; +void BIOS_ZeroExtendedSize(bool in) { + if(in) other_memsystems++; + else other_memsystems--; + if(other_memsystems < 0) other_memsystems=0; } -void BIOS_ZeroExtendedSize(void) { - size_extended=0; +#define RAM_REFRESH_DELAY 16.7f + +static void RAMRefresh_Event(Bitu val) { + PIC_ActivateIRQ(5); + PIC_AddEvent(RAMRefresh_Event,RAM_REFRESH_DELAY); } void BIOS_SetupKeyboard(void); void BIOS_SetupDisks(void); -void BIOS_Init(Section* sec) { - MSG_Add("BIOS_CONFIGFILE_HELP","Nothing to setup yet!\n"); - /* Clear the Bios Data Area */ - for (Bit16u i=0;i<1024;i++) real_writeb(0x40,i,0); - /* Setup all the interrupt handlers the bios controls */ - /* INT 8 Clock IRQ Handler */ - //TODO Maybe give this a special callback that will also call int 8 instead of starting - //a new system - call_int8=CALLBACK_Allocate(); - CALLBACK_Setup(call_int8,&INT8_Handler,CB_IRET,"Int 8 Clock"); - phys_writeb(CB_BASE+(call_int8<<4)+0,(Bit8u)0xFE); //GRP 4 - phys_writeb(CB_BASE+(call_int8<<4)+1,(Bit8u)0x38); //Extra Callback instruction - phys_writew(CB_BASE+(call_int8<<4)+2,call_int8); //The immediate word - phys_writeb(CB_BASE+(call_int8<<4)+4,(Bit8u)0x50); // push ax - phys_writeb(CB_BASE+(call_int8<<4)+5,(Bit8u)0xb0); // mov al, 0x20 - phys_writeb(CB_BASE+(call_int8<<4)+6,(Bit8u)0x20); - phys_writeb(CB_BASE+(call_int8<<4)+7,(Bit8u)0xe6); // out 0x20, al - phys_writeb(CB_BASE+(call_int8<<4)+8,(Bit8u)0x20); - phys_writeb(CB_BASE+(call_int8<<4)+9,(Bit8u)0x58); // pop ax - phys_writeb(CB_BASE+(call_int8<<4)+10,(Bit8u)0xcf); // iret +class BIOS:public Module_base{ +private: + CALLBACK_HandlerObject callback[9]; +public: + BIOS(Section* configuration):Module_base(configuration){ + /* tandy DAC can be requested in tandy_sound.cpp by initializing this field */ + bool use_tandyDAC=(real_readb(0x40,0xd4)==0xff); + /* Clear the Bios Data Area (0x400-0x5ff, 0x600- is accounted to DOS) */ + for (Bit16u i=0;i<0x200;i++) real_writeb(0x40,i,0); + /* Setup all the interrupt handlers the bios controls */ + /* INT 8 Clock IRQ Handler */ + //TODO Maybe give this a special callback that will also call int 8 instead of starting + //a new system + callback[0].Install(INT8_Handler,CB_IRET,"Int 8 Clock"); + callback[0].Set_RealVec(0x8); + Bit16u call_int8=callback[0].Get_callback(); + phys_writeb(CB_BASE+(call_int8<<4)+0,(Bit8u)0xFE); //GRP 4 + phys_writeb(CB_BASE+(call_int8<<4)+1,(Bit8u)0x38); //Extra Callback instruction + phys_writew(CB_BASE+(call_int8<<4)+2,call_int8); //The immediate word + phys_writeb(CB_BASE+(call_int8<<4)+4,(Bit8u)0x50); // push ax + phys_writeb(CB_BASE+(call_int8<<4)+5,(Bit8u)0xb0); // mov al, 0x20 + phys_writeb(CB_BASE+(call_int8<<4)+6,(Bit8u)0x20); + phys_writeb(CB_BASE+(call_int8<<4)+7,(Bit8u)0xe6); // out 0x20, al + phys_writeb(CB_BASE+(call_int8<<4)+8,(Bit8u)0x20); + phys_writeb(CB_BASE+(call_int8<<4)+9,(Bit8u)0x58); // pop ax + phys_writeb(CB_BASE+(call_int8<<4)+10,(Bit8u)0xcf); // iret - mem_writed(BIOS_TIMER,0); //Calculate the correct time - RealSetVec(0x8,CALLBACK_RealPointer(call_int8)); - /* INT 11 Get equipment list */ - call_int11=CALLBACK_Allocate(); - CALLBACK_Setup(call_int11,&INT11_Handler,CB_IRET,"Int 11 Equipment"); - RealSetVec(0x11,CALLBACK_RealPointer(call_int11)); - /* INT 12 Memory Size default at 640 kb */ - call_int12=CALLBACK_Allocate(); - CALLBACK_Setup(call_int12,&INT12_Handler,CB_IRET,"Int 12 Memory"); - RealSetVec(0x12,CALLBACK_RealPointer(call_int12)); - mem_writew(BIOS_MEMORY_SIZE,640); - /* INT 13 Bios Disk Support */ - BIOS_SetupDisks(); - call_int14=CALLBACK_Allocate(); - CALLBACK_Setup(call_int14,&INT14_Handler,CB_IRET,"Int 14 COM-port"); - RealSetVec(0x14,CALLBACK_RealPointer(call_int14)); - /* INT 15 Misc Calls */ - call_int15=CALLBACK_Allocate(); - CALLBACK_Setup(call_int15,&INT15_Handler,CB_IRET,"Int 15 Bios"); - RealSetVec(0x15,CALLBACK_RealPointer(call_int15)); - /* INT 16 Keyboard handled in another file */ - BIOS_SetupKeyboard(); - /* INT 16 Printer Routines */ - call_int17=CALLBACK_Allocate(); - CALLBACK_Setup(call_int17,&INT17_Handler,CB_IRET,"Int 17 Printer"); - RealSetVec(0x17,CALLBACK_RealPointer(call_int17)); - /* INT 1A TIME and some other functions */ - call_int1a=CALLBACK_Allocate(); - CALLBACK_Setup(call_int1a,&INT1A_Handler,CB_IRET_STI,"Int 1a Time"); - RealSetVec(0x1A,CALLBACK_RealPointer(call_int1a)); - /* INT 1C System Timer tick called from INT 8 */ - call_int1c=CALLBACK_Allocate(); - CALLBACK_Setup(call_int1c,&INT1C_Handler,CB_IRET,"Int 1c Timer tick"); - RealSetVec(0x1C,CALLBACK_RealPointer(call_int1c)); - /* IRQ 8 RTC Handler */ - call_int70=CALLBACK_Allocate(); - CALLBACK_Setup(call_int70,&INT70_Handler,CB_IRET,"Int 70 RTC"); - RealSetVec(0x70,CALLBACK_RealPointer(call_int70)); + mem_writed(BIOS_TIMER,0); //Calculate the correct time - /* Some defeault CPU error interrupt handlers */ - call_int1=CALLBACK_Allocate(); - CALLBACK_Setup(call_int1,&INT1_Single_Step,CB_IRET,"Int 1 Single step"); - RealSetVec(0x1,CALLBACK_RealPointer(call_int1)); + /* INT 11 Get equipment list */ + callback[1].Install(&INT11_Handler,CB_IRET,"Int 11 Equipment"); + callback[1].Set_RealVec(0x11); - /* Setup some stuff in 0x40 bios segment */ - /* Test for parallel port */ - if (IO_Read(0x378)!=0xff) real_writew(0x40,0x08,0x378); - /* Test for serial port */ - Bitu index=0; - if (IO_Read(0x3fa)!=0xff) real_writew(0x40,(index++)*2,0x3f8); - if (IO_Read(0x2fa)!=0xff) real_writew(0x40,(index++)*2,0x2f8); - /* Setup equipment list */ - Bitu config=0x4400; //1 Floppy, 2 serial and 1 parrallel -#if (C_FPU) - config|=0x2; //FPU -#endif - switch (machine) { - case MCH_HERC: - config|=0x30; //Startup monochrome - break; - case MCH_CGA: case MCH_TANDY: - config|=0x20; //Startup 80x25 color - break; - default: - config|=0; //EGA VGA - break; + /* INT 12 Memory Size default at 640 kb */ + callback[2].Install(&INT12_Handler,CB_IRET,"Int 12 Memory"); + callback[2].Set_RealVec(0x12); + if (IS_TANDY_ARCH) { + /* reduce reported memory size for the Tandy (32k graphics memory + at the end of the conventional 640k) */ + if (machine==MCH_TANDY) mem_writew(BIOS_MEMORY_SIZE,608); + else mem_writew(BIOS_MEMORY_SIZE,640); + mem_writew(BIOS_TRUE_MEMORY_SIZE,640); + } else mem_writew(BIOS_MEMORY_SIZE,640); + + /* INT 13 Bios Disk Support */ + BIOS_SetupDisks(); + + /* INT 14 Serial Ports */ + callback[3].Install(&INT14_Handler,CB_IRET,"Int 14 COM-port"); + callback[3].Set_RealVec(0x14); + + /* INT 15 Misc Calls */ + callback[4].Install(&INT15_Handler,CB_IRET,"Int 15 Bios"); + callback[4].Set_RealVec(0x15); + + /* INT 16 Keyboard handled in another file */ + BIOS_SetupKeyboard(); + + /* INT 17 Printer Routines */ + callback[5].Install(&INT17_Handler,CB_IRET,"Int 17 Printer"); + callback[5].Set_RealVec(0x17); + + /* INT 1A TIME and some other functions */ + callback[6].Install(&INT1A_Handler,CB_IRET_STI,"Int 1a Time"); + callback[6].Set_RealVec(0x1A); + + /* INT 1C System Timer tick called from INT 8 */ + callback[7].Install(&INT1C_Handler,CB_IRET,"Int 1c Timer tick"); + callback[7].Set_RealVec(0x1C); + + /* IRQ 8 RTC Handler */ + callback[8].Install(&INT70_Handler,CB_IRET,"Int 70 RTC"); + callback[8].Set_RealVec(0x70); + + if (machine==MCH_TANDY) phys_writeb(0xffffe,0xff) ; /* Tandy model */ + else if (machine==MCH_PCJR) phys_writeb(0xffffe,0xfd); /* PCJr model */ + else phys_writeb(0xffffe,0xfc); /* PC */ + + if (use_tandyDAC) { + /* tandy DAC sound requested, see if soundblaster device is available */ + if (Tandy_InitializeSB()) { + real_writew(0x40,0xd0,0x0000); + real_writew(0x40,0xd2,0x0000); + real_writeb(0x40,0xd4,0xff); /* tandy DAC init value */ + real_writed(0x40,0xd6,0x00000000); + /* install the DAC callback handler */ + tandy_DAC_callback=new CALLBACK_HandlerObject(); + tandy_DAC_callback->Install(&IRQ_TandyDAC,CB_IRET,"Tandy DAC IRQ"); + RealPt current_irq=RealGetVec(tandy_sb.irq+8); + real_writed(0x40,0xd6,current_irq); + for (Bitu i=0; i<0x10; i++) phys_writeb(PhysMake(0xf000,0xa084+i),0x80); + } else real_writeb(0x40,0xd4,0x00); + } + + /* Setup some stuff in 0x40 bios segment */ + /* detect parallel ports */ + Bit8u DEFAULTPORTTIMEOUT = 10; // 10 whatevers + Bitu ppindex=0; // number of lpt ports + if ((IO_Read(0x378)!=0xff)|(IO_Read(0x379)!=0xff)) { + // this is our LPT1 + mem_writew(BIOS_ADDRESS_LPT1,0x378); + mem_writeb(BIOS_LPT1_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + if((IO_Read(0x278)!=0xff)|(IO_Read(0x279)!=0xff)) { + // this is our LPT2 + mem_writew(BIOS_ADDRESS_LPT2,0x278); + mem_writeb(BIOS_LPT2_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + if((IO_Read(0x3bc)!=0xff)|(IO_Read(0x3be)!=0xff)) { + // this is our LPT3 + mem_writew(BIOS_ADDRESS_LPT3,0x3bc); + mem_writeb(BIOS_LPT3_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + } + } else if((IO_Read(0x3bc)!=0xff)|(IO_Read(0x3be)!=0xff)) { + // this is our LPT2 + mem_writew(BIOS_ADDRESS_LPT2,0x3bc); + mem_writeb(BIOS_LPT2_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + } + } else if((IO_Read(0x3bc)!=0xff)|(IO_Read(0x3be)!=0xff)) { + // this is our LPT1 + mem_writew(BIOS_ADDRESS_LPT1,0x3bc); + mem_writeb(BIOS_LPT1_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + if((IO_Read(0x278)!=0xff)|(IO_Read(0x279)!=0xff)) { + // this is our LPT2 + mem_writew(BIOS_ADDRESS_LPT2,0x278); + mem_writeb(BIOS_LPT2_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + } } - config |= 0x04; // PS2 mouse - mem_writew(BIOS_CONFIGURATION,config); - /* Setup extended memory size */ - IO_Write(0x70,0x30); - size_extended=IO_Read(0x71); - IO_Write(0x70,0x31); - size_extended|=(IO_Read(0x71) << 8); + else if((IO_Read(0x278)!=0xff)|(IO_Read(0x279)!=0xff)) { + // this is our LPT1 + mem_writew(BIOS_ADDRESS_LPT1,0x278); + mem_writeb(BIOS_LPT1_TIMEOUT,DEFAULTPORTTIMEOUT); + ppindex++; + } + + /* Setup equipment list */ + // look http://www.bioscentral.com/misc/bda.htm + + //Bitu config=0x4400; //1 Floppy, 2 serial and 1 parrallel + Bitu config = 0x0; + + // set number of parallel ports + // if(ppindex == 0) config |= 0x8000; // looks like 0 ports are not specified + //else if(ppindex == 1) config |= 0x0000; + if(ppindex == 2) config |= 0x4000; + else config |= 0xc000; // 3 ports +#if (C_FPU) + //FPU + config|=0x2; +#endif + switch (machine) { + case MCH_HERC: + //Startup monochrome + config|=0x30; + break; + case MCH_VGA: + case MCH_CGA: + case TANDY_ARCH_CASE: + //Startup 80x25 color + config|=0x20; + break; + default: + //EGA VGA + config|=0; + break; + } + // PS2 mouse + config |= 0x04; + mem_writew(BIOS_CONFIGURATION,config); + CMOS_SetRegister(0x14,config); //Should be updated on changes + /* Setup extended memory size */ + IO_Write(0x70,0x30); + size_extended=IO_Read(0x71); + IO_Write(0x70,0x31); + size_extended|=(IO_Read(0x71) << 8); + + phys_writeb(0xfff53,0xcf); /* bios default interrupt vector location */ + phys_writeb(0xfe987,0xea); /* original IRQ1 location (Defender booter) */ + phys_writed(0xfe988,RealGetVec(0x09)); + + if (machine==MCH_PCJR) PIC_AddEvent(RAMRefresh_Event,RAM_REFRESH_DELAY); + } + ~BIOS(){ + /* abort DAC playing */ + if (tandy_sb.port) { + IO_Write(tandy_sb.port+0xc,0xd3); + IO_Write(tandy_sb.port+0xc,0xd0); + } + real_writeb(0x40,0xd4,0x00); + if (tandy_DAC_callback) { + Bit32u orig_vector=real_readd(0x40,0xd6); + if (orig_vector==tandy_DAC_callback->Get_RealPointer()) { + /* set IRQ vector to old value */ + RealSetVec(tandy_sb.irq+8,real_readd(0x40,0xd6)); + real_writed(0x40,0xd6,0x00000000); + } + delete tandy_DAC_callback; + tandy_DAC_callback=NULL; + } + } +}; + +// set com port data in bios data area +// parameter: array of 4 com port base addresses, 0 = none +void BIOS_SetComPorts(Bit16u baseaddr[]) { + Bit8u DEFAULTPORTTIMEOUT = 10; // 10 whatevers + Bit16u portcount=0; + Bit16u equipmentword; + for(Bitu i = 0; i < 4; i++) { + if(baseaddr[i]!=0) portcount++; + if(i==0) { // com1 + mem_writew(BIOS_BASE_ADDRESS_COM1,baseaddr[i]); + mem_writeb(BIOS_COM1_TIMEOUT,DEFAULTPORTTIMEOUT); + } else if(i==1) { + mem_writew(BIOS_BASE_ADDRESS_COM2,baseaddr[i]); + mem_writeb(BIOS_COM2_TIMEOUT,DEFAULTPORTTIMEOUT); + } else if(i==2) { + mem_writew(BIOS_BASE_ADDRESS_COM3,baseaddr[i]); + mem_writeb(BIOS_COM3_TIMEOUT,DEFAULTPORTTIMEOUT); + } else { + mem_writew(BIOS_BASE_ADDRESS_COM4,baseaddr[i]); + mem_writeb(BIOS_COM4_TIMEOUT,DEFAULTPORTTIMEOUT); + } + } + // set equipment word + equipmentword = mem_readw(BIOS_CONFIGURATION); + equipmentword &= (~0x0E00); + equipmentword |= (portcount << 9); + mem_writew(BIOS_CONFIGURATION,equipmentword); + CMOS_SetRegister(0x14,equipmentword); //Should be updated on changes } +static BIOS* test; + +void BIOS_Destroy(Section* sec){ + delete test; +} + +void BIOS_Init(Section* sec) { + test = new BIOS(sec); + sec->AddDestroyFunction(&BIOS_Destroy,false); +} diff --git a/src/ints/bios_disk.cpp b/src/ints/bios_disk.cpp index be65ce6..11b4414 100644 --- a/src/ints/bios_disk.cpp +++ b/src/ints/bios_disk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: bios_disk.cpp,v 1.27 2006/02/12 23:23:52 harekiet Exp $ */ + #include "dosbox.h" #include "callback.h" #include "bios.h" @@ -25,13 +27,16 @@ #include "mapper.h" #define MAX_SWAPPABLE_DISKS 20 +#define MAX_DISK_IMAGES 4 diskGeo DiskGeometryList[] = { - {160, 8, 1, 40, 0}, - {180, 9, 1, 40, 0}, - {320, 8, 2, 40, 1}, - {360, 9, 2, 40, 1}, - {720, 9, 2, 80, 3}, + { 160, 8, 1, 40, 0}, + { 180, 9, 1, 40, 0}, + { 200, 10, 1, 40, 0}, + { 320, 8, 2, 40, 1}, + { 360, 9, 2, 40, 1}, + { 400, 10, 2, 40, 1}, + { 720, 9, 2, 80, 3}, {1200, 15, 2, 80, 2}, {1440, 18, 2, 80, 4}, {2880, 36, 2, 80, 6}, @@ -47,8 +52,10 @@ RealPt imgDTAPtr; DOS_DTA *imgDTA; bool killRead; +void CMOS_SetRegister(Bitu regNr, Bit8u val); //For setting equipment word + /* 2 floppys and 2 harddrives, max */ -imageDisk *imageDiskList[4]; +imageDisk *imageDiskList[MAX_DISK_IMAGES]; imageDisk *diskSwap[MAX_SWAPPABLE_DISKS]; Bits swapPosition; @@ -105,7 +112,9 @@ void swapInDisks(void) { } } -void swapInNextDisk(void) { +void swapInNextDisk(bool pressed) { + if (!pressed) + return; /* Hack/feature: rescan all disks as well */ for(Bitu i=0;iEmptyCache(); @@ -192,6 +201,17 @@ imageDisk::imageDisk(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHard } if(!founddisk) { active = false; + } else { + Bit16u equipment=mem_readw(BIOS_CONFIGURATION); + if(equipment&1) { + Bitu numofdisks = (equipment>>6)&3; + numofdisks++; + if(numofdisks > 1) numofdisks=1;//max 2 floppies at the moment + equipment&=~0x00C0; + equipment|=(numofdisks<<6); + } else equipment|=1; + mem_writew(BIOS_CONFIGURATION,equipment); + CMOS_SetRegister(0x14, equipment); } } } @@ -267,7 +287,6 @@ static Bitu INT13_DiskHandler(void) { Bit16u segat, bufptr; Bit8u sectbuf[512]; Bitu drivenum; - Bits readcnt; int i,t; last_drive = reg_dl; drivenum = GetDosDriveNumber(reg_dl); @@ -275,21 +294,46 @@ static Bitu INT13_DiskHandler(void) { //LOG_MSG("INT13: Function %x called on drive %x (dos drive %d)", reg_ah, reg_dl, drivenum); switch(reg_ah) { case 0x0: /* Reset disk */ - if(driveInactive(drivenum)) return CBRET_NONE; - last_status = 0x00; - CALLBACK_SCF(false); + { + bool any_images = false; + for(Bitu i = 0;i < MAX_DISK_IMAGES;i++) { + if(imageDiskList[i]) any_images=true; + } + /* if there aren't any diskimages (so only localdrives and virtual drives) + * always succeed on reset disk. If there are diskimages then and only then + * do real checks + */ + if (any_images && driveInactive(drivenum)) { + /* driveInactive sets carry flag if the specified drive is not available */ + if ((machine==MCH_CGA) || (machine==MCH_PCJR)) { + /* those bioses call floppy drive reset for invalid drive values */ + if (((imageDiskList[0]) && (imageDiskList[0]->active)) || ((imageDiskList[1]) && (imageDiskList[1]->active))) { + last_status = 0x00; + CALLBACK_SCF(false); + } + } + return CBRET_NONE; + } + last_status = 0x00; + CALLBACK_SCF(false); + } break; case 0x1: /* Get status of last operation */ if(last_status != 0x00) { reg_ah = last_status; - CALLBACK_SCF(true); + CALLBACK_SCF(true); } else { reg_ah = 0x00; CALLBACK_SCF(false); } break; case 0x2: /* Read sectors */ + if (reg_al==0) { + reg_ah = 0x01; + CALLBACK_SCF(true); + return CBRET_NONE; + } if(driveInactive(drivenum)) { reg_ah = 0xff; CALLBACK_SCF(true); @@ -313,7 +357,7 @@ static Bitu INT13_DiskHandler(void) { } } reg_ah = 0x00; - CALLBACK_SCF(false); + CALLBACK_SCF(false); break; case 0x3: /* Write sectors */ @@ -340,6 +384,11 @@ static Bitu INT13_DiskHandler(void) { CALLBACK_SCF(false); break; case 0x04: /* Verify sectors */ + if (reg_al==0) { + reg_ah = 0x01; + CALLBACK_SCF(true); + return CBRET_NONE; + } if(driveInactive(drivenum)) return CBRET_NONE; /* TODO: Finish coding this section */ @@ -359,8 +408,9 @@ static Bitu INT13_DiskHandler(void) { } }*/ reg_ah = 0x00; + //Qbix: The following codes don't match my specs. al should be number of sector verified //reg_al = 0x10; /* CRC verify failed */ - reg_al = 0x00; /* CRC verify succeeded */ + //reg_al = 0x00; /* CRC verify succeeded */ CALLBACK_SCF(false); break; @@ -375,13 +425,19 @@ static Bitu INT13_DiskHandler(void) { reg_bl = imageDiskList[drivenum]->GetBiosType(); Bit32u tmpheads, tmpcyl, tmpsect, tmpsize; imageDiskList[drivenum]->Get_Geometry(&tmpheads, &tmpcyl, &tmpsect, &tmpsize); - reg_ch = tmpcyl; - reg_cl = tmpsect; + reg_ch = tmpcyl & 0xff; + reg_cl = (((tmpcyl >> 2) & 0xc0) | (tmpsect & 0x3f)); reg_dh = tmpheads-1; last_status = 0x00; - reg_dl = 0; - if(imageDiskList[2] != NULL) reg_dl++; - if(imageDiskList[3] != NULL) reg_dl++; + if (reg_dl&0x80) { // harddisks + reg_dl = 0; + if(imageDiskList[2] != NULL) reg_dl++; + if(imageDiskList[3] != NULL) reg_dl++; + } else { // floppy disks + reg_dl = 0; + if(imageDiskList[0] != NULL) reg_dl++; + if(imageDiskList[1] != NULL) reg_dl++; + } CALLBACK_SCF(false); break; case 0x11: /* Recalibrate drive */ @@ -406,7 +462,6 @@ static Bitu INT13_DiskHandler(void) { void BIOS_SetupDisks(void) { /* TODO Start the time correctly */ call_int13=CALLBACK_Allocate(); - //CALLBACK_Setup(call_int13,&INT13_SmallHandler,CB_IRET); CALLBACK_Setup(call_int13,&INT13_DiskHandler,CB_IRET,"Int 13 Bios disk"); RealSetVec(0x13,CALLBACK_RealPointer(call_int13)); int i; @@ -438,4 +493,3 @@ void BIOS_SetupDisks(void) { MAPPER_AddHandler(swapInNextDisk,MK_f4,MMOD1,"swapimg","Swap Image"); killRead = false; } - diff --git a/src/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index 70f610f..0a524e9 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -24,12 +24,16 @@ #include "regs.h" #include "inout.h" +/* SDL by default treats numlock and scrolllock different from all other keys. + * Some linux distros disable this bad behaviour. (for example debian) + * Define the following if this is the case */ +//#define CAN_USE_LOCK 1 -static Bitu call_int16,call_irq1; +static Bitu call_int16,call_irq1,call_irq6; /* Nice table from BOCHS i should feel bad for ripping this */ #define none 0 -#define MAX_SCAN_CODE 0x53 +#define MAX_SCAN_CODE 0x58 static struct { Bit16u normal; Bit16u shift; @@ -37,7 +41,7 @@ static struct { Bit16u alt; } scan_to_scanascii[MAX_SCAN_CODE + 1] = { { none, none, none, none }, - { 0x011b, 0x011b, 0x011b, 0x0100 }, /* escape */ + { 0x011b, 0x011b, 0x011b, 0x01f0 }, /* escape */ { 0x0231, 0x0221, none, 0x7800 }, /* 1! */ { 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */ { 0x0433, 0x0423, none, 0x7a00 }, /* 3# */ @@ -50,8 +54,8 @@ static struct { { 0x0b30, 0x0b29, none, 0x8100 }, /* 0) */ { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */ { 0x0d3d, 0x0d2b, none, 0x8300 }, /* =+ */ - { 0x0e08, 0x0e08, 0x0e7f, none }, /* backspace */ - { 0x0f09, 0x0f00, none, none }, /* tab */ + { 0x0e08, 0x0e08, 0x0e7f, 0x0ef0 }, /* backspace */ + { 0x0f09, 0x0f00, 0x9400, none }, /* tab */ { 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */ { 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */ { 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */ @@ -62,8 +66,8 @@ static struct { { 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */ { 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */ { 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */ - { 0x1a5b, 0x1a7b, 0x1a1b, none }, /* [{ */ - { 0x1b5d, 0x1b7d, 0x1b1d, none }, /* ]} */ + { 0x1a5b, 0x1a7b, 0x1a1b, 0x1af0 }, /* [{ */ + { 0x1b5d, 0x1b7d, 0x1b1d, 0x1bf0 }, /* ]} */ { 0x1c0d, 0x1c0d, 0x1c0a, none }, /* Enter */ { none, none, none, none }, /* L Ctrl */ { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */ @@ -75,11 +79,11 @@ static struct { { 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */ { 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */ { 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */ - { 0x273b, 0x273a, none, none }, /* ;: */ - { 0x2827, 0x2822, none, none }, /* '" */ - { 0x2960, 0x297e, none, none }, /* `~ */ + { 0x273b, 0x273a, none, 0x27f0 }, /* ;: */ + { 0x2827, 0x2822, none, 0x28f0 }, /* '" */ + { 0x2960, 0x297e, none, 0x29f0 }, /* `~ */ { none, none, none, none }, /* L shift */ - { 0x2b5c, 0x2b7c, 0x2b1c, none }, /* |\ */ + { 0x2b5c, 0x2b7c, 0x2b1c, 0x2bf0 }, /* |\ */ { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */ { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */ { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */ @@ -87,11 +91,11 @@ static struct { { 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */ { 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */ { 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */ - { 0x332c, 0x333c, none, none }, /* ,< */ - { 0x342e, 0x343e, none, none }, /* .> */ - { 0x352f, 0x353f, none, none }, /* /? */ + { 0x332c, 0x333c, none, 0x33f0 }, /* ,< */ + { 0x342e, 0x343e, none, 0x34f0 }, /* .> */ + { 0x352f, 0x353f, none, 0x35f0 }, /* /? */ { none, none, none, none }, /* R Shift */ - { 0x372a, 0x372a, none, none }, /* * */ + { 0x372a, 0x372a, 0x9600, 0x37f0 }, /* * */ { none, none, none, none }, /* L Alt */ { 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */ { none, none, none, none }, /* caps lock */ @@ -108,24 +112,36 @@ static struct { { none, none, none, none }, /* Num Lock */ { none, none, none, none }, /* Scroll Lock */ { 0x4700, 0x4737, 0x7700, 0x0007 }, /* 7 Home */ - { 0x4800, 0x4838, none, 0x0008 }, /* 8 UP */ + { 0x4800, 0x4838, 0x8d00, 0x0008 }, /* 8 UP */ { 0x4900, 0x4939, 0x8400, 0x0009 }, /* 9 PgUp */ - { 0x4a2d, 0x4a2d, none, none }, /* - */ + { 0x4a2d, 0x4a2d, 0x8e00, 0x4af0 }, /* - */ { 0x4b00, 0x4b34, 0x7300, 0x0004 }, /* 4 Left */ - { 0x4c00, 0x4c35, none, 0x0005 }, /* 5 */ + { 0x4cf0, 0x4c35, 0x8f00, 0x0005 }, /* 5 */ { 0x4d00, 0x4d36, 0x7400, 0x0006 }, /* 6 Right */ - { 0x4e2b, 0x4e2b, none, none }, /* + */ + { 0x4e2b, 0x4e2b, 0x9000, 0x4ef0 }, /* + */ { 0x4f00, 0x4f31, 0x7500, 0x0001 }, /* 1 End */ - { 0x5000, 0x5032, none, 0x0002 }, /* 2 Down */ + { 0x5000, 0x5032, 0x9100, 0x0002 }, /* 2 Down */ { 0x5100, 0x5133, 0x7600, 0x0003 }, /* 3 PgDn */ - { 0x5200, 0x5230, none, 0x0000 }, /* 0 Ins */ - { 0x5300, 0x532e, none, none } /* Del */ + { 0x5200, 0x5230, 0x9200, 0x0000 }, /* 0 Ins */ + { 0x5300, 0x532e, 0x9300, none }, /* Del */ + { none, none, none, none }, + { none, none, none, none }, + { 0x565c, 0x567c, none, none }, /* (102-key) */ + { 0x8500, 0x8700, 0x8900, 0x8b00 }, /* F11 */ + { 0x8600, 0x8800, 0x8a00, 0x8c00 } /* F12 */ }; -static void add_key(Bit16u code) { +static bool add_key_forced(Bit16u code) { + if (mem_readb(BIOS_KEYBOARD_FLAGS2)&8) return true; Bit16u start,end,head,tail,ttail; - start=mem_readw(BIOS_KEYBOARD_BUFFER_START); - end =mem_readw(BIOS_KEYBOARD_BUFFER_END); + if (machine==MCH_PCJR) { + /* should be done for cga and others as well, to be tested */ + start=0x1e; + end=0x3e; + } else { + start=mem_readw(BIOS_KEYBOARD_BUFFER_START); + end =mem_readw(BIOS_KEYBOARD_BUFFER_END); + } head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); ttail=tail+2; @@ -134,31 +150,44 @@ static void add_key(Bit16u code) { } /* Check for buffer Full */ //TODO Maybe beeeeeeep or something although that should happend when internal buffer is full - if (ttail==head) return; + if (ttail==head) return false; real_writew(0x40,tail,code); mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,ttail); + return true; } -static Bit16u get_key(void) { +static void add_key(Bit16u code) { + if (code!=0) add_key_forced(code); +} + +static bool get_key(Bit16u &code) { Bit16u start,end,head,tail,thead; - start=mem_readw(BIOS_KEYBOARD_BUFFER_START); - end =mem_readw(BIOS_KEYBOARD_BUFFER_END); + if (machine==MCH_PCJR) { + /* should be done for cga and others as well, to be tested */ + start=0x1e; + end=0x3e; + } else { + start=mem_readw(BIOS_KEYBOARD_BUFFER_START); + end =mem_readw(BIOS_KEYBOARD_BUFFER_END); + } head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); - if (head==tail) return 0; + if (head==tail) return false; thead=head+2; if (thead>=end) thead=start; mem_writew(BIOS_KEYBOARD_BUFFER_HEAD,thead); - return real_readw(0x40,head); + code = real_readw(0x40,head); + return true; } -static Bit16u check_key(void) { +static bool check_key(Bit16u &code) { Bit16u head,tail; head =mem_readw(BIOS_KEYBOARD_BUFFER_HEAD); tail =mem_readw(BIOS_KEYBOARD_BUFFER_TAIL); - if (head==tail) return 0; - return real_readw(0x40,head); + if (head==tail) return false; + code = real_readw(0x40,head); + return true; } /* Flag Byte 1 @@ -224,26 +253,34 @@ static Bitu IRQ1_Handler(void) { flags2=mem_readb(BIOS_KEYBOARD_FLAGS2); flags3=mem_readb(BIOS_KEYBOARD_FLAGS3); leds =mem_readb(BIOS_KEYBOARD_LEDS); +#ifdef CAN_USE_LOCK + /* No hack anymore! */ +#else flags2&=~(0x40+0x20);//remove numlock/capslock pressed (hack for sdl only reporting states) +#endif switch (scancode) { /* First the hard ones */ case 0xfa: /* ack. Do nothing for now */ break; case 0xe1: /* Extended key special. Only pause uses this */ - LOG(LOG_KEYBOARD,LOG_ERROR)("someone is putting the pause key in the keyboard buffer"); + flags3 |=0x01; break; case 0xe0: /* Extended key */ flags3 |=0x02; break; case 0x1d: /* Ctrl Pressed */ - flags1 |=0x04; - if (flags3 &0x02) flags3 |=0x04; - else flags2 |=0x01; + if (!(flags3 &0x01)) { + flags1 |=0x04; + if (flags3 &0x02) flags3 |=0x04; + else flags2 |=0x01; + } /* else it's part of the pause scancodes */ break; case 0x9d: /* Ctrl Released */ - if (flags3 &0x02) flags3 &=~0x04; - else flags2 &=~0x01; - if( !( (flags3 &0x04) || (flags2 &0x01) ) ) flags1 &=~0x04; + if (!(flags3 &0x01)) { + if (flags3 &0x02) flags3 &=~0x04; + else flags2 &=~0x01; + if( !( (flags3 &0x04) || (flags2 &0x01) ) ) flags1 &=~0x04; + } break; case 0x2a: /* Left Shift Pressed */ flags1 |=0x02; @@ -275,11 +312,58 @@ static Bitu IRQ1_Handler(void) { } break; - +#ifdef CAN_USE_LOCK + case 0x3a:flags2 |=0x40;break;//CAPSLOCK + case 0xba:flags1 ^=0x40;flags2 &=~0x40;leds ^=0x04;break; +#else case 0x3a:flags2 |=0x40;flags1 |=0x40;leds |=0x04;break; //SDL gives only the state instead of the toggle /* Caps Lock */ case 0xba:flags1 &=~0x40;leds &=~0x04;break; - case 0x45:flags2 |=0x20;flags1 |=0x20;leds |=0x02;break; /* Num Lock */ - case 0xc5:flags1 &=~0x20;leds &=~0x02;break; +#endif + case 0x45: + if (flags3 &0x01) { + /* last scancode of pause received; first remove 0xe1-prefix */ + flags3 &=~0x01; + mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3); + if (flags2&1) { + /* ctrl-pause (break), special handling needed: + add zero to the keyboard buffer, call int 0x1b which + sets ctrl-c flag which calls int 0x23 in certain dos + input/output functions; not handled */ + } else if ((flags2&8)==0) { + /* normal pause key, enter loop */ + mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2|8); + IO_Write(0x20,0x20); + while (mem_readb(BIOS_KEYBOARD_FLAGS2)&8) CALLBACK_Idle(); // pause loop + reg_ip+=4; // skip out 20,20 + return CBRET_NONE; + } + } else { + /* Num Lock */ +#ifdef CAN_USE_LOCK + flags2 |=0x20; +#else + flags2 |=0x20; + flags1 |=0x20; + leds |=0x02; +#endif + } + break; + case 0xc5: + if (flags3 &0x01) { + /* pause released */ + flags3 &=~0x01; + } else { +#ifdef CAN_USE_LOCK + flags1^=0x20; + leds^=0x02; + flags2&=~0x20; +#else + /* Num Lock released */ + flags1 &=~0x20; + leds &=~0x02; +#endif + } + break; case 0x46:flags2 |=0x10;break; /* Scroll Lock SDL Seems to do this one fine (so break and make codes) */ case 0xc6:flags1 ^=0x10;flags2 &=~0x10;leds ^=0x01;break; // case 0x52:flags2|=128;break;//See numpad /* Insert */ @@ -306,10 +390,10 @@ static Bitu IRQ1_Handler(void) { if(scancode == 0x52) flags2 |=0x80; /* press insert */ if(flags1 &0x08) { add_key(scan_to_scanascii[scancode].normal+0x5000); - } else if( ((flags1 &0x3) != 0) ^ ((flags1 &0x20) != 0) ) { - add_key((scan_to_scanascii[scancode].shift&0xff00)|0xe0); } else if (flags1 &0x04) { add_key((scan_to_scanascii[scancode].control&0xff00)|0xe0); + } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { + add_key((scan_to_scanascii[scancode].shift&0xff00)|0xe0); } else add_key((scan_to_scanascii[scancode].normal&0xff00)|0xe0); break; } @@ -317,10 +401,10 @@ static Bitu IRQ1_Handler(void) { Bit8u token = mem_readb(BIOS_KEYBOARD_TOKEN); token= token*10 + scan_to_scanascii[scancode].alt; mem_writeb(BIOS_KEYBOARD_TOKEN,token); - } else if( ((flags1 &0x3) != 0) ^ ((flags1 &0x20) != 0) ) { - add_key(scan_to_scanascii[scancode].shift); } else if (flags1 &0x04) { add_key(scan_to_scanascii[scancode].control); + } else if( ((flags1 &0x3) != 0) || ((flags1 &0x20) != 0) ) { + add_key(scan_to_scanascii[scancode].shift); } else add_key(scan_to_scanascii[scancode].normal); break; @@ -355,12 +439,24 @@ static Bitu IRQ1_Handler(void) { asciiscan=scan_to_scanascii[scancode].shift; } } + if (flags3 &0x02) { + /* extended key (numblock), return and slash need special handling */ + if (scancode==0x1c) { /* return */ + if (flags1 &0x08) asciiscan=0xa600; + else asciiscan=(asciiscan&0xff)|0xe000; + } else if (scancode==0x35) { /* slash */ + if (flags1 &0x08) asciiscan=0xa400; + else if (flags1 &0x04) asciiscan=0x9500; + else asciiscan=0xe02f; + } + } add_key(asciiscan); break; }; irq1_end: if(scancode !=0xe0) flags3 &=~0x02; //Reset 0xE0 Flag mem_writeb(BIOS_KEYBOARD_FLAGS1,flags1); + if ((scancode&0x80)==0) flags2&=0xf7; mem_writeb(BIOS_KEYBOARD_FLAGS2,flags2); mem_writeb(BIOS_KEYBOARD_FLAGS3,flags3); mem_writeb(BIOS_KEYBOARD_LEDS,leds); @@ -376,30 +472,108 @@ irq1_return: return CBRET_NONE; } +static Bitu IRQ6_Handler(void) { + Bit8u scancode=IO_Read(0x60); + /* skip extended keys, all of them should map quite nicely + onto corresponding non-extended keys */ + if (scancode!=0xe0) { + Bit16u old_ax=reg_ax; + reg_al=scancode; + /* call the real keyboard IRQ now, with the scancode in AL */ + CALLBACK_RunRealInt(0x09); + reg_ax=old_ax; + } + + IO_Write(0x20,0x20); + return CBRET_NONE; +} + + +/* check whether key combination is enhanced or not, + translate key if necessary */ +static bool IsEnhancedKey(Bit16u &key) { + /* test for special keys (return and slash on numblock) */ + if ((key>>8)==0xe0) { + if (((key&0xff)==0x0a) || ((key&0xff)==0x0d)) { + /* key is return on the numblock */ + key=(key&0xff)|0x1c00; + } else { + /* key is slash on the numblock */ + key=(key&0xff)|0x3500; + } + /* both keys are not considered enhanced keys */ + return false; + } else if (((key>>8)>0x84) || (((key&0xff)==0xf0) && (key>>8))) { + /* key is enhanced key (either scancode part>0x84 or + specially-marked keyboard combination, low part==0xf0) */ + return true; + } + /* convert key if necessary (extended keys) */ + if ((key>>8) && ((key&0xff)==0xe0)) { + key&=0xff00; + } + return false; +} + static Bitu INT16_Handler(void) { - Bit16u temp; + Bit16u temp=0; switch (reg_ah) { case 0x00: /* GET KEYSTROKE */ - case 0x10: - { -//TODO find a more elegant way to do this - do { - temp=get_key(); - if (temp==0) { CALLBACK_Idle();}; - } while (temp==0); - reg_ax=temp; - if(reg_al==0xe0) reg_al=0; //extended key - break; + for (;;) { + if (get_key(temp)) { + if (!IsEnhancedKey(temp)) { + /* normal key, exit scanning for keys */ + break; + } + } + CALLBACK_Idle(); } + /* normal key found, return translated key in ax */ + reg_ax=temp; + break; + case 0x10: /* GET KEYSTROKE (enhanced keyboards only) */ + for (;;) { + if (get_key(temp)) { + if (((temp&0xff)==0xf0) && (temp>>8)) { + /* special enhanced key, clear low part before returning key */ + temp&=0xff00; + } + break; + } + CALLBACK_Idle(); + } + reg_ax=temp; + break; case 0x01: /* CHECK FOR KEYSTROKE */ - case 0x11: - temp=check_key(); - if (temp==0) { + for (;;) { + if (check_key(temp)) { + if (!IsEnhancedKey(temp)) { + /* normal key, return translated key in ax */ + CALLBACK_SZF(false); + reg_ax=temp; + break; + } else { + /* remove enhanced key from buffer and ignore it */ + get_key(temp); + } + } else { + /* no key available */ + CALLBACK_SZF(true); + break; + } + CALLBACK_Idle(); + } + break; + case 0x11: /* CHECK FOR KEYSTROKE (enhanced keyboards only) */ + if (!check_key(temp)) { CALLBACK_SZF(true); } else { CALLBACK_SZF(false); + if (((temp&0xff)==0xf0) && (temp>>8)) { + /* special enhanced key, clear low part before returning key */ + temp&=0xff00; + } reg_ax=temp; - if(reg_al==0xe0) reg_al=0; //extended key } break; case 0x02: /* GET SHIFT FlAGS */ @@ -417,9 +591,8 @@ static Bitu INT16_Handler(void) { } break; case 0x05: /* STORE KEYSTROKE IN KEYBOARD BUFFER */ -//TODO make add_key bool :) - add_key(reg_cx); - reg_al=0; + if (add_key_forced(reg_cx)) reg_al=0; + else reg_al=1; break; case 0x12: /* GET EXTENDED SHIFT STATES */ reg_al=mem_readb(BIOS_KEYBOARD_FLAGS1); @@ -470,6 +643,11 @@ void BIOS_SetupKeyboard(void) { RealSetVec(0x16,CALLBACK_RealPointer(call_int16)); CALLBACK_Setup(call_irq1,&IRQ1_Handler,CB_IRET,"keyboard irq"); RealSetVec(0x9,CALLBACK_RealPointer(call_irq1)); + if (machine==MCH_PCJR) { + call_irq6=CALLBACK_Allocate(); + CALLBACK_Setup(call_irq6,&IRQ6_Handler,CB_IRET,"PCJr kb irq"); + RealSetVec(0x0e,CALLBACK_RealPointer(call_irq6)); + } /* bring the all port operations outside the callback */ phys_writeb(CB_BASE+(call_irq1<<4)+0x00,(Bit8u)0x50); // push ax diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index 570cd55..d05bbb9 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: ems.cpp,v 1.36 2004/10/23 15:15:06 qbix79 Exp $ */ +/* $Id: ems.cpp,v 1.47 2006/03/12 20:31:49 c2woody Exp $ */ #include #include @@ -30,10 +30,12 @@ #include "inout.h" #include "dos_inc.h" #include "setup.h" +#include "support.h" +#include "cpu.h" #define EMM_PAGEFRAME 0xE000 #define EMM_PAGEFRAME4K ((EMM_PAGEFRAME*16)/4096) -#define EMM_MAX_HANDLES 100 /* 255 Max */ +#define EMM_MAX_HANDLES 200 /* 255 Max */ #define EMM_PAGE_SIZE (16*1024U) #define EMM_MAX_PAGES (32 * 1024 / 16 ) #define EMM_MAX_PHYS 4 /* 4 16kb pages in pageframe */ @@ -43,6 +45,10 @@ #define NULL_HANDLE 0xffff #define NULL_PAGE 0xffff +#define ENABLE_VCPI 1 +#define ENABLE_V86_STARTUP 0 + + /* EMM errors */ #define EMM_NO_ERROR 0x00 #define EMM_SOFT_MAL 0x80 @@ -93,7 +99,14 @@ struct EMM_Handle { static EMM_Handle emm_handles[EMM_MAX_HANDLES]; static EMM_Mapping emm_mappings[EMM_MAX_PHYS]; -static Bitu call_int67,call_vdma; + +static struct { + bool enabled; + Bit16u ems_handle; + Bitu pm_interface; + MemHandle private_area; + Bit8u pic1_remapping,pic2_remapping; +} vcpi ; struct MoveRegion { Bit32u bytes; @@ -119,20 +132,22 @@ static bool INLINE ValidHandle(Bit16u handle) { return true; } -static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & handle) { +static Bit8u EMM_AllocateMemory(Bit16u pages,Bit16u & dhandle) { /* Check for 0 page allocation */ if (!pages) return EMM_ZERO_PAGES; /* Check for enough free pages */ - if ((MEM_FreeTotal()/4)=EMM_MAX_HANDLES) {handle=NULL_HANDLE;return EMM_OUT_OF_HANDLES;} + while (emm_handles[handle].pages != NULL_HANDLE) { + if (++handle >= EMM_MAX_HANDLES) {return EMM_OUT_OF_HANDLES;} } - MemHandle mem=MEM_AllocatePages(pages*4,false); + MemHandle mem = MEM_AllocatePages(pages*4,false); if (!mem) E_Exit("EMS:Memory allocation failure"); - emm_handles[handle].pages=pages; - emm_handles[handle].mem=mem; + emm_handles[handle].pages = pages; + emm_handles[handle].mem = mem; + /* Change handle only if there is no error. */ + dhandle = handle; return EMM_NO_ERROR; } @@ -196,7 +211,9 @@ static Bit8u EMM_ReleaseMemory(Bit16u handle) { static Bit8u EMM_SavePageMap(Bit16u handle) { /* Check for valid handle */ - if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) { + if (handle!=0) return EMM_INVALID_HANDLE; + } /* Check for previous save */ if (emm_handles[handle].saved_page_map) return EMM_PAGE_MAP_SAVED; /* Copy the mappings over */ @@ -218,7 +235,9 @@ static Bit8u EMM_RestoreMappingTable(void) { } static Bit8u EMM_RestorePageMap(Bit16u handle) { /* Check for valid handle */ - if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) return EMM_INVALID_HANDLE; + if (handle>=EMM_MAX_HANDLES || emm_handles[handle].pages==NULL_HANDLE) { + if (handle!=0) return EMM_INVALID_HANDLE; + } /* Check for previous save */ if (!emm_handles[handle].saved_page_map) return EMM_INVALID_HANDLE; /* Restore the mappings */ @@ -583,8 +602,174 @@ static Bitu INT67_Handler(void) { }; break; case 0xDE: /* VCPI Functions */ - LOG(LOG_MISC,LOG_ERROR)("EMS:VCPI Call %2X not supported",reg_al); - reg_ah=EMM_FUNC_NOSUP; + if (!vcpi.enabled) { + LOG(LOG_MISC,LOG_ERROR)("EMS:VCPI Call %2X not supported",reg_al); + reg_ah=EMM_FUNC_NOSUP; + } else { + switch (reg_al) { + case 0x00: /* VCPI Installation Check */ + if (((reg_cx==0) && (reg_di=0x0012)) || (cpu.pmode && (reg_flags & FLAG_VM))) { + /* JEMM detected or already in v86 mode */ + reg_ah=EMM_NO_ERROR; + reg_bx=0x100; + } else { + reg_ah=EMM_FUNC_NOSUP; + } + break; + case 0x01: { /* VCPI Get Protected Mode Interface */ + Bit16u ct; + /* Set up page table buffer */ + for (ct=0; ct<0xff; ct++) { + real_writeb(SegValue(es),reg_di+ct*4+0x00,0x67); // access bits + real_writew(SegValue(es),reg_di+ct*4+0x01,ct*0x10); // mapping + real_writeb(SegValue(es),reg_di+ct*4+0x03,0x00); + } + for (ct=0xff; ct<0x100; ct++) { + real_writeb(SegValue(es),reg_di+ct*4+0x00,0x67); // access bits + real_writew(SegValue(es),reg_di+ct*4+0x01,(ct-0xff)*0x10+0x1100); // mapping + real_writeb(SegValue(es),reg_di+ct*4+0x03,0x00); + } + /* adjust paging entries for page frame (if mapped) */ + for (ct=0; ct<4; ct++) { + Bit16u handle=emm_mappings[ct].handle; + if (handle!=0xffff) { + Bit16u memh=(Bit16u)MEM_NextHandleAt(emm_handles[handle].mem,emm_mappings[ct].page*4); + Bit16u entry_addr=reg_di+(EMM_PAGEFRAME>>6)+(ct*0x10); + real_writew(SegValue(es),entry_addr+0x00+0x01,(memh+0)*0x10); // mapping of 1/4 of page + real_writew(SegValue(es),entry_addr+0x04+0x01,(memh+1)*0x10); // mapping of 2/4 of page + real_writew(SegValue(es),entry_addr+0x08+0x01,(memh+2)*0x10); // mapping of 3/4 of page + real_writew(SegValue(es),entry_addr+0x0c+0x01,(memh+3)*0x10); // mapping of 4/4 of page + } + } + reg_di+=0x400; // advance pointer by 0x100*4 + + /* Set up three descriptor table entries */ + real_writed(SegValue(ds),reg_si+0x00,0x8000ffff); // descriptor 1 (code segment) + real_writed(SegValue(ds),reg_si+0x04,0x00009a0c); // descriptor 1 + real_writed(SegValue(ds),reg_si+0x08,0x0000ffff); // descriptor 2 (data segment) + real_writed(SegValue(ds),reg_si+0x0c,0x00009200); // descriptor 2 + real_writed(SegValue(ds),reg_si+0x10,0x0000ffff); // descriptor 3 + real_writed(SegValue(ds),reg_si+0x14,0x00009200); // descriptor 3 + + reg_ebx=(vcpi.pm_interface&0xffff); + reg_ah=EMM_NO_ERROR; + break; + } + case 0x02: /* VCPI Maximum Physical Address */ + reg_edx=((MEM_TotalPages()*MEM_PAGESIZE)-1)&0xfffff000; + reg_ah=EMM_NO_ERROR; + break; + case 0x03: /* VCPI Get Number of Free Pages */ + reg_edx=MEM_FreeTotal(); + reg_ah=EMM_NO_ERROR; + break; + case 0x04: { /* VCPI Allocate one Page */ + MemHandle mem = MEM_AllocatePages(1,false); + if (mem) { + reg_edx=mem<<12; + reg_ah=EMM_NO_ERROR; + } else { + reg_ah=EMM_OUT_OF_LOG; + } + break; + } + case 0x05: /* VCPI Free Page */ + MEM_ReleasePages(reg_edx>>12); + reg_ah=EMM_NO_ERROR; + break; + case 0x06: { /* VCPI Get Physical Address of Page in 1st MB */ + if (((reg_cx<<8)>=EMM_PAGEFRAME) && ((reg_cx<<8)>12); + reg_ah=EMM_NO_ERROR; + break; + case 0xDE0C: { /* VCPI Switch from Protected Mode to V86 */ + reg_flags&=(~FLAG_IF); + + /* Flags need to be filled in, VM=true, IOPL=3 */ + mem_writed(SegPhys(ss) + (reg_esp & cpu.stack.mask)+0x10, 0x23002); + + /* Disable Paging */ + CPU_SET_CRX(0, CPU_GET_CRX(0)&0x7ffffff7); + CPU_SET_CRX(3, 0); + + PhysPt tbaddr=vcpi.private_area+0x0000+(0x10&0xfff8)+5; + Bit8u tb=mem_readb(tbaddr); + mem_writeb(tbaddr, tb&0xfd); + + /* Load descriptor table registers */ + CPU_LGDT(0xff, vcpi.private_area+0x0000); + CPU_LIDT(0x7ff, vcpi.private_area+0x2000); + if (CPU_LLDT(0x08)) LOG_MSG("VCPI:Could not load LDT"); + if (CPU_LTR(0x10)) LOG_MSG("VCPI:Could not load TR"); + + reg_flags&=(~FLAG_NT); + reg_esp+=8; // skip interrupt return information +// MEM_A20_Enable(false); + + /* Switch to v86-task */ + CPU_IRET(true,0); + } + break; + default: + LOG(LOG_MISC,LOG_WARN)("Unhandled VCPI-function %x in protected mode",reg_al); + break; + } + return CBRET_NONE; +} + +static Bitu V86_Monitor() { + /* Calculate which interrupt did occur */ + Bitu int_num=(mem_readw(SegPhys(ss)+(reg_esp & cpu.stack.mask))-0x2803); + + /* See if Exception 0x0d and not Interrupt 0x0d */ + if ((int_num==(0x0d*4)) && ((reg_sp&0xffff)!=0x1fda)) { + /* Protection violation during V86-execution, + needs intervention by monitor (depends on faulting opcode) */ + + reg_esp+=6; // skip ip of CALL and error code of EXCEPTION 0x0d + + /* Get adress of faulting instruction */ + Bit16u v86_cs=mem_readw(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask)); + Bit16u v86_ip=mem_readw(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask)); + Bit8u v86_opcode=mem_readb((v86_cs<<4)+v86_ip); +// LOG_MSG("v86 monitor caught protection violation at %x:%x, opcode=%x",v86_cs,v86_ip,v86_opcode); + switch (v86_opcode) { + case 0x0f: // double byte opcode + v86_opcode=mem_readb((v86_cs<<4)+v86_ip+1); + switch (v86_opcode) { + case 0x20: { // mov reg,CRx + Bitu rm_val=mem_readb((v86_cs<<4)+v86_ip+2); + Bitu which=(rm_val >> 3) & 7; + if ((rm_val<0xc0) || (rm_val>=0xe8)) + E_Exit("Invalid opcode 0x0f 0x20 %x caused a protection fault!",rm_val); + Bit32u crx=CPU_GET_CRX(which); + switch (rm_val&3) { + case 0: reg_eax=crx; break; + case 1: reg_ecx=crx; break; + case 2: reg_edx=crx; break; + case 3: reg_ebx=crx; break; + case 4: reg_esp=crx; break; + case 5: reg_ebp=crx; break; + case 6: reg_esi=crx; break; + case 7: reg_edi=crx; break; + } + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+3); + } + break; + case 0x22: { // mov CRx,reg + Bitu rm_val=mem_readb((v86_cs<<4)+v86_ip+2); + Bitu which=(rm_val >> 3) & 7; + if ((rm_val<0xc0) || (rm_val>=0xe8)) + E_Exit("Invalid opcode 0x0f 0x22 %x caused a protection fault!",rm_val); + Bit32u crx; + switch (rm_val&3) { + case 0: crx=reg_eax; break; + case 1: crx=reg_ecx; break; + case 2: crx=reg_edx; break; + case 3: crx=reg_ebx; break; + case 4: crx=reg_esp; break; + case 5: crx=reg_ebp; break; + case 6: crx=reg_esi; break; + case 7: crx=reg_edi; break; + } + if (which==0) crx|=1; // protection bit always on + CPU_SET_CRX(which,crx); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+3); + } + break; + default: + E_Exit("Unhandled opcode 0x0f %x caused a protection fault!",v86_opcode); + } + break; + case 0xe4: // IN AL,Ib + reg_al=IO_ReadB(mem_readb((v86_cs<<4)+v86_ip+1)); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2); + break; + case 0xe5: // IN AX,Ib + reg_ax=IO_ReadW(mem_readb((v86_cs<<4)+v86_ip+1)); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2); + break; + case 0xe6: // OUT Ib,AL + IO_WriteB(mem_readb((v86_cs<<4)+v86_ip+1),reg_al); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2); + break; + case 0xe7: // OUT Ib,AX + IO_WriteW(mem_readb((v86_cs<<4)+v86_ip+1),reg_ax); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+2); + break; + case 0xec: // IN AL,DX + reg_al=IO_ReadB(reg_dx); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1); + break; + case 0xed: // IN AX,DX + reg_ax=IO_ReadW(reg_dx); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1); + break; + case 0xee: // OUT DX,AL + IO_WriteB(reg_dx,reg_al); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1); + break; + case 0xef: // OUT DX,AX + IO_WriteW(reg_dx,reg_ax); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1); + break; + case 0xf0: // LOCK prefix + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1); + break; + case 0xf4: // HLT + reg_flags|=FLAG_IF; + CPU_HLT(reg_eip); + mem_writew(SegPhys(ss)+((reg_esp+0) & cpu.stack.mask),v86_ip+1); + break; + default: + E_Exit("Unhandled opcode %x caused a protection fault!",v86_opcode); + } + return CBRET_NONE; + } + + /* Get address to interrupt handler */ + Bit16u vint_vector_seg=mem_readw(SegValue(ds)+int_num+2); + Bit16u vint_vector_ofs=mem_readw(int_num); + if (reg_sp!=0x1fda) reg_esp+=(2+3*4); // Interrupt from within protected mode + else reg_esp+=2; + + /* Read entries that were pushed onto the stack by the interrupt */ + Bit16u return_ip=mem_readw(SegPhys(ss)+(reg_esp & cpu.stack.mask)); + Bit16u return_cs=mem_readw(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask)); + Bit32u return_eflags=mem_readd(SegPhys(ss)+((reg_esp+8) & cpu.stack.mask)); + + /* Modify stack to call v86-interrupt handler */ + mem_writed(SegPhys(ss)+(reg_esp & cpu.stack.mask),vint_vector_ofs); + mem_writed(SegPhys(ss)+((reg_esp+4) & cpu.stack.mask),vint_vector_seg); + mem_writed(SegPhys(ss)+((reg_esp+8) & cpu.stack.mask),return_eflags&(~(FLAG_IF|FLAG_TF))); + + /* Adjust SP of v86-stack */ + Bit16u v86_ss=mem_readw(SegPhys(ss)+((reg_esp+0x10) & cpu.stack.mask)); + Bit16u v86_sp=mem_readw(SegPhys(ss)+((reg_esp+0x0c) & cpu.stack.mask))-6; + mem_writew(SegPhys(ss)+((reg_esp+0x0c) & cpu.stack.mask),v86_sp); + + /* Return to original code after v86-interrupt handler */ + mem_writew((v86_ss<<4)+v86_sp+0,return_ip); + mem_writew((v86_ss<<4)+v86_sp+2,return_cs); + mem_writew((v86_ss<<4)+v86_sp+4,(Bit16u)(return_eflags&0xffff)); + return CBRET_NONE; +} + +static void SetupVCPI() { + vcpi.enabled=true; + + vcpi.pic1_remapping=0x08; // master PIC base + vcpi.pic2_remapping=0x70; // slave PIC base + + /* Allocate one EMS-page for private VCPI-data in memory beyond 1MB */ + EMM_AllocateMemory(1,vcpi.ems_handle); + vcpi.private_area=emm_handles[vcpi.ems_handle].mem<<12; + + /* GDT */ + mem_writed(vcpi.private_area+0x0000,0x00000000); // descriptor 0 + mem_writed(vcpi.private_area+0x0004,0x00000000); // descriptor 0 + + Bit32u ldt_address=(vcpi.private_area+0x1000); + Bit16u ldt_limit=0xff; + Bit32u ldt_desc_part=((ldt_address&0xffff)<<16)|ldt_limit; + mem_writed(vcpi.private_area+0x0008,ldt_desc_part); // descriptor 1 (LDT) + ldt_desc_part=((ldt_address&0xff0000)>>16)|(ldt_address&0xff000000)|0x8200; + mem_writed(vcpi.private_area+0x000c,ldt_desc_part); // descriptor 1 + + Bit32u tss_address=(vcpi.private_area+0x3000); + Bit32u tss_desc_part=((tss_address&0xffff)<<16)|(0x0068+0x200); + mem_writed(vcpi.private_area+0x0010,tss_desc_part); // descriptor 2 (TSS) + tss_desc_part=((tss_address&0xff0000)>>16)|(tss_address&0xff000000)|0x8900; + mem_writed(vcpi.private_area+0x0014,tss_desc_part); // descriptor 2 + + /* LDT */ + mem_writed(vcpi.private_area+0x1000,0x00000000); // descriptor 0 + mem_writed(vcpi.private_area+0x1004,0x00000000); // descriptor 0 + Bit32u cs_desc_part=((vcpi.private_area&0xffff)<<16)|0xffff; + mem_writed(vcpi.private_area+0x1008,cs_desc_part); // descriptor 1 (code) + cs_desc_part=((vcpi.private_area&0xff0000)>>16)|(vcpi.private_area&0xff000000)|0x9a00; + mem_writed(vcpi.private_area+0x100c,cs_desc_part); // descriptor 1 + Bit32u ds_desc_part=((vcpi.private_area&0xffff)<<16)|0xffff; + mem_writed(vcpi.private_area+0x1010,ds_desc_part); // descriptor 2 (data) + ds_desc_part=((vcpi.private_area&0xff0000)>>16)|(vcpi.private_area&0xff000000)|0x9200; + mem_writed(vcpi.private_area+0x1014,ds_desc_part); // descriptor 2 + + /* IDT setup */ + for (Bit16u int_ct=0; int_ct<0x100; int_ct++) { + /* build a CALL NEAR V86MON, the value of IP pushed by the + CALL is used to identify the interrupt number */ + mem_writeb(vcpi.private_area+0x2800+int_ct*4+0,0xe8); // call + mem_writew(vcpi.private_area+0x2800+int_ct*4+1,0x05fd-(int_ct*4)); + mem_writeb(vcpi.private_area+0x2800+int_ct*4+3,0xcf); // iret (dummy) + + /* put a Gate-Descriptor into the IDT */ + mem_writed(vcpi.private_area+0x2000+int_ct*8+0,0x000c0000|(0x2800+int_ct*4)); + mem_writed(vcpi.private_area+0x2000+int_ct*8+4,0x0000ee00); + } + + /* TSS */ + for (Bitu tse_ct=0; tse_ct<0x68+0x200; tse_ct++) { + /* clear the TSS as most entries are not used here */ + mem_writeb(vcpi.private_area+0x3000,0); + } + /* Set up the ring0-stack */ + mem_writed(vcpi.private_area+0x3004,0x00002000); // esp + mem_writed(vcpi.private_area+0x3008,0x00000014); // ss + + mem_writed(vcpi.private_area+0x3066,0x0068); // io-map base (map follows, all zero) +} + static Bitu INT4B_Handler() { switch (reg_ah) { case 0x81: @@ -607,40 +1050,149 @@ static Bitu INT4B_Handler() { return CBRET_NONE; } -void EMS_Init(Section* sec) { + +class EMS: public Module_base { +private: + /* location in protected unfreeable memory where the ems name and callback are + * stored 32 bytes.*/ + static Bit16u emsnameseg; + RealPt old4b_pointer,old67_pointer; + CALLBACK_HandlerObject call_vdma,int67,call_vcpi,call_v86mon; + +public: + EMS(Section* configuration):Module_base(configuration){ + /* Virtual DMA interrupt callback */ - call_vdma=CALLBACK_Allocate(); - CALLBACK_Setup(call_vdma,&INT4B_Handler,CB_IRET,"Int 4b vdma"); - RealSetVec(0x4b,CALLBACK_RealPointer(call_vdma)); + call_vdma.Install(&INT4B_Handler,CB_IRET,"Int 4b vdma"); + call_vdma.Set_RealVec(0x4b); - Section_prop * section=static_cast(sec); - if (!section->Get_bool("ems")) return; - BIOS_ZeroExtendedSize(); - call_int67=CALLBACK_Allocate(); - CALLBACK_Setup(call_int67,&INT67_Handler,CB_IRET,"Int 67 ems"); -/* Register the ems device */ - DOS_Device * newdev = new device_EMM(); - DOS_AddDevice(newdev); + vcpi.enabled=false; + + Section_prop * section=static_cast(configuration); + if (!section->Get_bool("ems")) return; + if (machine==MCH_PCJR) { + LOG_MSG("EMS disabled for PCJr machine"); + return; + } + BIOS_ZeroExtendedSize(true); + int67.Install(&INT67_Handler,CB_IRET,"Int 67 ems"); + Bit16u call_int67=int67.Get_callback(); -/* Add a little hack so it appears that there is an actual ems device installed */ - char * emsname="EMMXXXX0"; - Bit16u seg=DOS_GetMemory(2); //We have 32 bytes - MEM_BlockWrite(PhysMake(seg,0xa),emsname,strlen(emsname)+1); -/* Copy the callback piece into the beginning, and set the interrupt vector to it*/ - char buf[16]; - MEM_BlockRead(PhysMake(CB_SEG,call_int67<<4),buf,0xa); - MEM_BlockWrite(PhysMake(seg,0),buf,0xa); - RealSetVec(0x67,RealMake(seg,0)); -/* Clear handle and page tables */ - Bitu i; - for (i=0;i(m_configuration); + if (!section->Get_bool("ems")) return; + /* Undo Biosclearing */ + BIOS_ZeroExtendedSize(false); + + /* Remove ems device */ + device_EMM newdev; + DOS_DelDevice(&newdev); + + /* Remove the emsname and callback hack */ + char buf[32]= { 0 }; + MEM_BlockWrite(PhysMake(emsnameseg,0),buf,32); + RealSetVec(0x67,old67_pointer); + /* Clear handle and page tables */ + //TODO + + if (!ENABLE_VCPI) return; + + /* Free private data area in expanded memory */ + EMM_ReleaseMemory(vcpi.ems_handle); + + if (cpu.pmode && GETFLAG(VM)) { + /* Switch back to real mode if in v86-mode */ + CPU_SET_CRX(0, 0); + CPU_SET_CRX(3, 0); + reg_flags&=(~(FLAG_IOPL|FLAG_VM)); + CPU_LIDT(0x3ff, 0); + cpu.cpl=0; + } } +}; + +static EMS* test; + +void EMS_ShutDown(Section* sec) { + delete test; } +void EMS_Init(Section* sec) { + test = new EMS(sec); + sec->AddDestroyFunction(&EMS_ShutDown,true); +} + +//Initialize static members +Bit16u EMS::emsnameseg = 0; diff --git a/src/ints/int10.cpp b/src/ints/int10.cpp index 975d7ac..21749b2 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,18 +16,13 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include #include "dosbox.h" -#include "bios.h" #include "mem.h" #include "callback.h" #include "regs.h" -#include "video.h" #include "inout.h" #include "int10.h" #include "setup.h" -#include "support.h" -#include "vga.h" Int10Data int10; static Bitu call_10; @@ -51,6 +46,7 @@ static Bitu INT10_Handler(void) { break; } #endif + switch (reg_ah) { case 0x00: /* Set VideoMode */ INT10_SetVideoMode(reg_al); @@ -72,7 +68,7 @@ static Bitu INT10_Handler(void) { reg_ah=0; break; case 0x05: /* Set Active Page */ - if (reg_al & 0x80 && machine==MCH_TANDY) { + if (reg_al & 0x80 && IS_TANDY_ARCH) { Bit8u crtcpu=real_readb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE); switch (reg_al) { case 0x80: @@ -89,6 +85,11 @@ static Bitu INT10_Handler(void) { crtcpu=(crtcpu & 0xc0) | (reg_bh & 7) | ((reg_bl & 7) << 3); break; } + if (machine==MCH_PCJR) { + /* always return graphics mapping, even for invalid values of AL */ + reg_bh=crtcpu & 7; + reg_bl=(crtcpu >> 3) & 0x7; + } IO_WriteB(0x3df,crtcpu); real_writeb(BIOSMEM_SEG, BIOSMEM_CRTCPU_PAGE,crtcpu); } @@ -117,6 +118,12 @@ static Bitu INT10_Handler(void) { case 0x01: //Set color Select INT10_SetColorSelect(reg_bl); break; + default: + if ((machine==MCH_CGA) || (machine==MCH_PCJR)) { + /* those BIOSes check for !=0 */ + INT10_SetColorSelect(reg_bl); + } + break; } break; case 0x0C: /* Write Graphics Pixel */ @@ -130,7 +137,7 @@ static Bitu INT10_Handler(void) { break; case 0x0F: /* Get videomode */ reg_bh=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); - reg_al=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE); + reg_al=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)|(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL)&0x80); reg_ah=(Bit8u)real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS); break; case 0x10: /* EGA/VGA Palette functions */ @@ -177,6 +184,12 @@ static Bitu INT10_Handler(void) { case 0x19: /* undocumented - GET PEL MASK */ INT10_GetPelMask(reg_bl); break; + case 0x1A: /* GET VIDEO DAC COLOR PAGE */ + INT10_GetDACPage(®_bl,®_bh); + break; + case 0x1B: /* PERFORM GRAY-SCALE SUMMING */ + INT10_PerformGrayScaleSumming(reg_bx,reg_cx); + break; default: LOG(LOG_INT10,LOG_ERROR)("Function 10:Unhandled EGA/VGA Palette Function %2X",reg_al); } @@ -211,8 +224,10 @@ static Bitu INT10_Handler(void) { RealSetVec(0x43,int10.rom.font_14); real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,14); goto graphics_chars; -// case 0x23: /* Rom 8x8 double dot set */ - //TODO + case 0x23: /* Rom 8x8 double dot set */ + RealSetVec(0x43,int10.rom.font_8_first); + real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,8); + goto graphics_chars; case 0x24: /* Rom 8x16 set */ RealSetVec(0x43,int10.rom.font_16); real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,16); @@ -234,7 +249,6 @@ graphics_chars: RealPt int_1f=RealGetVec(0x1f); SegSet16(es,RealSeg(int_1f)); reg_bp=RealOff(int_1f); - reg_cx=8; } break; case 0x01: /* interupt 0x43 vector */ @@ -242,33 +256,28 @@ graphics_chars: RealPt int_43=RealGetVec(0x43); SegSet16(es,RealSeg(int_43)); reg_bp=RealOff(int_43); - reg_cx=8; } break; case 0x02: /* font 8x14 */ SegSet16(es,RealSeg(int10.rom.font_14)); reg_bp=RealOff(int10.rom.font_14); - reg_cx=14; break; case 0x03: /* font 8x8 first 128 */ SegSet16(es,RealSeg(int10.rom.font_8_first)); reg_bp=RealOff(int10.rom.font_8_first); - reg_cx=8; break; case 0x04: /* font 8x8 second 128 */ SegSet16(es,RealSeg(int10.rom.font_8_second)); reg_bp=RealOff(int10.rom.font_8_second); - reg_cx=8; break; case 0x06: /* font 8x16 */ SegSet16(es,RealSeg(int10.rom.font_16)); reg_bp=RealOff(int10.rom.font_16); - reg_cx=16; break; default: - reg_cx=16; - LOG(LOG_INT10,LOG_ERROR)("Fucntion 11:30 Request for font %2X",reg_bh); + LOG(LOG_INT10,LOG_ERROR)("Function 11:30 Request for font %2X",reg_bh); } + reg_cx=real_readw(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); reg_dl=real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS); break; default: @@ -279,12 +288,26 @@ graphics_chars: if (machinemode<0x8) mem_address>>=1; + if (machine==MCH_VGA && CurMode->mode<0x8) mem_address>>=1; /* Write the new start address in vgahardware */ Bit16u base=real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); IO_Write(base,0x0c); @@ -299,7 +297,7 @@ void INT10_SetActivePage(Bit8u page) { void INT10_SetCursorShape(Bit8u first,Bit8u last) { real_writew(BIOSMEM_SEG,BIOSMEM_CURSOR_TYPE,last|(first<<8)); if (machine==MCH_CGA) goto dowrite; - if (machine==MCH_TANDY) goto dowrite; + if (IS_TANDY_ARCH) goto dowrite; /* Skip CGA cursor emulation if EGA/VGA system is active */ if (!(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0x8)) { /* Check for CGA type 01, invisible */ @@ -309,11 +307,12 @@ void INT10_SetCursorShape(Bit8u first,Bit8u last) { goto dowrite; } /* Check if we need to convert CGA Bios cursor values */ - if (!(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0x1)) { + if (!(real_readb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL) & 0x1)) { // set by int10 fun12 sub34 // if (CurMode->mode>0x3) goto dowrite; //Only mode 0-3 are text modes on cga if ((first & 0xe0) || (last & 0xe0)) goto dowrite; Bit8u cheight=real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT)-1; /* Creative routine i based of the original ibmvga bios */ + if (last0xc) { - first--; + + if (cheight>0xc) { // vgatest sets 15 15 2x where only one should be decremented to 14 14 + first--; // implementing int10 fun12 sub34 fixed this. last--; } } @@ -369,21 +369,75 @@ void INT10_SetCursorPos(Bit8u row,Bit8u col,Bit8u page) { } } +void ReadCharAttr(Bit16u col,Bit16u row,Bit8u page,Bit16u * result) { + /* Externally used by the mouse routine */ + PhysPt fontdata; + Bitu x,y; + Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); + bool split_chr = false; + switch (CurMode->type) { + case M_TEXT: + { + // Compute the address + Bit16u address=page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); + address+=(row*real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)+col)*2; + // read the char + PhysPt where = CurMode->pstart+address; + *result=mem_readw(where); + } + return; + case M_CGA4: + case M_CGA2: + case M_TANDY16: + split_chr = true; + /* Fallthrough */ + default: /* EGA/VGA don't have a split font-table */ + for(Bit16u chr=0;chr <= 255 ;chr++) { + if (!split_chr || (chr<128)) fontdata = Real2Phys(RealGetVec(0x43))+chr*cheight; + else fontdata = Real2Phys(RealGetVec(0x1F))+(chr-128)*cheight; + x=8*col; + y=cheight*row; + bool error=false; + for (Bit8u h=0;h>=1; + } + y++; + if(bitline != vidline){ + /* It's not character 'chr', move on to the next */ + error = true; + break; + } + } + if(!error){ + /* We found it */ + *result = chr; + return; + } + } + LOG(LOG_INT10,LOG_ERROR)("ReadChar didn't find character"); + *result = 0; + break; + } +} void INT10_ReadCharAttr(Bit16u * result,Bit8u page) { if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); Bit8u cur_row=CURSOR_POS_ROW(page); Bit8u cur_col=CURSOR_POS_COL(page); - - // Compute the address - Bit16u address=page*real_readw(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE); - address+=(cur_row*real_readw(BIOSMEM_SEG,BIOSMEM_NB_COLS)+cur_col)*2; - // REad the char - PhysPt where = CurMode->pstart+address; - *result=mem_readw(where); + ReadCharAttr(cur_col,cur_row,page,result); } - -static void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u attr,bool useattr) { +void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u attr,bool useattr) { + /* Externally used by the mouse routine */ PhysPt fontdata; Bitu x,y; Bit8u cheight = real_readb(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT); @@ -414,9 +468,39 @@ static void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u attr,bool fontdata=Real2Phys(RealGetVec(0x43))+chr*cheight; break; } + + if(GCC_UNLIKELY(!useattr)) { //Set attribute(color) to a sensible value + static bool warned_use = false; + if(GCC_UNLIKELY(!warned_use)){ + LOG(LOG_INT10,LOG_ERROR)("writechar used without attribute in non-textmode"); + warned_use = true; + } + switch(CurMode->type) { + case M_CGA4: + case M_CGA2: + attr = 0x1; + break; + case M_TANDY16: + case M_EGA: + default: + attr = 0xf; + break; + } + } + + //Some weird behavior of mode 6 (and 11) + if ((CurMode->mode == 0x6)/* || (CurMode->mode==0x11)*/) attr = (attr&0x80)|1; + //(same fix for 11 fixes vgatest2, but it's not entirely correct according to wd) + x=8*col; y=cheight*row;Bit8u xor_mask=(CurMode->type == M_VGA) ? 0x0 : 0x80; //TODO Check for out of bounds + if (CurMode->type==M_EGA) { + /* enable all planes for EGA modes (Ultima 1 colour bug) */ + /* might be put into INT10_PutPixel but different vga bios + implementations have different opinions about this */ + IO_Write(0x3c4,0x2);IO_Write(0x3c5,0xf); + } for (Bit8u h=0;htype!=M_TEXT) page=0xff; - if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); + if (CurMode->type!=M_TEXT) { + switch (machine) { + case MCH_VGA: + page%=CurMode->ptotal; + break; + case MCH_CGA: + case MCH_PCJR: + page=0; + break; + } + } + Bit8u cur_row=CURSOR_POS_ROW(page); Bit8u cur_col=CURSOR_POS_COL(page); BIOS_NCOLS;BIOS_NROWS; @@ -449,9 +542,7 @@ void INT10_WriteChar(Bit8u chr,Bit8u attr,Bit8u page,Bit16u count,bool showattr) } } -void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) { - //TODO Check if this page thing is correct - Bit8u page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); +static INLINE void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr,Bit8u page) { BIOS_NCOLS;BIOS_NROWS; Bit8u cur_row=CURSOR_POS_ROW(page); Bit8u cur_col=CURSOR_POS_COL(page); @@ -466,12 +557,12 @@ void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) { cur_col=0; break; case '\n': - cur_col=0; +// cur_col=0; //Seems to break an old chess game cur_row++; break; case '\t': do { - INT10_TeletypeOutputAttr(' ',attr,useattr); + INT10_TeletypeOutputAttr(' ',attr,useattr,page); cur_row=CURSOR_POS_ROW(page); cur_col=CURSOR_POS_COL(page); } while(cur_col%8); @@ -487,22 +578,24 @@ void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) { } // Do we need to scroll ? if(cur_row==nrows) { - INT10_ScrollWindow(0,0,nrows-1,ncols-1,-1,0x07,page); + //Fill with black on non-text modes and with 0x7 on textmode + Bit8u fill = (CurMode->type == M_TEXT)?0x7:0; + INT10_ScrollWindow(0,0,nrows-1,ncols-1,-1,fill,page); cur_row--; } - // Set the cursor for the page + // Set the cursor for the page INT10_SetCursorPos(cur_row,cur_col,page); } +void INT10_TeletypeOutputAttr(Bit8u chr,Bit8u attr,bool useattr) { + INT10_TeletypeOutputAttr(chr,attr,useattr,real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)); +} + void INT10_TeletypeOutput(Bit8u chr,Bit8u attr) { INT10_TeletypeOutputAttr(chr,attr,CurMode->type!=M_TEXT); } void INT10_WriteString(Bit8u row,Bit8u col,Bit8u flag,Bit8u attr,PhysPt string,Bit16u count,Bit8u page) { - //TODO Check if this page thing is correct - if (CurMode->type!=M_TEXT) page=0xff; - - if(page==0xFF) page=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE); BIOS_NCOLS;BIOS_NROWS; Bit8u cur_row=CURSOR_POS_ROW(page); Bit8u cur_col=CURSOR_POS_COL(page); @@ -520,11 +613,10 @@ void INT10_WriteString(Bit8u row,Bit8u col,Bit8u flag,Bit8u attr,PhysPt string,B attr=mem_readb(string); string++; }; - INT10_TeletypeOutputAttr(chr,attr,true); + INT10_TeletypeOutputAttr(chr,attr,true,page); count--; } if (!(flag&1)) { INT10_SetCursorPos(cur_row,cur_col,page); } } - diff --git a/src/ints/int10_memory.cpp b/src/ints/int10_memory.cpp index 2a78806..7079e45 100644 --- a/src/ints/int10_memory.cpp +++ b/src/ints/int10_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -72,17 +72,21 @@ void INT10_LoadFont(PhysPt font,bool reload,Bitu count,Bitu offset,Bitu map,Bitu } } - - - +static Bitu checksumlocation = 0; //Same type as int10.rom.used void INT10_SetupRomMemory(void) { /* This should fill up certain structures inside the Video Bios Rom Area */ PhysPt rom_base=PhysMake(0xc000,0); Bitu i; - int10.rom.used=3; // int10.rom.used=2; Size of ROM added + int10.rom.used=3; if (machine==MCH_VGA) { + // set up the start of the ROM phys_writew(rom_base+0,0xaa55); - phys_writeb(rom_base+2,0x40); // Size of ROM: 64 512-blocks = 32KB + phys_writeb(rom_base+2,0x40); // Size of ROM: 64 512-blocks = 32KB + phys_writeb(rom_base+0x1e,0x49); // IBM string + phys_writeb(rom_base+0x1f,0x42); + phys_writeb(rom_base+0x20,0x4d); + phys_writeb(rom_base+0x21,0x00); + int10.rom.used=0x100; } int10.rom.font_8_first=RealMake(0xC000,int10.rom.used); for (i=0;i<128*8;i++) { @@ -108,9 +112,24 @@ void INT10_SetupRomMemory(void) { phys_writeb(PhysMake(0xf000,0xfa6e)+i,int10_font_08[i]); } RealSetVec(0x1F,int10.rom.font_8_second); + + if (machine == MCH_VGA) { //EGA/VGA. Just to be safe + //Reserve checksum location + checksumlocation = int10.rom.used++; + } }; - +void INT10_SetupRomMemoryChecksum(void) { + if (machine == MCH_VGA) { //EGA/VGA. Just to be safe + /* Sum of all bytes in rom module 256 should be 0 */ + Bit8u sum = 0; + PhysPt rom_base = PhysMake(0xc000,0); + for (Bitu i = 0;i < 32 * 1024;i++) //32 KB romsize + sum += phys_readb(rom_base + i); //OVERFLOW IS OKAY + sum = 256 - sum; + phys_writeb(rom_base + checksumlocation,sum); + } +} Bit8u int10_font_08[256 * 8] = { diff --git a/src/ints/int10_misc.cpp b/src/ints/int10_misc.cpp index 99f0e25..9bce3d6 100644 --- a/src/ints/int10_misc.cpp +++ b/src/ints/int10_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -82,7 +82,8 @@ void INT10_GetFuncStateInformation(PhysPt save) { mem_writeb(save+0x4+i,real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE+i)); } /* Second area */ - for (i=0;i<3;i++) { + mem_writeb(save+0x22,real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS)+1); + for (i=1;i<3;i++) { mem_writeb(save+0x22+i,real_readb(BIOSMEM_SEG,BIOSMEM_NB_ROWS+i)); } /* Zero out rest of block */ @@ -92,13 +93,17 @@ void INT10_GetFuncStateInformation(PhysPt save) { Bit16u col_count=0; switch (CurMode->type) { case M_TEXT: - col_count=16;break; + if (CurMode->mode==0x7) col_count=1; else col_count=16;break; case M_CGA2: col_count=2;break; case M_CGA4: col_count=4;break; - case M_EGA16: - col_count=16;break; + case M_EGA: + if (CurMode->mode==0x11 || CurMode->mode==0x0f) + col_count=2; + else + col_count=16; + break; case M_VGA: col_count=256;break; default: @@ -119,8 +124,171 @@ void INT10_GetFuncStateInformation(PhysPt save) { case 480: mem_writeb(save+0x2a,3);break; }; - //TODO Maybe misc flags + /* misc flags */ + if (CurMode->type==M_TEXT) mem_writeb(save+0x2d,0x21); + else mem_writeb(save+0x2d,0x01); /* Video Memory available */ mem_writeb(save+0x31,3); } +RealPt INT10_EGA_RIL_GetVersionPt(void) { + /* points to a graphics ROM location at the moment + as checks test for bx!=0 only */ + return RealMake(0xc000,0x30); +} + +static void EGA_RIL(Bit16u dx, Bitu& port, Bitu& regs) { + port = 0; + regs = 0; //if nul is returned it's a single register port + switch(dx) { + case 0x00: /* CRT Controller (25 reg) 3B4h mono modes, 3D4h color modes */ + port = real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS); + regs = 25; + break; + case 0x08: /* Sequencer (5 registers) 3C4h */ + port = 0x3C4; + regs = 5; + break; + case 0x10: /* Graphics Controller (9 registers) 3CEh */ + port = 0x3CE; + regs = 9; + break; + case 0x18: /* Attribute Controller (20 registers) 3C0h */ + port = 0x3c0; + regs = 20; + break; + case 0x20: /* Miscellaneous Output register 3C2h */ + port = 0x3C2; + break; + case 0x28: /* Feature Control register (3BAh mono modes, 3DAh color modes) */ + port = real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6; + break; + case 0x30: /* Graphics 1 Position register 3CCh */ + port = 0x3CC; + break; + case 0x38: /* Graphics 2 Position register 3CAh */ + port = 0x3CA; + break; + default: + LOG(LOG_INT10,LOG_ERROR)("unknown RIL port selection %X",dx); + break; + } +} + +void INT10_EGA_RIL_ReadRegister(Bit8u & bl, Bit16u dx) { + Bitu port = 0; + Bitu regs = 0; + EGA_RIL(dx,port,regs); + if(regs == 0) { + if(port) bl = IO_Read(port); + } else { + if(port == 0x3c0) IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6); + IO_Write(port,bl); + bl = IO_Read(port+1); + if(port == 0x3c0) IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6); + LOG(LOG_INT10,LOG_NORMAL)("EGA RIL read used with multi-reg"); + } +} + +void INT10_EGA_RIL_WriteRegister(Bit8u & bl, Bit8u bh, Bit16u dx) { + Bitu port = 0; + Bitu regs = 0; + EGA_RIL(dx,port,regs); + if(regs == 0) { + if(port) IO_Write(port,bl); + } else { + if(port == 0x3c0) { + IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6); + IO_Write(port,bl); + IO_Write(port,bh); + } else { + IO_Write(port,bl); + IO_Write(port+1,bh); + } + bl = bh;//Not sure + LOG(LOG_INT10,LOG_NORMAL)("EGA RIL write used with multi-reg"); + } +} + +void INT10_EGA_RIL_ReadRegisterRange(Bit8u & bl, Bit8u ch, Bit8u cl, Bit16u dx, PhysPt dst) { + Bitu port = 0; + Bitu regs = 0; + EGA_RIL(dx,port,regs); + if(regs == 0) { + LOG(LOG_INT10,LOG_ERROR)("EGA RIL range read with port %x called",port); + } else { + if(chregs) cl=regs-ch; + for (Bitu i=0; iregs) cl=regs-ch; + if(port == 0x3c0) { + IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6); + for (Bitu i=0; i #include "dosbox.h" @@ -9,6 +27,7 @@ #define _EGA_HALF_CLOCK 0x0001 #define _EGA_LINE_DOUBLE 0x0002 +#define _VGA_PIXEL_DOUBLE 0x0004 #define SEQ_REGS 0x05 #define GFX_REGS 0x09 @@ -16,32 +35,69 @@ VideoModeBlock ModeList_VGA[]={ /* mode ,type ,sw ,sh ,tw ,th ,cw,ch ,pt,pstart ,plength,htot,vtot,hde,vde special flags */ -{ 0x000 ,M_TEXT ,320 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK }, -{ 0x001 ,M_TEXT ,320 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK }, -{ 0x002 ,M_TEXT ,640 ,400 ,80 ,25 ,9 ,16 ,4 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0 }, -{ 0x003 ,M_TEXT ,640 ,400 ,80 ,25 ,9 ,16 ,4 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0 }, -{ 0x004 ,M_CGA4 ,320 ,200 ,40 ,25 ,8 ,8 ,4 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE}, -{ 0x005 ,M_CGA4 ,320 ,200 ,40 ,25 ,8 ,8 ,4 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE}, -{ 0x006 ,M_CGA2 ,640 ,200 ,80 ,25 ,8 ,8 ,4 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE }, -{ 0x007 ,M_TEXT ,640 ,400 ,80 ,25 ,9 ,16 ,4 ,0xB0000 ,0x1000 ,100 ,449 ,80 ,400 ,0 }, +{ 0x000 ,M_TEXT ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK }, +{ 0x001 ,M_TEXT ,360 ,400 ,40 ,25 ,9 ,16 ,8 ,0xB8000 ,0x0800 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK }, +{ 0x002 ,M_TEXT ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0 }, +{ 0x003 ,M_TEXT ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB8000 ,0x1000 ,100 ,449 ,80 ,400 ,0 }, +{ 0x004 ,M_CGA4 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xB8000 ,0x4000 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE}, +{ 0x005 ,M_CGA4 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xB8000 ,0x4000 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE}, +{ 0x006 ,M_CGA2 ,640 ,200 ,80 ,25 ,8 ,8 ,1 ,0xB8000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE}, +{ 0x007 ,M_TEXT ,720 ,400 ,80 ,25 ,9 ,16 ,8 ,0xB0000 ,0x1000 ,100 ,449 ,80 ,400 ,0 }, -{ 0x00D ,M_EGA16 ,320 ,200 ,40 ,25 ,8 ,8 ,8 ,0xA0000 ,0x2000 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE }, -{ 0x00E ,M_EGA16 ,640 ,200 ,80 ,25 ,8 ,8 ,4 ,0xA0000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE }, -{ 0x00F ,M_EGA16 ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,400 ,0 },/*was EGA_2*/ -{ 0x010 ,M_EGA16 ,640 ,350 ,80 ,25 ,8 ,14 ,1 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0 }, -{ 0x011 ,M_EGA16 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0 },/*was EGA_2 */ -{ 0x012 ,M_EGA16 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0 }, -{ 0x013 ,M_VGA ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x0000 ,100 ,449 ,80 ,400 ,0 }, -{ 0x054 ,M_TEXT ,1056 ,688, 132,43, 8, 8, 1 ,0xB8000 ,0x4000, 192, 800, 132, 688, 0 }, -{ 0x055 ,M_TEXT ,1056 ,400, 132,25, 8, 16, 1 ,0xB8000 ,0x2000, 192, 449, 132, 400, 0 }, +{ 0x00D ,M_EGA ,320 ,200 ,40 ,25 ,8 ,8 ,8 ,0xA0000 ,0x2000 ,50 ,449 ,40 ,400 ,_EGA_HALF_CLOCK | _EGA_LINE_DOUBLE }, +{ 0x00E ,M_EGA ,640 ,200 ,80 ,25 ,8 ,8 ,4 ,0xA0000 ,0x4000 ,100 ,449 ,80 ,400 ,_EGA_LINE_DOUBLE }, +{ 0x00F ,M_EGA ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0 },/*was EGA_2*/ +{ 0x010 ,M_EGA ,640 ,350 ,80 ,25 ,8 ,14 ,2 ,0xA0000 ,0x8000 ,100 ,449 ,80 ,350 ,0 }, +{ 0x011 ,M_EGA ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0 },/*was EGA_2 */ +{ 0x012 ,M_EGA ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0xA000 ,100 ,525 ,80 ,480 ,0 }, +{ 0x013 ,M_VGA ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x2000 ,100 ,449 ,80 ,400 ,0 }, + +{ 0x054 ,M_TEXT ,1056,688, 132,43, 8, 8, 1 ,0xB8000 ,0x4000, 192, 800, 132,688, 0 }, +{ 0x055 ,M_TEXT ,1056,400, 132,25, 8, 16, 1 ,0xB8000 ,0x2000, 192, 449, 132,400, 0 }, + +/* Follow vesa 1.2 for first 0x20 */ { 0x100 ,M_LIN8 ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 ,0 }, { 0x101 ,M_LIN8 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0 }, +{ 0x102 ,M_LIN4 ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0 }, { 0x103 ,M_LIN8 ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0 }, +{ 0x104 ,M_LIN4 ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,150 ,800 ,128,768 ,0 }, +{ 0x105 ,M_LIN8 ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,150 ,800 ,128,768 ,0 }, + +{ 0x10D ,M_LIN15 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x10E ,M_LIN16 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x10F ,M_LIN32 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x110 ,M_LIN15 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0 }, +{ 0x111 ,M_LIN16 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0 }, +{ 0x112 ,M_LIN32 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0 }, +{ 0x113 ,M_LIN15 ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0 }, +{ 0x114 ,M_LIN16 ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0 }, +{ 0x115 ,M_LIN32 ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0 }, + +{ 0x116 ,M_LIN15 ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,150 ,800 ,128,768 ,0 }, +{ 0x117 ,M_LIN16 ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,150 ,800 ,128,768 ,0 }, +{ 0x118 ,M_LIN32 ,1024,768 ,128,48 ,8 ,16 ,1 ,0xA0000 ,0x10000,150 ,800 ,128,768 ,0 }, + + +{ 0x150 ,M_LIN8 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x151 ,M_LIN8 ,320 ,240 ,40 ,30 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x152 ,M_LIN8 ,320 ,400 ,40 ,50 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE }, +{ 0x153 ,M_LIN8 ,320 ,480 ,40 ,60 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE }, + +{ 0x160 ,M_LIN15 ,320 ,240 ,40 ,30 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x161 ,M_LIN15 ,320 ,400 ,40 ,50 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE }, +{ 0x162 ,M_LIN15 ,320 ,480 ,40 ,60 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE }, +{ 0x165 ,M_LIN15 ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 ,0 }, + +{ 0x170 ,M_LIN16 ,320 ,240 ,40 ,30 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x171 ,M_LIN16 ,320 ,400 ,40 ,50 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE }, +{ 0x172 ,M_LIN16 ,320 ,480 ,40 ,60 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE }, +{ 0x175 ,M_LIN16 ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 ,0 }, + +{ 0x190 ,M_LIN32 ,320 ,240 ,40 ,30 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE | _EGA_LINE_DOUBLE }, +{ 0x191 ,M_LIN32 ,320 ,400 ,40 ,50 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _VGA_PIXEL_DOUBLE }, +{ 0x192 ,M_LIN32 ,320 ,480 ,40 ,60 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _VGA_PIXEL_DOUBLE }, +{ 0x195 ,M_LIN32 ,640 ,400 ,80 ,25 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 ,0 }, -{ 0x150 ,M_LIN8 ,320 ,200 ,40 ,25 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , _EGA_LINE_DOUBLE }, -{ 0x151 ,M_LIN8 ,320 ,240 ,40 ,30 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , _EGA_LINE_DOUBLE }, -{ 0x152 ,M_LIN8 ,320 ,400 ,40 ,50 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,449 ,80 ,400 , 0 }, -{ 0x153 ,M_LIN8 ,320 ,480 ,40 ,60 ,8 ,8 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 , 0 }, {0xFFFF ,M_ERROR ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0x00000 ,0x0000 ,0 ,0 ,0 ,0 ,0 }, }; @@ -76,6 +132,18 @@ static Bit8u text_palette[64][3]= {0x15,0x15,0x15},{0x15,0x15,0x3f},{0x15,0x3f,0x15},{0x15,0x3f,0x3f},{0x3f,0x15,0x15},{0x3f,0x15,0x3f},{0x3f,0x3f,0x15},{0x3f,0x3f,0x3f} }; +static Bit8u mtext_palette[64][3]= +{ + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, + 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, 0x2a,0x2a,0x2a, + 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f, 0x3f,0x3f,0x3f +}; + static Bit8u ega_palette[64][3]= { {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a}, @@ -88,11 +156,24 @@ static Bit8u ega_palette[64][3]= {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f} }; -static Bit8u cga_palette[16][3]= { +static Bit8u cga_palette[16][3]= +{ {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a}, {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f}, }; +static Bit8u cga_palette_2[64][3]= +{ + {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a}, + {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a}, + {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f}, + {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f}, + {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a}, + {0x00,0x00,0x00}, {0x00,0x00,0x2a}, {0x00,0x2a,0x00}, {0x00,0x2a,0x2a}, {0x2a,0x00,0x00}, {0x2a,0x00,0x2a}, {0x2a,0x15,0x00}, {0x2a,0x2a,0x2a}, + {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f}, + {0x15,0x15,0x15}, {0x15,0x15,0x3f}, {0x15,0x3f,0x15}, {0x15,0x3f,0x3f}, {0x3f,0x15,0x15}, {0x3f,0x15,0x3f}, {0x3f,0x3f,0x15}, {0x3f,0x3f,0x3f}, +}; + static Bit8u vga_palette[256][3]= { {0x00,0x00,0x00},{0x00,0x00,0x2a},{0x00,0x2a,0x00},{0x00,0x2a,0x2a},{0x2a,0x00,0x00},{0x2a,0x00,0x2a},{0x2a,0x15,0x00},{0x2a,0x2a,0x2a}, @@ -131,7 +212,6 @@ static Bit8u vga_palette[256][3]= {0x0b,0x10,0x0b},{0x0b,0x10,0x0c},{0x0b,0x10,0x0d},{0x0b,0x10,0x0f},{0x0b,0x10,0x10},{0x0b,0x0f,0x10},{0x0b,0x0d,0x10},{0x0b,0x0c,0x10}, {0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00},{0x00,0x00,0x00} }; - VideoModeBlock * CurMode; static bool SetCurMode(VideoModeBlock modeblock[],Bitu mode) { @@ -154,6 +234,7 @@ static void FinishSetMode(bool clearmem) { switch (CurMode->type) { case M_CGA4: case M_CGA2: + case M_TANDY16: for (i=0;i<16*1024;i++) { real_writew(0xb800,i*2,0x0000); } @@ -165,9 +246,13 @@ static void FinishSetMode(bool clearmem) { real_writew(0xb800,i*2,0x0720); } break; - case M_EGA16: + case M_EGA: case M_VGA: case M_LIN8: + case M_LIN4: + case M_LIN15: + case M_LIN16: + case M_LIN32: /* Hack we just acess the memory directly */ memset(&vga.mem,0,sizeof(vga.mem)); } @@ -177,10 +262,10 @@ static void FinishSetMode(bool clearmem) { else real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE,CurMode->mode-0x98); //Looks like the s3 bios real_writew(BIOSMEM_SEG,BIOSMEM_NB_COLS,CurMode->twidth); real_writew(BIOSMEM_SEG,BIOSMEM_PAGE_SIZE,CurMode->plength); - real_writew(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,CurMode->mode==7 ? 0x3b4 : 0x3d4); + real_writew(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS,((CurMode->mode==7 )|| (CurMode->mode==0x0f)) ? 0x3b4 : 0x3d4); real_writeb(BIOSMEM_SEG,BIOSMEM_NB_ROWS,CurMode->theight-1); real_writew(BIOSMEM_SEG,BIOSMEM_CHAR_HEIGHT,CurMode->cheight); - real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem << 7))); + real_writeb(BIOSMEM_SEG,BIOSMEM_VIDEO_CTL,(0x60|(clearmem?0:0x80))); real_writeb(BIOSMEM_SEG,BIOSMEM_SWITCHES,0x09); real_writeb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL,real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL)&0x7f); @@ -212,7 +297,7 @@ bool INT10_SetVideoMode_OTHER(Bitu mode,bool clearmem) { switch (machine) { case MCH_CGA: if (mode>6) return false; - case MCH_TANDY: + case TANDY_ARCH_CASE: if (mode>0xa) return false; if (!SetCurMode(ModeList_OTHER,mode)) { LOG(LOG_INT10,LOG_ERROR)("Trying to set illegal mode %X",mode); @@ -255,9 +340,11 @@ bool INT10_SetVideoMode_OTHER(Bitu mode,bool clearmem) { break; case M_CGA2: scanline=2; + break; case M_CGA4: if (CurMode->mode!=0xa) scanline=2; else scanline=4; + break; case M_TANDY16: if (CurMode->mode!=0x9) scanline=2; else scanline=4; @@ -271,9 +358,14 @@ bool INT10_SetVideoMode_OTHER(Bitu mode,bool clearmem) { //Setup the special registers for each machine type Bit8u mode_control_list[0xa+1]={ 0x2c,0x28,0x2d,0x29, //0-3 - 0x2a,0x2e,0x1e,0x29, //4-7 + 0x2a,0x2e,0x16,0x29, //4-7 0x2a,0x2b,0x3b //8-a }; + Bit8u mode_control_list_pcjr[0xa+1]={ + 0x0c,0x08,0x0d,0x09, //0-3 + 0x0a,0x0e,0x0e,0x09, //4-7 + 0x1a,0x1b,0x0b //8-a + }; Bit8u mode_control,color_select; switch (machine) { case MCH_HERC: @@ -294,7 +386,7 @@ bool INT10_SetVideoMode_OTHER(Bitu mode,bool clearmem) { case MCH_TANDY: /* Init some registers */ IO_WriteB(0x3da,0x1);IO_WriteB(0x3de,0xf); //Palette mask always 0xf - IO_WriteB(0x3da,0x2);IO_WriteB(0x3de,0x0); //block border + IO_WriteB(0x3da,0x2);IO_WriteB(0x3de,0x0); //black border IO_WriteB(0x3da,0x3); //Tandy color overrides? switch (CurMode->mode) { case 0x8: @@ -317,6 +409,32 @@ bool INT10_SetVideoMode_OTHER(Bitu mode,bool clearmem) { real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,mode_control); real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select); break; + case MCH_PCJR: + /* Init some registers */ + IO_ReadB(0x3da); + IO_WriteB(0x3da,0x1);IO_WriteB(0x3da,0xf); //Palette mask always 0xf + IO_WriteB(0x3da,0x2);IO_WriteB(0x3da,0x0); //black border + IO_WriteB(0x3da,0x3); + if (CurMode->mode<=0x04) IO_WriteB(0x3da,0x02); + else if (CurMode->mode==0x06) IO_WriteB(0x3da,0x08); + else IO_WriteB(0x3da,0x00); + + /* set CRT/Processor page register */ + if (CurMode->mode<0x04) crtpage=0x3f; + else if (CurMode->mode>=0x09) crtpage=0xf6; + else crtpage=0x7f; + IO_WriteB(0x3df,crtpage); + real_writeb(BIOSMEM_SEG,BIOSMEM_CRTCPU_PAGE,crtpage); + + mode_control=mode_control_list_pcjr[CurMode->mode]; + IO_WriteB(0x3da,0x0);IO_WriteB(0x3da,mode_control); + real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,mode_control); + + if (CurMode->mode == 0x6 || CurMode->mode==0xa) color_select=0x3f; + else color_select=0x30; + IO_WriteB(0x3d9,color_select); + real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,color_select); + break; } FinishSetMode(clearmem); return true; @@ -325,13 +443,18 @@ bool INT10_SetVideoMode_OTHER(Bitu mode,bool clearmem) { bool INT10_SetVideoMode(Bitu mode) { bool clearmem=true;Bitu i; - if ((mode<256) && (mode & 128)) { + if (mode>=0x100) { + if (mode & 0x8000) clearmem=false; + mode&=0xfff; + } + if ((mode<0x100) && (mode & 0x80)) { clearmem=false; - mode-=128; + mode-=0x80; } LOG(LOG_INT10,LOG_NORMAL)("Set Video Mode %X",mode); if (machine!=MCH_VGA) return INT10_SetVideoMode_OTHER(mode,clearmem); Bit8u modeset_ctl,video_ctl,vga_switches; + if (!SetCurMode(ModeList_VGA,mode)){ LOG(LOG_INT10,LOG_ERROR)("Trying to set illegal mode %X",mode); return false; @@ -345,28 +468,52 @@ bool INT10_SetVideoMode(Bitu mode) { /* Setup the VGA to the correct mode */ Bit16u crtc_base; - bool mono_mode=(mode == 7); + bool mono_mode=(mode == 7) || (mode==0xf); if (mono_mode) crtc_base=0x3b4; else crtc_base=0x3d4; + /* Setup MISC Output Register */ Bit8u misc_output=0x2 | (mono_mode ? 0x0 : 0x1); + + switch (CurMode->vdispend) { + case 400: + misc_output|=0x60; + if (CurMode->type==M_TEXT) // && (CurMode->pstart==0xB8000)) + misc_output|=0x4; + break; + case 480: + misc_output|=0xe0; + break; + case 350: + misc_output|=0xa0; + break; + default: + misc_output|=0x60; + } IO_Write(0x3c2,misc_output); //Setup for 3b4 or 3d4 + /* Program Sequencer */ Bit8u seq_data[SEQ_REGS]; memset(seq_data,0,SEQ_REGS); - seq_data[1]|=1; //8 dot fonts by default - seq_data[1]|= //Check for half clock - (CurMode->special & _EGA_HALF_CLOCK) ? 0x08 : 0x00; + if (CurMode->cwidth==8) seq_data[1]|=1; //8 dot fonts by default + if (CurMode->special & _EGA_HALF_CLOCK) seq_data[1]|=0x08; //Check for half clock seq_data[4]|=0x02; //More than 64kb switch (CurMode->type) { case M_TEXT: seq_data[2]|=0x3; //Enable plane 0 and 1 seq_data[4]|=0x05; //Alpanumeric and odd/even enabled break; - case M_EGA16: + case M_CGA2: + seq_data[2]|=0xf; //Enable plane 0 + break; + case M_LIN4: + case M_EGA: seq_data[2]|=0xf; //Enable all planes for writing break; case M_LIN8: //Seems to have the same reg layout from testing + case M_LIN15: + case M_LIN16: + case M_LIN32: case M_VGA: seq_data[2]|=0xf; //Enable all planes for writing seq_data[4]|=0xc; //Graphics - odd/even - Chained @@ -376,6 +523,8 @@ bool INT10_SetVideoMode(Bitu mode) { IO_Write(0x3c4,i); IO_Write(0x3c5,seq_data[i]); } + vga.config.compatible_chain4 = true; // this may be changed by SVGA chipset emulation + /* Program CRTC */ /* First disable write protection */ IO_Write(crtc_base,0x11); @@ -396,41 +545,53 @@ bool INT10_SetVideoMode(Bitu mode) { IO_Write(crtc_base,0x02);IO_Write(crtc_base+1,CurMode->hdispend); hor_overflow|=((CurMode->hdispend) & 0x100) >> 6; /* End horizontal Blanking */ - Bitu blank_end; - if (CurMode->special & _EGA_HALF_CLOCK) { - blank_end = (CurMode->htotal-1) & 0x7f; - } else { - blank_end = (CurMode->htotal-2) & 0x7f; - } + Bitu blank_end=(CurMode->htotal-2) & 0x7f; IO_Write(crtc_base,0x03);IO_Write(crtc_base+1,0x80|(blank_end & 0x1f)); + /* Start Horizontal Retrace */ Bitu ret_start; - if (CurMode->special & _EGA_HALF_CLOCK) ret_start = (CurMode->hdispend+2); + if ((CurMode->special & _EGA_HALF_CLOCK) && (CurMode->type!=M_CGA2)) ret_start = (CurMode->hdispend+3); + else if (CurMode->type==M_TEXT) ret_start = (CurMode->hdispend+5); else ret_start = (CurMode->hdispend+4); IO_Write(crtc_base,0x04);IO_Write(crtc_base+1,ret_start); hor_overflow|=(ret_start & 0x100) >> 4; + /* End Horizontal Retrace */ Bitu ret_end; - if (CurMode->special & _EGA_HALF_CLOCK) ret_end = (CurMode->htotal-2) & 0x3f; - else ret_end = (CurMode->htotal-4) & 0x3f; - IO_Write(crtc_base,0x05);IO_Write(crtc_base+1,(ret_end & 0x1f) | (blank_end & 0x20) << 2); + if (CurMode->special & _EGA_HALF_CLOCK) { + if (CurMode->type==M_CGA2) ret_end=0; // mode 6 + else if (CurMode->special & _EGA_LINE_DOUBLE) ret_end = (CurMode->htotal-18) & 0x1f; + else ret_end = ((CurMode->htotal-18) & 0x1f) | 0x20; // mode 0&1 have 1 char sync delay + } else if (CurMode->type==M_TEXT) ret_end = (CurMode->htotal-3) & 0x1f; + else ret_end = (CurMode->htotal-4) & 0x1f; + + IO_Write(crtc_base,0x05);IO_Write(crtc_base+1,ret_end | (blank_end & 0x20) << 2); + /* Vertical Total */ IO_Write(crtc_base,0x06);IO_Write(crtc_base+1,(CurMode->vtotal-2)); overflow|=((CurMode->vtotal-2) & 0x100) >> 8; overflow|=((CurMode->vtotal-2) & 0x200) >> 4; ver_overflow|=((CurMode->vtotal-2) & 0x400) >> 10; -/* - These aren't exactly accurate i think, - Should be more like a certain percentage based on vertical total - So you get same sized borders, but okay :) - */ + + Bitu vretrace; + switch (CurMode->vdispend) { + case 400: vretrace=CurMode->vdispend+12; + break; + case 480: vretrace=CurMode->vdispend+10; + break; + case 350: vretrace=CurMode->vdispend+37; + break; + default: vretrace=CurMode->vdispend+12; + } + /* Vertical Retrace Start */ - IO_Write(crtc_base,0x10);IO_Write(crtc_base+1,(CurMode->vdispend+12)); - overflow|=((CurMode->vdispend+12) & 0x100) >> 6; - overflow|=((CurMode->vdispend+12) & 0x200) >> 2; - ver_overflow|=((CurMode->vdispend+12) & 0x400) >> 6; + IO_Write(crtc_base,0x10);IO_Write(crtc_base+1,vretrace); + overflow|=(vretrace & 0x100) >> 6; + overflow|=(vretrace & 0x200) >> 2; + ver_overflow|=(vretrace & 0x400) >> 6; + /* Vertical Retrace End */ - IO_Write(crtc_base,0x11);IO_Write(crtc_base+1,(CurMode->vdispend+14) & 0xF); + IO_Write(crtc_base,0x11);IO_Write(crtc_base+1,(vretrace+2) & 0xF); /* Vertical Display End */ IO_Write(crtc_base,0x12);IO_Write(crtc_base+1,(CurMode->vdispend-1)); @@ -438,13 +599,26 @@ bool INT10_SetVideoMode(Bitu mode) { overflow|=((CurMode->vdispend-1) & 0x200) >> 3; ver_overflow|=((CurMode->vdispend-1) & 0x400) >> 9; + Bitu vblank_trim; + switch (CurMode->vdispend) { + case 400: vblank_trim=6; + break; + case 480: vblank_trim=7; + break; + case 350: vblank_trim=5; + break; + default: vblank_trim=8; + } + /* Vertical Blank Start */ - IO_Write(crtc_base,0x15);IO_Write(crtc_base+1,(CurMode->vdispend+8)); - overflow|=((CurMode->vdispend+8) & 0x100) >> 5; - max_scanline|=((CurMode->vdispend+8) & 0x200) >> 4; - ver_overflow|=((CurMode->vdispend+8) & 0x400) >> 8; - /* Vertical Retrace End */ - IO_Write(crtc_base,0x16);IO_Write(crtc_base+1,(CurMode->vtotal-8)); + IO_Write(crtc_base,0x15);IO_Write(crtc_base+1,(CurMode->vdispend+vblank_trim)); + overflow|=((CurMode->vdispend+vblank_trim) & 0x100) >> 5; + max_scanline|=((CurMode->vdispend+vblank_trim) & 0x200) >> 4; + ver_overflow|=((CurMode->vdispend+vblank_trim) & 0x400) >> 8; + + /* Vertical Blank End */ + IO_Write(crtc_base,0x16);IO_Write(crtc_base+1,(CurMode->vtotal-vblank_trim-2)); + /* Line Compare */ Bitu line_compare=(CurMode->vtotal < 1024) ? 1023 : 2047; IO_Write(crtc_base,0x18);IO_Write(crtc_base+1,line_compare&0xff); @@ -457,19 +631,25 @@ bool INT10_SetVideoMode(Bitu mode) { switch (CurMode->type) { case M_TEXT: max_scanline|=CurMode->cheight-1; - underline=0x1f; + underline=mono_mode ? 0x0f : 0x1f; // mode 7 uses a diff underline position break; case M_VGA: underline=0x40; max_scanline|=1; //Vga doesn't use double line but this break; case M_LIN8: + case M_LIN15: + case M_LIN16: + case M_LIN32: underline=0x60; //Seems to enable the every 4th clock on my s3 break; + case M_CGA2: case M_CGA4: max_scanline|=1; break; } + if (CurMode->vdispend==350) underline=0x0f; + IO_Write(crtc_base,0x09);IO_Write(crtc_base+1,max_scanline); IO_Write(crtc_base,0x14);IO_Write(crtc_base+1,underline); @@ -480,32 +660,59 @@ bool INT10_SetVideoMode(Bitu mode) { /* Extended Vertical Overflow */ IO_Write(crtc_base,0x5e);IO_Write(crtc_base+1,ver_overflow); /* Offset Register */ - IO_Write(crtc_base,0x13); + Bitu offset; switch (CurMode->type) { case M_LIN8: - IO_Write(crtc_base+1,CurMode->swidth/8); + offset = CurMode->swidth/8; + break; + case M_LIN15: + case M_LIN16: + offset = 2 * CurMode->swidth/8; + break; + case M_LIN32: + offset = 4 * CurMode->swidth/8; break; default: - IO_Write(crtc_base+1,CurMode->hdispend/2); + offset = CurMode->hdispend/2; } + IO_Write(crtc_base,0x13); + IO_Write(crtc_base + 1,offset & 0xff); + /* Extended System Control 2 Register */ + /* This register actually has more bits but only use the extended offset ones */ + IO_Write(crtc_base,0x51); + IO_Write(crtc_base + 1,(offset & 0x300) >> 4); + /* Extended Vertical Overflow */ + IO_Write(crtc_base,0x5e);IO_Write(crtc_base+1,ver_overflow); + /* Mode Control */ Bit8u mode_control=0; + switch (CurMode->type) { - case M_CGA4: case M_CGA2: + mode_control=0xc2; // 0x06 sets address wrap. + break; + case M_CGA4: mode_control=0xa2; break; - case M_EGA16: + case M_LIN4: + case M_EGA: + if (CurMode->mode==0x11) // 0x11 also sets address wrap. thought maybe all 2 color modes did but 0x0f doesn't. + mode_control=0xc3; // so.. 0x11 or 0x0f a one off? + else mode_control=0xe3; break; case M_TEXT: case M_VGA: - mode_control=0xa3; - break; case M_LIN8: - mode_control=0xab; + case M_LIN15: + case M_LIN16: + case M_LIN32: + mode_control=0xa3; + if (CurMode->special & _VGA_PIXEL_DOUBLE) + mode_control |= 0x08; break; } + IO_Write(crtc_base,0x17);IO_Write(crtc_base+1,mode_control); /* Renable write protection */ IO_Write(crtc_base,0x11); @@ -520,14 +727,24 @@ bool INT10_SetVideoMode(Bitu mode) { /* Setup Pixel format */ switch (CurMode->type) { case M_LIN8: - if (CurMode->swidth < 640) misc_control_2=0x0; //Use single pixel mode,M_VGA then - else misc_control_2=0x10; + /* This should be 0x0 according to the specs but makes it easier to detect + compared to normal vga modes now */ + misc_control_2=0x10; + break; + case M_LIN15: + misc_control_2=0x30; + break; + case M_LIN16: + misc_control_2=0x50; + break; + case M_LIN32: + misc_control_2=0xd0; break; default: misc_control_2=0x0; break; } - IO_WriteB(0x3d4,0x67);IO_WriteB(0x3d5,misc_control_2); + IO_WriteB(crtc_base,0x67);IO_WriteB(crtc_base+1,misc_control_2); /* Write Misc Output */ IO_Write(0x3c2,misc_output); /* Program Graphics controller */ @@ -541,17 +758,20 @@ bool INT10_SetVideoMode(Bitu mode) { gfx_data[0x6]|=mono_mode ? 0x0a : 0x0e; //Either b800 or b000 break; case M_LIN8: + case M_LIN15: + case M_LIN16: + case M_LIN32: case M_VGA: gfx_data[0x5]|=0x40; //256 color mode gfx_data[0x6]|=0x05; //graphics mode at 0xa000-affff break; - case M_EGA16: + case M_LIN4: + case M_EGA: gfx_data[0x6]|=0x05; //graphics mode at 0xa000-affff break; - case M_CGA2: case M_CGA4: - case M_TANDY16: gfx_data[0x5]|=0x20; //CGA mode + case M_CGA2: gfx_data[0x6]|=0x0f; //graphics mode at at 0xb800=0xbfff break; } @@ -564,12 +784,29 @@ bool INT10_SetVideoMode(Bitu mode) { att_data[0x12]=0xf; //Always have all color planes enabled /* Program Attribute Controller */ switch (CurMode->type) { - case M_EGA16: + case M_LIN4: + case M_EGA: att_data[0x10]=0x01; //Color Graphics - if (CurMode->mode>0xe) goto att_text16; + switch (CurMode->mode) { + case 0x0f: + att_data[0x10]|=0x0a; //Monochrome + att_data[0x01]=0x08; + att_data[0x04]=0x18; + att_data[0x05]=0x18; + att_data[0x09]=0x08; + att_data[0x0d]=0x18; + break; + case 0x11: + for (i=1;i<16;i++) att_data[i]=0x3f; + break; + case 0x10: + case 0x12: goto att_text16; + default: for (i=0;i<8;i++) { - att_data[i]=i; - att_data[i+8]=i+0x10; + att_data[i]=i; + att_data[i+8]=i+0x10; + } + break; } break; case M_TANDY16: @@ -579,6 +816,7 @@ bool INT10_SetVideoMode(Bitu mode) { case M_TEXT: att_data[0x13]=0x08; //Pel panning on 8, although we don't have 9 dot text mode att_data[0x10]=0x0C; //Color Text with blinking + real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x30); att_text16: for (i=0;i<8;i++) { att_data[i]=i; @@ -589,20 +827,27 @@ att_text16: case M_CGA2: att_data[0x10]=0x01; //Color Graphics att_data[0]=0x0; - att_data[1]=0xf; + for (i=1;i<0x10;i++) att_data[i]=0x17; att_data[0x12]=0x1; //Only enable 1 plane real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x3f); break; case M_CGA4: att_data[0x10]=0x01; //Color Graphics att_data[0]=0x0; - att_data[1]=0x3; - att_data[2]=0x5; - att_data[3]=0x7; + att_data[1]=0x13; + att_data[2]=0x15; + att_data[3]=0x17; + att_data[4]=0x02; + att_data[5]=0x04; + att_data[6]=0x06; + att_data[7]=0x07; + for (i=0x8;i<0x10;i++) + att_data[i] = i + 0x8; real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,0x30); break; case M_VGA: case M_LIN8: + case M_LIN16: for (i=0;i<16;i++) att_data[i]=i; att_data[0x10]=0x41; //Color Graphics 8-bit break; @@ -612,11 +857,13 @@ att_text16: IO_Write(0x3c0,i); IO_Write(0x3c0,att_data[i]); } + IO_Write(0x3c0,0x20); IO_Write(0x3c0,0x00); //Disable palette access /* Setup the DAC */ IO_Write(0x3c8,0); switch (CurMode->type) { - case M_EGA16: - if (CurMode->mode>0xe) goto dac_text16; + case M_EGA: + if (CurMode->mode>0xf) goto dac_text16; + else if (CurMode->mode==0xf) goto dac_mtext16; for (i=0;i<64;i++) { IO_Write(0x3c9,ega_palette[i][0]); IO_Write(0x3c9,ega_palette[i][1]); @@ -626,13 +873,22 @@ att_text16: case M_CGA2: case M_CGA4: case M_TANDY16: - for (i=0;i<16;i++) { - IO_Write(0x3c9,cga_palette[i][0]); - IO_Write(0x3c9,cga_palette[i][1]); - IO_Write(0x3c9,cga_palette[i][2]); + for (i=0;i<64;i++) { + IO_Write(0x3c9,cga_palette_2[i][0]); + IO_Write(0x3c9,cga_palette_2[i][1]); + IO_Write(0x3c9,cga_palette_2[i][2]); } break; case M_TEXT: + if (CurMode->mode==7) { +dac_mtext16: + for (i=0;i<64;i++) { + IO_Write(0x3c9,mtext_palette[i][0]); + IO_Write(0x3c9,mtext_palette[i][1]); + IO_Write(0x3c9,mtext_palette[i][2]); + } + break; + } dac_text16: for (i=0;i<64;i++) { IO_Write(0x3c9,text_palette[i][0]); @@ -642,6 +898,7 @@ dac_text16: break; case M_VGA: case M_LIN8: + case M_LIN16: for (i=0;i<256;i++) { IO_Write(0x3c9,vga_palette[i][0]); IO_Write(0x3c9,vga_palette[i][1]); @@ -649,30 +906,45 @@ dac_text16: } break; } + if (machine==MCH_VGA) { + /* check if gray scale summing is enabled */ + if (real_readb(BIOSMEM_SEG,BIOSMEM_MODESET_CTL) & 2) { + INT10_PerformGrayScaleSumming(0,256); + } + } /* Setup some special stuff for different modes */ Bit8u feature=real_readb(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE); switch (CurMode->type) { case M_CGA2: feature=(feature&~0x30)|0x20; - real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x12); + real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x1e); break; case M_CGA4: feature=(feature&~0x30)|0x20; - real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2); + if (CurMode->mode==4) real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2a); + else if (CurMode->mode==5) real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2e); + else real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2); break; case M_TANDY16: feature=(feature&~0x30)|0x20; break; case M_TEXT: feature=(feature&~0x30)|0x20; + switch (CurMode->mode) { + case 0:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2c);break; + case 1:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x28);break; + case 2:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x2d);break; + case 3:real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR,0x29);break; + } break; - case M_EGA16: + case M_LIN4: + case M_EGA: case M_VGA: feature=(feature&~0x30); break; - } - real_writeb(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE,feature); + // disabled, has to be set in bios.cpp exclusively +// real_writeb(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE,feature); /* Setup the CPU Window */ IO_Write(crtc_base,0x6a); IO_Write(crtc_base+1,0); @@ -681,10 +953,24 @@ dac_text16: IO_Write(crtc_base+1,(Bit8u)(S3_LFB_BASE >> 24)); IO_Write(crtc_base,0x5a); IO_Write(crtc_base+1,(Bit8u)(S3_LFB_BASE >> 16)); - /* Setup some remaining S3 registers */ - IO_Write(crtc_base,0x31);IO_Write(crtc_base+1,0x9); //Enable banked memory and 256k+ access + Bitu reg_31; + switch (CurMode->type) { + case M_LIN4: + case M_LIN8: + case M_LIN15: + case M_LIN16: + case M_LIN32: + reg_31 = 9; + break; + default: + reg_31 = 0; + break; + } + IO_Write(crtc_base,0x31);IO_Write(crtc_base+1,reg_31); //Enable banked memory and 256k+ access + IO_Write(crtc_base,0x58);IO_Write(crtc_base+1,0x3); //Enable 8 mb of linear addressing IO_Write(crtc_base,0x58);IO_Write(crtc_base+1,0x3); //Enable 8 mb of linear addressing + IO_Write(crtc_base,0x38);IO_Write(crtc_base+1,0x48); //Register lock 1 IO_Write(crtc_base,0x39);IO_Write(crtc_base+1,0xa5); //Register lock 2 @@ -695,6 +981,3 @@ dac_text16: } return true; } - - - diff --git a/src/ints/int10_pal.cpp b/src/ints/int10_pal.cpp index 44cdf0a..62f4398 100644 --- a/src/ints/int10_pal.cpp +++ b/src/ints/int10_pal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -23,48 +23,80 @@ #define ACTL_MAX_REG 0x14 +static INLINE void ResetACTL(void) { + IO_Read(real_readw(BIOSMEM_SEG,BIOSMEM_CRTC_ADDRESS) + 6); +} + +static INLINE void WriteTandyACTL(Bit8u creg,Bit8u val) { + IO_Write(VGAREG_TDY_ADDRESS,creg); + if (machine==MCH_TANDY) IO_Write(VGAREG_TDY_DATA,val); + else IO_Write(VGAREG_PCJR_DATA,val); +} + void INT10_SetSinglePaletteRegister(Bit8u reg,Bit8u val) { - if(reg<=ACTL_MAX_REG) { - IO_Read(VGAREG_ACTL_RESET); - IO_Write(VGAREG_ACTL_ADDRESS,reg); - IO_Write(VGAREG_ACTL_WRITE_DATA,val); + switch (machine) { + case TANDY_ARCH_CASE: + IO_Read(VGAREG_TDY_RESET); + WriteTandyACTL(reg+0x10,val); + break; + case MCH_VGA: + if(reg<=ACTL_MAX_REG) { + ResetACTL(); + IO_Write(VGAREG_ACTL_ADDRESS,reg); + IO_Write(VGAREG_ACTL_WRITE_DATA,val); + } + IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette + break; } - IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette } void INT10_SetOverscanBorderColor(Bit8u val) { - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); IO_Write(VGAREG_ACTL_ADDRESS,0x11); IO_Write(VGAREG_ACTL_WRITE_DATA,val); IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette } void INT10_SetAllPaletteRegisters(PhysPt data) { - IO_Read(VGAREG_ACTL_RESET); - // First the colors - for(Bit8u i=0;i<0x10;i++) { - IO_Write(VGAREG_ACTL_ADDRESS,i); + switch (machine) { + case TANDY_ARCH_CASE: + IO_Read(VGAREG_TDY_RESET); + // First the colors + for(Bit8u i=0;i<0x10;i++) { + WriteTandyACTL(i+0x10,mem_readb(data)); + data++; + } + // Then the border + WriteTandyACTL(0x02,mem_readb(data)); + break; + case MCH_VGA: + ResetACTL(); + // First the colors + for(Bit8u i=0;i<0x10;i++) { + IO_Write(VGAREG_ACTL_ADDRESS,i); + IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data)); + data++; + } + // Then the border + IO_Write(VGAREG_ACTL_ADDRESS,0x11); IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data)); - data++; + IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette + break; } - // Then the border - IO_Write(VGAREG_ACTL_ADDRESS,0x11); - IO_Write(VGAREG_ACTL_WRITE_DATA,mem_readb(data)); - IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette } void INT10_ToggleBlinkingBit(Bit8u state) { Bit8u value; state&=0x01; - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); IO_Write(VGAREG_ACTL_ADDRESS,0x10); value=IO_Read(VGAREG_ACTL_READ_DATA); value&=0xf7; value|=state<<3; - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); IO_Write(VGAREG_ACTL_ADDRESS,0x10); IO_Write(VGAREG_ACTL_WRITE_DATA,value); IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette @@ -72,29 +104,33 @@ void INT10_ToggleBlinkingBit(Bit8u state) { void INT10_GetSinglePaletteRegister(Bit8u reg,Bit8u * val) { if(reg<=ACTL_MAX_REG) { - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); IO_Write(VGAREG_ACTL_ADDRESS,reg+32); *val=IO_Read(VGAREG_ACTL_READ_DATA); + IO_Write(VGAREG_ACTL_WRITE_DATA,*val); } } void INT10_GetOverscanBorderColor(Bit8u * val) { - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); IO_Write(VGAREG_ACTL_ADDRESS,0x11+32); *val=IO_Read(VGAREG_ACTL_READ_DATA); + IO_Write(VGAREG_ACTL_WRITE_DATA,*val); } void INT10_GetAllPaletteRegisters(PhysPt data) { - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); // First the colors for(Bit8u i=0;i<0x10;i++) { IO_Write(VGAREG_ACTL_ADDRESS,i); mem_writeb(data,IO_Read(VGAREG_ACTL_READ_DATA)); + ResetACTL(); data++; } // Then the border IO_Write(VGAREG_ACTL_ADDRESS,0x11+32); mem_writeb(data,IO_Read(VGAREG_ACTL_READ_DATA)); + ResetACTL(); } void INT10_SetSingleDacRegister(Bit8u index,Bit8u red,Bit8u green,Bit8u blue) { @@ -121,7 +157,7 @@ void INT10_SetDACBlock(Bit16u index,Bit16u count,PhysPt data) { } void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data) { - IO_Write(VGAREG_DAC_WRITE_ADDRESS,(Bit8u)index); + IO_Write(VGAREG_DAC_READ_ADDRESS,(Bit8u)index); for (;count>0;count--) { mem_writeb(data++,IO_Read(VGAREG_DAC_DATA)); mem_writeb(data++,IO_Read(VGAREG_DAC_DATA)); @@ -130,15 +166,16 @@ void INT10_GetDACBlock(Bit16u index,Bit16u count,PhysPt data) { } void INT10_SelectDACPage(Bit8u function,Bit8u mode) { - IO_Read(VGAREG_ACTL_RESET); + ResetACTL(); IO_Write(VGAREG_ACTL_ADDRESS,0x10); Bit8u old10=IO_Read(VGAREG_ACTL_READ_DATA); if (!function) { //Select paging mode if (mode) old10|=0x80; else old10&=0x7f; - IO_Write(VGAREG_ACTL_ADDRESS,0x10); + //IO_Write(VGAREG_ACTL_ADDRESS,0x10); IO_Write(VGAREG_ACTL_WRITE_DATA,old10); } else { //Select page + IO_Write(VGAREG_ACTL_WRITE_DATA,old10); if (!(old10 & 0x80)) mode<<=2; mode&=0xf; IO_Write(VGAREG_ACTL_ADDRESS,0x14); @@ -147,6 +184,23 @@ void INT10_SelectDACPage(Bit8u function,Bit8u mode) { IO_Write(VGAREG_ACTL_ADDRESS,32); //Enable output and protect palette } +void INT10_GetDACPage(Bit8u* mode,Bit8u* page) { + ResetACTL(); + IO_Write(VGAREG_ACTL_ADDRESS,0x10); + Bit8u reg10=IO_Read(VGAREG_ACTL_READ_DATA); + IO_Write(VGAREG_ACTL_WRITE_DATA,reg10); + *mode=(reg10&0x80)?0x01:0x00; + IO_Write(VGAREG_ACTL_ADDRESS,0x14); + *page=IO_Read(VGAREG_ACTL_READ_DATA); + IO_Write(VGAREG_ACTL_WRITE_DATA,*page); + if(*mode) { + *page&=0xf; + } else { + *page&=0xc; + *page>>=2; + } +} + void INT10_SetPelMask(Bit8u mask) { IO_Write(VGAREG_PEL_MASK,mask); } @@ -159,13 +213,52 @@ void INT10_SetBackgroundBorder(Bit8u val) { Bitu temp=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); temp=(temp & 0xe0) | (val & 0x1f); real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,temp); - IO_Write(0x3d9,temp); + if (machine == MCH_CGA || IS_TANDY_ARCH) + IO_Write(0x3d9,temp); + else if (machine == MCH_VGA) { + val = ((val << 1) & 0x10) | (val & 0x7); + /* Aways set the overscan color */ + INT10_SetSinglePaletteRegister( 0x11, val ); + /* Don't set any extra colors when in text mode */ + if (CurMode->mode <= 3) + return; + INT10_SetSinglePaletteRegister( 0, val ); + val = (temp & 0x10) | 2 | ((temp & 0x20) >> 5); + INT10_SetSinglePaletteRegister( 1, val ); + val+=2; + INT10_SetSinglePaletteRegister( 2, val ); + val+=2; + INT10_SetSinglePaletteRegister( 3, val ); + } } void INT10_SetColorSelect(Bit8u val) { Bitu temp=real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL); temp=(temp & 0xdf) | ((val & 1) ? 0x20 : 0x0); real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAL,temp); - IO_Write(0x3d9,temp); + if (machine == MCH_CGA || IS_TANDY_ARCH) + IO_Write(0x3d9,temp); + else if (machine == MCH_VGA) { + val = (temp & 0x10) | 2 | val; + INT10_SetSinglePaletteRegister( 1, val ); + val+=2; + INT10_SetSinglePaletteRegister( 2, val ); + val+=2; + INT10_SetSinglePaletteRegister( 3, val ); + } } +void INT10_PerformGrayScaleSumming(Bit16u start_reg,Bit16u count) { + if (count>0x100) count=0x100; + for (Bitu ct=0; ct> 8; + Bit8u ic=(i>0x3f) ? 0x3f : ((Bit8u)(i & 0xff)); + INT10_SetSingleDacRegister(start_reg+ct,ic,ic,ic); + } +} diff --git a/src/ints/int10_put_pixel.cpp b/src/ints/int10_put_pixel.cpp index 13c5bfe..93db017 100644 --- a/src/ints/int10_put_pixel.cpp +++ b/src/ints/int10_put_pixel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -28,16 +28,31 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { switch (CurMode->type) { case M_CGA4: { - Bit16u off=(y>>1)*80+(x>>2); - if (y&1) off+=8*1024; - Bit8u old=real_readb(0xb800,off); - if (color & 0x80) { - color&=3; - old^=color << (2*(3-(x&3))); + if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_MODE)<=5) { + Bit16u off=(y>>1)*80+(x>>2); + if (y&1) off+=8*1024; + + Bit8u old=real_readb(0xb800,off); + if (color & 0x80) { + color&=3; + old^=color << (2*(3-(x&3))); + } else { + old=old&cga_masks[x&3]|((color&3) << (2*(3-(x&3)))); + } + real_writeb(0xb800,off,old); } else { - old=old&cga_masks[x&3]|((color&3) << (2*(3-(x&3)))); + Bit16u off=(y>>2)*160+((x>>2)&(~1)); + off+=(8*1024) * (y & 3); + + Bit16u old=real_readw(0xb800,off); + if (color & 0x80) { + old^=(color&1) << (7-(x&7)); + old^=((color&2)>>1) << ((7-(x&7))+8); + } else { + old=old&(~(0x101<<(7-(x&7)))) | ((color&1) << (7-(x&7))) | (((color&2)>>1) << ((7-(x&7))+8)); + } + real_writew(0xb800,off,old); } - real_writeb(0xb800,off,old); } break; case M_CGA2: @@ -56,8 +71,10 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { break; case M_TANDY16: { - Bit16u off=(y>>2)*160+(x>>1); - off+=(8*1024) * (y & 3); + IO_Write(0x3d4,0x09); + Bit8u scanlines_m1=IO_Read(0x3d5); + Bit16u off=(y>>((scanlines_m1==1)?1:2))*(CurMode->swidth>>1)+(x>>1); + off+=(8*1024) * (y & scanlines_m1); Bit8u old=real_readb(0xb800,off); Bit8u p[2]; p[1] = (old >> 4) & 0xf; @@ -65,7 +82,7 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { Bitu ind = 1-(x & 0x1); if (color & 0x80) { - p[ind]^=color; + p[ind]^=(color & 0x7f); } else { p[ind]=color; } @@ -73,7 +90,7 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { real_writeb(0xb800,off,old); } break; - case M_EGA16: + case M_EGA: { /* Set the correct bitmask for the pixel position */ IO_Write(0x3ce,0x8);Bit8u mask=128>>(x&7);IO_Write(0x3cf,mask); @@ -100,6 +117,11 @@ void INT10_PutPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u color) { case M_VGA: mem_writeb(PhysMake(0xa000,y*320+x),color); break; + case M_LIN8: { + PhysPt off=S3_LFB_BASE+y*CurMode->swidth+x; + mem_writeb(off,color); + break; + } default: LOG(LOG_INT10,LOG_ERROR)("PutPixel unhandled mode type %d",CurMode->type); break; @@ -124,7 +146,7 @@ void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color) { *color=(val>>(((7-x&7)))) & 1 ; } break; - case M_EGA16: + case M_EGA: { /* Calculate where the pixel is in video memory */ PhysPt off=0xa0000+CurMode->plength*page+((y*CurMode->swidth+x)>>3); @@ -144,6 +166,11 @@ void INT10_GetPixel(Bit16u x,Bit16u y,Bit8u page,Bit8u * color) { case M_VGA: *color=mem_readb(PhysMake(0xa000,320*y+x)); break; + case M_LIN8: { + PhysPt off=S3_LFB_BASE+y*CurMode->swidth+x; + *color = mem_readb(off); + break; + } default: LOG(LOG_INT10,LOG_ERROR)("GetPixel unhandled mode type %d",CurMode->type); break; diff --git a/src/ints/int10_vesa.cpp b/src/ints/int10_vesa.cpp index 41fea05..086076f 100644 --- a/src/ints/int10_vesa.cpp +++ b/src/ints/int10_vesa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: int10_vesa.cpp,v 1.12 2004/09/10 22:09:54 harekiet Exp $ */ +/* $Id: int10_vesa.cpp,v 1.23 2006/02/12 23:06:15 harekiet Exp $ */ #include #include @@ -31,6 +31,9 @@ static struct { Bitu setwindow; + Bitu pmStart; + Bitu pmWindow; + Bitu pmPalette; } callback; static char string_oem[]="S3 Incorporated. Trio64"; @@ -87,7 +90,8 @@ Bit8u VESA_GetSVGAInformation(Bit16u seg,Bit16u off) { PhysPt buffer=PhysMake(seg,off); Bitu i; bool vbe2=false;Bit16u vbe2_pos=256+off; - if (mem_readd(buffer)==0x32454256) vbe2=true; + Bitu id=mem_readd(buffer); + if ((id==0x56424532)||(id==0x32454256)) vbe2=true; if (vbe2) { for (i=0;i<0x200;i++) mem_writeb(buffer+i,0); } else { @@ -95,8 +99,8 @@ Bit8u VESA_GetSVGAInformation(Bit16u seg,Bit16u off) { } /* Fill common data */ MEM_BlockWrite(buffer,(void *)"VESA",4); //Identification + mem_writew(buffer+0x04,0x200); //Vesa version 0x200 if (vbe2) { - mem_writew(buffer+0x04,0x200); //Vesa version 0x200 mem_writed(buffer+0x06,RealMake(seg,vbe2_pos)); for (i=0;itype) { - case M_LIN8: //Linear 8-bit - WLE(minfo.ModeAttributes,0x9b); - WLE(minfo.WinAAttributes,0x7); //Exists/readable/writable - WLE(minfo.WinGranularity,64); - WLE(minfo.WinSize,64); - WLE(minfo.WinASegment,0xa000); -// WLE(minfo.WinBSegment,0xa000); - WLE(minfo.WinFuncPtr,CALLBACK_RealPointer(callback.setwindow)); - WLE(minfo.BytesPerScanLine,mblock->swidth); - WLE(minfo.NumberOfPlanes,0x1); - WLE(minfo.BitsPerPixel,0x08); - WLE(minfo.NumberOfBanks,0x1); - WLE(minfo.MemoryModel,0x04); //packed pixel - WLE(minfo.NumberOfImagePages,0x05); - WLE(minfo.Reserved_page,0x1); + case M_LIN4: + pageSize = mblock->sheight * mblock->swidth/2; + pageSize = (pageSize | 15) & ~ 15; + var_write(&minfo.NumberOfImagePages,(512*1024 / pageSize)-1); + var_write(&minfo.BytesPerScanLine,mblock->swidth/8); + var_write(&minfo.BitsPerPixel,4); + var_write(&minfo.MemoryModel,3); //ega planar mode + var_write(&minfo.ModeAttributes,0x1b); //Color, graphics, no linear buffer break; + case M_LIN8: + pageSize = mblock->sheight * mblock->swidth; + pageSize = (pageSize | 15) & ~ 15; + var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); + var_write(&minfo.BytesPerScanLine,mblock->swidth); + var_write(&minfo.BitsPerPixel,8); + var_write(&minfo.MemoryModel,4); //packed pixel + var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer + break; + case M_LIN15: + pageSize = mblock->sheight * mblock->swidth*2; + pageSize = (pageSize | 15) & ~ 15; + var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); + var_write(&minfo.BytesPerScanLine,mblock->swidth*2); + var_write(&minfo.BitsPerPixel,15); + var_write(&minfo.MemoryModel,6); //HiColour + var_write(&minfo.RedMaskSize,5); + var_write(&minfo.RedMaskPos,10); + var_write(&minfo.GreenMaskSize,5); + var_write(&minfo.GreenMaskPos,5); + var_write(&minfo.BlueMaskSize,5); + var_write(&minfo.BlueMaskPos,0); + var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer + break; + case M_LIN16: + pageSize = mblock->sheight * mblock->swidth*2; + pageSize = (pageSize | 15) & ~ 15; + var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); + var_write(&minfo.BytesPerScanLine,mblock->swidth*2); + var_write(&minfo.BitsPerPixel,16); + var_write(&minfo.MemoryModel,6); //HiColour + var_write(&minfo.RedMaskSize,5); + var_write(&minfo.RedMaskPos,11); + var_write(&minfo.GreenMaskSize,6); + var_write(&minfo.GreenMaskPos,5); + var_write(&minfo.BlueMaskSize,5); + var_write(&minfo.BlueMaskPos,0); + var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer + break; + case M_LIN32: + pageSize = mblock->sheight * mblock->swidth*4; + pageSize = (pageSize | 15) & ~ 15; + var_write(&minfo.NumberOfImagePages,(2*1024*1024 / pageSize)-1); + var_write(&minfo.BytesPerScanLine,mblock->swidth*4); + var_write(&minfo.BitsPerPixel,32); + var_write(&minfo.MemoryModel,6); //HiColour + var_write(&minfo.RedMaskSize,8); + var_write(&minfo.RedMaskPos,0x10); + var_write(&minfo.GreenMaskSize,0x8); + var_write(&minfo.GreenMaskPos,0x8); + var_write(&minfo.BlueMaskSize,0x8); + var_write(&minfo.BlueMaskPos,0x0); + var_write(&minfo.ReservedMaskSize,0x8); + var_write(&minfo.ReservedMaskPos,0x18); + var_write(&minfo.ModeAttributes,0x9b); //Color, graphics, linear buffer + break; + default: + return 0x1; } - WLE(minfo.XResolution,mblock->swidth); - WLE(minfo.YResolution,mblock->sheight); - WLE(minfo.XCharSize,mblock->cwidth); - WLE(minfo.YCharSize,mblock->cheight); - WLE(minfo.PhysBasePtr,S3_LFB_BASE); + var_write(&minfo.WinAAttributes,0x7); //Exists/readable/writable + var_write(&minfo.WinGranularity,64); + var_write(&minfo.WinSize,64); + var_write(&minfo.WinASegment,0xa000); + var_write(&minfo.WinFuncPtr,CALLBACK_RealPointer(callback.setwindow)); + var_write(&minfo.NumberOfPlanes,0x1); + var_write(&minfo.NumberOfBanks,0x1); + var_write(&minfo.Reserved_page,0x1); + var_write(&minfo.XResolution,mblock->swidth); + var_write(&minfo.YResolution,mblock->sheight); + var_write(&minfo.XCharSize,mblock->cwidth); + var_write(&minfo.YCharSize,mblock->cheight); + var_write(&minfo.PhysBasePtr,S3_LFB_BASE); MEM_BlockWrite(buf,&minfo,sizeof(MODE_INFO)); return 0x00; @@ -161,7 +223,7 @@ foundit: Bit8u VESA_SetSVGAMode(Bit16u mode) { - if (INT10_SetVideoMode(mode & 0xfff)) return 0x00; + if (INT10_SetVideoMode(mode)) return 0x00; return 0x01; }; @@ -188,14 +250,19 @@ Bit8u VESA_GetCPUWindow(Bit8u window,Bit16u & address) { Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count) { +//Structure is (vesa 3.0 doc): blue,green,red,alignment + Bit8u r,g,b; if (index>255) return 0x1; if (index+count>256) return 0x1; IO_Write(0x3c8,index); while (count) { - IO_Write(0x3c9,mem_readb(data++)); - IO_Write(0x3c9,mem_readb(data++)); - IO_Write(0x3c9,mem_readb(data++)); + b = mem_readb(data++); + g = mem_readb(data++); + r = mem_readb(data++); data++; + IO_Write(0x3c9,r); + IO_Write(0x3c9,g); + IO_Write(0x3c9,b); count--; } return 0x00; @@ -203,13 +270,17 @@ Bit8u VESA_SetPalette(PhysPt data,Bitu index,Bitu count) { Bit8u VESA_GetPalette(PhysPt data,Bitu index,Bitu count) { + Bit8u r,g,b; if (index>255) return 0x1; if (index+count>256) return 0x1; IO_Write(0x3c7,index); while (count) { - mem_writeb(data++,IO_Read(0x3c9)); - mem_writeb(data++,IO_Read(0x3c9)); - mem_writeb(data++,IO_Read(0x3c9)); + r = IO_Read(0x3c9); + g = IO_Read(0x3c9); + b = IO_Read(0x3c9); + mem_writeb(data++,b); + mem_writeb(data++,g); + mem_writeb(data++,r); data++; count--; } @@ -217,58 +288,65 @@ Bit8u VESA_GetPalette(PhysPt data,Bitu index,Bitu count) { } -Bit8u VESA_ScanLineLength(Bit8u subcall,Bit16u & bytes,Bit16u & pixels,Bit16u & lines) { +Bit8u VESA_ScanLineLength(Bit8u subcall,Bit16u val, Bit16u & bytes,Bit16u & pixels,Bit16u & lines) { Bit8u bpp; switch (CurMode->type) { + case M_LIN4: + break; case M_LIN8: - bpp=1;break; + bpp=1; + break; + case M_LIN15: + case M_LIN16: + bpp=2; + break; + case M_LIN32: + bpp=4; + break; default: return 0x1; } - Bitu scan_len; - lines=0xfff; //Does anyone care? switch (subcall) { case 0x00: /* Set in pixels */ - bytes=(pixels*bpp); + vga.config.scan_len = (val * bpp); + break; case 0x02: /* Set in bytes */ - scan_len=bytes/8; - if (bytes % 8) scan_len++; - vga.config.scan_len=scan_len; - VGA_StartResize(); + vga.config.scan_len = val; break; case 0x03: /* Get maximum */ bytes=0x400*4; pixels=bytes/bpp; + lines = 2*1024*1024 / bytes; return 0x00; case 0x01: /* Get lengths */ break; default: return 0x1; //Illegal call } - /* Write the scan line to video card the simple way */ + if (subcall!=0x01) { + /* Write the scan line to video card the simple way */ + if (vga.config.scan_len & 7) + vga.config.scan_len += 8; + vga.config.scan_len /= 8; + } pixels=(vga.config.scan_len*8)/bpp; bytes=vga.config.scan_len*8; + lines = 2*1024*1024 / bytes; + VGA_StartResize(); return 0x0; } - -/* Based of the s3 univbe driver */ -static Bit8u PmodeInterface[]={ - 0x08,0x00,0x19,0x00,0x57,0x00,0x00,0x00,0x50,0x52,0x8b,0xc2,0x8a,0xe0,0xb0,0x6a, - 0x66,0xba,0xd4,0x03,0x66,0xef,0x5a,0x58,0xc3,0x52,0x66,0xba,0xda,0x03,0xec,0xa8, - 0x01,0x75,0xfb,0x5a,0x53,0x8a,0xf9,0xb3,0x0d,0xb1,0x0c,0x66,0x8b,0xf2,0x66,0xba, - 0xd4,0x03,0x66,0x8b,0xc3,0x66,0xef,0x66,0x8b,0xc1,0x66,0xef,0x66,0x8b,0xde,0x8a, - 0xe3,0xb0,0x69,0x66,0xef,0x5b,0x52,0xf6,0xc3,0x80,0x74,0x09,0x66,0xba,0xda,0x03, - 0xec,0xa8,0x08,0x74,0xfb,0x5a,0xc3,0xf6,0xc3,0x80,0x74,0x10,0x52,0x66,0xba,0xda, - 0x03,0xec,0xa8,0x08,0x75,0xfb,0xec,0xa8,0x08,0x74,0xfb,0x5a,0x1e,0x06,0x1f,0x0f, - 0xb7,0xc9,0x8b,0xc2,0x66,0xba,0xc8,0x03,0xee,0x42,0xfc,0x8a,0x47,0x02,0xee,0x8a, - 0x47,0x01,0xee,0x8a,0x07,0xee,0x83,0xc7,0x04,0x49,0x75,0xef,0x1f,0xc3 -}; - Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y) { //TODO Maybe do things differently with lowres double line modes? Bitu start; switch (CurMode->type) { + case M_LIN4: + start=vga.config.scan_len*8*y+x; + vga.config.display_start=start/8; + IO_Read(0x3da); + IO_Write(0x3c0,0x13+32); + IO_Write(0x3c0,start % 8); + break; case M_LIN8: start=vga.config.scan_len*8*y+x; vga.config.display_start=start/4; @@ -276,6 +354,15 @@ Bit8u VESA_SetDisplayStart(Bit16u x,Bit16u y) { IO_Write(0x3c0,0x13+32); IO_Write(0x3c0,(start % 4)*2); break; + case M_LIN16: + case M_LIN15: + start=vga.config.scan_len*8*y+x; + vga.config.display_start=start/4; + break; + case M_LIN32: + start=vga.config.scan_len*8*y+x; + vga.config.display_start=start/4; + break; default: return 0x1; } @@ -289,7 +376,7 @@ Bit8u VESA_GetDisplayStart(Bit16u & x,Bit16u & y) { switch (CurMode->type) { case M_LIN8: y=times; - x=rem*4+pan; + x=rem+pan; break; default: return 0x1; @@ -297,13 +384,30 @@ Bit8u VESA_GetDisplayStart(Bit16u & x,Bit16u & y) { return 0x00; } -static Bitu SetWindowPositionHandler(void) { +static Bitu VESA_SetWindow(void) { if (reg_bh) reg_ah=VESA_GetCPUWindow(reg_bl,reg_dx); else reg_ah=VESA_SetCPUWindow(reg_bl,(Bit8u)reg_dx); reg_al=0x4f; return 0; } +static Bitu VESA_PMSetWindow(void) { + VESA_SetCPUWindow(reg_bl,(Bit8u)reg_dx); + return 0; +} +static Bitu VESA_PMSetPalette(void) { + VESA_SetPalette(SegPhys(es) + reg_edi, reg_dx, reg_cx ); + return 0; +} +static Bitu VESA_PMSetStart(void) { + Bit32u start = (reg_dx << 16) | reg_cx; + vga.config.display_start = start; + return 0; +} + + + + void INT10_SetupVESA(void) { /* Put the mode list somewhere in memory */ Bitu i; @@ -324,14 +428,37 @@ void INT10_SetupVESA(void) { for (i=0;i #include @@ -36,7 +36,7 @@ static Bitu call_int33,call_int74; static Bit16u ps2cbseg,ps2cbofs; -static bool useps2callback; +static bool useps2callback,ps2callbackinit; static Bit16u call_ps2; static RealPt ps2_callback; static Bit16s oldmouseX, oldmouseY; @@ -113,26 +113,37 @@ static struct { float senv_y; Bit16u updateRegion_x[2]; Bit16u updateRegion_y[2]; - Bit16u page; Bit16u doubleSpeedThreshold; Bit16u language; Bit16u cursorType; + Bit16s oldshown; + Bit8u page; bool enabled; - Bit16s oldshown; + } mouse; -void Mouse_SetPS2State(bool use) { - if ((SegValue(es)!=0) && (reg_bx!=0)) useps2callback = use; - else useps2callback = false; +bool Mouse_SetPS2State(bool use) { + if (use && (!ps2callbackinit)) { + useps2callback = false; + PIC_SetIRQMask(MOUSE_IRQ,true); + return false; + } + useps2callback = use; Mouse_AutoLock(useps2callback); + PIC_SetIRQMask(MOUSE_IRQ,!useps2callback); + return true; } void Mouse_ChangePS2Callback(Bit16u pseg, Bit16u pofs) { - if ((pseg==0) && (pofs==0)) useps2callback = false; - else useps2callback = true; - ps2cbseg = pseg; - ps2cbofs = pofs; - Mouse_AutoLock(useps2callback); + if ((pseg==0) && (pofs==0)) { + ps2callbackinit = false; + Mouse_AutoLock(false); + } else { + ps2callbackinit = true; + ps2cbseg = pseg; + ps2cbofs = pofs; + } + Mouse_AutoLock(ps2callbackinit); } void DoPS2Callback(Bit16u data, Bit16s mouseX, Bit16s mouseY) { @@ -166,7 +177,7 @@ void DoPS2Callback(Bit16u data, Bit16s mouseX, Bit16s mouseY) { } Bitu PS2_Handler(void) { - reg_sp += 8; // remove the 4 words + CPU_Pop16();CPU_Pop16();CPU_Pop16();CPU_Pop16();// remove the 4 words return CBRET_NONE; } @@ -199,20 +210,16 @@ INLINE void Mouse_AddEvent(Bit16u type) { // *************************************************************************** // Mouse cursor - text mode // *************************************************************************** +/* Write and read directly to the screen. Do no use int_setcursorpos (LOTUS123) */ +extern void WriteChar(Bit16u col,Bit16u row,Bit8u page,Bit8u chr,Bit8u attr,bool useattr); +extern void ReadCharAttr(Bit16u col,Bit16u row,Bit8u page,Bit16u * result); void RestoreCursorBackgroundText() { if (mouse.shown<0) return; if (mouse.background) { - // Save old Cursorposition - Bit8u oldx = CURSOR_POS_ROW(0); - Bit8u oldy = CURSOR_POS_COL(0); - // Restore background - INT10_SetCursorPos ((Bit8u)mouse.backposy,(Bit8u)mouse.backposx,0); - INT10_WriteChar (mouse.backData[0],mouse.backData[1],0,1,true); - // Restore old cursor position - INT10_SetCursorPos (oldx,oldy,0); + WriteChar(mouse.backposx,mouse.backposy,0,mouse.backData[0],mouse.backData[1],true); mouse.background = false; } }; @@ -222,51 +229,52 @@ void DrawCursorText() // Restore Background RestoreCursorBackgroundText(); - // Save old Cursorposition - Bit8u oldx = CURSOR_POS_ROW(0); - Bit8u oldy = CURSOR_POS_COL(0); // Save Background - Bit16u result; - INT10_SetCursorPos (POS_Y>>3,POS_X>>3,0); - INT10_ReadCharAttr (&result,0); - mouse.backData[0] = result & 0xFF; - mouse.backData[1] = result>>8; mouse.backposx = POS_X>>3; mouse.backposy = POS_Y>>3; - mouse.background = true; + Bit16u result; + ReadCharAttr(mouse.backposx,mouse.backposy,0,&result); + mouse.backData[0] = result & 0xFF; + mouse.backData[1] = result>>8; + mouse.background = true; // Write Cursor result = (result & mouse.textAndMask) ^ mouse.textXorMask; - INT10_WriteChar (result&0xFF,result>>8,0,1,true); - - // Restore old cursor position - INT10_SetCursorPos (oldx,oldy,0); + WriteChar(mouse.backposx,mouse.backposy,0,result&0xFF,result>>8,true); }; // *************************************************************************** // Mouse cursor - graphic mode // *************************************************************************** -static Bit8u gfxReg[9]; - +static Bit8u gfxReg3CE[9]; +static Bit8u index3C4,gfxReg3C5; void SaveVgaRegisters() { for (int i=0; i<9; i++) { IO_Write (0x3CE,i); - gfxReg[i] = IO_Read(0x3CF); + gfxReg3CE[i] = IO_Read(0x3CF); } /* Setup some default values in GFX regs that should work */ - IO_Write (0x3CE,3);IO_Write(0x3Cf,0); //disable rotate and operation - IO_Write (0x3CE,5);IO_Write(0x3Cf,0); //Force read/write mode 0 + IO_Write(0x3CE,3); IO_Write(0x3Cf,0); //disable rotate and operation + IO_Write(0x3CE,5); IO_Write(0x3Cf,gfxReg3CE[5]&0xf0); //Force read/write mode 0 + + //Set Map to all planes. Celtic Tales + index3C4 = IO_Read(0x3c4); IO_Write(0x3C4,2); + gfxReg3C5 = IO_Read(0x3C5); IO_Write(0x3C5,0xF); } void RestoreVgaRegisters() { for (int i=0; i<9; i++) { IO_Write(0x3CE,i); - IO_Write(0x3CF,gfxReg[i]); + IO_Write(0x3CF,gfxReg3CE[i]); } + + IO_Write(0x3C4,2); + IO_Write(0x3C5,gfxReg3C5); + IO_Write(0x3C4,index3C4); } void ClipCursorArea(Bit16s& x1, Bit16s& x2, Bit16s& y1, Bit16s& y2, Bit16u& addx1, Bit16u& addx2, Bit16u& addy) @@ -314,7 +322,7 @@ void RestoreCursorBackground() for (y=y1; y<=y2; y++) { dataPos += addx1; for (x=x1; x<=x2; x++) { - INT10_PutPixel(x,y,0,mouse.backData[dataPos++]); + INT10_PutPixel(x,y,mouse.page,mouse.backData[dataPos++]); }; dataPos += addx2; }; @@ -324,11 +332,9 @@ void RestoreCursorBackground() }; void DrawCursor() { - if (mouse.shown<0) return; // Check video page if (real_readb(BIOSMEM_SEG,BIOSMEM_CURRENT_PAGE)!=mouse.page) return; - // Check if cursor in update region /* if ((POS_X >= mouse.updateRegion_x[0]) && (POS_X <= mouse.updateRegion_x[1]) && (POS_Y >= mouse.updateRegion_y[0]) && (POS_Y <= mouse.updateRegion_y[1])) { @@ -351,8 +357,8 @@ void DrawCursor() { mouse.clipx = CurMode->swidth-1; /* Get from bios ? */ mouse.clipy = CurMode->sheight-1; - Bit16s xratio = 640 / CurMode->swidth; /* might be mouse.max_x-.mouse.min_x+1/swidth */ - /* might even be vidmode == 0x13?2:1 */ + Bit16s xratio = 640 / CurMode->swidth;/* might be vidmode == 0x13?2:1 */ + if(xratio==0) xratio = 1; RestoreCursorBackground(); @@ -373,7 +379,7 @@ void DrawCursor() { for (y=y1; y<=y2; y++) { dataPos += addx1; for (x=x1; x<=x2; x++) { - INT10_GetPixel(x,y,0,&mouse.backData[dataPos++]); + INT10_GetPixel(x,y,mouse.page,&mouse.backData[dataPos++]); }; dataPos += addx2; }; @@ -396,7 +402,7 @@ void DrawCursor() { if (cuMask & HIGHESTBIT) pixel = pixel ^ 0x0F; cuMask<<=1; // Set Pixel - INT10_PutPixel(x,y,0,pixel); + INT10_PutPixel(x,y,mouse.page,pixel); dataPos++; }; dataPos += addx2; @@ -404,18 +410,32 @@ void DrawCursor() { RestoreVgaRegisters(); } -void Mouse_CursorMoved(float x,float y) { - float dx = x * mouse.pixelPerMickey_x; - float dy = y * mouse.pixelPerMickey_y; - if((fabs(x) > 1.0) || (mouse.senv_y < 1.0)) dx *= mouse.senv_x; +void Mouse_CursorMoved(float xrel,float yrel,float x,float y,bool emulate) { + float dx = xrel * mouse.pixelPerMickey_x; + float dy = yrel * mouse.pixelPerMickey_y; + if((fabs(x) > 1.0) || (mouse.senv_x < 1.0)) dx *= mouse.senv_x; if((fabs(y) > 1.0) || (mouse.senv_y < 1.0)) dy *= mouse.senv_y; - + if (useps2callback) dy *= 2; mouse.mickey_x += dx; mouse.mickey_y += dy; - mouse.x += dx; - mouse.y += dy; + if (emulate) { + mouse.x += dx; + mouse.y += dy; + } else { + if (CurMode->type == M_TEXT) { + mouse.x = x*CurMode->swidth; + mouse.y = y*CurMode->sheight * 8 / CurMode->cheight; + } else if (mouse.max_x < 2048 || mouse.max_y < 2048 || mouse.max_x != mouse.max_y) { + mouse.x = x*mouse.max_x; + mouse.y = y*mouse.max_y; + } else { // Games faking relative movement through absolute coordinates. Quite surprising that this actually works.. + mouse.x += xrel; + mouse.y += yrel; + } + } + /* ignore constraints if using PS2 mouse callback in the bios */ if (!useps2callback) { @@ -475,7 +495,6 @@ void Mouse_ButtonReleased(Bit8u button) { } static void SetMickeyPixelRate(Bit16s px, Bit16s py){ - if ((px!=0) && (py!=0)) { mouse.mickeysPerPixel_x = (float)px/X_MICKEY; mouse.mickeysPerPixel_y = (float)py/Y_MICKEY; @@ -484,6 +503,8 @@ static void SetMickeyPixelRate(Bit16s px, Bit16s py){ } }; static void SetSensitivity(Bit16s px, Bit16s py){ + if(px>100) px=100; + if(py>100) py=100; if ((px!=0) && (py!=0)) { px--; //Inspired by cutemouse py--; //Although their cursor update routine is far more complex then ours @@ -499,14 +520,12 @@ static void mouse_reset_hardware(void){ void Mouse_NewVideoMode(void) { //Does way to much. Many of this stuff should be moved to mouse_reset one day - WriteMouseIntVector(); - if(MOUSE_IRQ > 7) { real_writed(0,((0x70+MOUSE_IRQ-8)<<2),CALLBACK_RealPointer(call_int74)); } else { real_writed(0,((0x8+MOUSE_IRQ)<<2),CALLBACK_RealPointer(call_int74)); } - mouse.shown=-1; +// mouse.shown=-1;//Disabled as ida doesn't have mousecursor anymore /* Get the correct resolution from the current video mode */ Bitu mode=mem_readb(BIOS_VIDEO_MODE); switch (mode) { @@ -537,14 +556,16 @@ void Mouse_NewVideoMode(void) default: mouse.max_y=199; LOG(LOG_MOUSE,LOG_ERROR)("Unhandled videomode %X on reset",mode); + // Hide mouse cursor on non supported modi. Pirates Gold + mouse.shown = -1; break; } mouse.max_x = 639; mouse.min_x = 0; mouse.min_y = 0; // Dont set max coordinates here. it is done by SetResolution! - mouse.x = static_cast(mouse.max_x / 2); - mouse.y = static_cast(mouse.max_y / 2); + mouse.x = static_cast((mouse.max_x + 1)/ 2); + mouse.y = static_cast((mouse.max_y + 1)/ 2); mouse.events = 0; mouse.mickey_x = 0; mouse.mickey_y = 0; @@ -569,17 +590,17 @@ void Mouse_NewVideoMode(void) SetMickeyPixelRate(8,16); oldmouseX = static_cast(mouse.x); - oldmouseY = static_cast(mouse.y); - - - } - - static void mouse_reset(void) { //Much to empty Mouse_NewVideoMode contains stuff that should be in here + + /* Remove drawn mouse Legends of Valor */ + if (CurMode->type!=M_TEXT) RestoreCursorBackground(); + else RestoreCursorBackgroundText(); + mouse.shown = -1; + Mouse_NewVideoMode(); mouse.sub_mask=0; @@ -589,13 +610,11 @@ static void mouse_reset(void) { mouse.senv_y=1.0; - - //Added this for cd-v19 } static Bitu INT33_Handler(void) { -// LOG(LOG_MOUSE,LOG_NORMAL)("MOUSE: %04X",reg_ax); +// LOG(LOG_MOUSE,LOG_NORMAL)("MOUSE: %04X %X %X %d %d",reg_ax,reg_bx,reg_cx,POS_X,POS_Y); switch (reg_ax) { case 0x00: /* Reset Driver and Read Status */ mouse_reset_hardware(); /* fallthrough */ @@ -613,8 +632,8 @@ static Bitu INT33_Handler(void) { break; case 0x02: /* Hide Mouse */ { - if (CurMode->type!=M_TEXT) RestoreCursorBackground(); - else RestoreCursorBackgroundText(); + if (CurMode->type!=M_TEXT) RestoreCursorBackground(); + else RestoreCursorBackgroundText(); mouse.shown--; } break; @@ -624,14 +643,23 @@ static Bitu INT33_Handler(void) { reg_dx=POS_Y; break; case 0x04: /* Position Mouse */ - mouse.x = static_cast(((reg_cx > mouse.max_x) ? mouse.max_x : reg_cx)); - mouse.y = static_cast(((reg_dx > mouse.max_y) ? mouse.max_y : reg_dx)); + /* If position isn't different from current position + * don't change it then. (as position is rounded so numbers get + * lost when the rounded number is set) (arena/simulation Wolf) */ + if(reg_cx >= mouse.max_x) mouse.x = static_cast(mouse.max_x); + else if (mouse.min_x >= reg_cx) mouse.x = static_cast(mouse.min_x); + else if (reg_cx != POS_X) mouse.x = static_cast(reg_cx); + + if(reg_dx >= mouse.max_y) mouse.y = static_cast(mouse.max_y); + else if (mouse.min_y >= reg_dx) mouse.y = static_cast(mouse.min_y); + else if (reg_dx != POS_Y) mouse.y = static_cast(reg_dx); DrawCursor(); break; case 0x05: /* Return Button Press Data */ { Bit16u but=reg_bx; reg_ax=mouse.buttons; + reg_bx++; if (but>=MOUSE_BUTTONS) break; reg_cx=mouse.last_pressed_x[but]; reg_dx=mouse.last_pressed_y[but]; @@ -643,6 +671,7 @@ static Bitu INT33_Handler(void) { { Bit16u but=reg_bx; reg_ax=mouse.buttons; + reg_bx++; if (but>=MOUSE_BUTTONS) break; reg_cx=mouse.last_released_x[but]; reg_dx=mouse.last_released_y[but]; @@ -659,6 +688,11 @@ static Bitu INT33_Handler(void) { else { min=(Bit16s)reg_dx;max=(Bit16s)reg_cx;} mouse.min_x=min; mouse.max_x=max; + /* Battlechess wants this */ + if(mouse.x > mouse.max_x) mouse.x = mouse.max_x; + if(mouse.x < mouse.min_x) mouse.x = mouse.min_x; + /* Or alternatively this: + mouse.x = (mouse.max_x - mouse.min_x + 1)/2;*/ LOG(LOG_MOUSE,LOG_NORMAL)("Define Hortizontal range min:%d max:%d",min,max); } break; @@ -671,6 +705,11 @@ static Bitu INT33_Handler(void) { else { min=(Bit16s)reg_dx;max=(Bit16s)reg_cx;} mouse.min_y=min; mouse.max_y=max; + /* Battlechess wants this */ + if(mouse.y > mouse.max_y) mouse.y = mouse.max_y; + if(mouse.y < mouse.min_y) mouse.y = mouse.min_y; + /* Or alternatively this: + mouse.y = (mouse.max_y - mouse.min_y + 1)/2;*/ LOG(LOG_MOUSE,LOG_NORMAL)("Define Vertical range min:%d max:%d",min,max); } break; @@ -696,6 +735,7 @@ static Bitu INT33_Handler(void) { mouse.sub_mask=reg_cx; mouse.sub_seg=SegValue(es); mouse.sub_ofs=reg_dx; + Mouse_AutoLock(true); //Some games don't seem to reset the mouse before using break; case 0x0f: /* Define mickey/pixel rate */ SetMickeyPixelRate(reg_cx,reg_dx); @@ -772,7 +812,7 @@ static Bitu INT33_Handler(void) { /* Can't really set a rate this is host determined */ break; case 0x1d: /* Set display page number */ - mouse.page=reg_bx; + mouse.page=reg_bl; break; case 0x1e: /* Get display page number */ reg_bx=mouse.page; @@ -891,7 +931,7 @@ void CreateMouseCallback(void) }; void MOUSE_Init(Section* sec) { - + // Callback 0x33 CreateMouseCallback(); call_int74=CALLBACK_Allocate(); @@ -901,12 +941,12 @@ void MOUSE_Init(Section* sec) { } else { real_writed(0,((0x8+MOUSE_IRQ)<<2),CALLBACK_RealPointer(call_int74)); } - useps2callback = false; + useps2callback = false; ps2callbackinit = false; call_ps2=CALLBACK_Allocate(); CALLBACK_Setup(call_ps2,&PS2_Handler,CB_IRET,"ps2 bios callback"); ps2_callback=CALLBACK_RealPointer(call_ps2); memset(&mouse,0,sizeof(mouse)); + mouse.shown=-1; //Hide mouse on startup mouse_reset_hardware(); mouse_reset(); } - diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index 8ab5fc2..20917a3 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: xms.cpp,v 1.33 2004/08/04 09:12:56 qbix79 Exp $ */ +/* $Id: xms.cpp,v 1.39 2006/02/09 11:47:57 qbix79 Exp $ */ #include #include @@ -54,7 +54,9 @@ #define XMS_DEALLOCATE_UMB 0x11 #define XMS_QUERY_ANY_FREE_MEMORY 0x88 #define XMS_ALLOCATE_ANY_MEMORY 0x89 +#define XMS_GET_EMB_HANDLE_INFORMATION_EXT 0x8e +#define XMS_FUNCTION_NOT_IMPLEMENTED 0x80 #define HIGH_MEMORY_NOT_EXIST 0x90 #define HIGH_MEMORY_IN_USE 0x91 #define HIGH_MEMORY_NOT_ALLOCATED 0x93 @@ -63,6 +65,8 @@ #define XMS_INVALID_HANDLE 0xa2 #define XMS_BLOCK_NOT_LOCKED 0xaa #define XMS_BLOCK_LOCKED 0xab +#define UMB_ONLY_SMALLER_BLOCK 0xb0 +#define UMB_NO_BLOCKS_AVAILABLE 0xb1 struct XMS_Block { Bitu size; @@ -101,8 +105,8 @@ Bitu XMS_GetEnabledA20(void) return (IO_Read(0x92)&2)>0; }; -static Bit16u call_xms; static RealPt xms_callback; +static bool umb_available; static XMS_Block xms_handles[XMS_HANDLES]; @@ -315,62 +319,160 @@ Bitu XMS_Handler(void) { reg_bl = XMS_UnlockMemory(reg_dx); reg_ax = (reg_bl==0); break; - case XMS_GET_EMB_HANDLE_INFORMATION: /* 0e */ - reg_bl = XMS_GetHandleInformation(reg_dx,reg_bh,reg_bl,reg_dx); - reg_ax = (reg_bl==0); - break; + case XMS_GET_EMB_HANDLE_INFORMATION: { /* 0e */ + Bitu result = XMS_GetHandleInformation(reg_dx,reg_bh,reg_bl,reg_dx); + if (result != 0) reg_bl = result; + reg_ax = (result==0); + }; break; case XMS_RESIZE_EXTENDED_MEMORY_BLOCK: /* 0f */ reg_bl = XMS_ResizeMemory(reg_dx, reg_bx); reg_ax = (reg_bl==0); break; - case XMS_ALLOCATE_UMB: /* 10 */ - reg_ax=0; - reg_bl=0xb1; //No UMB Available - reg_dx=0; + case XMS_ALLOCATE_UMB: { /* 10 */ + if (!umb_available) { + reg_ax=0; + reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED; + break; + } + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + if (umb_start==0xffff) { + reg_ax=0; + reg_bl=UMB_NO_BLOCKS_AVAILABLE; + reg_dx=0; // no upper memory available + break; + } + /* Save status and linkage of upper UMB chain and link upper + memory to the regular MCB chain */ + Bit8u umb_flag=dos_infoblock.GetUMBChainState(); + if ((umb_flag&1)==0) DOS_LinkUMBsToMemChain(1); + Bit8u old_memstrat=DOS_GetMemAllocStrategy()&0xff; + DOS_SetMemAllocStrategy(0x40); // search in UMBs only + + Bit16u size=reg_dx;Bit16u seg; + if (DOS_AllocateMemory(&seg,&size)) { + reg_ax=1; + reg_bx=seg; + } else { + reg_ax=0; + if (size==0) reg_bl=UMB_NO_BLOCKS_AVAILABLE; + else reg_bl=UMB_ONLY_SMALLER_BLOCK; + reg_dx=size; // size of largest available UMB + } + + /* Restore status and linkage of upper UMB chain */ + Bit8u current_umb_flag=dos_infoblock.GetUMBChainState(); + if ((current_umb_flag&1)!=(umb_flag&1)) DOS_LinkUMBsToMemChain(umb_flag); + DOS_SetMemAllocStrategy(old_memstrat); + } break; case XMS_DEALLOCATE_UMB: /* 11 */ - LOG(LOG_MISC,LOG_ERROR)("XMS:Unhandled call %2X",reg_ah); + if (!umb_available) { + reg_ax=0; + reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED; + break; + } + if (dos_infoblock.GetStartOfUMBChain()!=0xffff) { + if (DOS_FreeMemory(reg_dx)) { + reg_ax=0x0001; + break; + } + } + reg_ax=0x0000; + reg_bl=UMB_NO_BLOCKS_AVAILABLE; break; case XMS_QUERY_ANY_FREE_MEMORY: /* 88 */ reg_bl = XMS_QueryFreeMemory(reg_ax,reg_dx); - reg_eax &= 0xffff; - reg_edx &= 0xffff; - reg_ecx = (MEM_TotalPages()*MEM_PAGESIZE)-1; // highest known physical memory address + reg_eax &= 0xffff; + reg_edx &= 0xffff; + reg_ecx = (MEM_TotalPages()*MEM_PAGESIZE)-1; // highest known physical memory address break; + case XMS_GET_EMB_HANDLE_INFORMATION_EXT: { /* 8e */ + Bit8u free_handles; + Bitu result = XMS_GetHandleInformation(reg_dx,reg_bh,free_handles,reg_dx); + if (result != 0) reg_bl = result; + else { + reg_edx &= 0xffff; + reg_cx = free_handles; + } + reg_ax = (result==0); + } break; + default: + LOG(LOG_MISC,LOG_ERROR)("XMS: unknown function %02X",reg_ah); + reg_ax=0; + reg_bl=XMS_FUNCTION_NOT_IMPLEMENTED; } // LOG(LOG_MISC,LOG_ERROR)("XMS: CALL Result: %02X",reg_bl); return CBRET_NONE; } +class XMS: public Module_base { +private: + CALLBACK_HandlerObject callbackhandler; +public: + XMS(Section* configuration):Module_base(configuration){ + Section_prop * section=static_cast(configuration); + umb_available=false; + if (!section->Get_bool("xms")) return; + Bitu i; + BIOS_ZeroExtendedSize(true); + DOS_AddMultiplexHandler(multiplex_xms); + callbackhandler.Install(&XMS_Handler,CB_RETF, "XMS Handler"); + xms_callback=callbackhandler.Get_RealPointer(); + Bit16u call_xms=callbackhandler.Get_callback(); + + /* Override the callback with one that can be hooked */ + phys_writeb(CB_BASE+(call_xms<<4)+0,(Bit8u)0xeb); //jump near + phys_writeb(CB_BASE+(call_xms<<4)+1,(Bit8u)0x03); //offset + phys_writeb(CB_BASE+(call_xms<<4)+2,(Bit8u)0x90); //NOP + phys_writeb(CB_BASE+(call_xms<<4)+3,(Bit8u)0x90); //NOP + phys_writeb(CB_BASE+(call_xms<<4)+4,(Bit8u)0x90); //NOP + phys_writeb(CB_BASE+(call_xms<<4)+5,(Bit8u)0xFE); //GRP 4 + phys_writeb(CB_BASE+(call_xms<<4)+6,(Bit8u)0x38); //Extra Callback instruction + phys_writew(CB_BASE+(call_xms<<4)+7,call_xms); //The immediate word + phys_writeb(CB_BASE+(call_xms<<4)+9,(Bit8u)0xCB); //A RETF Instruction + + for (i=0;i(sec); - if (!section->Get_bool("xms")) return; - Bitu i; - BIOS_ZeroExtendedSize(); - DOS_AddMultiplexHandler(multiplex_xms); - call_xms=CALLBACK_Allocate(); - CALLBACK_Setup(call_xms,&XMS_Handler,CB_RETF, "XMS Handler"); - xms_callback=CALLBACK_RealPointer(call_xms); - - /* Overide the callback with one that can be hooked */ - phys_writeb(CB_BASE+(call_xms<<4)+0,(Bit8u)0xeb); //jump near - phys_writeb(CB_BASE+(call_xms<<4)+1,(Bit8u)0x03); //offset - phys_writeb(CB_BASE+(call_xms<<4)+2,(Bit8u)0x90); //NOP - phys_writeb(CB_BASE+(call_xms<<4)+3,(Bit8u)0x90); //NOP - phys_writeb(CB_BASE+(call_xms<<4)+4,(Bit8u)0x90); //NOP - phys_writeb(CB_BASE+(call_xms<<4)+5,(Bit8u)0xFE); //GRP 4 - phys_writeb(CB_BASE+(call_xms<<4)+6,(Bit8u)0x38); //Extra Callback instruction - phys_writew(CB_BASE+(call_xms<<4)+7,call_xms); //The immediate word - phys_writeb(CB_BASE+(call_xms<<4)+9,(Bit8u)0xCB); //A RETF Instruction - - for (i=0;iGet_string("umb"),"false")!=0; + DOS_BuildUMBChain(section->Get_string("umb"),section->Get_bool("ems")); } - /* Disable the 0 handle */ - xms_handles[0].free = false; + + ~XMS(){ + Section_prop * section = static_cast(m_configuration); + /* Remove upper memory information */ + dos_infoblock.SetStartOfUMBChain(0xffff); + if (umb_available) { + dos_infoblock.SetUMBChainState(0); + umb_available=false; + } + + if (!section->Get_bool("xms")) return; + /* Undo biosclearing */ + BIOS_ZeroExtendedSize(false); + + /* Remove Multiplex */ + DOS_DelMultiplexHandler(multiplex_xms); + + /* Free used memory while skipping the 0 handle */ + for (Bitu i = 1;iAddDestroyFunction(&XMS_ShutDown,true); +} diff --git a/src/ints/xms.h b/src/ints/xms.h index 3ee5d5c..5944911 100644 --- a/src/ints/xms.h +++ b/src/ints/xms.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 diff --git a/src/libs/Makefile.am b/src/libs/Makefile.am new file mode 100644 index 0000000..b74bb58 --- /dev/null +++ b/src/libs/Makefile.am @@ -0,0 +1,3 @@ +AM_CPPFLAGS = -I$(top_srcdir)/include + +SUBDIRS = zmbv \ No newline at end of file diff --git a/src/libs/Makefile.in b/src/libs/Makefile.in new file mode 100644 index 0000000..2702c53 --- /dev/null +++ b/src/libs/Makefile.in @@ -0,0 +1,462 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/libs +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-exec-recursive install-info-recursive \ + install-recursive installcheck-recursive installdirs-recursive \ + pdf-recursive ps-recursive uninstall-info-recursive \ + uninstall-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_CONFIG = @SDL_CONFIG@ +SDL_LIBS = @SDL_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +AM_CPPFLAGS = -I$(top_srcdir)/include +SUBDIRS = zmbv +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/libs/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/libs/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(mkdir_p) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am \ + clean clean-generic clean-recursive ctags ctags-recursive \ + distclean distclean-generic distclean-recursive distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-recursive pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libs/zmbv/Makefile.am b/src/libs/zmbv/Makefile.am new file mode 100644 index 0000000..311db44 --- /dev/null +++ b/src/libs/zmbv/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = zmbv.cpp zmbv.h diff --git a/src/libs/zmbv/Makefile.in b/src/libs/zmbv/Makefile.in new file mode 100644 index 0000000..34920a3 --- /dev/null +++ b/src/libs/zmbv/Makefile.in @@ -0,0 +1,305 @@ +# Makefile.in generated by automake 1.9.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../../.. +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = src/libs/zmbv +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALSA_CFLAGS = @ALSA_CFLAGS@ +ALSA_LIBS = @ALSA_LIBS@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_CONFIG = @SDL_CONFIG@ +SDL_LIBS = @SDL_LIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +WINDRES = @WINDRES@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +datadir = @datadir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +EXTRA_DIST = zmbv.cpp zmbv.h +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnits src/libs/zmbv/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnits src/libs/zmbv/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +uninstall-info-am: +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-exec \ + install-exec-am install-info install-info-am install-man \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am \ + uninstall-info-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libs/zmbv/zmbv.cpp b/src/libs/zmbv/zmbv.cpp new file mode 100644 index 0000000..0681251 --- /dev/null +++ b/src/libs/zmbv/zmbv.cpp @@ -0,0 +1,549 @@ +/* + * Copyright (C) 2002-2006 The DOSBox Team + * + * 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 +#include +#include + +#include "zmbv.h" + +#define DBZV_VERSION_HIGH 0 +#define DBZV_VERSION_LOW 1 + +#define COMPRESSION_NONE 0 +#define COMPRESSION_ZLIB 1 + +#define MAX_VECTOR 16 + +#define Mask_KeyFrame 0x01 +#define Mask_DeltaPalette 0x02 + +zmbv_format_t BPPFormat( int bpp ) { + switch (bpp) { + case 8: + return ZMBV_FORMAT_8BPP; + case 15: + return ZMBV_FORMAT_15BPP; + case 16: + return ZMBV_FORMAT_16BPP; + case 32: + return ZMBV_FORMAT_32BPP; + } + return ZMBV_FORMAT_NONE; +} +int VideoCodec::NeededSize( int _width, int _height, zmbv_format_t _format) { + int f; + switch (_format) { + case ZMBV_FORMAT_8BPP:f = 1;break; + case ZMBV_FORMAT_15BPP:f = 2;break; + case ZMBV_FORMAT_16BPP:f = 2;break; + case ZMBV_FORMAT_32BPP:f = 4;break; + default: + return -1; + } + f = f*_width*_height + 2*(1+(_width/8)) * (1+(_height/8))+1024; + return f + f/1000; +} + +bool VideoCodec::SetupBuffers(zmbv_format_t _format, int blockwidth, int blockheight) { + FreeBuffers(); + palsize = 0; + switch (_format) { + case ZMBV_FORMAT_8BPP: + pixelsize = 1; + palsize = 256; + break; + case ZMBV_FORMAT_15BPP: + pixelsize = 2; + break; + case ZMBV_FORMAT_16BPP: + pixelsize = 2; + break; + case ZMBV_FORMAT_32BPP: + pixelsize = 4; + break; + default: + return false; + }; + bufsize = (height+2*MAX_VECTOR)*pitch*pixelsize+2048; + + buf1 = new unsigned char[bufsize]; + buf2 = new unsigned char[bufsize]; + work = new unsigned char[bufsize]; + + int xblocks = (width/blockwidth); + int xleft = width % blockwidth; + if (xleft) xblocks++; + int yblocks = (height/blockheight); + int yleft = height % blockheight; + if (yleft) yblocks++; + blockcount=yblocks*xblocks; + blocks=new FrameBlock[blockcount]; + + if (!buf1 || !buf2 || !work || !blocks) { + FreeBuffers(); + return false; + } + int y,x,i; + i=0; + for (y=0;y +INLINE int VideoCodec::PossibleBlock(int vx,int vy,FrameBlock * block) { + int ret=0; + P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; + P * pnew=((P*)newframe)+block->start;; + for (int y=0;ydy;y+=4) { + for (int x=0;xdx;x+=4) { + int test=0-((pold[x]-pnew[x])&0x00ffffff); + ret-=(test>>31); + } + pold+=pitch*4; + pnew+=pitch*4; + } + return ret; +} + +template +INLINE int VideoCodec::CompareBlock(int vx,int vy,FrameBlock * block) { + int ret=0; + P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; + P * pnew=((P*)newframe)+block->start;; + for (int y=0;ydy;y++) { + for (int x=0;xdx;x++) { + int test=0-((pold[x]-pnew[x])&0x00ffffff); + ret-=(test>>31); + } + pold+=pitch; + pnew+=pitch; + } + return ret; +} + +template +INLINE void VideoCodec::AddXorBlock(int vx,int vy,FrameBlock * block) { + P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; + P * pnew=((P*)newframe)+block->start; + for (int y=0;ydy;y++) { + for (int x=0;xdx;x++) { + *((P*)&work[workUsed])=pnew[x] ^ pold[x]; + workUsed+=sizeof(P); + } + pold+=pitch; + pnew+=pitch; + } +} + +template +void VideoCodec::AddXorFrame(void) { + int written=0; + int lastvector=0; + signed char * vectors=(signed char*)&work[workUsed]; + /* Align the following xor data on 4 byte boundary*/ + workUsed=(workUsed + blockcount*2 +3) & ~3; + int totalx=0; + int totaly=0; + for (int b=0;b(0,0, block); + int possibles=64; + for (int v=0;v(vx, vy, block) < 4) { + possibles--; +// if (!possibles) Msg("Ran out of possibles, at %d of %d best %d\n",v,VectorCount,bestchange); + int testchange=CompareBlock

(vx,vy, block); + if (testchange(bestvx, bestvy, block); + } + } +} + +bool VideoCodec::SetupCompress( int _width, int _height ) { + width = _width; + height = _height; + pitch = _width + 2*MAX_VECTOR; + format = ZMBV_FORMAT_NONE; + if (deflateInit (&zstream, 4) != Z_OK) + return false; + return true; +} + +bool VideoCodec::SetupDecompress( int _width, int _height) { + width = _width; + height = _height; + pitch = _width + 2*MAX_VECTOR; + format = ZMBV_FORMAT_NONE; + if (inflateInit (&zstream) != Z_OK) + return false; + return true; +} + +bool VideoCodec::PrepareCompressFrame(int flags, zmbv_format_t _format, char * pal, void *writeBuf, int writeSize) { + int i; + unsigned char *firstByte; + + if (_format != format) { + if (!SetupBuffers( _format, 16, 16)) + return false; + flags|=1; //Force a keyframe + } + /* replace oldframe with new frame */ + unsigned char *copyFrame = newframe; + newframe = oldframe; + oldframe = copyFrame; + + compress.linesDone = 0; + compress.writeSize = writeSize; + compress.writeDone = 1; + compress.writeBuf = (unsigned char *)writeBuf; + /* Set a pointer to the first byte which will contain info about this frame */ + firstByte = compress.writeBuf; + *firstByte = 0; + //Reset the work buffer + workUsed = 0;workPos = 0; + if (flags & 1) { + /* Make a keyframe */ + *firstByte |= Mask_KeyFrame; + KeyframeHeader * header = (KeyframeHeader *)(compress.writeBuf + compress.writeDone); + header->high_version = DBZV_VERSION_HIGH; + header->low_version = DBZV_VERSION_LOW; + header->compression = COMPRESSION_ZLIB; + header->format = format; + header->blockwidth = 16; + header->blockheight = 16; + compress.writeDone += sizeof(KeyframeHeader); + /* Copy the new frame directly over */ + if (palsize) { + if (pal) + memcpy(&palette, pal, sizeof(palette)); + else + memset(&palette,0, sizeof(palette)); + /* keyframes get the full palette */ + for (i=0;i(); + break; + case ZMBV_FORMAT_15BPP: + case ZMBV_FORMAT_16BPP: + AddXorFrame(); + break; + case ZMBV_FORMAT_32BPP: + AddXorFrame(); + break; + } + } + /* Create the actual frame with compression */ + zstream.next_in = (Bytef *)work; + zstream.avail_in = workUsed; + zstream.total_in = 0; + + zstream.next_out = (Bytef *)(compress.writeBuf + compress.writeDone); + zstream.avail_out = compress.writeSize - compress.writeDone; + zstream.total_out = 0; + int res = deflate(&zstream, Z_SYNC_FLUSH); + return compress.writeDone + zstream.total_out; +} + +template +INLINE void VideoCodec::UnXorBlock(int vx,int vy,FrameBlock * block) { + P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; + P * pnew=((P*)newframe)+block->start; + for (int y=0;ydy;y++) { + for (int x=0;xdx;x++) { + pnew[x]=pold[x]^*((P*)&work[workPos]); + workPos+=sizeof(P); + } + pold+=pitch; + pnew+=pitch; + } +} + +template +INLINE void VideoCodec::CopyBlock(int vx,int vy,FrameBlock * block) { + P * pold=((P*)oldframe)+block->start+(vy*pitch)+vx; + P * pnew=((P*)newframe)+block->start; + for (int y=0;ydy;y++) { + for (int x=0;xdx;x++) { + pnew[x]=pold[x]; + } + pold+=pitch; + pnew+=pitch; + } +} + +template +void VideoCodec::UnXorFrame(void) { + signed char * vectors=(signed char *)&work[workPos]; + workPos=(workPos + blockcount*2 + 3) & ~3; + for (int b=0;b> 1; + int vy = vectors[b*2+1] >> 1; + if (delta) UnXorBlock

(vx,vy,block); + else CopyBlock

(vx,vy,block); + } +} + +bool VideoCodec::DecompressFrame(void * framedata, int size) { + unsigned char *data=(unsigned char *)framedata; + unsigned char tag;int i; + + tag = *data++; + if (--size<=0) + return false; + if (tag & Mask_KeyFrame) { + KeyframeHeader * header = (KeyframeHeader *)data; + size -= sizeof(KeyframeHeader);data += sizeof(KeyframeHeader); + if (size<=0) + return false; + if (header->low_version != DBZV_VERSION_LOW || header->high_version != DBZV_VERSION_HIGH) + return false; + if (format != (zmbv_format_t)header->format && !SetupBuffers((zmbv_format_t)header->format, header->blockwidth, header->blockheight)) + return false; + inflateReset(&zstream); + } + zstream.next_in = (Bytef *)data; + zstream.avail_in = size; + zstream.total_in = 0; + + zstream.next_out = (Bytef *)work; + zstream.avail_out = bufsize; + zstream.total_out = 0; + int res = inflate(&zstream, Z_FINISH); + workUsed= zstream.total_out; + workPos = 0; + if (tag & Mask_KeyFrame) { + if (palsize) { + for (i=0;i(); + break; + case ZMBV_FORMAT_15BPP: + case ZMBV_FORMAT_16BPP: + UnXorFrame(); + break; + case ZMBV_FORMAT_32BPP: + UnXorFrame(); + break; + } + } + return true; +} + +void VideoCodec::Output_UpsideDown_24(void *output) { + int i; + unsigned char *r; + unsigned char *w = (unsigned char *)output; + int pad = width & 3; + + for (i=height-1;i>=0;i--) { + r = newframe + pixelsize*(MAX_VECTOR+(i+MAX_VECTOR)*pitch); + switch (format) { + case ZMBV_FORMAT_8BPP: + for (int j=0;j> 2); + *w++ = (unsigned char)(((c & 0x03e0) * 0x21) >> 7); + *w++ = (unsigned char)(((c & 0x7c00) * 0x21) >> 12); + } + break; + case ZMBV_FORMAT_16BPP: + for (int j=0;j> 2); + *w++ = (unsigned char)(((c & 0x07e0) * 0x41) >> 9); + *w++ = (unsigned char)(((c & 0xf800) * 0x21) >> 13); + } + break; + case ZMBV_FORMAT_32BPP: + for (int j=0;j + void AddXorFrame(void); + template + void UnXorFrame(void); + template + INLINE int PossibleBlock(int vx,int vy,FrameBlock * block); + template + INLINE int CompareBlock(int vx,int vy,FrameBlock * block); + template + INLINE void AddXorBlock(int vx,int vy,FrameBlock * block); + template + INLINE void UnXorBlock(int vx,int vy,FrameBlock * block); + template + INLINE void CopyBlock(int vx, int vy,FrameBlock * block); +public: + VideoCodec(); + bool SetupCompress( int _width, int _height); + bool SetupDecompress( int _width, int _height); + zmbv_format_t BPPFormat( int bpp ); + int NeededSize( int _width, int _height, zmbv_format_t _format); + + void CompressLines(int lineCount, void *lineData[]); + bool PrepareCompressFrame(int flags, zmbv_format_t _format, char * pal, void *writeBuf, int writeSize); + int FinishCompressFrame( void ); + bool DecompressFrame(void * framedata, int size); + void Output_UpsideDown_24(void * output); +}; diff --git a/src/misc/Makefile.in b/src/misc/Makefile.in index 73b5a74..a61a777 100644 --- a/src/misc/Makefile.in +++ b/src/misc/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -96,6 +96,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -121,10 +123,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/misc/messages.cpp b/src/misc/messages.cpp index 10be411..c2b31b0 100644 --- a/src/misc/messages.cpp +++ b/src/misc/messages.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,6 +16,8 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* $Id: messages.cpp,v 1.18 2006/02/09 11:47:57 qbix79 Exp $ */ + #include #include #include @@ -56,9 +58,7 @@ void MSG_Replace(const char * _name, const char* _val) { /* Find the message */ for(itmb tel=Lang.begin();tel!=Lang.end();tel++) { if((*tel).name==_name) { - itmb teln=tel; - teln++; - Lang.erase(tel,teln); + Lang.erase(tel); break; } } diff --git a/src/misc/programs.cpp b/src/misc/programs.cpp index 5e3e321..9f739f5 100644 --- a/src/misc/programs.cpp +++ b/src/misc/programs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: programs.cpp,v 1.17 2004/10/23 17:54:36 qbix79 Exp $ */ +/* $Id: programs.cpp,v 1.24 2006/03/02 14:12:49 qbix79 Exp $ */ #include #include @@ -30,6 +30,7 @@ #include "support.h" #include "cross.h" #include "setup.h" +#include "shell.h" Bitu call_program; @@ -51,7 +52,7 @@ static Bit8u exe_block[]={ static std::vector internal_progs; void PROGRAMS_MakeFile(char * name,PROGRAMS_Main * main) { - Bit8u * comdata=(Bit8u *)malloc(128); + Bit8u * comdata=(Bit8u *)malloc(32); //MEM LEAK memcpy(comdata,&exe_block,sizeof(exe_block)); comdata[CB_POS]=call_program&0xff; comdata[CB_POS+1]=(call_program>>8)&0xff; @@ -127,9 +128,15 @@ bool Program::GetEnvStr(const char * entry,std::string & result) { MEM_StrCopy(env_read,env_string,1024); if (!env_string[0]) return false; env_read+=strlen(env_string)+1; - if (!strchr(env_string,'=')) continue; - if (strncasecmp(entry,env_string,strlen(entry))!=0) continue; - result=env_string; + char* equal = strchr(env_string,'='); + if (!equal) continue; + /* replace the = with \0 to get the length */ + *equal = 0; + if (strlen(env_string) != strlen(entry)) continue; + if (strcasecmp(entry,env_string)!=0) continue; + /* restore the = to get the original result */ + *equal = '='; + result = env_string; return true; } while (1); return false; @@ -197,7 +204,8 @@ void MSG_Write(const char *); void CONFIG::Run(void) { FILE * f; - if (cmd->FindString("-writeconf",temp_line,true)) { + if (cmd->FindString("-writeconf",temp_line,true) + || cmd->FindString("-wc",temp_line,true)) { f=fopen(temp_line.c_str(),"wb+"); if (!f) { WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),temp_line.c_str()); @@ -207,7 +215,8 @@ void CONFIG::Run(void) { control->PrintConfig(temp_line.c_str()); return; } - if (cmd->FindString("-writelang",temp_line,true)) { + if (cmd->FindString("-writelang",temp_line,true) + ||cmd->FindString("-wl",temp_line,true)) { f=fopen(temp_line.c_str(),"wb+"); if (!f) { WriteOut(MSG_Get("PROGRAM_CONFIG_FILE_ERROR"),temp_line.c_str()); @@ -217,7 +226,101 @@ void CONFIG::Run(void) { MSG_Write(temp_line.c_str()); return; } - WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); + + /* Code for getting the current configuration. * + * Official format: config -get "section property" * + * As a bonus it will set %CONFIG% to this value as well */ + if(cmd->FindString("-get",temp_line,true)) { + std::string temp2 = ""; + cmd->GetStringRemain(temp2);//So -get n1 n2= can be used without quotes + if(temp2 != "") temp_line = temp_line + " " + temp2; + + std::string::size_type space = temp_line.find(" "); + if(space == std::string::npos) { + WriteOut(MSG_Get("PROGRAM_CONFIG_GET_SYNTAX")); + return; + } + //Copy the found property to a new string and erase from templine (mind the space) + std::string prop = temp_line.substr(space+1); temp_line.erase(space); + + Section* sec = control->GetSection(temp_line.c_str()); + if(!sec) { + WriteOut(MSG_Get("PROGRAM_CONFIG_SECTION_ERROR"),temp_line.c_str()); + return; + } + char* val = sec->GetPropValue(prop.c_str()); + if(!val) { + WriteOut(MSG_Get("PROGRAM_CONFIG_NO_PROPERTY"),prop.c_str(),temp_line.c_str()); + return; + } + WriteOut("%s",val); + first_shell->SetEnv("CONFIG",val); + return; + } + + + + /* Code for the configuration changes * + * Official format: config -set "section property=value" * + * Accepted: without quotes and/or without -set and/or without section * + * and/or the "=" replaced by a " " */ + + if (cmd->FindString("-set",temp_line,true)) { //get all arguments + std::string temp2 = ""; + cmd->GetStringRemain(temp2);//So -set n1 n2=n3 can be used without quotes + if(temp2!="") temp_line = temp_line + " " + temp2; + } else if(!cmd->GetStringRemain(temp_line)) {//no set + WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); //and no arguments specified + return; + }; + //Wanted input: n1 n2=n3 + char copy[1024]; + strcpy(copy,temp_line.c_str()); + //seperate section from property + const char* temp = strchr(copy,' '); + if((temp && *temp) || (temp=strchr(copy,'=')) ) copy[temp++ - copy]= 0; + else { + WriteOut(MSG_Get("PROGRAM_CONFIG_USAGE")); + return; + } + //if n1 n2 n3 then replace last space with = + const char* sign = strchr(temp,'='); + if(!sign) { + sign = strchr(temp,' '); + if(sign) { + copy[sign - copy] = '='; + } else { + //2 items specified (no space nor = between n2 and n3 + //assume that they posted: property value + //Try to determine the section. + Section* sec=control->GetSectionFromProperty(copy); + if(!sec){ + if(control->GetSectionFromProperty(temp)) return; //Weird situation:ignore + WriteOut(MSG_Get("PROGRAM_CONFIG_PROPERTY_ERROR"),copy); + return; + } //Hack to allow config ems true + char buffer[1024];strcpy(buffer,copy);strcat(buffer,"=");strcat(buffer,temp); + sign = strchr(buffer,' '); + if(sign) buffer[sign - buffer] = '='; + strcpy(copy,sec->GetName()); + temp = buffer; + } + } + + /* Input processed. Now the real job starts + * copy contains the likely "sectionname" + * temp contains "property=value" + * the section is destroyed and a new input line is given to + * the configuration parser. Then the section is restarted. + */ + char* inputline = const_cast(temp); + Section* sec = 0; + sec = control->GetSection(copy); + if(!sec) { WriteOut(MSG_Get("PROGRAM_CONFIG_SECTION_ERROR"),copy);return;} + sec->ExecuteDestroy(false); + sec->HandleInputline(inputline); + sec->ExecuteInit(false); + return; } @@ -234,4 +337,8 @@ void PROGRAMS_Init(Section* sec) { MSG_Add("PROGRAM_CONFIG_FILE_ERROR","Can't open file %s\n"); MSG_Add("PROGRAM_CONFIG_USAGE","Config tool:\nUse -writeconf filename to write the current config.\nUse -writelang filename to write the current language strings.\n"); + MSG_Add("PROGRAM_CONFIG_SECTION_ERROR","Section %s doesn't exist.\n"); + MSG_Add("PROGRAM_CONFIG_PROPERTY_ERROR","No such section or property.\n"); + MSG_Add("PROGRAM_CONFIG_NO_PROPERTY","There is no property %s in section %s.\n"); + MSG_Add("PROGRAM_CONFIG_GET_SYNTAX","Correct syntax: config -get \"section property\".\n"); } diff --git a/src/misc/setup.cpp b/src/misc/setup.cpp index 547ae45..e960965 100644 --- a/src/misc/setup.cpp +++ b/src/misc/setup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: setup.cpp,v 1.23 2004/10/25 21:16:30 qbix79 Exp $ */ +/* $Id: setup.cpp,v 1.34 2006/03/12 21:26:22 qbix79 Exp $ */ #include "dosbox.h" #include "cross.h" @@ -32,51 +32,51 @@ using namespace std; void Prop_float::SetValue(char* input){ input=trim(input); - __value._float= atof(input); + value._float= static_cast(atof(input)); } void Prop_int::SetValue(char* input){ input=trim(input); - __value._int= atoi(input); + value._int= atoi(input); } void Prop_string::SetValue(char* input){ input=trim(input); - __value._string->assign(input); + value._string->assign(input); } void Prop_bool::SetValue(char* input){ input=lowcase(trim(input)); /* valid false entries: 0 ,d*, of* ,f* everything else gets true */ if((input[0]=='0') || (input[0]=='d') || ( (input[0]=='o') && (input[1]=='f')) || (input[0]=='f')){ - __value._bool=false; + value._bool=false; }else{ - __value._bool=true; + value._bool=true; } } void Prop_hex::SetValue(char* input){ input=trim(input); - if(!sscanf(input,"%X",&(__value._hex))) __value._hex=0; + if(!sscanf(input,"%X",&(value._hex))) value._hex=0; } void Prop_int::GetValuestring(char* str){ - sprintf(str,"%d",__value._int); + sprintf(str,"%d",value._int); } void Prop_string::GetValuestring(char* str){ - sprintf(str,"%s",__value._string->c_str()); + sprintf(str,"%s",value._string->c_str()); } void Prop_bool::GetValuestring(char* str){ - sprintf(str,"%s",__value._bool?"true":"false"); + sprintf(str,"%s",value._bool?"true":"false"); } void Prop_float::GetValuestring(char* str){ - sprintf(str,"%1.2f",__value._float); + sprintf(str,"%1.2f",value._float); } void Prop_hex::GetValuestring(char* str){ - sprintf(str,"%X",__value._hex); + sprintf(str,"%X",value._hex); } void Section_prop::Add_float(const char* _propname, float _value) { @@ -148,7 +148,8 @@ int Section_prop::Get_hex(const char* _propname){ void Section_prop::HandleInputline(char *gegevens){ char * rest=strrchr(gegevens,'='); - *rest=0; + if(!rest) return; + *rest = 0; gegevens=trim(gegevens); for(it tel=properties.begin();tel!=properties.end();tel++){ if(!strcasecmp((*tel)->propname.c_str(),gegevens)){ @@ -168,7 +169,17 @@ void Section_prop::PrintData(FILE* outfile){ } } - +static char buffer[1024]; +char* Section_prop::GetPropValue(const char* _property) { + for(it tel=properties.begin();tel!=properties.end();tel++){ + if(!strcasecmp((*tel)->propname.c_str(),_property)){ + (*tel)->GetValuestring(buffer); + return buffer; + } + } + return NULL; +} + void Section_line::HandleInputline(char* line){ data+=line; data+="\n"; @@ -178,13 +189,17 @@ void Section_line::PrintData(FILE* outfile) { fprintf(outfile,"%s",data.c_str()); } +char* Section_line::GetPropValue(const char* _property) { + return NULL; +} + void Config::PrintConfig(const char* configfilename){ char temp[50];char helpline[256]; FILE* outfile=fopen(configfilename,"w+t"); if(outfile==NULL) return; for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ /* Print out the Section header */ - strcpy(temp,(*tel)->sectionname.c_str()); + strcpy(temp,(*tel)->GetName()); lowcase(temp); fprintf(outfile,"[%s]\n",temp); upcase(temp); @@ -207,20 +222,23 @@ void Config::PrintConfig(const char* configfilename){ fclose(outfile); } -Section* Config::AddSection(const char* _name,void (*_initfunction)(Section*)){ - Section* blah = new Section(_name); - blah->AddInitFunction(_initfunction); + +Section_prop* Config::AddSection_prop(const char* _name,void (*_initfunction)(Section*),bool canchange){ + Section_prop* blah = new Section_prop(_name); + blah->AddInitFunction(_initfunction,canchange); sectionlist.push_back(blah); return blah; } -Section_prop* Config::AddSection_prop(const char* _name,void (*_initfunction)(Section*)){ - Section_prop* blah = new Section_prop(_name); - blah->AddInitFunction(_initfunction); - sectionlist.push_back(blah); - return blah; +Section_prop::~Section_prop() { +//ExecuteDestroy should be here else the destroy functions use destroyed properties + ExecuteDestroy(true); + /* Delete properties themself (properties stores the pointer of a prop */ + for(it prop = properties.begin(); prop != properties.end(); prop++) + delete (*prop); } + Section_line* Config::AddSection_line(const char* _name,void (*_initfunction)(Section*)){ Section_line* blah = new Section_line(_name); blah->AddInitFunction(_initfunction); @@ -235,6 +253,23 @@ void Config::Init(){ } } +void Section::ExecuteInit(bool initall) { + typedef std::list::iterator func_it; + for (func_it tel=initfunctions.begin(); tel!=initfunctions.end(); tel++) { + if(initall || (*tel).canchange) (*tel).function(this); + } +} + +void Section::ExecuteDestroy(bool destroyall) { + typedef std::list::iterator func_it; + for (func_it tel=destroyfunctions.begin(); tel!=destroyfunctions.end(); ) { + if(destroyall || (*tel).canchange) { + (*tel).function(this); + tel=destroyfunctions.erase(tel); //Remove destroyfunction once used + } else tel++; + } +} + Config::~Config() { reverse_it cnt=sectionlist.rbegin(); while (cnt!=sectionlist.rend()) { @@ -245,11 +280,18 @@ Config::~Config() { Section* Config::GetSection(const char* _sectionname){ for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ - if (!strcasecmp((*tel)->sectionname.c_str(),_sectionname)) return (*tel); + if (!strcasecmp((*tel)->GetName(),_sectionname)) return (*tel); } return NULL; } +Section* Config::GetSectionFromProperty(const char* prop) +{ + for (it tel=sectionlist.begin(); tel!=sectionlist.end(); tel++){ + if ((*tel)->GetPropValue(prop)) return (*tel); + } + return NULL; +} bool Config::ParseConfigFile(const char* configfilename){ ifstream in(configfilename); if (!in) return false; @@ -305,14 +347,18 @@ bool Config::ParseConfigFile(const char* configfilename){ void Config::ParseEnv(char ** envp) { for(char** env=envp; *env;env++) { char copy[1024]; - strncpy(copy,*env,1024); + safe_strncpy(copy,*env,1024); if(strncasecmp(copy,"DOSBOX_",7)) continue; char* sec_name = ©[7]; + if(!(*sec_name)) + continue; char* prop_name = strrchr(sec_name,'_'); + if(!prop_name || !(*prop_name)) + continue; *prop_name++=0; Section* sect = GetSection(sec_name); - if(!sect) + if(!sect) continue; sect->HandleInputline(prop_name); } @@ -404,6 +450,17 @@ bool CommandLine::FindStringRemain(char * name,std::string & value) { return true; } +bool CommandLine::GetStringRemain(std::string & value) { + if(!cmds.size()) return false; + + cmd_it it=cmds.begin();value=(*it++); + for(;it != cmds.end();it++) { + value+=" "; + value+=(*it); + } + return true; +} + unsigned int CommandLine::GetCount(void) { return cmds.size(); @@ -449,4 +506,3 @@ CommandLine::CommandLine(char * name,char * cmdline) { } if (inword || inquote) cmds.push_back(str); } - diff --git a/src/misc/support.cpp b/src/misc/support.cpp index 80a9d5b..0ac9ad2 100644 --- a/src/misc/support.cpp +++ b/src/misc/support.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: support.cpp,v 1.27 2004/10/24 10:03:29 qbix79 Exp $ */ +/* $Id: support.cpp,v 1.29 2006/02/09 11:47:57 qbix79 Exp $ */ #include #include diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in index 6b134fb..9758a77 100644 --- a/src/platform/Makefile.in +++ b/src/platform/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -84,6 +84,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -109,10 +111,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ @@ -196,7 +200,13 @@ uninstall-info-am: # (which will cause the Makefiles to be regenerated when you run `make'); # (2) otherwise, pass the desired values on the `make' command line. $(RECURSIVE_TARGETS): - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ list='$(SUBDIRS)'; for subdir in $$list; do \ @@ -208,7 +218,7 @@ $(RECURSIVE_TARGETS): local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ @@ -216,7 +226,13 @@ $(RECURSIVE_TARGETS): mostlyclean-recursive clean-recursive distclean-recursive \ maintainer-clean-recursive: - @set fnord $$MAKEFLAGS; amf=$$2; \ + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ dot_seen=no; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ @@ -237,7 +253,7 @@ maintainer-clean-recursive: local_target="$$target"; \ fi; \ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + || eval $$failcom; \ done && test -z "$$fail" tags-recursive: list='$(SUBDIRS)'; for subdir in $$list; do \ diff --git a/src/platform/visualc/Makefile.in b/src/platform/visualc/Makefile.in index 5ddf338..c258d56 100644 --- a/src/platform/visualc/Makefile.in +++ b/src/platform/visualc/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -75,6 +75,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -100,10 +102,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/platform/visualc/config.h b/src/platform/visualc/config.h index d31afd0..f80fb7c 100644 --- a/src/platform/visualc/config.h +++ b/src/platform/visualc/config.h @@ -33,6 +33,12 @@ /* Enable the FPU module, still only for beta testing */ #define C_FPU 1 +/* Define to 1 to use a x86 assembly fpu core */ +#define C_FPU_X86 1 + +/* Define to 1 to use a unaligned memory access */ +#define C_UNALIGNED_MEMORY 1 + /* environ is defined */ #define ENVIRON_INCLUDED 1 @@ -46,6 +52,7 @@ #define C_DIRECTSERIAL 1 #define GCC_ATTRIBUTE(x) /* attribute not supported */ +#define GCC_UNLIKELY(x) (x) typedef double Real64; /* The internal types */ diff --git a/src/shell/Makefile.in b/src/shell/Makefile.in index 93a96dd..33a53df 100644 --- a/src/shell/Makefile.in +++ b/src/shell/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -96,6 +96,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -121,10 +123,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index 097b9c4..6465504 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,40 +16,115 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: shell.cpp,v 1.53 2004/11/13 12:19:43 qbix79 Exp $ */ +/* $Id: shell.cpp,v 1.72 2006/02/26 15:58:49 qbix79 Exp $ */ #include #include #include +#include "dosbox.h" +#include "regs.h" #include "setup.h" #include "shell.h" +#include "callback.h" +#include "support.h" Bitu call_shellstop; +/* Larger scope so shell_del autoexec can use it to + * remove things from the environment */ +Program * first_shell = 0; static Bitu shellstop_handler(void) { return CBRET_STOP; } static void SHELL_ProgramStart(Program * * make) { - *make=new DOS_Shell; + *make = new DOS_Shell; } #define AUTOEXEC_SIZE 4096 -static char autoexec_data[AUTOEXEC_SIZE]={0}; +static char autoexec_data[AUTOEXEC_SIZE] = { 0 }; +static std::list autoexec_strings; +typedef std::list::iterator auto_it; -void SHELL_AddAutoexec(char * line,...) { - char buf[2048]; +void VFILE_Remove(const char *name); + +void AutoexecObject::Install(char* line,...) { + if(GCC_UNLIKELY(installed)) E_Exit("autoexec: allready created %s",buf); + installed = true; va_list msg; va_start(msg,line); vsprintf(buf,line,msg); va_end(msg); + autoexec_strings.push_back(std::string(buf)); - size_t auto_len=strlen(autoexec_data); - if ((auto_len+strlen(line)+3)>AUTOEXEC_SIZE) { - E_Exit("SYSTEM:Autoexec.bat file overflow"); + this->CreateAutoexec(); + + //autoexec.bat is normally created AUTOEXEC_Init. + //But if we are allready running (first_shell) + //we have to update the envirionment to display changes + + if(first_shell) { + char buf2[256]; strcpy(buf2,buf);//used in shell.h + if((strncasecmp(buf2,"set ",4) == 0) && (strlen(buf2) > 4)){ + char* after_set = buf2 + 4;//move to variable that is being set + char* test = strpbrk(after_set,"="); + if(!test) {first_shell->SetEnv(after_set,"");return;} + *test++ = 0; + //If the shell is running/exists update the environment + first_shell->SetEnv(after_set,test); + } } - sprintf((autoexec_data+auto_len),"%s\r\n",buf); +} + +void AutoexecObject::InstallBefore(char* line,...) { + if(GCC_UNLIKELY(installed)) E_Exit("autoexec: allready created %s",buf); + installed = true; + va_list msg; + + va_start(msg,line); + vsprintf(buf,line,msg); + va_end(msg); + autoexec_strings.push_front(std::string(buf)); + this->CreateAutoexec(); +} + +void AutoexecObject::CreateAutoexec(void) { + /* Remove old autoexec.bat if the shell exists */ + if(first_shell) VFILE_Remove("AUTOEXEC.BAT"); + + //Create a new autoexec.bat + autoexec_data[0] = 0; + size_t auto_len; + for(auto_it it= autoexec_strings.begin(); it != autoexec_strings.end(); it++) { + auto_len = strlen(autoexec_data); + if ((auto_len+strlen((*it).c_str())+3)>AUTOEXEC_SIZE) { + E_Exit("SYSTEM:Autoexec.bat file overflow"); + } + sprintf((autoexec_data+auto_len),"%s\r\n",(*it).c_str()); + } + if(first_shell) VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data)); +} + +AutoexecObject::~AutoexecObject(){ + if(!installed) return; + + // Remove the line from the autoexecbuffer and update environment + for(auto_it it = autoexec_strings.begin(); it != autoexec_strings.end(); ) { + if((*it) == buf) { + it = autoexec_strings.erase(it); + // If it's a environment variable remove it from there as well + if((strncasecmp(buf,"set ",4) == 0) && (strlen(buf) > 4)){ + char* after_set = buf + 4;//move to variable that is being set + char* test = strpbrk(after_set,"="); + if(!test) continue; + *test = 0; + //If the shell is running/exists update the environment + if(first_shell) first_shell->SetEnv(after_set,""); + } + } else it++; + } + this->CreateAutoexec(); } DOS_Shell::DOS_Shell():Program(){ @@ -61,18 +136,24 @@ DOS_Shell::DOS_Shell():Program(){ completion_start = NULL; } - - - Bitu DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn,bool * append) { char * lr=s; char * lw=s; char ch; Bitu num=0; + bool quote = false; while ( (ch=*lr++) ) { + if(quote && ch != '"') { /* don't parse redirection within quotes. Not perfect yet. Escaped quotes will mess the count up */ + *lw++ = ch; + continue; + } + switch (ch) { + case '"': + quote = !quote; + break; case '>': *append=((*lr)=='>'); if (*append) lr++; @@ -80,6 +161,8 @@ Bitu DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn,bool * append) { if (*ofn) free(*ofn); *ofn=lr; while (*lr && *lr!=' ') lr++; + //if it ends on a : => remove it. + if((*ofn != lr) && (lr[-1] == ':')) lr[-1] = 0; if(*lr && *(lr+1)) *lr++=0; else @@ -91,6 +174,7 @@ Bitu DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn,bool * append) { lr=ltrim(lr); *ifn=lr; while (*lr && *lr!=' ') lr++; + if((*ifn != lr) && (lr[-1] == ':')) lr[-1] = 0; if(*lr && *(lr+1)) *lr++=0; else @@ -110,49 +194,67 @@ Bitu DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn,bool * append) { void DOS_Shell::ParseLine(char * line) { LOG(LOG_EXEC,LOG_ERROR)("Parsing command line: %s",line); /* Check for a leading @ */ - if (line[0]=='@') line[0]=' '; - line=trim(line); + if (line[0] == '@') line[0] = ' '; + line = trim(line); /* Do redirection and pipe checks */ - char * in=0; - char * out=0; + char * in = 0; + char * out = 0; - Bit16u old_in,old_out; Bit16u dummy,dummy2; - Bitu num=0; /* Number of commands in this line */ + Bit32u bigdummy = 0; + Bitu num = 0; /* Number of commands in this line */ bool append; - + bool normalstdin = false; /* wether stdin/out are open on start. */ + bool normalstdout = false; /* Bug: Assumed is they are "con" */ + num = GetRedirection(line,&in, &out,&append); if (num>1) LOG_MSG("SHELL:Multiple command on 1 line not supported"); -// if (in || num>1) DOS_DuplicateEntry(0,&old_in); - + if (in || out) { + normalstdin = (psp->GetFileHandle(0) != 0xff); + normalstdout = (psp->GetFileHandle(1) != 0xff); + } if (in) { if(DOS_OpenFile(in,0,&dummy)) { //Test if file exists DOS_CloseFile(dummy); LOG_MSG("SHELL:Redirect input from %s",in); - DOS_CloseFile(0); //Close stdin - DOS_OpenFile(in,0,&dummy);//Open new stdin + if(normalstdin) DOS_CloseFile(0); //Close stdin + DOS_OpenFile(in,0,&dummy); //Open new stdin } } if (out){ LOG_MSG("SHELL:Redirect output to %s",out); - DOS_CloseFile(1); + if(normalstdout) DOS_CloseFile(1); + if(!normalstdin && !in) DOS_OpenFile("con",2,&dummy); + bool status = true; /* Create if not exist. Open if exist. Both in read/write mode */ - if(!DOS_OpenFileExtended(out,2,2,0x11,&dummy,&dummy2)) - DOS_OpenFile("con",2,&dummy); //Read only file, open con again + if(append) { + if( (status = DOS_OpenFile(out,2,&dummy)) ) { + DOS_SeekFile(1,&bigdummy,DOS_SEEK_END); + } else { + status = DOS_CreateFile(out,2,&dummy); //Create if not exists. + } + } + else + status = DOS_OpenFileExtended(out,2,2,0x12,&dummy,&dummy2); + + if(!status && normalstdout) DOS_OpenFile("con",2,&dummy); //Read only file, open con again + if(!normalstdin && !in) DOS_CloseFile(0); } /* Run the actual command */ DoCommand(line); /* Restore handles */ if(in) { DOS_CloseFile(0); - DOS_OpenFile("con",2,&dummy); + if(normalstdin) DOS_OpenFile("con",2,&dummy); free(in); } - if(out) { + if(out) { DOS_CloseFile(1); - DOS_OpenFile("con",2,&dummy); + if(!normalstdin) DOS_OpenFile("con",2,&dummy); + if(normalstdout) DOS_OpenFile("con",2,&dummy); + if(!normalstdin) DOS_CloseFile(0); free(out); } } @@ -166,7 +268,7 @@ void DOS_Shell::RunInternal(void) while(bf && bf->ReadLine(input_line)) { if (echo) { - if (input_line[0]!='@') { + if (input_line[0] != '@') { ShowPrompt(); WriteOut(input_line); WriteOut("\n"); @@ -190,7 +292,12 @@ void DOS_Shell::Run(void) { return; } /* Start a normal shell and check for a first command init */ - WriteOut(MSG_Get("SHELL_STARTUP")); + WriteOut(MSG_Get("SHELL_STARTUP_BEGIN")); +#if C_DEBUG + WriteOut(MSG_Get("SHELL_STARTUP_DEBUG")); +#endif + if(machine == MCH_CGA) WriteOut(MSG_Get("SHELL_STARTUP_CGA")); + WriteOut(MSG_Get("SHELL_STARTUP_END")); if (cmd->FindString("/INIT",line,true)) { strcpy(input_line,line.c_str()); line.erase(); @@ -222,55 +329,91 @@ void DOS_Shell::SyntaxError(void) { WriteOut(MSG_Get("SHELL_SYNTAXERROR")); } +class AUTOEXEC:public Module_base { +private: + AutoexecObject autoexec[16]; + AutoexecObject autoexec_echo; +public: + AUTOEXEC(Section* configuration):Module_base(configuration) { + /* Register a virtual AUOEXEC.BAT file */ + std::string line; + Section_line * section=static_cast(configuration); + /* add stuff from the configfile unless -noautexec is specified. */ + char * extra=const_cast(section->data.c_str()); + if (extra && !control->cmdline->FindExist("-noautoexec",true)) { + /* detect if "echo off" is the first line */ + bool echo_off = !strncasecmp(extra,"echo off",8); + if (!echo_off) echo_off = !strncasecmp(extra,"@echo off",9); + + /* if "echo off" add it to the front of autoexec.bat */ + if(echo_off) autoexec_echo.InstallBefore("@echo off"); + + /* Install the stuff from the configfile */ + autoexec[0].Install("%s",extra); + } + + /* Check to see for extra command line options to be added (before the command specified on commandline) */ + /* Maximum of extra commands: 10 */ + Bitu i = 1; + while (control->cmdline->FindString("-c",line,true) && (i <= 11)) + autoexec[i++].Install((char *)line.c_str()); + + /* Check for the -exit switch which causes dosbox to when the command on the commandline has finished */ + bool addexit = control->cmdline->FindExist("-exit",true); + + /* Check for first command being a directory or file */ + char buffer[CROSS_LEN]; + char cross_filesplit[2] = {CROSS_FILESPLIT , 0}; + if (control->cmdline->FindCommand(1,line)) { + struct stat test; + strcpy(buffer,line.c_str()); + if (stat(buffer,&test)){ + getcwd(buffer,CROSS_LEN); + strcat(buffer,cross_filesplit); + strcat(buffer,line.c_str()); + if (stat(buffer,&test)) goto nomount; + } + if (test.st_mode & S_IFDIR) { + autoexec[12].Install("MOUNT C \"%s\"",buffer); + autoexec[13].Install("C:"); + } else { + char* name = strrchr(buffer,CROSS_FILESPLIT); + if (!name) { //Only a filename + line = buffer; + getcwd(buffer,CROSS_LEN); + strcat(buffer,cross_filesplit); + strcat(buffer,line.c_str()); + if(stat(buffer,&test)) goto nomount; + name = strrchr(buffer,CROSS_FILESPLIT); + if(!name) goto nomount; + } + *name++ = 0; + if (access(buffer,F_OK)) goto nomount; + autoexec[12].Install("MOUNT C \"%s\"",buffer); + autoexec[13].Install("C:"); + upcase(name); + if(strstr(name,".BAT") == 0) { + autoexec[14].Install(name); + } else { + /* BATch files are called else exit will not work */ + char call[CROSS_LEN] = { 0 }; + strcpy(call,"CALL "); + strcat(call,name); + autoexec[14].Install(call); + } + if(addexit) autoexec[15].Install("exit"); + } + } +nomount: + VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data)); + } +}; + +static AUTOEXEC* test; void AUTOEXEC_Init(Section * sec) { - /* Register a virtual AUOEXEC.BAT file */ - std::string line; - Section_line * section=static_cast(sec); - char * extra=(char *)section->data.c_str(); - if (extra) SHELL_AddAutoexec("%s",extra); - /* Check to see for extra command line options to be added (before the command specified on commandline) */ - while (control->cmdline->FindString("-c",line,true)) - SHELL_AddAutoexec((char *)line.c_str()); - - /* Check for the -exit switch which causes dosbox to when the command on the commandline has finished */ - bool addexit = control->cmdline->FindExist("-exit",true); - - /* Check for first command being a directory or file */ - char buffer[CROSS_LEN]; - if (control->cmdline->FindCommand(1,line)) { - struct stat test; - strcpy(buffer,line.c_str()); - if (stat(buffer,&test)){ - getcwd(buffer,CROSS_LEN); - strcat(buffer,line.c_str()); - if (stat(buffer,&test)) goto nomount; - } - if (test.st_mode & S_IFDIR) { - SHELL_AddAutoexec("MOUNT C \"%s\"",buffer); - SHELL_AddAutoexec("C:"); - } else { - char * name=strrchr(buffer,CROSS_FILESPLIT); - if (!name) goto nomount; - *name++=0; - if (access(buffer,F_OK)) goto nomount; - SHELL_AddAutoexec("MOUNT C \"%s\"",buffer); - SHELL_AddAutoexec("C:"); - upcase(name); - if(strstr(name,".BAT")==0) { - SHELL_AddAutoexec(name); - } else { - char call[CROSS_LEN] = { 0 }; - strcpy(call,"CALL "); - strcat(call,name); - SHELL_AddAutoexec(call); - } - if(addexit) SHELL_AddAutoexec("exit"); - } - } -nomount: - VFILE_Register("AUTOEXEC.BAT",(Bit8u *)autoexec_data,strlen(autoexec_data)); + test = new AUTOEXEC(sec); } static char * path_string="PATH=Z:\\"; @@ -286,6 +429,7 @@ void SHELL_Init() { MSG_Add("SHELL_CMD_ECHO_OFF","ECHO is off.\n"); MSG_Add("SHELL_ILLEGAL_SWITCH","Illegal switch: %s.\n"); MSG_Add("SHELL_CMD_CHDIR_ERROR","Unable to change to: %s.\n"); + MSG_Add("SHELL_CMD_CHDIR_HINT","To change to different drive type \033[31m%c:\033[0m\n"); MSG_Add("SHELL_CMD_MKDIR_ERROR","Unable to make: %s.\n"); MSG_Add("SHELL_CMD_RMDIR_ERROR","Unable to remove: %s.\n"); MSG_Add("SHELL_CMD_DEL_ERROR","Unable to delete: %s.\n"); @@ -302,7 +446,7 @@ void SHELL_Init() { MSG_Add("SHELL_CMD_DIR_INTRO","Directory of %s.\n"); MSG_Add("SHELL_CMD_DIR_BYTES_USED","%5d File(s) %17s Bytes.\n"); MSG_Add("SHELL_CMD_DIR_BYTES_FREE","%5d Dir(s) %17s Bytes free.\n"); - MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\nYou must \033[31mmount\033[0m it first. Type \033[1;33mintro\033[0m for more information.\n"); + MSG_Add("SHELL_EXECUTE_DRIVE_NOT_FOUND","Drive %c does not exist!\nYou must \033[31mmount\033[0m it first. Type \033[1;33mintro\033[0m or \033[1;33mintro mount\033[0m for more information.\n"); MSG_Add("SHELL_EXECUTE_ILLEGAL_COMMAND","Illegal command: %s.\n"); MSG_Add("SHELL_CMD_PAUSE","Press any key to continue.\n"); MSG_Add("SHELL_CMD_PAUSE_HELP","Waits for 1 keystroke to continue.\n"); @@ -311,7 +455,7 @@ void SHELL_Init() { MSG_Add("SHELL_CMD_SUBST_NO_REMOVE","Removing drive not supported. Doing nothing.\n"); MSG_Add("SHELL_CMD_SUBST_FAILURE","SUBST failed. You either made an error in your commandline or the target drive is already used.\nIt's only possible to use SUBST on Local drives"); - MSG_Add("SHELL_STARTUP", + MSG_Add("SHELL_STARTUP_BEGIN", "\033[44;1m\xC9\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBB\n" @@ -324,18 +468,23 @@ void SHELL_Init() { "\xBA To activate the keymapper \033[31mctrl-F1\033[37m. \xBA\n" "\xBA For more information read the \033[36mREADME\033[37m file in the DOSBox directory. \xBA\n" "\xBA \xBA\n" -#if C_DEBUG - "\xBA Press \033[31mPause\033[37m to enter the debugger or start the exe with \033[33mDEBUG\033[37m. \xBA\n" - "\xBA \xBA\n" -#endif - "\xBA \033[32mHAVE FUN!\033[37m \xBA\n" - "\xBA \033[32mThe DOSBox Team\033[37m \xBA\n" - "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" - "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC\033[0m\n" - //"\n" //Breaks the startup message if you type a mount and a drive change. ); - + MSG_Add("SHELL_STARTUP_CGA","\xBA DOSBox supports Composite CGA mode. \xBA\n" + "\xBA Use \033[31m(alt-)F11\033[37m to change the colours when in this mode. \xBA\n" + "\xBA \xBA\n" + ); + MSG_Add("SHELL_STARTUP_DEBUG", + "\xBA Press \033[31malt-Pause\033[37m to enter the debugger or start the exe with \033[33mDEBUG\033[37m. \xBA\n" + "\xBA \xBA\n" + ); + MSG_Add("SHELL_STARTUP_END", + "\xBA \033[32mHAVE FUN!\033[37m \xBA\n" + "\xBA \033[32mThe DOSBox Team\033[37m \xBA\n" + "\xC8\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD" + "\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xBC\033[0m\n" + //"\n" //Breaks the startup message if you type a mount and a drive change. + ); MSG_Add("SHELL_CMD_CHDIR_HELP","Change Directory.\n"); MSG_Add("SHELL_CMD_CLS_HELP","Clear screen.\n"); MSG_Add("SHELL_CMD_DIR_HELP","Directory View.\n"); @@ -371,11 +520,20 @@ void SHELL_Init() { PROGRAMS_MakeFile("COMMAND.COM",SHELL_ProgramStart); /* Now call up the shell for the first time */ - Bit16u psp_seg=DOS_GetMemory(16+1)+1; + Bit16u psp_seg=DOS_GetMemory(16+3)+1; Bit16u env_seg=DOS_GetMemory(1+(4096/16))+1; Bit16u stack_seg=DOS_GetMemory(2048/16); SegSet16(ss,stack_seg); reg_sp=2046; + + /* Set up int 24 and psp (Telarium games) */ + real_writeb(psp_seg+16+1,0,0xea); /* far jmp */ + real_writed(psp_seg+16+1,1,real_readd(0,0x24*4)); + real_writed(0,0x24*4,((Bit32u)psp_seg<<16) | ((16+1)<<4)); + + /* Set up int 23 to "int 20" in the psp. Fixes what.exe */ + real_writed(0,0x23*4,((Bit32u)psp_seg<<16)); + /* Setup MCB and the environment */ DOS_MCB envmcb((Bit16u)(env_seg-1)); envmcb.SetPSPSeg(psp_seg); @@ -394,12 +552,20 @@ void SHELL_Init() { DOS_PSP psp(psp_seg); psp.MakeNew(0); dos.psp(psp_seg); + + /* The start of the filetable in the psp must look like this: + * 01 01 01 00 02 + * In order to achieve this: First open 2 files. Close the first and + * duplicate the second (so the entries get 01) */ Bit16u dummy=0; DOS_OpenFile("CON",2,&dummy);/* STDIN */ DOS_OpenFile("CON",2,&dummy);/* STDOUT */ - DOS_OpenFile("CON",2,&dummy);/* STDERR */ + DOS_CloseFile(0); /* Close STDIN */ + DOS_ForceDuplicateEntry(1,0);/* "new" STDIN */ + DOS_ForceDuplicateEntry(1,2);/* STDERR */ DOS_OpenFile("CON",2,&dummy);/* STDAUX */ DOS_OpenFile("CON",2,&dummy);/* STDPRN */ + psp.SetParent(psp_seg); /* Set the environment */ psp.SetEnvironment(env_seg); @@ -413,8 +579,9 @@ void SHELL_Init() { dos.dta(RealMake(psp_seg,0x80)); dos.psp(psp_seg); - Program * new_program; - SHELL_ProgramStart(&new_program); - new_program->Run(); - delete new_program; + + SHELL_ProgramStart(&first_shell); + first_shell->Run(); + delete first_shell; + first_shell = 0;//Make clear that it shouldn't be used anymore } diff --git a/src/shell/shell_batch.cpp b/src/shell/shell_batch.cpp index c1742d7..445ede5 100644 --- a/src/shell/shell_batch.cpp +++ b/src/shell/shell_batch.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,19 +16,19 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: shell_batch.cpp,v 1.14 2004/08/04 09:12:57 qbix79 Exp $ */ +/* $Id: shell_batch.cpp,v 1.20 2006/02/23 08:13:14 qbix79 Exp $ */ #include #include #include "shell.h" - +#include "support.h" BatchFile::BatchFile(DOS_Shell * host,char * name, char * cmd_line) { prev=host->bf; echo=host->echo; shell=host; - cmd=new CommandLine(0,cmd_line); + cmd=new CommandLine(name,cmd_line); if (!DOS_OpenFile(name,128,&file_handle)) { //TODO Come up with something better E_Exit("SHELL:Can't open BatchFile"); @@ -51,7 +51,11 @@ emptyline: n=1; DOS_ReadFile(file_handle,&c,&n); if (n>0) { - if (c>31 || c==0x1b || c=='\t') + /* Why are we filtering this ? + * Exclusion list: tab for batch files + * escape for ansi + * backspace for alien odyssey */ + if (c>31 || c==0x1b || c=='\t' || c==8) *cmd_write++=c; } } while (c!='\n' && n); @@ -70,12 +74,19 @@ emptyline: env_write=env_name; if (*cmd_read=='%') { cmd_read++; - if (cmd_read[0]=='%') { + if (cmd_read[0] == '%') { cmd_read++; *cmd_write++='%'; } - size_t len=strspn(cmd_read,"0123456789"); - if (len) { + if (cmd_read[0] == '0') { /* Handle %0 */ + const char *file_name = cmd->GetFileName(); + cmd_read++; + strcpy(cmd_write,file_name); + cmd_write+=strlen(file_name); + continue; + } + size_t len=strspn(cmd_read,"123456789"); + if (len) { /* Handle %1 %2 .. %9 */ memcpy(env_name,cmd_read,len); env_name[len]=0;cmd_read+=len; len=atoi(env_name); @@ -126,9 +137,10 @@ again: } } while (c!='\n' && n); *cmd_write++=0; - if (cmd[0]==':') { - char *nospace = trim(cmd+1); - if (strcasecmp(nospace,where)==0) return true; + char *nospace = trim(cmd); + if (nospace[0] == ':') { + char* nonospace = trim(nospace+1); + if (strcasecmp(nonospace,where)==0) return true; } if (!n) { delete this; diff --git a/src/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index fe83f67..cb3a604 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: shell_cmds.cpp,v 1.50 2004/11/13 12:06:39 qbix79 Exp $ */ +/* $Id: shell_cmds.cpp,v 1.62 2006/02/24 11:50:11 qbix79 Exp $ */ #include #include @@ -25,6 +25,7 @@ #include "callback.h" #include "regs.h" #include "../dos/drives.h" +#include "support.h" static SHELL_Cmd cmd_list[]={ { "CHDIR", 0, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP"}, @@ -59,6 +60,20 @@ static SHELL_Cmd cmd_list[]={ { "PATH", 1, &DOS_Shell::CMD_PATH, "SHELL_CMD_PATH_HELP"}, {0,0,0,0} }; +bool DOS_Shell::CheckConfig(char* cmd,char*line) { + Section* test = control->GetSectionFromProperty(cmd); + if(!test) return false; + if(line && !line[0]) { + char* val = test->GetPropValue(cmd); + if(val) WriteOut("%s\n",val); + return true; + } + char newcom[1024]; newcom[0] = 0; strcpy(newcom,"z:\\config "); + strcat(newcom,test->GetName()); strcat(newcom," "); + strcat(newcom,cmd);strcat(newcom,line); + DoCommand(newcom); + return true; +} void DOS_Shell::DoCommand(char * line) { /* First split the line into command and arguments */ @@ -95,7 +110,9 @@ void DOS_Shell::DoCommand(char * line) { cmd_index++; } /* This isn't an internal command execute it */ - Execute(cmd,line); + if(Execute(cmd,line)) return; + if(CheckConfig(cmd,line)) return; + WriteOut(MSG_Get("SHELL_EXECUTE_ILLEGAL_COMMAND"),cmd); } @@ -159,7 +176,32 @@ void DOS_Shell::CMD_RENAME(char * args){ if(!*args) {SyntaxError();return;} if((strchr(args,'*')!=NULL) || (strchr(args,'?')!=NULL) ) { WriteOut(MSG_Get("SHELL_CMD_NO_WILD"));return;} char * arg1=StripWord(args); - DOS_Rename(arg1,args); + char* slash = strrchr(arg1,'\\'); + if(slash) { + slash++; + //If directory specified (crystal caves installer) + // rename from c:\X : rename c:\abc.exe abc.shr. File must appear in C:\ + + char dir_source[DOS_PATHLENGTH]={0}; + //Copy first and then modify, makes GCC happy + strcpy(dir_source,arg1); + char* dummy = strrchr(dir_source,'\\'); + *dummy=0; + + if((strlen(dir_source) == 2) && (dir_source[1] == ':')) + strcat(dir_source,"\\"); //X: add slash + + char dir_current[DOS_PATHLENGTH]; + DOS_GetCurrentDir(0,dir_current); + if(!DOS_ChangeDir(dir_source)) { + WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); + return; + } + DOS_Rename(slash,args); + DOS_ChangeDir(dir_current); + } else { + DOS_Rename(arg1,args); + } } void DOS_Shell::CMD_ECHO(char * args){ @@ -196,6 +238,8 @@ void DOS_Shell::CMD_CHDIR(char * args) { char dir[DOS_PATHLENGTH]; DOS_GetCurrentDir(0,dir); WriteOut("%c:\\%s\n",drive,dir); + } else if(strlen(args) == 2 && args[1]==':') { + WriteOut(MSG_Get("SHELL_CMD_CHDIR_HINT"),toupper(*reinterpret_cast(&args[0]))); } else if (!DOS_ChangeDir(args)) { WriteOut(MSG_Get("SHELL_CMD_CHDIR_ERROR"),args); } @@ -226,12 +270,18 @@ void DOS_Shell::CMD_RMDIR(char * args) { }; static void FormatNumber(Bitu num,char * buf) { - Bitu numm,numk,numb; + Bitu numm,numk,numb,numg; numb=num % 1000; num/=1000; numk=num % 1000; num/=1000; - numm=num; + numm=num % 1000; + num/=1000; + numg=num; + if (numg) { + sprintf(buf,"%d,%03d,%03d,%03d",numg,numm,numk,numb); + return; + }; if (numm) { sprintf(buf,"%d,%03d,%03d",numm,numk,numb); return; @@ -474,7 +524,7 @@ void DOS_Shell::CMD_COPY(char * args) { if (DOS_CreateFile(nameTarget,0,&targetHandle)) { // Copy - Bit8u buffer[0x8000]; + static Bit8u buffer[0x8000]; // static, otherwise stack overflow possible. bool failed = false; Bit16u toread = 0x8000; do { @@ -514,21 +564,52 @@ void DOS_Shell::CMD_SET(char * args) { WriteOut("%s\n",line.c_str()); } else { *p++=0; - if (!SetEnv(args,p)) { + /* parse p for envirionment variables */ + char parsed[CMD_MAXLINE]; + char* p_parsed = parsed; + while(*p) { + if(*p != '%') *p_parsed++ = *p++; //Just add it (most likely path) + else if( *(p+1) == '%') { + *p_parsed++ = '%'; p += 2; //%% => % + } else { + char * second = strchr(++p,'%'); + if(!second) continue; *second++ = 0; + std::string temp; + if (GetEnvStr(p,temp)) { + std::string::size_type equals = temp.find('='); + if (equals == std::string::npos) continue; + strcpy(p_parsed,temp.substr(equals+1).c_str()); + p_parsed += strlen(p_parsed); + } + p = second; + } + } + *p_parsed = 0; + /* Try setting the variable */ + if (!SetEnv(args,parsed)) { WriteOut(MSG_Get("SHELL_CMD_SET_OUT_OF_SPACE")); } } } - void DOS_Shell::CMD_IF(char * args) { StripSpaces(args); bool has_not=false; char * comp=strchr(args,'='); if (comp) { - if (comp[1]!='=') {SyntaxError();return;} - *comp++=' '; - *comp++=' '; + if (comp[1] == '=') { + *comp++ = ' '; + *comp++ = ' '; + } else if(strncasecmp(args,"ERRORLEVEL",10) == 0) { + /* this is in general a syntax error except for errorlevel */ + *comp++ = ' '; + while(*comp++ == ' ') + ; /*nothing */ + } else if(strncasecmp(args," set ",5) !=0) { + /* if cond set a=b is allowed as well */ + SyntaxError(); + return; + } }; char * word=StripWord(args); if (strcasecmp(word,"NOT")==0) { @@ -685,7 +766,17 @@ void DOS_Shell::CMD_SUBST (char * args) { } void DOS_Shell::CMD_LOADHIGH(char *args){ - this->ParseLine(args); + Bit16u umb_start=dos_infoblock.GetStartOfUMBChain(); + Bit8u umb_flag=dos_infoblock.GetUMBChainState(); + Bit8u old_memstrat=DOS_GetMemAllocStrategy()&0xff; + if (umb_start==0x9fff) { + if ((umb_flag&1)==0) DOS_LinkUMBsToMemChain(1); + DOS_SetMemAllocStrategy(0x80); // search in UMBs first + this->ParseLine(args); + Bit8u current_umb_flag=dos_infoblock.GetUMBChainState(); + if ((current_umb_flag&1)!=(umb_flag&1)) DOS_LinkUMBsToMemChain(umb_flag); + DOS_SetMemAllocStrategy(old_memstrat); // restore strategy + } else this->ParseLine(args); } void DOS_Shell::CMD_CHOICE(char * args){ diff --git a/src/shell/shell_misc.cpp b/src/shell/shell_misc.cpp index e6b1f01..fc8a06f 100644 --- a/src/shell/shell_misc.cpp +++ b/src/shell/shell_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2004 The DOSBox Team + * Copyright (C) 2002-2006 The DOSBox Team * * 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 @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: shell_misc.cpp,v 1.33 2004/10/20 19:53:50 qbix79 Exp $ */ +/* $Id: shell_misc.cpp,v 1.43 2006/02/28 19:41:27 qbix79 Exp $ */ #include #include @@ -24,6 +24,8 @@ #include //std::front_inserter #include "shell.h" #include "regs.h" +#include "callback.h" +#include "support.h" void DOS_Shell::ShowPrompt(void) { Bit8u drive=DOS_GetDefaultDrive()+'A'; @@ -54,7 +56,12 @@ void DOS_Shell::InputCommand(char * line) { while (size) { dos.echo=false; - DOS_ReadFile(input_handle,&c,&n); + while(!DOS_ReadFile(input_handle,&c,&n)) { + Bit16u dummy; + DOS_CloseFile(input_handle); + DOS_OpenFile("con",2,&dummy); + LOG(LOG_MISC,LOG_ERROR)("Reopening the input handle.This is a bug!"); + } if (!n) { size=0; //Kill the while loop continue; @@ -76,6 +83,7 @@ void DOS_Shell::InputCommand(char * line) { } str_len = str_index = it_history->length(); size = CMD_MAXLINE - str_index - 2; + line[str_len] = 0; } break; @@ -92,6 +100,19 @@ void DOS_Shell::InputCommand(char * line) { } break; + case 0x47: /* HOME */ + while (str_index) { + outc(8); + str_index--; + } + break; + + case 0x4F: /* END */ + while (str_index < str_len) { + outc(line[str_index++]); + } + break; + case 0x48: /* UP */ if (l_history.empty() || it_history == l_history.end()) break; @@ -105,7 +126,6 @@ void DOS_Shell::InputCommand(char * line) { size = CMD_MAXLINE - str_index - 2; DOS_WriteFile(STDOUT, (Bit8u *)line, &len); it_history ++; - break; case 0x50: /* DOWN */ @@ -171,7 +191,7 @@ void DOS_Shell::InputCommand(char * line) { // moves the cursor left while (str_remain--) outc(8); } - if (strlen(line) == 0 && l_completion.size()) l_completion.clear(); + if (l_completion.size()) l_completion.clear(); break; case 0x0a: /* New Line not handled */ /* Don't care */ @@ -207,14 +227,26 @@ void DOS_Shell::InputCommand(char * line) { char mask[DOS_PATHLENGTH]; if (completion_start) { strcpy(mask, completion_start); + char* dot_pos=strrchr(mask,'.'); + char* bs_pos=strrchr(mask,'\\'); + char* fs_pos=strrchr(mask,'/'); + char* cl_pos=strrchr(mask,':'); // not perfect when line already contains wildcards, but works - strcat(mask, "*.*"); + if ((dot_pos-bs_pos>0) && (dot_pos-fs_pos>0) && (dot_pos-cl_pos>0)) + strcat(mask, "*"); + else strcat(mask, "*.*"); } else { strcpy(mask, "*.*"); } + RealPt save_dta=dos.dta(); + dos.dta(dos.tables.tempdta); + bool res = DOS_FindFirst(mask, 0xffff & ~DOS_ATTR_VOLUME); - if (!res) break; // TODO: beep + if (!res) { + dos.dta(save_dta); + break; // TODO: beep + } DOS_DTA dta(dos.dta()); char name[DOS_NAMELENGTH_ASCII];Bit32u size;Bit16u date;Bit16u time;Bit8u attr; @@ -239,6 +271,7 @@ void DOS_Shell::InputCommand(char * line) { /* Add excutable list to front of completion list. */ std::copy(executable.begin(),executable.end(),std::front_inserter(l_completion)); it_completion = l_completion.begin(); + dos.dta(save_dta); } if (l_completion.size() && it_completion->length()) { @@ -301,17 +334,20 @@ void DOS_Shell::InputCommand(char * line) { if (l_completion.size()) l_completion.clear(); } -void DOS_Shell::Execute(char * name,char * args) { +bool DOS_Shell::Execute(char * name,char * args) { +/* return true => don't check for hardware changes in do_command + * return false => check for hardware changes in do_command */ char * fullname; char line[CMD_MAXLINE]; if(strlen(args)!= 0){ if(*args != ' '){ //put a space in front line[0]=' ';line[1]=0; - strcat(line,args); + strncat(line,args,CMD_MAXLINE-2); + line[CMD_MAXLINE-1]=0; } else { - strcpy(line,args); + safe_strncpy(line,args,CMD_MAXLINE); } }else{ line[0]=0; @@ -323,22 +359,19 @@ void DOS_Shell::Execute(char * name,char * args) { if (!DOS_SetDrive(toupper(name[0])-'A')) { WriteOut(MSG_Get("SHELL_EXECUTE_DRIVE_NOT_FOUND"),toupper(name[0])); } - return; + return true; } /* Check for a full name */ fullname=Which(name); - if (!fullname) { - WriteOut(MSG_Get("SHELL_EXECUTE_ILLEGAL_COMMAND"),name); - return; - } - + if (!fullname) return false; + char* extension =strrchr(fullname,'.'); /*always disallow files without extension from being executed. */ /*only internal commands can be run this way and they never get in this handler */ if(extension == 0) { - char temp_name[256],* temp_fullname; + char temp_name[DOS_PATHLENGTH+4],* temp_fullname; //try to add .com, .exe and .bat extensions to filename strcpy(temp_name,fullname); @@ -362,8 +395,7 @@ void DOS_Shell::Execute(char * name,char * args) { else { - WriteOut(MSG_Get("SHELL_EXECUTE_ILLEGAL_COMMAND"),fullname); - return; + return false; } } @@ -382,11 +414,7 @@ void DOS_Shell::Execute(char * name,char * args) { { /* only .bat .exe .com extensions maybe be executed by the shell */ if(strcasecmp(extension, ".com") !=0) { - if(strcasecmp(extension, ".exe") !=0) - { - WriteOut(MSG_Get("SHELL_EXECUTE_ILLEGAL_COMMAND"),fullname); - return; - } + if(strcasecmp(extension, ".exe") !=0) return false; } /* Run the .exe or .com file from the shell */ /* Allocate some stack space for tables in physical memory */ @@ -439,6 +467,7 @@ void DOS_Shell::Execute(char * name,char * args) { SegSet16(cs,oldcs); #endif } + return true; //Executable started } @@ -450,7 +479,8 @@ static char * exe_ext=".EXE"; static char which_ret[DOS_PATHLENGTH+4]; char * DOS_Shell::Which(char * name) { - if(strlen(name) >= DOS_PATHLENGTH) return 0; + size_t name_len = strlen(name); + if(name_len >= DOS_PATHLENGTH) return 0; /* Parse through the Path to find the correct entry */ /* Check if name is already ok but just misses an extension */ @@ -476,26 +506,37 @@ char * DOS_Shell::Which(char * name) { pathenv=strchr(pathenv,'='); if (!pathenv) return 0; pathenv++; - char * path_write=path; + Bitu i_path = 0; while (*pathenv) { /* remove ; and ;; at the beginning. (and from the second entry etc) */ while(*pathenv && (*pathenv ==';')) pathenv++; - /* Clear old path */ - for(Bitu dummy = 0;dummy < DOS_PATHLENGTH; dummy++) - path[dummy] = 0; //OVERKILL could be strlen(path). but run no risks - /* get next entry */ - while(*pathenv && (*pathenv !=';')) - *path_write++=*pathenv++; - + i_path = 0; /* reset writer */ + while(*pathenv && (*pathenv !=';') && (i_path < DOS_PATHLENGTH) ) + path[i_path++] = *pathenv++; + + if(i_path == DOS_PATHLENGTH) { + /* If max size. move till next ; and terminate path */ + while(*pathenv != ';') + pathenv++; + path[DOS_PATHLENGTH - 1] = 0; + } else path[i_path] = 0; + + /* check entry */ - if(Bitu len=strlen(path)){ - if(path[strlen(path)-1]!='\\') strcat(path,"\\"); - strcat(path,name); + if(size_t len = strlen(path)){ + if(len >= (DOS_PATHLENGTH - 2)) continue; + + if(path[len - 1] != '\\') { + strcat(path,"\\"); + len++; + } + //If name too long =>next - if(strlen(path) >= DOS_PATHLENGTH) continue; + if((name_len + len + 1) >= DOS_PATHLENGTH) continue; + strcat(path,name); strcpy(which_ret,path); if (DOS_FileExists(which_ret)) return which_ret; @@ -509,9 +550,6 @@ char * DOS_Shell::Which(char * name) { strcat(which_ret,bat_ext); if (DOS_FileExists(which_ret)) return which_ret; } - path_write=path; /* reset it */ - } return 0; } - diff --git a/visualc/Makefile.in b/visualc/Makefile.in index 6c9604a..363b8d5 100644 --- a/visualc/Makefile.in +++ b/visualc/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -75,6 +75,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -100,10 +102,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/visualc/dosbox.dsp b/visualc/dosbox.dsp index a01dc42..306f9f7 100644 --- a/visualc/dosbox.dsp +++ b/visualc/dosbox.dsp @@ -639,6 +639,10 @@ SOURCE=..\src\fpu\fpu_instructions.h # End Source File # Begin Source File +SOURCE=..\src\fpu\fpu_instructions_x86.h +# End Source File +# Begin Source File + SOURCE=..\src\fpu\fpu_types.h # End Source File # End Group diff --git a/visualc_net/Makefile.in b/visualc_net/Makefile.in index 3a29a39..5664a0d 100644 --- a/visualc_net/Makefile.in +++ b/visualc_net/Makefile.in @@ -1,8 +1,8 @@ -# Makefile.in generated by automake 1.9.3 from Makefile.am. +# Makefile.in generated by automake 1.9.5 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004 Free Software Foundation, Inc. +# 2003, 2004, 2005 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. @@ -75,6 +75,8 @@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ +HAVE_WINDRES_FALSE = @HAVE_WINDRES_FALSE@ +HAVE_WINDRES_TRUE = @HAVE_WINDRES_TRUE@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ @@ -100,10 +102,12 @@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WINDRES = @WINDRES@ ac_ct_CC = @ac_ct_CC@ ac_ct_CXX = @ac_ct_CXX@ ac_ct_RANLIB = @ac_ct_RANLIB@ ac_ct_STRIP = @ac_ct_STRIP@ +ac_ct_WINDRES = @ac_ct_WINDRES@ am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ diff --git a/visualc_net/dosbox.vcproj b/visualc_net/dosbox.vcproj index f397a0f..cafb898 100644 --- a/visualc_net/dosbox.vcproj +++ b/visualc_net/dosbox.vcproj @@ -404,9 +404,6 @@ - - @@ -440,12 +437,6 @@ - - - - @@ -485,6 +476,9 @@ + + + + + + + + + + + + + + + + + + + +