From b6e39ef9fe2a22fa686e1925bb18e80986c2d2e3 Mon Sep 17 00:00:00 2001 From: dborth Date: Thu, 18 Feb 2010 06:03:55 +0000 Subject: [PATCH] sync with SVN --- AUTHORS | 22 +- COPYING | 680 +-- ChangeLog | 1212 ++-- INSTALL | 208 +- NEWS | 1188 ++-- README | 2614 ++++----- THANKS | 56 +- VERSION | 2 +- acinclude.m4 | 2 +- autogen.sh | 28 +- configure.in | 1056 ++-- docs/PORTING | 100 +- docs/README.video | 70 +- docs/dosbox.1 | 724 +-- include/bios.h | 2 +- include/bios_disk.h | 2 +- include/callback.h | 2 +- include/control.h | 2 +- include/cpu.h | 2 +- include/cross.h | 2 +- include/debug.h | 2 +- include/dma.h | 2 +- include/dos_inc.h | 2 +- include/dos_system.h | 8 +- include/dosbox.h | 2 +- include/fpu.h | 2 +- include/hardware.h | 2 +- include/inout.h | 2 +- include/ipx.h | 2 +- include/ipxserver.h | 2 +- include/joystick.h | 2 +- include/keyboard.h | 2 +- include/mapper.h | 2 +- include/mem.h | 2 +- include/mixer.h | 2 +- include/mouse.h | 2 +- include/paging.h | 2 +- include/pic.h | 2 +- include/programs.h | 2 +- include/regs.h | 2 +- include/render.h | 2 +- include/serialport.h | 5 +- include/setup.h | 2 +- include/shell.h | 2 +- include/support.h | 2 +- include/timer.h | 2 +- include/vga.h | 2 +- include/video.h | 2 +- scripts/dosbox-installer.nsi | 314 +- scripts/ega-switch.pl | 64 +- scripts/font-switch.pl | 50 +- src/cpu/callback.cpp | 2 +- src/cpu/core_dyn_x86.cpp | 2 +- src/cpu/core_dyn_x86/cache.h | 1144 ++-- src/cpu/core_dyn_x86/decoder.h | 5420 +++++++++--------- src/cpu/core_dyn_x86/dyn_fpu.h | 1340 ++--- src/cpu/core_dyn_x86/dyn_fpu_dh.h | 996 ++-- src/cpu/core_dyn_x86/helpers.h | 138 +- src/cpu/core_dyn_x86/risc_x86.h | 2144 +++---- src/cpu/core_dyn_x86/string.h | 328 +- src/cpu/core_dynrec.cpp | 2 +- src/cpu/core_dynrec/cache.h | 1330 ++--- src/cpu/core_dynrec/decoder.h | 1224 ++-- src/cpu/core_dynrec/decoder_basic.h | 2534 ++++---- src/cpu/core_dynrec/decoder_opcodes.h | 2860 ++++----- src/cpu/core_dynrec/dyn_fpu.h | 1376 ++--- src/cpu/core_dynrec/operators.h | 3994 ++++++------- src/cpu/core_dynrec/risc_armv4le-common.h | 228 +- src/cpu/core_dynrec/risc_armv4le-o3.h | 2166 +++---- src/cpu/core_dynrec/risc_armv4le-s3.h | 1838 +++--- src/cpu/core_dynrec/risc_armv4le-thumb-iw.h | 2596 ++++----- src/cpu/core_dynrec/risc_armv4le-thumb-niw.h | 2662 ++++----- src/cpu/core_dynrec/risc_armv4le-thumb.h | 2268 ++++---- src/cpu/core_dynrec/risc_armv4le.h | 62 +- src/cpu/core_dynrec/risc_mipsel32.h | 1502 ++--- src/cpu/core_dynrec/risc_x64.h | 1362 ++--- src/cpu/core_dynrec/risc_x86.h | 1034 ++-- src/cpu/core_full.cpp | 2 +- src/cpu/core_normal.cpp | 2 +- src/cpu/core_normal/helpers.h | 2 +- src/cpu/core_normal/prefix_0f.h | 2 +- src/cpu/core_normal/prefix_66.h | 2 +- src/cpu/core_normal/prefix_66_0f.h | 2 +- src/cpu/core_normal/prefix_none.h | 2 +- src/cpu/core_normal/support.h | 2 +- src/cpu/core_normal/table_ea.h | 2 +- src/cpu/core_prefetch.cpp | 2 +- src/cpu/core_simple.cpp | 2 +- src/cpu/cpu.cpp | 2 +- src/cpu/flags.cpp | 2 +- src/cpu/instructions.h | 2 +- src/cpu/lazyflags.h | 2 +- src/cpu/modrm.cpp | 2 +- src/cpu/modrm.h | 2 +- src/cpu/paging.cpp | 2 +- src/debug/debug.cpp | 2 +- src/debug/debug_gui.cpp | 2 +- src/debug/debug_inc.h | 2 +- src/debug/debug_win32.cpp | 2 +- src/debug/disasm_tables.h | 2 +- src/dos/cdrom.cpp | 2 +- src/dos/cdrom_aspi_win32.cpp | 2 +- src/dos/cdrom_image.cpp | 2 +- src/dos/cdrom_ioctl_linux.cpp | 2 +- src/dos/cdrom_ioctl_os2.cpp | 2 +- src/dos/cdrom_ioctl_win32.cpp | 2 +- src/dos/dev_con.h | 2 +- src/dos/dos.cpp | 2 +- src/dos/dos_classes.cpp | 2 +- src/dos/dos_devices.cpp | 2 +- src/dos/dos_execute.cpp | 26 +- src/dos/dos_files.cpp | 9 +- src/dos/dos_ioctl.cpp | 2 +- src/dos/dos_keyboard_layout.cpp | 11 +- src/dos/dos_memory.cpp | 2 +- src/dos/dos_misc.cpp | 4 +- src/dos/dos_mscdex.cpp | 101 +- src/dos/dos_programs.cpp | 80 +- src/dos/dos_tables.cpp | 2 +- src/dos/drive_cache.cpp | 22 +- src/dos/drive_fat.cpp | 10 +- src/dos/drive_iso.cpp | 12 +- src/dos/drive_local.cpp | 6 +- src/dos/drive_virtual.cpp | 2 +- src/dos/drives.cpp | 2 +- src/dos/drives.h | 5 +- src/dosbox.cpp | 1374 ++--- src/fpu/fpu.cpp | 2 +- src/fpu/fpu_instructions.h | 20 +- src/fpu/fpu_instructions_x86.h | 2 +- src/gui/dosbox_logo.h | 2 +- src/gui/midi.cpp | 2 +- src/gui/midi_alsa.h | 2 +- src/gui/midi_coreaudio.h | 2 +- src/gui/midi_oss.h | 2 +- src/gui/midi_win32.h | 2 +- src/gui/render.cpp | 2 +- src/gui/render_loops.h | 2 +- src/gui/render_scalers.cpp | 2 +- src/gui/render_scalers.h | 2 +- src/gui/render_simple.h | 2 +- src/gui/render_templates.h | 2 +- src/gui/render_templates_hq.h | 2 +- src/gui/render_templates_hq2x.h | 2 +- src/gui/render_templates_hq3x.h | 2 +- src/gui/render_templates_sai.h | 2 +- src/gui/sdl_gui.cpp | 4 +- src/gui/sdl_mapper.cpp | 2 +- src/gui/sdlmain.cpp | 13 +- src/hardware/adlib.cpp | 2 +- src/hardware/adlib.h | 2 +- src/hardware/cmos.cpp | 2 +- src/hardware/dbopl.cpp | 2 +- src/hardware/dbopl.h | 2 +- src/hardware/disney.cpp | 2 +- src/hardware/dma.cpp | 2 +- src/hardware/gameblaster.cpp | 87 +- src/hardware/gus.cpp | 2 +- src/hardware/hardware.cpp | 2 +- src/hardware/iohandler.cpp | 99 +- src/hardware/ipx.cpp | 2 +- src/hardware/ipxserver.cpp | 2 +- src/hardware/joystick.cpp | 2 +- src/hardware/keyboard.cpp | 2 +- src/hardware/memory.cpp | 2 +- src/hardware/mixer.cpp | 2 +- src/hardware/mpu401.cpp | 2 +- src/hardware/opl.cpp | 2 +- src/hardware/opl.h | 2 +- src/hardware/pcspeaker.cpp | 2 +- src/hardware/pic.cpp | 41 +- src/hardware/sblaster.cpp | 28 +- src/hardware/serialport/directserial.cpp | 2 +- src/hardware/serialport/directserial.h | 2 +- src/hardware/serialport/libserial.cpp | 2 +- src/hardware/serialport/libserial.h | 2 +- src/hardware/serialport/misc_util.cpp | 2 +- src/hardware/serialport/misc_util.h | 2 +- src/hardware/serialport/nullmodem.cpp | 2 +- src/hardware/serialport/nullmodem.h | 2 +- src/hardware/serialport/serialdummy.cpp | 2 +- src/hardware/serialport/serialdummy.h | 2 +- src/hardware/serialport/serialport.cpp | 2 +- src/hardware/serialport/softmodem.cpp | 2 +- src/hardware/serialport/softmodem.h | 2 +- src/hardware/tandy_sound.cpp | 2 +- src/hardware/timer.cpp | 10 +- src/hardware/vga.cpp | 2 +- src/hardware/vga_attr.cpp | 2 +- src/hardware/vga_crtc.cpp | 2 +- src/hardware/vga_dac.cpp | 2 +- src/hardware/vga_draw.cpp | 2 +- src/hardware/vga_gfx.cpp | 2 +- src/hardware/vga_memory.cpp | 2 +- src/hardware/vga_misc.cpp | 2 +- src/hardware/vga_other.cpp | 2 +- src/hardware/vga_paradise.cpp | 2 +- src/hardware/vga_s3.cpp | 2 +- src/hardware/vga_seq.cpp | 2 +- src/hardware/vga_tseng.cpp | 2 +- src/hardware/vga_xga.cpp | 2 +- src/ints/bios.cpp | 2 +- src/ints/bios_disk.cpp | 2 +- src/ints/bios_keyboard.cpp | 15 +- src/ints/ems.cpp | 2 +- src/ints/int10.cpp | 2 +- src/ints/int10.h | 2 +- src/ints/int10_char.cpp | 2 +- src/ints/int10_memory.cpp | 2 +- src/ints/int10_misc.cpp | 2 +- src/ints/int10_modes.cpp | 28 +- src/ints/int10_pal.cpp | 2 +- src/ints/int10_put_pixel.cpp | 2 +- src/ints/int10_vesa.cpp | 2 +- src/ints/int10_video_state.cpp | 2 +- src/ints/int10_vptable.cpp | 2 +- src/ints/mouse.cpp | 22 +- src/ints/xms.cpp | 2 +- src/ints/xms.h | 2 +- src/libs/gui_tk/Doxyfile | 476 +- src/libs/gui_tk/gui_tk.cpp | 3412 +++++------ src/libs/gui_tk/gui_tk.h | 4450 +++++++------- src/libs/zmbv/drvproc.cpp | 424 +- src/libs/zmbv/resource.h | 42 +- src/libs/zmbv/zmbv.cpp | 1098 ++-- src/libs/zmbv/zmbv.def | 8 +- src/libs/zmbv/zmbv.h | 236 +- src/libs/zmbv/zmbv.inf | 210 +- src/libs/zmbv/zmbv.sln | 42 +- src/libs/zmbv/zmbv.vcproj | 282 +- src/libs/zmbv/zmbv_vfw.cpp | 794 +-- src/libs/zmbv/zmbv_vfw.h | 122 +- src/libs/zmbv/zmbv_vfw.rc | 246 +- src/misc/cross.cpp | 2 +- src/misc/messages.cpp | 2 +- src/misc/programs.cpp | 26 +- src/misc/setup.cpp | 2 +- src/misc/support.cpp | 2 +- src/platform/sdl-win32.diff | 110 +- src/platform/visualc/config.h | 155 +- src/platform/visualc/ntddcdrm.h | 640 +-- src/platform/visualc/ntddscsi.h | 348 +- src/platform/visualc/unistd.h | 20 +- src/platform/wii/config.h | 1 + src/shell/shell.cpp | 50 +- src/shell/shell_batch.cpp | 2 +- src/shell/shell_cmds.cpp | 36 +- src/shell/shell_misc.cpp | 2 +- src/winres.rc | 74 +- visualc_net/dosbox.sln | 42 +- visualc_net/dosbox.vcproj | 1748 +++--- 251 files changed, 33300 insertions(+), 33088 deletions(-) diff --git a/AUTHORS b/AUTHORS index ef20cdf..c7f4622 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,11 +1,11 @@ -The DOSBox Team ---------------- - -Sjoerd v.d. Berg -Peter Veenstra -Ulf Wohlers -Tommy Frössman -Dean Beeler -Sebastian Strohhäcker - -nick_without_<> @ users.sourceforge.net +The DOSBox Team +--------------- + +Sjoerd v.d. Berg +Peter Veenstra +Ulf Wohlers +Tommy Frössman +Dean Beeler +Sebastian Strohhäcker + +nick_without_<> @ users.sourceforge.net diff --git a/COPYING b/COPYING index fbdd65f..d60c31a 100644 --- a/COPYING +++ b/COPYING @@ -1,340 +1,340 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog index fc90fa7..270019f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,573 +1,639 @@ -0.73 - - Add two new opl2+opl3 emulators. (better speed, different implementation - approach) - - Improved DRO recording/better file structure. - - Add EGA emulation. - - Add special vga machine mode. Supports more of the exotic tricks like - changing the palette during screen updates, 9x16 fonts etc. - - Added special machine modes for the following svga cards: - - S3 - - Paradise - - Tseng - - Fix problems with the vga split line feature. - - Improve vesa emulation. - - Add optional selection of old vesa mode for games that don't work - with certain vesa features. - - Improve video BIOS emulation to behave more like a real bios. - - Fixes for emulated 4bpp graphics modes. - - Fixes to paging system. - - Various fixes and improvements for the recompiling core. - - Add arm backend for the recompiling core. - - Add some mscdex quirks when dealing with files that are exactly 8.3 long. - - Small fixes to batch file handling. - - Small fixes to the XMS memory handling. - - Various fixes for aligned memory on hosts that want it. - - Various improvements to the mouse. - - Fixes and small speed ups to the debugger. - - Fix and improve lot's of compilation problems. (curses detection, - GCC 3.4 and GCC 4.X fixes) - - Added some basic auto keyboard layout handling. (windows only currently) - - Add basic support for evdev keyboard driver. - - Various fixes to the timer. (improve mode 2 timer changes, - implement mode 1, improve gate2 handling) - - Add audio extraction and mci audio support. Should enable CDROM audio - for Vista and adds volume control. - - Improve the directory cache speed a lot, especially with mounting slow - media like network paths. - - Various fixes to the create temporary file call. - - Don't keep batchfiles open during execution. Allows rewriting of the - active batchfile. (menu programs use this trick sometimes) - - Fix problems with filenames with 2 extensions. - - Add some more lowlevel dos tables. - - Fixes to hercules emulation. - - Fix flag handling for special case of ROR. - - Make the batchfile handling in regard to IF more flexible. - - Fixes to scrolling/panning feature. - - Add prefetch queue emulation. - - Make the emulated cpu type selectable. This is mainly the - identification commands and the way paging works. - - Some special EMS functionality added. (OS handles, zero-page handling) - - Improve support for EMS when booting a different OS. - - Improve cdrom speed detection by games. - - Improve stability of cycle guessing code, when there is background - activity. - - Fix various mscdex and cdrom detection schemes. - - Added Coremidi support on Mac OS X. - - Improve support for DOS devices when used to detect the existance - of directories in various ways. - - Add IRQ 2 emulation on VRET. (ega only) - - Added video parameter table and video state functionality. - - Increase default freespace to 250 MB. - - Some fixes to the fat filesystem handling for disk images. - - Some soundblaster fixes and command additions. - - Fix mixer 16bit direct transfers on bigendian hosts. - -0.72 - - Fixed unitialized variable in joystick. (Fixes crashes on Vista and - Mac OS X) - - Some bugfixes and speedups to the 64 bit recompiling core. - - Fixed sign flag on soundblaster dma transfers (Space Quest 6 intro) - - Fixed a bug in keyboard layout processing code and fixed certain - layouts. - - Fixed Dreamweb. - - Improved speed unlocking when running cycles=max. - - Fixed a crash related to the tab completion in the shell. - - Improved aspect correction code. Should now be like how a real monitor - handles it. - - Fixed a bug in the xms status report code. (Blake Stone 1.0 shareware) - - Added a lot more keyboard layouts. - - Fix crash related to changing the scaler before a screen was created. - - Hopefully fixed compilation on *bsd. - - Enabled auto cpu core selection for recompiling core as well. - - Made the used joystick selectable when 4axis is specified. - - Added some hints for inexperienced DOS users to the shell. - -0.71 - - Add a new recompiling cpu core, which should be easier to port. - - Add 64 bit version of the recompiling core. - - Add mipsel 32 bit version of the recompiling core. - - Fix a few small problems with FCBs. (fixes Jewels of darkness and - cyrus chess) - - Raise some more exceptions. (fixes vbdos) - - Fix a few problems with the dynamic core. (fixes Inner Words, - Archmimedean Dynasty and others) - - Improve/Fix fallback code for certain graphics cards. - - Fix a few cd audio related bugs. - - Add an undocumented MSCDEX feature. (Fixes Ultimate Domain) - - Fix some pcspeaker mode. (fixes Test Drive and similar games) - - Improve dos keyinput handling. (fixes Wing Commander 3 exit dialog) - - Remove Exit condition on fully nested mode. (fixes some demo) - - Add image file size detection. - - Add/Fix some ansi codes. (fixes PC Larn and certain versions of - infocom games) - - Several general DOS fixes. (fixes nba95, hexit and various other games) - - Add some valid input checks. (fixes 3d body adventure and similar - games) - - Fix digital joystick centering problem. - - Reenable textmode 54 and 55. - - Fix a pelmask problem with univbe 5.0 lite. (fixes Panzer General) - - Fix minor mixer underflow. - - Some general image and bios disk emulation fixes. - - Hopefully fix compilation on BSD and darwin. - - Try using ioctl cdrom access by default if possible. - - Fix some svga detection routine. (fixes Grandest Fleet 2 and Bobby Fischer - Teaches Chess) - - You can now close DOSBox using the status window in win32. - - Add support for NX enabled systems. - - Fix a casting error which only showed with certain compilers. (fixes - various games under mac os x and 64 bit linux) - - Improve timer and add gate 2 support. (fixes various games and - joystick problems) - - Improve mouse. Add undocumented backdoor. (fixes Last half of Darkness, - PC-BLOX and others) - - Add/improve support for ~ and ~username in all commands. - - Fix a font problem with the pcjr/tandy. (fixes personal deskmate 2) - - Change dma routine a bit. (fixes ticks in sound in various games) - - Allow read-only diskimages to be booted. (fixes various booter - games) - - Add basic hidden file support on cdrom images. (fixes Player - Manager 2) - - Add some rarely used functionality to the int10 mode setup. (fixes - WW2 Battles of the South pacific) - - Add ability to force scaler usage. - - Speed up flag generation and make it more 386-like. - - Some colourful feedback in the mapper. - - General code cleanup. - -0.70 - - Improve register handling and support with XMS. - - Fix some issues with deleting open files.(windows only issue) - - Add dummy LPT1 class. (windows only issue) - - Improve some of the internal dos commands. (choice, copy and shift) - - Improve ROM area. (for games that use it for random numbers or - overwrite it as some sort of detection thing) - - Improve compatibility of dynamic core by making it handle certain - pagefaults earlier. - - Move internal dos tables around so we have more umb memory. - - Add some dos tables. - - Dynamic core supports io exceptions. - - Move some interrupt handlers to XT Bios locations. - - Add a dynamic fpu on x86. - - Improve fpu on non-x86. - - Trapflag gets strict priority over hardware IRQs. - - Trapflag support for the dynamic core. - - Add dummy TRx handling. - - Fix a few rarely used character functions. - - Improve auto cycle guessing code. - - Improve and extend the joystick support. - - Add autofire support. - - Improve the mapper so you can map keys to the joystick and vice versa. - - A few game specific video card fixes. - - Fix some 64 bit cpu bugs. - - Add support for certain cdrom detection schemes. - - Improve HSG/Red Book support. - - Improve MSCDEX. - - Improve dynamic core support under intel macs. - - Add basic support for clipper programs. - - Add support for different keyboard layouts. - - Add auto core guessing. - - Fix a few flags bugs. - - Fix a few small cpu bugs. - - Improve soundblaster detection rate by various programs. - - Improve EMS emulation. (allow mapping of non standard regions) - - Improve keyboard input codes on various OS-es. - - Fix problems with filenames having stackdata in them. - - Changed a few basic operations in DOSBox so they take emulated time. - - Improve dos ioctl functions. - - Extend cpu core so they are capable of detecting and raising a few - more exception types. - - Improve DOS functions when dealing with virtual drive. - - Improve FAT drives. - - Better handling of volume-labels in file functions. - - Image disk cycling capability. (prompt) - - Try to reduce the impact of using an analog joystick. - - Several measures to avoid code invalidation on certain types - of self modification in the dynamic core. - - Add dynamic core memory function inlining. - - A few small mouse improvements. (some games are using things they - shouldn't) - - Add nullmodem emulation.(h-a-l-9000) - - Some small cga and hercules fixes. - - Add more scalers (hq2x/hq3x/sai). (Kronuz) - - Change configuration file loading support. It now supports - multiple configuration files. - - Make dynamic core capable of running some win32s programs. - - Fix and add some rare soundblaster modes. (Srecko) - - Better soundblaster mixer controls. (Srecko) - - Make soundblaster installation under windows much easier. - - Add device control channel handling. - - GEMMIS support (ems under windows). - - Support more colours in win 3. (vasyl) - - Don't show unmounted drives in windows filemanager. - - Fix some bugs in the int13 handler. - - Simulate some side-effects of bios interrupt handlers on flags. - - Add IPX functions needed by netbios. - - Make ports take emulated time. - - Tabcompletion is now aware of the CD command. - - Add suppport for the dac pel mask. - - Fixes to hercules emulation, better detection and bank switching. - - Fixes to tandy emulation, 640x200x16 mode and different sizes bank. - - EGA/VGA memory changes detection for faster rendering. - - Gus 16 bit fixes. - - Many timer improvements. - - Some pcjr fixes. - - Some booter fixes. - - Many small fixes. - -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. - - Fixed multiple issues with drive labels. - - Fixed most if not all FILES=XX problems. - - Added redirection in the shell. - - Fixed crashes with subst. - - Fixed multiple crashes with the drive images support. - - Added a missing fpu instruction. - - Fixed some cpu and fpu instructions. - - Fixed a small bug related to font loading. - - Rewrote the devices support. - - Added capslock/numlock checks on startup. - - Fixed wave writing. - - A few internal DOS fixes. - - Timer fixes for the hybrid loader. - - Some small soundblaster fixes. - - The drive cache can now be cleared by a keycombo. (CTRL-F4) - - A few keyboard fixes. - - Compilation fixes on various platforms. - - Quite some debugger improvements. - - Fixed dir only showing files after the first run on cdrom drives. - - Added some cdrom detection checks. - - Enabled insert in the shell. (Easier editing of commands) - - Changed order in which executables appear with tab-completion. - - Fixed some issues with raw opl recording and using a slightly different - format - -0.62 - - Added blinking support in the shell and some color fixes. - - Fixed commandline parsing when .bat files involved (fixes -exit) - - Fixed issues with tabs in commandline not being processed correctly. - - Cleaned/improved shutdown sequence. - - Added some more bios functions (wait and delay functions). - - Made our XMS driver conform the specs better. (c2woody) - - Added support for some more ems functions. - - Added intelligent mpu401 emulation. (Srecko) - - Added soundblaster 16 emulation. - - Rewrote GUS emulation to sound more authentic. - - Improved pc speaker emulation. - - Added an internal (programmable) mixer. - - Added support a few soundblaster/adlib detection routines. - - Fixed lot's of bugs related to DMA transfers. - - Added interpolating prebuffering mixer routines. - - Added recording of OPL commands and raw midi. - - Fixed some bugs with the wave recording. - - Changed sensitivity settings of the mouse. - - Added ps2 mouse-emulation in bios interrupts (c2woody). - - Fixed some bugs with mouse emulation limits. - - Fixed a bug with an unterminated string in the drivelabel. - - Changed file search routines a bit to be more compatible. - - Added support for attribute-searching with fcb's. - - Added basic SDA. - - Added TPA and DIB. - - Added Lot's of missing dos tables (c2woody). - - Changed psp and dta functions to use dta. - - Returned filename in ds:dx in create-random-file (c2woody). - - Fixed a bug with date and time used on open files. - - Some mscdex fixes. - - Added the -version switch, which makes dosbox report its version. - - Added a keymapper. - - Added basic IPX emulation. - - Added cdrom iso support and floppy images support. - - Added the possibity to boot another dos version. - - Added Serial passthrough support (win32 only). - - Added the possibility to pause dosbox. - - Changed OpenGL so that it is initialized only when used. - - Make dosbox run at higher priority when active and lower when inactive. - - Added direct draw output support (win32 only). - - Added current running program to title bar. - - Rewrote video emulation to support new scalers. - - Added new graphics scalers like advmame3x,tv2x. - - Added a support for a few anti-debugger tricks. - - Improved the handling of the tab-key. - - Improved support for the numeric keyboard. - - Fixed a few cpu opcodes. - - Added cpu core simple (for lowerend machines) - - Fixed some nasty bugs in the dynamic cpu core. - - Added a few (rarely used) fpu opcodes. - - Fixed various issues with GCC 3.4. - - Many internal timer improvements (PIT and PIC). - - Added some more PIC commands (c2woody). - - Added BCD counting to the timers. - - Fix some vesa functions. - - Add some basic support for 132x25 and 132x45 textmodes. - - Improved Tandy emulation a lot. - - Lowered cpu usage when dosbox is idle. - - Allow virtualisation of some basic IO-ports (c2woody). - - -0.61 - - Added a beta dynamic cpu for x86 hosts (very unstable) - - Added opengl and hardware overlay display output - - Rewrote the vga screen updates to go in lines - - Added paging and v86 support to cpu emulation - - Added a config option to simulate a certain type of machine - - Added hercules graphics emulation - - Made CGA/TANDY modes more compatible - - Updated textmode drawing routines to support blinking colors - - Fixed VESA set page function that was documented wrong - - Fixed some wrongly emulated cpu opcodes. - - improved exception handling - - debugger: fixes; logging of gdt,lgt,idt, new commands(Fizzban) - - fixed some mscdex issues (drive letter header error, added get directory entry) - - added/fixed some bios funcs - - added some rarely used xms functions (thanks c2woody!) - - implemented GUS emulation - - Added 16-bit DMA support (for GUS and eventually SB16) - - Fixed many small bugs in filehandling routines - - Many small FPU fixes (c2woody/Fizzban) - - Some keyboard improvements (pharlab games) - - Some Timer and cmos/rtc fixes (Mirek/Srecko/Others) - - Lot's of mouse fixes (Help from various people) - - Enabled internal modem - - Made the DOS parsing routines a bit more flexible - - Added Subst (Srecko) - - Added cdrom ioctl support for linux (prompt) - - Many internal DOS fixes: memory/files/datastructures. - - Got some help from c2woody in allowing more than 1 irq being served - - Disabled DPMI (not needed anymore. DOSBox handles almost every extender) - - Search configfile in $HOME directory if none present in current directory - - Added another way to switch to protected mode. (Thanks Morten Eriksen!) - - Fixed some odd badly documented behaviour with PSP/DTA - - Added some warnings on opening of readonly files in writemode(DOS default). - - Many shell enhanchements - - Fixed a win32 specific bug dealing with filenames starting with a "." - - Fixed some bugs with the directory structure: not found/can't save errors - -0.60 - - rewrote memory system for future paging support - - fixed several EMS and XMS bugs and rewrite for new memory system - - added some support for tandy video modes - - added MAME Tandy 3 voice emulation - - added MAME CMS/GameBlaster emulation - - added serial port emulation with virtual tcp/ip modem (somewhat buggy) - - sound blaster emulation is now sb pro 2.0 compatible - - added basic support for 32-bit protected mode - - VGA now tries to emulate an S3 Trio 64 card with 2 MB - - VESA 2.0 support for some 256 color modes - - rewrote large piece of video bios code for better compatibility - - added support for the not inheritance flags. - - created functions for creating child psp. - - updated errorcodes of findfirst (thanks Mirek!) - - rewrote loggingsystem to generate less warnings - - added dos protected mode interface (dpmi) - - added cdrom label support - - improved cdrom audio playing - - fixed and improved directory cache - - debugger shows selector- and cpu mode info - - added SELINFO (selector information) command to debugger - - added reference counting for dos files - - added tab-completion - - added basic fpu support. - - fixed several bugs with case sensitive filesystems. - - added more shell commands and improved their behaviour. - - mouse improvements. - - real time clock improvements. - - DMA fixes. - - Improved .BAT file support. - -0.58 - - fixed date and time issues with fcbs - - added more commands to the internal Shell - - corrected config system when a old configfile was used - - fixed cga put and get pixel - - fixed some vga register getting reset to wrong values - - improved support for foreign keyboards - - improved joystick support - - made dosbox multithreaded again - - lot's of soundblaster fixes - - dma fixes - - cdrom support - - midi support - - added scale2x - - reenabled screenshot support - - joystick support fixes - - mouse improvements - - support for writing wavefiles - - added directory cache and longfilename support (longfilenames will be mangled) - - mouse fixes - - date and time updates at z:\ - - added (partial) direct disk support. (works probably only if directory is mounted under a:\) - - added support for env variables. (must be set before starting dosbox: DOSBOX_SECTION_PROPERTY=value - like DOSBOX_SBLASTER_IRQ=1) -0.57 - - added support for command /C - - fixed all fcb-write functions - - fixed fcb-parseline - - added debugger under linux/freebsd - - added debugger memory breakpoints and autolog function (heavy debug) - - added loadfix.com program that eats up memory (default 64kb) - Usage : loadfix [-option] [programname] [parameters]... - Example: loadfix mm2 (Allocates 64kb and starts executable mm2) - loadfix -32 mm2 (Allocates 32kb and starts executable mm2) - loadfix -128 (Allocates 128kb) - loadfix -f (frees all previous allocated memory) - - added echoing of characters for input function - - added support for backspace for input function - - added partial support for int10:01 set cursortype - - fixed most of the problems/bugs with character input. - - fixed allocationinfo call.(darksun series) - - improved dos support for non-existant functions - - Split screen support - - prefix 66 67 support - - rewrote timingscheme so 1000 hz timers don't cause problems anymore - - update adlib emulation - - fixed some isues with the mouse (double clicks and visible when it shouldn't be) - - improved mouse behaviour (mickey/pixel rate) and detection routines. - - basic ansi.sys support - - Disney sound system emulation - - rewrote upcase/lowcase functions so they work fine with gcc3.2 - - SHELL: added rename and delete - - added support for command /C. Fixed crashes in the shell - - fixed various bugs when exiting dosbox - - fixed a bug in XMS - - fixed a bug with the joystick when pressing a button - - create nicer configfiles. - - bios_disk function improved. - - trapflag support - - improved vertical retrace timing. - - PIT Timer improvements and many bug fixes - - Many many bug fixes to the DOS subsystem - - Support for memory allocation strategy - - rewrote cpu mainloop to act more like a real cpu - -0.56 - - added support for a configclass/configfile - - added support for writing out the configclass into a configfile - - removed the language file and made it internal - - added support for writing the language file (will override the internal one) - - improved mousesupport - - updated readme - - support for screenshots - - some cpu-bug fixes - - dma changes - - Real Sound support - - EMM fixes and new functions. - - VGA fixes - - new wildcompare - - support for size and disktype at mount. - - added new debugger functionalities: start/trace into INTs, write processor status log, - step over rep and loop instructions, breakpoint support without using INT 03 (heavy debugging switch) - - Added more cpu instructions and changed the string operations. - - Added classes for most of the internal dos structures. - - Rewrote most of the fcb calls to use normal dos calls. - -0.55 - - fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned). - - fixed compilation error on FreeBSD when #disable_joystick was defined - - int10_writechar has been updated to move the cursor position. - - changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :) - - illegal command, now displays the command - - wildcmp updated to be case insensitive - - added fcb:open,close,findfirst, findnext. - - fixed rename in drive_local - - added new features to the debugger: breakpoint support / data view / command line - - partial support of list of lists (dos info block) - - full emm 3.2 support - - partial emm 4.0 support - - fixes to graphics core fonts (text in sierra games is now correct) - - improved support for user mousehandlers - - fixed EGA graphics - - fixed VGA graphics - - fixed write with size 0 - - changed memory management. - - fixed and cleaned up the cpu flags. - - changed interrupt handler. - - speeded up the graphics. - - speeded up the cpu-core - - changed dma - - improved dma streams from emm memory - - added some cga videomodes - - added more funtions to the keyboard handler +0.74 + - Several small game specific fixes/hacks/support. (Offensive, + Roadhog, GTA installer, Kingdom O' Magic soundcard detection, + Pirate booter, armored fist installer) + - Add the S3-specific 640x480 256 color mode. Fixes regression in "Wooden + Ships and Iron Men" and "I Have No Mouth And I Must Scream". + - Fix a stack overflow that could crash DOSBox. + - Add fake microphone input. (Fixes Talking Parrot) + - Modify adlib turn off code, so that it doesn't turn off in + cases where the same sound is repeated over and over again. + - Several small fixes to the CDROM audio code. (HOMM2, Redneck + Rampage and others) + - Several improvements to the CDROM emulation code. (fixes Alpha + Storm and GT Racing 97) + - Some small cpu fixes that might fix something. + - Handle opcode 0xff subcode 7 as invalid instruction, fixes dif-2 & others. + - Some hercules fixes (Testdrive) + - Improve support for blanked parts that wrap around to the start of + the screen. (Fixes Magic Circle demo and Sid&Al) + - Remove old opl cores as the new ones seem work very nice. + - Modify movie recording code so that the movies aren't corrupt when + you exit dosbox without stopping the movie. + - Change RGB3x scaler to look more pretty. + - Improve initial register values compatility of the GUS. + - Change render preferences a bit to be more compatible with windows 7. + - Add DOS fixes to terminate program. (Fixes fortune teller) + - Add FFREEP. (Fixes trucks) + - Improve FPU ST80 in C mode when writing zero. (Fixes antigok) + - Add special int10 scanline function. (Fixes mz700 and probably lots + of games that mess with them) + - Fix scrolling in rarely used video modes. (Fixes Orphee) + - Modify game specific hacks a bit so that Kick off 3 works again. + - Lots of fixes to the INT10 video parameter table. (Seven spirits + of ra and others) + - Several small DOS fixes. + - Some UMB related fixes. ( The Legacy without umb) + - Fix version number of DSP for SB 1.5. (fixes a few games) + - Several vga emulation improvements (Allertone football manager) + - Some tandy fixes. (mech warrior) + - Small improvements and fixes to the OPL emulation. + - Add low Level tandy DAC emulation. + - Some EMS fixes. (Fixes Mortal Kombat and others) + - Change SoundBlaster DSP reset mechanism, add sb irq acknowledge logic + (fixes stmik-based applications). + - Some interrupt pointer location modifications. (fixes tinker tales) + - Some fixes to the BOOT code. (fixes last mission) + - Respect write-only. (fixes champions of zulala) + - Some RTC fix. (Fixes Tully Bodine and others) + - Improve mouse emulation to work better with Water World. + - Hopefully fix the translation of the configuration file. + - Speed up and fixes for the recompiler core. (pitfall2 pcjr) + - Change memory start location. (Fixes 7th Guest installer) + - Several fixes to the BAT files handling. (Shift and + use the typed first %0 instead of the parsed %0) + - Improve file redirection and redirected line ends. (Fixes + Phantasmagoria 2 DOS installer) + - Fix compilation with new MAC os X version. + - Add 16C550A FIFO support to the serial port emulation. + - Improve modem emulation to get higher speeds. + - Change default samplerates to 44100, so that hopefully certain + soundcards produce more fluent sound playback. + - Add some rarely used, but for some games critical flags to + the internal commands. + - Improve internal timing with repeatings timers (especially with + the dynamic core). + +0.73 + - Add two new opl2+opl3 emulators. (better speed, different implementation + approach) + - Improved DRO recording/better file structure. + - Add EGA emulation. + - Add special vga machine mode. Supports more of the exotic tricks like + changing the palette during screen updates, 9x16 fonts etc. + - Added special machine modes for the following svga cards: + - S3 + - Paradise + - Tseng + - Fix problems with the vga split line feature. + - Improve vesa emulation. + - Add optional selection of old vesa mode for games that don't work + with certain vesa features. + - Improve video BIOS emulation to behave more like a real bios. + - Fixes for emulated 4bpp graphics modes. + - Fixes to paging system. + - Various fixes and improvements for the recompiling core. + - Add arm backend for the recompiling core. + - Add some mscdex quirks when dealing with files that are exactly 8.3 long. + - Small fixes to batch file handling. + - Small fixes to the XMS memory handling. + - Various fixes for aligned memory on hosts that want it. + - Various improvements to the mouse. + - Fixes and small speed ups to the debugger. + - Fix and improve lot's of compilation problems. (curses detection, + GCC 3.4 and GCC 4.X fixes) + - Added some basic auto keyboard layout handling. (windows only currently) + - Add basic support for evdev keyboard driver. + - Various fixes to the timer. (improve mode 2 timer changes, + implement mode 1, improve gate2 handling) + - Add audio extraction and mci audio support. Should enable CDROM audio + for Vista and adds volume control. + - Improve the directory cache speed a lot, especially with mounting slow + media like network paths. + - Various fixes to the create temporary file call. + - Don't keep batchfiles open during execution. Allows rewriting of the + active batchfile. (menu programs use this trick sometimes) + - Fix problems with filenames with 2 extensions. + - Add some more lowlevel dos tables. + - Fixes to hercules emulation. + - Fix flag handling for special case of ROR. + - Make the batchfile handling in regard to IF more flexible. + - Fixes to scrolling/panning feature. + - Add prefetch queue emulation. + - Make the emulated cpu type selectable. This is mainly the + identification commands and the way paging works. + - Some special EMS functionality added. (OS handles, zero-page handling) + - Improve support for EMS when booting a different OS. + - Improve cdrom speed detection by games. + - Improve stability of cycle guessing code, when there is background + activity. + - Fix various mscdex and cdrom detection schemes. + - Added Coremidi support on Mac OS X. + - Improve support for DOS devices when used to detect the existance + of directories in various ways. + - Add IRQ 2 emulation on VRET. (ega only) + - Added video parameter table and video state functionality. + - Increase default freespace to 250 MB. + - Some fixes to the fat filesystem handling for disk images. + - Some soundblaster fixes and command additions. + - Fix mixer 16bit direct transfers on bigendian hosts. + +0.72 + - Fixed unitialized variable in joystick. (Fixes crashes on Vista and + Mac OS X) + - Some bugfixes and speedups to the 64 bit recompiling core. + - Fixed sign flag on soundblaster dma transfers (Space Quest 6 intro) + - Fixed a bug in keyboard layout processing code and fixed certain + layouts. + - Fixed Dreamweb. + - Improved speed unlocking when running cycles=max. + - Fixed a crash related to the tab completion in the shell. + - Improved aspect correction code. Should now be like how a real monitor + handles it. + - Fixed a bug in the xms status report code. (Blake Stone 1.0 shareware) + - Added a lot more keyboard layouts. + - Fix crash related to changing the scaler before a screen was created. + - Hopefully fixed compilation on *bsd. + - Enabled auto cpu core selection for recompiling core as well. + - Made the used joystick selectable when 4axis is specified. + - Added some hints for inexperienced DOS users to the shell. + +0.71 + - Add a new recompiling cpu core, which should be easier to port. + - Add 64 bit version of the recompiling core. + - Add mipsel 32 bit version of the recompiling core. + - Fix a few small problems with FCBs. (fixes Jewels of darkness and + cyrus chess) + - Raise some more exceptions. (fixes vbdos) + - Fix a few problems with the dynamic core. (fixes Inner Words, + Archmimedean Dynasty and others) + - Improve/Fix fallback code for certain graphics cards. + - Fix a few cd audio related bugs. + - Add an undocumented MSCDEX feature. (Fixes Ultimate Domain) + - Fix some pcspeaker mode. (fixes Test Drive and similar games) + - Improve dos keyinput handling. (fixes Wing Commander 3 exit dialog) + - Remove Exit condition on fully nested mode. (fixes some demo) + - Add image file size detection. + - Add/Fix some ansi codes. (fixes PC Larn and certain versions of + infocom games) + - Several general DOS fixes. (fixes nba95, hexit and various other games) + - Add some valid input checks. (fixes 3d body adventure and similar + games) + - Fix digital joystick centering problem. + - Reenable textmode 54 and 55. + - Fix a pelmask problem with univbe 5.0 lite. (fixes Panzer General) + - Fix minor mixer underflow. + - Some general image and bios disk emulation fixes. + - Hopefully fix compilation on BSD and darwin. + - Try using ioctl cdrom access by default if possible. + - Fix some svga detection routine. (fixes Grandest Fleet 2 and Bobby Fischer + Teaches Chess) + - You can now close DOSBox using the status window in win32. + - Add support for NX enabled systems. + - Fix a casting error which only showed with certain compilers. (fixes + various games under mac os x and 64 bit linux) + - Improve timer and add gate 2 support. (fixes various games and + joystick problems) + - Improve mouse. Add undocumented backdoor. (fixes Last half of Darkness, + PC-BLOX and others) + - Add/improve support for ~ and ~username in all commands. + - Fix a font problem with the pcjr/tandy. (fixes personal deskmate 2) + - Change dma routine a bit. (fixes ticks in sound in various games) + - Allow read-only diskimages to be booted. (fixes various booter + games) + - Add basic hidden file support on cdrom images. (fixes Player + Manager 2) + - Add some rarely used functionality to the int10 mode setup. (fixes + WW2 Battles of the South pacific) + - Add ability to force scaler usage. + - Speed up flag generation and make it more 386-like. + - Some colourful feedback in the mapper. + - General code cleanup. + +0.70 + - Improve register handling and support with XMS. + - Fix some issues with deleting open files.(windows only issue) + - Add dummy LPT1 class. (windows only issue) + - Improve some of the internal dos commands. (choice, copy and shift) + - Improve ROM area. (for games that use it for random numbers or + overwrite it as some sort of detection thing) + - Improve compatibility of dynamic core by making it handle certain + pagefaults earlier. + - Move internal dos tables around so we have more umb memory. + - Add some dos tables. + - Dynamic core supports io exceptions. + - Move some interrupt handlers to XT Bios locations. + - Add a dynamic fpu on x86. + - Improve fpu on non-x86. + - Trapflag gets strict priority over hardware IRQs. + - Trapflag support for the dynamic core. + - Add dummy TRx handling. + - Fix a few rarely used character functions. + - Improve auto cycle guessing code. + - Improve and extend the joystick support. + - Add autofire support. + - Improve the mapper so you can map keys to the joystick and vice versa. + - A few game specific video card fixes. + - Fix some 64 bit cpu bugs. + - Add support for certain cdrom detection schemes. + - Improve HSG/Red Book support. + - Improve MSCDEX. + - Improve dynamic core support under intel macs. + - Add basic support for clipper programs. + - Add support for different keyboard layouts. + - Add auto core guessing. + - Fix a few flags bugs. + - Fix a few small cpu bugs. + - Improve soundblaster detection rate by various programs. + - Improve EMS emulation. (allow mapping of non standard regions) + - Improve keyboard input codes on various OS-es. + - Fix problems with filenames having stackdata in them. + - Changed a few basic operations in DOSBox so they take emulated time. + - Improve dos ioctl functions. + - Extend cpu core so they are capable of detecting and raising a few + more exception types. + - Improve DOS functions when dealing with virtual drive. + - Improve FAT drives. + - Better handling of volume-labels in file functions. + - Image disk cycling capability. (prompt) + - Try to reduce the impact of using an analog joystick. + - Several measures to avoid code invalidation on certain types + of self modification in the dynamic core. + - Add dynamic core memory function inlining. + - A few small mouse improvements. (some games are using things they + shouldn't) + - Add nullmodem emulation.(h-a-l-9000) + - Some small cga and hercules fixes. + - Add more scalers (hq2x/hq3x/sai). (Kronuz) + - Change configuration file loading support. It now supports + multiple configuration files. + - Make dynamic core capable of running some win32s programs. + - Fix and add some rare soundblaster modes. (Srecko) + - Better soundblaster mixer controls. (Srecko) + - Make soundblaster installation under windows much easier. + - Add device control channel handling. + - GEMMIS support (ems under windows). + - Support more colours in win 3. (vasyl) + - Don't show unmounted drives in windows filemanager. + - Fix some bugs in the int13 handler. + - Simulate some side-effects of bios interrupt handlers on flags. + - Add IPX functions needed by netbios. + - Make ports take emulated time. + - Tabcompletion is now aware of the CD command. + - Add suppport for the dac pel mask. + - Fixes to hercules emulation, better detection and bank switching. + - Fixes to tandy emulation, 640x200x16 mode and different sizes bank. + - EGA/VGA memory changes detection for faster rendering. + - Gus 16 bit fixes. + - Many timer improvements. + - Some pcjr fixes. + - Some booter fixes. + - Many small fixes. + +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. + - Fixed multiple issues with drive labels. + - Fixed most if not all FILES=XX problems. + - Added redirection in the shell. + - Fixed crashes with subst. + - Fixed multiple crashes with the drive images support. + - Added a missing fpu instruction. + - Fixed some cpu and fpu instructions. + - Fixed a small bug related to font loading. + - Rewrote the devices support. + - Added capslock/numlock checks on startup. + - Fixed wave writing. + - A few internal DOS fixes. + - Timer fixes for the hybrid loader. + - Some small soundblaster fixes. + - The drive cache can now be cleared by a keycombo. (CTRL-F4) + - A few keyboard fixes. + - Compilation fixes on various platforms. + - Quite some debugger improvements. + - Fixed dir only showing files after the first run on cdrom drives. + - Added some cdrom detection checks. + - Enabled insert in the shell. (Easier editing of commands) + - Changed order in which executables appear with tab-completion. + - Fixed some issues with raw opl recording and using a slightly different + format + +0.62 + - Added blinking support in the shell and some color fixes. + - Fixed commandline parsing when .bat files involved (fixes -exit) + - Fixed issues with tabs in commandline not being processed correctly. + - Cleaned/improved shutdown sequence. + - Added some more bios functions (wait and delay functions). + - Made our XMS driver conform the specs better. (c2woody) + - Added support for some more ems functions. + - Added intelligent mpu401 emulation. (Srecko) + - Added soundblaster 16 emulation. + - Rewrote GUS emulation to sound more authentic. + - Improved pc speaker emulation. + - Added an internal (programmable) mixer. + - Added support a few soundblaster/adlib detection routines. + - Fixed lot's of bugs related to DMA transfers. + - Added interpolating prebuffering mixer routines. + - Added recording of OPL commands and raw midi. + - Fixed some bugs with the wave recording. + - Changed sensitivity settings of the mouse. + - Added ps2 mouse-emulation in bios interrupts (c2woody). + - Fixed some bugs with mouse emulation limits. + - Fixed a bug with an unterminated string in the drivelabel. + - Changed file search routines a bit to be more compatible. + - Added support for attribute-searching with fcb's. + - Added basic SDA. + - Added TPA and DIB. + - Added Lot's of missing dos tables (c2woody). + - Changed psp and dta functions to use dta. + - Returned filename in ds:dx in create-random-file (c2woody). + - Fixed a bug with date and time used on open files. + - Some mscdex fixes. + - Added the -version switch, which makes dosbox report its version. + - Added a keymapper. + - Added basic IPX emulation. + - Added cdrom iso support and floppy images support. + - Added the possibity to boot another dos version. + - Added Serial passthrough support (win32 only). + - Added the possibility to pause dosbox. + - Changed OpenGL so that it is initialized only when used. + - Make dosbox run at higher priority when active and lower when inactive. + - Added direct draw output support (win32 only). + - Added current running program to title bar. + - Rewrote video emulation to support new scalers. + - Added new graphics scalers like advmame3x,tv2x. + - Added a support for a few anti-debugger tricks. + - Improved the handling of the tab-key. + - Improved support for the numeric keyboard. + - Fixed a few cpu opcodes. + - Added cpu core simple (for lowerend machines) + - Fixed some nasty bugs in the dynamic cpu core. + - Added a few (rarely used) fpu opcodes. + - Fixed various issues with GCC 3.4. + - Many internal timer improvements (PIT and PIC). + - Added some more PIC commands (c2woody). + - Added BCD counting to the timers. + - Fix some vesa functions. + - Add some basic support for 132x25 and 132x45 textmodes. + - Improved Tandy emulation a lot. + - Lowered cpu usage when dosbox is idle. + - Allow virtualisation of some basic IO-ports (c2woody). + + +0.61 + - Added a beta dynamic cpu for x86 hosts (very unstable) + - Added opengl and hardware overlay display output + - Rewrote the vga screen updates to go in lines + - Added paging and v86 support to cpu emulation + - Added a config option to simulate a certain type of machine + - Added hercules graphics emulation + - Made CGA/TANDY modes more compatible + - Updated textmode drawing routines to support blinking colors + - Fixed VESA set page function that was documented wrong + - Fixed some wrongly emulated cpu opcodes. + - improved exception handling + - debugger: fixes; logging of gdt,lgt,idt, new commands(Fizzban) + - fixed some mscdex issues (drive letter header error, added get directory entry) + - added/fixed some bios funcs + - added some rarely used xms functions (thanks c2woody!) + - implemented GUS emulation + - Added 16-bit DMA support (for GUS and eventually SB16) + - Fixed many small bugs in filehandling routines + - Many small FPU fixes (c2woody/Fizzban) + - Some keyboard improvements (pharlab games) + - Some Timer and cmos/rtc fixes (Mirek/Srecko/Others) + - Lot's of mouse fixes (Help from various people) + - Enabled internal modem + - Made the DOS parsing routines a bit more flexible + - Added Subst (Srecko) + - Added cdrom ioctl support for linux (prompt) + - Many internal DOS fixes: memory/files/datastructures. + - Got some help from c2woody in allowing more than 1 irq being served + - Disabled DPMI (not needed anymore. DOSBox handles almost every extender) + - Search configfile in $HOME directory if none present in current directory + - Added another way to switch to protected mode. (Thanks Morten Eriksen!) + - Fixed some odd badly documented behaviour with PSP/DTA + - Added some warnings on opening of readonly files in writemode(DOS default). + - Many shell enhanchements + - Fixed a win32 specific bug dealing with filenames starting with a "." + - Fixed some bugs with the directory structure: not found/can't save errors + +0.60 + - rewrote memory system for future paging support + - fixed several EMS and XMS bugs and rewrite for new memory system + - added some support for tandy video modes + - added MAME Tandy 3 voice emulation + - added MAME CMS/GameBlaster emulation + - added serial port emulation with virtual tcp/ip modem (somewhat buggy) + - sound blaster emulation is now sb pro 2.0 compatible + - added basic support for 32-bit protected mode + - VGA now tries to emulate an S3 Trio 64 card with 2 MB + - VESA 2.0 support for some 256 color modes + - rewrote large piece of video bios code for better compatibility + - added support for the not inheritance flags. + - created functions for creating child psp. + - updated errorcodes of findfirst (thanks Mirek!) + - rewrote loggingsystem to generate less warnings + - added dos protected mode interface (dpmi) + - added cdrom label support + - improved cdrom audio playing + - fixed and improved directory cache + - debugger shows selector- and cpu mode info + - added SELINFO (selector information) command to debugger + - added reference counting for dos files + - added tab-completion + - added basic fpu support. + - fixed several bugs with case sensitive filesystems. + - added more shell commands and improved their behaviour. + - mouse improvements. + - real time clock improvements. + - DMA fixes. + - Improved .BAT file support. + +0.58 + - fixed date and time issues with fcbs + - added more commands to the internal Shell + - corrected config system when a old configfile was used + - fixed cga put and get pixel + - fixed some vga register getting reset to wrong values + - improved support for foreign keyboards + - improved joystick support + - made dosbox multithreaded again + - lot's of soundblaster fixes + - dma fixes + - cdrom support + - midi support + - added scale2x + - reenabled screenshot support + - joystick support fixes + - mouse improvements + - support for writing wavefiles + - added directory cache and longfilename support (longfilenames will be mangled) + - mouse fixes + - date and time updates at z:\ + - added (partial) direct disk support. (works probably only if directory is mounted under a:\) + - added support for env variables. (must be set before starting dosbox: DOSBOX_SECTION_PROPERTY=value + like DOSBOX_SBLASTER_IRQ=1) +0.57 + - added support for command /C + - fixed all fcb-write functions + - fixed fcb-parseline + - added debugger under linux/freebsd + - added debugger memory breakpoints and autolog function (heavy debug) + - added loadfix.com program that eats up memory (default 64kb) + Usage : loadfix [-option] [programname] [parameters]... + Example: loadfix mm2 (Allocates 64kb and starts executable mm2) + loadfix -32 mm2 (Allocates 32kb and starts executable mm2) + loadfix -128 (Allocates 128kb) + loadfix -f (frees all previous allocated memory) + - added echoing of characters for input function + - added support for backspace for input function + - added partial support for int10:01 set cursortype + - fixed most of the problems/bugs with character input. + - fixed allocationinfo call.(darksun series) + - improved dos support for non-existant functions + - Split screen support + - prefix 66 67 support + - rewrote timingscheme so 1000 hz timers don't cause problems anymore + - update adlib emulation + - fixed some isues with the mouse (double clicks and visible when it shouldn't be) + - improved mouse behaviour (mickey/pixel rate) and detection routines. + - basic ansi.sys support + - Disney sound system emulation + - rewrote upcase/lowcase functions so they work fine with gcc3.2 + - SHELL: added rename and delete + - added support for command /C. Fixed crashes in the shell + - fixed various bugs when exiting dosbox + - fixed a bug in XMS + - fixed a bug with the joystick when pressing a button + - create nicer configfiles. + - bios_disk function improved. + - trapflag support + - improved vertical retrace timing. + - PIT Timer improvements and many bug fixes + - Many many bug fixes to the DOS subsystem + - Support for memory allocation strategy + - rewrote cpu mainloop to act more like a real cpu + +0.56 + - added support for a configclass/configfile + - added support for writing out the configclass into a configfile + - removed the language file and made it internal + - added support for writing the language file (will override the internal one) + - improved mousesupport + - updated readme + - support for screenshots + - some cpu-bug fixes + - dma changes + - Real Sound support + - EMM fixes and new functions. + - VGA fixes + - new wildcompare + - support for size and disktype at mount. + - added new debugger functionalities: start/trace into INTs, write processor status log, + step over rep and loop instructions, breakpoint support without using INT 03 (heavy debugging switch) + - Added more cpu instructions and changed the string operations. + - Added classes for most of the internal dos structures. + - Rewrote most of the fcb calls to use normal dos calls. + +0.55 + - fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned). + - fixed compilation error on FreeBSD when #disable_joystick was defined + - int10_writechar has been updated to move the cursor position. + - changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :) + - illegal command, now displays the command + - wildcmp updated to be case insensitive + - added fcb:open,close,findfirst, findnext. + - fixed rename in drive_local + - added new features to the debugger: breakpoint support / data view / command line + - partial support of list of lists (dos info block) + - full emm 3.2 support + - partial emm 4.0 support + - fixes to graphics core fonts (text in sierra games is now correct) + - improved support for user mousehandlers + - fixed EGA graphics + - fixed VGA graphics + - fixed write with size 0 + - changed memory management. + - fixed and cleaned up the cpu flags. + - changed interrupt handler. + - speeded up the graphics. + - speeded up the cpu-core + - changed dma + - improved dma streams from emm memory + - added some cga videomodes + - added more funtions to the keyboard handler diff --git a/INSTALL b/INSTALL index 3a9548f..cc48f8e 100644 --- a/INSTALL +++ b/INSTALL @@ -1,104 +1,104 @@ -Things needed for compilation. - -SDL - The Simple DirectMedia Library available at http://www.libsdl.org - The dll distributed with the windows version of DOSBox is slightly - modified. You can find the changes in the sourcepackage of DOSBox - (src/platform/sdl-win32.diff). If you want the patched sourcetree - send us an email. (see README) - Licensed under LGPL - Note that only version 1.2 and its subversions (1.2.8, 1.2.13 etc.) - are currently supported. - -Curses (optional) - If you want to enable the debugger you need a curses library. - ncurses should be installed on just about every unix distro. - For win32 get pdcurses at http://pdcurses.sourceforge.net - License: Open source - -Libpng (optional) - Needed for the screenshots. - For win32 get libpng from http://gnuwin32.sourceforge.net/packages.html - See http://www.libpng.org/pub/png/ for more details. - License: Open Source - -Zlib (optional) - Needed by libpng. - For win32 get libz (rename to zlib) from http://gnuwin32.sourceforge.net/packages.html - See http://www.zlib.net for more details. - License: Open Source - -SDL_Net (optional) - For modem/ipx support. Get it from http://www.libsdl.org/projects/SDL_net/ - Licensed under LGPL - -SDL_Sound - For compressed audio on diskimages. (optional) - This is for cue/bin cdrom images with compressed (mp3/ogg) audio tracks. - Get it from http://icculus.org/SDL_sound - Licenced under LGPL - -ALSA_Headers - (optional) - for Alsa support under linux. Part of the linux kernel sources - Licensed under LGPL - -If you want compile from the CVS under a unix system, you'll also need -automake (>=1.6), autoconf(>=2.50). Should be available at http://www.gnu.org - -For building on unix systems. -If you are building from the cvs run ./autogen.sh first before doing the following. - -1. ./configure -2. make - -In step 1 you could add the following switches: ---enable-debug - enables the internal debugger. --enable-debug=heavy enables even more - debug options. DOSBox should then be run from a xterm and when the sdl- - window is active press alt-pause to enter the debugger. - ---enable-core-inline - enables some memory increasing inlines. This greatly increases - compiletime for maybe a increase in speed. - ---disable-fpu - disables the emulated fpu. Although the fpu emulation code isn't - finished and isn't entirely accurate it's advised to leave it on. - ---disable-fpu-x86 - disables the assembly fpu core. Although relatively new the x86 fpu - core has more accuracy then the regular fpu core. - ---disable-dynamic-x86 - disables the dynamic x86 specific cpu core. Although it might be - be a bit unstable, it can greatly improve the speed of dosbox on x86 - hosts. - Please note that this option on x86 will result in a different - dynamic/recompiling cpu core being compiled then the default. - For more information see the option --disable-dynrec - ---disable-dynrec - disables the recompiling cpu core. Currently x86 and x86_64 only. - You can activate this core on x86 by disabling the dynamic-x86 core. - ---disable-dynamic-core - disables all dynamic cores. (same effect as - --disable-dynamic-x86 --disable-dynrec) - ---disable-opengl - disables OpenGL-support (output mode that can be selected in the - DOSBox configuration file). - ---disable-unaligned-memory - disables unaligned memory access. - -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 -Don't use VC++ 6: it creates faulty code in core_normal.cpp -Later Visual Studio versions work fine (vs2003/.net, vs2005, vs2008) +Things needed for compilation. + +SDL + The Simple DirectMedia Library available at http://www.libsdl.org + The dll distributed with the windows version of DOSBox is slightly + modified. You can find the changes in the sourcepackage of DOSBox + (src/platform/sdl-win32.diff). If you want the patched sourcetree + send us an email. (see README) + Licensed under LGPL + Note that only version 1.2 and its subversions (1.2.8, 1.2.13 etc.) + are currently supported. + +Curses (optional) + If you want to enable the debugger you need a curses library. + ncurses should be installed on just about every unix distro. + For win32 get pdcurses at http://pdcurses.sourceforge.net + License: Open source + +Libpng (optional) + Needed for the screenshots. + For win32 get libpng from http://gnuwin32.sourceforge.net/packages.html + See http://www.libpng.org/pub/png/ for more details. + License: Open Source + +Zlib (optional) + Needed by libpng. + For win32 get libz (rename to zlib) from http://gnuwin32.sourceforge.net/packages.html + See http://www.zlib.net for more details. + License: Open Source + +SDL_Net (optional) + For modem/ipx support. Get it from http://www.libsdl.org/projects/SDL_net/ + Licensed under LGPL + +SDL_Sound + For compressed audio on diskimages. (optional) + This is for cue/bin cdrom images with compressed (mp3/ogg) audio tracks. + Get it from http://icculus.org/SDL_sound + Licenced under LGPL + +ALSA_Headers + (optional) + for Alsa support under linux. Part of the linux kernel sources + Licensed under LGPL + +If you want compile from the CVS under a unix system, you'll also need +automake (>=1.6), autoconf(>=2.50). Should be available at http://www.gnu.org + +For building on unix systems. +If you are building from the cvs run ./autogen.sh first before doing the following. + +1. ./configure +2. make + +In step 1 you could add the following switches: +--enable-debug + enables the internal debugger. --enable-debug=heavy enables even more + debug options. DOSBox should then be run from a xterm and when the sdl- + window is active press alt-pause to enter the debugger. + +--enable-core-inline + enables some memory increasing inlines. This greatly increases + compiletime for maybe a increase in speed. + +--disable-fpu + disables the emulated fpu. Although the fpu emulation code isn't + finished and isn't entirely accurate it's advised to leave it on. + +--disable-fpu-x86 + disables the assembly fpu core. Although relatively new the x86 fpu + core has more accuracy then the regular fpu core. + +--disable-dynamic-x86 + disables the dynamic x86 specific cpu core. Although it might be + be a bit unstable, it can greatly improve the speed of dosbox on x86 + hosts. + Please note that this option on x86 will result in a different + dynamic/recompiling cpu core being compiled then the default. + For more information see the option --disable-dynrec + +--disable-dynrec + disables the recompiling cpu core. Currently x86 and x86_64 only. + You can activate this core on x86 by disabling the dynamic-x86 core. + +--disable-dynamic-core + disables all dynamic cores. (same effect as + --disable-dynamic-x86 --disable-dynrec) + +--disable-opengl + disables OpenGL-support (output mode that can be selected in the + DOSBox configuration file). + +--disable-unaligned-memory + disables unaligned memory access. + +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 +Don't use VC++ 6: it creates faulty code in core_normal.cpp +Later Visual Studio versions work fine (vs2003/.net, vs2005, vs2008) diff --git a/NEWS b/NEWS index 2b36f03..d303e45 100644 --- a/NEWS +++ b/NEWS @@ -1,594 +1,594 @@ -0.73 - - Add two new opl2+opl3 emulators. (better speed, different implementation - approach) - - Improved DRO recording/better file structure. - - Add EGA emulation. - - Add special vga machine mode. Supports more of the exotic tricks like - changing the palette during screen updates, 9x16 fonts etc. - - Added special machine modes for the following svga cards: - - S3 - - Paradise - - Tseng - - Fix problems with the vga split line feature. - - Improve vesa emulation. - - Add optional selection of old vesa mode for games that don't work - with certain vesa features. - - Improve video BIOS emulation to behave more like a real bios. - - Fixes for emulated 4bpp graphics modes. - - Fixes to paging system. - - Various fixes and improvements for the recompiling core. - - Add arm backend for the recompiling core. - - Add some mscdex quirks when dealing with files that are exactly 8.3 long. - - Small fixes to batch file handling. - - Small fixes to the XMS memory handling. - - Various fixes for aligned memory on hosts that want it. - - Various improvements to the mouse. - - Fixes and small speed ups to the debugger. - - Fix and improve lot's of compilation problems. (curses detection, - GCC 3.4 and GCC 4.X fixes) - - Added some basic auto keyboard layout handling. (windows only currently) - - Add basic support for evdev keyboard driver. - - Various fixes to the timer. (improve mode 2 timer changes, - implement mode 1, improve gate2 handling) - - Add audio extraction and mci audio support. Should enable CDROM audio - for Vista and adds volume control. - - Improve the directory cache speed a lot, especially with mounting slow - media like network paths. - - Various fixes to the create temporary file call. - - Don't keep batchfiles open during execution. Allows rewriting of the - active batchfile. (menu programs use this trick sometimes) - - Fix problems with filenames with 2 extensions. - - Add some more lowlevel dos tables. - - Fixes to hercules emulation. - - Fix flag handling for special case of ROR. - - Make the batchfile handling in regard to IF more flexible. - - Fixes to scrolling/panning feature. - - Add prefetch queue emulation. - - Make the emulated cpu type selectable. This is mainly the - identification commands and the way paging works. - - Some special EMS functionality added. (OS handles, zero-page handling) - - Improve support for EMS when booting a different OS. - - Improve cdrom speed detection by games. - - Improve stability of cycle guessing code, when there is background - activity. - - Fix various mscdex and cdrom detection schemes. - - Added Coremidi support on Mac OS X. - - Improve support for DOS devices when used to detect the existance - of directories in various ways. - - Add IRQ 2 emulation on VRET. (ega only) - - Added video parameter table and video state functionality. - - Increase default freespace to 250 MB. - - Some fixes to the fat filesystem handling for disk images. - - Some soundblaster fixes and command additions. - - Fix mixer 16bit direct transfers on bigendian hosts. - -0.72 - - Fixed unitialized variable in joystick. (Fixes crashes on Vista and - Mac OS X) - - Some bugfixes and speedups to the 64 bit recompiling core. - - Fixed sign flag on soundblaster dma transfers (Space Quest 6 intro) - - Fixed a bug in keyboard layout processing code and fixed certain - layouts. - - Fixed Dreamweb. - - Improved speed unlocking when running cycles=max. - - Fixed a crash related to the tab completion in the shell. - - Improved aspect correction code. Should now be like how a real monitor - handles it. - - Fixed a bug in the xms status report code. (Blake Stone 1.0 shareware) - - Added a lot more keyboard layouts. - - Fix crash related to changing the scaler before a screen was created. - - Hopefully fixed compilation on *bsd. - - Enabled auto cpu core selection for recompiling core as well. - - Made the used joystick selectable when 4axis is specified. - - Added some hints for inexperienced DOS users to the shell. - -0.71 - - Add a new recompiling cpu core, which should be easier to port. - - Add 64 bit version of the recompiling core. - - Add mipsel 32 bit version of the recompiling core. - - Fix a few small problems with FCBs. (fixes Jewels of darkness and - cyrus chess) - - Raise some more exceptions. (fixes vbdos) - - Fix a few problems with the dynamic core. (fixes Inner Words, - Archmimedean Dynasty and others) - - Improve/Fix fallback code for certain graphics cards. - - Fix a few cd audio related bugs. - - Add an undocumented MSCDEX feature. (Fixes Ultimate Domain) - - Fix some pcspeaker mode. (fixes Test Drive and similar games) - - Improve dos keyinput handling. (fixes Wing Commander 3 exit dialog) - - Remove Exit condition on fully nested mode. (fixes some demo) - - Add image file size detection. - - Add/Fix some ansi codes. (fixes PC Larn and certain versions of - infocom games) - - Several general DOS fixes. (fixes nba95, hexit and various other games) - - Add some valid input checks. (fixes 3d body adventure and similar - games) - - Fix digital joystick centering problem. - - Reenable textmode 54 and 55. - - Fix a pelmask problem with univbe 5.0 lite. (fixes Panzer General) - - Fix minor mixer underflow. - - Some general image and bios disk emulation fixes. - - Hopefully fix compilation on BSD and darwin. - - Try using ioctl cdrom access by default if possible. - - Fix some svga detection routine. (fixes Grandest Fleet 2 and Bobby Fischer - Teaches Chess) - - You can now close DOSBox using the status window in win32. - - Add support for NX enabled systems. - - Fix a casting error which only showed with certain compilers. (fixes - various games under mac os x and 64 bit linux) - - Improve timer and add gate 2 support. (fixes various games and - joystick problems) - - Improve mouse. Add undocumented backdoor. (fixes Last half of Darkness, - PC-BLOX and others) - - Add/improve support for ~ and ~username in all commands. - - Fix a font problem with the pcjr/tandy. (fixes personal deskmate 2) - - Change dma routine a bit. (fixes ticks in sound in various games) - - Allow read-only diskimages to be booted. (fixes various booter - games) - - Add basic hidden file support on cdrom images. (fixes Player - Manager 2) - - Add some rarely used functionality to the int10 mode setup. (fixes - WW2 Battles of the South pacific) - - Add ability to force scaler usage. - - Speed up flag generation and make it more 386-like. - - Some colourful feedback in the mapper. - - General code cleanup. - -0.70 - - Improve register handling and support with XMS. - - Fix some issues with deleting open files.(windows only issue) - - Add dummy LPT1 class. (windows only issue) - - Improve some of the internal dos commands. (choice, copy and shift) - - Improve ROM area. (for games that use it for random numbers or - overwrite it as some sort of detection thing) - - Improve compatibility of dynamic core by making it handle certain - pagefaults earlier. - - Move internal dos tables around so we have more umb memory. - - Add some dos tables. - - Dynamic core supports io exceptions. - - Move some interrupt handlers to XT Bios locations. - - Add a dynamic fpu on x86. - - Improve fpu on non-x86. - - Trapflag gets strict priority over hardware IRQs. - - Trapflag support for the dynamic core. - - Add dummy TRx handling. - - Fix a few rarely used character functions. - - Improve auto cycle guessing code. - - Improve and extend the joystick support. - - Add autofire support. - - Improve the mapper so you can map keys to the joystick and vice versa. - - A few game specific video card fixes. - - Fix some 64 bit cpu bugs. - - Add support for certain cdrom detection schemes. - - Improve HSG/Red Book support. - - Improve MSCDEX. - - Improve dynamic core support under intel macs. - - Add basic support for clipper programs. - - Add support for different keyboard layouts. - - Add auto core guessing. - - Fix a few flags bugs. - - Fix a few small cpu bugs. - - Improve soundblaster detection rate by various programs. - - Improve EMS emulation. (allow mapping of non standard regions) - - Improve keyboard input codes on various OS-es. - - Fix problems with filenames having stackdata in them. - - Changed a few basic operations in DOSBox so they take emulated time. - - Improve dos ioctl functions. - - Extend cpu core so they are capable of detecting and raising a few - more exception types. - - Improve DOS functions when dealing with virtual drive. - - Improve FAT drives. - - Better handling of volume-labels in file functions. - - Image disk cycling capability. (prompt) - - Try to reduce the impact of using an analog joystick. - - Several measures to avoid code invalidation on certain types - of self modification in the dynamic core. - - Add dynamic core memory function inlining. - - A few small mouse improvements. (some games are using things they - shouldn't) - - Add nullmodem emulation.(h-a-l-9000) - - Some small cga and hercules fixes. - - Add more scalers (hq2x/hq3x/sai). (Kronuz) - - Change configuration file loading support. It now supports - multiple configuration files. - - Make dynamic core capable of running some win32s programs. - - Fix and add some rare soundblaster modes. (Srecko) - - Better soundblaster mixer controls. (Srecko) - - Make soundblaster installation under windows much easier. - - Add device control channel handling. - - GEMMIS support (ems under windows). - - Support more colours in win 3. (vasyl) - - Don't show unmounted drives in windows filemanager. - - Fix some bugs in the int13 handler. - - Simulate some side-effects of bios interrupt handlers on flags. - - Add IPX functions needed by netbios. - - Make ports take emulated time. - - Tabcompletion is now aware of the CD command. - - Add suppport for the dac pel mask. - - Fixes to hercules emulation, better detection and bank switching. - - Fixes to tandy emulation, 640x200x16 mode and different sizes bank. - - EGA/VGA memory changes detection for faster rendering. - - Gus 16 bit fixes. - - Many timer improvements. - - Some pcjr fixes. - - Some booter fixes. - - Many small fixes. - -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. - - Fixed multiple issues with drive labels. - - Fixed most if not all FILES=XX problems. - - Added redirection in the shell. - - Fixed crashes with subst. - - Fixed multiple crashes with the drive images support. - - Added a missing fpu instruction. - - Fixed some cpu and fpu instructions. - - Fixed a small bug related to font loading. - - Rewrote the devices support. - - Added capslock/numlock checks on startup. - - Fixed wave writing. - - A few internal DOS fixes. - - Timer fixes for the hybrid loader. - - Some small soundblaster fixes. - - The drive cache can now be cleared by a keycombo. (CTRL-F4) - - A few keyboard fixes. - - Compilation fixes on various platforms. - - Quite some debugger improvements. - - Fixed dir only showing files after the first run on cdrom drives. - - Added some cdrom detection checks. - - Enabled insert in the shell. (Easier editing of commands) - - Changed order in which executables appear with tab-completion. - - Fixed some issues with raw opl recording and using a slightly different - format - -0.62 - - Added blinking support in the shell and some color fixes. - - Fixed commandline parsing when .bat files involved (fixes -exit) - - Fixed issues with tabs in commandline not being processed correctly. - - Cleaned/improved shutdown sequence. - - Added some more bios functions (wait and delay functions). - - Made our XMS driver conform the specs better. (c2woody) - - Added support for some more ems functions. - - Added intelligent mpu401 emulation. (Srecko) - - Added soundblaster 16 emulation. - - Rewrote GUS emulation to sound more authentic. - - Improved pc speaker emulation. - - Added an internal (programmable) mixer. - - Added support a few soundblaster/adlib detection routines. - - Fixed lot's of bugs related to DMA transfers. - - Added interpolating prebuffering mixer routines. - - Added recording of OPL commands and raw midi. - - Fixed some bugs with the wave recording. - - Changed sensitivity settings of the mouse. - - Added ps2 mouse-emulation in bios interrupts (c2woody). - - Fixed some bugs with mouse emulation limits. - - Fixed a bug with an unterminated string in the drivelabel. - - Changed file search routines a bit to be more compatible. - - Added support for attribute-searching with fcb's. - - Added basic SDA. - - Added TPA and DIB. - - Added Lot's of missing dos tables (c2woody). - - Changed psp and dta functions to use dta. - - Returned filename in ds:dx in create-random-file (c2woody). - - Fixed a bug with date and time used on open files. - - Some mscdex fixes. - - Added the -version switch, which makes dosbox report its version. - - Added a keymapper. - - Added basic IPX emulation. - - Added cdrom iso support and floppy images support. - - Added the possibity to boot another dos version. - - Added Serial passthrough support (win32 only). - - Added the possibility to pause dosbox. - - Changed OpenGL so that it is initialized only when used. - - Make dosbox run at higher priority when active and lower when inactive. - - Added direct draw output support (win32 only). - - Added current running program to title bar. - - Rewrote video emulation to support new scalers. - - Added new graphics scalers like advmame3x,tv2x. - - Added a support for a few anti-debugger tricks. - - Improved the handling of the tab-key. - - Improved support for the numeric keyboard. - - Fixed a few cpu opcodes. - - Added cpu core simple (for lowerend machines) - - Fixed some nasty bugs in the dynamic cpu core. - - Added a few (rarely used) fpu opcodes. - - Fixed various issues with GCC 3.4. - - Many internal timer improvements (PIT and PIC). - - Added some more PIC commands (c2woody). - - Added BCD counting to the timers. - - Fix some vesa functions. - - Add some basic support for 132x25 and 132x45 textmodes. - - Improved Tandy emulation a lot. - - Lowered cpu usage when dosbox is idle. - - Allow virtualisation of some basic IO-ports (c2woody). - -0.61 - - Added a beta dynamic cpu for x86 hosts (very unstable) - - Added opengl and hardware overlay display output - - Rewrote the vga screen updates to go in lines - - Added paging and v86 support to cpu emulation - - Added a config option to simulate a certain type of machine - - Added hercules graphics emulation - - Made CGA/TANDY modes more compatible - - Updated textmode drawing routines to support blinking colors - - Fixed VESA set page function that was documented wrong - - Fixed some wrongly emulated cpu opcodes. - - improved exception handling - - debugger: fixes; logging of gdt,lgt,idt, new commands(Fizzban) - - fixed some mscdex issues (drive letter header error, added get directory entry) - - added/fixed some bios funcs - - added some rarely used xms functions (thanks c2woody!) - - implemented GUS emulation - - Added 16-bit DMA support (for GUS and eventually SB16) - - Fixed many small bugs in filehandling routines - - Many small FPU fixes (c2woody/Fizzban) - - Some keyboard improvements (pharlab games) - - Some Timer and cmos/rtc fixes (Mirek/Srecko/Others) - - Lot's of mouse fixes (Help from various people) - - Enabled internal modem - - Made the DOS parsing routines a bit more flexible - - Added Subst (Srecko) - - Added cdrom ioctl support for linux (prompt) - - Many internal DOS fixes: memory/files/datastructures. - - Got some help from c2woody in allowing more than 1 irq being served - - Disabled DPMI (not needed anymore. DOSBox handles almost every extender) - - Search configfile in $HOME directory if none present in current directory - - Added another way to switch to protected mode. (Thanks Morten Eriksen!) - - Fixed some odd badly documented behaviour with PSP/DTA - - Added some warnings on opening of readonly files in writemode(DOS default). - - Many shell enhanchements - - Fixed a win32 specific bug dealing with filenames starting with a "." - - Fixed some bugs with the directory structure: not found/can't save errors - -0.60 - - rewrote memory system for future paging support - - fixed several EMS and XMS bugs and rewrite for new memory system - - added some support for tandy video modes - - added MAME Tandy 3 voice emulation - - added MAME CMS/GameBlaster emulation - - added serial port emulation with virtual tcp/ip modem (somewhat buggy) - - sound blaster emulation is now sb pro 2.0 compatible - - added basic support for 32-bit protected mode - - VGA now tries to emulate an S3 Trio 64 card with 2 MB - - VESA 2.0 support for some 256 color modes - - rewrote large piece of video bios code for better compatibility - - added support for the not inheritance flags. - - created functions for creating child psp. - - updated errorcodes of findfirst (thanks Mirek!) - - rewrote loggingsystem to generate less warnings - - added dos protected mode interface (dpmi) - - added cdrom label support - - improved cdrom audio playing - - fixed and improved directory cache - - debugger shows selector- and cpu mode info - - added SELINFO (selector information) command to debugger - - added reference counting for dos files - - added tab-completion - - added basic fpu support. - - fixed several bugs with case sensitive filesystems. - - added more shell commands and improved their behaviour. - - mouse improvements. - - real time clock improvements. - - DMA fixes. - - Improved .BAT file support. - -0.58 - - fixed date and time issues with fcbs - - added more commands to the internal Shell - - corrected config system when a old configfile was used - - fixed cga put and get pixel - - fixed some vga register getting reset to wrong values - - improved support for foreign keyboards - - improved joystick support - - made dosbox multithreaded again - - lot's of soundblaster fixes - - dma fixes - - cdrom support - - midi support - - added scale2x - - reenabled screenshot support - - joystick support fixes - - mouse improvements - - support for writing wavefiles - - added directory cache and longfilename support (longfilenames will be mangled) - - mouse fixes - - -0.57 - - added support for command /C - - fixed all fcb-write functions - - fixed fcb-parseline - - added debugger under linux/freebsd - - added debugger memory breakpoints and autolog function (heavy debug) - - added loadfix.com program that eats up memory (default 64kb) - Usage : loadfix [-option] [programname] [parameters]... - Example: loadfix mm2 (Allocates 64kb and starts executable mm2) - loadfix -32 mm2 (Allocates 32kb and starts executable mm2) - loadfix -128 (Allocates 128kb) - loadfix -f (frees all previous allocated memory) - - added echoing of characters for input function - - added support for backspace for input function - - added partial support for int10:01 set cursortype - - fixed most of the problems/bugs with character input. - - fixed allocationinfo call.(darksun series) - - improved dos support for non-existant functions - - Split screen support - - prefix 66 67 support - - rewrote timingscheme so 1000 hz timers don't cause problems anymore - - update adlib emulation - - fixed some isues with the mouse (double clicks and visible when it shouldn't be) - - improved mouse behaviour (mickey/pixel rate) and detection routines. - - basic ansi.sys support - - Disney sound system emulation - - rewrote upcase/lowcase functions so they work fine with gcc3.2 - - SHELL: added rename and delete - - added support for command /C. Fixed crashes in the shell - - fixed various bugs when exiting dosbox - - fixed a bug in XMS - - fixed a bug with the joystick when pressing a button - - create nicer configfiles. - - bios_disk function improved. - - trapflag support - - improved vertical retrace timing. - - PIT Timer improvements and many bug fixes - - Many many bug fixes to the DOS subsystem - - Support for memory allocation strategy - - rewrote cpu mainloop to act more like a real cpu - -0.56 - - added support for a configclass/configfile - - added support for writing out the configclass into a configfile - - removed the language file and made it internal - - added support for writing the language file (will override the internal one) - - improved mousesupport - - updated readme - - support for screenshots - - some cpu-bug fixes - - dma changes - - Real Sound support - - EMM fixes and new functions. - - VGA fixes - - new wildcompare - - support for size and disktype at mount. - - added new debugger functionalities: start/trace into INTs, write processor status log, - step over rep and loop instructions, breakpoint support without using INT 03 (heavy debugging switch) - - Added more cpu instructions and changed the string operations. - - Added classes for most of the internal dos structures. - - Rewrote most of the fcb calls to use normal dos calls. - -0.55 - - fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned). - - fixed compilation error on FreeBSD when #disable_joystick was defined - - int10_writechar has been updated to move the cursor position. - - changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :) - - illegal command, now displays the command - - wildcmp updated to be case insensitive - - added fcb:open,close,findfirst, findnext. - - fixed rename in drive_local - - added new features to the debugger: breakpoint support / data view / command line - - partial support of list of lists (dos info block) - - full emm 3.2 support - - partial emm 4.0 support - - fixes to graphics core fonts (text in sierra games is now correct) - - improved support for user mousehandlers - - fixed EGA graphics - - fixed VGA graphics - - fixed write with size 0 - - changed memory management. - - fixed and cleaned up the cpu flags. - - changed interrupt handler. - - speeded up the graphics. - - speeded up the cpu-core - - changed dma - - improved dma streams from emm memory - - added some cga videomodes - - added more funtions to the keyboard handler - -0.50: - -added F3 to repeat the last typed command. - -made it possible to change the shellmessages(dosshell). so - you can costumize it.(dosbox.lang) - -changed cpu core. - -Fixed a lot of errors with the keyboard: shift-f1 and - alt-f1 now works. - -Fixed some division errors. - -made a plugin system. - -added a lot of real 386 mode instructions. - -made it possible to resize the screen. - -Mayor source cleanup/reorganisation. - -Complete rewrite of the graphics routines. Should make it - possible to implement more fancy things like 2xsai,interpolation. - -changed the sound playback. - -Changed the vga drawing to only draw on memory changes, instead - of drawing an entire frame. - -fixes to the soundblaster/dma code should be able to play 4-bit - adpcm compressed sounds. - -added the correct time to dir. - -bugfixes to batch-file handling. - -Lot's of small bugfixes.(Dune1&2,wolf3d, many more). - -Released the source. +0.73 + - Add two new opl2+opl3 emulators. (better speed, different implementation + approach) + - Improved DRO recording/better file structure. + - Add EGA emulation. + - Add special vga machine mode. Supports more of the exotic tricks like + changing the palette during screen updates, 9x16 fonts etc. + - Added special machine modes for the following svga cards: + - S3 + - Paradise + - Tseng + - Fix problems with the vga split line feature. + - Improve vesa emulation. + - Add optional selection of old vesa mode for games that don't work + with certain vesa features. + - Improve video BIOS emulation to behave more like a real bios. + - Fixes for emulated 4bpp graphics modes. + - Fixes to paging system. + - Various fixes and improvements for the recompiling core. + - Add arm backend for the recompiling core. + - Add some mscdex quirks when dealing with files that are exactly 8.3 long. + - Small fixes to batch file handling. + - Small fixes to the XMS memory handling. + - Various fixes for aligned memory on hosts that want it. + - Various improvements to the mouse. + - Fixes and small speed ups to the debugger. + - Fix and improve lot's of compilation problems. (curses detection, + GCC 3.4 and GCC 4.X fixes) + - Added some basic auto keyboard layout handling. (windows only currently) + - Add basic support for evdev keyboard driver. + - Various fixes to the timer. (improve mode 2 timer changes, + implement mode 1, improve gate2 handling) + - Add audio extraction and mci audio support. Should enable CDROM audio + for Vista and adds volume control. + - Improve the directory cache speed a lot, especially with mounting slow + media like network paths. + - Various fixes to the create temporary file call. + - Don't keep batchfiles open during execution. Allows rewriting of the + active batchfile. (menu programs use this trick sometimes) + - Fix problems with filenames with 2 extensions. + - Add some more lowlevel dos tables. + - Fixes to hercules emulation. + - Fix flag handling for special case of ROR. + - Make the batchfile handling in regard to IF more flexible. + - Fixes to scrolling/panning feature. + - Add prefetch queue emulation. + - Make the emulated cpu type selectable. This is mainly the + identification commands and the way paging works. + - Some special EMS functionality added. (OS handles, zero-page handling) + - Improve support for EMS when booting a different OS. + - Improve cdrom speed detection by games. + - Improve stability of cycle guessing code, when there is background + activity. + - Fix various mscdex and cdrom detection schemes. + - Added Coremidi support on Mac OS X. + - Improve support for DOS devices when used to detect the existance + of directories in various ways. + - Add IRQ 2 emulation on VRET. (ega only) + - Added video parameter table and video state functionality. + - Increase default freespace to 250 MB. + - Some fixes to the fat filesystem handling for disk images. + - Some soundblaster fixes and command additions. + - Fix mixer 16bit direct transfers on bigendian hosts. + +0.72 + - Fixed unitialized variable in joystick. (Fixes crashes on Vista and + Mac OS X) + - Some bugfixes and speedups to the 64 bit recompiling core. + - Fixed sign flag on soundblaster dma transfers (Space Quest 6 intro) + - Fixed a bug in keyboard layout processing code and fixed certain + layouts. + - Fixed Dreamweb. + - Improved speed unlocking when running cycles=max. + - Fixed a crash related to the tab completion in the shell. + - Improved aspect correction code. Should now be like how a real monitor + handles it. + - Fixed a bug in the xms status report code. (Blake Stone 1.0 shareware) + - Added a lot more keyboard layouts. + - Fix crash related to changing the scaler before a screen was created. + - Hopefully fixed compilation on *bsd. + - Enabled auto cpu core selection for recompiling core as well. + - Made the used joystick selectable when 4axis is specified. + - Added some hints for inexperienced DOS users to the shell. + +0.71 + - Add a new recompiling cpu core, which should be easier to port. + - Add 64 bit version of the recompiling core. + - Add mipsel 32 bit version of the recompiling core. + - Fix a few small problems with FCBs. (fixes Jewels of darkness and + cyrus chess) + - Raise some more exceptions. (fixes vbdos) + - Fix a few problems with the dynamic core. (fixes Inner Words, + Archmimedean Dynasty and others) + - Improve/Fix fallback code for certain graphics cards. + - Fix a few cd audio related bugs. + - Add an undocumented MSCDEX feature. (Fixes Ultimate Domain) + - Fix some pcspeaker mode. (fixes Test Drive and similar games) + - Improve dos keyinput handling. (fixes Wing Commander 3 exit dialog) + - Remove Exit condition on fully nested mode. (fixes some demo) + - Add image file size detection. + - Add/Fix some ansi codes. (fixes PC Larn and certain versions of + infocom games) + - Several general DOS fixes. (fixes nba95, hexit and various other games) + - Add some valid input checks. (fixes 3d body adventure and similar + games) + - Fix digital joystick centering problem. + - Reenable textmode 54 and 55. + - Fix a pelmask problem with univbe 5.0 lite. (fixes Panzer General) + - Fix minor mixer underflow. + - Some general image and bios disk emulation fixes. + - Hopefully fix compilation on BSD and darwin. + - Try using ioctl cdrom access by default if possible. + - Fix some svga detection routine. (fixes Grandest Fleet 2 and Bobby Fischer + Teaches Chess) + - You can now close DOSBox using the status window in win32. + - Add support for NX enabled systems. + - Fix a casting error which only showed with certain compilers. (fixes + various games under mac os x and 64 bit linux) + - Improve timer and add gate 2 support. (fixes various games and + joystick problems) + - Improve mouse. Add undocumented backdoor. (fixes Last half of Darkness, + PC-BLOX and others) + - Add/improve support for ~ and ~username in all commands. + - Fix a font problem with the pcjr/tandy. (fixes personal deskmate 2) + - Change dma routine a bit. (fixes ticks in sound in various games) + - Allow read-only diskimages to be booted. (fixes various booter + games) + - Add basic hidden file support on cdrom images. (fixes Player + Manager 2) + - Add some rarely used functionality to the int10 mode setup. (fixes + WW2 Battles of the South pacific) + - Add ability to force scaler usage. + - Speed up flag generation and make it more 386-like. + - Some colourful feedback in the mapper. + - General code cleanup. + +0.70 + - Improve register handling and support with XMS. + - Fix some issues with deleting open files.(windows only issue) + - Add dummy LPT1 class. (windows only issue) + - Improve some of the internal dos commands. (choice, copy and shift) + - Improve ROM area. (for games that use it for random numbers or + overwrite it as some sort of detection thing) + - Improve compatibility of dynamic core by making it handle certain + pagefaults earlier. + - Move internal dos tables around so we have more umb memory. + - Add some dos tables. + - Dynamic core supports io exceptions. + - Move some interrupt handlers to XT Bios locations. + - Add a dynamic fpu on x86. + - Improve fpu on non-x86. + - Trapflag gets strict priority over hardware IRQs. + - Trapflag support for the dynamic core. + - Add dummy TRx handling. + - Fix a few rarely used character functions. + - Improve auto cycle guessing code. + - Improve and extend the joystick support. + - Add autofire support. + - Improve the mapper so you can map keys to the joystick and vice versa. + - A few game specific video card fixes. + - Fix some 64 bit cpu bugs. + - Add support for certain cdrom detection schemes. + - Improve HSG/Red Book support. + - Improve MSCDEX. + - Improve dynamic core support under intel macs. + - Add basic support for clipper programs. + - Add support for different keyboard layouts. + - Add auto core guessing. + - Fix a few flags bugs. + - Fix a few small cpu bugs. + - Improve soundblaster detection rate by various programs. + - Improve EMS emulation. (allow mapping of non standard regions) + - Improve keyboard input codes on various OS-es. + - Fix problems with filenames having stackdata in them. + - Changed a few basic operations in DOSBox so they take emulated time. + - Improve dos ioctl functions. + - Extend cpu core so they are capable of detecting and raising a few + more exception types. + - Improve DOS functions when dealing with virtual drive. + - Improve FAT drives. + - Better handling of volume-labels in file functions. + - Image disk cycling capability. (prompt) + - Try to reduce the impact of using an analog joystick. + - Several measures to avoid code invalidation on certain types + of self modification in the dynamic core. + - Add dynamic core memory function inlining. + - A few small mouse improvements. (some games are using things they + shouldn't) + - Add nullmodem emulation.(h-a-l-9000) + - Some small cga and hercules fixes. + - Add more scalers (hq2x/hq3x/sai). (Kronuz) + - Change configuration file loading support. It now supports + multiple configuration files. + - Make dynamic core capable of running some win32s programs. + - Fix and add some rare soundblaster modes. (Srecko) + - Better soundblaster mixer controls. (Srecko) + - Make soundblaster installation under windows much easier. + - Add device control channel handling. + - GEMMIS support (ems under windows). + - Support more colours in win 3. (vasyl) + - Don't show unmounted drives in windows filemanager. + - Fix some bugs in the int13 handler. + - Simulate some side-effects of bios interrupt handlers on flags. + - Add IPX functions needed by netbios. + - Make ports take emulated time. + - Tabcompletion is now aware of the CD command. + - Add suppport for the dac pel mask. + - Fixes to hercules emulation, better detection and bank switching. + - Fixes to tandy emulation, 640x200x16 mode and different sizes bank. + - EGA/VGA memory changes detection for faster rendering. + - Gus 16 bit fixes. + - Many timer improvements. + - Some pcjr fixes. + - Some booter fixes. + - Many small fixes. + +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. + - Fixed multiple issues with drive labels. + - Fixed most if not all FILES=XX problems. + - Added redirection in the shell. + - Fixed crashes with subst. + - Fixed multiple crashes with the drive images support. + - Added a missing fpu instruction. + - Fixed some cpu and fpu instructions. + - Fixed a small bug related to font loading. + - Rewrote the devices support. + - Added capslock/numlock checks on startup. + - Fixed wave writing. + - A few internal DOS fixes. + - Timer fixes for the hybrid loader. + - Some small soundblaster fixes. + - The drive cache can now be cleared by a keycombo. (CTRL-F4) + - A few keyboard fixes. + - Compilation fixes on various platforms. + - Quite some debugger improvements. + - Fixed dir only showing files after the first run on cdrom drives. + - Added some cdrom detection checks. + - Enabled insert in the shell. (Easier editing of commands) + - Changed order in which executables appear with tab-completion. + - Fixed some issues with raw opl recording and using a slightly different + format + +0.62 + - Added blinking support in the shell and some color fixes. + - Fixed commandline parsing when .bat files involved (fixes -exit) + - Fixed issues with tabs in commandline not being processed correctly. + - Cleaned/improved shutdown sequence. + - Added some more bios functions (wait and delay functions). + - Made our XMS driver conform the specs better. (c2woody) + - Added support for some more ems functions. + - Added intelligent mpu401 emulation. (Srecko) + - Added soundblaster 16 emulation. + - Rewrote GUS emulation to sound more authentic. + - Improved pc speaker emulation. + - Added an internal (programmable) mixer. + - Added support a few soundblaster/adlib detection routines. + - Fixed lot's of bugs related to DMA transfers. + - Added interpolating prebuffering mixer routines. + - Added recording of OPL commands and raw midi. + - Fixed some bugs with the wave recording. + - Changed sensitivity settings of the mouse. + - Added ps2 mouse-emulation in bios interrupts (c2woody). + - Fixed some bugs with mouse emulation limits. + - Fixed a bug with an unterminated string in the drivelabel. + - Changed file search routines a bit to be more compatible. + - Added support for attribute-searching with fcb's. + - Added basic SDA. + - Added TPA and DIB. + - Added Lot's of missing dos tables (c2woody). + - Changed psp and dta functions to use dta. + - Returned filename in ds:dx in create-random-file (c2woody). + - Fixed a bug with date and time used on open files. + - Some mscdex fixes. + - Added the -version switch, which makes dosbox report its version. + - Added a keymapper. + - Added basic IPX emulation. + - Added cdrom iso support and floppy images support. + - Added the possibity to boot another dos version. + - Added Serial passthrough support (win32 only). + - Added the possibility to pause dosbox. + - Changed OpenGL so that it is initialized only when used. + - Make dosbox run at higher priority when active and lower when inactive. + - Added direct draw output support (win32 only). + - Added current running program to title bar. + - Rewrote video emulation to support new scalers. + - Added new graphics scalers like advmame3x,tv2x. + - Added a support for a few anti-debugger tricks. + - Improved the handling of the tab-key. + - Improved support for the numeric keyboard. + - Fixed a few cpu opcodes. + - Added cpu core simple (for lowerend machines) + - Fixed some nasty bugs in the dynamic cpu core. + - Added a few (rarely used) fpu opcodes. + - Fixed various issues with GCC 3.4. + - Many internal timer improvements (PIT and PIC). + - Added some more PIC commands (c2woody). + - Added BCD counting to the timers. + - Fix some vesa functions. + - Add some basic support for 132x25 and 132x45 textmodes. + - Improved Tandy emulation a lot. + - Lowered cpu usage when dosbox is idle. + - Allow virtualisation of some basic IO-ports (c2woody). + +0.61 + - Added a beta dynamic cpu for x86 hosts (very unstable) + - Added opengl and hardware overlay display output + - Rewrote the vga screen updates to go in lines + - Added paging and v86 support to cpu emulation + - Added a config option to simulate a certain type of machine + - Added hercules graphics emulation + - Made CGA/TANDY modes more compatible + - Updated textmode drawing routines to support blinking colors + - Fixed VESA set page function that was documented wrong + - Fixed some wrongly emulated cpu opcodes. + - improved exception handling + - debugger: fixes; logging of gdt,lgt,idt, new commands(Fizzban) + - fixed some mscdex issues (drive letter header error, added get directory entry) + - added/fixed some bios funcs + - added some rarely used xms functions (thanks c2woody!) + - implemented GUS emulation + - Added 16-bit DMA support (for GUS and eventually SB16) + - Fixed many small bugs in filehandling routines + - Many small FPU fixes (c2woody/Fizzban) + - Some keyboard improvements (pharlab games) + - Some Timer and cmos/rtc fixes (Mirek/Srecko/Others) + - Lot's of mouse fixes (Help from various people) + - Enabled internal modem + - Made the DOS parsing routines a bit more flexible + - Added Subst (Srecko) + - Added cdrom ioctl support for linux (prompt) + - Many internal DOS fixes: memory/files/datastructures. + - Got some help from c2woody in allowing more than 1 irq being served + - Disabled DPMI (not needed anymore. DOSBox handles almost every extender) + - Search configfile in $HOME directory if none present in current directory + - Added another way to switch to protected mode. (Thanks Morten Eriksen!) + - Fixed some odd badly documented behaviour with PSP/DTA + - Added some warnings on opening of readonly files in writemode(DOS default). + - Many shell enhanchements + - Fixed a win32 specific bug dealing with filenames starting with a "." + - Fixed some bugs with the directory structure: not found/can't save errors + +0.60 + - rewrote memory system for future paging support + - fixed several EMS and XMS bugs and rewrite for new memory system + - added some support for tandy video modes + - added MAME Tandy 3 voice emulation + - added MAME CMS/GameBlaster emulation + - added serial port emulation with virtual tcp/ip modem (somewhat buggy) + - sound blaster emulation is now sb pro 2.0 compatible + - added basic support for 32-bit protected mode + - VGA now tries to emulate an S3 Trio 64 card with 2 MB + - VESA 2.0 support for some 256 color modes + - rewrote large piece of video bios code for better compatibility + - added support for the not inheritance flags. + - created functions for creating child psp. + - updated errorcodes of findfirst (thanks Mirek!) + - rewrote loggingsystem to generate less warnings + - added dos protected mode interface (dpmi) + - added cdrom label support + - improved cdrom audio playing + - fixed and improved directory cache + - debugger shows selector- and cpu mode info + - added SELINFO (selector information) command to debugger + - added reference counting for dos files + - added tab-completion + - added basic fpu support. + - fixed several bugs with case sensitive filesystems. + - added more shell commands and improved their behaviour. + - mouse improvements. + - real time clock improvements. + - DMA fixes. + - Improved .BAT file support. + +0.58 + - fixed date and time issues with fcbs + - added more commands to the internal Shell + - corrected config system when a old configfile was used + - fixed cga put and get pixel + - fixed some vga register getting reset to wrong values + - improved support for foreign keyboards + - improved joystick support + - made dosbox multithreaded again + - lot's of soundblaster fixes + - dma fixes + - cdrom support + - midi support + - added scale2x + - reenabled screenshot support + - joystick support fixes + - mouse improvements + - support for writing wavefiles + - added directory cache and longfilename support (longfilenames will be mangled) + - mouse fixes + + +0.57 + - added support for command /C + - fixed all fcb-write functions + - fixed fcb-parseline + - added debugger under linux/freebsd + - added debugger memory breakpoints and autolog function (heavy debug) + - added loadfix.com program that eats up memory (default 64kb) + Usage : loadfix [-option] [programname] [parameters]... + Example: loadfix mm2 (Allocates 64kb and starts executable mm2) + loadfix -32 mm2 (Allocates 32kb and starts executable mm2) + loadfix -128 (Allocates 128kb) + loadfix -f (frees all previous allocated memory) + - added echoing of characters for input function + - added support for backspace for input function + - added partial support for int10:01 set cursortype + - fixed most of the problems/bugs with character input. + - fixed allocationinfo call.(darksun series) + - improved dos support for non-existant functions + - Split screen support + - prefix 66 67 support + - rewrote timingscheme so 1000 hz timers don't cause problems anymore + - update adlib emulation + - fixed some isues with the mouse (double clicks and visible when it shouldn't be) + - improved mouse behaviour (mickey/pixel rate) and detection routines. + - basic ansi.sys support + - Disney sound system emulation + - rewrote upcase/lowcase functions so they work fine with gcc3.2 + - SHELL: added rename and delete + - added support for command /C. Fixed crashes in the shell + - fixed various bugs when exiting dosbox + - fixed a bug in XMS + - fixed a bug with the joystick when pressing a button + - create nicer configfiles. + - bios_disk function improved. + - trapflag support + - improved vertical retrace timing. + - PIT Timer improvements and many bug fixes + - Many many bug fixes to the DOS subsystem + - Support for memory allocation strategy + - rewrote cpu mainloop to act more like a real cpu + +0.56 + - added support for a configclass/configfile + - added support for writing out the configclass into a configfile + - removed the language file and made it internal + - added support for writing the language file (will override the internal one) + - improved mousesupport + - updated readme + - support for screenshots + - some cpu-bug fixes + - dma changes + - Real Sound support + - EMM fixes and new functions. + - VGA fixes + - new wildcompare + - support for size and disktype at mount. + - added new debugger functionalities: start/trace into INTs, write processor status log, + step over rep and loop instructions, breakpoint support without using INT 03 (heavy debugging switch) + - Added more cpu instructions and changed the string operations. + - Added classes for most of the internal dos structures. + - Rewrote most of the fcb calls to use normal dos calls. + +0.55 + - fixed the errors/warnings in prefix_66.h and prefix_66_of.h (decimal too large becomming unsigned). + - fixed compilation error on FreeBSD when #disable_joystick was defined + - int10_writechar has been updated to move the cursor position. + - changed the basedir routines to use the current working dir instead of argv[0]. This will fix and brake things :) + - illegal command, now displays the command + - wildcmp updated to be case insensitive + - added fcb:open,close,findfirst, findnext. + - fixed rename in drive_local + - added new features to the debugger: breakpoint support / data view / command line + - partial support of list of lists (dos info block) + - full emm 3.2 support + - partial emm 4.0 support + - fixes to graphics core fonts (text in sierra games is now correct) + - improved support for user mousehandlers + - fixed EGA graphics + - fixed VGA graphics + - fixed write with size 0 + - changed memory management. + - fixed and cleaned up the cpu flags. + - changed interrupt handler. + - speeded up the graphics. + - speeded up the cpu-core + - changed dma + - improved dma streams from emm memory + - added some cga videomodes + - added more funtions to the keyboard handler + +0.50: + -added F3 to repeat the last typed command. + -made it possible to change the shellmessages(dosshell). so + you can costumize it.(dosbox.lang) + -changed cpu core. + -Fixed a lot of errors with the keyboard: shift-f1 and + alt-f1 now works. + -Fixed some division errors. + -made a plugin system. + -added a lot of real 386 mode instructions. + -made it possible to resize the screen. + -Mayor source cleanup/reorganisation. + -Complete rewrite of the graphics routines. Should make it + possible to implement more fancy things like 2xsai,interpolation. + -changed the sound playback. + -Changed the vga drawing to only draw on memory changes, instead + of drawing an entire frame. + -fixes to the soundblaster/dma code should be able to play 4-bit + adpcm compressed sounds. + -added the correct time to dir. + -bugfixes to batch-file handling. + -Lot's of small bugfixes.(Dune1&2,wolf3d, many more). + -Released the source. diff --git a/README b/README index 75fd76f..65b2312 100644 --- a/README +++ b/README @@ -1,1346 +1,1268 @@ -¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ - - - DOSBox Wii - - Version 1.1 - http://code.google.com/p/dosbox-wii - (Under GPL License) - -¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤°`°¤ø,¸,ø¤°`°¤ø,¸¸,ø¤ - -A port of DOSBox to the Wii using SDL Wii. - --=[ Features ]=- - -* USB Keyboard and mouse support -* Wiimote pointer support -* SD/USB mounting -* Most DOS games are playable -* me menu, with onscreen keyboard - --=[ Update History ]=- - -[1.1 - October 27, 2009] - -* Fixed "black screen" issue with numerous games -* Minor optimizations and bug fixes -* Updated to latest DOSBox SVN - -[1.0 - October 9, 2009] - -* Home menu and on-screen keyboard (a proof of concept showing SDL + libwiigui) -* Small speed increases via SDL Wii improvements -* Compiled with devkitPPC r18 and libogc 1.8.0 -* Updated to latest DOSBox SVN - -[0.73.02 - July 1, 2009] - -* Upgraded DOSBox engine to latest SVN -* Fixed lockup when only using the Wiimote (no attachments connected) -* Compiled with latest libogc and SDL Wii - -[0.73.01 - June 3, 2009] - -* Upgraded DOSBox engine to 0.73 -* Sound issues fixed -* Compiled with latest libogc and SDL Wii - -[0.72.01 - May 14, 2009] - -* Initial release - --=[ Instructions ]=- - -You need a Wii Remote and a USB keyboard. The C: drive will automatically be -mounted to sd:/DOSBox/ if loaded from apps/dosbox-wii/. Otherwise, the -directory the dol is loaded from will be mounted as C, and sd:/DOSBox as D -(if present). The Z: driver is a virtual drive that is part of DOSBox. - -Other drives can be mounted using the MOUNT command. Prefix sd: for an SD card, -and usb: for a USB drive. The Wii's DVD drive and network folders can't be -mounted at this time. - -The configuration file is loaded from the directory the dol is located in -(if present) and sd:/DOSBox/dosbox.conf otherwise. This file will be created -automatically after you start DOSBox. Please edit it with a text editor -to choose settings appropriate for each game. - -Press the Home button, type "exit", press Ctrl+F9, or press Reset (on the -console) to exit. - --=[ Compatibility ]=- - -Most games work properly now; however, many games will require some sort -of adjustment to the dosbox.conf file. It is recommended to try the game -you want to play on the PC version of DOSBox first to discover the optimum -settings. - -------------------------------------------------------------------------------- - -DOSBox v0.73 - - -===== -NOTE: -===== - -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. -DOSBox can be configured to run a wide range of DOS games, from -CGA/Tandy/PCjr classics up to games from the Quake era. - - - -====== -INDEX: -====== -1. Quickstart -2. FAQ -3. Usage -4. Internal Programs -5. Special Keys -6. Mapper -7. Keyboard Layout -8. Serial Multiplayer feature -9. How to run resource-demanding games -10. Troubleshooting -11. The config file -12. The language file -13. Building your own version of DOSBox -14. Special thanks -15. Contact - - - -============== -1. Quickstart: -============== - -Type INTRO in DOSBox for a quick tour. -It is essential that you get familiar with the idea of mounting, -DOSBox does not automatically make any drive (or a part of it) -accessible to the emulation. -See the FAQ entry "I've got a Z instead of a C at the prompt" as -well as the description of the MOUNT command (section 4). - - - -======= -2. FAQ: -======= - -Some Frequently Asked Questions: - -Q: I've got a Z instead of a C at the prompt. -Q: Do I always have to type these commands? Automation? -Q: How do I change to fullscreen? -Q: My CD-ROM doesn't work. -Q: The game/application can't find its CD-ROM. -Q: The mouse doesn't work. -Q: There is no sound. -Q: The sound stutters or sounds stretched/weird. -Q: I can't type \ or : in DOSBox. -Q: The keyboard lags. -Q: The cursor always moves into one direction! -Q: The game/application runs much too slow! -Q: The game/application does not run at all/crashes! -Q: Can DOSBox harm my computer? -Q: I would like to change the memory size/cpu speed/ems/soundblaster IRQ. -Q: What sound hardware does DOSBox presently emulate? -Q: DOSBox crashes on startup and I'm running arts. -Q: My Build game(Duke3D/Blood/Shadow Warrior) has problems. -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:\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. - To change to the drive mounted like above, type "C:". If everything went - fine, DOSBox will display the prompt "C:\>". - - -Q: Do I always have to type these commands? Automation? -A: In the DOSBox configuration file is an [autoexec] section. The commands - present there are run when DOSBox starts, so you can use this section - for the mounting. - - -Q: How do I change to fullscreen? -A: Press alt-enter. Alternatively: Edit the configuration file of DOSBox and - change the option fullscreen=false to fullscreen=true. If fullscreen looks - wrong in your opinion: Play with the option fullresolution in the - configuration file of DOSBox. To get back from fullscreen mode: - Press alt-enter again. - - -Q: My CD-ROM doesn't work. -A: To mount your CD-ROM in DOSBox you have to specify some additional options - when mounting the CD-ROM. - To enable CD-ROM support (includes MSCDEX): - - mount d f:\ -t cdrom (windows) - - mount d /media/cdrom -t cdrom (linux) - - In some cases you might want to use a different CD-ROM interface, - for example if CD audio does not work: - To enable SDL-support (does not include low-level CD access!): - - mount d f:\ -t cdrom -usecd 0 -noioctl - To enable ioctl access using digital audio extraction for CD audio - (windows-only, useful for Vista): - - mount d f:\ -t cdrom -ioctl_dx - To enable ioctl access using MCI for CD audio (windows-only): - - mount d f:\ -t cdrom -ioctl_mci - To force ioctl-only access (windows-only): - - mount d f:\ -t cdrom -ioctl_dio - To enable low-level aspi-support (win98 with aspi-layer installed): - - mount d f:\ -t cdrom -aspi - - In the commands: - d driveletter you will get in DOSBox - - f:\ location of CD-ROM on your PC. - - 0 The number of the CD-ROM drive, reported by "mount -cd" - (note that this value is only needed when using SDL - for CD audio, otherwise it is ignored) - See also the next question: The game/application can't find its CD-ROM. - - -Q: The game/application can't find its CD-ROM. -A: Be sure to mount the CD-ROM with -t cdrom switch, this will enable the - MSCDEX interface required by DOS games to interface with CD-ROMs. - Also try adding the correct label (-label LABEL) to the mount command, - where LABEL is the CD-label (volume ID) of the CD-ROM. - Under Windows you can specify -ioctl, -aspi or -noioctl. Look at the - description of the mount command in Section 4 for their meaning and the - additional audio-CD related options -ioctl_dx, ioctl_mci, ioctl_dio. - - Try creating a CD-ROM image (preferably CUE/BIN pair) and use the - DOSBox-internal IMGMOUNT tool to mount the image (the CUE sheet). - This enables very good low-level CD-ROM support on any operating system. - - -Q: The mouse doesn't work. -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: There is no sound. -A: Be sure that the sound is correctly configured in the game. This might be - done during the installation or with a setup/setsound utility that - accompanies the game. First see if an autodetection option is provided. If - there is none try selecting soundblaster or soundblaster16 with the default - settings being "address=220 irq=7 dma=1". You might also want to select - midi at address 330 as music device. - The parameters of the emulated soundcards can be changed in the DOSBox - configuration file. - If you still don't get any sound set the core to normal and use some lower - fixed cycles value (like cycles=2000). Also assure that your host operating - sound does provide sound. - In certain cases it might be useful to use a different emulated sound device - like a soundblaster pro (sbtype=sbpro1 in the DOSBox configuration file) or - the gravis ultrasound (gus=true). - - -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 lower the cycles, skip frames, reduce the sampling rate of - the respective sound device (see the DOSBox configuration file) or - the mixer device. You can also increase the prebuffer in the configfile. - If you are using cycles=max or =auto, then make sure that there is no - background processes interfering! (especially if they access the harddisk) - - -Q: I can't type \ or : in DOSBox. -A: This can happen in various cases, like your host keyboard layout does not - have a matching DOS layout representation (or it was not correctly detected), - or the key mapping is wrong. - Some possible fixes: - 1. Use / instead, or ALT-58 for : and ALT-92 for \. - 2. Change the DOS keyboard layout (see Section 7: Keyboard Layout). - 3. Add the commands you want to execute to the [autoexec]-section - of the DOSBox configuration file. - 4. Open the DOSBox configuration file and change the usescancodes entry. - 5. Switch the keyboard layout of your operating system. - - Note that if the host layout can not be identified, or keyboardlayout is set - to none in the DOSBox configuration file, the standard US layout is used. - In this configuration try the keys around "enter" for the key \ (backslash), - and for the key : (colon) use shift and the keys between "enter" and "l". - - -Q: The keyboard lags. -A: Lower the priority setting in the DOSBox configuration file, for example - set "priority=normal,normal". You might also want to try lowering the cycles - (use a fixed cycle count to start with, like cycles=10000). - - -Q: The cursor always moves into one direction! -A: See if it still happens if you disable the joystick emulation, - set joysticktype=none in the [joystick] section of your DOSBox - configuration file. Maybe also try unplugging any joystick/gamepad. - If you want to use the joystick in the game, try setting timed=false - and be sure to calibrate the joystick (both in your OS as well as - in the game or the game's setup program). - - -Q: The game/application runs much too slow! -A: Look at the section "How to run resource-demanding games" for more - information. - - -Q: The game/application does not run at all/crashes! -A: Look at Section 10: Troubleshooting - - -Q: Can DOSBox harm my computer? -A: DOSBox can not harm your computer more than any other resource demanding - program. Increasing the cycles does not overclock your real CPU. - Setting the cycles too high has a negative performance effect on the - software running inside DOSBox. - - -Q: I would like to change the memory size/cpu speed/ems/soundblaster IRQ. -A: This is possible! Just create a config file: config -writeconf configfile. - Start your favourite editor and look through the settings. To start DOSBox - with your new settings: dosbox -conf configfile - See the description of the config command in Section 4 for more details. - - -Q: What sound hardware does DOSBox presently emulate? -A: DOSBox emulates several legacy sound devices: - - Internal PC speaker - This emulation includes both the tone generator and several forms of - digital sound output through the internal speaker. - - Creative CMS/Gameblaster - The is the first card released by Creative Labs(R). The default - configuration places it on port 0x220. It should be noted that enabling - 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. The noise channel is not very well documented and as - such is only a best guess as to the sound's accuracy. - - Tandy DAC - Emulation of the Tandy DAC utilizes the soundblaster emulation, thus - be sure the soundblaster is not disabled in the DOSBox configuration - file. The Tandy DAC is only emulated at the BIOS level. - - Adlib - This emulation is almost perfect and includes the Adlib's ability to - almost play digitized sound. - - 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 - 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. -A: This isn't really a DOSBox problem, but the solution is to set the - environment variable SDL_AUDIODRIVER to alsa or oss. - - -Q: My Build game(Duke3D/Blood/Shadow Warrior) has problems. -A: First of all, try to find a port of the game. Those will offer a - better experience. To fix the graphics problem that occurs in - DOSBox on higher resolutions. Open the configuration file of - DOSBox and search for machine=svga_s3. Change svga_s3 to vesa_nolfb - - -Q: Great README, but I still don't get it. -A: A look at "The Newbie's pictorial guide to DOSBox" located at - http://vogons.zetafleet.com/viewforum.php?f=39 might help you. - Also try the wiki of DOSBox: - http://www.dosbox.com/wiki/ - - -For more questions read the remainder of this README and/or check -the site/forum: -http://www.dosbox.com - - - -========= -3. Usage: -========= - -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. -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] [-noautoexec] [-securemode] - [-scaler scaler | -forcescaler scaler] - [-version] - -dosbox -version -dosbox -editconf program -dosbox -opencaptures program -dosbox -printconf -dosbox -eraseconf - - 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. - - -c command - Runs the specified command before running "name". Multiple commands - 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. - - -conf configfile - Start DOSBox with the options specified in "configfile". - Multiple -conf options may be present. - See Section 11 for more details. - - -lang languagefile - Start DOSBox using the language specified in "languagefile". - - -machine machinetype - Setup DOSBox to emulate a specific type of machine. Valid choices are: - hercules, cga, pcjr, tandy, svga_s3 (default) as well as the additional - svga chipsets listed in the help of the DOSBox configuration file. - svga_s3 enables vesa emulation as well. - For some special vga effects the machinetype vgaonly can be used, - note that this disables svga capabilites and might be (considerably) - slower due to the much higher emulation precision. - The machinetype affects both the videocard and the available soundcards. - - -noconsole (Windows Only) - Start DOSBox without showing the console window. Output will - be redirected to stdout.txt and stderr.txt - - -startmapper - Enter the keymapper directly on startup. Useful for people with - keyboard problems. - - -noautoexec - Skips the [autoexec] section of the loaded configuration file. - - -securemode - Same as -noautoexec, but adds config.com -securemode at the - bottom of AUTOEXEC.BAT (which in turn disables any changes to how - the drives are mounted inside DOSBox). - - -scaler scaler - Uses the scaler specified by "scaler". See the DOSBox configuration - file for the available scalers. - - -forcescaler scaler - Similar to the -scaler parameter, but tries to force usage of - the specified scaler even if it might not fit. - - -version - output version information and exit. Useful for frontends. - - -editconf program - calls program with as first parameter the configuration file. - You can specify this command more than once. In this case it will - move to second program if the first one fails to start. - - -opencaptures program - calls program with as first paramater the location of the captures - folder. - - -printconf - prints the location of the default configuration file. - - -eraseconf - removes the default configuration file. - -Note: If a name/command/configfile/languagefile contains a space, put - the whole name/command/configfile/languagefile between quotes - ("command or file name"). If you need to use quotes within quotes - (most likely with -c and mount): - Windows and OS/2 users can use single quotes inside the double quotes. - Other people should be able to use escaped double quotes inside the - double quotes. - Windows: -c "mount c 'c:\program files\'" - Linux: -c "mount c \"/tmp/name with space\"" - -For example (Windows): - -dosbox c:\atlantis\atlantis.exe -c "MOUNT D C:\SAVES" - 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. - - - -===================== -4. Internal Programs: -===================== - -DOSBox supports most of the DOS commands found in command.com. -To get a list of the internal commands type "HELP" at the prompt. - -In addition, the following commands are available: - -MOUNT "Emulated Drive letter" "Real Drive or Directory" - [-t type] [-aspi] [-ioctl] [-noioctl] [-usecd number] [-size drivesize] - [-label drivelabel] [-freesize size_in_mb] - [-freesize size_in_kb (floppies)] -MOUNT -cd -MOUNT -u "Emulated Drive letter" - - Program to mount local directories as drives inside DOSBox. - - "Emulated Drive letter" - The driveletter inside DOSBox (eg. C). - - "Real Drive letter (usually for CD-ROMs in Windows) or Directory" - The local directory you want accessible inside DOSBox. - - -t type - Type of the mounted directory. Supported are: dir (default), - floppy, cdrom. - - -size drivesize - Sets the size of the drive, where drivesize is of the form - "bps,spc,tcl,fcl": - bps: bytes per sector, by default 512 for regular drives and - 2048 for CD-ROM drives - spc: sectors per cluster, usually between 1 and 127 - tcl: total clusters, between 1 and 65534 - fcl: total free clusters, between 1 and tcl - - -freesize size_in_mb | size_in_kb - Sets the amount of free space available on a drive in megabytes - (regular drives) or kilobytes (floppy drives). - This is a simpler version of -size. - - -label drivelabel - Sets the name of the drive to "drivelabel". Needed on some - systems if the CD-ROM label isn't read correctly (useful when a - program can't find its CD-ROM). If you don't specify a label and no - lowlevel support is selected (that is omitting the -usecd # and/or - -aspi parameters, or specifying -noioctl): - For Windows: 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 - is mounted. It will not be updated !! - - -aspi - Forces use of the aspi layer. Only valid if mounting a CD-ROM under - Windows systems with an ASPI-Layer. - - -ioctl (automatic selection of the CD audio interface) - -ioctl_dx (digital audio extraction used for CD audio) - -ioctl_dio (ioctl calls used for CD audio) - -ioctl_mci (MCI used for CD audio) - Forces use of ioctl commands. Only valid if mounting a CD-ROM under - a Windows OS which support them (Win2000/XP/NT). - The various choices only differ in the way CD audio is handled, - preferrably -ioctl_dio is used (lowest workload), but this might not - work on all systems so -ioctl_dx (or -ioctl_mci) can be used. - - -noioctl - Forces use of the SDL CD-ROM layer. Valid on all systems. - - -usecd number - Valid on all systems, under windows the -noioctl switch has to be - present to make use of the -usecd switch. - Enables to select the drive that should be used by SDL. Use this if - the wrong or no CD-ROM drive is mounted while using the SDL CD-ROM - interface. "number" can be found by "MOUNT -cd". - - -cd - Displays all CD-ROM drives detected by SDL, and their numbers. - See the information at the -usecd entry above. - - -u - Removes the mount. Doesn't work for Z:\. - - Note: It's possible to mount a local directory as CD-ROM drive. - Hardware support is then missing. - - Basically MOUNT allows you to connect real hardware to DOSBox's emulated 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 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 the game into - believing it is on the C drive, while you can still place it where you - like. For example, if the game is in D:\OLDGAMES\TOUCHE, the command - MOUNT C D:\OLDGAMES will allow you to run Touche from the D drive. - - Mounting your entire C drive with MOUNT C C:\ is NOT recommended! The same - is true for mounting the root of any other drive, except for CD-ROMs (due to - their read-only nature). Otherwise if you or DOSBox make a mistake you may - lose all your files. - It is recommended to put all your applications/games into a subdirectory - and mount that. - - General MOUNT Examples: - 1. To mount c:\DirX as a floppy : - mount a c:\DirX -t floppy - 2. To mount system CD-ROM drive E as CD-ROM drive D in DOSBox: - mount d e:\ -t cdrom - 3. To mount system CD-ROM drive at mountpoint /media/cdrom as CD-ROM drive D - in DOSBox: - mount d /media/cdrom -t cdrom -usecd 0 - 4. To mount a drive with ~870 mb free diskspace (simple version): - mount c d:\ -freesize 870 - 5. To mount a drive with ~870 mb free diskspace (experts only, full control): - mount c d:\ -size 512,127,16513,13500 - 6. To mount /home/user/dirY as drive C in DOSBox: - mount c /home/user/dirY - 7. To mount the directory where DOSBox was started as D in DOSBox: - mount d . - (note the . which represents the directory where DOSBox was started) - - -MEM - Program to display the amount of free memory. - - -VER -VER set major_version [minor_version] - Display the current DOSBox version and reported DOS version - (parameterless usage). - Change the reported DOS version with the "set" parameter, - for example: "VER set 6 22" to have DOSBox report DOS 6.22 - as version number. - - -CONFIG -writeconf localfile -CONFIG -writelang localfile -CONFIG -securemode -CONFIG -set "section property=value" -CONFIG -get "section property" - - 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 11 (The Config File). - - -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 11 (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 output of the internal commands - and the internal DOS. - - -securemode - Switches DOSBox to a more secure mode. In this mode the internal - commands MOUNT, IMGMOUNT and BOOT won't work. It's not possible either - to create a new configfile or languagefile in this mode. - (Warning: you can only undo this mode by restarting DOSBox.) - - -set "section property=value" - CONFIG will attempt to set the property to new value. Currently - 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" - - -LOADFIX [-size] [program] [program-parameters] -LOADFIX -f - Program to reduce the amount of available conventional memory. - Useful for old programs which don't expect much memory to be free. - - -size - number of kilobytes to "eat up", default = 64kb - - -f - frees all previously allocated memory - - Examples: - 1. To start mm2.exe and allocate 64kb memory - (mm2 will have 64 kb less available) : - loadfix mm2 - 2. To start mm2.exe and allocate 32kb memory : - loadfix -32 mm2 - 3. To free previous allocated memory : - loadfix -f - - -RESCAN - Make DOSBox reread the directory structure. Useful if you changed something - on a mounted drive outside of DOSBox. (CTRL - F4 does this as well!) - - -MIXER - Makes DOSBox display its current volume settings. - Here's how you can change them: - - mixer channel left:right [/NOSHOW] [/LISTMIDI] - - channel - Can be one of the following: MASTER, DISNEY, SPKR, GUS, SB, FM [, CDAUDIO]. - CDAUDIO is only available if a CD-ROM interface with volume control is - enabled (CD image, ioctl_dx). - - left:right - The volume levels in percentages. If you put a D in front it will be - in decibel (Example: mixer gus d-10). - - /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 - 'midiconfig=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. - - IMGMOUNT DRIVE [imagefile] -t [image_type] -fs [image_format] - -size [sectorsbytesize, sectorsperhead, heads, cylinders] - IMGMOUNT DRIVE [imagefile1, .. ,imagefileN] -t iso -fs iso - - imagefile - Location of the image file to mount in DOSBox. The location can - be on a mounted drive inside DOSBox, or on your real disk. It is - possible to mount CD-ROM images (ISOs or CUE/BIN) as well, if you - need CD swapping capabilities specify all images in succession - (see the next entry). - CUE/BIN pairs are the preferred CD-ROM image type as they can - store audio tracks compared to ISOs (which are data-only). For - the CUE/BIN mounting always specify the CUE sheet. - - imagefile1, .. ,imagefileN - Location of the image files to mount in DOSBox. Specifying a number - of image files is only allowed for CD-ROM images. The CD's can be - swapped with CTRL-F4 at any time. This is required for games which - use multiple CD-ROMs and require the CD to be switched during the - gameplay at some point. - - -t - The following are valid image types: - floppy: Specifies a floppy image. DOSBox will automatically identify - the disk geometry (360K, 1.2MB, 720K, 1.44MB, etc). - iso: Specifies a CD-ROM iso image. The geometry is automatic and - set for this size. This can be an iso or a cue/bin pair. - hdd: Specifies a harddrive image. The proper CHS geometry - must be set for this to work. - - -fs - The following are valid file system formats: - iso: Specifies the ISO 9660 CD-ROM format. - 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 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, - you would type (without the quotes): - "imgmount 3 d:\test.img -size 512,63,16,142 -fs none" - Compare this with a mount to be able to access the drive - within DOSBox, which would read as: - "imgmount e: d:\test.img -size 512,63,16,142" - - -size - The Cylinders, Heads and Sectors of the drive. - Required to mount hard drive images. - - An example how to mount CD-ROM images: - 1a. mount c /tmp - 1b. imgmount d c:\myiso.iso -t iso - or (which also works): - 2. imgmount d /tmp/myiso.iso -t iso - - -BOOT - Boot will start floppy images or hard disk images independent of the - operating system emulation offered by DOSBox. This will allow you to - play booter floppies or boot other operating systems inside DOSBox. - If the target emulated system is PCjr (machine=pcjr) the boot command - can be used to load PCjr cartridges (.jrc). - - BOOT [diskimg1.img diskimg2.img .. diskimgN.img] [-l driveletter] - BOOT [cart.jrc] (PCjr only) - - 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, 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 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" - - cart.jrc (PCjr only) - When emulation of a PCjr is enabled, cartridges can be loaded with - the BOOT command. Support is still limited. - - -IPX - - You need to enable IPX networking in the configuration file of DOSBox. - - 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 the commands - and relevant documentation. - - With regard to actually setting up a network, one system needs to be - 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. - - To play games that need Netbios a file named NETBIOS.EXE from Novell is - needed. Establish the IPX connection as explained above, then run - "netbios.exe". - - The following is an IPXNET command reference: - - IPXNET CONNECT - - 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. 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 tunnelling server. - - The syntax for IPXNET DISCONNECT is: - IPXNET DISCONNECT - - IPXNET STARTSERVER - - IPXNET STARTSERVER starts an IPX tunnelling 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 tunnelling server. - - The syntax for IPXNET STARTSERVER is: - IPXNET STARTSERVER - - If the server is behind a router, UDP port needs to be forwarded - to that computer. - - On Linux/Unix-based systems port numbers smaller than 1023 can only be - used with root privileges. Use ports greater than 1023 on those systems. - - IPXNET STOPSERVER - - 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 that are still using the IPX tunnelling server. - - The syntax for IPXNET STOPSERVER is: - IPXNET STOPSERVER - - IPXNET PING - - 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 STATUS - - 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: - IPXNET STATUS - - -KEYB [languagecode [codepage [codepagefile]]] - Change the keyboard layout. For detailed information about keyboard - layouts please see Section 7. - - [languagecode] is a string consisting of two (in special cases more) - characters, examples are GK (Greece) or IT (Italy). It specifies - the keyboard layout to be used. - - [codepage] is the number of the codepage to be used. The keyboard layout - has to provide support for the specified codepage, otherwise the layout - loading will fail. - If no codepage is specified, an appropriate codepage for the requested - layout is chosen automatically. - - [codepagefile] can be used to load codepages that are yet not compiled - into DOSBox. This is only needed when DOSBox does not find the codepage. - - - Examples: - 1. To load the german keyboard layout (automatically uses codepage 858): - keyb gr - 2. To load the russian keyboard layout with codepage 866: - keyb ru 866 - In order to type russian characters press ALT+RIGHT-SHIFT. - 3. To load the french keyboard layout with codepage 850 (where the - codepage is defined in EGACPI.DAT): - keyb fr 850 EGACPI.DAT - 4. To load codepage 858 (without a keyboard layout): - keyb none 858 - This can be used to change the codepage for the FreeDOS keyb2 utility. - 5. To display the current codepage and, if loaded, the keyboard layout: - keyb - - - -For more information use the /? command line switch with the programs. - - - -================ -5. Special Keys: -================ - -ALT-ENTER Switch to full screen and back. -ALT-PAUSE Pause emulation (hit ALT-PAUSE again to continue). -CTRL-F1 Start the keymapper. -CTRL-F4 Change between mounted disk-images. Update directory cache for all drives! -CTRL-ALT-F5 Start/Stop creating a movie of the screen. (avi video capturing) -CTRL-F5 Save a screenshot. (PNG format) -CTRL-F6 Start/Stop recording sound output to a wave file. -CTRL-ALT-F7 Start/Stop recording of OPL commands. (DRO format) -CTRL-ALT-F8 Start/Stop the recording of raw MIDI commands. -CTRL-F7 Decrease frameskip. -CTRL-F8 Increase frameskip. -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). - -(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.) - - -These are the default keybindings. They can be changed in the keymapper -(see Section 6: Mapper). - -Saved/recorded files can be found in current_directory/capture -(this can be changed in the DOSBox configuration file). -The directory has to exist prior to starting DOSBox, otherwise nothing -gets saved/recorded ! - - - -========== -6. Mapper: -========== - -When you start the DOSBox mapper (either with CTRL-F1 or -startmapper as -a command line argument to the DOSBox executable) you are presented with -a virtual keyboard and a virtual joystick. - -These virtual devices correspond to the keys and events DOSBox will -report to the DOS applications. If you click on a button with your mouse, -you can see in the lower left corner with which event it is associated -(EVENT) and to what events it is currently bound. - -Event: EVENT -BIND: BIND - Add Del -mod1 hold Next -mod2 -mod3 - - -EVENT - The key or joystick axis/button/hat DOSBox will report to DOS applications. -BIND - The key on your real keyboard or the axis/button/hat on your real - joystick(s) (as reported by SDL) which is connected to the EVENT. -mod1,2,3 - Modfiers. These are keys you need to have to be pressed while pressing - 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. Basically add a key from your keyboard or an - event from the joystick (button press, axis/hat movement) which will - produce the EVENT in DOSBox. -Del - Delete the BIND to this EVENT. If an EVENT has no BINDS, then it is not - possible to trigger this event in DOSBox (that is there's no way to type - the key or use the respective action of the joystick). -Next - Go through the list of bindings which map to this EVENT. - - -Example: -Q1. You want to have the X on your keyboard to type a Z in DOSBox. - 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 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" 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 - 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" until you find the - mapped key X. Click "Del". - - -Examples about remapping the joystick: - You have a joystick attached, it is working fine under DOSBox and you - want to play some keyboard-only game with the joystick (it is assumed - that the game is controlled by the arrows on the keyboard): - 1. Start the mapper, then click on one of the arrows in the middle - of the left part of the screen (right above the Mod1/Mod2 buttons). - EVENT should be key_left. Now click on Add and move your joystick - in the respective direction, this should add an event to the BIND. - 2. Repeat the above for the missing three directions, additionally - the buttons of the joystick can be remapped as well (fire/jump). - 3. Click on Save, then on Exit and test it with some game. - - You want to swap the y-axis of the joystick because some flightsim uses - the up/down joystick movement in a way you don't like, and it is not - configurable in the game itself: - 1. Start the mapper and click on Y- in the upper joystick field (this - is for the first joystick if you have two joysticks attached) or the - lower joystick field (second joystick or, if you have only one - joystick attached, the second axes cross). - EVENT should be jaxis_0_1- (or jaxis_1_1-). - 2. Click on Del to remove the current binding, then click Add and move - your joystick downwards. A new bind should be created. - 3. Repeat this for Y+, save the layout and finally test it with some game. - - - -If you change the default mapping, you can save your changes by clicking on -"Save". DOSBox will save the mapping to a location specified in the configuration -file (the mapperfile= entry). At startup, DOSBox will load your mapperfile, -if it is present in the DOSBox configuration file. - - - -=================== -7. Keyboard Layout: -=================== - -To switch to a different keyboard layout, either the entry "keyboardlayout" -in the [dos] section of the DOSBox configuration file can be used, or the -internal DOSBox program keyb.com. Both accept DOS conforming language codes -(see below), but only by using keyb.com a custom codepage can be specified. - -The default keyboardlayout=auto currently works under windows only, the -layout is chosen according to the OS layout. - -Layout switching - DOSBox supports a number of keyboard layouts and codepages by default, - in this case just the layout identifier needs to be specified (like - keyboardlayout=sv in the DOSBox configuration file, or using "keyb sv" - at the DOSBox command prompt). - - Some keyboard layouts (for example layout GK codepage 869 and layout RU - codepage 808) have support for dual layouts that can be activated by - pressing LEFT-ALT+RIGHT-SHIFT and deactivated by LEFT-ALT+LEFT-SHIFT. - -Supported external files - The FreeDOS .kl files are supported (FreeDOS keyb2 keyboard layoutfiles) as - well as the FreeDOS keyboard.sys/keybrd2.sys/keybrd3.sys libraries which - consist of all available .kl files. - See http://projects.freedos.net/keyb/ for precompiled keyboard layouts if - the DOSBox-integrated layouts don't work for some reason, or if updated or - new layouts become available. - - Both .CPI (MS-DOS and compatible codepage files) and .CPX (FreeDOS - UPX-compressed codepage files) can be used. Some codepages are compiled - into DOSBox, so it is mostly not needed to care about external codepage - files. If you need a different (or custom) codepage file, copy it into - the directory of the DOSBox configuration file so it is accessible for - DOSBox. - - Additional layouts can be added by copying the corresponding .kl file into - the directory of the DOSBox configuration file and using the first part of - the filename as language code. - Example: For the file UZ.KL (keyboard layout for Uzbekistan) specify - "keyboardlayout=uz" in the DOSBox configuration file. - The integration of keyboard layout packages (like keybrd2.sys) works similar. - - -Note that the keyboard layout allows foreign characters to be entered, but -there is NO support for them in filenames. Try to avoid them both inside -DOSBox as well as in files on your host operating system that are accessible -by DOSBox. - - - -============================== -8. Serial Multiplayer feature: -============================== - -DOSBox can emulate a serial nullmodem cable over network and internet. -It can be configured through the [serialports] section in the DOSBox -configuration file. - -To create a nullmodem connection, one side needs to act as the server and -one as the client. - -The server needs to be set up in the DOSBox configuration file like this: - serial1=nullmodem - -The client: - serial1=nullmodem server: - -Now start your game and choose nullmodem / serial cable / already connected -as multiplayer method on COM1. Set the same baudrate on both computers. - -Furthermore, additional parameters can be specified to control the behavior -of the nullmodem connection. These are all parameters: - - * port: - TCP port number. Default: 23 - * rxdelay: - how long (milliseconds) to delay received data if the - interface is not ready. Increase this value if you encounter - overrun errors in the DOSBox Status Window. Default: 100 - * txdelay: - how long to gather data before sending a packet. Default: 12 - (reduces Network overhead) - * server: - This nullmodem will be a client connecting to the specified - server. (No server argument: be a server.) - * transparent:1 - Only send the serial data, no RTS/DTR handshake. Use this - when connecting to anything other than a nullmodem. - * telnet:1 - Interpret Telnet data from the remote site. Automatically - sets transparent. - * usedtr:1 - The connection will not be established until DTR is switched - on by the DOS program. Useful for modem terminals. - Automatically sets transparent. - * inhsocket:1 - Use a socket passed to DOSBox by command line. Automatically - sets transparent. (Socket Inheritance: It is used for - playing old DOS door games on new BBS software.) - -Example: Be a server listening on TCP port 5000. - serial1=nullmodem server: port:5000 rxdelay:1000 - - - -======================================= -9. How to run resource-demanding games: -======================================= - -DOSBox emulates the CPU, the sound and graphic cards, and other peripherals -of a PC, all at the same time. The speed of an emulated DOS application -depends on how many instructions can be emulated, which is adjustable -(number of cycles). - -CPU Cycles - By default (cycles=auto) DOSBox tries to detect whether a game needs to - be run with as many instructions emulated per time interval as possible. - You can force this behaviour by setting cycles=max in the DOSBox - configuration file. The DOSBox window will display a line "Cpu Cyles: max" - at the top then. In this mode you can reduce the amount of cycles on a - percentage-basis (hit CTRL-F11) or raise it again (CTRL-F12). - - Sometimes manually setting the number of cycles achieves better results, - in the DOSBox configuration file specify for example cycles=30000. When - running some DOS application you can raise the cycles with CTRL-F12 even - more, but you will be limited by the power of your actual CPU. You can see - how much free time your real 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 used there is no further way to speed up DOSBox - unless you reduce the load generated by the non-CPU parts of DOSBox. - -CPU Cores - On x86 architectures you can try to force the usage of a dynamically - recompiling core (set core=dynamic in the DOSBox configuration file). - This usually gives better results if the auto detection (core=auto) fails. - It is best accompanied by cycles=max. Note that there might be games - that work worse with the dynamic core, or do not work at all! - -Graphics emulation - VGA emulation is a very demanding part of DOSBox in terms of actual CPU - usage. Increase the number of frames skipped (in increments of one) by - pressing CTRL-F8. Your CPU usage should decrease when using a fixed - cycle setting. - 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. - -Sound emulation - You can also try to disable the sound through the setup utility of the game - to reduce load on your CPU further. Setting nosound=true does NOT disable - the emulation of sound devices, just the output of sound will be disabled. - -Also try to close every program but DOSBox to reserve as much resources -as possible for DOSBox. - - -Advanced cycles configuration: -The cycles=auto and cycles=max settings can be parameterized to have -different startup defaults. The syntax is - cycles=auto ["realmode default"] ["protected mode default"%] - [limit "cycle limit"] - cycles=max ["protected mode default"%] [limit "cycle limit"] -Example: - cycles=auto 1000 80% limit 20000 - will use cycles=1000 for real mode games, 80% CPU throttling for - protected mode games along with a hard cycle limit of 20000 - - - -==================== -10. Troubleshooting: -==================== - -DOSBox crashes right after starting it: - - use different values for the output= entry in your DOSBox - configuration file - - try to update your graphics card driver and DirectX - -Running a certain game closes DOSBox, crashes with some message or hangs: - - see if it works with a default DOSBox installation - (unmodified configuration file) - - try it with sound disabled (use the sound configuration - program that comes with the game, additionally you can - set sbtype=none and gus=false in the DOSBox configuration file) - - change some entries of the DOSBox configuration file, especially try: - core=normal - fixed cycles (for example cycles=10000) - ems=false - xms=false - or combinations of the above settings, - similar the machine settings that control the emulated chipset and - functionality: - machine=vesa_nolfb - or - machine=vgaonly - - use loadfix before starting the game - -The game exits to the DOSBox prompt with some error message: - - read the error message closely and try to locate the error - - try the hints at the above sections - - mount differently as some games are picky about the locations, - for example if you used "mount d d:\oldgames\game" try - "mount c d:\oldgames\game" and "mount c d:\oldgames" - - if the game requires a CD-ROM be sure you used "-t cdrom" when - mounting and try different additional parameters (the ioctl, - usecd and label switches, see the appropriate section) - - check the file permissions of the game files (remove read-only - attributes, add write permissions etc.) - - try reinstalling the game within DOSBox - - - -==================== -11. The Config File: -==================== - -A config file can be generated by CONFIG.COM, which can be found on the -internal DOSBox Z: drive when you start up DOSBox. Look in the internal -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 you can set. -# and % indicate comment-lines. -The DOSBox configuration file contains the current settings. You can -alter them and start DOSBox with the -conf switch to load the file and -use these settings. - -DOSBox will parse configuration files that are specified with -conf. If -none were specified it will try to load "dosbox.conf" from the local -directory. If there is none, DOSBox will load the user configuration -file. This file will be created if it doesn't exist. The file can be -found in ~/.dosbox (Linux) or "~/Library/Preferences" (MAC OS X). -Windows users should use the shortcuts in the startmenu to find it. - - - - -====================== -12. The Language File: -====================== - -A language file can be generated by CONFIG.COM (CONFIG -writelang langfile). -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. - - - -======================================== -13. Building your own version of DOSBox: -======================================== - -Download the source. -Check the INSTALL in the source distribution. - - - -=================== -14. Special thanks: -=================== - -See the THANKS file. - - -============ -15. Contact: -============ - -See the site: -http://www.dosbox.com -for an email address (The Crew-page). +DOSBox v0.73 + + +===== +NOTE: +===== + +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. +DOSBox can be configured to run a wide range of DOS games, from +CGA/Tandy/PCjr classics up to games from the Quake era. + + + +====== +INDEX: +====== +1. Quickstart +2. FAQ +3. Usage +4. Internal Programs +5. Special Keys +6. Mapper +7. Keyboard Layout +8. Serial Multiplayer feature +9. How to run resource-demanding games +10. Troubleshooting +11. The config file +12. The language file +13. Building your own version of DOSBox +14. Special thanks +15. Contact + + + +============== +1. Quickstart: +============== + +Type INTRO in DOSBox for a quick tour. +It is essential that you get familiar with the idea of mounting, +DOSBox does not automatically make any drive (or a part of it) +accessible to the emulation. +See the FAQ entry "I've got a Z instead of a C at the prompt" as +well as the description of the MOUNT command (section 4). + + + +======= +2. FAQ: +======= + +Some Frequently Asked Questions: + +Q: I've got a Z instead of a C at the prompt. +Q: Do I always have to type these commands? Automation? +Q: How do I change to fullscreen? +Q: My CD-ROM doesn't work. +Q: The game/application can't find its CD-ROM. +Q: The mouse doesn't work. +Q: There is no sound. +Q: The sound stutters or sounds stretched/weird. +Q: I can't type \ or : in DOSBox. +Q: The keyboard lags. +Q: The cursor always moves into one direction! +Q: The game/application runs much too slow! +Q: The game/application does not run at all/crashes! +Q: Can DOSBox harm my computer? +Q: I would like to change the memory size/cpu speed/ems/soundblaster IRQ. +Q: What sound hardware does DOSBox presently emulate? +Q: DOSBox crashes on startup and I'm running arts. +Q: My Build game(Duke3D/Blood/Shadow Warrior) has problems. +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:\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. + To change to the drive mounted like above, type "C:". If everything went + fine, DOSBox will display the prompt "C:\>". + + +Q: Do I always have to type these commands? Automation? +A: In the DOSBox configuration file is an [autoexec] section. The commands + present there are run when DOSBox starts, so you can use this section + for the mounting. + + +Q: How do I change to fullscreen? +A: Press alt-enter. Alternatively: Edit the configuration file of DOSBox and + change the option fullscreen=false to fullscreen=true. If fullscreen looks + wrong in your opinion: Play with the option fullresolution in the + configuration file of DOSBox. To get back from fullscreen mode: + Press alt-enter again. + + +Q: My CD-ROM doesn't work. +A: To mount your CD-ROM in DOSBox you have to specify some additional options + when mounting the CD-ROM. + To enable CD-ROM support (includes MSCDEX): + - mount d f:\ -t cdrom (windows) + - mount d /media/cdrom -t cdrom (linux) + + In some cases you might want to use a different CD-ROM interface, + for example if CD audio does not work: + To enable SDL-support (does not include low-level CD access!): + - mount d f:\ -t cdrom -usecd 0 -noioctl + To enable ioctl access using digital audio extraction for CD audio + (windows-only, useful for Vista): + - mount d f:\ -t cdrom -ioctl_dx + To enable ioctl access using MCI for CD audio (windows-only): + - mount d f:\ -t cdrom -ioctl_mci + To force ioctl-only access (windows-only): + - mount d f:\ -t cdrom -ioctl_dio + To enable low-level aspi-support (win98 with aspi-layer installed): + - mount d f:\ -t cdrom -aspi + + In the commands: - d driveletter you will get in DOSBox + - f:\ location of CD-ROM on your PC. + - 0 The number of the CD-ROM drive, reported by "mount -cd" + (note that this value is only needed when using SDL + for CD audio, otherwise it is ignored) + See also the next question: The game/application can't find its CD-ROM. + + +Q: The game/application can't find its CD-ROM. +A: Be sure to mount the CD-ROM with -t cdrom switch, this will enable the + MSCDEX interface required by DOS games to interface with CD-ROMs. + Also try adding the correct label (-label LABEL) to the mount command, + where LABEL is the CD-label (volume ID) of the CD-ROM. + Under Windows you can specify -ioctl, -aspi or -noioctl. Look at the + description of the mount command in Section 4 for their meaning and the + additional audio-CD related options -ioctl_dx, ioctl_mci, ioctl_dio. + + Try creating a CD-ROM image (preferably CUE/BIN pair) and use the + DOSBox-internal IMGMOUNT tool to mount the image (the CUE sheet). + This enables very good low-level CD-ROM support on any operating system. + + +Q: The mouse doesn't work. +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: There is no sound. +A: Be sure that the sound is correctly configured in the game. This might be + done during the installation or with a setup/setsound utility that + accompanies the game. First see if an autodetection option is provided. If + there is none try selecting soundblaster or soundblaster16 with the default + settings being "address=220 irq=7 dma=1". You might also want to select + midi at address 330 as music device. + The parameters of the emulated soundcards can be changed in the DOSBox + configuration file. + If you still don't get any sound set the core to normal and use some lower + fixed cycles value (like cycles=2000). Also assure that your host operating + sound does provide sound. + In certain cases it might be useful to use a different emulated sound device + like a soundblaster pro (sbtype=sbpro1 in the DOSBox configuration file) or + the gravis ultrasound (gus=true). + + +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 lower the cycles, skip frames, reduce the sampling rate of + the respective sound device (see the DOSBox configuration file) or + the mixer device. You can also increase the prebuffer in the configfile. + If you are using cycles=max or =auto, then make sure that there is no + background processes interfering! (especially if they access the harddisk) + + +Q: I can't type \ or : in DOSBox. +A: This can happen in various cases, like your host keyboard layout does not + have a matching DOS layout representation (or it was not correctly detected), + or the key mapping is wrong. + Some possible fixes: + 1. Use / instead, or ALT-58 for : and ALT-92 for \. + 2. Change the DOS keyboard layout (see Section 7: Keyboard Layout). + 3. Add the commands you want to execute to the [autoexec]-section + of the DOSBox configuration file. + 4. Open the DOSBox configuration file and change the usescancodes entry. + 5. Switch the keyboard layout of your operating system. + + Note that if the host layout can not be identified, or keyboardlayout is set + to none in the DOSBox configuration file, the standard US layout is used. + In this configuration try the keys around "enter" for the key \ (backslash), + and for the key : (colon) use shift and the keys between "enter" and "l". + + +Q: The keyboard lags. +A: Lower the priority setting in the DOSBox configuration file, for example + set "priority=normal,normal". You might also want to try lowering the cycles + (use a fixed cycle count to start with, like cycles=10000). + + +Q: The cursor always moves into one direction! +A: See if it still happens if you disable the joystick emulation, + set joysticktype=none in the [joystick] section of your DOSBox + configuration file. Maybe also try unplugging any joystick/gamepad. + If you want to use the joystick in the game, try setting timed=false + and be sure to calibrate the joystick (both in your OS as well as + in the game or the game's setup program). + + +Q: The game/application runs much too slow! +A: Look at the section "How to run resource-demanding games" for more + information. + + +Q: The game/application does not run at all/crashes! +A: Look at Section 10: Troubleshooting + + +Q: Can DOSBox harm my computer? +A: DOSBox can not harm your computer more than any other resource demanding + program. Increasing the cycles does not overclock your real CPU. + Setting the cycles too high has a negative performance effect on the + software running inside DOSBox. + + +Q: I would like to change the memory size/cpu speed/ems/soundblaster IRQ. +A: This is possible! Just create a config file: config -writeconf configfile. + Start your favourite editor and look through the settings. To start DOSBox + with your new settings: dosbox -conf configfile + See the description of the config command in Section 4 for more details. + + +Q: What sound hardware does DOSBox presently emulate? +A: DOSBox emulates several legacy sound devices: + - Internal PC speaker + This emulation includes both the tone generator and several forms of + digital sound output through the internal speaker. + - Creative CMS/Gameblaster + The is the first card released by Creative Labs(R). The default + configuration places it on port 0x220. It should be noted that enabling + 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. The noise channel is not very well documented and as + such is only a best guess as to the sound's accuracy. + - Tandy DAC + Emulation of the Tandy DAC utilizes the soundblaster emulation, thus + be sure the soundblaster is not disabled in the DOSBox configuration + file. The Tandy DAC is only emulated at the BIOS level. + - Adlib + This emulation is almost perfect and includes the Adlib's ability to + almost play digitized sound. + - 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 + 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. +A: This isn't really a DOSBox problem, but the solution is to set the + environment variable SDL_AUDIODRIVER to alsa or oss. + + +Q: My Build game(Duke3D/Blood/Shadow Warrior) has problems. +A: First of all, try to find a port of the game. Those will offer a + better experience. To fix the graphics problem that occurs in + DOSBox on higher resolutions. Open the configuration file of + DOSBox and search for machine=svga_s3. Change svga_s3 to vesa_nolfb + + +Q: Great README, but I still don't get it. +A: A look at "The Newbie's pictorial guide to DOSBox" located at + http://vogons.zetafleet.com/viewforum.php?f=39 might help you. + Also try the wiki of DOSBox: + http://www.dosbox.com/wiki/ + + +For more questions read the remainder of this README and/or check +the site/forum: +http://www.dosbox.com + + + +========= +3. Usage: +========= + +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. +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] [-noautoexec] [-securemode] + [-scaler scaler | -forcescaler scaler] + [-version] + +dosbox -version +dosbox -editconf program +dosbox -opencaptures program +dosbox -printconf +dosbox -eraseconf + + 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. + + -c command + Runs the specified command before running "name". Multiple commands + 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. + + -conf configfile + Start DOSBox with the options specified in "configfile". + Multiple -conf options may be present. + See Section 11 for more details. + + -lang languagefile + Start DOSBox using the language specified in "languagefile". + + -machine machinetype + Setup DOSBox to emulate a specific type of machine. Valid choices are: + hercules, cga, pcjr, tandy, svga_s3 (default) as well as the additional + svga chipsets listed in the help of the DOSBox configuration file. + svga_s3 enables vesa emulation as well. + For some special vga effects the machinetype vgaonly can be used, + note that this disables svga capabilites and might be (considerably) + slower due to the much higher emulation precision. + The machinetype affects both the videocard and the available soundcards. + + -noconsole (Windows Only) + Start DOSBox without showing the console window. Output will + be redirected to stdout.txt and stderr.txt + + -startmapper + Enter the keymapper directly on startup. Useful for people with + keyboard problems. + + -noautoexec + Skips the [autoexec] section of the loaded configuration file. + + -securemode + Same as -noautoexec, but adds config.com -securemode at the + bottom of AUTOEXEC.BAT (which in turn disables any changes to how + the drives are mounted inside DOSBox). + + -scaler scaler + Uses the scaler specified by "scaler". See the DOSBox configuration + file for the available scalers. + + -forcescaler scaler + Similar to the -scaler parameter, but tries to force usage of + the specified scaler even if it might not fit. + + -version + output version information and exit. Useful for frontends. + + -editconf program + calls program with as first parameter the configuration file. + You can specify this command more than once. In this case it will + move to second program if the first one fails to start. + + -opencaptures program + calls program with as first paramater the location of the captures + folder. + + -printconf + prints the location of the default configuration file. + + -eraseconf + removes the default configuration file. + +Note: If a name/command/configfile/languagefile contains a space, put + the whole name/command/configfile/languagefile between quotes + ("command or file name"). If you need to use quotes within quotes + (most likely with -c and mount): + Windows and OS/2 users can use single quotes inside the double quotes. + Other people should be able to use escaped double quotes inside the + double quotes. + Windows: -c "mount c 'c:\program files\'" + Linux: -c "mount c \"/tmp/name with space\"" + +For example (Windows): + +dosbox c:\atlantis\atlantis.exe -c "MOUNT D C:\SAVES" + 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. + + + +===================== +4. Internal Programs: +===================== + +DOSBox supports most of the DOS commands found in command.com. +To get a list of the internal commands type "HELP" at the prompt. + +In addition, the following commands are available: + +MOUNT "Emulated Drive letter" "Real Drive or Directory" + [-t type] [-aspi] [-ioctl] [-noioctl] [-usecd number] [-size drivesize] + [-label drivelabel] [-freesize size_in_mb] + [-freesize size_in_kb (floppies)] +MOUNT -cd +MOUNT -u "Emulated Drive letter" + + Program to mount local directories as drives inside DOSBox. + + "Emulated Drive letter" + The driveletter inside DOSBox (eg. C). + + "Real Drive letter (usually for CD-ROMs in Windows) or Directory" + The local directory you want accessible inside DOSBox. + + -t type + Type of the mounted directory. Supported are: dir (default), + floppy, cdrom. + + -size drivesize + Sets the size of the drive, where drivesize is of the form + "bps,spc,tcl,fcl": + bps: bytes per sector, by default 512 for regular drives and + 2048 for CD-ROM drives + spc: sectors per cluster, usually between 1 and 127 + tcl: total clusters, between 1 and 65534 + fcl: total free clusters, between 1 and tcl + + -freesize size_in_mb | size_in_kb + Sets the amount of free space available on a drive in megabytes + (regular drives) or kilobytes (floppy drives). + This is a simpler version of -size. + + -label drivelabel + Sets the name of the drive to "drivelabel". Needed on some + systems if the CD-ROM label isn't read correctly (useful when a + program can't find its CD-ROM). If you don't specify a label and no + lowlevel support is selected (that is omitting the -usecd # and/or + -aspi parameters, or specifying -noioctl): + For Windows: 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 + is mounted. It will not be updated !! + + -aspi + Forces use of the aspi layer. Only valid if mounting a CD-ROM under + Windows systems with an ASPI-Layer. + + -ioctl (automatic selection of the CD audio interface) + -ioctl_dx (digital audio extraction used for CD audio) + -ioctl_dio (ioctl calls used for CD audio) + -ioctl_mci (MCI used for CD audio) + Forces use of ioctl commands. Only valid if mounting a CD-ROM under + a Windows OS which support them (Win2000/XP/NT). + The various choices only differ in the way CD audio is handled, + preferrably -ioctl_dio is used (lowest workload), but this might not + work on all systems so -ioctl_dx (or -ioctl_mci) can be used. + + -noioctl + Forces use of the SDL CD-ROM layer. Valid on all systems. + + -usecd number + Valid on all systems, under windows the -noioctl switch has to be + present to make use of the -usecd switch. + Enables to select the drive that should be used by SDL. Use this if + the wrong or no CD-ROM drive is mounted while using the SDL CD-ROM + interface. "number" can be found by "MOUNT -cd". + + -cd + Displays all CD-ROM drives detected by SDL, and their numbers. + See the information at the -usecd entry above. + + -u + Removes the mount. Doesn't work for Z:\. + + Note: It's possible to mount a local directory as CD-ROM drive. + Hardware support is then missing. + + Basically MOUNT allows you to connect real hardware to DOSBox's emulated 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 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 the game into + believing it is on the C drive, while you can still place it where you + like. For example, if the game is in D:\OLDGAMES\TOUCHE, the command + MOUNT C D:\OLDGAMES will allow you to run Touche from the D drive. + + Mounting your entire C drive with MOUNT C C:\ is NOT recommended! The same + is true for mounting the root of any other drive, except for CD-ROMs (due to + their read-only nature). Otherwise if you or DOSBox make a mistake you may + lose all your files. + It is recommended to put all your applications/games into a subdirectory + and mount that. + + General MOUNT Examples: + 1. To mount c:\DirX as a floppy : + mount a c:\DirX -t floppy + 2. To mount system CD-ROM drive E as CD-ROM drive D in DOSBox: + mount d e:\ -t cdrom + 3. To mount system CD-ROM drive at mountpoint /media/cdrom as CD-ROM drive D + in DOSBox: + mount d /media/cdrom -t cdrom -usecd 0 + 4. To mount a drive with ~870 mb free diskspace (simple version): + mount c d:\ -freesize 870 + 5. To mount a drive with ~870 mb free diskspace (experts only, full control): + mount c d:\ -size 512,127,16513,13500 + 6. To mount /home/user/dirY as drive C in DOSBox: + mount c /home/user/dirY + 7. To mount the directory where DOSBox was started as D in DOSBox: + mount d . + (note the . which represents the directory where DOSBox was started) + + +MEM + Program to display the amount of free memory. + + +VER +VER set major_version [minor_version] + Display the current DOSBox version and reported DOS version + (parameterless usage). + Change the reported DOS version with the "set" parameter, + for example: "VER set 6 22" to have DOSBox report DOS 6.22 + as version number. + + +CONFIG -writeconf localfile +CONFIG -writelang localfile +CONFIG -securemode +CONFIG -set "section property=value" +CONFIG -get "section property" + + 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 11 (The Config File). + + -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 11 (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 output of the internal commands + and the internal DOS. + + -securemode + Switches DOSBox to a more secure mode. In this mode the internal + commands MOUNT, IMGMOUNT and BOOT won't work. It's not possible either + to create a new configfile or languagefile in this mode. + (Warning: you can only undo this mode by restarting DOSBox.) + + -set "section property=value" + CONFIG will attempt to set the property to new value. Currently + 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" + + +LOADFIX [-size] [program] [program-parameters] +LOADFIX -f + Program to reduce the amount of available conventional memory. + Useful for old programs which don't expect much memory to be free. + + -size + number of kilobytes to "eat up", default = 64kb + + -f + frees all previously allocated memory + + Examples: + 1. To start mm2.exe and allocate 64kb memory + (mm2 will have 64 kb less available) : + loadfix mm2 + 2. To start mm2.exe and allocate 32kb memory : + loadfix -32 mm2 + 3. To free previous allocated memory : + loadfix -f + + +RESCAN + Make DOSBox reread the directory structure. Useful if you changed something + on a mounted drive outside of DOSBox. (CTRL - F4 does this as well!) + + +MIXER + Makes DOSBox display its current volume settings. + Here's how you can change them: + + mixer channel left:right [/NOSHOW] [/LISTMIDI] + + channel + Can be one of the following: MASTER, DISNEY, SPKR, GUS, SB, FM [, CDAUDIO]. + CDAUDIO is only available if a CD-ROM interface with volume control is + enabled (CD image, ioctl_dx). + + left:right + The volume levels in percentages. If you put a D in front it will be + in decibel (Example: mixer gus d-10). + + /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 + 'midiconfig=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. + + IMGMOUNT DRIVE [imagefile] -t [image_type] -fs [image_format] + -size [sectorsbytesize, sectorsperhead, heads, cylinders] + IMGMOUNT DRIVE [imagefile1, .. ,imagefileN] -t iso -fs iso + + imagefile + Location of the image file to mount in DOSBox. The location can + be on a mounted drive inside DOSBox, or on your real disk. It is + possible to mount CD-ROM images (ISOs or CUE/BIN) as well, if you + need CD swapping capabilities specify all images in succession + (see the next entry). + CUE/BIN pairs are the preferred CD-ROM image type as they can + store audio tracks compared to ISOs (which are data-only). For + the CUE/BIN mounting always specify the CUE sheet. + + imagefile1, .. ,imagefileN + Location of the image files to mount in DOSBox. Specifying a number + of image files is only allowed for CD-ROM images. The CD's can be + swapped with CTRL-F4 at any time. This is required for games which + use multiple CD-ROMs and require the CD to be switched during the + gameplay at some point. + + -t + The following are valid image types: + floppy: Specifies a floppy image. DOSBox will automatically identify + the disk geometry (360K, 1.2MB, 720K, 1.44MB, etc). + iso: Specifies a CD-ROM iso image. The geometry is automatic and + set for this size. This can be an iso or a cue/bin pair. + hdd: Specifies a harddrive image. The proper CHS geometry + must be set for this to work. + + -fs + The following are valid file system formats: + iso: Specifies the ISO 9660 CD-ROM format. + 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 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, + you would type (without the quotes): + "imgmount 3 d:\test.img -size 512,63,16,142 -fs none" + Compare this with a mount to be able to access the drive + within DOSBox, which would read as: + "imgmount e: d:\test.img -size 512,63,16,142" + + -size + The Cylinders, Heads and Sectors of the drive. + Required to mount hard drive images. + + An example how to mount CD-ROM images: + 1a. mount c /tmp + 1b. imgmount d c:\myiso.iso -t iso + or (which also works): + 2. imgmount d /tmp/myiso.iso -t iso + + +BOOT + Boot will start floppy images or hard disk images independent of the + operating system emulation offered by DOSBox. This will allow you to + play booter floppies or boot other operating systems inside DOSBox. + If the target emulated system is PCjr (machine=pcjr) the boot command + can be used to load PCjr cartridges (.jrc). + + BOOT [diskimg1.img diskimg2.img .. diskimgN.img] [-l driveletter] + BOOT [cart.jrc] (PCjr only) + + 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, 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 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" + + cart.jrc (PCjr only) + When emulation of a PCjr is enabled, cartridges can be loaded with + the BOOT command. Support is still limited. + + +IPX + + You need to enable IPX networking in the configuration file of DOSBox. + + 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 the commands + and relevant documentation. + + With regard to actually setting up a network, one system needs to be + 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. + + To play games that need Netbios a file named NETBIOS.EXE from Novell is + needed. Establish the IPX connection as explained above, then run + "netbios.exe". + + The following is an IPXNET command reference: + + IPXNET CONNECT + + 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. 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 tunnelling server. + + The syntax for IPXNET DISCONNECT is: + IPXNET DISCONNECT + + IPXNET STARTSERVER + + IPXNET STARTSERVER starts an IPX tunnelling 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 tunnelling server. + + The syntax for IPXNET STARTSERVER is: + IPXNET STARTSERVER + + If the server is behind a router, UDP port needs to be forwarded + to that computer. + + On Linux/Unix-based systems port numbers smaller than 1023 can only be + used with root privileges. Use ports greater than 1023 on those systems. + + IPXNET STOPSERVER + + 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 that are still using the IPX tunnelling server. + + The syntax for IPXNET STOPSERVER is: + IPXNET STOPSERVER + + IPXNET PING + + 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 STATUS + + 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: + IPXNET STATUS + + +KEYB [languagecode [codepage [codepagefile]]] + Change the keyboard layout. For detailed information about keyboard + layouts please see Section 7. + + [languagecode] is a string consisting of two (in special cases more) + characters, examples are GK (Greece) or IT (Italy). It specifies + the keyboard layout to be used. + + [codepage] is the number of the codepage to be used. The keyboard layout + has to provide support for the specified codepage, otherwise the layout + loading will fail. + If no codepage is specified, an appropriate codepage for the requested + layout is chosen automatically. + + [codepagefile] can be used to load codepages that are yet not compiled + into DOSBox. This is only needed when DOSBox does not find the codepage. + + + Examples: + 1. To load the german keyboard layout (automatically uses codepage 858): + keyb gr + 2. To load the russian keyboard layout with codepage 866: + keyb ru 866 + In order to type russian characters press ALT+RIGHT-SHIFT. + 3. To load the french keyboard layout with codepage 850 (where the + codepage is defined in EGACPI.DAT): + keyb fr 850 EGACPI.DAT + 4. To load codepage 858 (without a keyboard layout): + keyb none 858 + This can be used to change the codepage for the FreeDOS keyb2 utility. + 5. To display the current codepage and, if loaded, the keyboard layout: + keyb + + + +For more information use the /? command line switch with the programs. + + + +================ +5. Special Keys: +================ + +ALT-ENTER Switch to full screen and back. +ALT-PAUSE Pause emulation (hit ALT-PAUSE again to continue). +CTRL-F1 Start the keymapper. +CTRL-F4 Change between mounted disk-images. Update directory cache for all drives! +CTRL-ALT-F5 Start/Stop creating a movie of the screen. (avi video capturing) +CTRL-F5 Save a screenshot. (PNG format) +CTRL-F6 Start/Stop recording sound output to a wave file. +CTRL-ALT-F7 Start/Stop recording of OPL commands. (DRO format) +CTRL-ALT-F8 Start/Stop the recording of raw MIDI commands. +CTRL-F7 Decrease frameskip. +CTRL-F8 Increase frameskip. +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). + +(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.) + + +These are the default keybindings. They can be changed in the keymapper +(see Section 6: Mapper). + +Saved/recorded files can be found in current_directory/capture +(this can be changed in the DOSBox configuration file). +The directory has to exist prior to starting DOSBox, otherwise nothing +gets saved/recorded ! + + + +========== +6. Mapper: +========== + +When you start the DOSBox mapper (either with CTRL-F1 or -startmapper as +a command line argument to the DOSBox executable) you are presented with +a virtual keyboard and a virtual joystick. + +These virtual devices correspond to the keys and events DOSBox will +report to the DOS applications. If you click on a button with your mouse, +you can see in the lower left corner with which event it is associated +(EVENT) and to what events it is currently bound. + +Event: EVENT +BIND: BIND + Add Del +mod1 hold Next +mod2 +mod3 + + +EVENT + The key or joystick axis/button/hat DOSBox will report to DOS applications. +BIND + The key on your real keyboard or the axis/button/hat on your real + joystick(s) (as reported by SDL) which is connected to the EVENT. +mod1,2,3 + Modfiers. These are keys you need to have to be pressed while pressing + 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. Basically add a key from your keyboard or an + event from the joystick (button press, axis/hat movement) which will + produce the EVENT in DOSBox. +Del + Delete the BIND to this EVENT. If an EVENT has no BINDS, then it is not + possible to trigger this event in DOSBox (that is there's no way to type + the key or use the respective action of the joystick). +Next + Go through the list of bindings which map to this EVENT. + + +Example: +Q1. You want to have the X on your keyboard to type a Z in DOSBox. + 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 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" 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 + 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" until you find the + mapped key X. Click "Del". + + +Examples about remapping the joystick: + You have a joystick attached, it is working fine under DOSBox and you + want to play some keyboard-only game with the joystick (it is assumed + that the game is controlled by the arrows on the keyboard): + 1. Start the mapper, then click on one of the arrows in the middle + of the left part of the screen (right above the Mod1/Mod2 buttons). + EVENT should be key_left. Now click on Add and move your joystick + in the respective direction, this should add an event to the BIND. + 2. Repeat the above for the missing three directions, additionally + the buttons of the joystick can be remapped as well (fire/jump). + 3. Click on Save, then on Exit and test it with some game. + + You want to swap the y-axis of the joystick because some flightsim uses + the up/down joystick movement in a way you don't like, and it is not + configurable in the game itself: + 1. Start the mapper and click on Y- in the upper joystick field (this + is for the first joystick if you have two joysticks attached) or the + lower joystick field (second joystick or, if you have only one + joystick attached, the second axes cross). + EVENT should be jaxis_0_1- (or jaxis_1_1-). + 2. Click on Del to remove the current binding, then click Add and move + your joystick downwards. A new bind should be created. + 3. Repeat this for Y+, save the layout and finally test it with some game. + + + +If you change the default mapping, you can save your changes by clicking on +"Save". DOSBox will save the mapping to a location specified in the configuration +file (the mapperfile= entry). At startup, DOSBox will load your mapperfile, +if it is present in the DOSBox configuration file. + + + +=================== +7. Keyboard Layout: +=================== + +To switch to a different keyboard layout, either the entry "keyboardlayout" +in the [dos] section of the DOSBox configuration file can be used, or the +internal DOSBox program keyb.com. Both accept DOS conforming language codes +(see below), but only by using keyb.com a custom codepage can be specified. + +The default keyboardlayout=auto currently works under windows only, the +layout is chosen according to the OS layout. + +Layout switching + DOSBox supports a number of keyboard layouts and codepages by default, + in this case just the layout identifier needs to be specified (like + keyboardlayout=sv in the DOSBox configuration file, or using "keyb sv" + at the DOSBox command prompt). + + Some keyboard layouts (for example layout GK codepage 869 and layout RU + codepage 808) have support for dual layouts that can be activated by + pressing LEFT-ALT+RIGHT-SHIFT and deactivated by LEFT-ALT+LEFT-SHIFT. + +Supported external files + The FreeDOS .kl files are supported (FreeDOS keyb2 keyboard layoutfiles) as + well as the FreeDOS keyboard.sys/keybrd2.sys/keybrd3.sys libraries which + consist of all available .kl files. + See http://projects.freedos.net/keyb/ for precompiled keyboard layouts if + the DOSBox-integrated layouts don't work for some reason, or if updated or + new layouts become available. + + Both .CPI (MS-DOS and compatible codepage files) and .CPX (FreeDOS + UPX-compressed codepage files) can be used. Some codepages are compiled + into DOSBox, so it is mostly not needed to care about external codepage + files. If you need a different (or custom) codepage file, copy it into + the directory of the DOSBox configuration file so it is accessible for + DOSBox. + + Additional layouts can be added by copying the corresponding .kl file into + the directory of the DOSBox configuration file and using the first part of + the filename as language code. + Example: For the file UZ.KL (keyboard layout for Uzbekistan) specify + "keyboardlayout=uz" in the DOSBox configuration file. + The integration of keyboard layout packages (like keybrd2.sys) works similar. + + +Note that the keyboard layout allows foreign characters to be entered, but +there is NO support for them in filenames. Try to avoid them both inside +DOSBox as well as in files on your host operating system that are accessible +by DOSBox. + + + +============================== +8. Serial Multiplayer feature: +============================== + +DOSBox can emulate a serial nullmodem cable over network and internet. +It can be configured through the [serialports] section in the DOSBox +configuration file. + +To create a nullmodem connection, one side needs to act as the server and +one as the client. + +The server needs to be set up in the DOSBox configuration file like this: + serial1=nullmodem + +The client: + serial1=nullmodem server: + +Now start your game and choose nullmodem / serial cable / already connected +as multiplayer method on COM1. Set the same baudrate on both computers. + +Furthermore, additional parameters can be specified to control the behavior +of the nullmodem connection. These are all parameters: + + * port: - TCP port number. Default: 23 + * rxdelay: - how long (milliseconds) to delay received data if the + interface is not ready. Increase this value if you encounter + overrun errors in the DOSBox Status Window. Default: 100 + * txdelay: - how long to gather data before sending a packet. Default: 12 + (reduces Network overhead) + * server: - This nullmodem will be a client connecting to the specified + server. (No server argument: be a server.) + * transparent:1 - Only send the serial data, no RTS/DTR handshake. Use this + when connecting to anything other than a nullmodem. + * telnet:1 - Interpret Telnet data from the remote site. Automatically + sets transparent. + * usedtr:1 - The connection will not be established until DTR is switched + on by the DOS program. Useful for modem terminals. + Automatically sets transparent. + * inhsocket:1 - Use a socket passed to DOSBox by command line. Automatically + sets transparent. (Socket Inheritance: It is used for + playing old DOS door games on new BBS software.) + +Example: Be a server listening on TCP port 5000. + serial1=nullmodem server: port:5000 rxdelay:1000 + + + +======================================= +9. How to run resource-demanding games: +======================================= + +DOSBox emulates the CPU, the sound and graphic cards, and other peripherals +of a PC, all at the same time. The speed of an emulated DOS application +depends on how many instructions can be emulated, which is adjustable +(number of cycles). + +CPU Cycles + By default (cycles=auto) DOSBox tries to detect whether a game needs to + be run with as many instructions emulated per time interval as possible. + You can force this behaviour by setting cycles=max in the DOSBox + configuration file. The DOSBox window will display a line "Cpu Cyles: max" + at the top then. In this mode you can reduce the amount of cycles on a + percentage-basis (hit CTRL-F11) or raise it again (CTRL-F12). + + Sometimes manually setting the number of cycles achieves better results, + in the DOSBox configuration file specify for example cycles=30000. When + running some DOS application you can raise the cycles with CTRL-F12 even + more, but you will be limited by the power of your actual CPU. You can see + how much free time your real 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 used there is no further way to speed up DOSBox + unless you reduce the load generated by the non-CPU parts of DOSBox. + +CPU Cores + On x86 architectures you can try to force the usage of a dynamically + recompiling core (set core=dynamic in the DOSBox configuration file). + This usually gives better results if the auto detection (core=auto) fails. + It is best accompanied by cycles=max. Note that there might be games + that work worse with the dynamic core, or do not work at all! + +Graphics emulation + VGA emulation is a very demanding part of DOSBox in terms of actual CPU + usage. Increase the number of frames skipped (in increments of one) by + pressing CTRL-F8. Your CPU usage should decrease when using a fixed + cycle setting. + 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. + +Sound emulation + You can also try to disable the sound through the setup utility of the game + to reduce load on your CPU further. Setting nosound=true does NOT disable + the emulation of sound devices, just the output of sound will be disabled. + +Also try to close every program but DOSBox to reserve as much resources +as possible for DOSBox. + + +Advanced cycles configuration: +The cycles=auto and cycles=max settings can be parameterized to have +different startup defaults. The syntax is + cycles=auto ["realmode default"] ["protected mode default"%] + [limit "cycle limit"] + cycles=max ["protected mode default"%] [limit "cycle limit"] +Example: + cycles=auto 1000 80% limit 20000 + will use cycles=1000 for real mode games, 80% CPU throttling for + protected mode games along with a hard cycle limit of 20000 + + + +==================== +10. Troubleshooting: +==================== + +DOSBox crashes right after starting it: + - use different values for the output= entry in your DOSBox + configuration file + - try to update your graphics card driver and DirectX + +Running a certain game closes DOSBox, crashes with some message or hangs: + - see if it works with a default DOSBox installation + (unmodified configuration file) + - try it with sound disabled (use the sound configuration + program that comes with the game, additionally you can + set sbtype=none and gus=false in the DOSBox configuration file) + - change some entries of the DOSBox configuration file, especially try: + core=normal + fixed cycles (for example cycles=10000) + ems=false + xms=false + or combinations of the above settings, + similar the machine settings that control the emulated chipset and + functionality: + machine=vesa_nolfb + or + machine=vgaonly + - use loadfix before starting the game + +The game exits to the DOSBox prompt with some error message: + - read the error message closely and try to locate the error + - try the hints at the above sections + - mount differently as some games are picky about the locations, + for example if you used "mount d d:\oldgames\game" try + "mount c d:\oldgames\game" and "mount c d:\oldgames" + - if the game requires a CD-ROM be sure you used "-t cdrom" when + mounting and try different additional parameters (the ioctl, + usecd and label switches, see the appropriate section) + - check the file permissions of the game files (remove read-only + attributes, add write permissions etc.) + - try reinstalling the game within DOSBox + + + +==================== +11. The Config File: +==================== + +A config file can be generated by CONFIG.COM, which can be found on the +internal DOSBox Z: drive when you start up DOSBox. Look in the internal +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 you can set. +# and % indicate comment-lines. +The DOSBox configuration file contains the current settings. You can +alter them and start DOSBox with the -conf switch to load the file and +use these settings. + +DOSBox will parse configuration files that are specified with -conf. If +none were specified it will try to load "dosbox.conf" from the local +directory. If there is none, DOSBox will load the user configuration +file. This file will be created if it doesn't exist. The file can be +found in ~/.dosbox (Linux) or "~/Library/Preferences" (MAC OS X). +Windows users should use the shortcuts in the startmenu to find it. + + + + +====================== +12. The Language File: +====================== + +A language file can be generated by CONFIG.COM (CONFIG -writelang langfile). +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. + + + +======================================== +13. Building your own version of DOSBox: +======================================== + +Download the source. +Check the INSTALL in the source distribution. + + + +=================== +14. Special thanks: +=================== + +See the THANKS file. + + +============ +15. Contact: +============ + +See the site: +http://www.dosbox.com +for an email address (The Crew-page). diff --git a/THANKS b/THANKS index 1e6f809..811f6c8 100644 --- a/THANKS +++ b/THANKS @@ -1,28 +1,28 @@ -We would like to thank: - - -Vlad R. of the vdmsound project for excellent sound blaster info. -Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator. -Jarek Burczynski for the new OPL3 emulator. -Ken Silverman for his work on an OPL2 emulator. - -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. - -Sourceforge for hosting our homepage and other development tools. -Mirek Luza, for his moderation of the forums. -eL_Pusher, DosFreak and MiniMax for their moderation of VOGONS forum. - -crazyc, gulikoza, M-HT for their work on the dynrec core. - -Jantien for the version management. -Shawn, Johannes and Marcus for creating the MAC OS X version. -Jochen for creating the OS/2 version. -Ido Beeri for the icon. -GOG Team for the splash screen. -All the people who submitted a bug. -The Beta Testers. - +We would like to thank: + + +Vlad R. of the vdmsound project for excellent sound blaster info. +Tatsuyuki Satoh of the Mame Team for making an excellent FM emulator. +Jarek Burczynski for the new OPL3 emulator. +Ken Silverman for his work on an OPL2 emulator. + +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. + +Sourceforge for hosting our homepage and other development tools. +Mirek Luza, for his moderation of the forums. +eL_Pusher, DosFreak and MiniMax for their moderation of VOGONS forum. + +crazyc, gulikoza, M-HT for their work on the dynrec core. + +Jantien for the version management. +Shawn, Johannes and Marcus for creating the MAC OS X version. +Jochen for creating the OS/2 version. +Ido Beeri for the icon. +GOG Team for the splash screen. +All the people who submitted a bug. +The Beta Testers. + diff --git a/VERSION b/VERSION index db9d1f2..6ab5ccf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.73 +0.73 diff --git a/acinclude.m4 b/acinclude.m4 index 1ba5441..61e3d06 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -305,7 +305,7 @@ AC_SUBST(ALSA_LIBS) AH_TOP([ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/autogen.sh b/autogen.sh index 2b2e66c..4d7d5ba 100644 --- a/autogen.sh +++ b/autogen.sh @@ -1,14 +1,14 @@ -#!/bin/sh - -echo "Generating build information using aclocal, autoheader, automake and autoconf" -echo "This may take a while ..." - -# Regenerate configuration files. - -aclocal -autoheader -automake --include-deps --add-missing --copy -autoconf - -echo "Now you are ready to run ./configure." -echo "You can also run ./configure --help for extra features to enable/disable." +#!/bin/sh + +echo "Generating build information using aclocal, autoheader, automake and autoconf" +echo "This may take a while ..." + +# Regenerate configuration files. + +aclocal +autoheader +automake --include-deps --add-missing --copy +autoconf + +echo "Now you are ready to run ./configure." +echo "You can also run ./configure --help for extra features to enable/disable." diff --git a/configure.in b/configure.in index 72c62c0..a24f9bf 100644 --- a/configure.in +++ b/configure.in @@ -1,528 +1,528 @@ -dnl Init. -AC_INIT(dosbox,0.73) -AC_PREREQ(2.50) -AC_CONFIG_SRCDIR(README) - -dnl Detect the canonical host and target build environment -AC_CANONICAL_HOST -AC_CANONICAL_TARGET - -dnl Setup for automake -AM_INIT_AUTOMAKE -AM_CONFIG_HEADER(config.h) - -dnl Checks for programs. -AC_PROG_MAKE_SET -AC_PROG_CC -AC_PROG_CPP -AC_PROG_CXX -AC_PROG_INSTALL -AC_PROG_RANLIB - -dnl Some needed libaries for OS2 -dnl perharps join this with the other target 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, - :, - AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]) -) -LIBS="$LIBS $SDL_LIBS" -CPPFLAGS="$CPPFLAGS $SDL_CFLAGS" - -dnl Check if SDL is 1.2.x (1.3 not supported) -AC_MSG_CHECKING([SDL version only being 1.2.X]) -AC_COMPILE_IFELSE([ -#include "SDL.h" -void blah(){ -#if SDL_MINOR_VERSION != 2 -#error "Only SDL 1.2 supported" -#endif -; -} -],AC_MSG_RESULT([yes]),[ - AC_MSG_RESULT([no]) - AC_MSG_ERROR([Only libSDL 1.2.X supported])]) - -dnl Checks for header files. - -dnl Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_SIZE_T -AC_STRUCT_TM -AC_CHECK_SIZEOF(unsigned char) -AC_CHECK_SIZEOF(unsigned short) -AC_CHECK_SIZEOF(unsigned int) -AC_CHECK_SIZEOF(unsigned long) -AC_CHECK_SIZEOF(unsigned long long) -AC_CHECK_SIZEOF(int *) - -dnl some semi complex check for sys/socket so it works on darwin as well -AC_CHECK_HEADERS([stdlib.h sys/types.h]) -AC_CHECK_HEADERS([sys/socket.h netinet/in.h pwd.h], [], [], -[#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -]) - -dnl check for the socklen_t (darwin doesn't always have it) -AC_COMPILE_IFELSE([ -#include -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -],[],[AC_DEFINE([socklen_t],[int],[Define to `int` if you don't have socklen_t])]) - -AC_MSG_CHECKING(if environ can be included) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include -#include ]],[[*environ;]])], -[AC_MSG_RESULT(yes);AC_DEFINE(ENVIRON_INCLUDED,1,[environ can be included])],AC_MSG_RESULT(no)) - -AC_MSG_CHECKING(if environ can be linked) -AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern char ** environ;]],[[*environ;]])], -[AC_MSG_RESULT(yes);AC_DEFINE(ENVIRON_LINKED,1,[environ can be linked])],AC_MSG_RESULT(no)) - -AC_MSG_CHECKING([if dirent includes d_type]) -AC_COMPILE_IFELSE([ -#include -#include -void blah(){ -struct dirent d_test; -d_test.d_type = 0; -}],[AC_MSG_RESULT(yes);AC_DEFINE(DIRENT_HAS_D_TYPE,1,[struct dirent has d_type])],AC_MSG_RESULT(no)) - - -dnl Check for powf -AC_MSG_CHECKING(for powf in libm); -LIBS_BACKUP=$LIBS; -LIBS="$LIBS -lm"; -AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ - powf(1.0f, 1.0f); -]])], [AC_MSG_RESULT(yes)], [AC_DEFINE([DB_HAVE_NO_POWF],[1],[libm doesn't include powf])]) -LIBS=$LIBS_BACKUP - - -dnl Checks for libraries. - -#Check if the compiler support attributes -AH_TEMPLATE([C_HAS_ATTRIBUTE],[Determines if the compilers supports attributes for structures.]) -AC_MSG_CHECKING(if compiler allows __attribute__) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -typedef struct { } __attribute__((packed)) junk;]], -[[ ]])],[ AC_MSG_RESULT(yes);AC_DEFINE(C_HAS_ATTRIBUTE)],AC_MSG_RESULT(no)) - - -#Check if the compiler supports certain attributes -OLDCFLAGS="$CFLAGS" -CFLAGS="-Werror" - -AH_TEMPLATE([C_ATTRIBUTE_ALWAYS_INLINE],[Determines if the compilers supports always_inline attribute.]) -AC_MSG_CHECKING(if compiler allows __attribute__((always_inline)) ) -AC_COMPILE_IFELSE([ void __attribute__((always_inline)) test(){} -],[ AC_MSG_RESULT(yes);AC_DEFINE(C_ATTRIBUTE_ALWAYS_INLINE)],AC_MSG_RESULT(no)) - -AH_TEMPLATE([C_ATTRIBUTE_FASTCALL],[Determines if the compilers supports fastcall attribute.]) -AC_MSG_CHECKING(if compiler allows __attribute__((fastcall)) ) -AC_COMPILE_IFELSE([ void __attribute__((fastcall)) test(){} -],[ AC_MSG_RESULT(yes);AC_DEFINE(C_ATTRIBUTE_FASTCALL)],AC_MSG_RESULT(no)) - - -CFLAGS="$OLDCFLAGS" - - -#Check if the compiler supports __builtin_expect -#Switch language to c++ -AC_LANG_PUSH(C++) -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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[ -int x=10;if( __builtin_expect ((x==1),0) ) ; -]])], [ AC_MSG_RESULT(yes);AC_DEFINE(C_HAS_BUILTIN_EXPECT)],AC_MSG_RESULT(no)) -#switch language back -AC_LANG_POP(C++) - -dnl enable disable alsa and pass it's cflags to CXXFLAGS -AC_ARG_ENABLE(alsa-midi, -AC_HELP_STRING([--enable-alsa-midi],[compile with alsa midi support (default yes)]), -[ case "${enableval}" in - yes) alsa_midi=true;; - no) alsa_midi=false;; -esac], -[alsa_midi=true]) -if test x$alsa_midi = xtrue ; then - AM_PATH_ALSA(0.9.0, AC_DEFINE(HAVE_ALSA,1,[Define to 1 to use ALSA for MIDI]) , : ) - CXXFLAGS="$CXXFLAGS $ALSA_CFLAGS" -fi - -#Check for big endian machine, should #define WORDS_BIGENDIAN if so -AC_C_BIGENDIAN - -#Features to enable/disable -AH_TEMPLATE(C_DEBUG,[Define to 1 to enable internal debugger, requires libcurses]) -AH_TEMPLATE(C_HEAVY_DEBUG,[Define to 1 to enable heavy debugging, also have to enable C_DEBUG]) -AC_ARG_ENABLE(debug,AC_HELP_STRING([--enable-debug],[Enable debug mode]),[ - AC_CHECK_HEADER(curses.h,have_curses_h=yes,) - AC_CHECK_LIB(curses, initscr, have_curses_lib=yes, , ) - AC_CHECK_LIB(ncurses, initscr, have_ncurses_lib=yes, , ) - AC_CHECK_LIB(pdcurses, initscr, have_pdcurses_lib=yes, , ) - - 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 - AC_DEFINE(C_HEAVY_DEBUG,1) - fi - elif test x$have_ncurses_lib = xyes -a x$have_curses_h = xyes ; then - LIBS="$LIBS -lncurses" - AC_DEFINE(C_DEBUG,1) - if test x$enable_debug = xheavy ; then - AC_DEFINE(C_HEAVY_DEBUG,1) - fi - elif test x$have_pdcurses_lib = xyes -a x$have_curses_h = xyes ; then - LIBS="$LIBS -lpdcurses" - AC_DEFINE(C_DEBUG,1) - if test x$enable_debug = xheavy ; then - AC_DEFINE(C_HEAVY_DEBUG,1) - fi - else - AC_MSG_ERROR([Can't find curses, which is required for debug mode]) - fi -],) - -AH_TEMPLATE(C_CORE_INLINE,[Define to 1 to use inlined memory functions in cpu core]) -AC_ARG_ENABLE(core-inline,AC_HELP_STRING([--enable-core-inline],[Enable inlined memory handling in CPU Core]),[ - if test x$enable_core_inline = xyes ; then - AC_MSG_RESULT([enabling inlined memory handling in CPU Core]) - AC_DEFINE(C_CORE_INLINE,1) - fi -],) - - -dnl The target cpu checks for dynamic cores -AH_TEMPLATE(C_TARGETCPU,[The type of cpu this target has]) -AC_MSG_CHECKING(for target cpu type) -case "$target_cpu" in - x86_64 | amd64) - AC_DEFINE(C_TARGETCPU,X86_64) - AC_MSG_RESULT(x86-64 bit compatible) - c_targetcpu="x86_64" - c_unalignedmemory=yes - ;; - i?86) - AC_DEFINE(C_TARGETCPU,X86) - AC_MSG_RESULT(x86 compatible) - c_targetcpu="x86" - c_unalignedmemory=yes - ;; - powerpc*) - AC_DEFINE(C_TARGETCPU,POWERPC) - AC_MSG_RESULT(Power PC) - c_targetcpu="powerpc" - c_unalignedmemory=yes - ;; - m68k*) - AC_DEFINE(C_TARGETCPU,M68K) - AC_MSG_RESULT(Motorola 68000) - c_targetcpu="m68k" - c_unalignedmemory=yes - ;; - *) - AC_DEFINE(C_TARGETCPU,UNKNOWN) - AC_MSG_RESULT(unknown) - c_unalignedmemory=no - ;; -esac - -AC_ARG_ENABLE(dynamic-core,AC_HELP_STRING([--disable-dynamic-core],[Disable all dynamic cores]),,enable_dynamic_core=yes) - -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) -if test x$enable_dynamic_x86 = xno -o x$enable_dynamic_core = xno; then - AC_MSG_RESULT(no) -else - if test x$c_targetcpu = xx86 ; then - AC_DEFINE(C_DYNAMIC_X86,1) - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - fi -fi - -AH_TEMPLATE(C_DYNREC,[Define to 1 to use recompiling cpu core. Can not be used together with the dynamic-x86 core]) -AC_ARG_ENABLE(dynrec,AC_HELP_STRING([--disable-dynrec],[Disable recompiling cpu core]),,enable_dynrec=yes) -AC_MSG_CHECKING(whether recompiling cpu core will be enabled) -if test x$enable_dynrec = xno -o x$enable_dynamic_core = xno; then - AC_MSG_RESULT(no) -else -dnl x86 only enable it if dynamic-x86 is disabled. - if test x$c_targetcpu = xx86 ; then - if test x$enable_dynamic_x86 = xno ; then - AC_DEFINE(C_DYNREC,1) - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT([no, using dynamic-x86]) - fi - else - if test x$c_targetcpu = xx86_64 ; then - AC_DEFINE(C_DYNREC,1) - AC_MSG_RESULT(yes) - else - AC_MSG_RESULT(no) - fi - 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) -if test x$enable_fpu = xyes ; then - AC_MSG_RESULT(yes) - AC_DEFINE(C_FPU,1) -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_targetcpu = 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) -if test x$have_png_lib = xyes -a x$have_png_h = xyes ; then - LIBS="$LIBS -lpng -lz" - AC_DEFINE(C_SSHOT,1) -else - AC_MSG_WARN([Can't find libpng, screenshot support disabled]) -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([AC_LANG_PROGRAM([[#include ]],[[ - 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) - AC_DEFINE(C_IPX,1) -else - AC_MSG_WARN([Can't find SDL_net, internal modem and ipx disabled]) -fi - -AH_TEMPLATE(C_X11_XKB,[define to 1 if you have XKBlib.h and X11 lib]) -AC_CHECK_LIB(X11, main, have_x11_lib=yes, have_x11_lib=no, ) -AC_CHECK_HEADER(X11/XKBlib.h, have_x11_h=yes, have_x11_h=no, ) -AC_MSG_CHECKING(for XKBlib support) -if test x$have_x11_lib = xyes -a x$have_x11_h = xyes ; then - LIBS="$LIBS -lX11" - AC_DEFINE(C_X11_XKB,1) - AC_MSG_RESULT(yes) -else - AC_MSG_RESULT(no) -fi - -AH_TEMPLATE(C_OPENGL,[Define to 1 to use opengl display output support]) -AC_CHECK_LIB(GL, main, have_gl_lib=yes, have_gl_lib=no , ) -AC_CHECK_LIB(opengl32, main, have_opengl32_lib=yes,have_opengl32_lib=no , ) -AC_CHECK_HEADER(GL/gl.h, have_gl_h=yes , have_gl_h=no , ) -AC_ARG_ENABLE(opengl,AC_HELP_STRING([--disable-opengl],[Disable opengl support]),,enable_opengl=yes) -AC_MSG_CHECKING(whether opengl display output will be enabled) -if test x$enable_opengl = xyes; then -case "$target" in - *-*-darwin*) - AC_MSG_RESULT(yes) - LIBS="$LIBS -framework OpenGL" - AC_DEFINE(C_OPENGL,1) - ;; - *) - if test x$have_gl_h = xyes -a x$have_gl_lib = xyes ; then - AC_MSG_RESULT(yes) - LIBS="$LIBS -lGL" - AC_DEFINE(C_OPENGL,1) - elif test x$have_gl_h = xyes -a x$have_opengl32_lib = xyes ; then - AC_MSG_RESULT(yes) - LIBS="$LIBS -lopengl32" - AC_DEFINE(C_OPENGL,1) - else - AC_MSG_RESULT(no) - fi - ;; -esac -fi - -AH_TEMPLATE(C_SDL_SOUND,[Define to 1 to enable SDL_sound support]) -AC_CHECK_HEADER(SDL_sound.h,have_SDL_sound_h=yes,) -AC_CHECK_LIB(SDL_sound, Sound_Init, have_SDL_sound_init=yes,,) -AC_CHECK_LIB(SDL_sound, Sound_Seek, have_SDL_sound_seek=yes,,) -if test x$have_SDL_sound_h = xyes -a x$have_SDL_sound_init = xyes ; then - if test x$have_SDL_sound_seek = xyes ; then - LIBS="-lSDL_sound $LIBS" - AC_DEFINE(C_SDL_SOUND,1) - else - AC_MSG_WARN([Can't find SoundSeek in libSDL_Sound, libSDL_sound support disabled]) - fi -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([ -#include -int main(int argc,char * argv[]) { - return setpriority (PRIO_PROCESS, 0,PRIO_MIN+PRIO_MAX); -}; -],AC_MSG_RESULT(yes);AC_DEFINE(C_SET_PRIORITY,1),AC_MSG_RESULT(no)) - - -dnl Some target detection and actions for them -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, Posix and OS/2 only).]) - if test x$have_sdl_net_lib = xyes -a x$have_sdl_net_h = xyes ; then - LIBS="$LIBS -lws2_32" - fi - ;; - *-*-darwin*) - dnl We have a problem here: both Mac OS X and Darwin report - dnl the same signature "powerpc-apple-darwin*" - so we have - dnl to do more to distinguish them. - dnl For now I am lazy and do not add proper detection code. - AC_DEFINE(MACOSX, 1, [Compiling on Mac OS X]) - LIBS="$LIBS -framework CoreMIDI -framework AudioUnit -framework AudioToolbox" - AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2).]) - ;; - *-*-linux*) - AC_DEFINE(LINUX, 1, [Compiling on GNU/Linux]) - AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2).]) - ;; - *-*-freebsd* | *-*-dragonfly* | *-*-netbsd* | *-*-openbsd*) - dnl Disabled directserial for now. It doesn't do anything without - dnl specifying an extra ifdef in directserial_posix.* - dnl directserial detection should be rewritten to test for the needed - dnl functions and headers. I currently do not know - dnl which ones are needed for BSD - AC_DEFINE(BSD, 1, [Compiling on BSD]) - AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2).]) - ;; - *-*-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, Posix and OS/2).]) - ;; -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_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/cpu/core_dynrec/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/libs/gui_tk/Makefile -src/misc/Makefile -src/shell/Makefile -src/platform/Makefile -src/platform/visualc/Makefile -visualc_net/Makefile -include/Makefile -docs/Makefile -]) -AC_OUTPUT +dnl Init. +AC_INIT(dosbox,0.73) +AC_PREREQ(2.50) +AC_CONFIG_SRCDIR(README) + +dnl Detect the canonical host and target build environment +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +dnl Setup for automake +AM_INIT_AUTOMAKE +AM_CONFIG_HEADER(config.h) + +dnl Checks for programs. +AC_PROG_MAKE_SET +AC_PROG_CC +AC_PROG_CPP +AC_PROG_CXX +AC_PROG_INSTALL +AC_PROG_RANLIB + +dnl Some needed libaries for OS2 +dnl perharps join this with the other target 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, + :, + AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]) +) +LIBS="$LIBS $SDL_LIBS" +CPPFLAGS="$CPPFLAGS $SDL_CFLAGS" + +dnl Check if SDL is 1.2.x (1.3 not supported) +AC_MSG_CHECKING([SDL version only being 1.2.X]) +AC_COMPILE_IFELSE([ +#include "SDL.h" +void blah(){ +#if SDL_MINOR_VERSION != 2 +#error "Only SDL 1.2 supported" +#endif +; +} +],AC_MSG_RESULT([yes]),[ + AC_MSG_RESULT([no]) + AC_MSG_ERROR([Only libSDL 1.2.X supported])]) + +dnl Checks for header files. + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_C_INLINE +AC_TYPE_SIZE_T +AC_STRUCT_TM +AC_CHECK_SIZEOF(unsigned char) +AC_CHECK_SIZEOF(unsigned short) +AC_CHECK_SIZEOF(unsigned int) +AC_CHECK_SIZEOF(unsigned long) +AC_CHECK_SIZEOF(unsigned long long) +AC_CHECK_SIZEOF(int *) + +dnl some semi complex check for sys/socket so it works on darwin as well +AC_CHECK_HEADERS([stdlib.h sys/types.h]) +AC_CHECK_HEADERS([sys/socket.h netinet/in.h pwd.h], [], [], +[#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +]) + +dnl check for the socklen_t (darwin doesn't always have it) +AC_COMPILE_IFELSE([ +#include +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +],[],[AC_DEFINE([socklen_t],[int],[Define to `int` if you don't have socklen_t])]) + +AC_MSG_CHECKING(if environ can be included) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#include ]],[[*environ;]])], +[AC_MSG_RESULT(yes);AC_DEFINE(ENVIRON_INCLUDED,1,[environ can be included])],AC_MSG_RESULT(no)) + +AC_MSG_CHECKING(if environ can be linked) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[extern char ** environ;]],[[*environ;]])], +[AC_MSG_RESULT(yes);AC_DEFINE(ENVIRON_LINKED,1,[environ can be linked])],AC_MSG_RESULT(no)) + +AC_MSG_CHECKING([if dirent includes d_type]) +AC_COMPILE_IFELSE([ +#include +#include +void blah(){ +struct dirent d_test; +d_test.d_type = 0; +}],[AC_MSG_RESULT(yes);AC_DEFINE(DIRENT_HAS_D_TYPE,1,[struct dirent has d_type])],AC_MSG_RESULT(no)) + + +dnl Check for powf +AC_MSG_CHECKING(for powf in libm); +LIBS_BACKUP=$LIBS; +LIBS="$LIBS -lm"; +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[ + powf(1.0f, 1.0f); +]])], [AC_MSG_RESULT(yes)], [AC_DEFINE([DB_HAVE_NO_POWF],[1],[libm doesn't include powf])]) +LIBS=$LIBS_BACKUP + + +dnl Checks for libraries. + +#Check if the compiler support attributes +AH_TEMPLATE([C_HAS_ATTRIBUTE],[Determines if the compilers supports attributes for structures.]) +AC_MSG_CHECKING(if compiler allows __attribute__) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +typedef struct { } __attribute__((packed)) junk;]], +[[ ]])],[ AC_MSG_RESULT(yes);AC_DEFINE(C_HAS_ATTRIBUTE)],AC_MSG_RESULT(no)) + + +#Check if the compiler supports certain attributes +OLDCFLAGS="$CFLAGS" +CFLAGS="-Werror" + +AH_TEMPLATE([C_ATTRIBUTE_ALWAYS_INLINE],[Determines if the compilers supports always_inline attribute.]) +AC_MSG_CHECKING(if compiler allows __attribute__((always_inline)) ) +AC_COMPILE_IFELSE([ void __attribute__((always_inline)) test(){} +],[ AC_MSG_RESULT(yes);AC_DEFINE(C_ATTRIBUTE_ALWAYS_INLINE)],AC_MSG_RESULT(no)) + +AH_TEMPLATE([C_ATTRIBUTE_FASTCALL],[Determines if the compilers supports fastcall attribute.]) +AC_MSG_CHECKING(if compiler allows __attribute__((fastcall)) ) +AC_COMPILE_IFELSE([ void __attribute__((fastcall)) test(){} +],[ AC_MSG_RESULT(yes);AC_DEFINE(C_ATTRIBUTE_FASTCALL)],AC_MSG_RESULT(no)) + + +CFLAGS="$OLDCFLAGS" + + +#Check if the compiler supports __builtin_expect +#Switch language to c++ +AC_LANG_PUSH(C++) +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_COMPILE_IFELSE([AC_LANG_PROGRAM([[]],[[ +int x=10;if( __builtin_expect ((x==1),0) ) ; +]])], [ AC_MSG_RESULT(yes);AC_DEFINE(C_HAS_BUILTIN_EXPECT)],AC_MSG_RESULT(no)) +#switch language back +AC_LANG_POP(C++) + +dnl enable disable alsa and pass it's cflags to CXXFLAGS +AC_ARG_ENABLE(alsa-midi, +AC_HELP_STRING([--enable-alsa-midi],[compile with alsa midi support (default yes)]), +[ case "${enableval}" in + yes) alsa_midi=true;; + no) alsa_midi=false;; +esac], +[alsa_midi=true]) +if test x$alsa_midi = xtrue ; then + AM_PATH_ALSA(0.9.0, AC_DEFINE(HAVE_ALSA,1,[Define to 1 to use ALSA for MIDI]) , : ) + CXXFLAGS="$CXXFLAGS $ALSA_CFLAGS" +fi + +#Check for big endian machine, should #define WORDS_BIGENDIAN if so +AC_C_BIGENDIAN + +#Features to enable/disable +AH_TEMPLATE(C_DEBUG,[Define to 1 to enable internal debugger, requires libcurses]) +AH_TEMPLATE(C_HEAVY_DEBUG,[Define to 1 to enable heavy debugging, also have to enable C_DEBUG]) +AC_ARG_ENABLE(debug,AC_HELP_STRING([--enable-debug],[Enable debug mode]),[ + AC_CHECK_HEADER(curses.h,have_curses_h=yes,) + AC_CHECK_LIB(curses, initscr, have_curses_lib=yes, , ) + AC_CHECK_LIB(ncurses, initscr, have_ncurses_lib=yes, , ) + AC_CHECK_LIB(pdcurses, initscr, have_pdcurses_lib=yes, , ) + + 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 + AC_DEFINE(C_HEAVY_DEBUG,1) + fi + elif test x$have_ncurses_lib = xyes -a x$have_curses_h = xyes ; then + LIBS="$LIBS -lncurses" + AC_DEFINE(C_DEBUG,1) + if test x$enable_debug = xheavy ; then + AC_DEFINE(C_HEAVY_DEBUG,1) + fi + elif test x$have_pdcurses_lib = xyes -a x$have_curses_h = xyes ; then + LIBS="$LIBS -lpdcurses" + AC_DEFINE(C_DEBUG,1) + if test x$enable_debug = xheavy ; then + AC_DEFINE(C_HEAVY_DEBUG,1) + fi + else + AC_MSG_ERROR([Can't find curses, which is required for debug mode]) + fi +],) + +AH_TEMPLATE(C_CORE_INLINE,[Define to 1 to use inlined memory functions in cpu core]) +AC_ARG_ENABLE(core-inline,AC_HELP_STRING([--enable-core-inline],[Enable inlined memory handling in CPU Core]),[ + if test x$enable_core_inline = xyes ; then + AC_MSG_RESULT([enabling inlined memory handling in CPU Core]) + AC_DEFINE(C_CORE_INLINE,1) + fi +],) + + +dnl The target cpu checks for dynamic cores +AH_TEMPLATE(C_TARGETCPU,[The type of cpu this target has]) +AC_MSG_CHECKING(for target cpu type) +case "$target_cpu" in + x86_64 | amd64) + AC_DEFINE(C_TARGETCPU,X86_64) + AC_MSG_RESULT(x86-64 bit compatible) + c_targetcpu="x86_64" + c_unalignedmemory=yes + ;; + i?86) + AC_DEFINE(C_TARGETCPU,X86) + AC_MSG_RESULT(x86 compatible) + c_targetcpu="x86" + c_unalignedmemory=yes + ;; + powerpc*) + AC_DEFINE(C_TARGETCPU,POWERPC) + AC_MSG_RESULT(Power PC) + c_targetcpu="powerpc" + c_unalignedmemory=yes + ;; + m68k*) + AC_DEFINE(C_TARGETCPU,M68K) + AC_MSG_RESULT(Motorola 68000) + c_targetcpu="m68k" + c_unalignedmemory=yes + ;; + *) + AC_DEFINE(C_TARGETCPU,UNKNOWN) + AC_MSG_RESULT(unknown) + c_unalignedmemory=no + ;; +esac + +AC_ARG_ENABLE(dynamic-core,AC_HELP_STRING([--disable-dynamic-core],[Disable all dynamic cores]),,enable_dynamic_core=yes) + +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) +if test x$enable_dynamic_x86 = xno -o x$enable_dynamic_core = xno; then + AC_MSG_RESULT(no) +else + if test x$c_targetcpu = xx86 ; then + AC_DEFINE(C_DYNAMIC_X86,1) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi +fi + +AH_TEMPLATE(C_DYNREC,[Define to 1 to use recompiling cpu core. Can not be used together with the dynamic-x86 core]) +AC_ARG_ENABLE(dynrec,AC_HELP_STRING([--disable-dynrec],[Disable recompiling cpu core]),,enable_dynrec=yes) +AC_MSG_CHECKING(whether recompiling cpu core will be enabled) +if test x$enable_dynrec = xno -o x$enable_dynamic_core = xno; then + AC_MSG_RESULT(no) +else +dnl x86 only enable it if dynamic-x86 is disabled. + if test x$c_targetcpu = xx86 ; then + if test x$enable_dynamic_x86 = xno ; then + AC_DEFINE(C_DYNREC,1) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT([no, using dynamic-x86]) + fi + else + if test x$c_targetcpu = xx86_64 ; then + AC_DEFINE(C_DYNREC,1) + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + 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) +if test x$enable_fpu = xyes ; then + AC_MSG_RESULT(yes) + AC_DEFINE(C_FPU,1) +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_targetcpu = 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) +if test x$have_png_lib = xyes -a x$have_png_h = xyes ; then + LIBS="$LIBS -lpng -lz" + AC_DEFINE(C_SSHOT,1) +else + AC_MSG_WARN([Can't find libpng, screenshot support disabled]) +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([AC_LANG_PROGRAM([[#include ]],[[ + 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) + AC_DEFINE(C_IPX,1) +else + AC_MSG_WARN([Can't find SDL_net, internal modem and ipx disabled]) +fi + +AH_TEMPLATE(C_X11_XKB,[define to 1 if you have XKBlib.h and X11 lib]) +AC_CHECK_LIB(X11, main, have_x11_lib=yes, have_x11_lib=no, ) +AC_CHECK_HEADER(X11/XKBlib.h, have_x11_h=yes, have_x11_h=no, ) +AC_MSG_CHECKING(for XKBlib support) +if test x$have_x11_lib = xyes -a x$have_x11_h = xyes ; then + LIBS="$LIBS -lX11" + AC_DEFINE(C_X11_XKB,1) + AC_MSG_RESULT(yes) +else + AC_MSG_RESULT(no) +fi + +AH_TEMPLATE(C_OPENGL,[Define to 1 to use opengl display output support]) +AC_CHECK_LIB(GL, main, have_gl_lib=yes, have_gl_lib=no , ) +AC_CHECK_LIB(opengl32, main, have_opengl32_lib=yes,have_opengl32_lib=no , ) +AC_CHECK_HEADER(GL/gl.h, have_gl_h=yes , have_gl_h=no , ) +AC_ARG_ENABLE(opengl,AC_HELP_STRING([--disable-opengl],[Disable opengl support]),,enable_opengl=yes) +AC_MSG_CHECKING(whether opengl display output will be enabled) +if test x$enable_opengl = xyes; then +case "$target" in + *-*-darwin*) + AC_MSG_RESULT(yes) + LIBS="$LIBS -framework OpenGL" + AC_DEFINE(C_OPENGL,1) + ;; + *) + if test x$have_gl_h = xyes -a x$have_gl_lib = xyes ; then + AC_MSG_RESULT(yes) + LIBS="$LIBS -lGL" + AC_DEFINE(C_OPENGL,1) + elif test x$have_gl_h = xyes -a x$have_opengl32_lib = xyes ; then + AC_MSG_RESULT(yes) + LIBS="$LIBS -lopengl32" + AC_DEFINE(C_OPENGL,1) + else + AC_MSG_RESULT(no) + fi + ;; +esac +fi + +AH_TEMPLATE(C_SDL_SOUND,[Define to 1 to enable SDL_sound support]) +AC_CHECK_HEADER(SDL_sound.h,have_SDL_sound_h=yes,) +AC_CHECK_LIB(SDL_sound, Sound_Init, have_SDL_sound_init=yes,,) +AC_CHECK_LIB(SDL_sound, Sound_Seek, have_SDL_sound_seek=yes,,) +if test x$have_SDL_sound_h = xyes -a x$have_SDL_sound_init = xyes ; then + if test x$have_SDL_sound_seek = xyes ; then + LIBS="-lSDL_sound $LIBS" + AC_DEFINE(C_SDL_SOUND,1) + else + AC_MSG_WARN([Can't find SoundSeek in libSDL_Sound, libSDL_sound support disabled]) + fi +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([ +#include +int main(int argc,char * argv[]) { + return setpriority (PRIO_PROCESS, 0,PRIO_MIN+PRIO_MAX); +}; +],AC_MSG_RESULT(yes);AC_DEFINE(C_SET_PRIORITY,1),AC_MSG_RESULT(no)) + + +dnl Some target detection and actions for them +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, Posix and OS/2 only).]) + if test x$have_sdl_net_lib = xyes -a x$have_sdl_net_h = xyes ; then + LIBS="$LIBS -lws2_32" + fi + ;; + *-*-darwin*) + dnl We have a problem here: both Mac OS X and Darwin report + dnl the same signature "powerpc-apple-darwin*" - so we have + dnl to do more to distinguish them. + dnl For now I am lazy and do not add proper detection code. + AC_DEFINE(MACOSX, 1, [Compiling on Mac OS X]) + LIBS="$LIBS -framework CoreMIDI -framework AudioUnit -framework AudioToolbox" + AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2).]) + ;; + *-*-linux*) + AC_DEFINE(LINUX, 1, [Compiling on GNU/Linux]) + AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2).]) + ;; + *-*-freebsd* | *-*-dragonfly* | *-*-netbsd* | *-*-openbsd*) + dnl Disabled directserial for now. It doesn't do anything without + dnl specifying an extra ifdef in directserial_posix.* + dnl directserial detection should be rewritten to test for the needed + dnl functions and headers. I currently do not know + dnl which ones are needed for BSD + AC_DEFINE(BSD, 1, [Compiling on BSD]) + AC_DEFINE(C_DIRECTSERIAL, 1, [ Define to 1 if you want serial passthrough support (Win32, Posix and OS/2).]) + ;; + *-*-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, Posix and OS/2).]) + ;; +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_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/cpu/core_dynrec/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/libs/gui_tk/Makefile +src/misc/Makefile +src/shell/Makefile +src/platform/Makefile +src/platform/visualc/Makefile +visualc_net/Makefile +include/Makefile +docs/Makefile +]) +AC_OUTPUT diff --git a/docs/PORTING b/docs/PORTING index 560e5d1..4a47607 100644 --- a/docs/PORTING +++ b/docs/PORTING @@ -1,50 +1,50 @@ -Some notes about porting DOSBox to systems with certain restrictions, -like handheld devices. - -General: - - depending on where you start off with the port, assure that the - config.h entries are correct/exhausting, like GCC_ATTRIBUTE is - required (struct packing) but is undefined if you base the port - on msvc sources which have a special config.h - -If memory is a constraint: - - in paging.h out-comment the USE_FULL_TLB define to enable special - TLB linking code that uses less memory - drawback: none (the code is not heavily tested though) - gain: reduces memory requirements about ~15mb - - in render.h lower the scaler integration: - #define RENDER_USE_ADVANCED_SCALERS 1 - or - #define RENDER_USE_ADVANCED_SCALERS 0 - drawback: complex scalers and the scaler cache are disabled, - be sure to test if this affects speed! - with define RENDER_USE_ADVANCED_SCALERS==0 most simple - scalers are disabled as well, some graphics modes won't - work due to reduced cache sizes - gain: ~2mb with RENDER_USE_ADVANCED_SCALERS==1 - ~5mb with RENDER_USE_ADVANCED_SCALERS==0 - - in dos_system.h reduce the drive cache entries: - #define MAX_OPENDIRS 256 - drawback: some apps might not work with large directory trees - gain: ~1mb per mounted drive - - remove the GUS emulation (gus.cpp, especially GUSRam[1024*1024] ) - drawback: no gravis ultrasound - gain: reduces memory requirements about 1mb - - reduce the size of the emulated graphics memory: - see the memory sizing in SVGA_Setup_*, especially the defaults - in vga_s3.cpp's SVGA_Setup_S3Trio - drawback: some graphics modes won't work then - gain: reduces memory requirements - TODO: fully check this, introduce hard limits - -If speed is a constraint: - - see if the simple core is faster, possibly remove the normal core - set the simple core as default - drawback: one game is known to not work with the simple core; - the simple core does only work for games which don't use paging - (when paging is requested the normal core is used automatically) - gain: the simple core should be somewhat faster - TODO: add possibility to easily remove the normal core, use fullcore fallback - - raise the default frameskip value - drawback: minor graphics smoothness loss for some games (video playback) - gain: reduces graphics load +Some notes about porting DOSBox to systems with certain restrictions, +like handheld devices. + +General: + - depending on where you start off with the port, assure that the + config.h entries are correct/exhausting, like GCC_ATTRIBUTE is + required (struct packing) but is undefined if you base the port + on msvc sources which have a special config.h + +If memory is a constraint: + - in paging.h out-comment the USE_FULL_TLB define to enable special + TLB linking code that uses less memory + drawback: none (the code is not heavily tested though) + gain: reduces memory requirements about ~15mb + - in render.h lower the scaler integration: + #define RENDER_USE_ADVANCED_SCALERS 1 + or + #define RENDER_USE_ADVANCED_SCALERS 0 + drawback: complex scalers and the scaler cache are disabled, + be sure to test if this affects speed! + with define RENDER_USE_ADVANCED_SCALERS==0 most simple + scalers are disabled as well, some graphics modes won't + work due to reduced cache sizes + gain: ~2mb with RENDER_USE_ADVANCED_SCALERS==1 + ~5mb with RENDER_USE_ADVANCED_SCALERS==0 + - in dos_system.h reduce the drive cache entries: + #define MAX_OPENDIRS 256 + drawback: some apps might not work with large directory trees + gain: ~1mb per mounted drive + - remove the GUS emulation (gus.cpp, especially GUSRam[1024*1024] ) + drawback: no gravis ultrasound + gain: reduces memory requirements about 1mb + - reduce the size of the emulated graphics memory: + see the memory sizing in SVGA_Setup_*, especially the defaults + in vga_s3.cpp's SVGA_Setup_S3Trio + drawback: some graphics modes won't work then + gain: reduces memory requirements + TODO: fully check this, introduce hard limits + +If speed is a constraint: + - see if the simple core is faster, possibly remove the normal core + set the simple core as default + drawback: one game is known to not work with the simple core; + the simple core does only work for games which don't use paging + (when paging is requested the normal core is used automatically) + gain: the simple core should be somewhat faster + TODO: add possibility to easily remove the normal core, use fullcore fallback + - raise the default frameskip value + drawback: minor graphics smoothness loss for some games (video playback) + gain: reduces graphics load diff --git a/docs/README.video b/docs/README.video index 5b4f665..1d15b4f 100644 --- a/docs/README.video +++ b/docs/README.video @@ -1,35 +1,35 @@ -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. - -Q: The colours are wrong and I'm using 64 bit windows -A: Look here: http://vogons.zetafleet.com/viewtopic.php?t=12133 +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. + +Q: The colours are wrong and I'm using 64 bit windows +A: Look here: http://vogons.zetafleet.com/viewtopic.php?t=12133 diff --git a/docs/dosbox.1 b/docs/dosbox.1 index 57781b5..edef4bc 100644 --- a/docs/dosbox.1 +++ b/docs/dosbox.1 @@ -1,361 +1,363 @@ -.\" Hey, EMACS: -*- nroff -*- -.TH DOSBOX 1 "May 27, 2009" -.\" Please adjust this date whenever revising the manpage. -.SH NAME -dosbox \- an x86/DOS emulator with sound/graphics -.SH SYNOPSIS -.B dosbox -.B [\-fullscreen] -.B [\-startmapper] -.B [\-noautoexec] -.B [\-securemode] -.BI "[\-scaler " scaler ] -.BI "[\-forcescaler " scaler ] -.BI "[\-conf " configfile ] -.BI "[\-lang " langfile ] -.B [file] -.BI "[\-c " command ] -.B [\-exit] -.BI "[\-machine " machinetype ] -.LP -.B dosbox \-version -.LP -.BI "dosbox \-editconf" " program" -.LP -.BI "dosbox \-opencaptures" " program" -.LP -.B dosbox \-printconf -.LP -.B dosbox \-eraseconf -.SH DESCRIPTION -This manual page briefly documents -.BR "dosbox" ", an x86/DOS emulator." -.LP -.RB "The optional " file " argument should be a DOS executable or a" -directory. If it is a dos executable (.com .exe .bat) the program will -run automatically. If it is a directory, a DOS session will run with -the directory mounted as C:\\. -.LP -.RI "For an introduction type " INTRO -.RB "inside " dosbox . -.SH OPTIONS -A summary of options is included below. -.TP -.B \-fullscreen -.RB "Start " dosbox " in fullscreen mode." -.TP -.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 -.B \-securemode -.RB "Same as " \-noautoexec ", but adds " "config.com \-securemode" -at the end of -.I AUTOEXEC.BAT -(which in turn disables any changes to how the drives are mounted -.RB "inside " dosbox ) -.TP -.BI \-scaler " scaler" -.RI "Uses the graphical scaler specified by " scaler ". See the configuration" -file for the available scalers -.TP -.BI \-forcescaler " scaler" -.RB "Similar to the " \-scaler " parameter, but tries to force usage of" -the specified scaler even if it might not fit. -.TP -.BI \-c " command" -.RI "Runs the specified " command " before running " -.BR file . -.RI "Multiple commands can be specified. Each " command " should start with " -.BR \-c " though. A command can be:" -an Internal Program, a DOS command or an executable on a mounted drive. -.TP -.BI \-conf " configfile -.RB "Start " dosbox " with the options specified in " -.IR configfile ". This file has a section in which you can put commands you " -wish to execute on startup. Multiple -.IR configfiles " can be present at the commandline." -.TP -.BI \-lang " langfile -.RB "Start " dosbox " with the language specified in " -.IR langfile . -.TP -.B "\-exit " -.BR "dosbox" " will close itself when the DOS program specified by "file " ends." -.TP -.BI \-machine " machinetype -.RB "Setup " dosbox " to emulate a specific type of machine." -.RI "Valid choices are: " "hercules, cga, tandy, pcjr, ega, vgaonly, svga_s3(default), svga_et3000, svga_et4000, svga_paradise, vesa_nolfb, vesa_oldvbe". -The machinetype has influence on both the videocard and the available -soundcards. -.TP -.B \-version -Output version information and exit. Useful for frontends. -.TP -.BI \-editconf " program" -.RI calls " program" " with as first parameter the configuration file." -.R You can specify this command more than once. In this case it will -.RI " move to second " program " if the first one fails to start." -.TP -.BI \-opencaptures " program" -.RI "calls " program " with as first paramater the location of the captures folder." -.TP -.B \-printconf -.R prints the location of the default configuration file. -.TP -.B \-eraseconf -.R removes the default configuration file. -.SH "INTERNAL COMMANDS" -.B dosbox -supports most of the DOS commands found in command.com. In addition, the -following extra commands are available: -.HP -.BI "MOUNT [\-t " type "] [\-size " size ] -.I driveletter sourcedirectory -.B [\-ioctl] -.BI "[\-usecd " number "] [\-label " drivelabel "] [\-freesize " freesize ] -.LP -.B MOUNT \-cd -.LP -.B MOUNT \-u driveletter -.LP -.RB "Program to mount local directories as drives inside " dosbox . -.RS -.TP -.I driveletter -The driveletter inside dosbox (eg. C). -.TP -.I sourcedirectory -The local directory you want to have inside dosbox. -.TP -.BI \-t " type" -Type of the mounted directory. Supported are: dir (standard), floppy, cdrom. -.TP -.BI \-size " drivesize" -Sets the size of the drive. See the examples in the README for details. -.TP -.BI \-freesize " size_in_mb" -Sets the amount of free space available on a drive in MB's. This is a more -.RB "simple version of " \-size . -.TP -.BI \-label " drivelabel" -.RI "Sets the name of the drive to " drivelabel ". Needed on some" -systems if the cd label isn't read correctly. Useful when a -program can't find its cdrom. If you don't specify a label and no -.RB "lowlevel support is selected (" "\-usecd #" " and/or " "\-ioctl/aspi" "):" -.RS -.LP -For win32: label is extracted from "Real Drive". -.TP -For Linux: label is set to NO_LABEL. -.TP -If you do specify a label this label will be kept as long as the drive -is mounted. It will not be updated !! -.RE -.TP -.B \-ioctl -Forces to use ioctl commands. -.TP -.BI \-usecd " number" -Forces to use SDL cdrom support for drive number. -.IR Number " can be found by " -.BR \-cd ". -.TP -.B \-cd -.RB "Displays all detected cdrom drives and their numbers. Use with " \-usecd "." -.TP -.B \-u -Unmounts a mounted drive. Doesn't work on virtual Drives (like Z:\\) -.RE -.PP -.B "Example:" -.TP -.RB "To mount your /home/dos/dosgames directory as C drive in " dosbox : -.RS -mount c /home/dos/dosgames -.RE -.TP -.B MEM -.LP -Display the amount of free memory -.TP -.B CONFIG [\-writeconf] [\-writelang] file -.LP -.B CONFIG -securemode -.LP -.RB "Write the current configuration or language settings to " file , -which is located on the local filesystem. Not a mounted drive in -.BR dosbox . -.TP -.B \-securemode -.RB Switches dosbox " to a more secure mode. In this mode the" -.RI "internal commands " MOUNT ", " IMGMOUNT " and " BOOT " won\'t work." -It\'s not possible -either to create a new configfile or languagefile in this mode. -(Warning you can only undo this mode by restarting -.BR dosbox .) -.LP -The configuration file controls various settings of -.BR dosbox ": The amount of emulated memory," -the emulated soundcards and many -.RI "more things. It futher allows acces to " AUTOEXEC.BAT . -.LP -The language file controls all visible ouput of the internal commands and -the internal dos. -.RB "See the section " FILES " for more information." -.TP -.B LOADFIX [\-size] [programname] [parameters] -.LP -.B LOADFIX \-f -.LP -Program to reduce the amount of memory available. Useful for old programs which don't expect much memory to be free. -.RS -.TP -.B [programname] -The name of the program which is executed after loadfix eats up its memory. -.TP -.B [parameters] -.RB "Parameters given to the " programname " executable." -.TP -.B \-size -The amount of memory to eat up (in kb). Example -32, -64 or -128 -.TP -.B \-f -Frees all memory eaten up by loadfix. -.RE -.TP -.B RESCAN -.LP -.RB "Make " dosbox " reread the directory structure. Useful if you changed -.RB "something on a mounted drive outside " dosbox ".(CTRL\-F4 does" -this as well!) -.TP -.B IMGMOUNT -.LP -.RB "A utility to mount disk images and CD-ROM images in " dosbox . -.TP -.RB "Read the " README " of " dosbox " for the full and correct syntax." -.RE -.TP -.B BOOT -.LP -Boot will start floppy images or hard disk images independent of the -.RB "operating system emulation offered by " dosbox ". This will allow you to play booter floppies or boot to other operating systems inside " dosbox . -.TP -.RB "Read the " README " of " dosbox " for the full and correct syntax." -.RE -.TP -.B IPX -.LP -.RB "You need to enable IPX networking in the configuration file of " dosbox . -.RB "All of the IPX networking is managed through the internal " dosbox " program -.BR IPXNET ". For help on the IPX networking from inside " dosbox ", type" -.BR "IPXNET HELP" " and the program will list out the commands and relevant documentation." -.TP -.RB "Read the " README " of " dosbox " for the full and correct syntax." -.RE -.TP -.B KEYB -.LP -Keyb can change the keyboardlayout and the codepage used inside dosbox. -.TP -.RB "Read the " README " of " dosbox " for the full and correct syntax." -.RE -.SH FILES -Configuration and language files use a format similar to Windows .ini files. -If no configfile is specified at the commandline, a file named -.BR dosbox.conf " (if present in the current directory) will be" -loaded automatically. If a configfile is specified at the commandline -that one will be used instead. If no configfile is specified or found -in the current directory -.RB " then dosbox will load one from " ~/.dosbox/ ". It will try to create " -one if there is none. -.SH "SPECIAL KEYS" -.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! -.IP CTRL\-F5 -Save a screenshot.(png) -.IP CTRL\-F6 -Start/Stop recording sound output to a wave file. -.IP CTRL\-ALT\-F7 -Start/Stop recording of OPL commands. -.IP CTRL\-ALT\-F8 -Start/Stop the recording of raw MIDI commands. -.IP CTRL\-F7 -Decrease frameskip. -.IP CTRL\-F8 -Increase frameskip. -.IP CTRL\-F9 -Kill dosbox. -.IP CTRL\-F10 -Capture/Release the mouse. -.IP CTRL\-F11 -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 -Saved/recorded files can be found in current_directory/capture -(can be changed in the configfile). -.RB "The directory has to exist prior to starting " dosbox " else nothing" -gets saved/recorded ! -.PP -.BR "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. -.SH "SYSTEM REQUIREMENTS" -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 -it up somewhat. -.SS "To run resource\-demanding games" -.BR dosbox " emulates the CPU, the sound and graphic cards, and some other" -.RB " 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 various utils (top). Once 100% of your real CPU time is -.RB "used there is no further way to speed up " dosbox " unless you reduce the load" -.RB "generated by the non\-CPU parts of " dosbox . -.PP -So: -.PP -.RB "Close every program but " dosbox . -.PP -.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 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. -.SH NOTES -.RB "While we hope that, one day, " dosbox " will run virtually all programs ever made for the PC..." -.RB "we are not there yet. At present, " dosbox " run on a 1.7 Gigahertz PC is roughly the equivalent of a 25MHz 386 PC." -While 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 -.RB "require a much faster processor for you to run it properly in " dosbox . -.SH BUGS -Not all DOS programs work properly. -.BR dosbox " will exit without warning if an error occurred." -.SH "SEE ALSO" -The README in /usr/share/doc/dosbox -.SH AUTHOR -This manual page was written by Peter Veenstra and James Oakley , -for the Debian system (but may be used by others). +.\" Hey, EMACS: -*- nroff -*- +.TH DOSBOX 1 "May 27, 2009" +.\" Please adjust this date whenever revising the manpage. +.SH NAME +dosbox \- an x86/DOS emulator with sound/graphics +.SH SYNOPSIS +.B dosbox +.B [\-fullscreen] +.B [\-startmapper] +.B [\-noautoexec] +.B [\-securemode] +.BI "[\-scaler " scaler ] +.BI "[\-forcescaler " scaler ] +.BI "[\-conf " configfile ] +.BI "[\-lang " langfile ] +.B [file] +.BI "[\-c " command ] +.B [\-exit] +.BI "[\-machine " machinetype ] +.LP +.B dosbox \-version +.LP +.BI "dosbox \-editconf" " program" +.LP +.BI "dosbox \-opencaptures" " program" +.LP +.B dosbox \-printconf +.LP +.B dosbox \-eraseconf +.SH DESCRIPTION +This manual page briefly documents +.BR "dosbox" ", an x86/DOS emulator." +.LP +.RB "The optional " file " argument should be a DOS executable or a" +directory. If it is a dos executable (.com .exe .bat) the program will +run automatically. If it is a directory, a DOS session will run with +the directory mounted as C:\\. +.LP +.RI "For an introduction type " INTRO +.RB "inside " dosbox . +.SH OPTIONS +A summary of options is included below. +.TP +.B \-fullscreen +.RB "Start " dosbox " in fullscreen mode." +.TP +.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 +.B \-securemode +.RB "Same as " \-noautoexec ", but adds " "config.com \-securemode" +at the end of +.I AUTOEXEC.BAT +(which in turn disables any changes to how the drives are mounted +.RB "inside " dosbox ) +.TP +.BI \-scaler " scaler" +.RI "Uses the graphical scaler specified by " scaler ". See the configuration" +file for the available scalers +.TP +.BI \-forcescaler " scaler" +.RB "Similar to the " \-scaler " parameter, but tries to force usage of" +the specified scaler even if it might not fit. +.TP +.BI \-c " command" +.RI "Runs the specified " command " before running " +.BR file . +.RI "Multiple commands can be specified. Each " command " should start with " +.BR \-c " though. A command can be:" +an Internal Program, a DOS command or an executable on a mounted drive. +.TP +.BI \-conf " configfile +.RB "Start " dosbox " with the options specified in " +.IR configfile ". This file has a section in which you can put commands you " +wish to execute on startup. Multiple +.IR configfiles " can be present at the commandline." +.TP +.BI \-lang " langfile +.RB "Start " dosbox " with the language specified in " +.IR langfile . +.TP +.B "\-exit " +.BR "dosbox" " will close itself when the DOS program specified by "file " ends." +.TP +.BI \-machine " machinetype +.RB "Setup " dosbox " to emulate a specific type of machine." +.RI "Valid choices are: " "hercules, cga, tandy, pcjr, ega, vgaonly, svga_s3(default), svga_et3000, svga_et4000, svga_paradise, vesa_nolfb, vesa_oldvbe". +The machinetype has influence on both the videocard and the available +soundcards. +.TP +.B \-version +Output version information and exit. Useful for frontends. +.TP +.BI \-editconf " program" +.RI calls " program" " with as first parameter the configuration file." +You can specify this command more than once. In this case it will +.RI " move to second " program " if the first one fails to start." +.TP +.BI \-opencaptures " program" +.RI "calls " program " with as first paramater the location of the captures folder." +.TP +.B \-printconf +prints the location of the default configuration file. +.TP +.B \-eraseconf +removes the default configuration file. +.SH "INTERNAL COMMANDS" +.B dosbox +supports most of the DOS commands found in command.com. In addition, the +following extra commands are available: +.HP +.BI "MOUNT [\-t " type "] [\-size " size ] +.I driveletter sourcedirectory +.B [\-ioctl] +.BI "[\-usecd " number "] [\-label " drivelabel "] [\-freesize " freesize ] +.LP +.B MOUNT \-cd +.LP +.B MOUNT \-u driveletter +.LP +.RB "Program to mount local directories as drives inside " dosbox . +.RS +.TP +.I driveletter +The driveletter inside dosbox (eg. C). +.TP +.I sourcedirectory +The local directory you want to have inside dosbox. +.TP +.BI \-t " type" +Type of the mounted directory. Supported are: dir (standard), floppy, cdrom. +.TP +.BI \-size " drivesize" +Sets the size of the drive. See the examples in the README for details. +.TP +.BI \-freesize " size_in_mb" +Sets the amount of free space available on a drive in MB's. This is a more +.RB "simple version of " \-size . +.TP +.BI \-label " drivelabel" +.RI "Sets the name of the drive to " drivelabel ". Needed on some" +systems if the cd label isn't read correctly. Useful when a +program can't find its cdrom. If you don't specify a label and no +.RB "lowlevel support is selected (" "\-usecd #" " and/or " "\-ioctl/aspi" "):" +.RS +.LP +For win32: label is extracted from "Real Drive". +.TP +For Linux: label is set to NO_LABEL. +.TP +If you do specify a label this label will be kept as long as the drive +is mounted. It will not be updated !! +.RE +.TP +.B \-ioctl +Forces to use ioctl commands. +.TP +.BI \-usecd " number" +Forces to use SDL cdrom support for drive number. +.IR Number " can be found by " +.BR \-cd ". +.TP +.B \-cd +.RB "Displays all detected cdrom drives and their numbers. Use with " \-usecd "." +.TP +.B \-u +Unmounts a mounted drive. Doesn't work on virtual Drives (like Z:\\) +.RE +.PP +.B "Example:" +.TP +.RB "To mount your /home/dos/dosgames directory as C drive in " dosbox : +.RS +mount c /home/dos/dosgames +.RE +.TP +.B MEM +.LP +Display the amount of free memory +.TP +.B CONFIG [\-writeconf] [\-writelang] file +.LP +.B CONFIG \-securemode +.LP +.RB "Write the current configuration or language settings to " file , +which is located on the local filesystem. Not a mounted drive in +.BR dosbox . +.RS +.TP +.B \-securemode +.RB Switches dosbox " to a more secure mode. In this mode the" +.RI "internal commands " MOUNT ", " IMGMOUNT " and " BOOT " won\'t work." +It\'s not possible +either to create a new configfile or languagefile in this mode. +(Warning you can only undo this mode by restarting +.BR dosbox .) +.RE +.LP +The configuration file controls various settings of +.BR dosbox ": The amount of emulated memory," +the emulated soundcards and many +.RI "more things. It futher allows acces to " AUTOEXEC.BAT . +.LP +The language file controls all visible ouput of the internal commands and +the internal dos. +.RB "See the section " FILES " for more information." +.TP +.B LOADFIX [\-size] [programname] [parameters] +.LP +.B LOADFIX \-f +.LP +Program to reduce the amount of memory available. Useful for old programs which don't expect much memory to be free. +.RS +.TP +.B [programname] +The name of the program which is executed after loadfix eats up its memory. +.TP +.B [parameters] +.RB "Parameters given to the " programname " executable." +.TP +.B \-size +The amount of memory to eat up (in kb). Example \-32, \-64 or \-128 +.TP +.B \-f +Frees all memory eaten up by loadfix. +.RE +.TP +.B RESCAN +.LP +.RB "Make " dosbox " reread the directory structure. Useful if you changed +.RB "something on a mounted drive outside " dosbox ".(CTRL\-F4 does" +this as well!) +.TP +.B IMGMOUNT +.LP +.RB "A utility to mount disk images and CD\(hyROM images in " dosbox . +.TP +.RB "Read the " README " of " dosbox " for the full and correct syntax." +.RE +.TP +.B BOOT +.LP +Boot will start floppy images or hard disk images independent of the +.RB "operating system emulation offered by " dosbox ". This will allow you to play booter floppies or boot to other operating systems inside " dosbox . +.TP +.RB "Read the " README " of " dosbox " for the full and correct syntax." +.RE +.TP +.B IPX +.LP +.RB "You need to enable IPX networking in the configuration file of " dosbox . +.RB "All of the IPX networking is managed through the internal " dosbox " program +.BR IPXNET ". For help on the IPX networking from inside " dosbox ", type" +.BR "IPXNET HELP" " and the program will list out the commands and relevant documentation." +.TP +.RB "Read the " README " of " dosbox " for the full and correct syntax." +.RE +.TP +.B KEYB +.LP +Keyb can change the keyboardlayout and the codepage used inside dosbox. +.TP +.RB "Read the " README " of " dosbox " for the full and correct syntax." +.RE +.SH FILES +Configuration and language files use a format similar to Windows .ini files. +If no configfile is specified at the commandline, a file named +.BR dosbox.conf " (if present in the current directory) will be" +loaded automatically. If a configfile is specified at the commandline +that one will be used instead. If no configfile is specified or found +in the current directory +.RB " then dosbox will load one from " ~/.dosbox/ ". It will try to create " +one if there is none. +.SH "SPECIAL KEYS" +.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\(hyimage (Only used with imgmount). Update directory cache +for all drives! +.IP CTRL\-F5 +Save a screenshot.(png) +.IP CTRL\-F6 +Start/Stop recording sound output to a wave file. +.IP CTRL\-ALT\-F7 +Start/Stop recording of OPL commands. +.IP CTRL\-ALT\-F8 +Start/Stop the recording of raw MIDI commands. +.IP CTRL\-F7 +Decrease frameskip. +.IP CTRL\-F8 +Increase frameskip. +.IP CTRL\-F9 +Kill dosbox. +.IP CTRL\-F10 +Capture/Release the mouse. +.IP CTRL\-F11 +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 +Saved/recorded files can be found in current_directory/capture +(can be changed in the configfile). +.RB "The directory has to exist prior to starting " dosbox " else nothing" +gets saved/recorded ! +.PP +.BR "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. +.SH "SYSTEM REQUIREMENTS" +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 +it up somewhat. +.SS "To run resource\-demanding games" +.BR dosbox " emulates the CPU, the sound and graphic cards, and some other" +.RB " 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 various utils (top). Once 100% of your real CPU time is +.RB "used there is no further way to speed up " dosbox " unless you reduce the load" +.RB "generated by the non\-CPU parts of " dosbox . +.PP +So: +.PP +.RB "Close every program but " dosbox . +.PP +.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 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. +.SH NOTES +.RB "While we hope that, one day, " dosbox " will run virtually all programs ever made for the PC..." +.RB "we are not there yet. At present, " dosbox " run on a 1.7 Gigahertz PC is roughly the equivalent of a 25MHz 386 PC." +While 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 +.RB "require a much faster processor for you to run it properly in " dosbox . +.SH BUGS +Not all DOS programs work properly. +.BR dosbox " will exit without warning if an error occurred." +.SH "SEE ALSO" +The README in /usr/share/doc/dosbox +.SH AUTHOR +This manual page was written by Peter Veenstra and James Oakley , +for the Debian system (but may be used by others). diff --git a/include/bios.h b/include/bios.h index 87696b6..8f722d6 100644 --- a/include/bios.h +++ b/include/bios.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/bios_disk.h b/include/bios_disk.h index 3a77ea5..861d96e 100644 --- a/include/bios_disk.h +++ b/include/bios_disk.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/callback.h b/include/callback.h index d1240ee..c4e6fa6 100644 --- a/include/callback.h +++ b/include/callback.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/control.h b/include/control.h index 427fc6d..0a688e1 100644 --- a/include/control.h +++ b/include/control.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/cpu.h b/include/cpu.h index a10291b..d18caa2 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/cross.h b/include/cross.h index 6a558e6..8628beb 100644 --- a/include/cross.h +++ b/include/cross.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/debug.h b/include/debug.h index 89378c7..d068492 100644 --- a/include/debug.h +++ b/include/debug.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/dma.h b/include/dma.h index 775f9d2..a12615d 100644 --- a/include/dma.h +++ b/include/dma.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/dos_inc.h b/include/dos_inc.h index c76ba88..290d76b 100644 --- a/include/dos_inc.h +++ b/include/dos_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/dos_system.h b/include/dos_system.h index e530cde..5edb048 100644 --- a/include/dos_system.h +++ b/include/dos_system.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -141,8 +141,8 @@ public: char* GetExpandName (const char* path); bool GetShortName (const char* fullname, char* shortname); - bool FindFirst (char* path, Bitu& id); - bool FindNext (Bitu id, char* &result); + bool FindFirst (char* path, Bit16u& id); + bool FindNext (Bit16u id, char* &result); void CacheOut (const char* path, bool ignoreLastDir = false); void AddEntry (const char* path, bool checkExist = false); @@ -205,7 +205,7 @@ private: char dirSearchName [MAX_OPENDIRS]; bool free [MAX_OPENDIRS]; CFileInfo* dirFindFirst [MAX_OPENDIRS]; - Bitu nextFreeFindFirst; + Bit16u nextFreeFindFirst; char label [CROSS_LEN]; bool updatelabel; diff --git a/include/dosbox.h b/include/dosbox.h index 743de58..c46cf0a 100644 --- a/include/dosbox.h +++ b/include/dosbox.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/fpu.h b/include/fpu.h index b5e3b2d..67f7db4 100644 --- a/include/fpu.h +++ b/include/fpu.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/hardware.h b/include/hardware.h index 4a44085..d7da348 100644 --- a/include/hardware.h +++ b/include/hardware.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/inout.h b/include/inout.h index 4943435..798e9db 100644 --- a/include/inout.h +++ b/include/inout.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/ipx.h b/include/ipx.h index f8e434d..27c984f 100644 --- a/include/ipx.h +++ b/include/ipx.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/ipxserver.h b/include/ipxserver.h index 6ed39b7..e31c175 100644 --- a/include/ipxserver.h +++ b/include/ipxserver.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/joystick.h b/include/joystick.h index 5d4575b..fe39e5e 100644 --- a/include/joystick.h +++ b/include/joystick.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/keyboard.h b/include/keyboard.h index bb62cab..0e60f29 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/mapper.h b/include/mapper.h index bf329cb..932f656 100644 --- a/include/mapper.h +++ b/include/mapper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/mem.h b/include/mem.h index 8b24762..73686ae 100644 --- a/include/mem.h +++ b/include/mem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/mixer.h b/include/mixer.h index a31b549..b9ca882 100644 --- a/include/mixer.h +++ b/include/mixer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/mouse.h b/include/mouse.h index 218a444..74ff010 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/paging.h b/include/paging.h index 900c039..5c4e974 100644 --- a/include/paging.h +++ b/include/paging.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/pic.h b/include/pic.h index e104ec4..8b6e2f4 100644 --- a/include/pic.h +++ b/include/pic.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/programs.h b/include/programs.h index e92fdb3..f847385 100644 --- a/include/programs.h +++ b/include/programs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/regs.h b/include/regs.h index 2f37b1c..13da923 100644 --- a/include/regs.h +++ b/include/regs.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/render.h b/include/render.h index ee3db59..bbfd90e 100644 --- a/include/render.h +++ b/include/render.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/serialport.h b/include/serialport.h index 5879a44..aa2446a 100644 --- a/include/serialport.h +++ b/include/serialport.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -100,8 +100,9 @@ public: Bit8u getb() { if (!used) return data[pos]; Bitu where=pos; - if (++pos>=size) pos-=size; used--; + if(used) pos++; + if (pos>=size) pos-=size; return data[where]; } Bit8u getTop() { diff --git a/include/setup.h b/include/setup.h index a80041b..5a0d605 100644 --- a/include/setup.h +++ b/include/setup.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/shell.h b/include/shell.h index 7bce84d..7d1f3c0 100644 --- a/include/shell.h +++ b/include/shell.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/support.h b/include/support.h index 9b7e702..32e1e20 100644 --- a/include/support.h +++ b/include/support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/timer.h b/include/timer.h index 495381f..b4be740 100644 --- a/include/timer.h +++ b/include/timer.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/vga.h b/include/vga.h index 8d8a3bc..55abf2f 100644 --- a/include/vga.h +++ b/include/vga.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/include/video.h b/include/video.h index 4b57e0e..7c7af5e 100644 --- a/include/video.h +++ b/include/video.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/scripts/dosbox-installer.nsi b/scripts/dosbox-installer.nsi index b3731ac..629bca5 100644 --- a/scripts/dosbox-installer.nsi +++ b/scripts/dosbox-installer.nsi @@ -1,157 +1,157 @@ -!define VER_MAYOR 0 -!define VER_MINOR 73 -!define APP_NAME "DOSBox ${VER_MAYOR}.${VER_MINOR} Installer" -!define COMP_NAME "DOSBox Team" -!define COPYRIGHT "Copyright © 2002-2009 DOSBox Team" -!define DESCRIPTION "DOSBox Installer" - -VIProductVersion "${VER_MAYOR}.${VER_MINOR}.0.0" -VIAddVersionKey "ProductName" "${APP_NAME}" -VIAddVersionKey "CompanyName" "${COMP_NAME}" -VIAddVersionKey "FileDescription" "${DESCRIPTION}" -VIAddVersionKey "FileVersion" "${VER_MAYOR}.${VER_MINOR}.0.0" -VIAddVersionKey "ProductVersion" "${VER_MAYOR}, ${VER_MINOR}, 0, 0" -VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" - -; The name of the installer -Name "${APP_NAME}" - -; The file to write -OutFile "DOSBox${VER_MAYOR}.${VER_MINOR}-win32-installer.exe" - -; The default installation directory -InstallDir "$PROGRAMFILES\DOSBox-${VER_MAYOR}.${VER_MINOR}" - -; The text to prompt the user to enter a directory -DirText "This will install DOSBox v${VER_MAYOR}.${VER_MINOR} on your computer. Choose a directory" -SetCompressor /solid lzma - - -LicenseData COPYING -LicenseText "DOSBox v${VER_MAYOR}.${VER_MINOR} License" "Next >" - -; Else vista enables compatibility mode -RequestExecutionLevel admin -; Shortcuts in all users - -ComponentText "Select components for DOSBox" -; The stuff to install -Section "!Core files" Core -SetShellVarContext all - - ; Set output path to the installation directory. - ClearErrors - SetOutPath $INSTDIR - IfErrors error_createdir - SectionIn RO - - ; Put file there - - CreateDirectory "$INSTDIR\zmbv" - File /oname=README.txt README - File /oname=COPYING.txt COPYING - File /oname=THANKS.txt THANKS - File /oname=NEWS.txt NEWS - File /oname=AUTHORS.txt AUTHORS - File /oname=INSTALL.txt INSTALL - File DOSBox.exe - File SDL.dll - File SDL_net.dll - File /oname=zmbv\zmbv.dll zmbv.dll - File /oname=zmbv\zmbv.inf zmbv.inf - File /oname=zmbv\README.txt README.video - - CreateDirectory "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}" - CreateDirectory "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video" - CreateDirectory "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration" - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox.lnk" "$INSTDIR\DOSBox.exe" "" "$INSTDIR\DOSBox.exe" 0 - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox (noconsole).lnk" "$INSTDIR\DOSBox.exe" "-noconsole" "$INSTDIR\DOSBox.exe" 0 - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\README.lnk" "$INSTDIR\README.txt" - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Edit Configuration.lnk" "$INSTDIR\DOSBox.exe" "-editconf notepad.exe -editconf $\"%SystemRoot%\system32\notepad.exe$\" -editconf $\"%WINDIR%\notepad.exe$\"" - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Reset Configuration.lnk" "$INSTDIR\DOSBox.exe" "-eraseconf" - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Capture folder.lnk" "$INSTDIR\DOSBox.exe" "-opencaptures explorer.exe" - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Video instructions.lnk" "$INSTDIR\zmbv\README.txt" -;change outpath so the working directory gets set to zmbv -SetOutPath "$INSTDIR\zmbv" - ; Shortcut creation depends on wether we are 9x of NT - ClearErrors - ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion - IfErrors we_9x we_nt -we_nt: - ;shortcut for win NT - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Install movie codec.lnk" "rundll32" "setupapi,InstallHinfSection DefaultInstall 128 $INSTDIR\zmbv\zmbv.inf" - goto end -we_9x: - ;shortcut for we_9x - CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Install movie codec.lnk" "rundll" "setupx.dll,InstallHinfSection DefaultInstall 128 $INSTDIR\zmbv\zmbv.inf" -end: -SetOutPath $INSTDIR -WriteUninstaller "uninstall.exe" - - goto end_section - -error_createdir: - MessageBox MB_OK "Can't create DOSBox program directory, aborting." - Abort - goto end_section - -end_section: -SectionEnd ; end the section - -Section "Desktop Shortcut" SecDesktop -SetShellVarContext all - -CreateShortCut "$DESKTOP\DOSBox ${VER_MAYOR}.${VER_MINOR}.lnk" "$INSTDIR\DOSBox.exe" "" "$INSTDIR\DOSBox.exe" 0 - - SectionEnd ; end the section - - -UninstallText "This will uninstall DOSBox v${VER_MAYOR}.${VER_MINOR}. Hit next to continue." - -Section "Uninstall" - -; Shortcuts in all users -SetShellVarContext all - - Delete "$DESKTOP\DOSBox ${VER_MAYOR}.${VER_MINOR}.lnk" - ; remove registry keys - ; remove files - Delete $INSTDIR\README.txt - Delete $INSTDIR\COPYING.txt - Delete $INSTDIR\THANKS.txt - Delete $INSTDIR\NEWS.txt - Delete $INSTDIR\AUTHORS.txt - Delete $INSTDIR\INSTALL.txt - Delete $INSTDIR\DOSBox.exe - Delete $INSTDIR\SDL.dll - Delete $INSTDIR\SDL_net.dll - Delete $INSTDIR\zmbv\zmbv.dll - Delete $INSTDIR\zmbv\zmbv.inf - Delete $INSTDIR\zmbv\README.txt - ;Files left by sdl taking over the console - Delete $INSTDIR\stdout.txt - Delete $INSTDIR\stderr.txt - - ; MUST REMOVE UNINSTALLER, too - Delete $INSTDIR\uninstall.exe - - ; remove shortcuts, if any. - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Uninstall.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\README.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox (noconsole).lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Edit Configuration.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Reset Configuration.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Capture folder.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Install movie codec.lnk" - Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Video instructions.lnk" -; remove directories used. - RMDir "$INSTDIR\zmbv" - RMDir "$INSTDIR" - RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration" - RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video" - RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}" -SectionEnd - -; eof +!define VER_MAYOR 0 +!define VER_MINOR 73 +!define APP_NAME "DOSBox ${VER_MAYOR}.${VER_MINOR} Installer" +!define COMP_NAME "DOSBox Team" +!define COPYRIGHT "Copyright © 2002-2009 DOSBox Team" +!define DESCRIPTION "DOSBox Installer" + +VIProductVersion "${VER_MAYOR}.${VER_MINOR}.0.0" +VIAddVersionKey "ProductName" "${APP_NAME}" +VIAddVersionKey "CompanyName" "${COMP_NAME}" +VIAddVersionKey "FileDescription" "${DESCRIPTION}" +VIAddVersionKey "FileVersion" "${VER_MAYOR}.${VER_MINOR}.0.0" +VIAddVersionKey "ProductVersion" "${VER_MAYOR}, ${VER_MINOR}, 0, 0" +VIAddVersionKey "LegalCopyright" "${COPYRIGHT}" + +; The name of the installer +Name "${APP_NAME}" + +; The file to write +OutFile "DOSBox${VER_MAYOR}.${VER_MINOR}-win32-installer.exe" + +; The default installation directory +InstallDir "$PROGRAMFILES\DOSBox-${VER_MAYOR}.${VER_MINOR}" + +; The text to prompt the user to enter a directory +DirText "This will install DOSBox v${VER_MAYOR}.${VER_MINOR} on your computer. Choose a directory" +SetCompressor /solid lzma + + +LicenseData COPYING +LicenseText "DOSBox v${VER_MAYOR}.${VER_MINOR} License" "Next >" + +; Else vista enables compatibility mode +RequestExecutionLevel admin +; Shortcuts in all users + +ComponentText "Select components for DOSBox" +; The stuff to install +Section "!Core files" Core +SetShellVarContext all + + ; Set output path to the installation directory. + ClearErrors + SetOutPath $INSTDIR + IfErrors error_createdir + SectionIn RO + + ; Put file there + + CreateDirectory "$INSTDIR\zmbv" + File /oname=README.txt README + File /oname=COPYING.txt COPYING + File /oname=THANKS.txt THANKS + File /oname=NEWS.txt NEWS + File /oname=AUTHORS.txt AUTHORS + File /oname=INSTALL.txt INSTALL + File DOSBox.exe + File SDL.dll + File SDL_net.dll + File /oname=zmbv\zmbv.dll zmbv.dll + File /oname=zmbv\zmbv.inf zmbv.inf + File /oname=zmbv\README.txt README.video + + CreateDirectory "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}" + CreateDirectory "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video" + CreateDirectory "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration" + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox.lnk" "$INSTDIR\DOSBox.exe" "" "$INSTDIR\DOSBox.exe" 0 + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox (noconsole).lnk" "$INSTDIR\DOSBox.exe" "-noconsole" "$INSTDIR\DOSBox.exe" 0 + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\README.lnk" "$INSTDIR\README.txt" + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Edit Configuration.lnk" "$INSTDIR\DOSBox.exe" "-editconf notepad.exe -editconf $\"%SystemRoot%\system32\notepad.exe$\" -editconf $\"%WINDIR%\notepad.exe$\"" + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Reset Configuration.lnk" "$INSTDIR\DOSBox.exe" "-eraseconf" + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Capture folder.lnk" "$INSTDIR\DOSBox.exe" "-opencaptures explorer.exe" + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Video instructions.lnk" "$INSTDIR\zmbv\README.txt" +;change outpath so the working directory gets set to zmbv +SetOutPath "$INSTDIR\zmbv" + ; Shortcut creation depends on wether we are 9x of NT + ClearErrors + ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows NT\CurrentVersion" CurrentVersion + IfErrors we_9x we_nt +we_nt: + ;shortcut for win NT + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Install movie codec.lnk" "rundll32" "setupapi,InstallHinfSection DefaultInstall 128 $INSTDIR\zmbv\zmbv.inf" + goto end +we_9x: + ;shortcut for we_9x + CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Install movie codec.lnk" "rundll" "setupx.dll,InstallHinfSection DefaultInstall 128 $INSTDIR\zmbv\zmbv.inf" +end: +SetOutPath $INSTDIR +WriteUninstaller "uninstall.exe" + + goto end_section + +error_createdir: + MessageBox MB_OK "Can't create DOSBox program directory, aborting." + Abort + goto end_section + +end_section: +SectionEnd ; end the section + +Section "Desktop Shortcut" SecDesktop +SetShellVarContext all + +CreateShortCut "$DESKTOP\DOSBox ${VER_MAYOR}.${VER_MINOR}.lnk" "$INSTDIR\DOSBox.exe" "" "$INSTDIR\DOSBox.exe" 0 + + SectionEnd ; end the section + + +UninstallText "This will uninstall DOSBox v${VER_MAYOR}.${VER_MINOR}. Hit next to continue." + +Section "Uninstall" + +; Shortcuts in all users +SetShellVarContext all + + Delete "$DESKTOP\DOSBox ${VER_MAYOR}.${VER_MINOR}.lnk" + ; remove registry keys + ; remove files + Delete $INSTDIR\README.txt + Delete $INSTDIR\COPYING.txt + Delete $INSTDIR\THANKS.txt + Delete $INSTDIR\NEWS.txt + Delete $INSTDIR\AUTHORS.txt + Delete $INSTDIR\INSTALL.txt + Delete $INSTDIR\DOSBox.exe + Delete $INSTDIR\SDL.dll + Delete $INSTDIR\SDL_net.dll + Delete $INSTDIR\zmbv\zmbv.dll + Delete $INSTDIR\zmbv\zmbv.inf + Delete $INSTDIR\zmbv\README.txt + ;Files left by sdl taking over the console + Delete $INSTDIR\stdout.txt + Delete $INSTDIR\stderr.txt + + ; MUST REMOVE UNINSTALLER, too + Delete $INSTDIR\uninstall.exe + + ; remove shortcuts, if any. + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Uninstall.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\README.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox (noconsole).lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Edit Configuration.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration\Reset Configuration.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Capture folder.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Install movie codec.lnk" + Delete "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video\Video instructions.lnk" +; remove directories used. + RMDir "$INSTDIR\zmbv" + RMDir "$INSTDIR" + RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Configuration" + RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video" + RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}" +SectionEnd + +; eof diff --git a/scripts/ega-switch.pl b/scripts/ega-switch.pl index 936ad28..6795b45 100644 --- a/scripts/ega-switch.pl +++ b/scripts/ega-switch.pl @@ -1,32 +1,32 @@ -#!/usr/bin/perl -use integer; -open (THEFILE,'>','../src/hardware/ega-switch.h') - or die "Can't open my file $!"; - -print THEFILE "switch (bit_mask) {\n"; -for ($i = 0; $i < 256; $i++) { - print THEFILE "\tcase $i:\n"; - $b=128; - $add=0; - do { - if ($i & $b) { - print THEFILE "\t{\n"; - print THEFILE "\t\tBit8u color=0;\n"; - print THEFILE "\t\tif (pixels.b[0] & $b) color|=1;\n"; - print THEFILE "\t\tif (pixels.b[1] & $b) color|=2;\n"; - print THEFILE "\t\tif (pixels.b[2] & $b) color|=4;\n"; - print THEFILE "\t\tif (pixels.b[3] & $b) color|=8;\n"; - print THEFILE "\t\t*(write_pixels+$add)=color;\n"; - print THEFILE "\t\t*(write_pixels+$add+512*1024)=color;\n"; - print THEFILE "\t}\n"; - } - - $b=$b >> 1; - $add=$add+1; - } until ($b == 0); - print THEFILE "\tbreak;\n"; -} -print THEFILE "}\n"; - - -close (THEFILE); +#!/usr/bin/perl +use integer; +open (THEFILE,'>','../src/hardware/ega-switch.h') + or die "Can't open my file $!"; + +print THEFILE "switch (bit_mask) {\n"; +for ($i = 0; $i < 256; $i++) { + print THEFILE "\tcase $i:\n"; + $b=128; + $add=0; + do { + if ($i & $b) { + print THEFILE "\t{\n"; + print THEFILE "\t\tBit8u color=0;\n"; + print THEFILE "\t\tif (pixels.b[0] & $b) color|=1;\n"; + print THEFILE "\t\tif (pixels.b[1] & $b) color|=2;\n"; + print THEFILE "\t\tif (pixels.b[2] & $b) color|=4;\n"; + print THEFILE "\t\tif (pixels.b[3] & $b) color|=8;\n"; + print THEFILE "\t\t*(write_pixels+$add)=color;\n"; + print THEFILE "\t\t*(write_pixels+$add+512*1024)=color;\n"; + print THEFILE "\t}\n"; + } + + $b=$b >> 1; + $add=$add+1; + } until ($b == 0); + print THEFILE "\tbreak;\n"; +} +print THEFILE "}\n"; + + +close (THEFILE); diff --git a/scripts/font-switch.pl b/scripts/font-switch.pl index 6ad629c..7274780 100644 --- a/scripts/font-switch.pl +++ b/scripts/font-switch.pl @@ -1,25 +1,25 @@ -#!/usr/bin/perl -use integer; -open (THEFILE,'>','../src/hardware/font-switch.h') - or die "Can't open my file $!"; - -print THEFILE "switch (bit_mask) {\n"; -for ($i = 0; $i < 256; $i++) { - print THEFILE "\tcase $i:\n"; - $b=128; - $add=0; - do { - if ($i & $b) { - print THEFILE "\t\t*(draw+$add)=fg;\n"; - } else { - print THEFILE "\t\t*(draw+$add)=bg;\n"; - } - $b=$b >> 1; - $add=$add+1; - } until ($b == 0); - print THEFILE "\tbreak;\n"; -} -print THEFILE "}\n"; - - -close (THEFILE); +#!/usr/bin/perl +use integer; +open (THEFILE,'>','../src/hardware/font-switch.h') + or die "Can't open my file $!"; + +print THEFILE "switch (bit_mask) {\n"; +for ($i = 0; $i < 256; $i++) { + print THEFILE "\tcase $i:\n"; + $b=128; + $add=0; + do { + if ($i & $b) { + print THEFILE "\t\t*(draw+$add)=fg;\n"; + } else { + print THEFILE "\t\t*(draw+$add)=bg;\n"; + } + $b=$b >> 1; + $add=$add+1; + } until ($b == 0); + print THEFILE "\tbreak;\n"; +} +print THEFILE "}\n"; + + +close (THEFILE); diff --git a/src/cpu/callback.cpp b/src/cpu/callback.cpp index 1d21062..8cedf92 100644 --- a/src/cpu/callback.cpp +++ b/src/cpu/callback.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_dyn_x86.cpp b/src/cpu/core_dyn_x86.cpp index b242e7b..851a04e 100644 --- a/src/cpu/core_dyn_x86.cpp +++ b/src/cpu/core_dyn_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_dyn_x86/cache.h b/src/cpu/core_dyn_x86/cache.h index aebdca3..b5bc7b5 100644 --- a/src/cpu/core_dyn_x86/cache.h +++ b/src/cpu/core_dyn_x86/cache.h @@ -1,572 +1,572 @@ -/* - * Copyright (C) 2002-2009 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: cache.h,v 1.20 2009/07/12 20:13:05 c2woody Exp $ */ - -class CacheBlock { -public: - void Clear(void); - void LinkTo(Bitu index,CacheBlock * toblock) { - assert(toblock); - link[index].to=toblock; - link[index].next=toblock->link[index].from; - toblock->link[index].from=this; - } - struct { - Bit16u start,end; //Where the page is the original code - CodePageHandler * handler; //Page containing this code - } page; - struct { - Bit8u * start; //Where in the cache are we - Bitu size; - CacheBlock * next; - Bit8u * wmapmask; - Bit16u maskstart; - Bit16u masklen; - } cache; - struct { - Bitu index; - CacheBlock * next; - } hash; - struct { - CacheBlock * to; - CacheBlock * next; - CacheBlock * from; - } link[2]; - CacheBlock * crossblock; -}; - -static struct { - struct { - CacheBlock * first; - CacheBlock * active; - CacheBlock * free; - CacheBlock * running; - } block; - Bit8u * pos; - CodePageHandler * free_pages; - CodePageHandler * used_pages; - CodePageHandler * last_page; -} cache; - -static CacheBlock link_blocks[2]; - -class CodePageHandler : public PageHandler { -public: - CodePageHandler() { - invalidation_map=NULL; - } - void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) { - phys_page=_phys_page; - old_pagehandler=_old_pagehandler; - flags=old_pagehandler->flags|PFLAG_HASCODE; - flags&=~PFLAG_WRITEABLE; - active_blocks=0; - active_count=16; - memset(&hash_map,0,sizeof(hash_map)); - memset(&write_map,0,sizeof(write_map)); - if (invalidation_map!=NULL) { - free(invalidation_map); - invalidation_map=NULL; - } - } - bool InvalidateRange(Bitu start,Bitu end) { - Bits index=1+(end>>DYN_HASH_SHIFT); - bool is_current_block=false; - Bit32u ip_point=SegPhys(cs)+reg_eip; - ip_point=(PAGING_GetPhysicalPage(ip_point)-(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 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 (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){ - if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return; - if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { - E_Exit("wb:non-readable code page found that is no ROM page"); - } - addr&=4095; - if (host_readb(hostmem+addr)==(Bit8u)val) return; - host_writeb(hostmem+addr,val); - if (!*(Bit8u*)&write_map[addr]) { - if (active_blocks) return; - active_count--; - if (!active_count) Release(); - return; - } else if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - invalidation_map[addr]++; - InvalidateRange(addr,addr); - } - void writew(PhysPt addr,Bitu val){ - if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return; - if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { - E_Exit("ww:non-readable code page found that is no ROM page"); - } - addr&=4095; - if (host_readw(hostmem+addr)==(Bit16u)val) return; - host_writew(hostmem+addr,val); - if (!*(Bit16u*)&write_map[addr]) { - if (active_blocks) return; - active_count--; - if (!active_count) Release(); - return; - } else if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - (*(Bit16u*)&invalidation_map[addr])+=0x101; - InvalidateRange(addr,addr+1); - } - void writed(PhysPt addr,Bitu val){ - if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return; - if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { - E_Exit("wd:non-readable code page found that is no ROM page"); - } - addr&=4095; - if (host_readd(hostmem+addr)==(Bit32u)val) return; - host_writed(hostmem+addr,val); - if (!*(Bit32u*)&write_map[addr]) { - if (active_blocks) return; - active_count--; - if (!active_count) Release(); - return; - } else if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - (*(Bit32u*)&invalidation_map[addr])+=0x1010101; - InvalidateRange(addr,addr+3); - } - bool writeb_checked(PhysPt addr,Bitu val) { - if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false; - if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { - E_Exit("cb:non-readable code page found that is no ROM page"); - } - addr&=4095; - if (host_readb(hostmem+addr)==(Bit8u)val) return false; - if (!*(Bit8u*)&write_map[addr]) { - if (!active_blocks) { - active_count--; - if (!active_count) Release(); - } - } else { - if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - invalidation_map[addr]++; - 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) { - if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false; - if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { - E_Exit("cw:non-readable code page found that is no ROM page"); - } - addr&=4095; - if (host_readw(hostmem+addr)==(Bit16u)val) return false; - if (!*(Bit16u*)&write_map[addr]) { - if (!active_blocks) { - active_count--; - if (!active_count) Release(); - } - } else { - if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - (*(Bit16u*)&invalidation_map[addr])+=0x101; - 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) { - if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false; - if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { - E_Exit("cd:non-readable code page found that is no ROM page"); - } - addr&=4095; - if (host_readd(hostmem+addr)==(Bit32u)val) return false; - if (!*(Bit32u*)&write_map[addr]) { - if (!active_blocks) { - active_count--; - if (!active_count) Release(); - } - } else { - if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - (*(Bit32u*)&invalidation_map[addr])+=0x1010101; - 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]; - block->hash.index=index; - hash_map[index]=block; - block->page.handler=this; - active_blocks++; - } - void AddCrossBlock(CacheBlock * block) { - block->hash.next=hash_map[0]; - block->hash.index=0; - hash_map[0]=block; - block->page.handler=this; - active_blocks++; - } - void DelCacheBlock(CacheBlock * block) { - active_blocks--; - active_count=16; - CacheBlock * * where=&hash_map[block->hash.index]; - while (*where!=block) { - where=&((*where)->hash.next); - //Will crash if a block isn't found, which should never happen. - } - *where=block->hash.next; - if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) { - for (Bitu i=block->page.start;icache.maskstart;i++) { - if (write_map[i]) write_map[i]--; - } - Bitu maskct=0; - for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) { - if (write_map[i]) { - if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--; - } - } - free(block->cache.wmapmask); - block->cache.wmapmask=NULL; - } else { - for (Bitu i=block->page.start;i<=block->page.end;i++) { - if (write_map[i]) write_map[i]--; - } - } - } - void Release(void) { - MEM_SetPageHandler(phys_page,1,old_pagehandler); - PAGING_ClearTLB(); - if (prev) prev->next=next; - else cache.used_pages=next; - if (next) next->prev=prev; - else cache.last_page=prev; - next=cache.free_pages; - cache.free_pages=this; - prev=0; - } - void ClearRelease(void) { - for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) { - CacheBlock * block=hash_map[index]; - while (block) { - CacheBlock * nextblock=block->hash.next; - block->page.handler=0; //No need, full clear - block->Clear(); - block=nextblock; - } - } - Release(); - } - CacheBlock * FindCacheBlock(Bitu start) { - CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)]; - while (block) { - if (block->page.start==start) return block; - block=block->hash.next; - } - return 0; - } - 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]; - Bit8u * invalidation_map; - CodePageHandler * next, * prev; -private: - PageHandler * old_pagehandler; - CacheBlock * hash_map[1+DYN_PAGE_HASH]; - Bitu active_blocks; - Bitu active_count; - HostPt hostmem; - Bitu phys_page; -}; - - -static INLINE void cache_addunsedblock(CacheBlock * block) { - block->cache.next=cache.block.free; - cache.block.free=block; -} - -static CacheBlock * cache_getblock(void) { - CacheBlock * ret=cache.block.free; - if (!ret) E_Exit("Ran out of CacheBlocks" ); - cache.block.free=ret->cache.next; - ret->cache.next=0; - return ret; -} - -void CacheBlock::Clear(void) { - Bitu ind; - /* Check if this is not a cross page block */ - if (hash.index) for (ind=0;ind<2;ind++) { - CacheBlock * fromlink=link[ind].from; - link[ind].from=0; - while (fromlink) { - CacheBlock * nextlink=fromlink->link[ind].next; - fromlink->link[ind].next=0; - fromlink->link[ind].to=&link_blocks[ind]; - fromlink=nextlink; - } - if (link[ind].to!=&link_blocks[ind]) { - CacheBlock * * wherelink=&link[ind].to->link[ind].from; - while (*wherelink != this && *wherelink) { - 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); - if (crossblock) { - crossblock->crossblock=0; - crossblock->Clear(); - crossblock=0; - } - if (page.handler) { - page.handler->DelCacheBlock(this); - page.handler=0; - } - if (cache.wmapmask){ - free(cache.wmapmask); - cache.wmapmask=NULL; - } -} - - -static CacheBlock * cache_openblock(void) { - CacheBlock * block=cache.block.active; - /* check for enough space in this block */ - Bitu size=block->cache.size; - CacheBlock * nextblock=block->cache.next; - if (block->page.handler) - block->Clear(); - while (sizecache.size; - CacheBlock * tempblock=nextblock->cache.next; - if (nextblock->page.handler) - nextblock->Clear(); - cache_addunsedblock(nextblock); - nextblock=tempblock; - } -skipresize: - block->cache.size=size; - block->cache.next=nextblock; - cache.pos=block->cache.start; - return block; -} - -static void cache_closeblock(void) { - CacheBlock * block=cache.block.active; - block->link[0].to=&link_blocks[0]; - block->link[1].to=&link_blocks[1]; - block->link[0].from=0; - block->link[1].from=0; - block->link[0].next=0; - block->link[1].next=0; - /* Close the block with correct alignments */ - Bitu written=cache.pos-block->cache.start; - if (written>block->cache.size) { - if (!block->cache.next) { - if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size); - } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size); - } else { - Bitu new_size; - Bitu left=block->cache.size-written; - /* Smaller than cache align then don't bother to resize */ - if (left>CACHE_ALIGN) { - new_size=((written-1)|(CACHE_ALIGN-1))+1; - CacheBlock * newblock=cache_getblock(); - newblock->cache.start=block->cache.start+new_size; - newblock->cache.size=block->cache.size-new_size; - newblock->cache.next=block->cache.next; - block->cache.next=newblock; - block->cache.size=new_size; - } - } - /* Advance the active block pointer */ - if (!block->cache.next) { -// LOG_MSG("Cache full restarting"); - cache.block.active=cache.block.first; - } else { - cache.block.active=block->cache.next; - } -} - -static INLINE void cache_addb(Bit8u val) { - *cache.pos++=val; -} - -static INLINE void cache_addw(Bit16u val) { - *(Bit16u*)cache.pos=val; - cache.pos+=2; -} - -static INLINE void cache_addd(Bit32u val) { - *(Bit32u*)cache.pos=val; - cache.pos+=4; -} - - -static void gen_return(BlockReturn retcode); - -static Bit8u * cache_code_start_ptr=NULL; -static Bit8u * cache_code=NULL; -static Bit8u * cache_code_link_blocks=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 4096 -#endif - -static bool cache_initialized = false; - -static void cache_init(bool enable) { - Bits i; - 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]; - link_blocks[0].cache.start=cache.pos; - gen_return(BR_Link1); - cache.pos=&cache_code_link_blocks[32]; - 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; - } - } -} - -static void cache_close(void) { -/* for (;;) { - if (cache.used_pages) { - CodePageHandler * cpage=cache.used_pages; - CodePageHandler * npage=cache.used_pages->next; - cpage->ClearRelease(); - delete cpage; - cache.used_pages=npage; - } else break; - } - if (cache_blocks != NULL) { - free(cache_blocks); - cache_blocks = NULL; - } - if (cache_code_start_ptr != NULL) { - ### care: under windows VirtualFree() has to be used if - ### VirtualAlloc was used for memory allocation - free(cache_code_start_ptr); - cache_code_start_ptr = NULL; - } - cache_code = NULL; - cache_code_link_blocks = NULL; - cache_initialized = false; */ -} +/* + * Copyright (C) 2002-2010 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: cache.h,v 1.20 2009-07-12 20:13:05 c2woody Exp $ */ + +class CacheBlock { +public: + void Clear(void); + void LinkTo(Bitu index,CacheBlock * toblock) { + assert(toblock); + link[index].to=toblock; + link[index].next=toblock->link[index].from; + toblock->link[index].from=this; + } + struct { + Bit16u start,end; //Where the page is the original code + CodePageHandler * handler; //Page containing this code + } page; + struct { + Bit8u * start; //Where in the cache are we + Bitu size; + CacheBlock * next; + Bit8u * wmapmask; + Bit16u maskstart; + Bit16u masklen; + } cache; + struct { + Bitu index; + CacheBlock * next; + } hash; + struct { + CacheBlock * to; + CacheBlock * next; + CacheBlock * from; + } link[2]; + CacheBlock * crossblock; +}; + +static struct { + struct { + CacheBlock * first; + CacheBlock * active; + CacheBlock * free; + CacheBlock * running; + } block; + Bit8u * pos; + CodePageHandler * free_pages; + CodePageHandler * used_pages; + CodePageHandler * last_page; +} cache; + +static CacheBlock link_blocks[2]; + +class CodePageHandler : public PageHandler { +public: + CodePageHandler() { + invalidation_map=NULL; + } + void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) { + phys_page=_phys_page; + old_pagehandler=_old_pagehandler; + flags=old_pagehandler->flags|PFLAG_HASCODE; + flags&=~PFLAG_WRITEABLE; + active_blocks=0; + active_count=16; + memset(&hash_map,0,sizeof(hash_map)); + memset(&write_map,0,sizeof(write_map)); + if (invalidation_map!=NULL) { + free(invalidation_map); + invalidation_map=NULL; + } + } + bool InvalidateRange(Bitu start,Bitu end) { + Bits index=1+(end>>DYN_HASH_SHIFT); + bool is_current_block=false; + Bit32u ip_point=SegPhys(cs)+reg_eip; + ip_point=(PAGING_GetPhysicalPage(ip_point)-(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 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 (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){ + if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return; + if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { + E_Exit("wb:non-readable code page found that is no ROM page"); + } + addr&=4095; + if (host_readb(hostmem+addr)==(Bit8u)val) return; + host_writeb(hostmem+addr,val); + if (!*(Bit8u*)&write_map[addr]) { + if (active_blocks) return; + active_count--; + if (!active_count) Release(); + return; + } else if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + invalidation_map[addr]++; + InvalidateRange(addr,addr); + } + void writew(PhysPt addr,Bitu val){ + if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return; + if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { + E_Exit("ww:non-readable code page found that is no ROM page"); + } + addr&=4095; + if (host_readw(hostmem+addr)==(Bit16u)val) return; + host_writew(hostmem+addr,val); + if (!*(Bit16u*)&write_map[addr]) { + if (active_blocks) return; + active_count--; + if (!active_count) Release(); + return; + } else if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + (*(Bit16u*)&invalidation_map[addr])+=0x101; + InvalidateRange(addr,addr+1); + } + void writed(PhysPt addr,Bitu val){ + if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return; + if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { + E_Exit("wd:non-readable code page found that is no ROM page"); + } + addr&=4095; + if (host_readd(hostmem+addr)==(Bit32u)val) return; + host_writed(hostmem+addr,val); + if (!*(Bit32u*)&write_map[addr]) { + if (active_blocks) return; + active_count--; + if (!active_count) Release(); + return; + } else if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + (*(Bit32u*)&invalidation_map[addr])+=0x1010101; + InvalidateRange(addr,addr+3); + } + bool writeb_checked(PhysPt addr,Bitu val) { + if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false; + if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { + E_Exit("cb:non-readable code page found that is no ROM page"); + } + addr&=4095; + if (host_readb(hostmem+addr)==(Bit8u)val) return false; + if (!*(Bit8u*)&write_map[addr]) { + if (!active_blocks) { + active_count--; + if (!active_count) Release(); + } + } else { + if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + invalidation_map[addr]++; + 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) { + if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false; + if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { + E_Exit("cw:non-readable code page found that is no ROM page"); + } + addr&=4095; + if (host_readw(hostmem+addr)==(Bit16u)val) return false; + if (!*(Bit16u*)&write_map[addr]) { + if (!active_blocks) { + active_count--; + if (!active_count) Release(); + } + } else { + if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + (*(Bit16u*)&invalidation_map[addr])+=0x101; + 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) { + if (GCC_UNLIKELY(old_pagehandler->flags&PFLAG_HASROM)) return false; + if (GCC_UNLIKELY((old_pagehandler->flags&PFLAG_READABLE)!=PFLAG_READABLE)) { + E_Exit("cd:non-readable code page found that is no ROM page"); + } + addr&=4095; + if (host_readd(hostmem+addr)==(Bit32u)val) return false; + if (!*(Bit32u*)&write_map[addr]) { + if (!active_blocks) { + active_count--; + if (!active_count) Release(); + } + } else { + if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + (*(Bit32u*)&invalidation_map[addr])+=0x1010101; + 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]; + block->hash.index=index; + hash_map[index]=block; + block->page.handler=this; + active_blocks++; + } + void AddCrossBlock(CacheBlock * block) { + block->hash.next=hash_map[0]; + block->hash.index=0; + hash_map[0]=block; + block->page.handler=this; + active_blocks++; + } + void DelCacheBlock(CacheBlock * block) { + active_blocks--; + active_count=16; + CacheBlock * * where=&hash_map[block->hash.index]; + while (*where!=block) { + where=&((*where)->hash.next); + //Will crash if a block isn't found, which should never happen. + } + *where=block->hash.next; + if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) { + for (Bitu i=block->page.start;icache.maskstart;i++) { + if (write_map[i]) write_map[i]--; + } + Bitu maskct=0; + for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) { + if (write_map[i]) { + if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--; + } + } + free(block->cache.wmapmask); + block->cache.wmapmask=NULL; + } else { + for (Bitu i=block->page.start;i<=block->page.end;i++) { + if (write_map[i]) write_map[i]--; + } + } + } + void Release(void) { + MEM_SetPageHandler(phys_page,1,old_pagehandler); + PAGING_ClearTLB(); + if (prev) prev->next=next; + else cache.used_pages=next; + if (next) next->prev=prev; + else cache.last_page=prev; + next=cache.free_pages; + cache.free_pages=this; + prev=0; + } + void ClearRelease(void) { + for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) { + CacheBlock * block=hash_map[index]; + while (block) { + CacheBlock * nextblock=block->hash.next; + block->page.handler=0; //No need, full clear + block->Clear(); + block=nextblock; + } + } + Release(); + } + CacheBlock * FindCacheBlock(Bitu start) { + CacheBlock * block=hash_map[1+(start>>DYN_HASH_SHIFT)]; + while (block) { + if (block->page.start==start) return block; + block=block->hash.next; + } + return 0; + } + 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]; + Bit8u * invalidation_map; + CodePageHandler * next, * prev; +private: + PageHandler * old_pagehandler; + CacheBlock * hash_map[1+DYN_PAGE_HASH]; + Bitu active_blocks; + Bitu active_count; + HostPt hostmem; + Bitu phys_page; +}; + + +static INLINE void cache_addunsedblock(CacheBlock * block) { + block->cache.next=cache.block.free; + cache.block.free=block; +} + +static CacheBlock * cache_getblock(void) { + CacheBlock * ret=cache.block.free; + if (!ret) E_Exit("Ran out of CacheBlocks" ); + cache.block.free=ret->cache.next; + ret->cache.next=0; + return ret; +} + +void CacheBlock::Clear(void) { + Bitu ind; + /* Check if this is not a cross page block */ + if (hash.index) for (ind=0;ind<2;ind++) { + CacheBlock * fromlink=link[ind].from; + link[ind].from=0; + while (fromlink) { + CacheBlock * nextlink=fromlink->link[ind].next; + fromlink->link[ind].next=0; + fromlink->link[ind].to=&link_blocks[ind]; + fromlink=nextlink; + } + if (link[ind].to!=&link_blocks[ind]) { + CacheBlock * * wherelink=&link[ind].to->link[ind].from; + while (*wherelink != this && *wherelink) { + 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); + if (crossblock) { + crossblock->crossblock=0; + crossblock->Clear(); + crossblock=0; + } + if (page.handler) { + page.handler->DelCacheBlock(this); + page.handler=0; + } + if (cache.wmapmask){ + free(cache.wmapmask); + cache.wmapmask=NULL; + } +} + + +static CacheBlock * cache_openblock(void) { + CacheBlock * block=cache.block.active; + /* check for enough space in this block */ + Bitu size=block->cache.size; + CacheBlock * nextblock=block->cache.next; + if (block->page.handler) + block->Clear(); + while (sizecache.size; + CacheBlock * tempblock=nextblock->cache.next; + if (nextblock->page.handler) + nextblock->Clear(); + cache_addunsedblock(nextblock); + nextblock=tempblock; + } +skipresize: + block->cache.size=size; + block->cache.next=nextblock; + cache.pos=block->cache.start; + return block; +} + +static void cache_closeblock(void) { + CacheBlock * block=cache.block.active; + block->link[0].to=&link_blocks[0]; + block->link[1].to=&link_blocks[1]; + block->link[0].from=0; + block->link[1].from=0; + block->link[0].next=0; + block->link[1].next=0; + /* Close the block with correct alignments */ + Bitu written=cache.pos-block->cache.start; + if (written>block->cache.size) { + if (!block->cache.next) { + if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size); + } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size); + } else { + Bitu new_size; + Bitu left=block->cache.size-written; + /* Smaller than cache align then don't bother to resize */ + if (left>CACHE_ALIGN) { + new_size=((written-1)|(CACHE_ALIGN-1))+1; + CacheBlock * newblock=cache_getblock(); + newblock->cache.start=block->cache.start+new_size; + newblock->cache.size=block->cache.size-new_size; + newblock->cache.next=block->cache.next; + block->cache.next=newblock; + block->cache.size=new_size; + } + } + /* Advance the active block pointer */ + if (!block->cache.next) { +// LOG_MSG("Cache full restarting"); + cache.block.active=cache.block.first; + } else { + cache.block.active=block->cache.next; + } +} + +static INLINE void cache_addb(Bit8u val) { + *cache.pos++=val; +} + +static INLINE void cache_addw(Bit16u val) { + *(Bit16u*)cache.pos=val; + cache.pos+=2; +} + +static INLINE void cache_addd(Bit32u val) { + *(Bit32u*)cache.pos=val; + cache.pos+=4; +} + + +static void gen_return(BlockReturn retcode); + +static Bit8u * cache_code_start_ptr=NULL; +static Bit8u * cache_code=NULL; +static Bit8u * cache_code_link_blocks=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 4096 +#endif + +static bool cache_initialized = false; + +static void cache_init(bool enable) { + Bits i; + 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]; + link_blocks[0].cache.start=cache.pos; + gen_return(BR_Link1); + cache.pos=&cache_code_link_blocks[32]; + 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; + } + } +} + +static void cache_close(void) { +/* for (;;) { + if (cache.used_pages) { + CodePageHandler * cpage=cache.used_pages; + CodePageHandler * npage=cache.used_pages->next; + cpage->ClearRelease(); + delete cpage; + cache.used_pages=npage; + } else break; + } + if (cache_blocks != NULL) { + free(cache_blocks); + cache_blocks = NULL; + } + if (cache_code_start_ptr != NULL) { + ### care: under windows VirtualFree() has to be used if + ### VirtualAlloc was used for memory allocation + free(cache_code_start_ptr); + cache_code_start_ptr = NULL; + } + cache_code = NULL; + cache_code_link_blocks = NULL; + cache_initialized = false; */ +} diff --git a/src/cpu/core_dyn_x86/decoder.h b/src/cpu/core_dyn_x86/decoder.h index 6905e3d..0f02454 100644 --- a/src/cpu/core_dyn_x86/decoder.h +++ b/src/cpu/core_dyn_x86/decoder.h @@ -1,2710 +1,2710 @@ -/* - * Copyright (C) 2002-2009 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: decoder.h,v 1.59 2009/10/18 17:52:09 c2woody Exp $ */ - -#define X86_DYNFPU_DH_ENABLED -#define X86_INLINED_MEMACCESS - - -enum REP_Type { - REP_NONE=0,REP_NZ,REP_Z -}; - -static struct DynDecode { - PhysPt code; - PhysPt code_start; - PhysPt op_start; - bool big_op; - bool big_addr; - REP_Type rep; - Bitu cycles; - CacheBlock * block; - CacheBlock * active_block; - struct { - CodePageHandler * code; - Bitu index; - Bit8u * wmap; - Bit8u * invmap; - Bitu first; - } page; - struct { - Bitu val; - Bitu mod; - Bitu rm; - Bitu reg; - } modrm; - DynReg * segprefix; -} decode; - -static bool MakeCodePage(Bitu lin_addr,CodePageHandler * &cph) { - Bit8u rdval; - //Ensure page contains memory: - if (GCC_UNLIKELY(mem_readb_checked(lin_addr,&rdval))) return true; - PageHandler * handler=get_tlb_readhandler(lin_addr); - if (handler->flags & PFLAG_HASCODE) { - cph=( CodePageHandler *)handler; - return false; - } - if (handler->flags & PFLAG_NOCODE) { - if (PAGING_ForcePageInit(lin_addr)) { - handler=get_tlb_readhandler(lin_addr); - if (handler->flags & PFLAG_HASCODE) { - cph=( CodePageHandler *)handler; - return false; - } - } - if (handler->flags & PFLAG_NOCODE) { - LOG_MSG("DYNX86:Can't run code in this page!"); - cph=0; return false; - } - } - Bitu lin_page=lin_addr >> 12; - Bitu phys_page=lin_page; - if (!PAGING_MakePhysPage(phys_page)) { - LOG_MSG("DYNX86:Can't find physpage"); - cph=0; return false; - } - /* Find a free CodePage */ - if (!cache.free_pages) { - if (cache.used_pages!=decode.page.code) cache.used_pages->ClearRelease(); - else { - if ((cache.used_pages->next) && (cache.used_pages->next!=decode.page.code)) - cache.used_pages->next->ClearRelease(); - else { - LOG_MSG("DYNX86:Invalid cache links"); - cache.used_pages->ClearRelease(); - } - } - } - CodePageHandler * cpagehandler=cache.free_pages; - cache.free_pages=cache.free_pages->next; - cpagehandler->prev=cache.last_page; - cpagehandler->next=0; - if (cache.last_page) cache.last_page->next=cpagehandler; - cache.last_page=cpagehandler; - if (!cache.used_pages) cache.used_pages=cpagehandler; - cpagehandler->SetupAt(phys_page,handler); - MEM_SetPageHandler(phys_page,1,cpagehandler); - PAGING_UnlinkPages(lin_page,1); - cph=cpagehandler; - return false; -} - -static Bit8u decode_fetchb(void) { - if (GCC_UNLIKELY(decode.page.index>=4096)) { - /* Advance to the next page */ - decode.active_block->page.end=4095; - /* trigger possible page fault here */ - decode.page.first++; - Bitu fetchaddr=decode.page.first << 12; - mem_readb(fetchaddr); - MakeCodePage(fetchaddr,decode.page.code); - CacheBlock * newblock=cache_getblock(); - decode.active_block->crossblock=newblock; - newblock->crossblock=decode.active_block; - decode.active_block=newblock; - decode.active_block->page.start=0; - decode.page.code->AddCrossBlock(decode.active_block); - decode.page.wmap=decode.page.code->write_map; - decode.page.invmap=decode.page.code->invalidation_map; - decode.page.index=0; - } - decode.page.wmap[decode.page.index]+=0x01; - decode.page.index++; - decode.code+=1; - return mem_readb(decode.code-1); -} -static Bit16u decode_fetchw(void) { - if (GCC_UNLIKELY(decode.page.index>=4095)) { - Bit16u val=decode_fetchb(); - val|=decode_fetchb() << 8; - return val; - } - *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101; - decode.code+=2;decode.page.index+=2; - return mem_readw(decode.code-2); -} -static Bit32u decode_fetchd(void) { - if (GCC_UNLIKELY(decode.page.index>=4093)) { - Bit32u val=decode_fetchb(); - val|=decode_fetchb() << 8; - val|=decode_fetchb() << 16; - val|=decode_fetchb() << 24; - return val; - /* Advance to the next page */ - } - *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101; - decode.code+=4;decode.page.index+=4; - return mem_readd(decode.code-4); -} - -#define START_WMMEM 64 - -static INLINE void decode_increase_wmapmask(Bitu size) { - Bitu mapidx; - CacheBlock* activecb=decode.active_block; - if (GCC_UNLIKELY(!activecb->cache.wmapmask)) { - activecb->cache.wmapmask=(Bit8u*)malloc(START_WMMEM); - memset(activecb->cache.wmapmask,0,START_WMMEM); - activecb->cache.maskstart=decode.page.index; - activecb->cache.masklen=START_WMMEM; - mapidx=0; - } else { - mapidx=decode.page.index-activecb->cache.maskstart; - if (GCC_UNLIKELY(mapidx+size>=activecb->cache.masklen)) { - Bitu newmasklen=activecb->cache.masklen*4; - if (newmasklencache.wmapmask,activecb->cache.masklen); - free(activecb->cache.wmapmask); - activecb->cache.wmapmask=tempmem; - activecb->cache.masklen=newmasklen; - } - } - switch (size) { - case 1 : activecb->cache.wmapmask[mapidx]+=0x01; break; - case 2 : (*(Bit16u*)&activecb->cache.wmapmask[mapidx])+=0x0101; break; - case 4 : (*(Bit32u*)&activecb->cache.wmapmask[mapidx])+=0x01010101; break; - } -} - -static bool decode_fetchb_imm(Bitu & val) { - if (decode.page.index<4096) { - if (decode.page.invmap != NULL) { - if (decode.page.invmap[decode.page.index] == 0) { - val=(Bit32u)decode_fetchb(); - return false; - } - HostPt tlb_addr=get_tlb_read(decode.code); - if (tlb_addr) { - val=(Bitu)(tlb_addr+decode.code); - decode_increase_wmapmask(1); - decode.code++; - decode.page.index++; - return true; - } - } - } - val=(Bit32u)decode_fetchb(); - return false; -} -static bool decode_fetchw_imm(Bitu & val) { - if (decode.page.index<4095) { - if (decode.page.invmap != NULL) { - if ((decode.page.invmap[decode.page.index] == 0) && - (decode.page.invmap[decode.page.index + 1] == 0) - ) { - val=decode_fetchw(); - return false; - } - HostPt tlb_addr=get_tlb_read(decode.code); - if (tlb_addr) { - val=(Bitu)(tlb_addr+decode.code); - decode_increase_wmapmask(2); - decode.code+=2; - decode.page.index+=2; - return true; - } - } - } - val=decode_fetchw(); - return false; -} -static bool decode_fetchd_imm(Bitu & val) { - if (decode.page.index<4093) { - if (decode.page.invmap != NULL) { - if ((decode.page.invmap[decode.page.index] == 0) && - (decode.page.invmap[decode.page.index + 1] == 0) && - (decode.page.invmap[decode.page.index + 2] == 0) && - (decode.page.invmap[decode.page.index + 3] == 0) - ) { - val=decode_fetchd(); - return false; - } - HostPt tlb_addr=get_tlb_read(decode.code); - if (tlb_addr) { - val=(Bitu)(tlb_addr+decode.code); - decode_increase_wmapmask(4); - decode.code+=4; - decode.page.index+=4; - return true; - } - } - } - val=decode_fetchd(); - return false; -} - - -static void dyn_reduce_cycles(void) { - gen_protectflags(); - if (!decode.cycles) decode.cycles++; - gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles); -} - -static void dyn_save_noncritical_regs(void) { - gen_releasereg(DREG(EAX)); - gen_releasereg(DREG(ECX)); - gen_releasereg(DREG(EDX)); - gen_releasereg(DREG(EBX)); - gen_releasereg(DREG(ESP)); - 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)); -} - -static void dyn_set_eip_last_end(DynReg * endreg) { - gen_protectflags(); - gen_lea(endreg,DREG(EIP),0,0,decode.code-decode.code_start); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),decode.op_start-decode.code_start); -} - -static INLINE void dyn_set_eip_end(void) { - gen_protectflags(); - 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(); - if (cpu.code.big) gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EIP)); - else gen_extend_word(false,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,cpu.code.big,DREG(EIP),decode.op_start-decode.code_start); -} - - -enum save_info_type {db_exception, cycle_check, normal, fpu_restore}; - - -static struct { - save_info_type type; - DynState state; - Bit8u * branch_pos; - Bit32u eip_change; - Bitu cycles; - Bit8u * return_pos; -} 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=db_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=db_exception; - used_save_info++; -} - -#include "pic.h" - -static void dyn_check_irqrequest(void) { - gen_load_host(&PIC_IRQCheck,DREG(TMPB),4); - gen_dop_word(DOP_OR,true,DREG(TMPB),DREG(TMPB)); - save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ); - gen_releasereg(DREG(TMPB)); - 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.code-decode.code_start; - if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff; - save_info[used_save_info].type=normal; - used_save_info++; -} - -static void dyn_check_bool_exception_ne(void) { - save_info[used_save_info].branch_pos=gen_create_branch_long(BR_Z); - 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=db_exception; - used_save_info++; -} - -static void dyn_fill_blocks(void) { - for (Bitu sct=0; sctindex<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.state_used))); - gen_releasereg(DREG(TMPB)); - dyn_synchstate(&save_info[sct].state); - gen_create_jump(save_info[sct].return_pos); - break; - } - } - used_save_info=0; -} - - -#if !defined(X86_INLINED_MEMACCESS) -static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) { - gen_protectflags(); - gen_call_function((void *)&mem_readb_checked,"%Dd%Id",addr,&core_dyn.readdata); - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dst,1,high); -} -static void dyn_write_byte(DynReg * addr,DynReg * val,Bitu high) { - gen_protectflags(); - if (high) gen_call_function((void *)&mem_writeb_checked,"%Dd%Dh",addr,val); - else gen_call_function((void *)&mem_writeb_checked,"%Dd%Dd",addr,val); - dyn_check_bool_exception_al(); -} -static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) { - gen_protectflags(); - if (dword) gen_call_function((void *)&mem_readd_checked,"%Dd%Id",addr,&core_dyn.readdata); - else gen_call_function((void *)&mem_readw_checked,"%Dd%Id",addr,&core_dyn.readdata); - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dst,dword?4:2); -} -static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { - gen_protectflags(); - if (dword) gen_call_function((void *)&mem_writed_checked,"%Dd%Dd",addr,val); - else gen_call_function((void *)&mem_writew_checked,"%Dd%Dd",addr,val); - dyn_check_bool_exception_al(); -} -static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) { - gen_protectflags(); - gen_call_function((void *)&mem_readb_checked,"%Ddr%Id",addr,&core_dyn.readdata); - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dst,1,high); -} -static void dyn_write_byte_release(DynReg * addr,DynReg * val,Bitu high) { - gen_protectflags(); - if (high) gen_call_function((void *)&mem_writeb_checked,"%Ddr%Dh",addr,val); - else gen_call_function((void *)&mem_writeb_checked,"%Ddr%Dd",addr,val); - dyn_check_bool_exception_al(); -} -static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) { - gen_protectflags(); - if (dword) gen_call_function((void *)&mem_readd_checked,"%Ddr%Id",addr,&core_dyn.readdata); - else gen_call_function((void *)&mem_readw_checked,"%Ddr%Id",addr,&core_dyn.readdata); - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dst,dword?4:2); -} -static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) { - gen_protectflags(); - if (dword) gen_call_function((void *)&mem_writed_checked,"%Ddr%Dd",addr,val); - else gen_call_function((void *)&mem_writew_checked,"%Ddr%Dd",addr,val); - dyn_check_bool_exception_al(); -} - -#else - -static void dyn_read_intro(DynReg * addr,bool release_addr=true) { - gen_protectflags(); - - if (addr->genreg) { - // addr already in a register - Bit8u reg_idx=(Bit8u)addr->genreg->index; - x86gen.regs[X86_REG_ECX]->Clear(); - if (reg_idx!=1) { - cache_addw(0xc88b+(reg_idx<<8)); //Mov ecx,reg - } - x86gen.regs[X86_REG_EAX]->Clear(); - if (release_addr) gen_releasereg(addr); - } else { - // addr still in memory, directly move into ecx - x86gen.regs[X86_REG_EAX]->Clear(); - x86gen.regs[X86_REG_ECX]->Clear(); - cache_addw(0x0d8b); //Mov ecx,[data] - cache_addd((Bit32u)addr->data); - } - x86gen.regs[X86_REG_EDX]->Clear(); - - cache_addw(0xc18b); // mov eax,ecx -} - -bool mem_readb_checked_dcx86(PhysPt address) { - return get_tlb_readhandler(address)->readb_checked(address, (Bit8u*)(&core_dyn.readdata)); -} - -static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) { - dyn_read_intro(addr,false); - - cache_addw(0xe8c1); // shr eax,0x0c - cache_addb(0x0c); - cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] - cache_addb(0x85); - cache_addd((Bit32u)(&paging.tlb.read[0])); - cache_addw(0xc085); // test eax,eax - Bit8u* je_loc=gen_create_branch(BR_Z); - - - cache_addw(0x048a); // mov al,[eax+ecx] - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(je_loc); - cache_addb(0x51); // push ecx - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_readb_checked_dcx86) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,4 - cache_addb(0x04); - cache_addw(0x012c); // sub al,1 - - dyn_check_bool_exception_ne(); - - cache_addw(0x058a); //mov al,[] - cache_addd((Bit32u)(&core_dyn.readdata)); - - gen_fill_jump(jmp_loc); - - x86gen.regs[X86_REG_EAX]->notusable=true; - GenReg * genreg=FindDynReg(dst); - x86gen.regs[X86_REG_EAX]->notusable=false; - cache_addw(0xc08a+(genreg->index<<11)+(high?0x2000:0)); - dst->flags|=DYNFLG_CHANGED; -} - -static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) { - dyn_read_intro(addr); - - cache_addw(0xe8c1); // shr eax,0x0c - cache_addb(0x0c); - cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] - cache_addb(0x85); - cache_addd((Bit32u)(&paging.tlb.read[0])); - cache_addw(0xc085); // test eax,eax - Bit8u* je_loc=gen_create_branch(BR_Z); - - - cache_addw(0x048a); // mov al,[eax+ecx] - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(je_loc); - cache_addb(0x51); // push ecx - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_readb_checked_dcx86) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,4 - cache_addb(0x04); - cache_addw(0x012c); // sub al,1 - - dyn_check_bool_exception_ne(); - - cache_addw(0x058a); //mov al,[] - cache_addd((Bit32u)(&core_dyn.readdata)); - - gen_fill_jump(jmp_loc); - - x86gen.regs[X86_REG_EAX]->notusable=true; - GenReg * genreg=FindDynReg(dst); - x86gen.regs[X86_REG_EAX]->notusable=false; - cache_addw(0xc08a+(genreg->index<<11)+(high?0x2000:0)); - dst->flags|=DYNFLG_CHANGED; -} - -bool mem_readd_checked_dcx86(PhysPt address) { - if ((address & 0xfff)<0xffd) { - HostPt tlb_addr=get_tlb_read(address); - if (tlb_addr) { - core_dyn.readdata=host_readd(tlb_addr+address); - return false; - } else { - return get_tlb_readhandler(address)->readd_checked(address, &core_dyn.readdata); - } - } else return mem_unalignedreadd_checked(address, &core_dyn.readdata); -} - -static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) { - if (dword) { - dyn_read_intro(addr,false); - - cache_addw(0xe8d1); // shr eax,0x1 - Bit8u* jb_loc1=gen_create_branch(BR_B); - cache_addw(0xe8d1); // shr eax,0x1 - Bit8u* jb_loc2=gen_create_branch(BR_B); - cache_addw(0xe8c1); // shr eax,0x0a - cache_addb(0x0a); - cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] - cache_addb(0x85); - cache_addd((Bit32u)(&paging.tlb.read[0])); - cache_addw(0xc085); // test eax,eax - Bit8u* je_loc=gen_create_branch(BR_Z); - - GenReg * genreg=FindDynReg(dst,true); - - cache_addw(0x048b+(genreg->index <<(8+3))); // mov dest,[eax+ecx] - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(jb_loc1); - gen_fill_branch(jb_loc2); - gen_fill_branch(je_loc); - cache_addb(0x51); // push ecx - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_readd_checked_dcx86) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,4 - cache_addb(0x04); - cache_addw(0x012c); // sub al,1 - - dyn_check_bool_exception_ne(); - - gen_mov_host(&core_dyn.readdata,dst,4); - dst->flags|=DYNFLG_CHANGED; - - gen_fill_jump(jmp_loc); - } else { - gen_protectflags(); - gen_call_function((void *)&mem_readw_checked,"%Dd%Id",addr,&core_dyn.readdata); - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dst,2); - } -} - -static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) { - if (dword) { - dyn_read_intro(addr); - - cache_addw(0xe8d1); // shr eax,0x1 - Bit8u* jb_loc1=gen_create_branch(BR_B); - cache_addw(0xe8d1); // shr eax,0x1 - Bit8u* jb_loc2=gen_create_branch(BR_B); - cache_addw(0xe8c1); // shr eax,0x0a - cache_addb(0x0a); - cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] - cache_addb(0x85); - cache_addd((Bit32u)(&paging.tlb.read[0])); - cache_addw(0xc085); // test eax,eax - Bit8u* je_loc=gen_create_branch(BR_Z); - - GenReg * genreg=FindDynReg(dst,true); - - cache_addw(0x048b+(genreg->index <<(8+3))); // mov dest,[eax+ecx] - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(jb_loc1); - gen_fill_branch(jb_loc2); - gen_fill_branch(je_loc); - cache_addb(0x51); // push ecx - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_readd_checked_dcx86) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,4 - cache_addb(0x04); - cache_addw(0x012c); // sub al,1 - - dyn_check_bool_exception_ne(); - - gen_mov_host(&core_dyn.readdata,dst,4); - dst->flags|=DYNFLG_CHANGED; - - gen_fill_jump(jmp_loc); - } else { - gen_protectflags(); - gen_call_function((void *)&mem_readw_checked,"%Ddr%Id",addr,&core_dyn.readdata); - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dst,2); - } -} - -static void dyn_write_intro(DynReg * addr,bool release_addr=true) { - gen_protectflags(); - - if (addr->genreg) { - // addr in a register - Bit8u reg_idx_addr=(Bit8u)addr->genreg->index; - - x86gen.regs[X86_REG_EAX]->Clear(); - x86gen.regs[X86_REG_EAX]->notusable=true; - x86gen.regs[X86_REG_ECX]->Clear(); - x86gen.regs[X86_REG_ECX]->notusable=true; - - if (reg_idx_addr) { - // addr!=eax - cache_addb(0x8b); //Mov eax,reg - cache_addb(0xc0+reg_idx_addr); - } - if (release_addr) gen_releasereg(addr); - } else { - // addr still in memory, directly move into eax - x86gen.regs[X86_REG_EAX]->Clear(); - x86gen.regs[X86_REG_EAX]->notusable=true; - x86gen.regs[X86_REG_ECX]->Clear(); - x86gen.regs[X86_REG_ECX]->notusable=true; - cache_addb(0xa1); //Mov eax,[data] - cache_addd((Bit32u)addr->data); - } - - cache_addw(0xc88b); // mov ecx,eax -} - -static void dyn_write_byte(DynReg * addr,DynReg * val,bool high) { - dyn_write_intro(addr,false); - - GenReg * genreg=FindDynReg(val); - cache_addw(0xe9c1); // shr ecx,0x0c - cache_addb(0x0c); - cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] - cache_addb(0x8d); - cache_addd((Bit32u)(&paging.tlb.write[0])); - cache_addw(0xc985); // test ecx,ecx - Bit8u* je_loc=gen_create_branch(BR_Z); - - cache_addw(0x0488+(genreg->index<<11)+(high?0x2000:0)); // mov [eax+ecx],reg - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(je_loc); - - if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); - cache_addb(0x52); // push edx - cache_addb(0x50+genreg->index); - cache_addb(0x50); // push eax - if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_writeb_checked) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,8 - cache_addb(0x08); - cache_addw(0x012c); // sub al,1 - cache_addb(0x5a); // pop edx - - // Restore registers to be used again - x86gen.regs[X86_REG_EAX]->notusable=false; - x86gen.regs[X86_REG_ECX]->notusable=false; - - dyn_check_bool_exception_ne(); - - gen_fill_jump(jmp_loc); -} - -static void dyn_write_byte_release(DynReg * addr,DynReg * val,bool high) { - dyn_write_intro(addr); - - GenReg * genreg=FindDynReg(val); - cache_addw(0xe9c1); // shr ecx,0x0c - cache_addb(0x0c); - cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] - cache_addb(0x8d); - cache_addd((Bit32u)(&paging.tlb.write[0])); - cache_addw(0xc985); // test ecx,ecx - Bit8u* je_loc=gen_create_branch(BR_Z); - - cache_addw(0x0488+(genreg->index<<11)+(high?0x2000:0)); // mov [eax+ecx],reg - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(je_loc); - - cache_addb(0x52); // push edx - if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); - cache_addb(0x50+genreg->index); - cache_addb(0x50); // push eax - if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_writeb_checked) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,8 - cache_addb(0x08); - cache_addw(0x012c); // sub al,1 - cache_addb(0x5a); // pop edx - - // Restore registers to be used again - x86gen.regs[X86_REG_EAX]->notusable=false; - x86gen.regs[X86_REG_ECX]->notusable=false; - - dyn_check_bool_exception_ne(); - - gen_fill_jump(jmp_loc); -} - -static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { - if (dword) { - dyn_write_intro(addr,false); - - GenReg * genreg=FindDynReg(val); - cache_addw(0xe9d1); // shr ecx,0x1 - Bit8u* jb_loc1=gen_create_branch(BR_B); - cache_addw(0xe9d1); // shr ecx,0x1 - Bit8u* jb_loc2=gen_create_branch(BR_B); - cache_addw(0xe9c1); // shr ecx,0x0a - cache_addb(0x0a); - cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] - cache_addb(0x8d); - cache_addd((Bit32u)(&paging.tlb.write[0])); - cache_addw(0xc985); // test ecx,ecx - Bit8u* je_loc=gen_create_branch(BR_Z); - - cache_addw(0x0489+(genreg->index <<(8+3))); // mov [eax+ecx],reg - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(jb_loc1); - gen_fill_branch(jb_loc2); - gen_fill_branch(je_loc); - - cache_addb(0x52); // push edx - cache_addb(0x50+genreg->index); - cache_addb(0x50); // push eax - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_writed_checked) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,8 - cache_addb(0x08); - cache_addw(0x012c); // sub al,1 - cache_addb(0x5a); // pop edx - - // Restore registers to be used again - x86gen.regs[X86_REG_EAX]->notusable=false; - x86gen.regs[X86_REG_ECX]->notusable=false; - - dyn_check_bool_exception_ne(); - - gen_fill_jump(jmp_loc); - } else { - gen_protectflags(); - gen_call_function((void *)&mem_writew_checked,"%Dd%Dd",addr,val); - dyn_check_bool_exception_al(); - } -} - -static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) { - if (dword) { - dyn_write_intro(addr); - - GenReg * genreg=FindDynReg(val); - cache_addw(0xe9d1); // shr ecx,0x1 - Bit8u* jb_loc1=gen_create_branch(BR_B); - cache_addw(0xe9d1); // shr ecx,0x1 - Bit8u* jb_loc2=gen_create_branch(BR_B); - cache_addw(0xe9c1); // shr ecx,0x0a - cache_addb(0x0a); - cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] - cache_addb(0x8d); - cache_addd((Bit32u)(&paging.tlb.write[0])); - cache_addw(0xc985); // test ecx,ecx - Bit8u* je_loc=gen_create_branch(BR_Z); - - cache_addw(0x0489+(genreg->index <<(8+3))); // mov [eax+ecx],reg - cache_addb(0x08); - - Bit8u* jmp_loc=gen_create_jump(); - gen_fill_branch(jb_loc1); - gen_fill_branch(jb_loc2); - gen_fill_branch(je_loc); - - cache_addb(0x52); // push edx - cache_addb(0x50+genreg->index); - cache_addb(0x50); // push eax - cache_addb(0xe8); - cache_addd(((Bit32u)&mem_writed_checked) - (Bit32u)cache.pos-4); - cache_addw(0xc483); // add esp,8 - cache_addb(0x08); - cache_addw(0x012c); // sub al,1 - cache_addb(0x5a); // pop edx - - // Restore registers to be used again - x86gen.regs[X86_REG_EAX]->notusable=false; - x86gen.regs[X86_REG_ECX]->notusable=false; - - dyn_check_bool_exception_ne(); - - gen_fill_jump(jmp_loc); - } else { - gen_protectflags(); - gen_call_function((void *)&mem_writew_checked,"%Ddr%Dd",addr,val); - dyn_check_bool_exception_al(); - } -} - -#endif - - -static void dyn_push_unchecked(DynReg * dynreg) { - gen_protectflags(); - gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2)); - gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); - gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask); - gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK)); - gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); - if (decode.big_op) { - gen_call_function((void *)&mem_writed,"%Drd%Dd",DREG(STACK),dynreg); - } else { - //Can just push the whole 32-bit word as operand - gen_call_function((void *)&mem_writew,"%Drd%Dd",DREG(STACK),dynreg); - } -} - -static void dyn_push(DynReg * dynreg) { - gen_protectflags(); - gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2)); - gen_dop_word(DOP_MOV,true,DREG(NEWESP),DREG(ESP)); - gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); - gen_dop_word_var(DOP_AND,true,DREG(NEWESP),&cpu.stack.notmask); - gen_dop_word(DOP_OR,true,DREG(NEWESP),DREG(STACK)); - gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); - if (decode.big_op) { - gen_call_function((void *)&mem_writed_checked,"%Drd%Dd",DREG(STACK),dynreg); - } else { - //Can just push the whole 32-bit word as operand - gen_call_function((void *)&mem_writew_checked,"%Drd%Dd",DREG(STACK),dynreg); - } - dyn_check_bool_exception_al(); - /* everything was ok, change register now */ - gen_dop_word(DOP_MOV,true,DREG(ESP),DREG(NEWESP)); - gen_releasereg(DREG(NEWESP)); -} - -static void dyn_pop(DynReg * dynreg,bool checked=true) { - gen_protectflags(); - gen_dop_word(DOP_MOV,true,DREG(STACK),DREG(ESP)); - gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); - gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); - if (checked) { - if (decode.big_op) { - gen_call_function((void *)&mem_readd_checked,"%Drd%Id",DREG(STACK),&core_dyn.readdata); - } else { - gen_call_function((void *)&mem_readw_checked,"%Drd%Id",DREG(STACK),&core_dyn.readdata); - } - dyn_check_bool_exception_al(); - gen_mov_host(&core_dyn.readdata,dynreg,decode.big_op?4:2); - } else { - if (decode.big_op) { - gen_call_function((void *)&mem_readd,"%Rd%Drd",dynreg,DREG(STACK)); - } else { - gen_call_function((void *)&mem_readw,"%Rw%Drd",dynreg,DREG(STACK)); - } - } - if (dynreg!=DREG(ESP)) { - gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?4:2); - gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); - gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask); - gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK)); - } -} - -static INLINE void dyn_get_modrm(void) { - decode.modrm.val=decode_fetchb(); - decode.modrm.mod=(decode.modrm.val >> 6) & 3; - decode.modrm.reg=(decode.modrm.val >> 3) & 7; - decode.modrm.rm=(decode.modrm.val & 7); -} - -static void dyn_fill_ea(bool addseg=true, DynReg * reg_ea=DREG(EA)) { - DynReg * segbase; - if (!decode.big_addr) { - Bits imm; - switch (decode.modrm.mod) { - case 0:imm=0;break; - case 1:imm=(Bit8s)decode_fetchb();break; - case 2:imm=(Bit16s)decode_fetchw();break; - } - DynReg * extend_src=reg_ea; - switch (decode.modrm.rm) { - case 0:/* BX+SI */ - gen_lea(reg_ea,DREG(EBX),DREG(ESI),0,imm); - segbase=DREG(DS); - break; - case 1:/* BX+DI */ - gen_lea(reg_ea,DREG(EBX),DREG(EDI),0,imm); - segbase=DREG(DS); - break; - case 2:/* BP+SI */ - gen_lea(reg_ea,DREG(EBP),DREG(ESI),0,imm); - segbase=DREG(SS); - break; - case 3:/* BP+DI */ - gen_lea(reg_ea,DREG(EBP),DREG(EDI),0,imm); - segbase=DREG(SS); - break; - case 4:/* SI */ - if (imm) gen_lea(reg_ea,DREG(ESI),0,0,imm); - else extend_src=DREG(ESI); - segbase=DREG(DS); - break; - case 5:/* DI */ - if (imm) gen_lea(reg_ea,DREG(EDI),0,0,imm); - else extend_src=DREG(EDI); - segbase=DREG(DS); - break; - case 6:/* imm/BP */ - if (!decode.modrm.mod) { - imm=decode_fetchw(); - gen_dop_word_imm(DOP_MOV,true,reg_ea,imm); - segbase=DREG(DS); - goto skip_extend_word; - } else { - gen_lea(reg_ea,DREG(EBP),0,0,imm); - segbase=DREG(SS); - } - break; - case 7: /* BX */ - if (imm) gen_lea(reg_ea,DREG(EBX),0,0,imm); - else extend_src=DREG(EBX); - segbase=DREG(DS); - break; - } - gen_extend_word(false,reg_ea,extend_src); -skip_extend_word: - if (addseg) { - gen_lea(reg_ea,reg_ea,decode.segprefix ? decode.segprefix : segbase,0,0); - } - } else { - Bits imm=0; - DynReg * base=0;DynReg * scaled=0;Bitu scale=0; - switch (decode.modrm.rm) { - case 0:base=DREG(EAX);segbase=DREG(DS);break; - case 1:base=DREG(ECX);segbase=DREG(DS);break; - case 2:base=DREG(EDX);segbase=DREG(DS);break; - case 3:base=DREG(EBX);segbase=DREG(DS);break; - case 4: /* SIB */ - { - Bitu sib=decode_fetchb(); - static DynReg * scaledtable[8]={ - DREG(EAX),DREG(ECX),DREG(EDX),DREG(EBX), - 0,DREG(EBP),DREG(ESI),DREG(EDI), - }; - scaled=scaledtable[(sib >> 3) &7]; - scale=(sib >> 6); - switch (sib & 7) { - case 0:base=DREG(EAX);segbase=DREG(DS);break; - case 1:base=DREG(ECX);segbase=DREG(DS);break; - case 2:base=DREG(EDX);segbase=DREG(DS);break; - case 3:base=DREG(EBX);segbase=DREG(DS);break; - case 4:base=DREG(ESP);segbase=DREG(SS);break; - case 5: - if (decode.modrm.mod) { - base=DREG(EBP);segbase=DREG(SS); - } else { - segbase=DREG(DS); - Bitu val; - if (decode_fetchd_imm(val)) { - gen_mov_host((void*)val,DREG(EA),4); - if (!addseg) { - gen_lea(reg_ea,DREG(EA),scaled,scale,0); - } else { - DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase; - gen_lea(DREG(EA),DREG(EA),scaled,scale,0); - gen_lea(reg_ea,DREG(EA),*seg,0,0); - } - return; - } - imm=(Bit32s)val; - } - break; - case 6:base=DREG(ESI);segbase=DREG(DS);break; - case 7:base=DREG(EDI);segbase=DREG(DS);break; - } - } - break; /* SIB Break */ - case 5: - if (decode.modrm.mod) { - base=DREG(EBP);segbase=DREG(SS); - } else { - imm=(Bit32s)decode_fetchd();segbase=DREG(DS); - } - break; - case 6:base=DREG(ESI);segbase=DREG(DS);break; - case 7:base=DREG(EDI);segbase=DREG(DS);break; - } - switch (decode.modrm.mod) { - case 1:imm=(Bit8s)decode_fetchb();break; - case 2: { - Bitu val; - if (decode_fetchd_imm(val)) { - gen_mov_host((void*)val,DREG(EA),4); - if (!addseg) { - gen_lea(DREG(EA),DREG(EA),scaled,scale,0); - gen_lea(reg_ea,DREG(EA),base,0,0); - } else { - DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase; - if (!base) { - gen_lea(DREG(EA),DREG(EA),scaled,scale,0); - gen_lea(reg_ea,DREG(EA),*seg,0,0); - } else if (!scaled) { - gen_lea(DREG(EA),DREG(EA),*seg,0,0); - gen_lea(reg_ea,DREG(EA),base,0,0); - } else { - gen_lea(DREG(EA),DREG(EA),scaled,scale,0); - gen_lea(DREG(EA),DREG(EA),base,0,0); - gen_lea(reg_ea,DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0); - } - } - return; - } - - imm=(Bit32s)val; - break; - } - } - if (!addseg) { - gen_lea(reg_ea,base,scaled,scale,imm); - } else { - DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase; - if (!base) gen_lea(reg_ea,*seg,scaled,scale,imm); - else if (!scaled) gen_lea(reg_ea,base,*seg,0,imm); - else { - gen_lea(DREG(EA),base,scaled,scale,imm); - gen_lea(reg_ea,DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0); - } - } - } -} - - -static void dyn_dop_word_imm(DualOps op,bool dword,DynReg * dr1) { - Bitu val; - if (dword) { - if (decode_fetchd_imm(val)) { - gen_dop_word_imm_mem(op,true,dr1,(void*)val); - return; - } - } else { - if (decode_fetchw_imm(val)) { - gen_dop_word_imm_mem(op,false,dr1,(void*)val); - return; - } - } - gen_dop_word_imm(op,dword,dr1,val); -} - -static void dyn_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1) { - Bitu val; - if (decode_fetchb_imm(val)) { - gen_dop_byte_imm_mem(op,dr1,di1,(void*)val); - } else { - gen_dop_byte_imm(op,dr1,di1,(Bit8u)val); - } -} - - -#include "helpers.h" -#include "string.h" - - -static void dyn_dop_ebgb(DualOps op) { - dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); - dyn_read_byte(DREG(EA),DREG(TMPB),false); - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else set_skipflags(false); - } - gen_dop_byte(op,DREG(TMPB),0,rm_reg,decode.modrm.reg&4); - if (op!=DOP_CMP) dyn_write_byte_release(DREG(EA),DREG(TMPB),false); - else gen_releasereg(DREG(EA)); - gen_releasereg(DREG(TMPB)); - } else { - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else gen_discardflags(); - } - gen_dop_byte(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,decode.modrm.reg&4); - } -} - - -static void dyn_dop_gbeb(DualOps op) { - dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); - dyn_read_byte_release(DREG(EA),DREG(TMPB),false); - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else set_skipflags(false); - } - gen_dop_byte(op,rm_reg,decode.modrm.reg&4,DREG(TMPB),0); - gen_releasereg(DREG(TMPB)); - } else { - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else gen_discardflags(); - } - gen_dop_byte(op,rm_reg,decode.modrm.reg&4,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - } -} - -static void dyn_mov_ebib(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(); - gen_call_write(DREG(EA),decode_fetchb(),1); - dyn_check_bool_exception_al(); - } else { - gen_dop_byte_imm(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb()); - } -} - -static void dyn_mov_ebgb(void) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_write_byte_release(DREG(EA),rm_reg,rm_regi==4); - } else { - gen_dop_byte(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,rm_regi); - } -} - -static void dyn_mov_gbeb(void) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_read_byte_release(DREG(EA),rm_reg,rm_regi); - } else { - gen_dop_byte(DOP_MOV,rm_reg,rm_regi,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - } -} - -static void dyn_dop_evgv(DualOps op) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); - dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else set_skipflags(false); - } - gen_dop_word(op,decode.big_op,DREG(TMPW),rm_reg); - if (op!=DOP_CMP) dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); - else gen_releasereg(DREG(EA)); - gen_releasereg(DREG(TMPW)); - } else { - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else gen_discardflags(); - } - gen_dop_word(op,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); - } -} - -static void dyn_imul_gvev(Bitu immsize) { - dyn_get_modrm();DynReg * src; - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea();dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op); - src=DREG(TMPW); - } else { - src=&DynRegs[decode.modrm.rm]; - } - gen_needflags(); - switch (immsize) { - case 0:gen_imul_word(decode.big_op,rm_reg,src);break; - case 1:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit8s)decode_fetchb());break; - case 2:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit16s)decode_fetchw());break; - case 4:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit32s)decode_fetchd());break; - } - gen_releasereg(DREG(TMPW)); -} - -static void dyn_dop_gvev(DualOps op) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); - dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op); - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else set_skipflags(false); - } - gen_dop_word(op,decode.big_op,rm_reg,DREG(TMPW)); - gen_releasereg(DREG(TMPW)); - } else { - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else gen_discardflags(); - } - gen_dop_word(op,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); - } -} - -static void dyn_mov_evgv(void) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_write_word_release(DREG(EA),rm_reg,decode.big_op); - } else { - gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); - } -} - -static void dyn_mov_gvev(void) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_read_word_release(DREG(EA),rm_reg,decode.big_op); - } else { - gen_dop_word(DOP_MOV,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); - } -} -static void dyn_mov_eviv(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(); - gen_call_write(DREG(EA),decode.big_op ? decode_fetchd() : decode_fetchw(),decode.big_op?4:2); - dyn_check_bool_exception_al(); - } else { - gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],decode.big_op ? decode_fetchd() : decode_fetchw()); - } -} - -static void dyn_mov_ev_gb(bool sign) { - dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_read_byte_release(DREG(EA),DREG(TMPB),false); - gen_extend_byte(sign,decode.big_op,rm_reg,DREG(TMPB),0); - gen_releasereg(DREG(TMPB)); - } else { - gen_extend_byte(sign,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - } -} - -static void dyn_mov_ev_gw(bool sign) { - if (!decode.big_op) { - dyn_mov_gvev(); - return; - } - dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_read_word_release(DREG(EA),DREG(TMPW),false); - gen_extend_word(sign,rm_reg,DREG(TMPW)); - gen_releasereg(DREG(TMPW)); - } else { - gen_extend_word(sign,rm_reg,&DynRegs[decode.modrm.rm]); - } -} - -static void dyn_cmpxchg_evgv(void) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - gen_protectflags(); - if (decode.modrm.mod<3) { - gen_releasereg(DREG(EAX)); - gen_releasereg(DREG(TMPB)); - gen_releasereg(rm_reg); - - dyn_fill_ea(); - dyn_read_word(DREG(EA),DREG(TMPB),decode.big_op); - gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),DREG(TMPB)); - Bit8u * branch=gen_create_branch(BR_NZ); - - // eax==mem -> mem:=rm_reg - dyn_write_word_release(DREG(EA),rm_reg,decode.big_op); - gen_setzeroflag(); - gen_releasereg(DREG(EAX)); - gen_releasereg(DREG(TMPB)); - gen_releasereg(rm_reg); - - Bit8u * jump=gen_create_jump(); - - gen_fill_branch(branch); - // eax!=mem -> eax:=mem - dyn_write_word_release(DREG(EA),DREG(TMPB),decode.big_op); // cmpxchg always issues write - gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),DREG(TMPB)); - gen_clearzeroflag(); - gen_releasereg(DREG(EAX)); - gen_releasereg(DREG(TMPB)); - gen_releasereg(rm_reg); - - gen_fill_jump(jump); - } else { - gen_releasereg(DREG(EAX)); - gen_releasereg(&DynRegs[decode.modrm.rm]); - gen_releasereg(rm_reg); - - gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]); - Bit8u * branch=gen_create_branch(BR_NZ); - - // eax==rm -> rm:=rm_reg - gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); - gen_setzeroflag(); - gen_releasereg(DREG(EAX)); - gen_releasereg(&DynRegs[decode.modrm.rm]); - gen_releasereg(rm_reg); - - Bit8u * jump=gen_create_jump(); - - gen_fill_branch(branch); - // eax!=rm -> eax:=rm - gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]); - gen_clearzeroflag(); - gen_releasereg(DREG(EAX)); - gen_releasereg(&DynRegs[decode.modrm.rm]); - gen_releasereg(rm_reg); - - gen_fill_jump(jump); - } -} - -static void dyn_dshift_ev_gv(bool left,bool immediate) { - dyn_get_modrm(); - DynReg * rm_reg=&DynRegs[decode.modrm.reg]; - DynReg * ea_reg; - if (decode.modrm.mod<3) { - dyn_fill_ea();ea_reg=DREG(TMPW); - dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); - } else ea_reg=&DynRegs[decode.modrm.rm]; - gen_needflags(); - if (immediate) gen_dshift_imm(decode.big_op,left,ea_reg,rm_reg,decode_fetchb()); - else gen_dshift_cl(decode.big_op,left,ea_reg,rm_reg,DREG(ECX)); - if (decode.modrm.mod<3) { - dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); - gen_releasereg(DREG(TMPW)); - } -} - - -static DualOps grp1_table[8]={DOP_ADD,DOP_OR,DOP_ADC,DOP_SBB,DOP_AND,DOP_SUB,DOP_XOR,DOP_CMP}; -static void dyn_grp1_eb_ib(void) { - dyn_get_modrm(); - DualOps op=grp1_table[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); - dyn_read_byte(DREG(EA),DREG(TMPB),false); - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else set_skipflags(false); - } - gen_dop_byte_imm(op,DREG(TMPB),0,decode_fetchb()); - if (op!=DOP_CMP) dyn_write_byte_release(DREG(EA),DREG(TMPB),false); - else gen_releasereg(DREG(EA)); - gen_releasereg(DREG(TMPB)); - } else { - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else gen_discardflags(); - } - dyn_dop_byte_imm(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - } -} - -static void dyn_grp1_ev_ivx(bool withbyte) { - dyn_get_modrm(); - DualOps op=grp1_table[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); - dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else set_skipflags(false); - } - if (!withbyte) { - dyn_dop_word_imm(op,decode.big_op,DREG(TMPW)); - } else { - gen_dop_word_imm(op,decode.big_op,DREG(TMPW),(Bit8s)decode_fetchb()); - } - if (op!=DOP_CMP) dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); - else gen_releasereg(DREG(EA)); - gen_releasereg(DREG(TMPW)); - } else { - if (op<=DOP_TEST) { - if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); - else gen_discardflags(); - } - if (!withbyte) { - dyn_dop_word_imm(op,decode.big_op,&DynRegs[decode.modrm.rm]); - } else { - gen_dop_word_imm(op,decode.big_op,&DynRegs[decode.modrm.rm],(Bit8s)decode_fetchb()); - } - } -} - -enum grp2_types { - grp2_1,grp2_imm,grp2_cl, -}; - -static void dyn_grp2_eb(grp2_types type) { - dyn_get_modrm();DynReg * src;Bit8u src_i; - if (decode.modrm.mod<3) { - dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); - src=DREG(TMPB); - src_i=0; - } else { - src=&DynRegs[decode.modrm.rm&3]; - src_i=decode.modrm.rm&4; - } - switch (type) { - case grp2_1: - /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ - if (decode.modrm.reg < 4) gen_needflags(); - else gen_discardflags(); - gen_shift_byte_imm(decode.modrm.reg,src,src_i,1); - break; - case grp2_imm: { - Bit8u imm=decode_fetchb(); - if (imm) { - /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ - if (decode.modrm.reg < 4) gen_needflags(); - else gen_discardflags(); - gen_shift_byte_imm(decode.modrm.reg,src,src_i,imm); - } else return; - } - break; - case grp2_cl: - gen_needflags(); /* flags must not be changed on ecx==0 */ - gen_shift_byte_cl (decode.modrm.reg,src,src_i,DREG(ECX)); - break; - } - if (decode.modrm.mod<3) { - dyn_write_byte_release(DREG(EA),src,false); - gen_releasereg(src); - } -} - -static void dyn_grp2_ev(grp2_types type) { - 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); - } else { - src=&DynRegs[decode.modrm.rm]; - } - switch (type) { - case grp2_1: - /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ - if (decode.modrm.reg < 4) gen_needflags(); - else gen_discardflags(); - gen_shift_word_imm(decode.modrm.reg,decode.big_op,src,1); - break; - case grp2_imm: { - Bitu val; - if (decode_fetchb_imm(val)) { - if (decode.modrm.reg < 4) gen_needflags(); - else gen_discardflags(); - gen_load_host((void*)val,DREG(TMPB),1); - gen_shift_word_cl(decode.modrm.reg,decode.big_op,src,DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - break; - } - Bit8u imm=(Bit8u)val; - if (imm) { - /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ - if (decode.modrm.reg < 4) gen_needflags(); - else gen_discardflags(); - gen_shift_word_imm(decode.modrm.reg,decode.big_op,src,imm); - } else return; - } - break; - case grp2_cl: - gen_needflags(); /* flags must not be changed on ecx==0 */ - gen_shift_word_cl (decode.modrm.reg,decode.big_op,src,DREG(ECX)); - break; - } - if (decode.modrm.mod<3) { - dyn_write_word_release(DREG(EA),src,decode.big_op); - gen_releasereg(src); - } -} - -static void dyn_grp3_eb(void) { - dyn_get_modrm();DynReg * src;Bit8u src_i; - if (decode.modrm.mod<3) { - dyn_fill_ea(); - if ((decode.modrm.reg==0) || (decode.modrm.reg==3)) set_skipflags(true); - dyn_read_byte(DREG(EA),DREG(TMPB),false); - src=DREG(TMPB);src_i=0; - } else { - src=&DynRegs[decode.modrm.rm&3]; - src_i=decode.modrm.rm&4; - } - switch (decode.modrm.reg) { - case 0x0: /* test eb,ib */ - set_skipflags(false);gen_dop_byte_imm(DOP_TEST,src,src_i,decode_fetchb()); - goto skipsave; - case 0x2: /* NOT Eb */ - gen_sop_byte(SOP_NOT,src,src_i); - break; - case 0x3: /* NEG Eb */ - set_skipflags(false);gen_sop_byte(SOP_NEG,src,src_i); - break; - case 0x4: /* mul Eb */ - gen_needflags();gen_mul_byte(false,DREG(EAX),src,src_i); - goto skipsave; - case 0x5: /* imul Eb */ - gen_needflags();gen_mul_byte(true,DREG(EAX),src,src_i); - goto skipsave; - case 0x6: /* div Eb */ - case 0x7: /* idiv Eb */ - /* EAX could be used, so precache it */ - if (decode.modrm.mod==3) - gen_dop_byte(DOP_MOV,DREG(TMPB),0,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - gen_releasereg(DREG(EAX)); - gen_call_function((decode.modrm.reg==6) ? (void *)&dyn_helper_divb : (void *)&dyn_helper_idivb, - "%Rd%Dd",DREG(TMPB),DREG(TMPB)); - dyn_check_bool_exception(DREG(TMPB)); - goto skipsave; - } - /* Save the result if memory op */ - if (decode.modrm.mod<3) dyn_write_byte_release(DREG(EA),src,false); -skipsave: - gen_releasereg(DREG(TMPB));gen_releasereg(DREG(EA)); -} - -static void dyn_grp3_ev(void) { - dyn_get_modrm();DynReg * src; - if (decode.modrm.mod<3) { - dyn_fill_ea();src=DREG(TMPW); - if ((decode.modrm.reg==0) || (decode.modrm.reg==3)) set_skipflags(true); - dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); - } else src=&DynRegs[decode.modrm.rm]; - switch (decode.modrm.reg) { - case 0x0: /* test ev,iv */ - set_skipflags(false);gen_dop_word_imm(DOP_TEST,decode.big_op,src,decode.big_op ? decode_fetchd() : decode_fetchw()); - goto skipsave; - case 0x2: /* NOT Ev */ - gen_sop_word(SOP_NOT,decode.big_op,src); - break; - case 0x3: /* NEG Eb */ - set_skipflags(false);gen_sop_word(SOP_NEG,decode.big_op,src); - break; - case 0x4: /* mul Eb */ - gen_needflags();gen_mul_word(false,DREG(EAX),DREG(EDX),decode.big_op,src); - goto skipsave; - case 0x5: /* imul Eb */ - gen_needflags();gen_mul_word(true,DREG(EAX),DREG(EDX),decode.big_op,src); - goto skipsave; - case 0x6: /* div Eb */ - case 0x7: /* idiv Eb */ - /* EAX could be used, so precache it */ - if (decode.modrm.mod==3) - gen_dop_word(DOP_MOV,decode.big_op,DREG(TMPW),&DynRegs[decode.modrm.rm]); - gen_releasereg(DREG(EAX));gen_releasereg(DREG(EDX)); - void * func=(decode.modrm.reg==6) ? - (decode.big_op ? (void *)&dyn_helper_divd : (void *)&dyn_helper_divw) : - (decode.big_op ? (void *)&dyn_helper_idivd : (void *)&dyn_helper_idivw); - gen_call_function(func,"%Rd%Dd",DREG(TMPB),DREG(TMPW)); - dyn_check_bool_exception(DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - goto skipsave; - } - /* Save the result if memory op */ - if (decode.modrm.mod<3) dyn_write_word_release(DREG(EA),src,decode.big_op); -skipsave: - gen_releasereg(DREG(TMPW));gen_releasereg(DREG(EA)); -} - -static void dyn_mov_ev_seg(void) { - dyn_get_modrm(); - gen_load_host(&Segs.val[decode.modrm.reg],DREG(TMPW),2); - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_write_word_release(DREG(EA),DREG(TMPW),false); - } else { - gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); - } - gen_releasereg(DREG(TMPW)); -} - -static void dyn_load_seg(SegNames seg,DynReg * src) { - gen_call_function((void *)&CPU_SetSegGeneral,"%Rd%Id%Drw",DREG(TMPB),seg,src); - dyn_check_bool_exception(DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - gen_releasereg(&DynRegs[G_ES+seg]); -} - -static void dyn_load_seg_off_ea(SegNames seg) { - if (decode.modrm.mod<3) { - dyn_fill_ea(); - gen_lea(DREG(TMPB),DREG(EA),0,0,decode.big_op ? 4:2); - dyn_read_word(DREG(TMPB),DREG(TMPB),false); - dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op); - dyn_load_seg(seg,DREG(TMPB));gen_releasereg(DREG(TMPB)); - gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(TMPW)); - } else { - IllegalOption("dyn_load_seg_off_ea"); - } -} - -static void dyn_mov_seg_ev(void) { - dyn_get_modrm(); - SegNames seg=(SegNames)decode.modrm.reg; - if (GCC_UNLIKELY(seg==cs)) IllegalOption("dyn_mov_seg_ev"); - if (decode.modrm.mod<3) { - dyn_fill_ea(); - dyn_read_word(DREG(EA),DREG(EA),false); - dyn_load_seg(seg,DREG(EA)); - gen_releasereg(DREG(EA)); - } else { - dyn_load_seg(seg,&DynRegs[decode.modrm.rm]); - } -} - -static void dyn_push_seg(SegNames seg) { - gen_load_host(&Segs.val[seg],DREG(TMPW),2); - dyn_push(DREG(TMPW)); - gen_releasereg(DREG(TMPW)); -} - -static void dyn_pop_seg(SegNames seg) { - gen_releasereg(DREG(ESP)); - gen_call_function((void *)&CPU_PopSeg,"%Rd%Id%Id",DREG(TMPB),seg,decode.big_op); - dyn_check_bool_exception(DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - gen_releasereg(&DynRegs[G_ES+seg]); - gen_releasereg(DREG(ESP)); -} - -static void dyn_pop_ev(void) { - dyn_pop(DREG(TMPW)); - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(); -// dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); - if (decode.big_op) gen_call_function((void *)&mem_writed_inline,"%Ddr%Dd",DREG(EA),DREG(TMPW)); - else gen_call_function((void *)&mem_writew_inline,"%Ddr%Dd",DREG(EA),DREG(TMPW)); - } else { - gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); - } - gen_releasereg(DREG(TMPW)); -} - -static void dyn_enter(void) { - gen_releasereg(DREG(ESP)); - gen_releasereg(DREG(EBP)); - Bitu bytes=decode_fetchw(); - Bitu level=decode_fetchb(); - gen_call_function((void *)&CPU_ENTER,"%Id%Id%Id",decode.big_op,bytes,level); -} - -static void dyn_leave(void) { - gen_protectflags(); - gen_dop_word_var(DOP_MOV,true,DREG(TMPW),&cpu.stack.mask); - gen_sop_word(SOP_NOT,true,DREG(TMPW)); - gen_dop_word(DOP_AND,true,DREG(ESP),DREG(TMPW)); - gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EBP)); - gen_dop_word_var(DOP_AND,true,DREG(TMPW),&cpu.stack.mask); - gen_dop_word(DOP_OR,true,DREG(ESP),DREG(TMPW)); - dyn_pop(DREG(EBP),false); - gen_releasereg(DREG(TMPW)); -} - -static void dyn_segprefix(SegNames seg) { -// if (GCC_UNLIKELY((Bitu)(decode.segprefix))) IllegalOption("dyn_segprefix"); - decode.segprefix=&DynRegs[G_ES+seg]; -} - -static void dyn_closeblock(void) { - //Shouldn't create empty block normally but let's do it like this - gen_protectflags(); - dyn_fill_blocks(); - cache_closeblock(); -} - -static void dyn_normal_exit(BlockReturn code) { - gen_protectflags(); - dyn_reduce_cycles(); - dyn_set_eip_last(); - dyn_save_critical_regs(); - gen_return(code); - dyn_closeblock(); -} - -static void dyn_exit_link(Bits eip_change) { - gen_protectflags(); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),(decode.code-decode.code_start)+eip_change); - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); - dyn_closeblock(); -} - -static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) { - Bitu eip_base=decode.code-decode.code_start; - gen_needflags(); - gen_protectflags(); - dyn_save_noncritical_regs(); - gen_releasereg(DREG(FLAGS)); - gen_releasereg(DREG(EIP)); - - gen_preloadreg(DREG(CYCLES)); - gen_preloadreg(DREG(EIP)); - DynReg save_cycles,save_eip; - dyn_saveregister(DREG(CYCLES),&save_cycles); - dyn_saveregister(DREG(EIP),&save_eip); - Bit8u * data=gen_create_branch(btype); - - /* 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 { - LOOP_NONE,LOOP_NE,LOOP_E,LOOP_JCXZ -}; - -static void dyn_loop(LoopTypes type) { - dyn_reduce_cycles(); - Bits eip_add=(Bit8s)decode_fetchb(); - Bitu eip_base=decode.code-decode.code_start; - Bit8u * branch1=0;Bit8u * branch2=0; - dyn_save_critical_regs(); - switch (type) { - case LOOP_E: - gen_needflags(); - branch1=gen_create_branch(BR_NZ); - break; - case LOOP_NE: - gen_needflags(); - branch1=gen_create_branch(BR_Z); - break; - } - gen_protectflags(); - switch (type) { - case LOOP_E: - case LOOP_NE: - case LOOP_NONE: - gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); - gen_releasereg(DREG(ECX)); - branch2=gen_create_branch(BR_Z); - break; - case LOOP_JCXZ: - gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX)); - gen_releasereg(DREG(ECX)); - branch2=gen_create_branch(BR_NZ); - break; - } - gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add); - gen_releasereg(DREG(EIP)); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); - if (branch1) { - gen_fill_branch(branch1); - gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); - gen_releasereg(DREG(ECX)); - } - /* Branch taken */ - gen_fill_branch(branch2); - gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base); - gen_releasereg(DREG(EIP)); - gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start)); - dyn_closeblock(); -} - -static void dyn_ret_near(Bitu bytes) { - gen_protectflags(); - dyn_reduce_cycles(); - dyn_pop(DREG(EIP)); - if (bytes) gen_dop_word_imm(DOP_ADD,true,DREG(ESP),bytes); - dyn_save_critical_regs(); - gen_return(BR_Normal); - dyn_closeblock(); -} - -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(DREG(TMPW)); - dyn_push(DREG(TMPW)); - gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(TMPW),imm); - if (cpu.code.big) gen_dop_word(DOP_MOV,true,DREG(EIP),DREG(TMPW)); - else gen_extend_word(false,DREG(EIP),DREG(TMPW)); - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); - dyn_closeblock(); -} - -static void dyn_ret_far(Bitu bytes) { - gen_protectflags(); - dyn_reduce_cycles(); - dyn_set_eip_last_end(DREG(TMPW)); - dyn_flags_gen_to_host(); - dyn_save_critical_regs(); - gen_call_function((void*)&CPU_RET,"%Id%Id%Drd",decode.big_op,bytes,DREG(TMPW)); - gen_return_fast(BR_Normal); - dyn_closeblock(); -} - -static void dyn_call_far_imm(void) { - Bitu sel,off; - off=decode.big_op ? decode_fetchd() : decode_fetchw(); - sel=decode_fetchw(); - dyn_reduce_cycles(); - dyn_set_eip_last_end(DREG(TMPW)); - 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)); - gen_return_fast(BR_Normal); - dyn_closeblock(); -} - -static void dyn_jmp_far_imm(void) { - Bitu sel,off; - gen_protectflags(); - off=decode.big_op ? decode_fetchd() : decode_fetchw(); - sel=decode_fetchw(); - dyn_reduce_cycles(); - dyn_set_eip_last_end(DREG(TMPW)); - 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)); - gen_return_fast(BR_Normal); - dyn_closeblock(); -} - -static void dyn_iret(void) { - gen_protectflags(); - dyn_flags_gen_to_host(); - dyn_reduce_cycles(); - dyn_set_eip_last_end(DREG(TMPW)); - dyn_save_critical_regs(); - gen_call_function((void*)&CPU_IRET,"%Id%Drd",decode.big_op,DREG(TMPW)); - gen_return_fast(BR_Iret); - dyn_closeblock(); -} - -static void dyn_interrupt(Bitu num) { - gen_protectflags(); - dyn_flags_gen_to_host(); - dyn_reduce_cycles(); - 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)); - gen_return_fast(BR_Normal); - dyn_closeblock(); -} - -static void dyn_add_iocheck(Bitu access_size) { - gen_call_function((void *)&CPU_IO_Exception,"%Dw%Id",DREG(EDX),access_size); - dyn_check_bool_exception_al(); -} - -static void dyn_add_iocheck_var(Bit8u accessed_port,Bitu access_size) { - gen_call_function((void *)&CPU_IO_Exception,"%Id%Id",accessed_port,access_size); - dyn_check_bool_exception_al(); -} - -#ifdef X86_DYNFPU_DH_ENABLED -#include "dyn_fpu_dh.h" -#define dh_fpu_startup() { \ - fpu_used=true; \ - gen_protectflags(); \ - gen_load_host(&dyn_dh_fpu.state_used,DREG(TMPB),4); \ - gen_dop_word_imm(DOP_CMP,true,DREG(TMPB),0); \ - gen_releasereg(DREG(TMPB)); \ - save_info[used_save_info].branch_pos=gen_create_branch_long(BR_Z); \ - dyn_savestate(&save_info[used_save_info].state); \ - save_info[used_save_info].return_pos=cache.pos; \ - save_info[used_save_info].type=fpu_restore; \ - used_save_info++; \ -} -#endif -#include "dyn_fpu.h" - -static CacheBlock * CreateCacheBlock(CodePageHandler * codepage,PhysPt start,Bitu max_opcodes) { - Bits i; -/* Init a load of variables */ - decode.code_start=start; - decode.code=start; - Bitu cycles=0; - decode.page.code=codepage; - decode.page.index=start&4095; - decode.page.wmap=codepage->write_map; - decode.page.invmap=codepage->invalidation_map; - decode.page.first=start >> 12; - decode.active_block=decode.block=cache_openblock(); - decode.block->page.start=decode.page.index; - codepage->AddCacheBlock(decode.block); - - gen_save_host_direct(&cache.block.running,(Bit32u)decode.block); - for (i=0;i=4)) goto illegalopcode; - opcode=decode_fetchb(); - } else { - opcode=decode_fetchb(); - if (GCC_UNLIKELY(decode.page.invmap && - (decode.page.invmap[decode.page.index-1]>=4))) goto illegalopcode; - } - } - switch (opcode) { - - case 0x00:dyn_dop_ebgb(DOP_ADD);break; - 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_discardflags();gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break; - case 0x05:gen_discardflags();dyn_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX));break; - case 0x06:dyn_push_seg(es);break; - case 0x07:dyn_pop_seg(es);break; - - case 0x08:dyn_dop_ebgb(DOP_OR);break; - 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_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: - { - Bitu dual_code=decode_fetchb(); - switch (dual_code) { - /* Short conditional jumps */ - case 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87: - case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f: - dyn_branched_exit((BranchTypes)(dual_code&0xf), - decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); - goto finish_block; - /* PUSH/POP FS */ - case 0xa0:dyn_push_seg(fs);break; - case 0xa1:dyn_pop_seg(fs);break; - /* SHLD Imm/cl*/ - case 0xa4:dyn_dshift_ev_gv(true,true);break; - case 0xa5:dyn_dshift_ev_gv(true,false);break; - /* PUSH/POP GS */ - case 0xa8:dyn_push_seg(gs);break; - case 0xa9:dyn_pop_seg(gs);break; - /* SHRD Imm/cl*/ - case 0xac:dyn_dshift_ev_gv(false,true);break; - case 0xad:dyn_dshift_ev_gv(false,false);break; - /* Imul Ev,Gv */ - case 0xaf:dyn_imul_gvev(0);break; - /* CMPXCHG */ - case 0xb1:dyn_cmpxchg_evgv();break; - /* LFS,LGS */ - case 0xb4: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(fs); - break; - case 0xb5: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(gs); - break; - /* MOVZX Gv,Eb/Ew */ - case 0xb6:dyn_mov_ev_gb(false);break; - case 0xb7:dyn_mov_ev_gw(false);break; - /* MOVSX Gv,Eb/Ew */ - case 0xbe:dyn_mov_ev_gb(true);break; - case 0xbf:dyn_mov_ev_gw(true);break; - - default: - DYN_LOG("Unhandled dual opcode 0F%02X",dual_code); - goto illegalopcode; - } - }break; - - case 0x10:dyn_dop_ebgb(DOP_ADC);break; - 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_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; - - case 0x18:dyn_dop_ebgb(DOP_SBB);break; - 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_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_discardflags();gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break; - case 0x25:gen_discardflags();dyn_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX));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_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_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_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_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_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: - dyn_push(&DynRegs[opcode&7]); - break; - case 0x54: /* PUSH SP is special */ - gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP)); - dyn_push(DREG(TMPW)); - gen_releasereg(DREG(TMPW)); - break; - case 0x58:case 0x59:case 0x5a:case 0x5b:case 0x5c:case 0x5d:case 0x5e:case 0x5f: - dyn_pop(&DynRegs[opcode&7]); - break; - case 0x60: /* PUSHA */ - gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP)); - for (i=G_EAX;i<=G_EDI;i++) { - 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),false); - } - gen_releasereg(DREG(TMPW)); - break; - //segprefix FS,GS - case 0x64:dyn_segprefix(fs);goto restart_prefix; - case 0x65:dyn_segprefix(gs);goto restart_prefix; - //Push immediates - //Operand size - case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix; - //Address size - case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix; - case 0x68: /* PUSH Iv */ - gen_dop_word_imm(DOP_MOV,decode.big_op,DREG(TMPW),decode.big_op ? decode_fetchd() : decode_fetchw()); - dyn_push(DREG(TMPW)); - gen_releasereg(DREG(TMPW)); - break; - /* Imul Ivx */ - case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break; - case 0x6a: /* PUSH Ibx */ - gen_dop_word_imm(DOP_MOV,true,DREG(TMPW),(Bit8s)decode_fetchb()); - dyn_push(DREG(TMPW)); - gen_releasereg(DREG(TMPW)); - break; - /* Imul Ibx */ - case 0x6b:dyn_imul_gvev(1);break; - /* Short conditional jumps */ - case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77: - case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f: - dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb()); - goto finish_block; - /* Group 1 */ - case 0x80:dyn_grp1_eb_ib();break; - case 0x81:dyn_grp1_ev_ivx(false);break; - case 0x82:dyn_grp1_eb_ib();break; - case 0x83:dyn_grp1_ev_ivx(true);break; - /* TEST Gb,Eb Gv,Ev */ - case 0x84:dyn_dop_gbeb(DOP_TEST);break; - case 0x85:dyn_dop_gvev(DOP_TEST);break; - /* XCHG Eb,Gb Ev,Gv */ - case 0x86:dyn_dop_ebgb(DOP_XCHG);break; - case 0x87:dyn_dop_evgv(DOP_XCHG);break; - /* MOV e,g and g,e */ - case 0x88:dyn_mov_ebgb();break; - case 0x89:dyn_mov_evgv();break; - case 0x8a:dyn_mov_gbeb();break; - case 0x8b:dyn_mov_gvev();break; - /* MOV ev,seg */ - case 0x8c:dyn_mov_ev_seg();break; - /* LEA Gv */ - case 0x8d: - 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; - /* POP Ev */ - case 0x8f:dyn_pop_ev();break; - case 0x90: //NOP - case 0x9b: //WAIT/FWAIT - break; - //XCHG ax,reg - case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: - gen_dop_word(DOP_XCHG,decode.big_op,DREG(EAX),&DynRegs[opcode&07]); - break; - /* CBW/CWDE */ - case 0x98: - gen_cbw(decode.big_op,DREG(EAX)); - break; - /* CWD/CDQ */ - case 0x99: - gen_cwd(decode.big_op,DREG(EAX),DREG(EDX)); - break; - /* CALL FAR Ip */ - case 0x9a:dyn_call_far_imm();goto finish_block; - case 0x9c: //PUSHF - gen_protectflags(); - gen_releasereg(DREG(ESP)); - dyn_flags_gen_to_host(); - gen_call_function((void *)&CPU_PUSHF,"%Rd%Id",DREG(TMPB),decode.big_op); - dyn_check_bool_exception(DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - break; - case 0x9d: //POPF - gen_releasereg(DREG(ESP)); - gen_releasereg(DREG(FLAGS)); - gen_call_function((void *)&CPU_POPF,"%Rd%Id",DREG(TMPB),decode.big_op); - dyn_check_bool_exception(DREG(TMPB)); - dyn_flags_host_to_gen(); - gen_releasereg(DREG(TMPB)); - dyn_check_irqrequest(); - break; - /* MOV AL,direct addresses */ - case 0xa0: - gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, - decode.big_addr ? decode_fetchd() : decode_fetchw()); - 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_release(DREG(EA),DREG(EAX),decode.big_op); - break; - /* MOV direct address,AL */ - case 0xa2: - if (decode.big_addr) { - Bitu val; - if (decode_fetchd_imm(val)) { - gen_lea_imm_mem(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),(void*)val); - } else { - gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,(Bits)val); - } - dyn_write_byte_release(DREG(EA),DREG(EAX),false); - } else { - gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,decode_fetchw()); - 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_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_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; - /* LODSB/W/D*/ - case 0xac:dyn_string(STR_LODSB);break; - case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break; - //Mov Byte reg,Imm byte - case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7: - gen_dop_byte_imm(DOP_MOV,&DynRegs[opcode&3],opcode&4,decode_fetchb()); - break; - //Mov word reg imm byte,word, - case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf: - if (decode.big_op) { - dyn_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7]);break; - } else { - gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7],decode_fetchw());break; - } - break; - //GRP2 Eb/Ev,Ib - case 0xc0:dyn_grp2_eb(grp2_imm);break; - case 0xc1:dyn_grp2_ev(grp2_imm);break; - //RET near Iw / Ret - case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block; - case 0xc3:dyn_ret_near(0);goto finish_block; - //LES - case 0xc4: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(es); - break; - //LDS - case 0xc5: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(ds); - break; - // MOV Eb/Ev,Ib/Iv - case 0xc6:dyn_mov_ebib();break; - case 0xc7:dyn_mov_eviv();break; - //ENTER and LEAVE - case 0xc8:dyn_enter();break; - case 0xc9:dyn_leave();break; - //RET far Iw / Ret - case 0xca:dyn_ret_far(decode_fetchw());goto finish_block; - case 0xcb:dyn_ret_far(0);goto finish_block; - /* Interrupt */ -// case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block; - /* IRET */ - case 0xcf:dyn_iret();goto finish_block; - - //GRP2 Eb/Ev,1 - case 0xd0:dyn_grp2_eb(grp2_1);break; - case 0xd1:dyn_grp2_ev(grp2_1);break; - //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: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc0(); - else { - dh_fpu_startup(); - dh_fpu_esc0(); - } - } else -#endif - dyn_fpu_esc0(); - break; - case 0xd9: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc1(); - else { - dh_fpu_startup(); - dh_fpu_esc1(); - } - } else -#endif - dyn_fpu_esc1(); - break; - case 0xda: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc2(); - else { - dh_fpu_startup(); - dh_fpu_esc2(); - } - } else -#endif - dyn_fpu_esc2(); - break; - case 0xdb: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc3(); - else { - dh_fpu_startup(); - dh_fpu_esc3(); - } - } else -#endif - dyn_fpu_esc3(); - break; - case 0xdc: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc4(); - else { - dh_fpu_startup(); - dh_fpu_esc4(); - } - } else -#endif - dyn_fpu_esc4(); - break; - case 0xdd: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc5(); - else { - dh_fpu_startup(); - dh_fpu_esc5(); - } - } else -#endif - dyn_fpu_esc5(); - break; - case 0xde: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc6(); - else { - dh_fpu_startup(); - dh_fpu_esc6(); - } - } else -#endif - dyn_fpu_esc6(); - break; - case 0xdf: -#ifdef X86_DYNFPU_DH_ENABLED - if (dyn_dh_fpu.dh_fpu_enabled) { - if (fpu_used) dh_fpu_esc7(); - else { - dh_fpu_startup(); - dh_fpu_esc7(); - } - } else -#endif - dyn_fpu_esc7(); - break; -#endif - //Loops - case 0xe2:dyn_loop(LOOP_NONE);goto finish_block; - case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block; - //IN AL/AX,imm - case 0xe4: { - Bitu port=decode_fetchb(); - dyn_add_iocheck_var(port,1); - gen_call_function((void*)&IO_ReadB,"%Id%Rl",port,DREG(EAX)); - } break; - case 0xe5: { - Bitu port=decode_fetchb(); - dyn_add_iocheck_var(port,decode.big_op?4:2); - if (decode.big_op) { - gen_call_function((void*)&IO_ReadD,"%Id%Rd",port,DREG(EAX)); - } else { - gen_call_function((void*)&IO_ReadW,"%Id%Rw",port,DREG(EAX)); - } - } break; - //OUT imm,AL - case 0xe6: { - Bitu port=decode_fetchb(); - dyn_add_iocheck_var(port,1); - gen_call_function((void*)&IO_WriteB,"%Id%Dl",port,DREG(EAX)); - } break; - case 0xe7: { - Bitu port=decode_fetchb(); - dyn_add_iocheck_var(port,decode.big_op?4:2); - if (decode.big_op) { - gen_call_function((void*)&IO_WriteD,"%Id%Dd",port,DREG(EAX)); - } else { - gen_call_function((void*)&IO_WriteW,"%Id%Dw",port,DREG(EAX)); - } - } break; - case 0xe8: /* CALL Ivx */ - dyn_call_near_imm(); - goto finish_block; - case 0xe9: /* Jmp Ivx */ - dyn_exit_link(decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); - goto finish_block; - case 0xea: /* JMP FAR Ip */ - dyn_jmp_far_imm(); - goto finish_block; - /* Jmp Ibx */ - case 0xeb:dyn_exit_link((Bit8s)decode_fetchb());goto finish_block; - /* IN AL/AX,DX*/ - case 0xec: - dyn_add_iocheck(1); - gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),DREG(EAX)); - break; - case 0xed: - dyn_add_iocheck(decode.big_op?4:2); - if (decode.big_op) { - gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),DREG(EAX)); - } else { - gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),DREG(EAX)); - } - break; - /* OUT DX,AL/AX */ - case 0xee: - dyn_add_iocheck(1); - gen_call_function((void*)&IO_WriteB,"%Dw%Dl",DREG(EDX),DREG(EAX)); - break; - case 0xef: - dyn_add_iocheck(decode.big_op?4:2); - if (decode.big_op) { - gen_call_function((void*)&IO_WriteD,"%Dw%Dd",DREG(EDX),DREG(EAX)); - } else { - gen_call_function((void*)&IO_WriteW,"%Dw%Dw",DREG(EDX),DREG(EAX)); - } - break; - case 0xf0: //LOCK - break; - case 0xf2: //REPNE/NZ - decode.rep=REP_NZ; - goto restart_prefix; - case 0xf3: //REPE/Z - decode.rep=REP_Z; - goto restart_prefix; - /* Change carry flag */ - case 0xf5: //CMC - case 0xf8: //CLC - case 0xf9: //STC - gen_needflags(); - cache_addb(opcode);break; - /* GRP 3 Eb/EV */ - case 0xf6:dyn_grp3_eb();break; - case 0xf7:dyn_grp3_ev();break; - /* Change interrupt flag */ - case 0xfa: //CLI - gen_releasereg(DREG(FLAGS)); - gen_call_function((void *)&CPU_CLI,"%Rd",DREG(TMPB)); - dyn_check_bool_exception(DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - break; - case 0xfb: //STI - gen_releasereg(DREG(FLAGS)); - gen_call_function((void *)&CPU_STI,"%Rd",DREG(TMPB)); - dyn_check_bool_exception(DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - dyn_check_irqrequest(); - if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode - break; - case 0xfc: //CLD - gen_protectflags(); - gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FLAG_DF); - gen_save_host_direct(&cpu.direction,1); - break; - case 0xfd: //STD - gen_protectflags(); - gen_dop_word_imm(DOP_OR,true,DREG(FLAGS),FLAG_DF); - gen_save_host_direct(&cpu.direction,-1); - break; - /* GRP 4 Eb and callback's */ - case 0xfe: - dyn_get_modrm(); - switch (decode.modrm.reg) { - case 0x0://INC Eb - case 0x1://DEC Eb - if (decode.modrm.mod<3) { - dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); - gen_needcarry(); - gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,DREG(TMPB),0); - dyn_write_byte_release(DREG(EA),DREG(TMPB),false); - gen_releasereg(DREG(TMPB)); - } else { - gen_needcarry(); - gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC, - &DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); - } - break; - case 0x7: //CALBACK Iw - gen_save_host_direct(&core_dyn.callback,decode_fetchw()); - dyn_set_eip_end(); - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_return(BR_CallBack); - dyn_closeblock(); - goto finish_block; - } - break; - - case 0xff: - { - 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); - } else src=&DynRegs[decode.modrm.rm]; - switch (decode.modrm.reg) { - case 0x0://INC Ev - case 0x1://DEC Ev - 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_release(DREG(EA),DREG(TMPW),decode.big_op); - gen_releasereg(DREG(TMPW)); - } - break; - case 0x2: /* CALL Ev */ - 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 */ - gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src); - goto core_close_block; - case 0x3: /* CALL Ep */ - case 0x5: /* JMP Ep */ - gen_protectflags(); - dyn_flags_gen_to_host(); - gen_lea(DREG(EA),DREG(EA),0,0,decode.big_op ? 4: 2); - 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, - decode.big_op ? "%Id%Drw%Drd%Drd" : "%Id%Drw%Drw%Drd", - decode.big_op,DREG(EA),DREG(TMPW),DREG(TMPB)); - dyn_flags_host_to_gen(); - goto core_close_block; - case 0x6: /* PUSH Ev */ - gen_releasereg(DREG(EA)); - dyn_push(src); - break; - default: - LOG(LOG_CPU,LOG_ERROR)("CPU:GRP5:Illegal opcode 0xff"); - goto illegalopcode; - }} - break; - default: -// DYN_LOG("Dynamic unhandled opcode %X",opcode); - goto illegalopcode; - } - } - // link to next block because the maximal number of opcodes has been reached - dyn_set_eip_end(); - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); - dyn_closeblock(); - goto finish_block; -core_close_block: - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_return(BR_Normal); - dyn_closeblock(); - goto finish_block; -illegalopcode: - dyn_set_eip_last(); - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_return(BR_Opcode); - dyn_closeblock(); - goto finish_block; -#if (C_DEBUG) - dyn_set_eip_last(); - dyn_reduce_cycles(); - dyn_save_critical_regs(); - gen_return(BR_OpcodeFull); - dyn_closeblock(); - goto finish_block; -#endif -finish_block: - /* Setup the correct end-address */ - decode.active_block->page.end=--decode.page.index; -// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end); - return decode.block; -} +/* + * Copyright (C) 2002-2010 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: decoder.h,v 1.59 2009-10-18 17:52:09 c2woody Exp $ */ + +#define X86_DYNFPU_DH_ENABLED +#define X86_INLINED_MEMACCESS + + +enum REP_Type { + REP_NONE=0,REP_NZ,REP_Z +}; + +static struct DynDecode { + PhysPt code; + PhysPt code_start; + PhysPt op_start; + bool big_op; + bool big_addr; + REP_Type rep; + Bitu cycles; + CacheBlock * block; + CacheBlock * active_block; + struct { + CodePageHandler * code; + Bitu index; + Bit8u * wmap; + Bit8u * invmap; + Bitu first; + } page; + struct { + Bitu val; + Bitu mod; + Bitu rm; + Bitu reg; + } modrm; + DynReg * segprefix; +} decode; + +static bool MakeCodePage(Bitu lin_addr,CodePageHandler * &cph) { + Bit8u rdval; + //Ensure page contains memory: + if (GCC_UNLIKELY(mem_readb_checked(lin_addr,&rdval))) return true; + PageHandler * handler=get_tlb_readhandler(lin_addr); + if (handler->flags & PFLAG_HASCODE) { + cph=( CodePageHandler *)handler; + return false; + } + if (handler->flags & PFLAG_NOCODE) { + if (PAGING_ForcePageInit(lin_addr)) { + handler=get_tlb_readhandler(lin_addr); + if (handler->flags & PFLAG_HASCODE) { + cph=( CodePageHandler *)handler; + return false; + } + } + if (handler->flags & PFLAG_NOCODE) { + LOG_MSG("DYNX86:Can't run code in this page!"); + cph=0; return false; + } + } + Bitu lin_page=lin_addr >> 12; + Bitu phys_page=lin_page; + if (!PAGING_MakePhysPage(phys_page)) { + LOG_MSG("DYNX86:Can't find physpage"); + cph=0; return false; + } + /* Find a free CodePage */ + if (!cache.free_pages) { + if (cache.used_pages!=decode.page.code) cache.used_pages->ClearRelease(); + else { + if ((cache.used_pages->next) && (cache.used_pages->next!=decode.page.code)) + cache.used_pages->next->ClearRelease(); + else { + LOG_MSG("DYNX86:Invalid cache links"); + cache.used_pages->ClearRelease(); + } + } + } + CodePageHandler * cpagehandler=cache.free_pages; + cache.free_pages=cache.free_pages->next; + cpagehandler->prev=cache.last_page; + cpagehandler->next=0; + if (cache.last_page) cache.last_page->next=cpagehandler; + cache.last_page=cpagehandler; + if (!cache.used_pages) cache.used_pages=cpagehandler; + cpagehandler->SetupAt(phys_page,handler); + MEM_SetPageHandler(phys_page,1,cpagehandler); + PAGING_UnlinkPages(lin_page,1); + cph=cpagehandler; + return false; +} + +static Bit8u decode_fetchb(void) { + if (GCC_UNLIKELY(decode.page.index>=4096)) { + /* Advance to the next page */ + decode.active_block->page.end=4095; + /* trigger possible page fault here */ + decode.page.first++; + Bitu fetchaddr=decode.page.first << 12; + mem_readb(fetchaddr); + MakeCodePage(fetchaddr,decode.page.code); + CacheBlock * newblock=cache_getblock(); + decode.active_block->crossblock=newblock; + newblock->crossblock=decode.active_block; + decode.active_block=newblock; + decode.active_block->page.start=0; + decode.page.code->AddCrossBlock(decode.active_block); + decode.page.wmap=decode.page.code->write_map; + decode.page.invmap=decode.page.code->invalidation_map; + decode.page.index=0; + } + decode.page.wmap[decode.page.index]+=0x01; + decode.page.index++; + decode.code+=1; + return mem_readb(decode.code-1); +} +static Bit16u decode_fetchw(void) { + if (GCC_UNLIKELY(decode.page.index>=4095)) { + Bit16u val=decode_fetchb(); + val|=decode_fetchb() << 8; + return val; + } + *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101; + decode.code+=2;decode.page.index+=2; + return mem_readw(decode.code-2); +} +static Bit32u decode_fetchd(void) { + if (GCC_UNLIKELY(decode.page.index>=4093)) { + Bit32u val=decode_fetchb(); + val|=decode_fetchb() << 8; + val|=decode_fetchb() << 16; + val|=decode_fetchb() << 24; + return val; + /* Advance to the next page */ + } + *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101; + decode.code+=4;decode.page.index+=4; + return mem_readd(decode.code-4); +} + +#define START_WMMEM 64 + +static INLINE void decode_increase_wmapmask(Bitu size) { + Bitu mapidx; + CacheBlock* activecb=decode.active_block; + if (GCC_UNLIKELY(!activecb->cache.wmapmask)) { + activecb->cache.wmapmask=(Bit8u*)malloc(START_WMMEM); + memset(activecb->cache.wmapmask,0,START_WMMEM); + activecb->cache.maskstart=decode.page.index; + activecb->cache.masklen=START_WMMEM; + mapidx=0; + } else { + mapidx=decode.page.index-activecb->cache.maskstart; + if (GCC_UNLIKELY(mapidx+size>=activecb->cache.masklen)) { + Bitu newmasklen=activecb->cache.masklen*4; + if (newmasklencache.wmapmask,activecb->cache.masklen); + free(activecb->cache.wmapmask); + activecb->cache.wmapmask=tempmem; + activecb->cache.masklen=newmasklen; + } + } + switch (size) { + case 1 : activecb->cache.wmapmask[mapidx]+=0x01; break; + case 2 : (*(Bit16u*)&activecb->cache.wmapmask[mapidx])+=0x0101; break; + case 4 : (*(Bit32u*)&activecb->cache.wmapmask[mapidx])+=0x01010101; break; + } +} + +static bool decode_fetchb_imm(Bitu & val) { + if (decode.page.index<4096) { + if (decode.page.invmap != NULL) { + if (decode.page.invmap[decode.page.index] == 0) { + val=(Bit32u)decode_fetchb(); + return false; + } + HostPt tlb_addr=get_tlb_read(decode.code); + if (tlb_addr) { + val=(Bitu)(tlb_addr+decode.code); + decode_increase_wmapmask(1); + decode.code++; + decode.page.index++; + return true; + } + } + } + val=(Bit32u)decode_fetchb(); + return false; +} +static bool decode_fetchw_imm(Bitu & val) { + if (decode.page.index<4095) { + if (decode.page.invmap != NULL) { + if ((decode.page.invmap[decode.page.index] == 0) && + (decode.page.invmap[decode.page.index + 1] == 0) + ) { + val=decode_fetchw(); + return false; + } + HostPt tlb_addr=get_tlb_read(decode.code); + if (tlb_addr) { + val=(Bitu)(tlb_addr+decode.code); + decode_increase_wmapmask(2); + decode.code+=2; + decode.page.index+=2; + return true; + } + } + } + val=decode_fetchw(); + return false; +} +static bool decode_fetchd_imm(Bitu & val) { + if (decode.page.index<4093) { + if (decode.page.invmap != NULL) { + if ((decode.page.invmap[decode.page.index] == 0) && + (decode.page.invmap[decode.page.index + 1] == 0) && + (decode.page.invmap[decode.page.index + 2] == 0) && + (decode.page.invmap[decode.page.index + 3] == 0) + ) { + val=decode_fetchd(); + return false; + } + HostPt tlb_addr=get_tlb_read(decode.code); + if (tlb_addr) { + val=(Bitu)(tlb_addr+decode.code); + decode_increase_wmapmask(4); + decode.code+=4; + decode.page.index+=4; + return true; + } + } + } + val=decode_fetchd(); + return false; +} + + +static void dyn_reduce_cycles(void) { + gen_protectflags(); + if (!decode.cycles) decode.cycles++; + gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles); +} + +static void dyn_save_noncritical_regs(void) { + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(ECX)); + gen_releasereg(DREG(EDX)); + gen_releasereg(DREG(EBX)); + gen_releasereg(DREG(ESP)); + 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)); +} + +static void dyn_set_eip_last_end(DynReg * endreg) { + gen_protectflags(); + gen_lea(endreg,DREG(EIP),0,0,decode.code-decode.code_start); + gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),decode.op_start-decode.code_start); +} + +static INLINE void dyn_set_eip_end(void) { + gen_protectflags(); + 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(); + if (cpu.code.big) gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EIP)); + else gen_extend_word(false,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,cpu.code.big,DREG(EIP),decode.op_start-decode.code_start); +} + + +enum save_info_type {db_exception, cycle_check, normal, fpu_restore}; + + +static struct { + save_info_type type; + DynState state; + Bit8u * branch_pos; + Bit32u eip_change; + Bitu cycles; + Bit8u * return_pos; +} 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=db_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=db_exception; + used_save_info++; +} + +#include "pic.h" + +static void dyn_check_irqrequest(void) { + gen_load_host(&PIC_IRQCheck,DREG(TMPB),4); + gen_dop_word(DOP_OR,true,DREG(TMPB),DREG(TMPB)); + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_NZ); + gen_releasereg(DREG(TMPB)); + 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.code-decode.code_start; + if (!cpu.code.big) save_info[used_save_info].eip_change&=0xffff; + save_info[used_save_info].type=normal; + used_save_info++; +} + +static void dyn_check_bool_exception_ne(void) { + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_Z); + 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=db_exception; + used_save_info++; +} + +static void dyn_fill_blocks(void) { + for (Bitu sct=0; sctindex<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.state_used))); + gen_releasereg(DREG(TMPB)); + dyn_synchstate(&save_info[sct].state); + gen_create_jump(save_info[sct].return_pos); + break; + } + } + used_save_info=0; +} + + +#if !defined(X86_INLINED_MEMACCESS) +static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) { + gen_protectflags(); + gen_call_function((void *)&mem_readb_checked,"%Dd%Id",addr,&core_dyn.readdata); + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dst,1,high); +} +static void dyn_write_byte(DynReg * addr,DynReg * val,Bitu high) { + gen_protectflags(); + if (high) gen_call_function((void *)&mem_writeb_checked,"%Dd%Dh",addr,val); + else gen_call_function((void *)&mem_writeb_checked,"%Dd%Dd",addr,val); + dyn_check_bool_exception_al(); +} +static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) { + gen_protectflags(); + if (dword) gen_call_function((void *)&mem_readd_checked,"%Dd%Id",addr,&core_dyn.readdata); + else gen_call_function((void *)&mem_readw_checked,"%Dd%Id",addr,&core_dyn.readdata); + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dst,dword?4:2); +} +static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { + gen_protectflags(); + if (dword) gen_call_function((void *)&mem_writed_checked,"%Dd%Dd",addr,val); + else gen_call_function((void *)&mem_writew_checked,"%Dd%Dd",addr,val); + dyn_check_bool_exception_al(); +} +static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) { + gen_protectflags(); + gen_call_function((void *)&mem_readb_checked,"%Ddr%Id",addr,&core_dyn.readdata); + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dst,1,high); +} +static void dyn_write_byte_release(DynReg * addr,DynReg * val,Bitu high) { + gen_protectflags(); + if (high) gen_call_function((void *)&mem_writeb_checked,"%Ddr%Dh",addr,val); + else gen_call_function((void *)&mem_writeb_checked,"%Ddr%Dd",addr,val); + dyn_check_bool_exception_al(); +} +static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) { + gen_protectflags(); + if (dword) gen_call_function((void *)&mem_readd_checked,"%Ddr%Id",addr,&core_dyn.readdata); + else gen_call_function((void *)&mem_readw_checked,"%Ddr%Id",addr,&core_dyn.readdata); + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dst,dword?4:2); +} +static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) { + gen_protectflags(); + if (dword) gen_call_function((void *)&mem_writed_checked,"%Ddr%Dd",addr,val); + else gen_call_function((void *)&mem_writew_checked,"%Ddr%Dd",addr,val); + dyn_check_bool_exception_al(); +} + +#else + +static void dyn_read_intro(DynReg * addr,bool release_addr=true) { + gen_protectflags(); + + if (addr->genreg) { + // addr already in a register + Bit8u reg_idx=(Bit8u)addr->genreg->index; + x86gen.regs[X86_REG_ECX]->Clear(); + if (reg_idx!=1) { + cache_addw(0xc88b+(reg_idx<<8)); //Mov ecx,reg + } + x86gen.regs[X86_REG_EAX]->Clear(); + if (release_addr) gen_releasereg(addr); + } else { + // addr still in memory, directly move into ecx + x86gen.regs[X86_REG_EAX]->Clear(); + x86gen.regs[X86_REG_ECX]->Clear(); + cache_addw(0x0d8b); //Mov ecx,[data] + cache_addd((Bit32u)addr->data); + } + x86gen.regs[X86_REG_EDX]->Clear(); + + cache_addw(0xc18b); // mov eax,ecx +} + +bool mem_readb_checked_dcx86(PhysPt address) { + return get_tlb_readhandler(address)->readb_checked(address, (Bit8u*)(&core_dyn.readdata)); +} + +static void dyn_read_byte(DynReg * addr,DynReg * dst,Bitu high) { + dyn_read_intro(addr,false); + + cache_addw(0xe8c1); // shr eax,0x0c + cache_addb(0x0c); + cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] + cache_addb(0x85); + cache_addd((Bit32u)(&paging.tlb.read[0])); + cache_addw(0xc085); // test eax,eax + Bit8u* je_loc=gen_create_branch(BR_Z); + + + cache_addw(0x048a); // mov al,[eax+ecx] + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(je_loc); + cache_addb(0x51); // push ecx + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_readb_checked_dcx86) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,4 + cache_addb(0x04); + cache_addw(0x012c); // sub al,1 + + dyn_check_bool_exception_ne(); + + cache_addw(0x058a); //mov al,[] + cache_addd((Bit32u)(&core_dyn.readdata)); + + gen_fill_jump(jmp_loc); + + x86gen.regs[X86_REG_EAX]->notusable=true; + GenReg * genreg=FindDynReg(dst); + x86gen.regs[X86_REG_EAX]->notusable=false; + cache_addw(0xc08a+(genreg->index<<11)+(high?0x2000:0)); + dst->flags|=DYNFLG_CHANGED; +} + +static void dyn_read_byte_release(DynReg * addr,DynReg * dst,Bitu high) { + dyn_read_intro(addr); + + cache_addw(0xe8c1); // shr eax,0x0c + cache_addb(0x0c); + cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] + cache_addb(0x85); + cache_addd((Bit32u)(&paging.tlb.read[0])); + cache_addw(0xc085); // test eax,eax + Bit8u* je_loc=gen_create_branch(BR_Z); + + + cache_addw(0x048a); // mov al,[eax+ecx] + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(je_loc); + cache_addb(0x51); // push ecx + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_readb_checked_dcx86) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,4 + cache_addb(0x04); + cache_addw(0x012c); // sub al,1 + + dyn_check_bool_exception_ne(); + + cache_addw(0x058a); //mov al,[] + cache_addd((Bit32u)(&core_dyn.readdata)); + + gen_fill_jump(jmp_loc); + + x86gen.regs[X86_REG_EAX]->notusable=true; + GenReg * genreg=FindDynReg(dst); + x86gen.regs[X86_REG_EAX]->notusable=false; + cache_addw(0xc08a+(genreg->index<<11)+(high?0x2000:0)); + dst->flags|=DYNFLG_CHANGED; +} + +bool mem_readd_checked_dcx86(PhysPt address) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + core_dyn.readdata=host_readd(tlb_addr+address); + return false; + } else { + return get_tlb_readhandler(address)->readd_checked(address, &core_dyn.readdata); + } + } else return mem_unalignedreadd_checked(address, &core_dyn.readdata); +} + +static void dyn_read_word(DynReg * addr,DynReg * dst,bool dword) { + if (dword) { + dyn_read_intro(addr,false); + + cache_addw(0xe8d1); // shr eax,0x1 + Bit8u* jb_loc1=gen_create_branch(BR_B); + cache_addw(0xe8d1); // shr eax,0x1 + Bit8u* jb_loc2=gen_create_branch(BR_B); + cache_addw(0xe8c1); // shr eax,0x0a + cache_addb(0x0a); + cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] + cache_addb(0x85); + cache_addd((Bit32u)(&paging.tlb.read[0])); + cache_addw(0xc085); // test eax,eax + Bit8u* je_loc=gen_create_branch(BR_Z); + + GenReg * genreg=FindDynReg(dst,true); + + cache_addw(0x048b+(genreg->index <<(8+3))); // mov dest,[eax+ecx] + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(jb_loc1); + gen_fill_branch(jb_loc2); + gen_fill_branch(je_loc); + cache_addb(0x51); // push ecx + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_readd_checked_dcx86) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,4 + cache_addb(0x04); + cache_addw(0x012c); // sub al,1 + + dyn_check_bool_exception_ne(); + + gen_mov_host(&core_dyn.readdata,dst,4); + dst->flags|=DYNFLG_CHANGED; + + gen_fill_jump(jmp_loc); + } else { + gen_protectflags(); + gen_call_function((void *)&mem_readw_checked,"%Dd%Id",addr,&core_dyn.readdata); + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dst,2); + } +} + +static void dyn_read_word_release(DynReg * addr,DynReg * dst,bool dword) { + if (dword) { + dyn_read_intro(addr); + + cache_addw(0xe8d1); // shr eax,0x1 + Bit8u* jb_loc1=gen_create_branch(BR_B); + cache_addw(0xe8d1); // shr eax,0x1 + Bit8u* jb_loc2=gen_create_branch(BR_B); + cache_addw(0xe8c1); // shr eax,0x0a + cache_addb(0x0a); + cache_addw(0x048b); // mov eax,paging.tlb.read[eax*TYPE Bit32u] + cache_addb(0x85); + cache_addd((Bit32u)(&paging.tlb.read[0])); + cache_addw(0xc085); // test eax,eax + Bit8u* je_loc=gen_create_branch(BR_Z); + + GenReg * genreg=FindDynReg(dst,true); + + cache_addw(0x048b+(genreg->index <<(8+3))); // mov dest,[eax+ecx] + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(jb_loc1); + gen_fill_branch(jb_loc2); + gen_fill_branch(je_loc); + cache_addb(0x51); // push ecx + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_readd_checked_dcx86) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,4 + cache_addb(0x04); + cache_addw(0x012c); // sub al,1 + + dyn_check_bool_exception_ne(); + + gen_mov_host(&core_dyn.readdata,dst,4); + dst->flags|=DYNFLG_CHANGED; + + gen_fill_jump(jmp_loc); + } else { + gen_protectflags(); + gen_call_function((void *)&mem_readw_checked,"%Ddr%Id",addr,&core_dyn.readdata); + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dst,2); + } +} + +static void dyn_write_intro(DynReg * addr,bool release_addr=true) { + gen_protectflags(); + + if (addr->genreg) { + // addr in a register + Bit8u reg_idx_addr=(Bit8u)addr->genreg->index; + + x86gen.regs[X86_REG_EAX]->Clear(); + x86gen.regs[X86_REG_EAX]->notusable=true; + x86gen.regs[X86_REG_ECX]->Clear(); + x86gen.regs[X86_REG_ECX]->notusable=true; + + if (reg_idx_addr) { + // addr!=eax + cache_addb(0x8b); //Mov eax,reg + cache_addb(0xc0+reg_idx_addr); + } + if (release_addr) gen_releasereg(addr); + } else { + // addr still in memory, directly move into eax + x86gen.regs[X86_REG_EAX]->Clear(); + x86gen.regs[X86_REG_EAX]->notusable=true; + x86gen.regs[X86_REG_ECX]->Clear(); + x86gen.regs[X86_REG_ECX]->notusable=true; + cache_addb(0xa1); //Mov eax,[data] + cache_addd((Bit32u)addr->data); + } + + cache_addw(0xc88b); // mov ecx,eax +} + +static void dyn_write_byte(DynReg * addr,DynReg * val,bool high) { + dyn_write_intro(addr,false); + + GenReg * genreg=FindDynReg(val); + cache_addw(0xe9c1); // shr ecx,0x0c + cache_addb(0x0c); + cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] + cache_addb(0x8d); + cache_addd((Bit32u)(&paging.tlb.write[0])); + cache_addw(0xc985); // test ecx,ecx + Bit8u* je_loc=gen_create_branch(BR_Z); + + cache_addw(0x0488+(genreg->index<<11)+(high?0x2000:0)); // mov [eax+ecx],reg + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(je_loc); + + if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); + cache_addb(0x52); // push edx + cache_addb(0x50+genreg->index); + cache_addb(0x50); // push eax + if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_writeb_checked) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,8 + cache_addb(0x08); + cache_addw(0x012c); // sub al,1 + cache_addb(0x5a); // pop edx + + // Restore registers to be used again + x86gen.regs[X86_REG_EAX]->notusable=false; + x86gen.regs[X86_REG_ECX]->notusable=false; + + dyn_check_bool_exception_ne(); + + gen_fill_jump(jmp_loc); +} + +static void dyn_write_byte_release(DynReg * addr,DynReg * val,bool high) { + dyn_write_intro(addr); + + GenReg * genreg=FindDynReg(val); + cache_addw(0xe9c1); // shr ecx,0x0c + cache_addb(0x0c); + cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] + cache_addb(0x8d); + cache_addd((Bit32u)(&paging.tlb.write[0])); + cache_addw(0xc985); // test ecx,ecx + Bit8u* je_loc=gen_create_branch(BR_Z); + + cache_addw(0x0488+(genreg->index<<11)+(high?0x2000:0)); // mov [eax+ecx],reg + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(je_loc); + + cache_addb(0x52); // push edx + if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); + cache_addb(0x50+genreg->index); + cache_addb(0x50); // push eax + if (GCC_UNLIKELY(high)) cache_addw(0xe086+((genreg->index+(genreg->index<<3))<<8)); + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_writeb_checked) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,8 + cache_addb(0x08); + cache_addw(0x012c); // sub al,1 + cache_addb(0x5a); // pop edx + + // Restore registers to be used again + x86gen.regs[X86_REG_EAX]->notusable=false; + x86gen.regs[X86_REG_ECX]->notusable=false; + + dyn_check_bool_exception_ne(); + + gen_fill_jump(jmp_loc); +} + +static void dyn_write_word(DynReg * addr,DynReg * val,bool dword) { + if (dword) { + dyn_write_intro(addr,false); + + GenReg * genreg=FindDynReg(val); + cache_addw(0xe9d1); // shr ecx,0x1 + Bit8u* jb_loc1=gen_create_branch(BR_B); + cache_addw(0xe9d1); // shr ecx,0x1 + Bit8u* jb_loc2=gen_create_branch(BR_B); + cache_addw(0xe9c1); // shr ecx,0x0a + cache_addb(0x0a); + cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] + cache_addb(0x8d); + cache_addd((Bit32u)(&paging.tlb.write[0])); + cache_addw(0xc985); // test ecx,ecx + Bit8u* je_loc=gen_create_branch(BR_Z); + + cache_addw(0x0489+(genreg->index <<(8+3))); // mov [eax+ecx],reg + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(jb_loc1); + gen_fill_branch(jb_loc2); + gen_fill_branch(je_loc); + + cache_addb(0x52); // push edx + cache_addb(0x50+genreg->index); + cache_addb(0x50); // push eax + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_writed_checked) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,8 + cache_addb(0x08); + cache_addw(0x012c); // sub al,1 + cache_addb(0x5a); // pop edx + + // Restore registers to be used again + x86gen.regs[X86_REG_EAX]->notusable=false; + x86gen.regs[X86_REG_ECX]->notusable=false; + + dyn_check_bool_exception_ne(); + + gen_fill_jump(jmp_loc); + } else { + gen_protectflags(); + gen_call_function((void *)&mem_writew_checked,"%Dd%Dd",addr,val); + dyn_check_bool_exception_al(); + } +} + +static void dyn_write_word_release(DynReg * addr,DynReg * val,bool dword) { + if (dword) { + dyn_write_intro(addr); + + GenReg * genreg=FindDynReg(val); + cache_addw(0xe9d1); // shr ecx,0x1 + Bit8u* jb_loc1=gen_create_branch(BR_B); + cache_addw(0xe9d1); // shr ecx,0x1 + Bit8u* jb_loc2=gen_create_branch(BR_B); + cache_addw(0xe9c1); // shr ecx,0x0a + cache_addb(0x0a); + cache_addw(0x0c8b); // mov ecx,paging.tlb.read[ecx*TYPE Bit32u] + cache_addb(0x8d); + cache_addd((Bit32u)(&paging.tlb.write[0])); + cache_addw(0xc985); // test ecx,ecx + Bit8u* je_loc=gen_create_branch(BR_Z); + + cache_addw(0x0489+(genreg->index <<(8+3))); // mov [eax+ecx],reg + cache_addb(0x08); + + Bit8u* jmp_loc=gen_create_jump(); + gen_fill_branch(jb_loc1); + gen_fill_branch(jb_loc2); + gen_fill_branch(je_loc); + + cache_addb(0x52); // push edx + cache_addb(0x50+genreg->index); + cache_addb(0x50); // push eax + cache_addb(0xe8); + cache_addd(((Bit32u)&mem_writed_checked) - (Bit32u)cache.pos-4); + cache_addw(0xc483); // add esp,8 + cache_addb(0x08); + cache_addw(0x012c); // sub al,1 + cache_addb(0x5a); // pop edx + + // Restore registers to be used again + x86gen.regs[X86_REG_EAX]->notusable=false; + x86gen.regs[X86_REG_ECX]->notusable=false; + + dyn_check_bool_exception_ne(); + + gen_fill_jump(jmp_loc); + } else { + gen_protectflags(); + gen_call_function((void *)&mem_writew_checked,"%Ddr%Dd",addr,val); + dyn_check_bool_exception_al(); + } +} + +#endif + + +static void dyn_push_unchecked(DynReg * dynreg) { + gen_protectflags(); + gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2)); + gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); + gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask); + gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK)); + gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); + if (decode.big_op) { + gen_call_function((void *)&mem_writed,"%Drd%Dd",DREG(STACK),dynreg); + } else { + //Can just push the whole 32-bit word as operand + gen_call_function((void *)&mem_writew,"%Drd%Dd",DREG(STACK),dynreg); + } +} + +static void dyn_push(DynReg * dynreg) { + gen_protectflags(); + gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?(-4):(-2)); + gen_dop_word(DOP_MOV,true,DREG(NEWESP),DREG(ESP)); + gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); + gen_dop_word_var(DOP_AND,true,DREG(NEWESP),&cpu.stack.notmask); + gen_dop_word(DOP_OR,true,DREG(NEWESP),DREG(STACK)); + gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); + if (decode.big_op) { + gen_call_function((void *)&mem_writed_checked,"%Drd%Dd",DREG(STACK),dynreg); + } else { + //Can just push the whole 32-bit word as operand + gen_call_function((void *)&mem_writew_checked,"%Drd%Dd",DREG(STACK),dynreg); + } + dyn_check_bool_exception_al(); + /* everything was ok, change register now */ + gen_dop_word(DOP_MOV,true,DREG(ESP),DREG(NEWESP)); + gen_releasereg(DREG(NEWESP)); +} + +static void dyn_pop(DynReg * dynreg,bool checked=true) { + gen_protectflags(); + gen_dop_word(DOP_MOV,true,DREG(STACK),DREG(ESP)); + gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); + gen_dop_word(DOP_ADD,true,DREG(STACK),DREG(SS)); + if (checked) { + if (decode.big_op) { + gen_call_function((void *)&mem_readd_checked,"%Drd%Id",DREG(STACK),&core_dyn.readdata); + } else { + gen_call_function((void *)&mem_readw_checked,"%Drd%Id",DREG(STACK),&core_dyn.readdata); + } + dyn_check_bool_exception_al(); + gen_mov_host(&core_dyn.readdata,dynreg,decode.big_op?4:2); + } else { + if (decode.big_op) { + gen_call_function((void *)&mem_readd,"%Rd%Drd",dynreg,DREG(STACK)); + } else { + gen_call_function((void *)&mem_readw,"%Rw%Drd",dynreg,DREG(STACK)); + } + } + if (dynreg!=DREG(ESP)) { + gen_lea(DREG(STACK),DREG(ESP),0,0,decode.big_op?4:2); + gen_dop_word_var(DOP_AND,true,DREG(STACK),&cpu.stack.mask); + gen_dop_word_var(DOP_AND,true,DREG(ESP),&cpu.stack.notmask); + gen_dop_word(DOP_OR,true,DREG(ESP),DREG(STACK)); + } +} + +static INLINE void dyn_get_modrm(void) { + decode.modrm.val=decode_fetchb(); + decode.modrm.mod=(decode.modrm.val >> 6) & 3; + decode.modrm.reg=(decode.modrm.val >> 3) & 7; + decode.modrm.rm=(decode.modrm.val & 7); +} + +static void dyn_fill_ea(bool addseg=true, DynReg * reg_ea=DREG(EA)) { + DynReg * segbase; + if (!decode.big_addr) { + Bits imm; + switch (decode.modrm.mod) { + case 0:imm=0;break; + case 1:imm=(Bit8s)decode_fetchb();break; + case 2:imm=(Bit16s)decode_fetchw();break; + } + DynReg * extend_src=reg_ea; + switch (decode.modrm.rm) { + case 0:/* BX+SI */ + gen_lea(reg_ea,DREG(EBX),DREG(ESI),0,imm); + segbase=DREG(DS); + break; + case 1:/* BX+DI */ + gen_lea(reg_ea,DREG(EBX),DREG(EDI),0,imm); + segbase=DREG(DS); + break; + case 2:/* BP+SI */ + gen_lea(reg_ea,DREG(EBP),DREG(ESI),0,imm); + segbase=DREG(SS); + break; + case 3:/* BP+DI */ + gen_lea(reg_ea,DREG(EBP),DREG(EDI),0,imm); + segbase=DREG(SS); + break; + case 4:/* SI */ + if (imm) gen_lea(reg_ea,DREG(ESI),0,0,imm); + else extend_src=DREG(ESI); + segbase=DREG(DS); + break; + case 5:/* DI */ + if (imm) gen_lea(reg_ea,DREG(EDI),0,0,imm); + else extend_src=DREG(EDI); + segbase=DREG(DS); + break; + case 6:/* imm/BP */ + if (!decode.modrm.mod) { + imm=decode_fetchw(); + gen_dop_word_imm(DOP_MOV,true,reg_ea,imm); + segbase=DREG(DS); + goto skip_extend_word; + } else { + gen_lea(reg_ea,DREG(EBP),0,0,imm); + segbase=DREG(SS); + } + break; + case 7: /* BX */ + if (imm) gen_lea(reg_ea,DREG(EBX),0,0,imm); + else extend_src=DREG(EBX); + segbase=DREG(DS); + break; + } + gen_extend_word(false,reg_ea,extend_src); +skip_extend_word: + if (addseg) { + gen_lea(reg_ea,reg_ea,decode.segprefix ? decode.segprefix : segbase,0,0); + } + } else { + Bits imm=0; + DynReg * base=0;DynReg * scaled=0;Bitu scale=0; + switch (decode.modrm.rm) { + case 0:base=DREG(EAX);segbase=DREG(DS);break; + case 1:base=DREG(ECX);segbase=DREG(DS);break; + case 2:base=DREG(EDX);segbase=DREG(DS);break; + case 3:base=DREG(EBX);segbase=DREG(DS);break; + case 4: /* SIB */ + { + Bitu sib=decode_fetchb(); + static DynReg * scaledtable[8]={ + DREG(EAX),DREG(ECX),DREG(EDX),DREG(EBX), + 0,DREG(EBP),DREG(ESI),DREG(EDI), + }; + scaled=scaledtable[(sib >> 3) &7]; + scale=(sib >> 6); + switch (sib & 7) { + case 0:base=DREG(EAX);segbase=DREG(DS);break; + case 1:base=DREG(ECX);segbase=DREG(DS);break; + case 2:base=DREG(EDX);segbase=DREG(DS);break; + case 3:base=DREG(EBX);segbase=DREG(DS);break; + case 4:base=DREG(ESP);segbase=DREG(SS);break; + case 5: + if (decode.modrm.mod) { + base=DREG(EBP);segbase=DREG(SS); + } else { + segbase=DREG(DS); + Bitu val; + if (decode_fetchd_imm(val)) { + gen_mov_host((void*)val,DREG(EA),4); + if (!addseg) { + gen_lea(reg_ea,DREG(EA),scaled,scale,0); + } else { + DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase; + gen_lea(DREG(EA),DREG(EA),scaled,scale,0); + gen_lea(reg_ea,DREG(EA),*seg,0,0); + } + return; + } + imm=(Bit32s)val; + } + break; + case 6:base=DREG(ESI);segbase=DREG(DS);break; + case 7:base=DREG(EDI);segbase=DREG(DS);break; + } + } + break; /* SIB Break */ + case 5: + if (decode.modrm.mod) { + base=DREG(EBP);segbase=DREG(SS); + } else { + imm=(Bit32s)decode_fetchd();segbase=DREG(DS); + } + break; + case 6:base=DREG(ESI);segbase=DREG(DS);break; + case 7:base=DREG(EDI);segbase=DREG(DS);break; + } + switch (decode.modrm.mod) { + case 1:imm=(Bit8s)decode_fetchb();break; + case 2: { + Bitu val; + if (decode_fetchd_imm(val)) { + gen_mov_host((void*)val,DREG(EA),4); + if (!addseg) { + gen_lea(DREG(EA),DREG(EA),scaled,scale,0); + gen_lea(reg_ea,DREG(EA),base,0,0); + } else { + DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase; + if (!base) { + gen_lea(DREG(EA),DREG(EA),scaled,scale,0); + gen_lea(reg_ea,DREG(EA),*seg,0,0); + } else if (!scaled) { + gen_lea(DREG(EA),DREG(EA),*seg,0,0); + gen_lea(reg_ea,DREG(EA),base,0,0); + } else { + gen_lea(DREG(EA),DREG(EA),scaled,scale,0); + gen_lea(DREG(EA),DREG(EA),base,0,0); + gen_lea(reg_ea,DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0); + } + } + return; + } + + imm=(Bit32s)val; + break; + } + } + if (!addseg) { + gen_lea(reg_ea,base,scaled,scale,imm); + } else { + DynReg** seg = decode.segprefix ? &decode.segprefix : &segbase; + if (!base) gen_lea(reg_ea,*seg,scaled,scale,imm); + else if (!scaled) gen_lea(reg_ea,base,*seg,0,imm); + else { + gen_lea(DREG(EA),base,scaled,scale,imm); + gen_lea(reg_ea,DREG(EA),decode.segprefix ? decode.segprefix : segbase,0,0); + } + } + } +} + + +static void dyn_dop_word_imm(DualOps op,bool dword,DynReg * dr1) { + Bitu val; + if (dword) { + if (decode_fetchd_imm(val)) { + gen_dop_word_imm_mem(op,true,dr1,(void*)val); + return; + } + } else { + if (decode_fetchw_imm(val)) { + gen_dop_word_imm_mem(op,false,dr1,(void*)val); + return; + } + } + gen_dop_word_imm(op,dword,dr1,val); +} + +static void dyn_dop_byte_imm(DualOps op,DynReg * dr1,Bit8u di1) { + Bitu val; + if (decode_fetchb_imm(val)) { + gen_dop_byte_imm_mem(op,dr1,di1,(void*)val); + } else { + gen_dop_byte_imm(op,dr1,di1,(Bit8u)val); + } +} + + +#include "helpers.h" +#include "string.h" + + +static void dyn_dop_ebgb(DualOps op) { + dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); + dyn_read_byte(DREG(EA),DREG(TMPB),false); + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else set_skipflags(false); + } + gen_dop_byte(op,DREG(TMPB),0,rm_reg,decode.modrm.reg&4); + if (op!=DOP_CMP) dyn_write_byte_release(DREG(EA),DREG(TMPB),false); + else gen_releasereg(DREG(EA)); + gen_releasereg(DREG(TMPB)); + } else { + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else gen_discardflags(); + } + gen_dop_byte(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,decode.modrm.reg&4); + } +} + + +static void dyn_dop_gbeb(DualOps op) { + dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg&3]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); + dyn_read_byte_release(DREG(EA),DREG(TMPB),false); + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else set_skipflags(false); + } + gen_dop_byte(op,rm_reg,decode.modrm.reg&4,DREG(TMPB),0); + gen_releasereg(DREG(TMPB)); + } else { + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else gen_discardflags(); + } + gen_dop_byte(op,rm_reg,decode.modrm.reg&4,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); + } +} + +static void dyn_mov_ebib(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(); + gen_call_write(DREG(EA),decode_fetchb(),1); + dyn_check_bool_exception_al(); + } else { + gen_dop_byte_imm(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,decode_fetchb()); + } +} + +static void dyn_mov_ebgb(void) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_write_byte_release(DREG(EA),rm_reg,rm_regi==4); + } else { + gen_dop_byte(DOP_MOV,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4,rm_reg,rm_regi); + } +} + +static void dyn_mov_gbeb(void) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg&3];Bitu rm_regi=decode.modrm.reg&4; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_read_byte_release(DREG(EA),rm_reg,rm_regi); + } else { + gen_dop_byte(DOP_MOV,rm_reg,rm_regi,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); + } +} + +static void dyn_dop_evgv(DualOps op) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); + dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else set_skipflags(false); + } + gen_dop_word(op,decode.big_op,DREG(TMPW),rm_reg); + if (op!=DOP_CMP) dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); + else gen_releasereg(DREG(EA)); + gen_releasereg(DREG(TMPW)); + } else { + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else gen_discardflags(); + } + gen_dop_word(op,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); + } +} + +static void dyn_imul_gvev(Bitu immsize) { + dyn_get_modrm();DynReg * src; + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea();dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op); + src=DREG(TMPW); + } else { + src=&DynRegs[decode.modrm.rm]; + } + gen_needflags(); + switch (immsize) { + case 0:gen_imul_word(decode.big_op,rm_reg,src);break; + case 1:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit8s)decode_fetchb());break; + case 2:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit16s)decode_fetchw());break; + case 4:gen_imul_word_imm(decode.big_op,rm_reg,src,(Bit32s)decode_fetchd());break; + } + gen_releasereg(DREG(TMPW)); +} + +static void dyn_dop_gvev(DualOps op) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); + dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op); + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else set_skipflags(false); + } + gen_dop_word(op,decode.big_op,rm_reg,DREG(TMPW)); + gen_releasereg(DREG(TMPW)); + } else { + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else gen_discardflags(); + } + gen_dop_word(op,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); + } +} + +static void dyn_mov_evgv(void) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_write_word_release(DREG(EA),rm_reg,decode.big_op); + } else { + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); + } +} + +static void dyn_mov_gvev(void) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_read_word_release(DREG(EA),rm_reg,decode.big_op); + } else { + gen_dop_word(DOP_MOV,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm]); + } +} +static void dyn_mov_eviv(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(); + gen_call_write(DREG(EA),decode.big_op ? decode_fetchd() : decode_fetchw(),decode.big_op?4:2); + dyn_check_bool_exception_al(); + } else { + gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],decode.big_op ? decode_fetchd() : decode_fetchw()); + } +} + +static void dyn_mov_ev_gb(bool sign) { + dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_read_byte_release(DREG(EA),DREG(TMPB),false); + gen_extend_byte(sign,decode.big_op,rm_reg,DREG(TMPB),0); + gen_releasereg(DREG(TMPB)); + } else { + gen_extend_byte(sign,decode.big_op,rm_reg,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); + } +} + +static void dyn_mov_ev_gw(bool sign) { + if (!decode.big_op) { + dyn_mov_gvev(); + return; + } + dyn_get_modrm();DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_read_word_release(DREG(EA),DREG(TMPW),false); + gen_extend_word(sign,rm_reg,DREG(TMPW)); + gen_releasereg(DREG(TMPW)); + } else { + gen_extend_word(sign,rm_reg,&DynRegs[decode.modrm.rm]); + } +} + +static void dyn_cmpxchg_evgv(void) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + gen_protectflags(); + if (decode.modrm.mod<3) { + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(rm_reg); + + dyn_fill_ea(); + dyn_read_word(DREG(EA),DREG(TMPB),decode.big_op); + gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),DREG(TMPB)); + Bit8u * branch=gen_create_branch(BR_NZ); + + // eax==mem -> mem:=rm_reg + dyn_write_word_release(DREG(EA),rm_reg,decode.big_op); + gen_setzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(rm_reg); + + Bit8u * jump=gen_create_jump(); + + gen_fill_branch(branch); + // eax!=mem -> eax:=mem + dyn_write_word_release(DREG(EA),DREG(TMPB),decode.big_op); // cmpxchg always issues write + gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),DREG(TMPB)); + gen_clearzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(rm_reg); + + gen_fill_jump(jump); + } else { + gen_releasereg(DREG(EAX)); + gen_releasereg(&DynRegs[decode.modrm.rm]); + gen_releasereg(rm_reg); + + gen_dop_word(DOP_CMP,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]); + Bit8u * branch=gen_create_branch(BR_NZ); + + // eax==rm -> rm:=rm_reg + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],rm_reg); + gen_setzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(&DynRegs[decode.modrm.rm]); + gen_releasereg(rm_reg); + + Bit8u * jump=gen_create_jump(); + + gen_fill_branch(branch); + // eax!=rm -> eax:=rm + gen_dop_word(DOP_MOV,decode.big_op,DREG(EAX),&DynRegs[decode.modrm.rm]); + gen_clearzeroflag(); + gen_releasereg(DREG(EAX)); + gen_releasereg(&DynRegs[decode.modrm.rm]); + gen_releasereg(rm_reg); + + gen_fill_jump(jump); + } +} + +static void dyn_dshift_ev_gv(bool left,bool immediate) { + dyn_get_modrm(); + DynReg * rm_reg=&DynRegs[decode.modrm.reg]; + DynReg * ea_reg; + if (decode.modrm.mod<3) { + dyn_fill_ea();ea_reg=DREG(TMPW); + dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + } else ea_reg=&DynRegs[decode.modrm.rm]; + gen_needflags(); + if (immediate) gen_dshift_imm(decode.big_op,left,ea_reg,rm_reg,decode_fetchb()); + else gen_dshift_cl(decode.big_op,left,ea_reg,rm_reg,DREG(ECX)); + if (decode.modrm.mod<3) { + dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); + gen_releasereg(DREG(TMPW)); + } +} + + +static DualOps grp1_table[8]={DOP_ADD,DOP_OR,DOP_ADC,DOP_SBB,DOP_AND,DOP_SUB,DOP_XOR,DOP_CMP}; +static void dyn_grp1_eb_ib(void) { + dyn_get_modrm(); + DualOps op=grp1_table[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); + dyn_read_byte(DREG(EA),DREG(TMPB),false); + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else set_skipflags(false); + } + gen_dop_byte_imm(op,DREG(TMPB),0,decode_fetchb()); + if (op!=DOP_CMP) dyn_write_byte_release(DREG(EA),DREG(TMPB),false); + else gen_releasereg(DREG(EA)); + gen_releasereg(DREG(TMPB)); + } else { + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else gen_discardflags(); + } + dyn_dop_byte_imm(op,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); + } +} + +static void dyn_grp1_ev_ivx(bool withbyte) { + dyn_get_modrm(); + DualOps op=grp1_table[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((op<=DOP_TEST) && (op!=DOP_ADC && op!=DOP_SBB)) set_skipflags(true); + dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else set_skipflags(false); + } + if (!withbyte) { + dyn_dop_word_imm(op,decode.big_op,DREG(TMPW)); + } else { + gen_dop_word_imm(op,decode.big_op,DREG(TMPW),(Bit8s)decode_fetchb()); + } + if (op!=DOP_CMP) dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); + else gen_releasereg(DREG(EA)); + gen_releasereg(DREG(TMPW)); + } else { + if (op<=DOP_TEST) { + if (op==DOP_ADC || op==DOP_SBB) gen_needcarry(); + else gen_discardflags(); + } + if (!withbyte) { + dyn_dop_word_imm(op,decode.big_op,&DynRegs[decode.modrm.rm]); + } else { + gen_dop_word_imm(op,decode.big_op,&DynRegs[decode.modrm.rm],(Bit8s)decode_fetchb()); + } + } +} + +enum grp2_types { + grp2_1,grp2_imm,grp2_cl, +}; + +static void dyn_grp2_eb(grp2_types type) { + dyn_get_modrm();DynReg * src;Bit8u src_i; + if (decode.modrm.mod<3) { + dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); + src=DREG(TMPB); + src_i=0; + } else { + src=&DynRegs[decode.modrm.rm&3]; + src_i=decode.modrm.rm&4; + } + switch (type) { + case grp2_1: + /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ + if (decode.modrm.reg < 4) gen_needflags(); + else gen_discardflags(); + gen_shift_byte_imm(decode.modrm.reg,src,src_i,1); + break; + case grp2_imm: { + Bit8u imm=decode_fetchb(); + if (imm) { + /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ + if (decode.modrm.reg < 4) gen_needflags(); + else gen_discardflags(); + gen_shift_byte_imm(decode.modrm.reg,src,src_i,imm); + } else return; + } + break; + case grp2_cl: + gen_needflags(); /* flags must not be changed on ecx==0 */ + gen_shift_byte_cl (decode.modrm.reg,src,src_i,DREG(ECX)); + break; + } + if (decode.modrm.mod<3) { + dyn_write_byte_release(DREG(EA),src,false); + gen_releasereg(src); + } +} + +static void dyn_grp2_ev(grp2_types type) { + 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); + } else { + src=&DynRegs[decode.modrm.rm]; + } + switch (type) { + case grp2_1: + /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ + if (decode.modrm.reg < 4) gen_needflags(); + else gen_discardflags(); + gen_shift_word_imm(decode.modrm.reg,decode.big_op,src,1); + break; + case grp2_imm: { + Bitu val; + if (decode_fetchb_imm(val)) { + if (decode.modrm.reg < 4) gen_needflags(); + else gen_discardflags(); + gen_load_host((void*)val,DREG(TMPB),1); + gen_shift_word_cl(decode.modrm.reg,decode.big_op,src,DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + break; + } + Bit8u imm=(Bit8u)val; + if (imm) { + /* rotates (first 4 ops) alter cf/of only; shifts (last 4 ops) alter all flags */ + if (decode.modrm.reg < 4) gen_needflags(); + else gen_discardflags(); + gen_shift_word_imm(decode.modrm.reg,decode.big_op,src,imm); + } else return; + } + break; + case grp2_cl: + gen_needflags(); /* flags must not be changed on ecx==0 */ + gen_shift_word_cl (decode.modrm.reg,decode.big_op,src,DREG(ECX)); + break; + } + if (decode.modrm.mod<3) { + dyn_write_word_release(DREG(EA),src,decode.big_op); + gen_releasereg(src); + } +} + +static void dyn_grp3_eb(void) { + dyn_get_modrm();DynReg * src;Bit8u src_i; + if (decode.modrm.mod<3) { + dyn_fill_ea(); + if ((decode.modrm.reg==0) || (decode.modrm.reg==3)) set_skipflags(true); + dyn_read_byte(DREG(EA),DREG(TMPB),false); + src=DREG(TMPB);src_i=0; + } else { + src=&DynRegs[decode.modrm.rm&3]; + src_i=decode.modrm.rm&4; + } + switch (decode.modrm.reg) { + case 0x0: /* test eb,ib */ + set_skipflags(false);gen_dop_byte_imm(DOP_TEST,src,src_i,decode_fetchb()); + goto skipsave; + case 0x2: /* NOT Eb */ + gen_sop_byte(SOP_NOT,src,src_i); + break; + case 0x3: /* NEG Eb */ + set_skipflags(false);gen_sop_byte(SOP_NEG,src,src_i); + break; + case 0x4: /* mul Eb */ + gen_needflags();gen_mul_byte(false,DREG(EAX),src,src_i); + goto skipsave; + case 0x5: /* imul Eb */ + gen_needflags();gen_mul_byte(true,DREG(EAX),src,src_i); + goto skipsave; + case 0x6: /* div Eb */ + case 0x7: /* idiv Eb */ + /* EAX could be used, so precache it */ + if (decode.modrm.mod==3) + gen_dop_byte(DOP_MOV,DREG(TMPB),0,&DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); + gen_releasereg(DREG(EAX)); + gen_call_function((decode.modrm.reg==6) ? (void *)&dyn_helper_divb : (void *)&dyn_helper_idivb, + "%Rd%Dd",DREG(TMPB),DREG(TMPB)); + dyn_check_bool_exception(DREG(TMPB)); + goto skipsave; + } + /* Save the result if memory op */ + if (decode.modrm.mod<3) dyn_write_byte_release(DREG(EA),src,false); +skipsave: + gen_releasereg(DREG(TMPB));gen_releasereg(DREG(EA)); +} + +static void dyn_grp3_ev(void) { + dyn_get_modrm();DynReg * src; + if (decode.modrm.mod<3) { + dyn_fill_ea();src=DREG(TMPW); + if ((decode.modrm.reg==0) || (decode.modrm.reg==3)) set_skipflags(true); + dyn_read_word(DREG(EA),DREG(TMPW),decode.big_op); + } else src=&DynRegs[decode.modrm.rm]; + switch (decode.modrm.reg) { + case 0x0: /* test ev,iv */ + set_skipflags(false);gen_dop_word_imm(DOP_TEST,decode.big_op,src,decode.big_op ? decode_fetchd() : decode_fetchw()); + goto skipsave; + case 0x2: /* NOT Ev */ + gen_sop_word(SOP_NOT,decode.big_op,src); + break; + case 0x3: /* NEG Eb */ + set_skipflags(false);gen_sop_word(SOP_NEG,decode.big_op,src); + break; + case 0x4: /* mul Eb */ + gen_needflags();gen_mul_word(false,DREG(EAX),DREG(EDX),decode.big_op,src); + goto skipsave; + case 0x5: /* imul Eb */ + gen_needflags();gen_mul_word(true,DREG(EAX),DREG(EDX),decode.big_op,src); + goto skipsave; + case 0x6: /* div Eb */ + case 0x7: /* idiv Eb */ + /* EAX could be used, so precache it */ + if (decode.modrm.mod==3) + gen_dop_word(DOP_MOV,decode.big_op,DREG(TMPW),&DynRegs[decode.modrm.rm]); + gen_releasereg(DREG(EAX));gen_releasereg(DREG(EDX)); + void * func=(decode.modrm.reg==6) ? + (decode.big_op ? (void *)&dyn_helper_divd : (void *)&dyn_helper_divw) : + (decode.big_op ? (void *)&dyn_helper_idivd : (void *)&dyn_helper_idivw); + gen_call_function(func,"%Rd%Dd",DREG(TMPB),DREG(TMPW)); + dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + goto skipsave; + } + /* Save the result if memory op */ + if (decode.modrm.mod<3) dyn_write_word_release(DREG(EA),src,decode.big_op); +skipsave: + gen_releasereg(DREG(TMPW));gen_releasereg(DREG(EA)); +} + +static void dyn_mov_ev_seg(void) { + dyn_get_modrm(); + gen_load_host(&Segs.val[decode.modrm.reg],DREG(TMPW),2); + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_write_word_release(DREG(EA),DREG(TMPW),false); + } else { + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); + } + gen_releasereg(DREG(TMPW)); +} + +static void dyn_load_seg(SegNames seg,DynReg * src) { + gen_call_function((void *)&CPU_SetSegGeneral,"%Rd%Id%Drw",DREG(TMPB),seg,src); + dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(&DynRegs[G_ES+seg]); +} + +static void dyn_load_seg_off_ea(SegNames seg) { + if (decode.modrm.mod<3) { + dyn_fill_ea(); + gen_lea(DREG(TMPB),DREG(EA),0,0,decode.big_op ? 4:2); + dyn_read_word(DREG(TMPB),DREG(TMPB),false); + dyn_read_word_release(DREG(EA),DREG(TMPW),decode.big_op); + dyn_load_seg(seg,DREG(TMPB));gen_releasereg(DREG(TMPB)); + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.reg],DREG(TMPW)); + } else { + IllegalOption("dyn_load_seg_off_ea"); + } +} + +static void dyn_mov_seg_ev(void) { + dyn_get_modrm(); + SegNames seg=(SegNames)decode.modrm.reg; + if (GCC_UNLIKELY(seg==cs)) IllegalOption("dyn_mov_seg_ev"); + if (decode.modrm.mod<3) { + dyn_fill_ea(); + dyn_read_word(DREG(EA),DREG(EA),false); + dyn_load_seg(seg,DREG(EA)); + gen_releasereg(DREG(EA)); + } else { + dyn_load_seg(seg,&DynRegs[decode.modrm.rm]); + } +} + +static void dyn_push_seg(SegNames seg) { + gen_load_host(&Segs.val[seg],DREG(TMPW),2); + dyn_push(DREG(TMPW)); + gen_releasereg(DREG(TMPW)); +} + +static void dyn_pop_seg(SegNames seg) { + gen_releasereg(DREG(ESP)); + gen_call_function((void *)&CPU_PopSeg,"%Rd%Id%Id",DREG(TMPB),seg,decode.big_op); + dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + gen_releasereg(&DynRegs[G_ES+seg]); + gen_releasereg(DREG(ESP)); +} + +static void dyn_pop_ev(void) { + dyn_pop(DREG(TMPW)); + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(); +// dyn_write_word_release(DREG(EA),DREG(TMPW),decode.big_op); + if (decode.big_op) gen_call_function((void *)&mem_writed_inline,"%Ddr%Dd",DREG(EA),DREG(TMPW)); + else gen_call_function((void *)&mem_writew_inline,"%Ddr%Dd",DREG(EA),DREG(TMPW)); + } else { + gen_dop_word(DOP_MOV,decode.big_op,&DynRegs[decode.modrm.rm],DREG(TMPW)); + } + gen_releasereg(DREG(TMPW)); +} + +static void dyn_enter(void) { + gen_releasereg(DREG(ESP)); + gen_releasereg(DREG(EBP)); + Bitu bytes=decode_fetchw(); + Bitu level=decode_fetchb(); + gen_call_function((void *)&CPU_ENTER,"%Id%Id%Id",decode.big_op,bytes,level); +} + +static void dyn_leave(void) { + gen_protectflags(); + gen_dop_word_var(DOP_MOV,true,DREG(TMPW),&cpu.stack.mask); + gen_sop_word(SOP_NOT,true,DREG(TMPW)); + gen_dop_word(DOP_AND,true,DREG(ESP),DREG(TMPW)); + gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(EBP)); + gen_dop_word_var(DOP_AND,true,DREG(TMPW),&cpu.stack.mask); + gen_dop_word(DOP_OR,true,DREG(ESP),DREG(TMPW)); + dyn_pop(DREG(EBP),false); + gen_releasereg(DREG(TMPW)); +} + +static void dyn_segprefix(SegNames seg) { +// if (GCC_UNLIKELY((Bitu)(decode.segprefix))) IllegalOption("dyn_segprefix"); + decode.segprefix=&DynRegs[G_ES+seg]; +} + +static void dyn_closeblock(void) { + //Shouldn't create empty block normally but let's do it like this + gen_protectflags(); + dyn_fill_blocks(); + cache_closeblock(); +} + +static void dyn_normal_exit(BlockReturn code) { + gen_protectflags(); + dyn_reduce_cycles(); + dyn_set_eip_last(); + dyn_save_critical_regs(); + gen_return(code); + dyn_closeblock(); +} + +static void dyn_exit_link(Bits eip_change) { + gen_protectflags(); + gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(EIP),(decode.code-decode.code_start)+eip_change); + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); +} + +static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) { + Bitu eip_base=decode.code-decode.code_start; + gen_needflags(); + gen_protectflags(); + dyn_save_noncritical_regs(); + gen_releasereg(DREG(FLAGS)); + gen_releasereg(DREG(EIP)); + + gen_preloadreg(DREG(CYCLES)); + gen_preloadreg(DREG(EIP)); + DynReg save_cycles,save_eip; + dyn_saveregister(DREG(CYCLES),&save_cycles); + dyn_saveregister(DREG(EIP),&save_eip); + Bit8u * data=gen_create_branch(btype); + + /* 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 { + LOOP_NONE,LOOP_NE,LOOP_E,LOOP_JCXZ +}; + +static void dyn_loop(LoopTypes type) { + dyn_reduce_cycles(); + Bits eip_add=(Bit8s)decode_fetchb(); + Bitu eip_base=decode.code-decode.code_start; + Bit8u * branch1=0;Bit8u * branch2=0; + dyn_save_critical_regs(); + switch (type) { + case LOOP_E: + gen_needflags(); + branch1=gen_create_branch(BR_NZ); + break; + case LOOP_NE: + gen_needflags(); + branch1=gen_create_branch(BR_Z); + break; + } + gen_protectflags(); + switch (type) { + case LOOP_E: + case LOOP_NE: + case LOOP_NONE: + gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); + gen_releasereg(DREG(ECX)); + branch2=gen_create_branch(BR_Z); + break; + case LOOP_JCXZ: + gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX)); + gen_releasereg(DREG(ECX)); + branch2=gen_create_branch(BR_NZ); + break; + } + gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base+eip_add); + gen_releasereg(DREG(EIP)); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + if (branch1) { + gen_fill_branch(branch1); + gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); + gen_releasereg(DREG(ECX)); + } + /* Branch taken */ + gen_fill_branch(branch2); + gen_lea(DREG(EIP),DREG(EIP),0,0,eip_base); + gen_releasereg(DREG(EIP)); + gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); +} + +static void dyn_ret_near(Bitu bytes) { + gen_protectflags(); + dyn_reduce_cycles(); + dyn_pop(DREG(EIP)); + if (bytes) gen_dop_word_imm(DOP_ADD,true,DREG(ESP),bytes); + dyn_save_critical_regs(); + gen_return(BR_Normal); + dyn_closeblock(); +} + +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(DREG(TMPW)); + dyn_push(DREG(TMPW)); + gen_dop_word_imm(DOP_ADD,decode.big_op,DREG(TMPW),imm); + if (cpu.code.big) gen_dop_word(DOP_MOV,true,DREG(EIP),DREG(TMPW)); + else gen_extend_word(false,DREG(EIP),DREG(TMPW)); + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); +} + +static void dyn_ret_far(Bitu bytes) { + gen_protectflags(); + dyn_reduce_cycles(); + dyn_set_eip_last_end(DREG(TMPW)); + dyn_flags_gen_to_host(); + dyn_save_critical_regs(); + gen_call_function((void*)&CPU_RET,"%Id%Id%Drd",decode.big_op,bytes,DREG(TMPW)); + gen_return_fast(BR_Normal); + dyn_closeblock(); +} + +static void dyn_call_far_imm(void) { + Bitu sel,off; + off=decode.big_op ? decode_fetchd() : decode_fetchw(); + sel=decode_fetchw(); + dyn_reduce_cycles(); + dyn_set_eip_last_end(DREG(TMPW)); + 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)); + gen_return_fast(BR_Normal); + dyn_closeblock(); +} + +static void dyn_jmp_far_imm(void) { + Bitu sel,off; + gen_protectflags(); + off=decode.big_op ? decode_fetchd() : decode_fetchw(); + sel=decode_fetchw(); + dyn_reduce_cycles(); + dyn_set_eip_last_end(DREG(TMPW)); + 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)); + gen_return_fast(BR_Normal); + dyn_closeblock(); +} + +static void dyn_iret(void) { + gen_protectflags(); + dyn_flags_gen_to_host(); + dyn_reduce_cycles(); + dyn_set_eip_last_end(DREG(TMPW)); + dyn_save_critical_regs(); + gen_call_function((void*)&CPU_IRET,"%Id%Drd",decode.big_op,DREG(TMPW)); + gen_return_fast(BR_Iret); + dyn_closeblock(); +} + +static void dyn_interrupt(Bitu num) { + gen_protectflags(); + dyn_flags_gen_to_host(); + dyn_reduce_cycles(); + 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)); + gen_return_fast(BR_Normal); + dyn_closeblock(); +} + +static void dyn_add_iocheck(Bitu access_size) { + gen_call_function((void *)&CPU_IO_Exception,"%Dw%Id",DREG(EDX),access_size); + dyn_check_bool_exception_al(); +} + +static void dyn_add_iocheck_var(Bit8u accessed_port,Bitu access_size) { + gen_call_function((void *)&CPU_IO_Exception,"%Id%Id",accessed_port,access_size); + dyn_check_bool_exception_al(); +} + +#ifdef X86_DYNFPU_DH_ENABLED +#include "dyn_fpu_dh.h" +#define dh_fpu_startup() { \ + fpu_used=true; \ + gen_protectflags(); \ + gen_load_host(&dyn_dh_fpu.state_used,DREG(TMPB),4); \ + gen_dop_word_imm(DOP_CMP,true,DREG(TMPB),0); \ + gen_releasereg(DREG(TMPB)); \ + save_info[used_save_info].branch_pos=gen_create_branch_long(BR_Z); \ + dyn_savestate(&save_info[used_save_info].state); \ + save_info[used_save_info].return_pos=cache.pos; \ + save_info[used_save_info].type=fpu_restore; \ + used_save_info++; \ +} +#endif +#include "dyn_fpu.h" + +static CacheBlock * CreateCacheBlock(CodePageHandler * codepage,PhysPt start,Bitu max_opcodes) { + Bits i; +/* Init a load of variables */ + decode.code_start=start; + decode.code=start; + Bitu cycles=0; + decode.page.code=codepage; + decode.page.index=start&4095; + decode.page.wmap=codepage->write_map; + decode.page.invmap=codepage->invalidation_map; + decode.page.first=start >> 12; + decode.active_block=decode.block=cache_openblock(); + decode.block->page.start=decode.page.index; + codepage->AddCacheBlock(decode.block); + + gen_save_host_direct(&cache.block.running,(Bit32u)decode.block); + for (i=0;i=4)) goto illegalopcode; + opcode=decode_fetchb(); + } else { + opcode=decode_fetchb(); + if (GCC_UNLIKELY(decode.page.invmap && + (decode.page.invmap[decode.page.index-1]>=4))) goto illegalopcode; + } + } + switch (opcode) { + + case 0x00:dyn_dop_ebgb(DOP_ADD);break; + 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_discardflags();gen_dop_byte_imm(DOP_ADD,DREG(EAX),0,decode_fetchb());break; + case 0x05:gen_discardflags();dyn_dop_word_imm(DOP_ADD,decode.big_op,DREG(EAX));break; + case 0x06:dyn_push_seg(es);break; + case 0x07:dyn_pop_seg(es);break; + + case 0x08:dyn_dop_ebgb(DOP_OR);break; + 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_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: + { + Bitu dual_code=decode_fetchb(); + switch (dual_code) { + /* Short conditional jumps */ + case 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87: + case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f: + dyn_branched_exit((BranchTypes)(dual_code&0xf), + decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); + goto finish_block; + /* PUSH/POP FS */ + case 0xa0:dyn_push_seg(fs);break; + case 0xa1:dyn_pop_seg(fs);break; + /* SHLD Imm/cl*/ + case 0xa4:dyn_dshift_ev_gv(true,true);break; + case 0xa5:dyn_dshift_ev_gv(true,false);break; + /* PUSH/POP GS */ + case 0xa8:dyn_push_seg(gs);break; + case 0xa9:dyn_pop_seg(gs);break; + /* SHRD Imm/cl*/ + case 0xac:dyn_dshift_ev_gv(false,true);break; + case 0xad:dyn_dshift_ev_gv(false,false);break; + /* Imul Ev,Gv */ + case 0xaf:dyn_imul_gvev(0);break; + /* CMPXCHG */ + case 0xb1:dyn_cmpxchg_evgv();break; + /* LFS,LGS */ + case 0xb4: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(fs); + break; + case 0xb5: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(gs); + break; + /* MOVZX Gv,Eb/Ew */ + case 0xb6:dyn_mov_ev_gb(false);break; + case 0xb7:dyn_mov_ev_gw(false);break; + /* MOVSX Gv,Eb/Ew */ + case 0xbe:dyn_mov_ev_gb(true);break; + case 0xbf:dyn_mov_ev_gw(true);break; + + default: + DYN_LOG("Unhandled dual opcode 0F%02X",dual_code); + goto illegalopcode; + } + }break; + + case 0x10:dyn_dop_ebgb(DOP_ADC);break; + 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_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; + + case 0x18:dyn_dop_ebgb(DOP_SBB);break; + 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_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_discardflags();gen_dop_byte_imm(DOP_AND,DREG(EAX),0,decode_fetchb());break; + case 0x25:gen_discardflags();dyn_dop_word_imm(DOP_AND,decode.big_op,DREG(EAX));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_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_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_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_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_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: + dyn_push(&DynRegs[opcode&7]); + break; + case 0x54: /* PUSH SP is special */ + gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP)); + dyn_push(DREG(TMPW)); + gen_releasereg(DREG(TMPW)); + break; + case 0x58:case 0x59:case 0x5a:case 0x5b:case 0x5c:case 0x5d:case 0x5e:case 0x5f: + dyn_pop(&DynRegs[opcode&7]); + break; + case 0x60: /* PUSHA */ + gen_dop_word(DOP_MOV,true,DREG(TMPW),DREG(ESP)); + for (i=G_EAX;i<=G_EDI;i++) { + 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),false); + } + gen_releasereg(DREG(TMPW)); + break; + //segprefix FS,GS + case 0x64:dyn_segprefix(fs);goto restart_prefix; + case 0x65:dyn_segprefix(gs);goto restart_prefix; + //Push immediates + //Operand size + case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix; + //Address size + case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix; + case 0x68: /* PUSH Iv */ + gen_dop_word_imm(DOP_MOV,decode.big_op,DREG(TMPW),decode.big_op ? decode_fetchd() : decode_fetchw()); + dyn_push(DREG(TMPW)); + gen_releasereg(DREG(TMPW)); + break; + /* Imul Ivx */ + case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break; + case 0x6a: /* PUSH Ibx */ + gen_dop_word_imm(DOP_MOV,true,DREG(TMPW),(Bit8s)decode_fetchb()); + dyn_push(DREG(TMPW)); + gen_releasereg(DREG(TMPW)); + break; + /* Imul Ibx */ + case 0x6b:dyn_imul_gvev(1);break; + /* Short conditional jumps */ + case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77: + case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f: + dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb()); + goto finish_block; + /* Group 1 */ + case 0x80:dyn_grp1_eb_ib();break; + case 0x81:dyn_grp1_ev_ivx(false);break; + case 0x82:dyn_grp1_eb_ib();break; + case 0x83:dyn_grp1_ev_ivx(true);break; + /* TEST Gb,Eb Gv,Ev */ + case 0x84:dyn_dop_gbeb(DOP_TEST);break; + case 0x85:dyn_dop_gvev(DOP_TEST);break; + /* XCHG Eb,Gb Ev,Gv */ + case 0x86:dyn_dop_ebgb(DOP_XCHG);break; + case 0x87:dyn_dop_evgv(DOP_XCHG);break; + /* MOV e,g and g,e */ + case 0x88:dyn_mov_ebgb();break; + case 0x89:dyn_mov_evgv();break; + case 0x8a:dyn_mov_gbeb();break; + case 0x8b:dyn_mov_gvev();break; + /* MOV ev,seg */ + case 0x8c:dyn_mov_ev_seg();break; + /* LEA Gv */ + case 0x8d: + 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; + /* POP Ev */ + case 0x8f:dyn_pop_ev();break; + case 0x90: //NOP + case 0x9b: //WAIT/FWAIT + break; + //XCHG ax,reg + case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: + gen_dop_word(DOP_XCHG,decode.big_op,DREG(EAX),&DynRegs[opcode&07]); + break; + /* CBW/CWDE */ + case 0x98: + gen_cbw(decode.big_op,DREG(EAX)); + break; + /* CWD/CDQ */ + case 0x99: + gen_cwd(decode.big_op,DREG(EAX),DREG(EDX)); + break; + /* CALL FAR Ip */ + case 0x9a:dyn_call_far_imm();goto finish_block; + case 0x9c: //PUSHF + gen_protectflags(); + gen_releasereg(DREG(ESP)); + dyn_flags_gen_to_host(); + gen_call_function((void *)&CPU_PUSHF,"%Rd%Id",DREG(TMPB),decode.big_op); + dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + break; + case 0x9d: //POPF + gen_releasereg(DREG(ESP)); + gen_releasereg(DREG(FLAGS)); + gen_call_function((void *)&CPU_POPF,"%Rd%Id",DREG(TMPB),decode.big_op); + dyn_check_bool_exception(DREG(TMPB)); + dyn_flags_host_to_gen(); + gen_releasereg(DREG(TMPB)); + dyn_check_irqrequest(); + break; + /* MOV AL,direct addresses */ + case 0xa0: + gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0, + decode.big_addr ? decode_fetchd() : decode_fetchw()); + 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_release(DREG(EA),DREG(EAX),decode.big_op); + break; + /* MOV direct address,AL */ + case 0xa2: + if (decode.big_addr) { + Bitu val; + if (decode_fetchd_imm(val)) { + gen_lea_imm_mem(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),(void*)val); + } else { + gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,(Bits)val); + } + dyn_write_byte_release(DREG(EA),DREG(EAX),false); + } else { + gen_lea(DREG(EA),decode.segprefix ? decode.segprefix : DREG(DS),0,0,decode_fetchw()); + 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_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_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; + /* LODSB/W/D*/ + case 0xac:dyn_string(STR_LODSB);break; + case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break; + //Mov Byte reg,Imm byte + case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7: + gen_dop_byte_imm(DOP_MOV,&DynRegs[opcode&3],opcode&4,decode_fetchb()); + break; + //Mov word reg imm byte,word, + case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf: + if (decode.big_op) { + dyn_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7]);break; + } else { + gen_dop_word_imm(DOP_MOV,decode.big_op,&DynRegs[opcode&7],decode_fetchw());break; + } + break; + //GRP2 Eb/Ev,Ib + case 0xc0:dyn_grp2_eb(grp2_imm);break; + case 0xc1:dyn_grp2_ev(grp2_imm);break; + //RET near Iw / Ret + case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block; + case 0xc3:dyn_ret_near(0);goto finish_block; + //LES + case 0xc4: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(es); + break; + //LDS + case 0xc5: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(ds); + break; + // MOV Eb/Ev,Ib/Iv + case 0xc6:dyn_mov_ebib();break; + case 0xc7:dyn_mov_eviv();break; + //ENTER and LEAVE + case 0xc8:dyn_enter();break; + case 0xc9:dyn_leave();break; + //RET far Iw / Ret + case 0xca:dyn_ret_far(decode_fetchw());goto finish_block; + case 0xcb:dyn_ret_far(0);goto finish_block; + /* Interrupt */ +// case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block; + /* IRET */ + case 0xcf:dyn_iret();goto finish_block; + + //GRP2 Eb/Ev,1 + case 0xd0:dyn_grp2_eb(grp2_1);break; + case 0xd1:dyn_grp2_ev(grp2_1);break; + //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: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc0(); + else { + dh_fpu_startup(); + dh_fpu_esc0(); + } + } else +#endif + dyn_fpu_esc0(); + break; + case 0xd9: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc1(); + else { + dh_fpu_startup(); + dh_fpu_esc1(); + } + } else +#endif + dyn_fpu_esc1(); + break; + case 0xda: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc2(); + else { + dh_fpu_startup(); + dh_fpu_esc2(); + } + } else +#endif + dyn_fpu_esc2(); + break; + case 0xdb: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc3(); + else { + dh_fpu_startup(); + dh_fpu_esc3(); + } + } else +#endif + dyn_fpu_esc3(); + break; + case 0xdc: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc4(); + else { + dh_fpu_startup(); + dh_fpu_esc4(); + } + } else +#endif + dyn_fpu_esc4(); + break; + case 0xdd: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc5(); + else { + dh_fpu_startup(); + dh_fpu_esc5(); + } + } else +#endif + dyn_fpu_esc5(); + break; + case 0xde: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc6(); + else { + dh_fpu_startup(); + dh_fpu_esc6(); + } + } else +#endif + dyn_fpu_esc6(); + break; + case 0xdf: +#ifdef X86_DYNFPU_DH_ENABLED + if (dyn_dh_fpu.dh_fpu_enabled) { + if (fpu_used) dh_fpu_esc7(); + else { + dh_fpu_startup(); + dh_fpu_esc7(); + } + } else +#endif + dyn_fpu_esc7(); + break; +#endif + //Loops + case 0xe2:dyn_loop(LOOP_NONE);goto finish_block; + case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block; + //IN AL/AX,imm + case 0xe4: { + Bitu port=decode_fetchb(); + dyn_add_iocheck_var(port,1); + gen_call_function((void*)&IO_ReadB,"%Id%Rl",port,DREG(EAX)); + } break; + case 0xe5: { + Bitu port=decode_fetchb(); + dyn_add_iocheck_var(port,decode.big_op?4:2); + if (decode.big_op) { + gen_call_function((void*)&IO_ReadD,"%Id%Rd",port,DREG(EAX)); + } else { + gen_call_function((void*)&IO_ReadW,"%Id%Rw",port,DREG(EAX)); + } + } break; + //OUT imm,AL + case 0xe6: { + Bitu port=decode_fetchb(); + dyn_add_iocheck_var(port,1); + gen_call_function((void*)&IO_WriteB,"%Id%Dl",port,DREG(EAX)); + } break; + case 0xe7: { + Bitu port=decode_fetchb(); + dyn_add_iocheck_var(port,decode.big_op?4:2); + if (decode.big_op) { + gen_call_function((void*)&IO_WriteD,"%Id%Dd",port,DREG(EAX)); + } else { + gen_call_function((void*)&IO_WriteW,"%Id%Dw",port,DREG(EAX)); + } + } break; + case 0xe8: /* CALL Ivx */ + dyn_call_near_imm(); + goto finish_block; + case 0xe9: /* Jmp Ivx */ + dyn_exit_link(decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); + goto finish_block; + case 0xea: /* JMP FAR Ip */ + dyn_jmp_far_imm(); + goto finish_block; + /* Jmp Ibx */ + case 0xeb:dyn_exit_link((Bit8s)decode_fetchb());goto finish_block; + /* IN AL/AX,DX*/ + case 0xec: + dyn_add_iocheck(1); + gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),DREG(EAX)); + break; + case 0xed: + dyn_add_iocheck(decode.big_op?4:2); + if (decode.big_op) { + gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),DREG(EAX)); + } else { + gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),DREG(EAX)); + } + break; + /* OUT DX,AL/AX */ + case 0xee: + dyn_add_iocheck(1); + gen_call_function((void*)&IO_WriteB,"%Dw%Dl",DREG(EDX),DREG(EAX)); + break; + case 0xef: + dyn_add_iocheck(decode.big_op?4:2); + if (decode.big_op) { + gen_call_function((void*)&IO_WriteD,"%Dw%Dd",DREG(EDX),DREG(EAX)); + } else { + gen_call_function((void*)&IO_WriteW,"%Dw%Dw",DREG(EDX),DREG(EAX)); + } + break; + case 0xf0: //LOCK + break; + case 0xf2: //REPNE/NZ + decode.rep=REP_NZ; + goto restart_prefix; + case 0xf3: //REPE/Z + decode.rep=REP_Z; + goto restart_prefix; + /* Change carry flag */ + case 0xf5: //CMC + case 0xf8: //CLC + case 0xf9: //STC + gen_needflags(); + cache_addb(opcode);break; + /* GRP 3 Eb/EV */ + case 0xf6:dyn_grp3_eb();break; + case 0xf7:dyn_grp3_ev();break; + /* Change interrupt flag */ + case 0xfa: //CLI + gen_releasereg(DREG(FLAGS)); + gen_call_function((void *)&CPU_CLI,"%Rd",DREG(TMPB)); + dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + break; + case 0xfb: //STI + gen_releasereg(DREG(FLAGS)); + gen_call_function((void *)&CPU_STI,"%Rd",DREG(TMPB)); + dyn_check_bool_exception(DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + dyn_check_irqrequest(); + if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode + break; + case 0xfc: //CLD + gen_protectflags(); + gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FLAG_DF); + gen_save_host_direct(&cpu.direction,1); + break; + case 0xfd: //STD + gen_protectflags(); + gen_dop_word_imm(DOP_OR,true,DREG(FLAGS),FLAG_DF); + gen_save_host_direct(&cpu.direction,-1); + break; + /* GRP 4 Eb and callback's */ + case 0xfe: + dyn_get_modrm(); + switch (decode.modrm.reg) { + case 0x0://INC Eb + case 0x1://DEC Eb + if (decode.modrm.mod<3) { + dyn_fill_ea();dyn_read_byte(DREG(EA),DREG(TMPB),false); + gen_needcarry(); + gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,DREG(TMPB),0); + dyn_write_byte_release(DREG(EA),DREG(TMPB),false); + gen_releasereg(DREG(TMPB)); + } else { + gen_needcarry(); + gen_sop_byte(decode.modrm.reg==0 ? SOP_INC : SOP_DEC, + &DynRegs[decode.modrm.rm&3],decode.modrm.rm&4); + } + break; + case 0x7: //CALBACK Iw + gen_save_host_direct(&core_dyn.callback,decode_fetchw()); + dyn_set_eip_end(); + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_return(BR_CallBack); + dyn_closeblock(); + goto finish_block; + } + break; + + case 0xff: + { + 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); + } else src=&DynRegs[decode.modrm.rm]; + switch (decode.modrm.reg) { + case 0x0://INC Ev + case 0x1://DEC Ev + 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_release(DREG(EA),DREG(TMPW),decode.big_op); + gen_releasereg(DREG(TMPW)); + } + break; + case 0x2: /* CALL Ev */ + 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 */ + gen_dop_word(DOP_MOV,decode.big_op,DREG(EIP),src); + goto core_close_block; + case 0x3: /* CALL Ep */ + case 0x5: /* JMP Ep */ + gen_protectflags(); + dyn_flags_gen_to_host(); + gen_lea(DREG(EA),DREG(EA),0,0,decode.big_op ? 4: 2); + 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, + decode.big_op ? "%Id%Drw%Drd%Drd" : "%Id%Drw%Drw%Drd", + decode.big_op,DREG(EA),DREG(TMPW),DREG(TMPB)); + dyn_flags_host_to_gen(); + goto core_close_block; + case 0x6: /* PUSH Ev */ + gen_releasereg(DREG(EA)); + dyn_push(src); + break; + default: + LOG(LOG_CPU,LOG_ERROR)("CPU:GRP5:Illegal opcode 0xff"); + goto illegalopcode; + }} + break; + default: +// DYN_LOG("Dynamic unhandled opcode %X",opcode); + goto illegalopcode; + } + } + // link to next block because the maximal number of opcodes has been reached + dyn_set_eip_end(); + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlock,cache.start)); + dyn_closeblock(); + goto finish_block; +core_close_block: + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_return(BR_Normal); + dyn_closeblock(); + goto finish_block; +illegalopcode: + dyn_set_eip_last(); + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_return(BR_Opcode); + dyn_closeblock(); + goto finish_block; +#if (C_DEBUG) + dyn_set_eip_last(); + dyn_reduce_cycles(); + dyn_save_critical_regs(); + gen_return(BR_OpcodeFull); + dyn_closeblock(); + goto finish_block; +#endif +finish_block: + /* Setup the correct end-address */ + decode.active_block->page.end=--decode.page.index; +// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end); + return decode.block; +} diff --git a/src/cpu/core_dyn_x86/dyn_fpu.h b/src/cpu/core_dyn_x86/dyn_fpu.h index d247256..ab23152 100644 --- a/src/cpu/core_dyn_x86/dyn_fpu.h +++ b/src/cpu/core_dyn_x86/dyn_fpu.h @@ -1,670 +1,670 @@ -/* - * Copyright (C) 2002-2009 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: dyn_fpu.h,v 1.5 2009/09/23 20:55:19 c2woody Exp $ */ - -#include "dosbox.h" -#if C_FPU - -#include -#include -#include "cross.h" -#include "mem.h" -#include "fpu.h" -#include "cpu.h" - - -static void FPU_FDECSTP(){ - TOP = (TOP - 1) & 7; -} - -static void FPU_FINCSTP(){ - TOP = (TOP + 1) & 7; -} - -static void FPU_FNSTCW(PhysPt addr){ - mem_writew(addr,fpu.cw); -} - -static void FPU_FFREE(Bitu st) { - fpu.tags[st]=TAG_Empty; -} - - -#if C_FPU_X86 -#include "../../fpu/fpu_instructions_x86.h" -#else -#include "../../fpu/fpu_instructions.h" -#endif - - -#define dyn_fpu_top() { \ - gen_protectflags(); \ - gen_load_host(&TOP,DREG(EA),4); \ - gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm); \ - gen_dop_word_imm(DOP_AND,true,DREG(EA),7); \ - gen_load_host(&TOP,DREG(TMPB),4); \ -} - -static void dyn_eatree() { - Bitu group=(decode.modrm.val >> 3) & 7; - switch (group){ - case 0x00: /* FADD ST,STi */ - gen_call_function((void*)&FPU_FADD_EA,"%Ddr",DREG(TMPB)); - break; - case 0x01: /* FMUL ST,STi */ - gen_call_function((void*)&FPU_FMUL_EA,"%Ddr",DREG(TMPB)); - break; - case 0x02: /* FCOM STi */ - gen_call_function((void*)&FPU_FCOM_EA,"%Ddr",DREG(TMPB)); - break; - case 0x03: /* FCOMP STi */ - gen_call_function((void*)&FPU_FCOM_EA,"%Ddr",DREG(TMPB)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: /* FSUB ST,STi */ - gen_call_function((void*)&FPU_FSUB_EA,"%Ddr",DREG(TMPB)); - break; - case 0x05: /* FSUBR ST,STi */ - gen_call_function((void*)&FPU_FSUBR_EA,"%Ddr",DREG(TMPB)); - break; - case 0x06: /* FDIV ST,STi */ - gen_call_function((void*)&FPU_FDIV_EA,"%Ddr",DREG(TMPB)); - break; - case 0x07: /* FDIVR ST,STi */ - gen_call_function((void*)&FPU_FDIVR_EA,"%Ddr",DREG(TMPB)); - break; - default: - break; - } -} - -static void dyn_fpu_esc0(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - dyn_fpu_top(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - switch (group){ - case 0x00: //FADD ST,STi / - gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x01: // FMUL ST,STi / - gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x02: // FCOM STi / - gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x03: // FCOMP STi / - gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: // FSUB ST,STi / - gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x05: // FSUBR ST,STi / - gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x06: // FDIV ST,STi / - gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x07: // FDIVR ST,STi / - gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - default: - break; - } - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_F32_EA,"%Ddr",DREG(EA)); - gen_load_host(&TOP,DREG(TMPB),4); - dyn_eatree(); - } -} - -static void dyn_fpu_esc1(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - switch (group){ - case 0x00: /* FLD STi */ - gen_protectflags(); - gen_load_host(&TOP,DREG(EA),4); - gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm); - gen_dop_word_imm(DOP_AND,true,DREG(EA),7); - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: /* FXCH STi */ - dyn_fpu_top(); - gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x02: /* FNOP */ - gen_call_function((void*)&FPU_FNOP,""); - break; - case 0x03: /* FSTP STi */ - dyn_fpu_top(); - gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: - switch(sub){ - case 0x00: /* FCHS */ - gen_call_function((void*)&FPU_FCHS,""); - break; - case 0x01: /* FABS */ - gen_call_function((void*)&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 */ - gen_call_function((void*)&FPU_FTST,""); - break; - case 0x05: /* FXAM */ - gen_call_function((void*)&FPU_FXAM,""); - break; - case 0x06: /* FTSTP (cyrix)*/ - case 0x07: /* UNKNOWN */ - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); - break; - } - break; - case 0x05: - switch(sub){ - case 0x00: /* FLD1 */ - gen_call_function((void*)&FPU_FLD1,""); - break; - case 0x01: /* FLDL2T */ - gen_call_function((void*)&FPU_FLDL2T,""); - break; - case 0x02: /* FLDL2E */ - gen_call_function((void*)&FPU_FLDL2E,""); - break; - case 0x03: /* FLDPI */ - gen_call_function((void*)&FPU_FLDPI,""); - break; - case 0x04: /* FLDLG2 */ - gen_call_function((void*)&FPU_FLDLG2,""); - break; - case 0x05: /* FLDLN2 */ - gen_call_function((void*)&FPU_FLDLN2,""); - break; - case 0x06: /* FLDZ*/ - gen_call_function((void*)&FPU_FLDZ,""); - break; - case 0x07: /* ILLEGAL */ - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); - break; - } - break; - case 0x06: - switch(sub){ - case 0x00: /* F2XM1 */ - gen_call_function((void*)&FPU_F2XM1,""); - break; - case 0x01: /* FYL2X */ - gen_call_function((void*)&FPU_FYL2X,""); - break; - case 0x02: /* FPTAN */ - gen_call_function((void*)&FPU_FPTAN,""); - break; - case 0x03: /* FPATAN */ - gen_call_function((void*)&FPU_FPATAN,""); - break; - case 0x04: /* FXTRACT */ - gen_call_function((void*)&FPU_FXTRACT,""); - break; - case 0x05: /* FPREM1 */ - gen_call_function((void*)&FPU_FPREM1,""); - break; - case 0x06: /* FDECSTP */ - gen_call_function((void*)&FPU_FDECSTP,""); - break; - case 0x07: /* FINCSTP */ - gen_call_function((void*)&FPU_FINCSTP,""); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); - break; - } - break; - case 0x07: - switch(sub){ - case 0x00: /* FPREM */ - gen_call_function((void*)&FPU_FPREM,""); - break; - case 0x01: /* FYL2XP1 */ - gen_call_function((void*)&FPU_FYL2XP1,""); - break; - case 0x02: /* FSQRT */ - gen_call_function((void*)&FPU_FSQRT,""); - break; - case 0x03: /* FSINCOS */ - gen_call_function((void*)&FPU_FSINCOS,""); - break; - case 0x04: /* FRNDINT */ - gen_call_function((void*)&FPU_FRNDINT,""); - break; - case 0x05: /* FSCALE */ - gen_call_function((void*)&FPU_FSCALE,""); - break; - case 0x06: /* FSIN */ - gen_call_function((void*)&FPU_FSIN,""); - break; - case 0x07: /* FCOS */ - gen_call_function((void*)&FPU_FCOS,""); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); - break; - } - } else { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - dyn_fill_ea(); - switch(group){ - case 0x00: /* FLD float*/ - gen_protectflags(); - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FLD_F32,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: /* UNKNOWN */ - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FST float*/ - gen_call_function((void*)&FPU_FST_F32,"%Ddr",DREG(EA)); - break; - case 0x03: /* FSTP float*/ - gen_call_function((void*)&FPU_FST_F32,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: /* FLDENV */ - gen_call_function((void*)&FPU_FLDENV,"%Ddr",DREG(EA)); - break; - case 0x05: /* FLDCW */ - gen_call_function((void *)&FPU_FLDCW,"%Ddr",DREG(EA)); - break; - case 0x06: /* FSTENV */ - gen_call_function((void *)&FPU_FSTENV,"%Ddr",DREG(EA)); - break; - case 0x07: /* FNSTCW*/ - gen_call_function((void *)&FPU_FNSTCW,"%Ddr",DREG(EA)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); - break; - } - } -} - -static void dyn_fpu_esc2(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - switch(group){ - case 0x05: - switch(sub){ - case 0x01: /* FUCOMPP */ - gen_protectflags(); - gen_load_host(&TOP,DREG(EA),4); - gen_dop_word_imm(DOP_ADD,true,DREG(EA),1); - gen_dop_word_imm(DOP_AND,true,DREG(EA),7); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void *)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void *)&FPU_FPOP,""); - gen_call_function((void *)&FPU_FPOP,""); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub); - break; - } - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_I32_EA,"%Ddr",DREG(EA)); - gen_load_host(&TOP,DREG(TMPB),4); - dyn_eatree(); - } -} - -static void dyn_fpu_esc3(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - switch (group) { - case 0x04: - switch (sub) { - case 0x00: //FNENI - case 0x01: //FNDIS - LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub); - break; - case 0x02: //FNCLEX FCLEX - gen_call_function((void*)&FPU_FCLEX,""); - break; - case 0x03: //FNINIT FINIT - gen_call_function((void*)&FPU_FINIT,""); - break; - case 0x04: //FNSETPM - case 0x05: //FRSTPM -// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); - break; - default: - E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub); - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub); - break; - } - } else { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - dyn_fill_ea(); - switch(group){ - case 0x00: /* FILD */ - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_protectflags(); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FLD_I32,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: /* FISTTP */ - LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FIST */ - gen_call_function((void*)&FPU_FST_I32,"%Ddr",DREG(EA)); - break; - case 0x03: /* FISTP */ - gen_call_function((void*)&FPU_FST_I32,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x05: /* FLD 80 Bits Real */ - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_call_function((void*)&FPU_FLD_F80,"%Ddr",DREG(EA)); - break; - case 0x07: /* FSTP 80 Bits Real */ - gen_call_function((void*)&FPU_FST_F80,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); - } - } -} - -static void dyn_fpu_esc4(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - dyn_fpu_top(); - switch(group){ - case 0x00: /* FADD STi,ST*/ - gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: /* FMUL STi,ST*/ - gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x02: /* FCOM*/ - gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x03: /* FCOMP*/ - gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: /* FSUBR STi,ST*/ - gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x05: /* FSUB STi,ST*/ - gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x06: /* FDIVR STi,ST*/ - gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x07: /* FDIV STi,ST*/ - gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - default: - break; - } - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_F64_EA,"%Ddr",DREG(EA)); - gen_load_host(&TOP,DREG(TMPB),4); - dyn_eatree(); - } -} - -static void dyn_fpu_esc5(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - dyn_fpu_top(); - switch(group){ - case 0x00: /* FFREE STi */ - gen_call_function((void*)&FPU_FFREE,"%Ddr",DREG(EA)); - break; - case 0x01: /* FXCH STi*/ - gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x02: /* FST STi */ - gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x03: /* FSTP STi*/ - gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: /* FUCOM STi */ - gen_call_function((void*)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x05: /*FUCOMP STi */ - gen_call_function((void*)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",group,sub); - break; - } - gen_releasereg(DREG(EA)); - gen_releasereg(DREG(TMPB)); - } else { - dyn_fill_ea(); - switch(group){ - case 0x00: /* FLD double real*/ - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_protectflags(); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FLD_F64,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: /* FISTTP longint*/ - LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FST double real*/ - gen_call_function((void*)&FPU_FST_F64,"%Ddr",DREG(EA)); - break; - case 0x03: /* FSTP double real*/ - gen_call_function((void*)&FPU_FST_F64,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: /* FRSTOR */ - gen_call_function((void*)&FPU_FRSTOR,"%Ddr",DREG(EA)); - break; - case 0x06: /* FSAVE */ - gen_call_function((void*)&FPU_FSAVE,"%Ddr",DREG(EA)); - break; - case 0x07: /*FNSTSW */ - gen_protectflags(); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_SET_TOP,"%Dd",DREG(TMPB)); - gen_load_host(&fpu.sw,DREG(TMPB),4); - gen_call_function((void*)&mem_writew,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); - } - } -} - -static void dyn_fpu_esc6(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - dyn_fpu_top(); - switch(group){ - case 0x00: /*FADDP STi,ST*/ - gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: /* FMULP STi,ST*/ - gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x02: /* FCOMP5*/ - gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - 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; - } - gen_load_host(&TOP,DREG(EA),4); - gen_dop_word_imm(DOP_ADD,true,DREG(EA),1); - gen_dop_word_imm(DOP_AND,true,DREG(EA),7); - gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); /* extra pop at the bottom*/ - break; - case 0x04: /* FSUBRP STi,ST*/ - gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x05: /* FSUBP STi,ST*/ - gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x06: /* FDIVRP STi,ST*/ - gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x07: /* FDIVP STi,ST*/ - gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - default: - break; - } - gen_call_function((void*)&FPU_FPOP,""); - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_I16_EA,"%Ddr",DREG(EA)); - gen_load_host(&TOP,DREG(TMPB),4); - dyn_eatree(); - } -} - -static void dyn_fpu_esc7(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - switch (group){ - case 0x00: /* FFREEP STi*/ - dyn_fpu_top(); - gen_call_function((void*)&FPU_FFREE,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x01: /* FXCH STi*/ - dyn_fpu_top(); - gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - break; - case 0x02: /* FSTP STi*/ - case 0x03: /* FSTP STi*/ - dyn_fpu_top(); - gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: - switch(sub){ - case 0x00: /* FNSTSW AX*/ - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_SET_TOP,"%Ddr",DREG(TMPB)); - gen_mov_host(&fpu.sw,DREG(EAX),2); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); - break; - } - } else { - dyn_fill_ea(); - switch(group){ - case 0x00: /* FILD Bit16s */ - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FLD_I16,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x01: - LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FIST Bit16s */ - gen_call_function((void*)&FPU_FST_I16,"%Ddr",DREG(EA)); - break; - case 0x03: /* FISTP Bit16s */ - gen_call_function((void*)&FPU_FST_I16,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x04: /* FBLD packed BCD */ - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FBLD,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x05: /* FILD Bit64s */ - gen_call_function((void*)&FPU_PREP_PUSH,""); - gen_load_host(&TOP,DREG(TMPB),4); - gen_call_function((void*)&FPU_FLD_I64,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); - break; - case 0x06: /* FBSTP packed BCD */ - gen_call_function((void*)&FPU_FBST,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - case 0x07: /* FISTP Bit64s */ - gen_call_function((void*)&FPU_FST_I64,"%Ddr",DREG(EA)); - gen_call_function((void*)&FPU_FPOP,""); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); - break; - } - } -} - -#endif +/* + * Copyright (C) 2002-2010 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: dyn_fpu.h,v 1.5 2009-09-23 20:55:19 c2woody Exp $ */ + +#include "dosbox.h" +#if C_FPU + +#include +#include +#include "cross.h" +#include "mem.h" +#include "fpu.h" +#include "cpu.h" + + +static void FPU_FDECSTP(){ + TOP = (TOP - 1) & 7; +} + +static void FPU_FINCSTP(){ + TOP = (TOP + 1) & 7; +} + +static void FPU_FNSTCW(PhysPt addr){ + mem_writew(addr,fpu.cw); +} + +static void FPU_FFREE(Bitu st) { + fpu.tags[st]=TAG_Empty; +} + + +#if C_FPU_X86 +#include "../../fpu/fpu_instructions_x86.h" +#else +#include "../../fpu/fpu_instructions.h" +#endif + + +#define dyn_fpu_top() { \ + gen_protectflags(); \ + gen_load_host(&TOP,DREG(EA),4); \ + gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm); \ + gen_dop_word_imm(DOP_AND,true,DREG(EA),7); \ + gen_load_host(&TOP,DREG(TMPB),4); \ +} + +static void dyn_eatree() { + Bitu group=(decode.modrm.val >> 3) & 7; + switch (group){ + case 0x00: /* FADD ST,STi */ + gen_call_function((void*)&FPU_FADD_EA,"%Ddr",DREG(TMPB)); + break; + case 0x01: /* FMUL ST,STi */ + gen_call_function((void*)&FPU_FMUL_EA,"%Ddr",DREG(TMPB)); + break; + case 0x02: /* FCOM STi */ + gen_call_function((void*)&FPU_FCOM_EA,"%Ddr",DREG(TMPB)); + break; + case 0x03: /* FCOMP STi */ + gen_call_function((void*)&FPU_FCOM_EA,"%Ddr",DREG(TMPB)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: /* FSUB ST,STi */ + gen_call_function((void*)&FPU_FSUB_EA,"%Ddr",DREG(TMPB)); + break; + case 0x05: /* FSUBR ST,STi */ + gen_call_function((void*)&FPU_FSUBR_EA,"%Ddr",DREG(TMPB)); + break; + case 0x06: /* FDIV ST,STi */ + gen_call_function((void*)&FPU_FDIV_EA,"%Ddr",DREG(TMPB)); + break; + case 0x07: /* FDIVR ST,STi */ + gen_call_function((void*)&FPU_FDIVR_EA,"%Ddr",DREG(TMPB)); + break; + default: + break; + } +} + +static void dyn_fpu_esc0(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + dyn_fpu_top(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + switch (group){ + case 0x00: //FADD ST,STi / + gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x01: // FMUL ST,STi / + gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x02: // FCOM STi / + gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x03: // FCOMP STi / + gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: // FSUB ST,STi / + gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x05: // FSUBR ST,STi / + gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x06: // FDIV ST,STi / + gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x07: // FDIVR ST,STi / + gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + default: + break; + } + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_F32_EA,"%Ddr",DREG(EA)); + gen_load_host(&TOP,DREG(TMPB),4); + dyn_eatree(); + } +} + +static void dyn_fpu_esc1(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + switch (group){ + case 0x00: /* FLD STi */ + gen_protectflags(); + gen_load_host(&TOP,DREG(EA),4); + gen_dop_word_imm(DOP_ADD,true,DREG(EA),decode.modrm.rm); + gen_dop_word_imm(DOP_AND,true,DREG(EA),7); + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: /* FXCH STi */ + dyn_fpu_top(); + gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x02: /* FNOP */ + gen_call_function((void*)&FPU_FNOP,""); + break; + case 0x03: /* FSTP STi */ + dyn_fpu_top(); + gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: + switch(sub){ + case 0x00: /* FCHS */ + gen_call_function((void*)&FPU_FCHS,""); + break; + case 0x01: /* FABS */ + gen_call_function((void*)&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 */ + gen_call_function((void*)&FPU_FTST,""); + break; + case 0x05: /* FXAM */ + gen_call_function((void*)&FPU_FXAM,""); + break; + case 0x06: /* FTSTP (cyrix)*/ + case 0x07: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + case 0x05: + switch(sub){ + case 0x00: /* FLD1 */ + gen_call_function((void*)&FPU_FLD1,""); + break; + case 0x01: /* FLDL2T */ + gen_call_function((void*)&FPU_FLDL2T,""); + break; + case 0x02: /* FLDL2E */ + gen_call_function((void*)&FPU_FLDL2E,""); + break; + case 0x03: /* FLDPI */ + gen_call_function((void*)&FPU_FLDPI,""); + break; + case 0x04: /* FLDLG2 */ + gen_call_function((void*)&FPU_FLDLG2,""); + break; + case 0x05: /* FLDLN2 */ + gen_call_function((void*)&FPU_FLDLN2,""); + break; + case 0x06: /* FLDZ*/ + gen_call_function((void*)&FPU_FLDZ,""); + break; + case 0x07: /* ILLEGAL */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + case 0x06: + switch(sub){ + case 0x00: /* F2XM1 */ + gen_call_function((void*)&FPU_F2XM1,""); + break; + case 0x01: /* FYL2X */ + gen_call_function((void*)&FPU_FYL2X,""); + break; + case 0x02: /* FPTAN */ + gen_call_function((void*)&FPU_FPTAN,""); + break; + case 0x03: /* FPATAN */ + gen_call_function((void*)&FPU_FPATAN,""); + break; + case 0x04: /* FXTRACT */ + gen_call_function((void*)&FPU_FXTRACT,""); + break; + case 0x05: /* FPREM1 */ + gen_call_function((void*)&FPU_FPREM1,""); + break; + case 0x06: /* FDECSTP */ + gen_call_function((void*)&FPU_FDECSTP,""); + break; + case 0x07: /* FINCSTP */ + gen_call_function((void*)&FPU_FINCSTP,""); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + case 0x07: + switch(sub){ + case 0x00: /* FPREM */ + gen_call_function((void*)&FPU_FPREM,""); + break; + case 0x01: /* FYL2XP1 */ + gen_call_function((void*)&FPU_FYL2XP1,""); + break; + case 0x02: /* FSQRT */ + gen_call_function((void*)&FPU_FSQRT,""); + break; + case 0x03: /* FSINCOS */ + gen_call_function((void*)&FPU_FSINCOS,""); + break; + case 0x04: /* FRNDINT */ + gen_call_function((void*)&FPU_FRNDINT,""); + break; + case 0x05: /* FSCALE */ + gen_call_function((void*)&FPU_FSCALE,""); + break; + case 0x06: /* FSIN */ + gen_call_function((void*)&FPU_FSIN,""); + break; + case 0x07: /* FCOS */ + gen_call_function((void*)&FPU_FCOS,""); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",group,sub); + break; + } + } else { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + dyn_fill_ea(); + switch(group){ + case 0x00: /* FLD float*/ + gen_protectflags(); + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FLD_F32,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST float*/ + gen_call_function((void*)&FPU_FST_F32,"%Ddr",DREG(EA)); + break; + case 0x03: /* FSTP float*/ + gen_call_function((void*)&FPU_FST_F32,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: /* FLDENV */ + gen_call_function((void*)&FPU_FLDENV,"%Ddr",DREG(EA)); + break; + case 0x05: /* FLDCW */ + gen_call_function((void *)&FPU_FLDCW,"%Ddr",DREG(EA)); + break; + case 0x06: /* FSTENV */ + gen_call_function((void *)&FPU_FSTENV,"%Ddr",DREG(EA)); + break; + case 0x07: /* FNSTCW*/ + gen_call_function((void *)&FPU_FNSTCW,"%Ddr",DREG(EA)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + } + } +} + +static void dyn_fpu_esc2(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + switch(group){ + case 0x05: + switch(sub){ + case 0x01: /* FUCOMPP */ + gen_protectflags(); + gen_load_host(&TOP,DREG(EA),4); + gen_dop_word_imm(DOP_ADD,true,DREG(EA),1); + gen_dop_word_imm(DOP_AND,true,DREG(EA),7); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void *)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void *)&FPU_FPOP,""); + gen_call_function((void *)&FPU_FPOP,""); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",group,sub); + break; + } + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_I32_EA,"%Ddr",DREG(EA)); + gen_load_host(&TOP,DREG(TMPB),4); + dyn_eatree(); + } +} + +static void dyn_fpu_esc3(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + switch (group) { + case 0x04: + switch (sub) { + case 0x00: //FNENI + case 0x01: //FNDIS + LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub); + break; + case 0x02: //FNCLEX FCLEX + gen_call_function((void*)&FPU_FCLEX,""); + break; + case 0x03: //FNINIT FINIT + gen_call_function((void*)&FPU_FINIT,""); + break; + case 0x04: //FNSETPM + case 0x05: //FRSTPM +// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); + break; + default: + E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub); + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub); + break; + } + } else { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + dyn_fill_ea(); + switch(group){ + case 0x00: /* FILD */ + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_protectflags(); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FLD_I32,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FIST */ + gen_call_function((void*)&FPU_FST_I32,"%Ddr",DREG(EA)); + break; + case 0x03: /* FISTP */ + gen_call_function((void*)&FPU_FST_I32,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x05: /* FLD 80 Bits Real */ + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_call_function((void*)&FPU_FLD_F80,"%Ddr",DREG(EA)); + break; + case 0x07: /* FSTP 80 Bits Real */ + gen_call_function((void*)&FPU_FST_F80,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + } + } +} + +static void dyn_fpu_esc4(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + dyn_fpu_top(); + switch(group){ + case 0x00: /* FADD STi,ST*/ + gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: /* FMUL STi,ST*/ + gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x02: /* FCOM*/ + gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x03: /* FCOMP*/ + gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: /* FSUBR STi,ST*/ + gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x05: /* FSUB STi,ST*/ + gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x06: /* FDIVR STi,ST*/ + gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x07: /* FDIV STi,ST*/ + gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + default: + break; + } + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_F64_EA,"%Ddr",DREG(EA)); + gen_load_host(&TOP,DREG(TMPB),4); + dyn_eatree(); + } +} + +static void dyn_fpu_esc5(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + dyn_fpu_top(); + switch(group){ + case 0x00: /* FFREE STi */ + gen_call_function((void*)&FPU_FFREE,"%Ddr",DREG(EA)); + break; + case 0x01: /* FXCH STi*/ + gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x02: /* FST STi */ + gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x03: /* FSTP STi*/ + gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: /* FUCOM STi */ + gen_call_function((void*)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x05: /*FUCOMP STi */ + gen_call_function((void*)&FPU_FUCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",group,sub); + break; + } + gen_releasereg(DREG(EA)); + gen_releasereg(DREG(TMPB)); + } else { + dyn_fill_ea(); + switch(group){ + case 0x00: /* FLD double real*/ + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_protectflags(); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FLD_F64,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: /* FISTTP longint*/ + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST double real*/ + gen_call_function((void*)&FPU_FST_F64,"%Ddr",DREG(EA)); + break; + case 0x03: /* FSTP double real*/ + gen_call_function((void*)&FPU_FST_F64,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: /* FRSTOR */ + gen_call_function((void*)&FPU_FRSTOR,"%Ddr",DREG(EA)); + break; + case 0x06: /* FSAVE */ + gen_call_function((void*)&FPU_FSAVE,"%Ddr",DREG(EA)); + break; + case 0x07: /*FNSTSW */ + gen_protectflags(); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_SET_TOP,"%Dd",DREG(TMPB)); + gen_load_host(&fpu.sw,DREG(TMPB),4); + gen_call_function((void*)&mem_writew,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + } + } +} + +static void dyn_fpu_esc6(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + dyn_fpu_top(); + switch(group){ + case 0x00: /*FADDP STi,ST*/ + gen_call_function((void*)&FPU_FADD,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: /* FMULP STi,ST*/ + gen_call_function((void*)&FPU_FMUL,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x02: /* FCOMP5*/ + gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + 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; + } + gen_load_host(&TOP,DREG(EA),4); + gen_dop_word_imm(DOP_ADD,true,DREG(EA),1); + gen_dop_word_imm(DOP_AND,true,DREG(EA),7); + gen_call_function((void*)&FPU_FCOM,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); /* extra pop at the bottom*/ + break; + case 0x04: /* FSUBRP STi,ST*/ + gen_call_function((void*)&FPU_FSUBR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x05: /* FSUBP STi,ST*/ + gen_call_function((void*)&FPU_FSUB,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x06: /* FDIVRP STi,ST*/ + gen_call_function((void*)&FPU_FDIVR,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x07: /* FDIVP STi,ST*/ + gen_call_function((void*)&FPU_FDIV,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + default: + break; + } + gen_call_function((void*)&FPU_FPOP,""); + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_I16_EA,"%Ddr",DREG(EA)); + gen_load_host(&TOP,DREG(TMPB),4); + dyn_eatree(); + } +} + +static void dyn_fpu_esc7(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + switch (group){ + case 0x00: /* FFREEP STi*/ + dyn_fpu_top(); + gen_call_function((void*)&FPU_FFREE,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x01: /* FXCH STi*/ + dyn_fpu_top(); + gen_call_function((void*)&FPU_FXCH,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + break; + case 0x02: /* FSTP STi*/ + case 0x03: /* FSTP STi*/ + dyn_fpu_top(); + gen_call_function((void*)&FPU_FST,"%Ddr%Ddr",DREG(TMPB),DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: + switch(sub){ + case 0x00: /* FNSTSW AX*/ + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_SET_TOP,"%Ddr",DREG(TMPB)); + gen_mov_host(&fpu.sw,DREG(EAX),2); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + break; + } + } else { + dyn_fill_ea(); + switch(group){ + case 0x00: /* FILD Bit16s */ + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FLD_I16,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x01: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FIST Bit16s */ + gen_call_function((void*)&FPU_FST_I16,"%Ddr",DREG(EA)); + break; + case 0x03: /* FISTP Bit16s */ + gen_call_function((void*)&FPU_FST_I16,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x04: /* FBLD packed BCD */ + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FBLD,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x05: /* FILD Bit64s */ + gen_call_function((void*)&FPU_PREP_PUSH,""); + gen_load_host(&TOP,DREG(TMPB),4); + gen_call_function((void*)&FPU_FLD_I64,"%Ddr%Ddr",DREG(EA),DREG(TMPB)); + break; + case 0x06: /* FBSTP packed BCD */ + gen_call_function((void*)&FPU_FBST,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + case 0x07: /* FISTP Bit64s */ + gen_call_function((void*)&FPU_FST_I64,"%Ddr",DREG(EA)); + gen_call_function((void*)&FPU_FPOP,""); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + } + } +} + +#endif diff --git a/src/cpu/core_dyn_x86/dyn_fpu_dh.h b/src/cpu/core_dyn_x86/dyn_fpu_dh.h index 8e61531..cc48a02 100644 --- a/src/cpu/core_dyn_x86/dyn_fpu_dh.h +++ b/src/cpu/core_dyn_x86/dyn_fpu_dh.h @@ -1,498 +1,498 @@ -/* - * Copyright (C) 2002-2009 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: dyn_fpu_dh.h,v 1.7 2009/09/23 20:55:19 c2woody Exp $ */ - -#include "dosbox.h" -#if C_FPU - -static void FPU_FLD_16(PhysPt addr) { - dyn_dh_fpu.temp.m1 = (Bit32u)mem_readw(addr); -} - -static void FPU_FST_16(PhysPt addr) { - mem_writew(addr,(Bit16u)dyn_dh_fpu.temp.m1); -} - -static void FPU_FLD_32(PhysPt addr) { - dyn_dh_fpu.temp.m1 = mem_readd(addr); -} - -static void FPU_FST_32(PhysPt addr) { - mem_writed(addr,dyn_dh_fpu.temp.m1); -} - -static void FPU_FLD_64(PhysPt addr) { - dyn_dh_fpu.temp.m1 = mem_readd(addr); - dyn_dh_fpu.temp.m2 = mem_readd(addr+4); -} - -static void FPU_FST_64(PhysPt addr) { - mem_writed(addr,dyn_dh_fpu.temp.m1); - mem_writed(addr+4,dyn_dh_fpu.temp.m2); -} - -static void FPU_FLD_80(PhysPt addr) { - dyn_dh_fpu.temp.m1 = mem_readd(addr); - dyn_dh_fpu.temp.m2 = mem_readd(addr+4); - dyn_dh_fpu.temp.m3 = mem_readw(addr+8); -} - -static void FPU_FST_80(PhysPt addr) { - mem_writed(addr,dyn_dh_fpu.temp.m1); - mem_writed(addr+4,dyn_dh_fpu.temp.m2); - mem_writew(addr+8,dyn_dh_fpu.temp.m3); -} - -static void FPU_FLDCW_DH(PhysPt addr){ - dyn_dh_fpu.cw = mem_readw(addr); - dyn_dh_fpu.temp.m1 = (Bit32u)(dyn_dh_fpu.cw|0x3f); -} - -static void FPU_FNSTCW_DH(PhysPt addr){ - mem_writew(addr,(Bit16u)(dyn_dh_fpu.cw&0xffff)); -} - -static void FPU_FNINIT_DH(void){ - dyn_dh_fpu.cw = 0x37f; -} - -static void FPU_FSTENV_DH(PhysPt addr){ - if(!cpu.code.big) { - mem_writew(addr+0,(Bit16u)dyn_dh_fpu.cw); - mem_writew(addr+2,(Bit16u)dyn_dh_fpu.temp.m2); - mem_writew(addr+4,dyn_dh_fpu.temp.m3); - } else { - mem_writed(addr+0,dyn_dh_fpu.temp.m1); - mem_writew(addr+0,(Bit16u)dyn_dh_fpu.cw); - mem_writed(addr+4,dyn_dh_fpu.temp.m2); - mem_writed(addr+8,dyn_dh_fpu.temp.m3); - } -} - -static void FPU_FLDENV_DH(PhysPt addr){ - if(!cpu.code.big) { - dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); - dyn_dh_fpu.temp.m1 = dyn_dh_fpu.cw|0x3f; - dyn_dh_fpu.temp.m2 = (Bit32u)mem_readw(addr+2); - dyn_dh_fpu.temp.m3 = mem_readw(addr+4); - } else { - dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); - dyn_dh_fpu.temp.m1 = mem_readd(addr)|0x3f; - dyn_dh_fpu.temp.m2 = mem_readd(addr+4); - dyn_dh_fpu.temp.m3 = mem_readw(addr+8); - dyn_dh_fpu.temp.d1 = mem_readw(addr+10); - } -} - -static void FPU_FSAVE_DH(PhysPt addr){ - if (!cpu.code.big) { - mem_writew(addr,(Bit16u)dyn_dh_fpu.cw); - addr+=2; - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x04]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x05]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x08]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x09]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0c]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0d]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x10]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x11]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x14]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x15]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x18]); - mem_writeb(addr++,dyn_dh_fpu.temp_state[0x19]); - for(Bitu i=28;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]); - } else { - mem_writew(addr,(Bit16u)dyn_dh_fpu.cw); - addr+=2; - for(Bitu i=2;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]); - } -} - -static void FPU_FRSTOR_DH(PhysPt addr){ - if (!cpu.code.big) { - dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); - dyn_dh_fpu.temp_state[0x00] = mem_readb(addr++)|0x3f; - dyn_dh_fpu.temp_state[0x01] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x04] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x05] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x08] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x09] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x0c] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x0d] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x10] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x11] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x14] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x15] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x18] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0x19] = mem_readb(addr++); - for(Bitu i=28;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++); - } else { - dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); - for(Bitu i=0;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++); - dyn_dh_fpu.temp_state[0]|=0x3f; - } -} - -static void dh_fpu_esc0(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - cache_addb(0xd8); - cache_addb(decode.modrm.val); - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); - cache_addb(0xd8); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - } -} - -static void dh_fpu_esc1(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - cache_addb(0xd9); - cache_addb(decode.modrm.val); - } else { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - dyn_fill_ea(); - switch(group){ - case 0x00: /* FLD float*/ - gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); - cache_addb(0xd9); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x01: /* UNKNOWN */ - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FST float*/ - cache_addb(0xd9); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); - break; - case 0x03: /* FSTP float*/ - cache_addb(0xd9); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); - break; - case 0x04: /* FLDENV */ - gen_call_function((void*)&FPU_FLDENV_DH,"%Ddr",DREG(EA)); - cache_addb(0xd9); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x05: /* FLDCW */ - gen_call_function((void *)&FPU_FLDCW_DH,"%Ddr",DREG(EA)); - cache_addb(0xd9); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x06: /* FSTENV */ - cache_addb(0xd9); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FSTENV_DH,"%Ddr",DREG(EA)); - break; - case 0x07: /* FNSTCW*/ - gen_call_function((void*)&FPU_FNSTCW_DH,"%Ddr",DREG(EA)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); - break; - } - } -} - -static void dh_fpu_esc2(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - cache_addb(0xda); - cache_addb(decode.modrm.val); - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); - cache_addb(0xda); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - } -} - -static void dh_fpu_esc3(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - switch (group) { - case 0x04: - switch (sub) { - case 0x00: //FNENI - case 0x01: //FNDIS - LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub); - break; - case 0x02: //FNCLEX FCLEX - cache_addb(0xdb); - cache_addb(decode.modrm.val); - break; - case 0x03: //FNINIT FINIT - gen_call_function((void*)&FPU_FNINIT_DH,""); - cache_addb(0xdb); - cache_addb(decode.modrm.val); - break; - case 0x04: //FNSETPM - case 0x05: //FRSTPM -// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); - break; - default: - E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub); - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub); - break; - } - } else { - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - dyn_fill_ea(); - switch(group){ - case 0x00: /* FILD */ - gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); - cache_addb(0xdb); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x01: /* FISTTP */ - LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FIST */ - cache_addb(0xdb); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); - break; - case 0x03: /* FISTP */ - cache_addb(0xdb); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); - break; - case 0x05: /* FLD 80 Bits Real */ - gen_call_function((void*)&FPU_FLD_80,"%Ddr",DREG(EA)); - cache_addb(0xdb); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x07: /* FSTP 80 Bits Real */ - cache_addb(0xdb); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_80,"%Ddr",DREG(EA)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); - } - } -} - -static void dh_fpu_esc4(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - cache_addb(0xdc); - cache_addb(decode.modrm.val); - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA)); - cache_addb(0xdc); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - } -} - -static void dh_fpu_esc5(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - cache_addb(0xdd); - cache_addb(decode.modrm.val); - } else { - dyn_fill_ea(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - switch(group){ - case 0x00: /* FLD double real*/ - gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA)); - cache_addb(0xdd); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x01: /* FISTTP longint*/ - LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FST double real*/ - cache_addb(0xdd); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA)); - break; - case 0x03: /* FSTP double real*/ - cache_addb(0xdd); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA)); - break; - case 0x04: /* FRSTOR */ - gen_call_function((void*)&FPU_FRSTOR_DH,"%Ddr",DREG(EA)); - cache_addb(0xdd); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp_state[0]))); - break; - case 0x06: /* FSAVE */ - cache_addb(0xdd); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp_state[0]))); - gen_call_function((void*)&FPU_FSAVE_DH,"%Ddr",DREG(EA)); - cache_addb(0xdb); - cache_addb(0xe3); - break; - case 0x07: /* FNSTSW */ - cache_addb(0xdd); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); - } - } -} - -static void dh_fpu_esc6(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - cache_addb(0xde); - cache_addb(decode.modrm.val); - } else { - dyn_fill_ea(); - gen_call_function((void*)&FPU_FLD_16,"%Ddr",DREG(EA)); - cache_addb(0xde); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - } -} - -static void dh_fpu_esc7(){ - dyn_get_modrm(); - Bitu group=(decode.modrm.val >> 3) & 7; - Bitu sub=(decode.modrm.val & 7); - if (decode.modrm.val >= 0xc0) { - switch (group){ - case 0x00: /* FFREEP STi*/ - cache_addb(0xdf); - cache_addb(decode.modrm.val); - break; - case 0x01: /* FXCH STi*/ - cache_addb(0xdf); - cache_addb(decode.modrm.val); - break; - case 0x02: /* FSTP STi*/ - case 0x03: /* FSTP STi*/ - cache_addb(0xdf); - cache_addb(decode.modrm.val); - break; - case 0x04: - switch(sub){ - case 0x00: /* FNSTSW AX*/ - cache_addb(0xdd); - cache_addb(0x05|(0x07<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_load_host(&(dyn_dh_fpu.temp.m1),DREG(TMPB),4); - gen_dop_word(DOP_MOV,false,DREG(EAX),DREG(TMPB)); - gen_releasereg(DREG(TMPB)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); - break; - } - } else { - dyn_fill_ea(); - switch(group){ - case 0x00: /* FILD Bit16s */ - gen_call_function((void*)&FPU_FLD_16,"%Ddr",DREG(EA)); - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x01: - LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); - break; - case 0x02: /* FIST Bit16s */ - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA)); - break; - case 0x03: /* FISTP Bit16s */ - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA)); - break; - case 0x04: /* FBLD packed BCD */ - gen_call_function((void*)&FPU_FLD_80,"%Ddr",DREG(EA)); - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x05: /* FILD Bit64s */ - gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA)); - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - break; - case 0x06: /* FBSTP packed BCD */ - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_80,"%Ddr",DREG(EA)); - break; - case 0x07: /* FISTP Bit64s */ - cache_addb(0xdf); - cache_addb(0x05|(decode.modrm.reg<<3)); - cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); - gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA)); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); - break; - } - } -} - -#endif +/* + * Copyright (C) 2002-2010 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: dyn_fpu_dh.h,v 1.7 2009-09-23 20:55:19 c2woody Exp $ */ + +#include "dosbox.h" +#if C_FPU + +static void FPU_FLD_16(PhysPt addr) { + dyn_dh_fpu.temp.m1 = (Bit32u)mem_readw(addr); +} + +static void FPU_FST_16(PhysPt addr) { + mem_writew(addr,(Bit16u)dyn_dh_fpu.temp.m1); +} + +static void FPU_FLD_32(PhysPt addr) { + dyn_dh_fpu.temp.m1 = mem_readd(addr); +} + +static void FPU_FST_32(PhysPt addr) { + mem_writed(addr,dyn_dh_fpu.temp.m1); +} + +static void FPU_FLD_64(PhysPt addr) { + dyn_dh_fpu.temp.m1 = mem_readd(addr); + dyn_dh_fpu.temp.m2 = mem_readd(addr+4); +} + +static void FPU_FST_64(PhysPt addr) { + mem_writed(addr,dyn_dh_fpu.temp.m1); + mem_writed(addr+4,dyn_dh_fpu.temp.m2); +} + +static void FPU_FLD_80(PhysPt addr) { + dyn_dh_fpu.temp.m1 = mem_readd(addr); + dyn_dh_fpu.temp.m2 = mem_readd(addr+4); + dyn_dh_fpu.temp.m3 = mem_readw(addr+8); +} + +static void FPU_FST_80(PhysPt addr) { + mem_writed(addr,dyn_dh_fpu.temp.m1); + mem_writed(addr+4,dyn_dh_fpu.temp.m2); + mem_writew(addr+8,dyn_dh_fpu.temp.m3); +} + +static void FPU_FLDCW_DH(PhysPt addr){ + dyn_dh_fpu.cw = mem_readw(addr); + dyn_dh_fpu.temp.m1 = (Bit32u)(dyn_dh_fpu.cw|0x3f); +} + +static void FPU_FNSTCW_DH(PhysPt addr){ + mem_writew(addr,(Bit16u)(dyn_dh_fpu.cw&0xffff)); +} + +static void FPU_FNINIT_DH(void){ + dyn_dh_fpu.cw = 0x37f; +} + +static void FPU_FSTENV_DH(PhysPt addr){ + if(!cpu.code.big) { + mem_writew(addr+0,(Bit16u)dyn_dh_fpu.cw); + mem_writew(addr+2,(Bit16u)dyn_dh_fpu.temp.m2); + mem_writew(addr+4,dyn_dh_fpu.temp.m3); + } else { + mem_writed(addr+0,dyn_dh_fpu.temp.m1); + mem_writew(addr+0,(Bit16u)dyn_dh_fpu.cw); + mem_writed(addr+4,dyn_dh_fpu.temp.m2); + mem_writed(addr+8,dyn_dh_fpu.temp.m3); + } +} + +static void FPU_FLDENV_DH(PhysPt addr){ + if(!cpu.code.big) { + dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); + dyn_dh_fpu.temp.m1 = dyn_dh_fpu.cw|0x3f; + dyn_dh_fpu.temp.m2 = (Bit32u)mem_readw(addr+2); + dyn_dh_fpu.temp.m3 = mem_readw(addr+4); + } else { + dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); + dyn_dh_fpu.temp.m1 = mem_readd(addr)|0x3f; + dyn_dh_fpu.temp.m2 = mem_readd(addr+4); + dyn_dh_fpu.temp.m3 = mem_readw(addr+8); + dyn_dh_fpu.temp.d1 = mem_readw(addr+10); + } +} + +static void FPU_FSAVE_DH(PhysPt addr){ + if (!cpu.code.big) { + mem_writew(addr,(Bit16u)dyn_dh_fpu.cw); + addr+=2; + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x04]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x05]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x08]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x09]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0c]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x0d]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x10]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x11]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x14]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x15]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x18]); + mem_writeb(addr++,dyn_dh_fpu.temp_state[0x19]); + for(Bitu i=28;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]); + } else { + mem_writew(addr,(Bit16u)dyn_dh_fpu.cw); + addr+=2; + for(Bitu i=2;i<108;i++) mem_writeb(addr++,dyn_dh_fpu.temp_state[i]); + } +} + +static void FPU_FRSTOR_DH(PhysPt addr){ + if (!cpu.code.big) { + dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); + dyn_dh_fpu.temp_state[0x00] = mem_readb(addr++)|0x3f; + dyn_dh_fpu.temp_state[0x01] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x04] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x05] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x08] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x09] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x0c] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x0d] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x10] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x11] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x14] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x15] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x18] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0x19] = mem_readb(addr++); + for(Bitu i=28;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++); + } else { + dyn_dh_fpu.cw = (Bit32u)mem_readw(addr); + for(Bitu i=0;i<108;i++) dyn_dh_fpu.temp_state[i] = mem_readb(addr++); + dyn_dh_fpu.temp_state[0]|=0x3f; + } +} + +static void dh_fpu_esc0(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + cache_addb(0xd8); + cache_addb(decode.modrm.val); + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); + cache_addb(0xd8); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + } +} + +static void dh_fpu_esc1(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + cache_addb(0xd9); + cache_addb(decode.modrm.val); + } else { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + dyn_fill_ea(); + switch(group){ + case 0x00: /* FLD float*/ + gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); + cache_addb(0xd9); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x01: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST float*/ + cache_addb(0xd9); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); + break; + case 0x03: /* FSTP float*/ + cache_addb(0xd9); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); + break; + case 0x04: /* FLDENV */ + gen_call_function((void*)&FPU_FLDENV_DH,"%Ddr",DREG(EA)); + cache_addb(0xd9); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x05: /* FLDCW */ + gen_call_function((void *)&FPU_FLDCW_DH,"%Ddr",DREG(EA)); + cache_addb(0xd9); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x06: /* FSTENV */ + cache_addb(0xd9); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FSTENV_DH,"%Ddr",DREG(EA)); + break; + case 0x07: /* FNSTCW*/ + gen_call_function((void*)&FPU_FNSTCW_DH,"%Ddr",DREG(EA)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",group,sub); + break; + } + } +} + +static void dh_fpu_esc2(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + cache_addb(0xda); + cache_addb(decode.modrm.val); + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); + cache_addb(0xda); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + } +} + +static void dh_fpu_esc3(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + switch (group) { + case 0x04: + switch (sub) { + case 0x00: //FNENI + case 0x01: //FNDIS + LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion :%d",sub); + break; + case 0x02: //FNCLEX FCLEX + cache_addb(0xdb); + cache_addb(decode.modrm.val); + break; + case 0x03: //FNINIT FINIT + gen_call_function((void*)&FPU_FNINIT_DH,""); + cache_addb(0xdb); + cache_addb(decode.modrm.val); + break; + case 0x04: //FNSETPM + case 0x05: //FRSTPM +// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); + break; + default: + E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",group,sub); + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",group,sub); + break; + } + } else { + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + dyn_fill_ea(); + switch(group){ + case 0x00: /* FILD */ + gen_call_function((void*)&FPU_FLD_32,"%Ddr",DREG(EA)); + cache_addb(0xdb); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FIST */ + cache_addb(0xdb); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); + break; + case 0x03: /* FISTP */ + cache_addb(0xdb); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_32,"%Ddr",DREG(EA)); + break; + case 0x05: /* FLD 80 Bits Real */ + gen_call_function((void*)&FPU_FLD_80,"%Ddr",DREG(EA)); + cache_addb(0xdb); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x07: /* FSTP 80 Bits Real */ + cache_addb(0xdb); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_80,"%Ddr",DREG(EA)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",group,sub); + } + } +} + +static void dh_fpu_esc4(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + cache_addb(0xdc); + cache_addb(decode.modrm.val); + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA)); + cache_addb(0xdc); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + } +} + +static void dh_fpu_esc5(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + cache_addb(0xdd); + cache_addb(decode.modrm.val); + } else { + dyn_fill_ea(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + switch(group){ + case 0x00: /* FLD double real*/ + gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA)); + cache_addb(0xdd); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x01: /* FISTTP longint*/ + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FST double real*/ + cache_addb(0xdd); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA)); + break; + case 0x03: /* FSTP double real*/ + cache_addb(0xdd); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA)); + break; + case 0x04: /* FRSTOR */ + gen_call_function((void*)&FPU_FRSTOR_DH,"%Ddr",DREG(EA)); + cache_addb(0xdd); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp_state[0]))); + break; + case 0x06: /* FSAVE */ + cache_addb(0xdd); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp_state[0]))); + gen_call_function((void*)&FPU_FSAVE_DH,"%Ddr",DREG(EA)); + cache_addb(0xdb); + cache_addb(0xe3); + break; + case 0x07: /* FNSTSW */ + cache_addb(0xdd); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",group,sub); + } + } +} + +static void dh_fpu_esc6(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + cache_addb(0xde); + cache_addb(decode.modrm.val); + } else { + dyn_fill_ea(); + gen_call_function((void*)&FPU_FLD_16,"%Ddr",DREG(EA)); + cache_addb(0xde); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + } +} + +static void dh_fpu_esc7(){ + dyn_get_modrm(); + Bitu group=(decode.modrm.val >> 3) & 7; + Bitu sub=(decode.modrm.val & 7); + if (decode.modrm.val >= 0xc0) { + switch (group){ + case 0x00: /* FFREEP STi*/ + cache_addb(0xdf); + cache_addb(decode.modrm.val); + break; + case 0x01: /* FXCH STi*/ + cache_addb(0xdf); + cache_addb(decode.modrm.val); + break; + case 0x02: /* FSTP STi*/ + case 0x03: /* FSTP STi*/ + cache_addb(0xdf); + cache_addb(decode.modrm.val); + break; + case 0x04: + switch(sub){ + case 0x00: /* FNSTSW AX*/ + cache_addb(0xdd); + cache_addb(0x05|(0x07<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_load_host(&(dyn_dh_fpu.temp.m1),DREG(TMPB),4); + gen_dop_word(DOP_MOV,false,DREG(EAX),DREG(TMPB)); + gen_releasereg(DREG(TMPB)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",group,sub); + break; + } + } else { + dyn_fill_ea(); + switch(group){ + case 0x00: /* FILD Bit16s */ + gen_call_function((void*)&FPU_FLD_16,"%Ddr",DREG(EA)); + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x01: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + case 0x02: /* FIST Bit16s */ + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA)); + break; + case 0x03: /* FISTP Bit16s */ + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_16,"%Ddr",DREG(EA)); + break; + case 0x04: /* FBLD packed BCD */ + gen_call_function((void*)&FPU_FLD_80,"%Ddr",DREG(EA)); + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x05: /* FILD Bit64s */ + gen_call_function((void*)&FPU_FLD_64,"%Ddr",DREG(EA)); + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + break; + case 0x06: /* FBSTP packed BCD */ + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_80,"%Ddr",DREG(EA)); + break; + case 0x07: /* FISTP Bit64s */ + cache_addb(0xdf); + cache_addb(0x05|(decode.modrm.reg<<3)); + cache_addd((Bit32u)(&(dyn_dh_fpu.temp.m1))); + gen_call_function((void*)&FPU_FST_64,"%Ddr",DREG(EA)); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",group,sub); + break; + } + } +} + +#endif diff --git a/src/cpu/core_dyn_x86/helpers.h b/src/cpu/core_dyn_x86/helpers.h index 5e718a5..b1e6775 100644 --- a/src/cpu/core_dyn_x86/helpers.h +++ b/src/cpu/core_dyn_x86/helpers.h @@ -1,69 +1,69 @@ -static bool dyn_helper_divb(Bit8u val) { - if (!val) return CPU_PrepareException(0,0); - Bitu quo=reg_ax / val; - 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; - 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; -} - -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; - 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; -} - -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; - 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; -} - -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; - 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; -} - -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; - 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; -} +static bool dyn_helper_divb(Bit8u val) { + if (!val) return CPU_PrepareException(0,0); + Bitu quo=reg_ax / val; + 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; + 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; +} + +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; + 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; +} + +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; + 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; +} + +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; + 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; +} + +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; + 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 323955e..849b433 100644 --- a/src/cpu/core_dyn_x86/risc_x86.h +++ b/src/cpu/core_dyn_x86/risc_x86.h @@ -1,1072 +1,1072 @@ -/* - * Copyright (C) 2002-2009 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: risc_x86.h,v 1.32 2009/05/27 09:15:41 qbix79 Exp $ */ - -static void gen_init(void); - -/* End of needed */ - -#define X86_REGS 7 -#define X86_REG_EAX 0x00 -#define X86_REG_ECX 0x01 -#define X86_REG_EDX 0x02 -#define X86_REG_EBX 0x03 -#define X86_REG_EBP 0x04 -#define X86_REG_ESI 0x05 -#define X86_REG_EDI 0x06 - -#define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_) - -static struct { - bool flagsactive; - Bitu last_used; - GenReg * regs[X86_REGS]; -} x86gen; - -class GenReg { -public: - GenReg(Bit8u _index) { - index=_index; - notusable=false;dynreg=0; - } - DynReg * dynreg; - Bitu last_used; //Keeps track of last assigned regs - Bit8u index; - bool notusable; - void Load(DynReg * _dynreg,bool stale=false) { - if (!_dynreg) return; - if (GCC_UNLIKELY((Bitu)dynreg)) Clear(); - dynreg=_dynreg; - last_used=x86gen.last_used; - dynreg->flags&=~DYNFLG_CHANGED; - dynreg->genreg=this; - 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 (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 (GCC_UNLIKELY(!((Bitu)dynreg))) return; - if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) { - Save(); - } - dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE); - dynreg->genreg=0;dynreg=0; - } - void Clear(void) { - if (!dynreg) return; - if (dynreg->flags&DYNFLG_CHANGED) { - Save(); - } - dynreg->genreg=0;dynreg=0; - } -}; - -static BlockReturn gen_runcode(Bit8u * code) { - BlockReturn retval; -#if defined (_MSC_VER) - __asm { -/* Prepare the flags */ - mov eax,[code] - push ebx - push ebp - push esi - push edi - mov ebx,[reg_flags] - and ebx,FMASK_TEST - push offset(return_address) - push ebx - jmp eax -/* Restore the flags */ -return_address: - /* return here with flags in ecx */ - and dword ptr [reg_flags],~FMASK_TEST - and ecx,FMASK_TEST - or [reg_flags],ecx - pop edi - pop esi - pop ebp - pop ebx - mov [retval],eax - } -#elif defined (MACOSX) - register Bit32u tempflags=reg_flags & FMASK_TEST; - __asm__ volatile ( - "pushl %%ebx \n" - "pushl %%ebp \n" - "pushl $(run_return_adress) \n" - "pushl %2 \n" - "jmp *%3 \n" - "run_return_adress: \n" - "popl %%ebp \n" - "popl %%ebx \n" - :"=a" (retval), "=c" (tempflags) - :"r" (tempflags),"r" (code) - :"%edx","%edi","%esi","cc","memory" - ); - reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST); -#else - register Bit32u tempflags=reg_flags & FMASK_TEST; - __asm__ volatile ( - "pushl %%ebp \n" - "pushl $(run_return_adress) \n" - "pushl %2 \n" - "jmp *%3 \n" - "run_return_adress: \n" - "popl %%ebp \n" - :"=a" (retval), "=c" (tempflags) - :"r" (tempflags),"r" (code) - :"%edx","%ebx","%edi","%esi","cc","memory" - ); - reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST); -#endif - return retval; -} - -static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) { - x86gen.last_used++; - if (dynreg->genreg) { - dynreg->genreg->last_used=x86gen.last_used; - return dynreg->genreg; - } - /* Find best match for selected global reg */ - Bits i; - Bits first_used,first_index; - first_used=-1; - if (dynreg->flags & DYNFLG_HAS8) { - /* Has to be eax,ebx,ecx,edx */ - 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,stale); - return genreg; - } - if (genreg->last_used<(Bitu)first_used) { - first_used=genreg->last_used; - first_index=i; - } - } - } 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,stale); - return genreg; - } - if (genreg->last_used<(Bitu)first_used) { - first_used=genreg->last_used; - first_index=i; - } - } - } - /* 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) { - genreg->last_used=++x86gen.last_used; - if (dynreg->genreg==genreg) return genreg; - if (genreg->dynreg) genreg->Clear(); - if (dynreg->genreg) dynreg->genreg->Clear(); - genreg->Load(dynreg); - return genreg; -} - -static void gen_preloadreg(DynReg * dynreg) { - FindDynReg(dynreg); -} - -static void gen_releasereg(DynReg * dynreg) { - GenReg * genreg=dynreg->genreg; - if (genreg) genreg->Release(); - else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED); -} - -static void gen_setupreg(DynReg * dnew,DynReg * dsetup) { - dnew->flags=dsetup->flags; - if (dnew->genreg==dsetup->genreg) return; - /* Not the same genreg must be wrong */ - if (dnew->genreg) { - /* Check if the genreg i'm changing is actually linked to me */ - if (dnew->genreg->dynreg==dnew) dnew->genreg->dynreg=0; - } - dnew->genreg=dsetup->genreg; - if (dnew->genreg) dnew->genreg->dynreg=dnew; -} - -static void gen_synchreg(DynReg * dnew,DynReg * dsynch) { - /* First make sure the registers match */ - if (dnew->genreg!=dsynch->genreg) { - if (dnew->genreg) dnew->genreg->Clear(); - if (dsynch->genreg) { - dsynch->genreg->Load(dnew); - } - } - /* Always use the loadonce flag from either state */ - dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE); - if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) { - /* Ensure the changed value gets saved */ - if (dnew->flags & DYNFLG_CHANGED) { - dnew->genreg->Save(); - } else dnew->flags|=DYNFLG_CHANGED; - } -} - -static void gen_needflags(void) { - if (!x86gen.flagsactive) { - x86gen.flagsactive=true; - cache_addb(0x9d); //POPFD - } -} - -static void gen_protectflags(void) { - if (x86gen.flagsactive) { - x86gen.flagsactive=false; - cache_addb(0x9c); //PUSHFD - } -} - -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 void gen_setzeroflag(void) { - if (x86gen.flagsactive) IllegalOption("gen_setzeroflag"); - cache_addw(0x0c83); //OR DWORD [ESP],0x40 - cache_addw(0x4024); -} - -static void gen_clearzeroflag(void) { - if (x86gen.flagsactive) IllegalOption("gen_clearzeroflag"); - cache_addw(0x2483); //AND DWORD [ESP],~0x40 - cache_addw(0xbf24); -} - -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; - for (Bitu i=0;idynreg=0; - } -} - - -static void gen_load_host(void * data,DynReg * dr1,Bitu size) { - GenReg * gr1=FindDynReg(dr1,true); - switch (size) { - case 1:cache_addw(0xb60f);break; //movzx byte - case 2:cache_addw(0xb70f);break; //movzx word - case 4:cache_addb(0x8b);break; //mov - default: - 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,(size==4)); - 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_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: 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("gen_dop_byte"); - } - 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: 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("gen_dop_byte_imm"); - } - dr1->flags|=DYNFLG_CHANGED; -nochange: - cache_addw(tmp+((gr1->index+di1)<<8)); -finish: - cache_addb(imm); -} - -static void gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void* data) { - GenReg * gr1=FindDynReg(dr1); - Bit16u tmp; - switch (op) { - case DOP_ADD: tmp=0x0502; break; - case DOP_ADC: tmp=0x0512; break; - case DOP_SUB: tmp=0x052a; break; - case DOP_SBB: tmp=0x051a; break; - case DOP_CMP: tmp=0x053a; goto nochange; //Doesn't change - case DOP_XOR: tmp=0x0532; break; - case DOP_AND: tmp=0x0522; break; - case DOP_OR: tmp=0x050a; break; - case DOP_TEST: tmp=0x0584; goto nochange; //Doesn't change - case DOP_MOV: tmp=0x0585; break; - default: - IllegalOption("gen_dop_byte_imm_mem"); - } - dr1->flags|=DYNFLG_CHANGED; -nochange: - cache_addw(tmp+((gr1->index+di1)<<11)); - cache_addd((Bit32u)data); -} - -static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) { - GenReg * gr1=FindDynReg(dr1); - Bit16u tmp; - switch (op) { - 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("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 * 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)); - ddr->flags|=DYNFLG_CHANGED; -} - -static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) { - GenReg * gsr=FindDynReg(dsr); - GenReg * gdr=FindDynReg(ddr,dword); - if (!dword) cache_addb(0x66); - if (sign) cache_addw(0xbe0f); - else cache_addw(0xb60f); - cache_addb(0xc0+(gdr->index<<3)+(gsr->index+dsi)); - ddr->flags|=DYNFLG_CHANGED; -} - -static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm) { - GenReg * gdr=FindDynReg(ddr); - Bitu imm_size; - Bit8u rm_base=(gdr->index << 3); - if (dsr1) { - GenReg * gsr1=FindDynReg(dsr1); - if (!imm && (gsr1->index!=0x5)) { - imm_size=0; rm_base+=0x0; //no imm - } else if ((imm>=-128 && imm<=127)) { - imm_size=1;rm_base+=0x40; //Signed byte imm - } else { - imm_size=4;rm_base+=0x80; //Signed dword imm - } - if (dsr2) { - GenReg * gsr2=FindDynReg(dsr2); - cache_addb(0x8d); //LEA - cache_addb(rm_base+0x4); //The sib indicator - 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); - } - } else { - if (dsr2) { - GenReg * gsr2=FindDynReg(dsr2); - cache_addb(0x8d); //LEA - cache_addb(rm_base+0x4); //The sib indicator - Bit8u sib=(5+(gsr2->index<<3)+(scale<<6)); - cache_addb(sib); - imm_size=4; - } else { - cache_addb(0x8d); //LEA - cache_addb(rm_base+0x05); //dword imm - imm_size=4; - } - } - switch (imm_size) { - case 0: break; - case 1:cache_addb(imm);break; - case 4:cache_addd(imm);break; - } - ddr->flags|=DYNFLG_CHANGED; -} - -static void gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void* data) { - GenReg * gdr=FindDynReg(ddr); - Bit8u rm_base=(gdr->index << 3); - cache_addw(0x058b+(rm_base<<8)); - cache_addd((Bit32u)data); - GenReg * gsr=FindDynReg(dsr); - cache_addb(0x8d); //LEA - cache_addb(rm_base+0x44); - cache_addb(rm_base+gsr->index); - cache_addb(0x00); - ddr->flags|=DYNFLG_CHANGED; -} - -static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) { - GenReg * gr2=FindDynReg(dr2); - GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); - Bit8u tmp; - switch (op) { - 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("gen_dop_word"); - } - 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,dword && op==DOP_MOV); - Bit16u tmp; - if (!dword) cache_addb(0x66); - switch (op) { - 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("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_dop_word_imm_mem(DualOps op,bool dword,DynReg * dr1,void* data) { - GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); - Bit16u tmp; - switch (op) { - case DOP_ADD: tmp=0x0503; break; - case DOP_ADC: tmp=0x0513; break; - case DOP_SUB: tmp=0x052b; break; - case DOP_SBB: tmp=0x051b; break; - case DOP_CMP: tmp=0x053b; goto nochange; //Doesn't change - case DOP_XOR: tmp=0x0533; break; - case DOP_AND: tmp=0x0523; break; - case DOP_OR: tmp=0x050b; break; - case DOP_TEST: tmp=0x0585; goto nochange; //Doesn't change - case DOP_MOV: - gen_mov_host(data,dr1,dword?4:2); - dr1->flags|=DYNFLG_CHANGED; - return; - default: - IllegalOption("gen_dop_word_imm_mem"); - } - dr1->flags|=DYNFLG_CHANGED; -nochange: - if (!dword) cache_addb(0x66); - cache_addw(tmp+(gr1->index<<11)); - cache_addd((Bit32u)data); -} - -static void gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void* drd) { - GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); - Bit8u tmp; - switch (op) { - 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; break; - case DOP_XOR: tmp=0x33; break; - case DOP_AND: tmp=0x23; break; - case DOP_OR: tmp=0x0b; break; - case DOP_TEST: tmp=0x85; break; - case DOP_MOV: tmp=0x8b; break; - case DOP_XCHG: tmp=0x87; break; - default: - IllegalOption("gen_dop_word_var"); - } - if (!dword) cache_addb(0x66); - cache_addw(tmp|(0x05+((gr1->index)<<3))<<8); - cache_addd((Bit32u)drd); -} - -static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) { - GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); - 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)) { - cache_addb(0x6b); - cache_addb(0xc0+(gr1->index<<3)+gr2->index); - cache_addb(imm); - } else { - cache_addb(0x69); - cache_addb(0xc0+(gr1->index<<3)+gr2->index); - if (dword) cache_addd(imm); - else cache_addw(imm); - } - dr1->flags|=DYNFLG_CHANGED; -} - - -static void gen_sop_word(SingleOps op,bool dword,DynReg * dr1) { - GenReg * gr1=FindDynReg(dr1); - if (!dword) cache_addb(0x66); - switch (op) { - case SOP_INC:cache_addb(0x40+gr1->index);break; - case SOP_DEC:cache_addb(0x48+gr1->index);break; - case SOP_NOT:cache_addw(0xd0f7+(gr1->index<<8));break; - case SOP_NEG:cache_addw(0xd8f7+(gr1->index<<8));break; - default: - IllegalOption("gen_sop_word"); - } - dr1->flags|=DYNFLG_CHANGED; -} - -static void gen_shift_byte_cl(Bitu op,DynReg * dr1,Bit8u di1,DynReg * drecx) { - ForceDynReg(x86gen.regs[X86_REG_ECX],drecx); - GenReg * gr1=FindDynReg(dr1); - cache_addw(0xc0d2+(((Bit16u)op) << 11)+ ((gr1->index+di1)<<8)); - dr1->flags|=DYNFLG_CHANGED; -} - -static void gen_shift_byte_imm(Bitu op,DynReg * dr1,Bit8u di1,Bit8u imm) { - GenReg * gr1=FindDynReg(dr1); - cache_addw(0xc0c0+(((Bit16u)op) << 11) + ((gr1->index+di1)<<8)); - cache_addb(imm); - dr1->flags|=DYNFLG_CHANGED; -} - -static void gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx) { - ForceDynReg(x86gen.regs[X86_REG_ECX],drecx); - GenReg * gr1=FindDynReg(dr1); - if (!dword) cache_addb(0x66); - cache_addw(0xc0d3+(((Bit16u)op) << 11) + ((gr1->index)<<8)); - dr1->flags|=DYNFLG_CHANGED; -} - -static void gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm) { - GenReg * gr1=FindDynReg(dr1); - 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) { - ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); - if (!dword) cache_addb(0x66); - cache_addb(0x98); - dyn_ax->flags|=DYNFLG_CHANGED; -} - -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); - 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) { - ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); - GenReg * gr1=FindDynReg(dr1); - if (imul) cache_addw(0xe8f6+((gr1->index+di1)<<8)); - else cache_addw(0xe0f6+((gr1->index+di1)<<8)); - dyn_ax->flags|=DYNFLG_CHANGED; -} - -static void gen_mul_word(bool imul,DynReg * dyn_ax,DynReg * dyn_dx,bool dword,DynReg * dr1) { - ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); - ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx); - GenReg * gr1=FindDynReg(dr1); - if (!dword) cache_addb(0x66); - if (imul) cache_addw(0xe8f7+(gr1->index<<8)); - else cache_addw(0xe0f7+(gr1->index<<8)); - dyn_ax->flags|=DYNFLG_CHANGED; - dyn_dx->flags|=DYNFLG_CHANGED; -} - -static void gen_dshift_imm(bool dword,bool left,DynReg * dr1,DynReg * dr2,Bitu imm) { - GenReg * gr1=FindDynReg(dr1); - GenReg * gr2=FindDynReg(dr2); - if (!dword) cache_addb(0x66); - if (left) cache_addw(0xa40f); //SHLD IMM - else cache_addw(0xac0f); //SHRD IMM - cache_addb(0xc0+gr1->index+(gr2->index<<3)); - cache_addb(imm); - dr1->flags|=DYNFLG_CHANGED; -} - -static void gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg * drecx) { - ForceDynReg(x86gen.regs[X86_REG_ECX],drecx); - GenReg * gr1=FindDynReg(dr1); - GenReg * gr2=FindDynReg(dr2); - if (!dword) cache_addb(0x66); - if (left) cache_addw(0xa50f); //SHLD CL - else cache_addw(0xad0f); //SHRD CL - cache_addb(0xc0+gr1->index+(gr2->index<<3)); - dr1->flags|=DYNFLG_CHANGED; -} - -static void gen_call_function(void * func,char const* ops,...) { - Bits paramcount=0; - bool release_flags=false; - struct ParamInfo { - const char * line; - Bitu value; - } pinfo[32]; - ParamInfo * retparam=0; - /* Clear the EAX Genreg for usage */ - x86gen.regs[X86_REG_EAX]->Clear(); - x86gen.regs[X86_REG_EAX]->notusable=true; - /* Save the flags */ - if (GCC_UNLIKELY(!skip_flags)) gen_protectflags(); - /* Scan for the amount of params */ - if (ops) { - va_list params; - va_start(params,ops); -#if defined (MACOSX) - Bitu stack_used=0; - bool free_flags=false; -#endif - Bits pindex=0; - while (*ops) { - if (*ops=='%') { - pinfo[pindex].line=ops+1; - pinfo[pindex].value=va_arg(params,Bitu); -#if defined (MACOSX) - const char * scan=pinfo[pindex].line; - if ((*scan=='I') || (*scan=='D')) stack_used+=4; - else if (*scan=='F') free_flags=true; -#endif - pindex++; - } - ops++; - } - -#if defined (MACOSX) - /* align stack */ - stack_used+=4; // saving esp on stack as well - - cache_addw(0xc48b); // mov eax,esp - cache_addb(0x2d); // sub eax,stack_used - cache_addd(stack_used); - cache_addw(0xe083); // and eax,0xfffffff0 - cache_addb(0xf0); - cache_addb(0x05); // sub eax,stack_used - cache_addd(stack_used); - cache_addb(0x94); // xchg eax,esp - if (free_flags) { - cache_addw(0xc083); // add eax,4 - cache_addb(0x04); - } - cache_addb(0x50); // push eax (==old esp) -#endif - - paramcount=0; - while (pindex) { - pindex--; - const char * scan=pinfo[pindex].line; - switch (*scan++) { - case 'I': /* immediate value */ - paramcount++; - cache_addb(0x68); //Push immediate - cache_addd(pinfo[pindex].value); //Push value - break; - case 'D': /* Dynamic register */ - { - bool release=false; - paramcount++; - DynReg * dynreg=(DynReg *)pinfo[pindex].value; - GenReg * genreg=FindDynReg(dynreg); - scanagain: - switch (*scan++) { - case 'd': - cache_addb(0x50+genreg->index); //Push reg - break; - case 'w': - cache_addw(0xb70f); //MOVZX EAX,reg - cache_addb(0xc0+genreg->index); - cache_addb(0x50); //Push EAX - break; - case 'l': - cache_addw(0xb60f); //MOVZX EAX,reg[0] - cache_addb(0xc0+genreg->index); - cache_addb(0x50); //Push EAX - break; - case 'h': - cache_addw(0xb60f); //MOVZX EAX,reg[1] - cache_addb(0xc4+genreg->index); - cache_addb(0x50); //Push EAX - break; - case 'r': /* release the reg afterwards */ - release=true; - goto scanagain; - default: - IllegalOption("gen_call_function param:DREG"); - } - if (release) gen_releasereg(dynreg); - } - break; - case 'R': /* Dynamic register to get the return value */ - retparam =&pinfo[pindex]; - pinfo[pindex].line=scan; - break; - case 'F': /* Release flags from stack */ - release_flags=true; - break; - default: - IllegalOption("gen_call_function unknown param"); - } - } -#if defined (MACOSX) - if (free_flags) release_flags=false; - } else { - /* align stack */ - Bit32u stack_used=8; // saving esp and return address on the stack - - cache_addw(0xc48b); // mov eax,esp - cache_addb(0x2d); // sub eax,stack_used - cache_addd(stack_used); - cache_addw(0xe083); // and eax,0xfffffff0 - cache_addb(0xf0); - cache_addb(0x05); // sub eax,stack_used - cache_addd(stack_used); - cache_addb(0x94); // xchg eax,esp - cache_addb(0x50); // push esp (==old esp) -#endif - } - - /* 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); - cache_addd((Bit32u)func - (Bit32u)cache.pos-4); - /* Restore the params of the stack */ - if (paramcount) { - cache_addw(0xc483); //add ESP,imm byte - 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 - break; - case 'w': - cache_addb(0x66); - cache_addw(0xc08b+(genreg->index <<(8+3))); //mov reg,eax - break; - case 'l': - cache_addw(0xc08a+(genreg->index <<(8+3))); //mov reg,eax - break; - case 'h': - cache_addw(0xc08a+((genreg->index+4) <<(8+3))); //mov reg,eax - break; - } - dynreg->flags|=DYNFLG_CHANGED; - } - /* Restore EAX registers to be used again */ - x86gen.regs[X86_REG_EAX]->notusable=false; - -#if defined (MACOSX) - /* restore stack */ - cache_addb(0x5c); // pop esp -#endif -} - -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(); - -#if defined (MACOSX) - /* align stack */ - Bitu stack_used=12; - - cache_addw(0xc48b); // mov eax,esp - cache_addb(0x2d); // sub eax,stack_used - cache_addd(stack_used); - cache_addw(0xe083); // and eax,0xfffffff0 - cache_addb(0xf0); - cache_addb(0x05); // sub eax,stack_used - cache_addd(stack_used); - cache_addb(0x94); // xchg eax,esp - cache_addb(0x50); // push eax (==old esp) -#endif - - 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); - switch (write_size) { - case 1: cache_addd((Bit32u)mem_writeb_checked - (Bit32u)cache.pos-4); break; - case 2: cache_addd((Bit32u)mem_writew_checked - (Bit32u)cache.pos-4); break; - case 4: cache_addd((Bit32u)mem_writed_checked - (Bit32u)cache.pos-4); break; - default: IllegalOption("gen_call_write"); - } - - cache_addw(0xc483); //ADD ESP,8 - cache_addb(2*4); - x86gen.regs[X86_REG_EAX]->notusable=false; - gen_releasereg(dr); - -#if defined (MACOSX) - /* restore stack */ - cache_addb(0x5c); // pop esp -#endif -} - -static Bit8u * gen_create_branch(BranchTypes type) { - /* First free all registers */ - cache_addw(0x70+type); - return (cache.pos-1); -} - -static void gen_fill_branch(Bit8u * data,Bit8u * from=cache.pos) { -#if C_DEBUG - Bits len=from-data; - if (len<0) len=-len; - if (len>126) LOG_MSG("Big jump %d",len); -#endif - *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); - cache_addd(to-(cache.pos+4)); - return (cache.pos-4); -} - -static void gen_fill_jump(Bit8u * data,Bit8u * to=cache.pos) { - *(Bit32u*)data=(to-data-4); -} - - -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - cache_addb(0xa1); - cache_addd((Bit32u)ptr); - cache_addb(0xff); //JMP EA - if (!imm) { //NO EBP - cache_addb(0x20); - } else if ((imm>=-128 && imm<=127)) { - cache_addb(0x60); - cache_addb(imm); - } else { - cache_addb(0xa0); - cache_addd(imm); - } -} - -static void gen_save_flags(DynReg * dynreg) { - 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)); - dynreg->flags|=DYNFLG_CHANGED; -} - -static void gen_load_flags(DynReg * dynreg) { - if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_load_flags"); - cache_addw(0xc483); //ADD ESP,4 - cache_addb(0x4); - GenReg * genreg=FindDynReg(dynreg); - cache_addb(0x50+genreg->index); //PUSH 32 -} - -static void gen_save_host_direct(void * data,Bits imm) { - cache_addw(0x05c7); //MOV [],dword - cache_addd((Bit32u)data); - cache_addd(imm); -} - -static void gen_return(BlockReturn retcode) { - gen_protectflags(); - cache_addb(0x59); //POP ECX, the flags - 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); - 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); -} - - +/* + * Copyright (C) 2002-2010 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: risc_x86.h,v 1.32 2009-05-27 09:15:41 qbix79 Exp $ */ + +static void gen_init(void); + +/* End of needed */ + +#define X86_REGS 7 +#define X86_REG_EAX 0x00 +#define X86_REG_ECX 0x01 +#define X86_REG_EDX 0x02 +#define X86_REG_EBX 0x03 +#define X86_REG_EBP 0x04 +#define X86_REG_ESI 0x05 +#define X86_REG_EDI 0x06 + +#define X86_REG_MASK(_REG_) (1 << X86_REG_ ## _REG_) + +static struct { + bool flagsactive; + Bitu last_used; + GenReg * regs[X86_REGS]; +} x86gen; + +class GenReg { +public: + GenReg(Bit8u _index) { + index=_index; + notusable=false;dynreg=0; + } + DynReg * dynreg; + Bitu last_used; //Keeps track of last assigned regs + Bit8u index; + bool notusable; + void Load(DynReg * _dynreg,bool stale=false) { + if (!_dynreg) return; + if (GCC_UNLIKELY((Bitu)dynreg)) Clear(); + dynreg=_dynreg; + last_used=x86gen.last_used; + dynreg->flags&=~DYNFLG_CHANGED; + dynreg->genreg=this; + 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 (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 (GCC_UNLIKELY(!((Bitu)dynreg))) return; + if (dynreg->flags&DYNFLG_CHANGED && dynreg->flags&DYNFLG_SAVE) { + Save(); + } + dynreg->flags&=~(DYNFLG_CHANGED|DYNFLG_ACTIVE); + dynreg->genreg=0;dynreg=0; + } + void Clear(void) { + if (!dynreg) return; + if (dynreg->flags&DYNFLG_CHANGED) { + Save(); + } + dynreg->genreg=0;dynreg=0; + } +}; + +static BlockReturn gen_runcode(Bit8u * code) { + BlockReturn retval; +#if defined (_MSC_VER) + __asm { +/* Prepare the flags */ + mov eax,[code] + push ebx + push ebp + push esi + push edi + mov ebx,[reg_flags] + and ebx,FMASK_TEST + push offset(return_address) + push ebx + jmp eax +/* Restore the flags */ +return_address: + /* return here with flags in ecx */ + and dword ptr [reg_flags],~FMASK_TEST + and ecx,FMASK_TEST + or [reg_flags],ecx + pop edi + pop esi + pop ebp + pop ebx + mov [retval],eax + } +#elif defined (MACOSX) + register Bit32u tempflags=reg_flags & FMASK_TEST; + __asm__ volatile ( + "pushl %%ebx \n" + "pushl %%ebp \n" + "pushl $(run_return_adress) \n" + "pushl %2 \n" + "jmp *%3 \n" + "run_return_adress: \n" + "popl %%ebp \n" + "popl %%ebx \n" + :"=a" (retval), "=c" (tempflags) + :"r" (tempflags),"r" (code) + :"%edx","%edi","%esi","cc","memory" + ); + reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST); +#else + register Bit32u tempflags=reg_flags & FMASK_TEST; + __asm__ volatile ( + "pushl %%ebp \n" + "pushl $(run_return_adress) \n" + "pushl %2 \n" + "jmp *%3 \n" + "run_return_adress: \n" + "popl %%ebp \n" + :"=a" (retval), "=c" (tempflags) + :"r" (tempflags),"r" (code) + :"%edx","%ebx","%edi","%esi","cc","memory" + ); + reg_flags=(reg_flags & ~FMASK_TEST) | (tempflags & FMASK_TEST); +#endif + return retval; +} + +static GenReg * FindDynReg(DynReg * dynreg,bool stale=false) { + x86gen.last_used++; + if (dynreg->genreg) { + dynreg->genreg->last_used=x86gen.last_used; + return dynreg->genreg; + } + /* Find best match for selected global reg */ + Bits i; + Bits first_used,first_index; + first_used=-1; + if (dynreg->flags & DYNFLG_HAS8) { + /* Has to be eax,ebx,ecx,edx */ + 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,stale); + return genreg; + } + if (genreg->last_used<(Bitu)first_used) { + first_used=genreg->last_used; + first_index=i; + } + } + } 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,stale); + return genreg; + } + if (genreg->last_used<(Bitu)first_used) { + first_used=genreg->last_used; + first_index=i; + } + } + } + /* 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) { + genreg->last_used=++x86gen.last_used; + if (dynreg->genreg==genreg) return genreg; + if (genreg->dynreg) genreg->Clear(); + if (dynreg->genreg) dynreg->genreg->Clear(); + genreg->Load(dynreg); + return genreg; +} + +static void gen_preloadreg(DynReg * dynreg) { + FindDynReg(dynreg); +} + +static void gen_releasereg(DynReg * dynreg) { + GenReg * genreg=dynreg->genreg; + if (genreg) genreg->Release(); + else dynreg->flags&=~(DYNFLG_ACTIVE|DYNFLG_CHANGED); +} + +static void gen_setupreg(DynReg * dnew,DynReg * dsetup) { + dnew->flags=dsetup->flags; + if (dnew->genreg==dsetup->genreg) return; + /* Not the same genreg must be wrong */ + if (dnew->genreg) { + /* Check if the genreg i'm changing is actually linked to me */ + if (dnew->genreg->dynreg==dnew) dnew->genreg->dynreg=0; + } + dnew->genreg=dsetup->genreg; + if (dnew->genreg) dnew->genreg->dynreg=dnew; +} + +static void gen_synchreg(DynReg * dnew,DynReg * dsynch) { + /* First make sure the registers match */ + if (dnew->genreg!=dsynch->genreg) { + if (dnew->genreg) dnew->genreg->Clear(); + if (dsynch->genreg) { + dsynch->genreg->Load(dnew); + } + } + /* Always use the loadonce flag from either state */ + dnew->flags|=(dsynch->flags & dnew->flags&DYNFLG_ACTIVE); + if ((dnew->flags ^ dsynch->flags) & DYNFLG_CHANGED) { + /* Ensure the changed value gets saved */ + if (dnew->flags & DYNFLG_CHANGED) { + dnew->genreg->Save(); + } else dnew->flags|=DYNFLG_CHANGED; + } +} + +static void gen_needflags(void) { + if (!x86gen.flagsactive) { + x86gen.flagsactive=true; + cache_addb(0x9d); //POPFD + } +} + +static void gen_protectflags(void) { + if (x86gen.flagsactive) { + x86gen.flagsactive=false; + cache_addb(0x9c); //PUSHFD + } +} + +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 void gen_setzeroflag(void) { + if (x86gen.flagsactive) IllegalOption("gen_setzeroflag"); + cache_addw(0x0c83); //OR DWORD [ESP],0x40 + cache_addw(0x4024); +} + +static void gen_clearzeroflag(void) { + if (x86gen.flagsactive) IllegalOption("gen_clearzeroflag"); + cache_addw(0x2483); //AND DWORD [ESP],~0x40 + cache_addw(0xbf24); +} + +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; + for (Bitu i=0;idynreg=0; + } +} + + +static void gen_load_host(void * data,DynReg * dr1,Bitu size) { + GenReg * gr1=FindDynReg(dr1,true); + switch (size) { + case 1:cache_addw(0xb60f);break; //movzx byte + case 2:cache_addw(0xb70f);break; //movzx word + case 4:cache_addb(0x8b);break; //mov + default: + 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,(size==4)); + 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_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: 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("gen_dop_byte"); + } + 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: 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("gen_dop_byte_imm"); + } + dr1->flags|=DYNFLG_CHANGED; +nochange: + cache_addw(tmp+((gr1->index+di1)<<8)); +finish: + cache_addb(imm); +} + +static void gen_dop_byte_imm_mem(DualOps op,DynReg * dr1,Bit8u di1,void* data) { + GenReg * gr1=FindDynReg(dr1); + Bit16u tmp; + switch (op) { + case DOP_ADD: tmp=0x0502; break; + case DOP_ADC: tmp=0x0512; break; + case DOP_SUB: tmp=0x052a; break; + case DOP_SBB: tmp=0x051a; break; + case DOP_CMP: tmp=0x053a; goto nochange; //Doesn't change + case DOP_XOR: tmp=0x0532; break; + case DOP_AND: tmp=0x0522; break; + case DOP_OR: tmp=0x050a; break; + case DOP_TEST: tmp=0x0584; goto nochange; //Doesn't change + case DOP_MOV: tmp=0x0585; break; + default: + IllegalOption("gen_dop_byte_imm_mem"); + } + dr1->flags|=DYNFLG_CHANGED; +nochange: + cache_addw(tmp+((gr1->index+di1)<<11)); + cache_addd((Bit32u)data); +} + +static void gen_sop_byte(SingleOps op,DynReg * dr1,Bit8u di1) { + GenReg * gr1=FindDynReg(dr1); + Bit16u tmp; + switch (op) { + 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("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 * 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)); + ddr->flags|=DYNFLG_CHANGED; +} + +static void gen_extend_byte(bool sign,bool dword,DynReg * ddr,DynReg * dsr,Bit8u dsi) { + GenReg * gsr=FindDynReg(dsr); + GenReg * gdr=FindDynReg(ddr,dword); + if (!dword) cache_addb(0x66); + if (sign) cache_addw(0xbe0f); + else cache_addw(0xb60f); + cache_addb(0xc0+(gdr->index<<3)+(gsr->index+dsi)); + ddr->flags|=DYNFLG_CHANGED; +} + +static void gen_lea(DynReg * ddr,DynReg * dsr1,DynReg * dsr2,Bitu scale,Bits imm) { + GenReg * gdr=FindDynReg(ddr); + Bitu imm_size; + Bit8u rm_base=(gdr->index << 3); + if (dsr1) { + GenReg * gsr1=FindDynReg(dsr1); + if (!imm && (gsr1->index!=0x5)) { + imm_size=0; rm_base+=0x0; //no imm + } else if ((imm>=-128 && imm<=127)) { + imm_size=1;rm_base+=0x40; //Signed byte imm + } else { + imm_size=4;rm_base+=0x80; //Signed dword imm + } + if (dsr2) { + GenReg * gsr2=FindDynReg(dsr2); + cache_addb(0x8d); //LEA + cache_addb(rm_base+0x4); //The sib indicator + 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); + } + } else { + if (dsr2) { + GenReg * gsr2=FindDynReg(dsr2); + cache_addb(0x8d); //LEA + cache_addb(rm_base+0x4); //The sib indicator + Bit8u sib=(5+(gsr2->index<<3)+(scale<<6)); + cache_addb(sib); + imm_size=4; + } else { + cache_addb(0x8d); //LEA + cache_addb(rm_base+0x05); //dword imm + imm_size=4; + } + } + switch (imm_size) { + case 0: break; + case 1:cache_addb(imm);break; + case 4:cache_addd(imm);break; + } + ddr->flags|=DYNFLG_CHANGED; +} + +static void gen_lea_imm_mem(DynReg * ddr,DynReg * dsr,void* data) { + GenReg * gdr=FindDynReg(ddr); + Bit8u rm_base=(gdr->index << 3); + cache_addw(0x058b+(rm_base<<8)); + cache_addd((Bit32u)data); + GenReg * gsr=FindDynReg(dsr); + cache_addb(0x8d); //LEA + cache_addb(rm_base+0x44); + cache_addb(rm_base+gsr->index); + cache_addb(0x00); + ddr->flags|=DYNFLG_CHANGED; +} + +static void gen_dop_word(DualOps op,bool dword,DynReg * dr1,DynReg * dr2) { + GenReg * gr2=FindDynReg(dr2); + GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); + Bit8u tmp; + switch (op) { + 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("gen_dop_word"); + } + 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,dword && op==DOP_MOV); + Bit16u tmp; + if (!dword) cache_addb(0x66); + switch (op) { + 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("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_dop_word_imm_mem(DualOps op,bool dword,DynReg * dr1,void* data) { + GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); + Bit16u tmp; + switch (op) { + case DOP_ADD: tmp=0x0503; break; + case DOP_ADC: tmp=0x0513; break; + case DOP_SUB: tmp=0x052b; break; + case DOP_SBB: tmp=0x051b; break; + case DOP_CMP: tmp=0x053b; goto nochange; //Doesn't change + case DOP_XOR: tmp=0x0533; break; + case DOP_AND: tmp=0x0523; break; + case DOP_OR: tmp=0x050b; break; + case DOP_TEST: tmp=0x0585; goto nochange; //Doesn't change + case DOP_MOV: + gen_mov_host(data,dr1,dword?4:2); + dr1->flags|=DYNFLG_CHANGED; + return; + default: + IllegalOption("gen_dop_word_imm_mem"); + } + dr1->flags|=DYNFLG_CHANGED; +nochange: + if (!dword) cache_addb(0x66); + cache_addw(tmp+(gr1->index<<11)); + cache_addd((Bit32u)data); +} + +static void gen_dop_word_var(DualOps op,bool dword,DynReg * dr1,void* drd) { + GenReg * gr1=FindDynReg(dr1,dword && op==DOP_MOV); + Bit8u tmp; + switch (op) { + 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; break; + case DOP_XOR: tmp=0x33; break; + case DOP_AND: tmp=0x23; break; + case DOP_OR: tmp=0x0b; break; + case DOP_TEST: tmp=0x85; break; + case DOP_MOV: tmp=0x8b; break; + case DOP_XCHG: tmp=0x87; break; + default: + IllegalOption("gen_dop_word_var"); + } + if (!dword) cache_addb(0x66); + cache_addw(tmp|(0x05+((gr1->index)<<3))<<8); + cache_addd((Bit32u)drd); +} + +static void gen_imul_word(bool dword,DynReg * dr1,DynReg * dr2) { + GenReg * gr1=FindDynReg(dr1);GenReg * gr2=FindDynReg(dr2); + 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)) { + cache_addb(0x6b); + cache_addb(0xc0+(gr1->index<<3)+gr2->index); + cache_addb(imm); + } else { + cache_addb(0x69); + cache_addb(0xc0+(gr1->index<<3)+gr2->index); + if (dword) cache_addd(imm); + else cache_addw(imm); + } + dr1->flags|=DYNFLG_CHANGED; +} + + +static void gen_sop_word(SingleOps op,bool dword,DynReg * dr1) { + GenReg * gr1=FindDynReg(dr1); + if (!dword) cache_addb(0x66); + switch (op) { + case SOP_INC:cache_addb(0x40+gr1->index);break; + case SOP_DEC:cache_addb(0x48+gr1->index);break; + case SOP_NOT:cache_addw(0xd0f7+(gr1->index<<8));break; + case SOP_NEG:cache_addw(0xd8f7+(gr1->index<<8));break; + default: + IllegalOption("gen_sop_word"); + } + dr1->flags|=DYNFLG_CHANGED; +} + +static void gen_shift_byte_cl(Bitu op,DynReg * dr1,Bit8u di1,DynReg * drecx) { + ForceDynReg(x86gen.regs[X86_REG_ECX],drecx); + GenReg * gr1=FindDynReg(dr1); + cache_addw(0xc0d2+(((Bit16u)op) << 11)+ ((gr1->index+di1)<<8)); + dr1->flags|=DYNFLG_CHANGED; +} + +static void gen_shift_byte_imm(Bitu op,DynReg * dr1,Bit8u di1,Bit8u imm) { + GenReg * gr1=FindDynReg(dr1); + cache_addw(0xc0c0+(((Bit16u)op) << 11) + ((gr1->index+di1)<<8)); + cache_addb(imm); + dr1->flags|=DYNFLG_CHANGED; +} + +static void gen_shift_word_cl(Bitu op,bool dword,DynReg * dr1,DynReg * drecx) { + ForceDynReg(x86gen.regs[X86_REG_ECX],drecx); + GenReg * gr1=FindDynReg(dr1); + if (!dword) cache_addb(0x66); + cache_addw(0xc0d3+(((Bit16u)op) << 11) + ((gr1->index)<<8)); + dr1->flags|=DYNFLG_CHANGED; +} + +static void gen_shift_word_imm(Bitu op,bool dword,DynReg * dr1,Bit8u imm) { + GenReg * gr1=FindDynReg(dr1); + 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) { + ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); + if (!dword) cache_addb(0x66); + cache_addb(0x98); + dyn_ax->flags|=DYNFLG_CHANGED; +} + +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); + 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) { + ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); + GenReg * gr1=FindDynReg(dr1); + if (imul) cache_addw(0xe8f6+((gr1->index+di1)<<8)); + else cache_addw(0xe0f6+((gr1->index+di1)<<8)); + dyn_ax->flags|=DYNFLG_CHANGED; +} + +static void gen_mul_word(bool imul,DynReg * dyn_ax,DynReg * dyn_dx,bool dword,DynReg * dr1) { + ForceDynReg(x86gen.regs[X86_REG_EAX],dyn_ax); + ForceDynReg(x86gen.regs[X86_REG_EDX],dyn_dx); + GenReg * gr1=FindDynReg(dr1); + if (!dword) cache_addb(0x66); + if (imul) cache_addw(0xe8f7+(gr1->index<<8)); + else cache_addw(0xe0f7+(gr1->index<<8)); + dyn_ax->flags|=DYNFLG_CHANGED; + dyn_dx->flags|=DYNFLG_CHANGED; +} + +static void gen_dshift_imm(bool dword,bool left,DynReg * dr1,DynReg * dr2,Bitu imm) { + GenReg * gr1=FindDynReg(dr1); + GenReg * gr2=FindDynReg(dr2); + if (!dword) cache_addb(0x66); + if (left) cache_addw(0xa40f); //SHLD IMM + else cache_addw(0xac0f); //SHRD IMM + cache_addb(0xc0+gr1->index+(gr2->index<<3)); + cache_addb(imm); + dr1->flags|=DYNFLG_CHANGED; +} + +static void gen_dshift_cl(bool dword,bool left,DynReg * dr1,DynReg * dr2,DynReg * drecx) { + ForceDynReg(x86gen.regs[X86_REG_ECX],drecx); + GenReg * gr1=FindDynReg(dr1); + GenReg * gr2=FindDynReg(dr2); + if (!dword) cache_addb(0x66); + if (left) cache_addw(0xa50f); //SHLD CL + else cache_addw(0xad0f); //SHRD CL + cache_addb(0xc0+gr1->index+(gr2->index<<3)); + dr1->flags|=DYNFLG_CHANGED; +} + +static void gen_call_function(void * func,char const* ops,...) { + Bits paramcount=0; + bool release_flags=false; + struct ParamInfo { + const char * line; + Bitu value; + } pinfo[32]; + ParamInfo * retparam=0; + /* Clear the EAX Genreg for usage */ + x86gen.regs[X86_REG_EAX]->Clear(); + x86gen.regs[X86_REG_EAX]->notusable=true; + /* Save the flags */ + if (GCC_UNLIKELY(!skip_flags)) gen_protectflags(); + /* Scan for the amount of params */ + if (ops) { + va_list params; + va_start(params,ops); +#if defined (MACOSX) + Bitu stack_used=0; + bool free_flags=false; +#endif + Bits pindex=0; + while (*ops) { + if (*ops=='%') { + pinfo[pindex].line=ops+1; + pinfo[pindex].value=va_arg(params,Bitu); +#if defined (MACOSX) + const char * scan=pinfo[pindex].line; + if ((*scan=='I') || (*scan=='D')) stack_used+=4; + else if (*scan=='F') free_flags=true; +#endif + pindex++; + } + ops++; + } + +#if defined (MACOSX) + /* align stack */ + stack_used+=4; // saving esp on stack as well + + cache_addw(0xc48b); // mov eax,esp + cache_addb(0x2d); // sub eax,stack_used + cache_addd(stack_used); + cache_addw(0xe083); // and eax,0xfffffff0 + cache_addb(0xf0); + cache_addb(0x05); // sub eax,stack_used + cache_addd(stack_used); + cache_addb(0x94); // xchg eax,esp + if (free_flags) { + cache_addw(0xc083); // add eax,4 + cache_addb(0x04); + } + cache_addb(0x50); // push eax (==old esp) +#endif + + paramcount=0; + while (pindex) { + pindex--; + const char * scan=pinfo[pindex].line; + switch (*scan++) { + case 'I': /* immediate value */ + paramcount++; + cache_addb(0x68); //Push immediate + cache_addd(pinfo[pindex].value); //Push value + break; + case 'D': /* Dynamic register */ + { + bool release=false; + paramcount++; + DynReg * dynreg=(DynReg *)pinfo[pindex].value; + GenReg * genreg=FindDynReg(dynreg); + scanagain: + switch (*scan++) { + case 'd': + cache_addb(0x50+genreg->index); //Push reg + break; + case 'w': + cache_addw(0xb70f); //MOVZX EAX,reg + cache_addb(0xc0+genreg->index); + cache_addb(0x50); //Push EAX + break; + case 'l': + cache_addw(0xb60f); //MOVZX EAX,reg[0] + cache_addb(0xc0+genreg->index); + cache_addb(0x50); //Push EAX + break; + case 'h': + cache_addw(0xb60f); //MOVZX EAX,reg[1] + cache_addb(0xc4+genreg->index); + cache_addb(0x50); //Push EAX + break; + case 'r': /* release the reg afterwards */ + release=true; + goto scanagain; + default: + IllegalOption("gen_call_function param:DREG"); + } + if (release) gen_releasereg(dynreg); + } + break; + case 'R': /* Dynamic register to get the return value */ + retparam =&pinfo[pindex]; + pinfo[pindex].line=scan; + break; + case 'F': /* Release flags from stack */ + release_flags=true; + break; + default: + IllegalOption("gen_call_function unknown param"); + } + } +#if defined (MACOSX) + if (free_flags) release_flags=false; + } else { + /* align stack */ + Bit32u stack_used=8; // saving esp and return address on the stack + + cache_addw(0xc48b); // mov eax,esp + cache_addb(0x2d); // sub eax,stack_used + cache_addd(stack_used); + cache_addw(0xe083); // and eax,0xfffffff0 + cache_addb(0xf0); + cache_addb(0x05); // sub eax,stack_used + cache_addd(stack_used); + cache_addb(0x94); // xchg eax,esp + cache_addb(0x50); // push esp (==old esp) +#endif + } + + /* 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); + cache_addd((Bit32u)func - (Bit32u)cache.pos-4); + /* Restore the params of the stack */ + if (paramcount) { + cache_addw(0xc483); //add ESP,imm byte + 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 + break; + case 'w': + cache_addb(0x66); + cache_addw(0xc08b+(genreg->index <<(8+3))); //mov reg,eax + break; + case 'l': + cache_addw(0xc08a+(genreg->index <<(8+3))); //mov reg,eax + break; + case 'h': + cache_addw(0xc08a+((genreg->index+4) <<(8+3))); //mov reg,eax + break; + } + dynreg->flags|=DYNFLG_CHANGED; + } + /* Restore EAX registers to be used again */ + x86gen.regs[X86_REG_EAX]->notusable=false; + +#if defined (MACOSX) + /* restore stack */ + cache_addb(0x5c); // pop esp +#endif +} + +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(); + +#if defined (MACOSX) + /* align stack */ + Bitu stack_used=12; + + cache_addw(0xc48b); // mov eax,esp + cache_addb(0x2d); // sub eax,stack_used + cache_addd(stack_used); + cache_addw(0xe083); // and eax,0xfffffff0 + cache_addb(0xf0); + cache_addb(0x05); // sub eax,stack_used + cache_addd(stack_used); + cache_addb(0x94); // xchg eax,esp + cache_addb(0x50); // push eax (==old esp) +#endif + + 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); + switch (write_size) { + case 1: cache_addd((Bit32u)mem_writeb_checked - (Bit32u)cache.pos-4); break; + case 2: cache_addd((Bit32u)mem_writew_checked - (Bit32u)cache.pos-4); break; + case 4: cache_addd((Bit32u)mem_writed_checked - (Bit32u)cache.pos-4); break; + default: IllegalOption("gen_call_write"); + } + + cache_addw(0xc483); //ADD ESP,8 + cache_addb(2*4); + x86gen.regs[X86_REG_EAX]->notusable=false; + gen_releasereg(dr); + +#if defined (MACOSX) + /* restore stack */ + cache_addb(0x5c); // pop esp +#endif +} + +static Bit8u * gen_create_branch(BranchTypes type) { + /* First free all registers */ + cache_addw(0x70+type); + return (cache.pos-1); +} + +static void gen_fill_branch(Bit8u * data,Bit8u * from=cache.pos) { +#if C_DEBUG + Bits len=from-data; + if (len<0) len=-len; + if (len>126) LOG_MSG("Big jump %d",len); +#endif + *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); + cache_addd(to-(cache.pos+4)); + return (cache.pos-4); +} + +static void gen_fill_jump(Bit8u * data,Bit8u * to=cache.pos) { + *(Bit32u*)data=(to-data-4); +} + + +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + cache_addb(0xa1); + cache_addd((Bit32u)ptr); + cache_addb(0xff); //JMP EA + if (!imm) { //NO EBP + cache_addb(0x20); + } else if ((imm>=-128 && imm<=127)) { + cache_addb(0x60); + cache_addb(imm); + } else { + cache_addb(0xa0); + cache_addd(imm); + } +} + +static void gen_save_flags(DynReg * dynreg) { + 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)); + dynreg->flags|=DYNFLG_CHANGED; +} + +static void gen_load_flags(DynReg * dynreg) { + if (GCC_UNLIKELY(x86gen.flagsactive)) IllegalOption("gen_load_flags"); + cache_addw(0xc483); //ADD ESP,4 + cache_addb(0x4); + GenReg * genreg=FindDynReg(dynreg); + cache_addb(0x50+genreg->index); //PUSH 32 +} + +static void gen_save_host_direct(void * data,Bits imm) { + cache_addw(0x05c7); //MOV [],dword + cache_addd((Bit32u)data); + cache_addd(imm); +} + +static void gen_return(BlockReturn retcode) { + gen_protectflags(); + cache_addb(0x59); //POP ECX, the flags + 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); + 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 62f44ac..388422f 100644 --- a/src/cpu/core_dyn_x86/string.h +++ b/src/cpu/core_dyn_x86/string.h @@ -1,164 +1,164 @@ -/* - * Copyright (C) 2002-2009 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. - */ - -enum STRING_OP { - STR_OUTSB=0,STR_OUTSW,STR_OUTSD, - STR_INSB=4,STR_INSW,STR_INSD, - STR_MOVSB=8,STR_MOVSW,STR_MOVSD, - STR_LODSB=12,STR_LODSW,STR_LODSD, - STR_STOSB=16,STR_STOSW,STR_STOSD, - STR_SCASB=20,STR_SCASW,STR_SCASD, - STR_CMPSB=24,STR_CMPSW,STR_CMPSD -}; - -static void dyn_string(STRING_OP op) { - DynReg * si_base=decode.segprefix ? decode.segprefix : DREG(DS); - DynReg * di_base=DREG(ES); - DynReg * tmp_reg;bool usesi;bool usedi; - gen_protectflags(); - if (decode.rep) { - gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles); - gen_releasereg(DREG(CYCLES)); - decode.cycles=0; - } - /* Check what each string operation will be using */ - switch (op) { - case STR_MOVSB: case STR_MOVSW: case STR_MOVSD: - case STR_CMPSB: case STR_CMPSW: case STR_CMPSD: - tmp_reg=DREG(TMPB);usesi=true;usedi=true;break; - case STR_LODSB: case STR_LODSW: case STR_LODSD: - tmp_reg=DREG(EAX);usesi=true;usedi=false;break; - case STR_OUTSB: case STR_OUTSW: case STR_OUTSD: - tmp_reg=DREG(TMPB);usesi=true;usedi=false;break; - case STR_SCASB: case STR_SCASW: case STR_SCASD: - case STR_STOSB: case STR_STOSW: case STR_STOSD: - tmp_reg=DREG(EAX);usesi=false;usedi=true;break; - case STR_INSB: case STR_INSW: case STR_INSD: - tmp_reg=DREG(TMPB);usesi=false;usedi=true;break; - default: - IllegalOption("dyn_string op"); - } - gen_load_host(&cpu.direction,DREG(TMPW),4); - switch (op & 3) { - case 0:break; - 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("dyn_string shift"); - - } - if (usesi) { - gen_preloadreg(DREG(ESI)); - DynRegs[G_ESI].flags|=DYNFLG_CHANGED; - gen_preloadreg(si_base); - } - if (usedi) { - gen_preloadreg(DREG(EDI)); - DynRegs[G_EDI].flags|=DYNFLG_CHANGED; - gen_preloadreg(di_base); - } - if (decode.rep) { - gen_preloadreg(DREG(ECX)); - DynRegs[G_ECX].flags|=DYNFLG_CHANGED; - } - DynState rep_state; - dyn_savestate(&rep_state); - Bit8u * rep_start=cache.pos; - Bit8u * rep_ecx_jmp; - /* Check if ECX!=zero */ - if (decode.rep) { - gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX)); - rep_ecx_jmp=gen_create_branch_long(BR_Z); - } - if (usesi) { - if (!decode.big_addr) { - gen_extend_word(false,DREG(EA),DREG(ESI)); - gen_lea(DREG(EA),si_base,DREG(EA),0,0); - } else { - gen_lea(DREG(EA),si_base,DREG(ESI),0,0); - } - 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; - case 2:dyn_read_word(DREG(EA),tmp_reg,true);break; - } - switch (op) { - case STR_OUTSB: - gen_call_function((void*)&IO_WriteB,"%Id%Dl",DREG(EDX),tmp_reg);break; - case STR_OUTSW: - gen_call_function((void*)&IO_WriteW,"%Id%Dw",DREG(EDX),tmp_reg);break; - case STR_OUTSD: - gen_call_function((void*)&IO_WriteD,"%Id%Dd",DREG(EDX),tmp_reg);break; - } - } - if (usedi) { - if (!decode.big_addr) { - gen_extend_word(false,DREG(EA),DREG(EDI)); - gen_lea(DREG(EA),di_base,DREG(EA),0,0); - } else { - gen_lea(DREG(EA),di_base,DREG(EDI),0,0); - } - /* Maybe something special to be done to fill the value */ - switch (op) { - case STR_INSB: - gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),tmp_reg); - case STR_MOVSB: - case STR_STOSB: - dyn_write_byte(DREG(EA),tmp_reg,false); - break; - case STR_INSW: - gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),tmp_reg); - case STR_MOVSW: - case STR_STOSW: - dyn_write_word(DREG(EA),tmp_reg,false); - break; - case STR_INSD: - gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),tmp_reg); - case STR_MOVSD: - case STR_STOSD: - dyn_write_word(DREG(EA),tmp_reg,true); - break; - default: - 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) { - gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); - gen_sop_word(SOP_DEC,true,DREG(CYCLES)); - gen_releasereg(DREG(CYCLES)); - 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); - - dyn_loadstate(&rep_state); - gen_fill_branch_long(rep_ecx_jmp); - } - gen_releasereg(DREG(TMPW)); -} +/* + * Copyright (C) 2002-2010 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. + */ + +enum STRING_OP { + STR_OUTSB=0,STR_OUTSW,STR_OUTSD, + STR_INSB=4,STR_INSW,STR_INSD, + STR_MOVSB=8,STR_MOVSW,STR_MOVSD, + STR_LODSB=12,STR_LODSW,STR_LODSD, + STR_STOSB=16,STR_STOSW,STR_STOSD, + STR_SCASB=20,STR_SCASW,STR_SCASD, + STR_CMPSB=24,STR_CMPSW,STR_CMPSD +}; + +static void dyn_string(STRING_OP op) { + DynReg * si_base=decode.segprefix ? decode.segprefix : DREG(DS); + DynReg * di_base=DREG(ES); + DynReg * tmp_reg;bool usesi;bool usedi; + gen_protectflags(); + if (decode.rep) { + gen_dop_word_imm(DOP_SUB,true,DREG(CYCLES),decode.cycles); + gen_releasereg(DREG(CYCLES)); + decode.cycles=0; + } + /* Check what each string operation will be using */ + switch (op) { + case STR_MOVSB: case STR_MOVSW: case STR_MOVSD: + case STR_CMPSB: case STR_CMPSW: case STR_CMPSD: + tmp_reg=DREG(TMPB);usesi=true;usedi=true;break; + case STR_LODSB: case STR_LODSW: case STR_LODSD: + tmp_reg=DREG(EAX);usesi=true;usedi=false;break; + case STR_OUTSB: case STR_OUTSW: case STR_OUTSD: + tmp_reg=DREG(TMPB);usesi=true;usedi=false;break; + case STR_SCASB: case STR_SCASW: case STR_SCASD: + case STR_STOSB: case STR_STOSW: case STR_STOSD: + tmp_reg=DREG(EAX);usesi=false;usedi=true;break; + case STR_INSB: case STR_INSW: case STR_INSD: + tmp_reg=DREG(TMPB);usesi=false;usedi=true;break; + default: + IllegalOption("dyn_string op"); + } + gen_load_host(&cpu.direction,DREG(TMPW),4); + switch (op & 3) { + case 0:break; + 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("dyn_string shift"); + + } + if (usesi) { + gen_preloadreg(DREG(ESI)); + DynRegs[G_ESI].flags|=DYNFLG_CHANGED; + gen_preloadreg(si_base); + } + if (usedi) { + gen_preloadreg(DREG(EDI)); + DynRegs[G_EDI].flags|=DYNFLG_CHANGED; + gen_preloadreg(di_base); + } + if (decode.rep) { + gen_preloadreg(DREG(ECX)); + DynRegs[G_ECX].flags|=DYNFLG_CHANGED; + } + DynState rep_state; + dyn_savestate(&rep_state); + Bit8u * rep_start=cache.pos; + Bit8u * rep_ecx_jmp; + /* Check if ECX!=zero */ + if (decode.rep) { + gen_dop_word(DOP_OR,decode.big_addr,DREG(ECX),DREG(ECX)); + rep_ecx_jmp=gen_create_branch_long(BR_Z); + } + if (usesi) { + if (!decode.big_addr) { + gen_extend_word(false,DREG(EA),DREG(ESI)); + gen_lea(DREG(EA),si_base,DREG(EA),0,0); + } else { + gen_lea(DREG(EA),si_base,DREG(ESI),0,0); + } + 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; + case 2:dyn_read_word(DREG(EA),tmp_reg,true);break; + } + switch (op) { + case STR_OUTSB: + gen_call_function((void*)&IO_WriteB,"%Id%Dl",DREG(EDX),tmp_reg);break; + case STR_OUTSW: + gen_call_function((void*)&IO_WriteW,"%Id%Dw",DREG(EDX),tmp_reg);break; + case STR_OUTSD: + gen_call_function((void*)&IO_WriteD,"%Id%Dd",DREG(EDX),tmp_reg);break; + } + } + if (usedi) { + if (!decode.big_addr) { + gen_extend_word(false,DREG(EA),DREG(EDI)); + gen_lea(DREG(EA),di_base,DREG(EA),0,0); + } else { + gen_lea(DREG(EA),di_base,DREG(EDI),0,0); + } + /* Maybe something special to be done to fill the value */ + switch (op) { + case STR_INSB: + gen_call_function((void*)&IO_ReadB,"%Dw%Rl",DREG(EDX),tmp_reg); + case STR_MOVSB: + case STR_STOSB: + dyn_write_byte(DREG(EA),tmp_reg,false); + break; + case STR_INSW: + gen_call_function((void*)&IO_ReadW,"%Dw%Rw",DREG(EDX),tmp_reg); + case STR_MOVSW: + case STR_STOSW: + dyn_write_word(DREG(EA),tmp_reg,false); + break; + case STR_INSD: + gen_call_function((void*)&IO_ReadD,"%Dw%Rd",DREG(EDX),tmp_reg); + case STR_MOVSD: + case STR_STOSD: + dyn_write_word(DREG(EA),tmp_reg,true); + break; + default: + 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) { + gen_sop_word(SOP_DEC,decode.big_addr,DREG(ECX)); + gen_sop_word(SOP_DEC,true,DREG(CYCLES)); + gen_releasereg(DREG(CYCLES)); + 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); + + dyn_loadstate(&rep_state); + gen_fill_branch_long(rep_ecx_jmp); + } + gen_releasereg(DREG(TMPW)); +} diff --git a/src/cpu/core_dynrec.cpp b/src/cpu/core_dynrec.cpp index df8275c..79f9e15 100644 --- a/src/cpu/core_dynrec.cpp +++ b/src/cpu/core_dynrec.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_dynrec/cache.h b/src/cpu/core_dynrec/cache.h index da78ac2..16619cb 100644 --- a/src/cpu/core_dynrec/cache.h +++ b/src/cpu/core_dynrec/cache.h @@ -1,665 +1,665 @@ -/* - * Copyright (C) 2002-2009 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. - */ - - -class CodePageHandlerDynRec; // forward - -// basic cache block representation -class CacheBlockDynRec { -public: - void Clear(void); - // link this cache block to another block, index specifies the code - // path (always zero for unconditional links, 0/1 for conditional ones - void LinkTo(Bitu index,CacheBlockDynRec * toblock) { - assert(toblock); - link[index].to=toblock; - link[index].next=toblock->link[index].from; // set target block - toblock->link[index].from=this; // remember who links me - } - struct { - Bit16u start,end; // where in the page is the original code - CodePageHandlerDynRec * handler; // page containing this code - } page; - struct { - Bit8u * start; // where in the cache are we - Bitu size; - CacheBlockDynRec * next; - // writemap masking maskpointer/start/length - // to allow holes in the writemap - Bit8u * wmapmask; - Bit16u maskstart; - Bit16u masklen; - } cache; - struct { - Bitu index; - CacheBlockDynRec * next; - } hash; - struct { - CacheBlockDynRec * to; // this block can transfer control to the to-block - CacheBlockDynRec * next; - CacheBlockDynRec * from; // the from-block can transfer control to this block - } link[2]; // maximal two links (conditional jumps) - CacheBlockDynRec * crossblock; -}; - -static struct { - struct { - CacheBlockDynRec * first; // the first cache block in the list - CacheBlockDynRec * active; // the current cache block - CacheBlockDynRec * free; // pointer to the free list - CacheBlockDynRec * running; // the last block that was entered for execution - } block; - Bit8u * pos; // position in the cache block - CodePageHandlerDynRec * free_pages; // pointer to the free list - CodePageHandlerDynRec * used_pages; // pointer to the list of used pages - CodePageHandlerDynRec * last_page; // the last used page -} cache; - - -// cache memory pointers, to be malloc'd later -static Bit8u * cache_code_start_ptr=NULL; -static Bit8u * cache_code=NULL; -static Bit8u * cache_code_link_blocks=NULL; - -static CacheBlockDynRec * cache_blocks=NULL; -static CacheBlockDynRec link_blocks[2]; // default linking (specially marked) - - -// the CodePageHandlerDynRec class provides access to the contained -// cache blocks and intercepts writes to the code for special treatment -class CodePageHandlerDynRec : public PageHandler { -public: - CodePageHandlerDynRec() { - invalidation_map=NULL; - } - - void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) { - // initialize this codepage handler - phys_page=_phys_page; - // save the old pagehandler to provide direct read access to the memory, - // and to be able to restore it later on - old_pagehandler=_old_pagehandler; - - // adjust flags - flags=old_pagehandler->flags|PFLAG_HASCODE; - flags&=~PFLAG_WRITEABLE; - - active_blocks=0; - active_count=16; - - // initialize the maps with zero (no cache blocks as well as code present) - memset(&hash_map,0,sizeof(hash_map)); - memset(&write_map,0,sizeof(write_map)); - if (invalidation_map!=NULL) { - free(invalidation_map); - invalidation_map=NULL; - } - } - - // clear out blocks that contain code which has been modified - bool InvalidateRange(Bitu start,Bitu end) { - Bits index=1+(end>>DYN_HASH_SHIFT); - bool is_current_block=false; // if the current block is modified, it has to be exited as soon as possible - - Bit32u ip_point=SegPhys(cs)+reg_eip; - ip_point=(PAGING_GetPhysicalPage(ip_point)-(phys_page<<12))+(ip_point&0xfff); - while (index>=0) { - Bitu map=0; - // see if there is still some code in the range - for (Bitu count=start;count<=end;count++) map+=write_map[count]; - if (!map) return is_current_block; // no more code, finished - - CacheBlockDynRec * block=hash_map[index]; - while (block) { - CacheBlockDynRec * nextblock=block->hash.next; - // test if this block is in the range - 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(); // clear the block, decrements the write_map accordingly - } - block=nextblock; - } - index--; - } - return is_current_block; - } - - // the following functions will clean all cache blocks that are invalid now due to the write - void writeb(PhysPt addr,Bitu val){ - addr&=4095; - if (host_readb(hostmem+addr)==(Bit8u)val) return; - host_writeb(hostmem+addr,val); - // see if there's code where we are writing to - if (!host_readb(&write_map[addr])) { - if (active_blocks) return; // still some blocks in this page - active_count--; - if (!active_count) Release(); // delay page releasing until active_count is zero - return; - } else if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - invalidation_map[addr]++; - InvalidateRange(addr,addr); - } - void writew(PhysPt addr,Bitu val){ - addr&=4095; - if (host_readw(hostmem+addr)==(Bit16u)val) return; - host_writew(hostmem+addr,val); - // see if there's code where we are writing to - if (!host_readw(&write_map[addr])) { - if (active_blocks) return; // still some blocks in this page - active_count--; - if (!active_count) Release(); // delay page releasing until active_count is zero - return; - } else if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } -#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) - host_writew(&invalidation_map[addr], - host_readw(&invalidation_map[addr])+0x101); -#else - (*(Bit16u*)&invalidation_map[addr])+=0x101; -#endif - InvalidateRange(addr,addr+1); - } - void writed(PhysPt addr,Bitu val){ - addr&=4095; - if (host_readd(hostmem+addr)==(Bit32u)val) return; - host_writed(hostmem+addr,val); - // see if there's code where we are writing to - if (!host_readd(&write_map[addr])) { - if (active_blocks) return; // still some blocks in this page - active_count--; - if (!active_count) Release(); // delay page releasing until active_count is zero - return; - } else if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } -#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) - host_writed(&invalidation_map[addr], - host_readd(&invalidation_map[addr])+0x1010101); -#else - (*(Bit32u*)&invalidation_map[addr])+=0x1010101; -#endif - InvalidateRange(addr,addr+3); - } - bool writeb_checked(PhysPt addr,Bitu val) { - addr&=4095; - if (host_readb(hostmem+addr)==(Bit8u)val) return false; - // see if there's code where we are writing to - if (!host_readb(&write_map[addr])) { - if (!active_blocks) { - // no blocks left in this page, still delay the page releasing a bit - active_count--; - if (!active_count) Release(); - } - } else { - if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } - invalidation_map[addr]++; - 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 (host_readw(hostmem+addr)==(Bit16u)val) return false; - // see if there's code where we are writing to - if (!host_readw(&write_map[addr])) { - if (!active_blocks) { - // no blocks left in this page, still delay the page releasing a bit - active_count--; - if (!active_count) Release(); - } - } else { - if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } -#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) - host_writew(&invalidation_map[addr], - host_readw(&invalidation_map[addr])+0x101); -#else - (*(Bit16u*)&invalidation_map[addr])+=0x101; -#endif - 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 (host_readd(hostmem+addr)==(Bit32u)val) return false; - // see if there's code where we are writing to - if (!host_readd(&write_map[addr])) { - if (!active_blocks) { - // no blocks left in this page, still delay the page releasing a bit - active_count--; - if (!active_count) Release(); - } - } else { - if (!invalidation_map) { - invalidation_map=(Bit8u*)malloc(4096); - memset(invalidation_map,0,4096); - } -#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) - host_writed(&invalidation_map[addr], - host_readd(&invalidation_map[addr])+0x1010101); -#else - (*(Bit32u*)&invalidation_map[addr])+=0x1010101; -#endif - if (InvalidateRange(addr,addr+3)) { - cpu.exception.which=SMC_CURRENT_BLOCK; - return true; - } - } - host_writed(hostmem+addr,val); - return false; - } - - // add a cache block to this page and note it in the hash map - void AddCacheBlock(CacheBlockDynRec * block) { - Bitu index=1+(block->page.start>>DYN_HASH_SHIFT); - block->hash.next=hash_map[index]; // link to old block at index from the new block - block->hash.index=index; - hash_map[index]=block; // put new block at hash position - block->page.handler=this; - active_blocks++; - } - // there's a block whose code started in a different page - void AddCrossBlock(CacheBlockDynRec * block) { - block->hash.next=hash_map[0]; - block->hash.index=0; - hash_map[0]=block; - block->page.handler=this; - active_blocks++; - } - // remove a cache block - void DelCacheBlock(CacheBlockDynRec * block) { - active_blocks--; - active_count=16; - CacheBlockDynRec * * bwhere=&hash_map[block->hash.index]; - while (*bwhere!=block) { - bwhere=&((*bwhere)->hash.next); - //Will crash if a block isn't found, which should never happen. - } - *bwhere=block->hash.next; - - // remove the cleared block from the write map - if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) { - // first part is not influenced by the mask - for (Bitu i=block->page.start;icache.maskstart;i++) { - if (write_map[i]) write_map[i]--; - } - Bitu maskct=0; - // last part sticks to the writemap mask - for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) { - if (write_map[i]) { - // only adjust writemap if it isn't masked - if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--; - } - } - free(block->cache.wmapmask); - block->cache.wmapmask=NULL; - } else { - for (Bitu i=block->page.start;i<=block->page.end;i++) { - if (write_map[i]) write_map[i]--; - } - } - } - - void Release(void) { - MEM_SetPageHandler(phys_page,1,old_pagehandler); // revert to old handler - PAGING_ClearTLB(); - - // remove page from the lists - if (prev) prev->next=next; - else cache.used_pages=next; - if (next) next->prev=prev; - else cache.last_page=prev; - next=cache.free_pages; - cache.free_pages=this; - prev=0; - } - void ClearRelease(void) { - // clear out all cache blocks in this page - for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) { - CacheBlockDynRec * block=hash_map[index]; - while (block) { - CacheBlockDynRec * nextblock=block->hash.next; - block->page.handler=0; // no need, full clear - block->Clear(); - block=nextblock; - } - } - Release(); // now can release this page - } - - CacheBlockDynRec * FindCacheBlock(Bitu start) { - CacheBlockDynRec * block=hash_map[1+(start>>DYN_HASH_SHIFT)]; - // see if there's a cache block present at the start address - while (block) { - if (block->page.start==start) return block; // found - block=block->hash.next; - } - return 0; // none found - } - - HostPt GetHostReadPt(Bitu phys_page) { - hostmem=old_pagehandler->GetHostReadPt(phys_page); - return hostmem; - } - HostPt GetHostWritePt(Bitu phys_page) { - return GetHostReadPt( phys_page ); - } -public: - // the write map, there are write_map[i] cache blocks that cover the byte at address i - Bit8u write_map[4096]; - Bit8u * invalidation_map; - CodePageHandlerDynRec * next, * prev; // page linking -private: - PageHandler * old_pagehandler; - - // hash map to quickly find the cache blocks in this page - CacheBlockDynRec * hash_map[1+DYN_PAGE_HASH]; - - Bitu active_blocks; // the number of cache blocks in this page - Bitu active_count; // delaying parameter to not immediately release a page - HostPt hostmem; - Bitu phys_page; -}; - - -static INLINE void cache_addunusedblock(CacheBlockDynRec * block) { - // block has become unused, add it to the freelist - block->cache.next=cache.block.free; - cache.block.free=block; -} - -static CacheBlockDynRec * cache_getblock(void) { - // get a free cache block and advance the free pointer - CacheBlockDynRec * ret=cache.block.free; - if (!ret) E_Exit("Ran out of CacheBlocks" ); - cache.block.free=ret->cache.next; - ret->cache.next=0; - return ret; -} - -void CacheBlockDynRec::Clear(void) { - Bitu ind; - // check if this is not a cross page block - if (hash.index) for (ind=0;ind<2;ind++) { - CacheBlockDynRec * fromlink=link[ind].from; - link[ind].from=0; - while (fromlink) { - CacheBlockDynRec * nextlink=fromlink->link[ind].next; - // clear the next-link and let the block point to the standard linkcode - fromlink->link[ind].next=0; - fromlink->link[ind].to=&link_blocks[ind]; - - fromlink=nextlink; - } - if (link[ind].to!=&link_blocks[ind]) { - // not linked to the standard linkcode, find the block that links to this block - CacheBlockDynRec * * wherelink=&link[ind].to->link[ind].from; - while (*wherelink != this && *wherelink) { - wherelink = &(*wherelink)->link[ind].next; - } - // now remove the link - if(*wherelink) - *wherelink = (*wherelink)->link[ind].next; - else { - LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate"); - } - } - } else - cache_addunusedblock(this); - if (crossblock) { - // clear out the crossblock (in the page before) as well - crossblock->crossblock=0; - crossblock->Clear(); - crossblock=0; - } - if (page.handler) { - // clear out the code page handler - page.handler->DelCacheBlock(this); - page.handler=0; - } - if (cache.wmapmask){ - free(cache.wmapmask); - cache.wmapmask=NULL; - } -} - - -static CacheBlockDynRec * cache_openblock(void) { - CacheBlockDynRec * block=cache.block.active; - // check for enough space in this block - Bitu size=block->cache.size; - CacheBlockDynRec * nextblock=block->cache.next; - if (block->page.handler) - block->Clear(); - // block size must be at least CACHE_MAXSIZE - while (sizecache.size; - CacheBlockDynRec * tempblock=nextblock->cache.next; - if (nextblock->page.handler) - nextblock->Clear(); - // block is free now - cache_addunusedblock(nextblock); - nextblock=tempblock; - } -skipresize: - // adjust parameters and open this block - block->cache.size=size; - block->cache.next=nextblock; - cache.pos=block->cache.start; - return block; -} - -static void cache_closeblock(void) { - CacheBlockDynRec * block=cache.block.active; - // links point to the default linking code - block->link[0].to=&link_blocks[0]; - block->link[1].to=&link_blocks[1]; - block->link[0].from=0; - block->link[1].from=0; - block->link[0].next=0; - block->link[1].next=0; - // close the block with correct alignment - Bitu written=(Bitu)(cache.pos-block->cache.start); - if (written>block->cache.size) { - if (!block->cache.next) { - if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size); - } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size); - } else { - Bitu new_size; - Bitu left=block->cache.size-written; - // smaller than cache align then don't bother to resize - if (left>CACHE_ALIGN) { - new_size=((written-1)|(CACHE_ALIGN-1))+1; - CacheBlockDynRec * newblock=cache_getblock(); - // align block now to CACHE_ALIGN - newblock->cache.start=block->cache.start+new_size; - newblock->cache.size=block->cache.size-new_size; - newblock->cache.next=block->cache.next; - block->cache.next=newblock; - block->cache.size=new_size; - } - } - // advance the active block pointer - if (!block->cache.next || (block->cache.next->cache.start>(cache_code_start_ptr + CACHE_TOTAL - CACHE_MAXSIZE))) { -// LOG_MSG("Cache full restarting"); - cache.block.active=cache.block.first; - } else { - cache.block.active=block->cache.next; - } -} - - -// place an 8bit value into the cache -static INLINE void cache_addb(Bit8u val) { - *cache.pos++=val; -} - -// place a 16bit value into the cache -static INLINE void cache_addw(Bit16u val) { - *(Bit16u*)cache.pos=val; - cache.pos+=2; -} - -// place a 32bit value into the cache -static INLINE void cache_addd(Bit32u val) { - *(Bit32u*)cache.pos=val; - cache.pos+=4; -} - -// place a 64bit value into the cache -static INLINE void cache_addq(Bit64u val) { - *(Bit64u*)cache.pos=val; - cache.pos+=8; -} - - -static void dyn_return(BlockReturn retcode,bool ret_exception); -static void dyn_run_code(void); - - -/* 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 4096 -#endif - -static bool cache_initialized = false; - -static void cache_init(bool enable) { - Bits i; - if (enable) { - // see if cache is already initialized - if (cache_initialized) return; - cache_initialized = true; - if (cache_blocks == NULL) { - // allocate the cache blocks memory - cache_blocks=(CacheBlockDynRec*)malloc(CACHE_BLOCKS*sizeof(CacheBlockDynRec)); - if(!cache_blocks) E_Exit("Allocating cache_blocks has failed"); - memset(cache_blocks,0,sizeof(CacheBlockDynRec)*CACHE_BLOCKS); - cache.block.free=&cache_blocks[0]; - // initialize the cache blocks - 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]; - link_blocks[0].cache.start=cache.pos; - // link code that returns with a special return code - dyn_return(BR_Link1,false); - cache.pos=&cache_code_link_blocks[32]; - link_blocks[1].cache.start=cache.pos; - // link code that returns with a special return code - dyn_return(BR_Link2,false); - - cache.pos=&cache_code_link_blocks[64]; - core_dynrec.runcode=(BlockReturn (*)(Bit8u*))cache.pos; -// link_blocks[1].cache.start=cache.pos; - dyn_run_code(); - - 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; - } - } -} - -static void cache_close(void) { -/* for (;;) { - if (cache.used_pages) { - CodePageHandler * cpage=cache.used_pages; - CodePageHandler * npage=cache.used_pages->next; - cpage->ClearRelease(); - delete cpage; - cache.used_pages=npage; - } else break; - } - if (cache_blocks != NULL) { - free(cache_blocks); - cache_blocks = NULL; - } - if (cache_code_start_ptr != NULL) { - ### care: under windows VirtualFree() has to be used if - ### VirtualAlloc was used for memory allocation - free(cache_code_start_ptr); - cache_code_start_ptr = NULL; - } - cache_code = NULL; - cache_code_link_blocks = NULL; - cache_initialized = false; */ -} +/* + * Copyright (C) 2002-2010 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. + */ + + +class CodePageHandlerDynRec; // forward + +// basic cache block representation +class CacheBlockDynRec { +public: + void Clear(void); + // link this cache block to another block, index specifies the code + // path (always zero for unconditional links, 0/1 for conditional ones + void LinkTo(Bitu index,CacheBlockDynRec * toblock) { + assert(toblock); + link[index].to=toblock; + link[index].next=toblock->link[index].from; // set target block + toblock->link[index].from=this; // remember who links me + } + struct { + Bit16u start,end; // where in the page is the original code + CodePageHandlerDynRec * handler; // page containing this code + } page; + struct { + Bit8u * start; // where in the cache are we + Bitu size; + CacheBlockDynRec * next; + // writemap masking maskpointer/start/length + // to allow holes in the writemap + Bit8u * wmapmask; + Bit16u maskstart; + Bit16u masklen; + } cache; + struct { + Bitu index; + CacheBlockDynRec * next; + } hash; + struct { + CacheBlockDynRec * to; // this block can transfer control to the to-block + CacheBlockDynRec * next; + CacheBlockDynRec * from; // the from-block can transfer control to this block + } link[2]; // maximal two links (conditional jumps) + CacheBlockDynRec * crossblock; +}; + +static struct { + struct { + CacheBlockDynRec * first; // the first cache block in the list + CacheBlockDynRec * active; // the current cache block + CacheBlockDynRec * free; // pointer to the free list + CacheBlockDynRec * running; // the last block that was entered for execution + } block; + Bit8u * pos; // position in the cache block + CodePageHandlerDynRec * free_pages; // pointer to the free list + CodePageHandlerDynRec * used_pages; // pointer to the list of used pages + CodePageHandlerDynRec * last_page; // the last used page +} cache; + + +// cache memory pointers, to be malloc'd later +static Bit8u * cache_code_start_ptr=NULL; +static Bit8u * cache_code=NULL; +static Bit8u * cache_code_link_blocks=NULL; + +static CacheBlockDynRec * cache_blocks=NULL; +static CacheBlockDynRec link_blocks[2]; // default linking (specially marked) + + +// the CodePageHandlerDynRec class provides access to the contained +// cache blocks and intercepts writes to the code for special treatment +class CodePageHandlerDynRec : public PageHandler { +public: + CodePageHandlerDynRec() { + invalidation_map=NULL; + } + + void SetupAt(Bitu _phys_page,PageHandler * _old_pagehandler) { + // initialize this codepage handler + phys_page=_phys_page; + // save the old pagehandler to provide direct read access to the memory, + // and to be able to restore it later on + old_pagehandler=_old_pagehandler; + + // adjust flags + flags=old_pagehandler->flags|PFLAG_HASCODE; + flags&=~PFLAG_WRITEABLE; + + active_blocks=0; + active_count=16; + + // initialize the maps with zero (no cache blocks as well as code present) + memset(&hash_map,0,sizeof(hash_map)); + memset(&write_map,0,sizeof(write_map)); + if (invalidation_map!=NULL) { + free(invalidation_map); + invalidation_map=NULL; + } + } + + // clear out blocks that contain code which has been modified + bool InvalidateRange(Bitu start,Bitu end) { + Bits index=1+(end>>DYN_HASH_SHIFT); + bool is_current_block=false; // if the current block is modified, it has to be exited as soon as possible + + Bit32u ip_point=SegPhys(cs)+reg_eip; + ip_point=(PAGING_GetPhysicalPage(ip_point)-(phys_page<<12))+(ip_point&0xfff); + while (index>=0) { + Bitu map=0; + // see if there is still some code in the range + for (Bitu count=start;count<=end;count++) map+=write_map[count]; + if (!map) return is_current_block; // no more code, finished + + CacheBlockDynRec * block=hash_map[index]; + while (block) { + CacheBlockDynRec * nextblock=block->hash.next; + // test if this block is in the range + 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(); // clear the block, decrements the write_map accordingly + } + block=nextblock; + } + index--; + } + return is_current_block; + } + + // the following functions will clean all cache blocks that are invalid now due to the write + void writeb(PhysPt addr,Bitu val){ + addr&=4095; + if (host_readb(hostmem+addr)==(Bit8u)val) return; + host_writeb(hostmem+addr,val); + // see if there's code where we are writing to + if (!host_readb(&write_map[addr])) { + if (active_blocks) return; // still some blocks in this page + active_count--; + if (!active_count) Release(); // delay page releasing until active_count is zero + return; + } else if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + invalidation_map[addr]++; + InvalidateRange(addr,addr); + } + void writew(PhysPt addr,Bitu val){ + addr&=4095; + if (host_readw(hostmem+addr)==(Bit16u)val) return; + host_writew(hostmem+addr,val); + // see if there's code where we are writing to + if (!host_readw(&write_map[addr])) { + if (active_blocks) return; // still some blocks in this page + active_count--; + if (!active_count) Release(); // delay page releasing until active_count is zero + return; + } else if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } +#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) + host_writew(&invalidation_map[addr], + host_readw(&invalidation_map[addr])+0x101); +#else + (*(Bit16u*)&invalidation_map[addr])+=0x101; +#endif + InvalidateRange(addr,addr+1); + } + void writed(PhysPt addr,Bitu val){ + addr&=4095; + if (host_readd(hostmem+addr)==(Bit32u)val) return; + host_writed(hostmem+addr,val); + // see if there's code where we are writing to + if (!host_readd(&write_map[addr])) { + if (active_blocks) return; // still some blocks in this page + active_count--; + if (!active_count) Release(); // delay page releasing until active_count is zero + return; + } else if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } +#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) + host_writed(&invalidation_map[addr], + host_readd(&invalidation_map[addr])+0x1010101); +#else + (*(Bit32u*)&invalidation_map[addr])+=0x1010101; +#endif + InvalidateRange(addr,addr+3); + } + bool writeb_checked(PhysPt addr,Bitu val) { + addr&=4095; + if (host_readb(hostmem+addr)==(Bit8u)val) return false; + // see if there's code where we are writing to + if (!host_readb(&write_map[addr])) { + if (!active_blocks) { + // no blocks left in this page, still delay the page releasing a bit + active_count--; + if (!active_count) Release(); + } + } else { + if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } + invalidation_map[addr]++; + 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 (host_readw(hostmem+addr)==(Bit16u)val) return false; + // see if there's code where we are writing to + if (!host_readw(&write_map[addr])) { + if (!active_blocks) { + // no blocks left in this page, still delay the page releasing a bit + active_count--; + if (!active_count) Release(); + } + } else { + if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } +#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) + host_writew(&invalidation_map[addr], + host_readw(&invalidation_map[addr])+0x101); +#else + (*(Bit16u*)&invalidation_map[addr])+=0x101; +#endif + 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 (host_readd(hostmem+addr)==(Bit32u)val) return false; + // see if there's code where we are writing to + if (!host_readd(&write_map[addr])) { + if (!active_blocks) { + // no blocks left in this page, still delay the page releasing a bit + active_count--; + if (!active_count) Release(); + } + } else { + if (!invalidation_map) { + invalidation_map=(Bit8u*)malloc(4096); + memset(invalidation_map,0,4096); + } +#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY) + host_writed(&invalidation_map[addr], + host_readd(&invalidation_map[addr])+0x1010101); +#else + (*(Bit32u*)&invalidation_map[addr])+=0x1010101; +#endif + if (InvalidateRange(addr,addr+3)) { + cpu.exception.which=SMC_CURRENT_BLOCK; + return true; + } + } + host_writed(hostmem+addr,val); + return false; + } + + // add a cache block to this page and note it in the hash map + void AddCacheBlock(CacheBlockDynRec * block) { + Bitu index=1+(block->page.start>>DYN_HASH_SHIFT); + block->hash.next=hash_map[index]; // link to old block at index from the new block + block->hash.index=index; + hash_map[index]=block; // put new block at hash position + block->page.handler=this; + active_blocks++; + } + // there's a block whose code started in a different page + void AddCrossBlock(CacheBlockDynRec * block) { + block->hash.next=hash_map[0]; + block->hash.index=0; + hash_map[0]=block; + block->page.handler=this; + active_blocks++; + } + // remove a cache block + void DelCacheBlock(CacheBlockDynRec * block) { + active_blocks--; + active_count=16; + CacheBlockDynRec * * bwhere=&hash_map[block->hash.index]; + while (*bwhere!=block) { + bwhere=&((*bwhere)->hash.next); + //Will crash if a block isn't found, which should never happen. + } + *bwhere=block->hash.next; + + // remove the cleared block from the write map + if (GCC_UNLIKELY(block->cache.wmapmask!=NULL)) { + // first part is not influenced by the mask + for (Bitu i=block->page.start;icache.maskstart;i++) { + if (write_map[i]) write_map[i]--; + } + Bitu maskct=0; + // last part sticks to the writemap mask + for (Bitu i=block->cache.maskstart;i<=block->page.end;i++,maskct++) { + if (write_map[i]) { + // only adjust writemap if it isn't masked + if ((maskct>=block->cache.masklen) || (!block->cache.wmapmask[maskct])) write_map[i]--; + } + } + free(block->cache.wmapmask); + block->cache.wmapmask=NULL; + } else { + for (Bitu i=block->page.start;i<=block->page.end;i++) { + if (write_map[i]) write_map[i]--; + } + } + } + + void Release(void) { + MEM_SetPageHandler(phys_page,1,old_pagehandler); // revert to old handler + PAGING_ClearTLB(); + + // remove page from the lists + if (prev) prev->next=next; + else cache.used_pages=next; + if (next) next->prev=prev; + else cache.last_page=prev; + next=cache.free_pages; + cache.free_pages=this; + prev=0; + } + void ClearRelease(void) { + // clear out all cache blocks in this page + for (Bitu index=0;index<(1+DYN_PAGE_HASH);index++) { + CacheBlockDynRec * block=hash_map[index]; + while (block) { + CacheBlockDynRec * nextblock=block->hash.next; + block->page.handler=0; // no need, full clear + block->Clear(); + block=nextblock; + } + } + Release(); // now can release this page + } + + CacheBlockDynRec * FindCacheBlock(Bitu start) { + CacheBlockDynRec * block=hash_map[1+(start>>DYN_HASH_SHIFT)]; + // see if there's a cache block present at the start address + while (block) { + if (block->page.start==start) return block; // found + block=block->hash.next; + } + return 0; // none found + } + + HostPt GetHostReadPt(Bitu phys_page) { + hostmem=old_pagehandler->GetHostReadPt(phys_page); + return hostmem; + } + HostPt GetHostWritePt(Bitu phys_page) { + return GetHostReadPt( phys_page ); + } +public: + // the write map, there are write_map[i] cache blocks that cover the byte at address i + Bit8u write_map[4096]; + Bit8u * invalidation_map; + CodePageHandlerDynRec * next, * prev; // page linking +private: + PageHandler * old_pagehandler; + + // hash map to quickly find the cache blocks in this page + CacheBlockDynRec * hash_map[1+DYN_PAGE_HASH]; + + Bitu active_blocks; // the number of cache blocks in this page + Bitu active_count; // delaying parameter to not immediately release a page + HostPt hostmem; + Bitu phys_page; +}; + + +static INLINE void cache_addunusedblock(CacheBlockDynRec * block) { + // block has become unused, add it to the freelist + block->cache.next=cache.block.free; + cache.block.free=block; +} + +static CacheBlockDynRec * cache_getblock(void) { + // get a free cache block and advance the free pointer + CacheBlockDynRec * ret=cache.block.free; + if (!ret) E_Exit("Ran out of CacheBlocks" ); + cache.block.free=ret->cache.next; + ret->cache.next=0; + return ret; +} + +void CacheBlockDynRec::Clear(void) { + Bitu ind; + // check if this is not a cross page block + if (hash.index) for (ind=0;ind<2;ind++) { + CacheBlockDynRec * fromlink=link[ind].from; + link[ind].from=0; + while (fromlink) { + CacheBlockDynRec * nextlink=fromlink->link[ind].next; + // clear the next-link and let the block point to the standard linkcode + fromlink->link[ind].next=0; + fromlink->link[ind].to=&link_blocks[ind]; + + fromlink=nextlink; + } + if (link[ind].to!=&link_blocks[ind]) { + // not linked to the standard linkcode, find the block that links to this block + CacheBlockDynRec * * wherelink=&link[ind].to->link[ind].from; + while (*wherelink != this && *wherelink) { + wherelink = &(*wherelink)->link[ind].next; + } + // now remove the link + if(*wherelink) + *wherelink = (*wherelink)->link[ind].next; + else { + LOG(LOG_CPU,LOG_ERROR)("Cache anomaly. please investigate"); + } + } + } else + cache_addunusedblock(this); + if (crossblock) { + // clear out the crossblock (in the page before) as well + crossblock->crossblock=0; + crossblock->Clear(); + crossblock=0; + } + if (page.handler) { + // clear out the code page handler + page.handler->DelCacheBlock(this); + page.handler=0; + } + if (cache.wmapmask){ + free(cache.wmapmask); + cache.wmapmask=NULL; + } +} + + +static CacheBlockDynRec * cache_openblock(void) { + CacheBlockDynRec * block=cache.block.active; + // check for enough space in this block + Bitu size=block->cache.size; + CacheBlockDynRec * nextblock=block->cache.next; + if (block->page.handler) + block->Clear(); + // block size must be at least CACHE_MAXSIZE + while (sizecache.size; + CacheBlockDynRec * tempblock=nextblock->cache.next; + if (nextblock->page.handler) + nextblock->Clear(); + // block is free now + cache_addunusedblock(nextblock); + nextblock=tempblock; + } +skipresize: + // adjust parameters and open this block + block->cache.size=size; + block->cache.next=nextblock; + cache.pos=block->cache.start; + return block; +} + +static void cache_closeblock(void) { + CacheBlockDynRec * block=cache.block.active; + // links point to the default linking code + block->link[0].to=&link_blocks[0]; + block->link[1].to=&link_blocks[1]; + block->link[0].from=0; + block->link[1].from=0; + block->link[0].next=0; + block->link[1].next=0; + // close the block with correct alignment + Bitu written=(Bitu)(cache.pos-block->cache.start); + if (written>block->cache.size) { + if (!block->cache.next) { + if (written>block->cache.size+CACHE_MAXSIZE) E_Exit("CacheBlock overrun 1 %d",written-block->cache.size); + } else E_Exit("CacheBlock overrun 2 written %d size %d",written,block->cache.size); + } else { + Bitu new_size; + Bitu left=block->cache.size-written; + // smaller than cache align then don't bother to resize + if (left>CACHE_ALIGN) { + new_size=((written-1)|(CACHE_ALIGN-1))+1; + CacheBlockDynRec * newblock=cache_getblock(); + // align block now to CACHE_ALIGN + newblock->cache.start=block->cache.start+new_size; + newblock->cache.size=block->cache.size-new_size; + newblock->cache.next=block->cache.next; + block->cache.next=newblock; + block->cache.size=new_size; + } + } + // advance the active block pointer + if (!block->cache.next || (block->cache.next->cache.start>(cache_code_start_ptr + CACHE_TOTAL - CACHE_MAXSIZE))) { +// LOG_MSG("Cache full restarting"); + cache.block.active=cache.block.first; + } else { + cache.block.active=block->cache.next; + } +} + + +// place an 8bit value into the cache +static INLINE void cache_addb(Bit8u val) { + *cache.pos++=val; +} + +// place a 16bit value into the cache +static INLINE void cache_addw(Bit16u val) { + *(Bit16u*)cache.pos=val; + cache.pos+=2; +} + +// place a 32bit value into the cache +static INLINE void cache_addd(Bit32u val) { + *(Bit32u*)cache.pos=val; + cache.pos+=4; +} + +// place a 64bit value into the cache +static INLINE void cache_addq(Bit64u val) { + *(Bit64u*)cache.pos=val; + cache.pos+=8; +} + + +static void dyn_return(BlockReturn retcode,bool ret_exception); +static void dyn_run_code(void); + + +/* 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 4096 +#endif + +static bool cache_initialized = false; + +static void cache_init(bool enable) { + Bits i; + if (enable) { + // see if cache is already initialized + if (cache_initialized) return; + cache_initialized = true; + if (cache_blocks == NULL) { + // allocate the cache blocks memory + cache_blocks=(CacheBlockDynRec*)malloc(CACHE_BLOCKS*sizeof(CacheBlockDynRec)); + if(!cache_blocks) E_Exit("Allocating cache_blocks has failed"); + memset(cache_blocks,0,sizeof(CacheBlockDynRec)*CACHE_BLOCKS); + cache.block.free=&cache_blocks[0]; + // initialize the cache blocks + 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]; + link_blocks[0].cache.start=cache.pos; + // link code that returns with a special return code + dyn_return(BR_Link1,false); + cache.pos=&cache_code_link_blocks[32]; + link_blocks[1].cache.start=cache.pos; + // link code that returns with a special return code + dyn_return(BR_Link2,false); + + cache.pos=&cache_code_link_blocks[64]; + core_dynrec.runcode=(BlockReturn (*)(Bit8u*))cache.pos; +// link_blocks[1].cache.start=cache.pos; + dyn_run_code(); + + 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; + } + } +} + +static void cache_close(void) { +/* for (;;) { + if (cache.used_pages) { + CodePageHandler * cpage=cache.used_pages; + CodePageHandler * npage=cache.used_pages->next; + cpage->ClearRelease(); + delete cpage; + cache.used_pages=npage; + } else break; + } + if (cache_blocks != NULL) { + free(cache_blocks); + cache_blocks = NULL; + } + if (cache_code_start_ptr != NULL) { + ### care: under windows VirtualFree() has to be used if + ### VirtualAlloc was used for memory allocation + free(cache_code_start_ptr); + cache_code_start_ptr = NULL; + } + cache_code = NULL; + cache_code_link_blocks = NULL; + cache_initialized = false; */ +} diff --git a/src/cpu/core_dynrec/decoder.h b/src/cpu/core_dynrec/decoder.h index 315e113..0ca887c 100644 --- a/src/cpu/core_dynrec/decoder.h +++ b/src/cpu/core_dynrec/decoder.h @@ -1,612 +1,612 @@ -/* - * Copyright (C) 2002-2009 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: decoder.h,v 1.8 2009/10/18 17:52:10 c2woody Exp $ */ - - -#include "decoder_basic.h" -#include "operators.h" -#include "decoder_opcodes.h" - -#include "dyn_fpu.h" - -/* - The function CreateCacheBlock translates the instruction stream - until either an unhandled instruction is found, the maximal - number of translated instructions is reached or some critical - instruction is encountered. -*/ - -static CacheBlockDynRec * CreateCacheBlock(CodePageHandlerDynRec * codepage,PhysPt start,Bitu max_opcodes) { - // initialize a load of variables - decode.code_start=start; - decode.code=start; - decode.page.code=codepage; - decode.page.index=start&4095; - decode.page.wmap=codepage->write_map; - decode.page.invmap=codepage->invalidation_map; - decode.page.first=start >> 12; - decode.active_block=decode.block=cache_openblock(); - decode.block->page.start=(Bit16u)decode.page.index; - codepage->AddCacheBlock(decode.block); - - InitFlagsOptimization(); - - // every codeblock that is run sets cache.block.running to itself - // so the block linking knows the last executed block - gen_mov_direct_ptr(&cache.block.running,(DRC_PTR_SIZE_IM)decode.block); - - // start with the cycles check - gen_mov_word_to_reg(FC_RETOP,&CPU_Cycles,true); - save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_leqzero(FC_RETOP); - save_info_dynrec[used_save_info_dynrec].type=cycle_check; - used_save_info_dynrec++; - - decode.cycles=0; - while (max_opcodes--) { - // Init prefixes - decode.big_addr=cpu.code.big; - decode.big_op=cpu.code.big; - decode.seg_prefix=0; - decode.seg_prefix_used=false; - decode.rep=REP_NONE; - decode.cycles++; - decode.op_start=decode.code; -restart_prefix: - Bitu opcode; - if (!decode.page.invmap) opcode=decode_fetchb(); - else { - // some entries in the invalidation map, see if the next - // instruction is known to be modified a lot - if (decode.page.index<4096) { - if (GCC_UNLIKELY(decode.page.invmap[decode.page.index]>=4)) goto illegalopcode; - opcode=decode_fetchb(); - } else { - // switch to the next page - opcode=decode_fetchb(); - if (GCC_UNLIKELY(decode.page.invmap && - (decode.page.invmap[decode.page.index-1]>=4))) goto illegalopcode; - } - } - switch (opcode) { - // instructions 'op reg8,reg8' and 'op [],reg8' - case 0x00:dyn_dop_ebgb(DOP_ADD);break; - case 0x08:dyn_dop_ebgb(DOP_OR);break; - case 0x10:dyn_dop_ebgb(DOP_ADC);break; - case 0x18:dyn_dop_ebgb(DOP_SBB);break; - case 0x20:dyn_dop_ebgb(DOP_AND);break; - case 0x28:dyn_dop_ebgb(DOP_SUB);break; - case 0x30:dyn_dop_ebgb(DOP_XOR);break; - case 0x38:dyn_dop_ebgb(DOP_CMP);break; - - // instructions 'op reg8,reg8' and 'op reg8,[]' - case 0x02:dyn_dop_gbeb(DOP_ADD);break; - case 0x0a:dyn_dop_gbeb(DOP_OR);break; - case 0x12:dyn_dop_gbeb(DOP_ADC);break; - case 0x1a:dyn_dop_gbeb(DOP_SBB);break; - case 0x22:dyn_dop_gbeb(DOP_AND);break; - case 0x2a:dyn_dop_gbeb(DOP_SUB);break; - case 0x32:dyn_dop_gbeb(DOP_XOR);break; - case 0x3a:dyn_dop_gbeb(DOP_CMP);break; - - // instructions 'op reg16/32,reg16/32' and 'op [],reg16/32' - case 0x01:dyn_dop_evgv(DOP_ADD);break; - case 0x09:dyn_dop_evgv(DOP_OR);break; - case 0x11:dyn_dop_evgv(DOP_ADC);break; - case 0x19:dyn_dop_evgv(DOP_SBB);break; - case 0x21:dyn_dop_evgv(DOP_AND);break; - case 0x29:dyn_dop_evgv(DOP_SUB);break; - case 0x31:dyn_dop_evgv(DOP_XOR);break; - case 0x39:dyn_dop_evgv(DOP_CMP);break; - - // instructions 'op reg16/32,reg16/32' and 'op reg16/32,[]' - case 0x03:dyn_dop_gvev(DOP_ADD);break; - case 0x0b:dyn_dop_gvev(DOP_OR);break; - case 0x13:dyn_dop_gvev(DOP_ADC);break; - case 0x1b:dyn_dop_gvev(DOP_SBB);break; - case 0x23:dyn_dop_gvev(DOP_AND);break; - case 0x2b:dyn_dop_gvev(DOP_SUB);break; - case 0x33:dyn_dop_gvev(DOP_XOR);break; - case 0x3b:dyn_dop_gvev(DOP_CMP);break; - - // instructions 'op reg8,imm8' - case 0x04:dyn_dop_byte_imm(DOP_ADD,DRC_REG_EAX,0);break; - case 0x0c:dyn_dop_byte_imm(DOP_OR,DRC_REG_EAX,0);break; - case 0x14:dyn_dop_byte_imm(DOP_ADC,DRC_REG_EAX,0);break; - case 0x1c:dyn_dop_byte_imm(DOP_SBB,DRC_REG_EAX,0);break; - case 0x24:dyn_dop_byte_imm(DOP_AND,DRC_REG_EAX,0);break; - case 0x2c:dyn_dop_byte_imm(DOP_SUB,DRC_REG_EAX,0);break; - case 0x34:dyn_dop_byte_imm(DOP_XOR,DRC_REG_EAX,0);break; - case 0x3c:dyn_dop_byte_imm(DOP_CMP,DRC_REG_EAX,0);break; - - // instructions 'op reg16/32,imm16/32' - case 0x05:dyn_dop_word_imm(DOP_ADD,DRC_REG_EAX);break; - case 0x0d:dyn_dop_word_imm_old(DOP_OR,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - case 0x15:dyn_dop_word_imm_old(DOP_ADC,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - case 0x1d:dyn_dop_word_imm_old(DOP_SBB,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - case 0x25:dyn_dop_word_imm(DOP_AND,DRC_REG_EAX);break; - case 0x2d:dyn_dop_word_imm_old(DOP_SUB,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - case 0x35:dyn_dop_word_imm_old(DOP_XOR,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - case 0x3d:dyn_dop_word_imm_old(DOP_CMP,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - - // push segment register onto stack - case 0x06:dyn_push_seg(DRC_SEG_ES);break; - case 0x0e:dyn_push_seg(DRC_SEG_CS);break; - case 0x16:dyn_push_seg(DRC_SEG_SS);break; - case 0x1e:dyn_push_seg(DRC_SEG_DS);break; - - // pop segment register from stack - case 0x07:dyn_pop_seg(DRC_SEG_ES);break; - case 0x17:dyn_pop_seg(DRC_SEG_SS);break; - case 0x1f:dyn_pop_seg(DRC_SEG_DS);break; - - // segment prefixes - case 0x26:dyn_segprefix(DRC_SEG_ES);goto restart_prefix; - case 0x2e:dyn_segprefix(DRC_SEG_CS);goto restart_prefix; - case 0x36:dyn_segprefix(DRC_SEG_SS);goto restart_prefix; - case 0x3e:dyn_segprefix(DRC_SEG_DS);goto restart_prefix; - case 0x64:dyn_segprefix(DRC_SEG_FS);goto restart_prefix; - case 0x65:dyn_segprefix(DRC_SEG_GS);goto restart_prefix; - -// case 0x27: DAA missing -// case 0x2f: DAS missing -// case 0x37: AAA missing -// case 0x3f: AAS missing - - // dual opcodes - case 0x0f: - { - Bitu dual_code=decode_fetchb(); - switch (dual_code) { - case 0x00: - if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; - dyn_grp6(); - break; - case 0x01: - if (dyn_grp7()) goto finish_block; - break; -/* case 0x02: - if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; - dyn_larlsl(true); - break; - case 0x03: - if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; - dyn_larlsl(false); - break; */ - - case 0x20:dyn_mov_from_crx();break; - case 0x22:dyn_mov_to_crx();goto finish_block; - - // short conditional jumps - case 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87: - case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f: - dyn_branched_exit((BranchTypes)(dual_code&0xf), - decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); - goto finish_block; - - // conditional byte set instructions -/* case 0x90:case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: - case 0x98:case 0x99:case 0x9a:case 0x9b:case 0x9c:case 0x9d:case 0x9e:case 0x9f: - dyn_set_byte_on_condition((BranchTypes)(dual_code&0xf)); - AcquireFlags(FMASK_TEST); - break; */ - - // push/pop segment registers - case 0xa0:dyn_push_seg(DRC_SEG_FS);break; - case 0xa1:dyn_pop_seg(DRC_SEG_FS);break; - case 0xa8:dyn_push_seg(DRC_SEG_GS);break; - case 0xa9:dyn_pop_seg(DRC_SEG_GS);break; - - // double shift instructions - case 0xa4:dyn_dshift_ev_gv(true,true);break; - case 0xa5:dyn_dshift_ev_gv(true,false);break; - case 0xac:dyn_dshift_ev_gv(false,true);break; - case 0xad:dyn_dshift_ev_gv(false,false);break; - - case 0xaf:dyn_imul_gvev(0);break; - - // lfs - case 0xb4: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(DRC_SEG_FS); - break; - // lgs - case 0xb5: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(DRC_SEG_GS); - break; - - // zero-extending moves - case 0xb6:dyn_movx_ev_gb(false);break; - case 0xb7:dyn_movx_ev_gw(false);break; - - // sign-extending moves - case 0xbe:dyn_movx_ev_gb(true);break; - case 0xbf:dyn_movx_ev_gw(true);break; - - default: -// DYN_LOG("Unhandled dual opcode 0F%02X",dual_code); - goto illegalopcode; - } - break; - } - - // 'inc/dec reg16/32' - case 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47: - dyn_sop_word(SOP_INC,opcode&7); - break; - case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f: - dyn_sop_word(SOP_DEC,opcode&7); - break; - - // 'push/pop reg16/32' - case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57: - dyn_push_reg(opcode&7); - break; - case 0x58:case 0x59:case 0x5a:case 0x5b:case 0x5c:case 0x5d:case 0x5e:case 0x5f: - dyn_pop_reg(opcode&7); - break; - - case 0x60: - if (decode.big_op) gen_call_function_raw((void *)&dynrec_pusha_dword); - else gen_call_function_raw((void *)&dynrec_pusha_word); - break; - case 0x61: - if (decode.big_op) gen_call_function_raw((void *)&dynrec_popa_dword); - else gen_call_function_raw((void *)&dynrec_popa_word); - break; - -// case 0x62: BOUND missing -// case 0x61: ARPL missing - - case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix; - case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix; - - // 'push imm8/16/32' - case 0x68: - dyn_push_word_imm(decode.big_op ? decode_fetchd() : decode_fetchw()); - break; - case 0x6a: - dyn_push_byte_imm((Bit8s)decode_fetchb()); - break; - - // signed multiplication - case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break; - case 0x6b:dyn_imul_gvev(1);break; - -// case 0x6c to 0x6f missing (ins/outs) - - // short conditional jumps - case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77: - case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f: - dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb()); - goto finish_block; - - // 'op []/reg8,imm8' - case 0x80: - case 0x82:dyn_grp1_eb_ib();break; - - // 'op []/reg16/32,imm16/32' - case 0x81:dyn_grp1_ev_iv(false);break; - case 0x83:dyn_grp1_ev_iv(true);break; - - // 'test []/reg8/16/32,reg8/16/32' - case 0x84:dyn_dop_gbeb(DOP_TEST);break; - case 0x85:dyn_dop_gvev(DOP_TEST);break; - - // 'xchg reg8/16/32,[]/reg8/16/32' - case 0x86:dyn_dop_ebgb_xchg();break; - case 0x87:dyn_dop_evgv_xchg();break; - - // 'mov []/reg8/16/32,reg8/16/32' - case 0x88:dyn_dop_ebgb_mov();break; - case 0x89:dyn_dop_evgv_mov();break; - // 'mov reg8/16/32,[]/reg8/16/32' - case 0x8a:dyn_dop_gbeb_mov();break; - case 0x8b:dyn_dop_gvev_mov();break; - - // move segment register into memory or a 16bit register - case 0x8c:dyn_mov_ev_seg();break; - - // load effective address - case 0x8d:dyn_lea();break; - - // move a value from memory or a 16bit register into a segment register - case 0x8e:dyn_mov_seg_ev();break; - - // 'pop []' - case 0x8f:dyn_pop_ev();break; - - case 0x90: // nop - case 0x9b: // wait - case 0xf0: // lock - break; - - case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: - dyn_xchg_ax(opcode&7); - break; - - // sign-extend al into ax/sign-extend ax into eax - case 0x98:dyn_cbw();break; - // sign-extend ax into dx:ax/sign-extend eax into edx:eax - case 0x99:dyn_cwd();break; - - case 0x9a:dyn_call_far_imm();goto finish_block; - - case 0x9c: // pushf - AcquireFlags(FMASK_TEST); - gen_call_function_I((void *)&CPU_PUSHF,decode.big_op); - dyn_check_exception(FC_RETOP); - break; - case 0x9d: // popf - gen_call_function_I((void *)&CPU_POPF,decode.big_op); - dyn_check_exception(FC_RETOP); - InvalidateFlags(); - break; - - case 0x9e:dyn_sahf();break; -// case 0x9f: LAHF missing - - // 'mov al/ax,[]' - case 0xa0: - dyn_mov_byte_al_direct(decode.big_addr ? decode_fetchd() : decode_fetchw()); - break; - case 0xa1: - dyn_mov_byte_ax_direct(decode.big_addr ? decode_fetchd() : decode_fetchw()); - break; - // 'mov [],al/ax' - case 0xa2: - dyn_mov_byte_direct_al(); - break; - case 0xa3: - dyn_mov_byte_direct_ax(decode.big_addr ? decode_fetchd() : decode_fetchw()); - break; - - -// case 0xa6 to 0xaf string operations, some missing - - // movsb/w/d - case 0xa4:dyn_string(STR_MOVSB);break; - case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break; - - // stosb/w/d - case 0xaa:dyn_string(STR_STOSB);break; - case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break; - - // lodsb/w/d - case 0xac:dyn_string(STR_LODSB);break; - case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break; - - - // 'test reg8/16/32,imm8/16/32' - case 0xa8:dyn_dop_byte_imm(DOP_TEST,DRC_REG_EAX,0);break; - case 0xa9:dyn_dop_word_imm_old(DOP_TEST,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; - - // 'mov reg8/16/32,imm8/16/32' - case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7: - dyn_mov_byte_imm(opcode&3,(opcode>>2)&1,decode_fetchb()); - break; - case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf: - dyn_mov_word_imm(opcode&7);break; - break; - - // 'shiftop []/reg8,imm8/1/cl' - case 0xc0:dyn_grp2_eb(grp2_imm);break; - case 0xd0:dyn_grp2_eb(grp2_1);break; - case 0xd2:dyn_grp2_eb(grp2_cl);break; - - // 'shiftop []/reg16/32,imm8/1/cl' - case 0xc1:dyn_grp2_ev(grp2_imm);break; - case 0xd1:dyn_grp2_ev(grp2_1);break; - case 0xd3:dyn_grp2_ev(grp2_cl);break; - - // retn [param] - case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block; - case 0xc3:dyn_ret_near(0);goto finish_block; - - // les - case 0xc4: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(DRC_SEG_ES); - break; - // lds - case 0xc5: - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; - dyn_load_seg_off_ea(DRC_SEG_DS);break; - - // 'mov []/reg8/16/32,imm8/16/32' - case 0xc6:dyn_dop_ebib_mov();break; - case 0xc7:dyn_dop_eviv_mov();break; - - case 0xc8:dyn_enter();break; - case 0xc9:dyn_leave();break; - - // retf [param] - case 0xca:dyn_ret_far(decode_fetchw());goto finish_block; - case 0xcb:dyn_ret_far(0);goto finish_block; - - // int/iret - case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block; - case 0xcf:dyn_iret();goto finish_block; - -// case 0xd4: AAM missing -// case 0xd5: AAD missing - -// case 0xd6: SALC missing -// case 0xd7: XLAT missing - - -#ifdef CPU_FPU - // floating point instructions - case 0xd8: - dyn_fpu_esc0(); - break; - case 0xd9: - dyn_fpu_esc1(); - break; - case 0xda: - dyn_fpu_esc2(); - break; - case 0xdb: - dyn_fpu_esc3(); - break; - case 0xdc: - dyn_fpu_esc4(); - break; - case 0xdd: - dyn_fpu_esc5(); - break; - case 0xde: - dyn_fpu_esc6(); - break; - case 0xdf: - dyn_fpu_esc7(); - break; -#endif - - - // loop instructions - case 0xe0:dyn_loop(LOOP_NE);goto finish_block; - case 0xe1:dyn_loop(LOOP_E);goto finish_block; - case 0xe2:dyn_loop(LOOP_NONE);goto finish_block; - case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block; - - - // 'in al/ax/eax,port_imm' - case 0xe4:dyn_read_port_byte_direct(decode_fetchb());break; - case 0xe5:dyn_read_port_word_direct(decode_fetchb());break; - // 'out port_imm,al/ax/eax' - case 0xe6:dyn_write_port_byte_direct(decode_fetchb());break; - case 0xe7:dyn_write_port_word_direct(decode_fetchb());break; - - // 'in al/ax/eax,port_dx' - case 0xec:dyn_read_port_byte();break; - case 0xed:dyn_read_port_word();break; - // 'out port_dx,al/ax/eax' - case 0xee:dyn_write_port_byte();break; - case 0xef:dyn_write_port_word();break; - - - // 'call near imm16/32' - case 0xe8: - dyn_call_near_imm(); - goto finish_block; - // 'jmp near imm16/32' - case 0xe9: - dyn_exit_link(decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); - goto finish_block; - // 'jmp far' - case 0xea: - dyn_jmp_far_imm(); - goto finish_block; - // 'jmp short imm8' - case 0xeb: - dyn_exit_link((Bit8s)decode_fetchb()); - goto finish_block; - - - // repeat prefixes - case 0xf2: - decode.rep=REP_NZ; - goto restart_prefix; - case 0xf3: - decode.rep=REP_Z; - goto restart_prefix; - - case 0xf5: //CMC - gen_call_function_raw((void*)dynrec_cmc); - break; - case 0xf8: //CLC - gen_call_function_raw((void*)dynrec_clc); - break; - case 0xf9: //STC - gen_call_function_raw((void*)dynrec_stc); - break; - - case 0xf6:dyn_grp3_eb();break; - case 0xf7:dyn_grp3_ev();break; - - case 0xfa: //CLI - gen_call_function_raw((void *)&CPU_CLI); - dyn_check_exception(FC_RETOP); - break; - case 0xfb: //STI - gen_call_function_raw((void *)&CPU_STI); - dyn_check_exception(FC_RETOP); - if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode - break; - - case 0xfc: //CLD - gen_call_function_raw((void*)dynrec_cld); - break; - case 0xfd: //STD - gen_call_function_raw((void*)dynrec_std); - break; - - case 0xfe: - if (dyn_grp4_eb()) goto finish_block; - break; - case 0xff: - switch (dyn_grp4_ev()) { - case 0: - break; - case 1: - goto core_close_block; - case 2: - goto illegalopcode; - default: - break; - } - break; - - default: -// DYN_LOG("Dynrec unhandled opcode %X",opcode); - goto illegalopcode; - } - } - // link to next block because the maximal number of opcodes has been reached - dyn_set_eip_end(); - dyn_reduce_cycles(); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); - dyn_closeblock(); - goto finish_block; -core_close_block: - dyn_reduce_cycles(); - dyn_return(BR_Normal); - dyn_closeblock(); - goto finish_block; -illegalopcode: - // some unhandled opcode has been encountered - dyn_set_eip_last(); - dyn_reduce_cycles(); - dyn_return(BR_Opcode); // tell the core what happened - dyn_closeblock(); - goto finish_block; -finish_block: - - // setup the correct end-address - decode.page.index--; - decode.active_block->page.end=(Bit16u)decode.page.index; -// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end); - - return decode.block; -} +/* + * Copyright (C) 2002-2010 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: decoder.h,v 1.8 2009-10-18 17:52:10 c2woody Exp $ */ + + +#include "decoder_basic.h" +#include "operators.h" +#include "decoder_opcodes.h" + +#include "dyn_fpu.h" + +/* + The function CreateCacheBlock translates the instruction stream + until either an unhandled instruction is found, the maximal + number of translated instructions is reached or some critical + instruction is encountered. +*/ + +static CacheBlockDynRec * CreateCacheBlock(CodePageHandlerDynRec * codepage,PhysPt start,Bitu max_opcodes) { + // initialize a load of variables + decode.code_start=start; + decode.code=start; + decode.page.code=codepage; + decode.page.index=start&4095; + decode.page.wmap=codepage->write_map; + decode.page.invmap=codepage->invalidation_map; + decode.page.first=start >> 12; + decode.active_block=decode.block=cache_openblock(); + decode.block->page.start=(Bit16u)decode.page.index; + codepage->AddCacheBlock(decode.block); + + InitFlagsOptimization(); + + // every codeblock that is run sets cache.block.running to itself + // so the block linking knows the last executed block + gen_mov_direct_ptr(&cache.block.running,(DRC_PTR_SIZE_IM)decode.block); + + // start with the cycles check + gen_mov_word_to_reg(FC_RETOP,&CPU_Cycles,true); + save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_leqzero(FC_RETOP); + save_info_dynrec[used_save_info_dynrec].type=cycle_check; + used_save_info_dynrec++; + + decode.cycles=0; + while (max_opcodes--) { + // Init prefixes + decode.big_addr=cpu.code.big; + decode.big_op=cpu.code.big; + decode.seg_prefix=0; + decode.seg_prefix_used=false; + decode.rep=REP_NONE; + decode.cycles++; + decode.op_start=decode.code; +restart_prefix: + Bitu opcode; + if (!decode.page.invmap) opcode=decode_fetchb(); + else { + // some entries in the invalidation map, see if the next + // instruction is known to be modified a lot + if (decode.page.index<4096) { + if (GCC_UNLIKELY(decode.page.invmap[decode.page.index]>=4)) goto illegalopcode; + opcode=decode_fetchb(); + } else { + // switch to the next page + opcode=decode_fetchb(); + if (GCC_UNLIKELY(decode.page.invmap && + (decode.page.invmap[decode.page.index-1]>=4))) goto illegalopcode; + } + } + switch (opcode) { + // instructions 'op reg8,reg8' and 'op [],reg8' + case 0x00:dyn_dop_ebgb(DOP_ADD);break; + case 0x08:dyn_dop_ebgb(DOP_OR);break; + case 0x10:dyn_dop_ebgb(DOP_ADC);break; + case 0x18:dyn_dop_ebgb(DOP_SBB);break; + case 0x20:dyn_dop_ebgb(DOP_AND);break; + case 0x28:dyn_dop_ebgb(DOP_SUB);break; + case 0x30:dyn_dop_ebgb(DOP_XOR);break; + case 0x38:dyn_dop_ebgb(DOP_CMP);break; + + // instructions 'op reg8,reg8' and 'op reg8,[]' + case 0x02:dyn_dop_gbeb(DOP_ADD);break; + case 0x0a:dyn_dop_gbeb(DOP_OR);break; + case 0x12:dyn_dop_gbeb(DOP_ADC);break; + case 0x1a:dyn_dop_gbeb(DOP_SBB);break; + case 0x22:dyn_dop_gbeb(DOP_AND);break; + case 0x2a:dyn_dop_gbeb(DOP_SUB);break; + case 0x32:dyn_dop_gbeb(DOP_XOR);break; + case 0x3a:dyn_dop_gbeb(DOP_CMP);break; + + // instructions 'op reg16/32,reg16/32' and 'op [],reg16/32' + case 0x01:dyn_dop_evgv(DOP_ADD);break; + case 0x09:dyn_dop_evgv(DOP_OR);break; + case 0x11:dyn_dop_evgv(DOP_ADC);break; + case 0x19:dyn_dop_evgv(DOP_SBB);break; + case 0x21:dyn_dop_evgv(DOP_AND);break; + case 0x29:dyn_dop_evgv(DOP_SUB);break; + case 0x31:dyn_dop_evgv(DOP_XOR);break; + case 0x39:dyn_dop_evgv(DOP_CMP);break; + + // instructions 'op reg16/32,reg16/32' and 'op reg16/32,[]' + case 0x03:dyn_dop_gvev(DOP_ADD);break; + case 0x0b:dyn_dop_gvev(DOP_OR);break; + case 0x13:dyn_dop_gvev(DOP_ADC);break; + case 0x1b:dyn_dop_gvev(DOP_SBB);break; + case 0x23:dyn_dop_gvev(DOP_AND);break; + case 0x2b:dyn_dop_gvev(DOP_SUB);break; + case 0x33:dyn_dop_gvev(DOP_XOR);break; + case 0x3b:dyn_dop_gvev(DOP_CMP);break; + + // instructions 'op reg8,imm8' + case 0x04:dyn_dop_byte_imm(DOP_ADD,DRC_REG_EAX,0);break; + case 0x0c:dyn_dop_byte_imm(DOP_OR,DRC_REG_EAX,0);break; + case 0x14:dyn_dop_byte_imm(DOP_ADC,DRC_REG_EAX,0);break; + case 0x1c:dyn_dop_byte_imm(DOP_SBB,DRC_REG_EAX,0);break; + case 0x24:dyn_dop_byte_imm(DOP_AND,DRC_REG_EAX,0);break; + case 0x2c:dyn_dop_byte_imm(DOP_SUB,DRC_REG_EAX,0);break; + case 0x34:dyn_dop_byte_imm(DOP_XOR,DRC_REG_EAX,0);break; + case 0x3c:dyn_dop_byte_imm(DOP_CMP,DRC_REG_EAX,0);break; + + // instructions 'op reg16/32,imm16/32' + case 0x05:dyn_dop_word_imm(DOP_ADD,DRC_REG_EAX);break; + case 0x0d:dyn_dop_word_imm_old(DOP_OR,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x15:dyn_dop_word_imm_old(DOP_ADC,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x1d:dyn_dop_word_imm_old(DOP_SBB,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x25:dyn_dop_word_imm(DOP_AND,DRC_REG_EAX);break; + case 0x2d:dyn_dop_word_imm_old(DOP_SUB,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x35:dyn_dop_word_imm_old(DOP_XOR,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + case 0x3d:dyn_dop_word_imm_old(DOP_CMP,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + + // push segment register onto stack + case 0x06:dyn_push_seg(DRC_SEG_ES);break; + case 0x0e:dyn_push_seg(DRC_SEG_CS);break; + case 0x16:dyn_push_seg(DRC_SEG_SS);break; + case 0x1e:dyn_push_seg(DRC_SEG_DS);break; + + // pop segment register from stack + case 0x07:dyn_pop_seg(DRC_SEG_ES);break; + case 0x17:dyn_pop_seg(DRC_SEG_SS);break; + case 0x1f:dyn_pop_seg(DRC_SEG_DS);break; + + // segment prefixes + case 0x26:dyn_segprefix(DRC_SEG_ES);goto restart_prefix; + case 0x2e:dyn_segprefix(DRC_SEG_CS);goto restart_prefix; + case 0x36:dyn_segprefix(DRC_SEG_SS);goto restart_prefix; + case 0x3e:dyn_segprefix(DRC_SEG_DS);goto restart_prefix; + case 0x64:dyn_segprefix(DRC_SEG_FS);goto restart_prefix; + case 0x65:dyn_segprefix(DRC_SEG_GS);goto restart_prefix; + +// case 0x27: DAA missing +// case 0x2f: DAS missing +// case 0x37: AAA missing +// case 0x3f: AAS missing + + // dual opcodes + case 0x0f: + { + Bitu dual_code=decode_fetchb(); + switch (dual_code) { + case 0x00: + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; + dyn_grp6(); + break; + case 0x01: + if (dyn_grp7()) goto finish_block; + break; +/* case 0x02: + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; + dyn_larlsl(true); + break; + case 0x03: + if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode; + dyn_larlsl(false); + break; */ + + case 0x20:dyn_mov_from_crx();break; + case 0x22:dyn_mov_to_crx();goto finish_block; + + // short conditional jumps + case 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87: + case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f: + dyn_branched_exit((BranchTypes)(dual_code&0xf), + decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); + goto finish_block; + + // conditional byte set instructions +/* case 0x90:case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: + case 0x98:case 0x99:case 0x9a:case 0x9b:case 0x9c:case 0x9d:case 0x9e:case 0x9f: + dyn_set_byte_on_condition((BranchTypes)(dual_code&0xf)); + AcquireFlags(FMASK_TEST); + break; */ + + // push/pop segment registers + case 0xa0:dyn_push_seg(DRC_SEG_FS);break; + case 0xa1:dyn_pop_seg(DRC_SEG_FS);break; + case 0xa8:dyn_push_seg(DRC_SEG_GS);break; + case 0xa9:dyn_pop_seg(DRC_SEG_GS);break; + + // double shift instructions + case 0xa4:dyn_dshift_ev_gv(true,true);break; + case 0xa5:dyn_dshift_ev_gv(true,false);break; + case 0xac:dyn_dshift_ev_gv(false,true);break; + case 0xad:dyn_dshift_ev_gv(false,false);break; + + case 0xaf:dyn_imul_gvev(0);break; + + // lfs + case 0xb4: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(DRC_SEG_FS); + break; + // lgs + case 0xb5: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(DRC_SEG_GS); + break; + + // zero-extending moves + case 0xb6:dyn_movx_ev_gb(false);break; + case 0xb7:dyn_movx_ev_gw(false);break; + + // sign-extending moves + case 0xbe:dyn_movx_ev_gb(true);break; + case 0xbf:dyn_movx_ev_gw(true);break; + + default: +// DYN_LOG("Unhandled dual opcode 0F%02X",dual_code); + goto illegalopcode; + } + break; + } + + // 'inc/dec reg16/32' + case 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47: + dyn_sop_word(SOP_INC,opcode&7); + break; + case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f: + dyn_sop_word(SOP_DEC,opcode&7); + break; + + // 'push/pop reg16/32' + case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57: + dyn_push_reg(opcode&7); + break; + case 0x58:case 0x59:case 0x5a:case 0x5b:case 0x5c:case 0x5d:case 0x5e:case 0x5f: + dyn_pop_reg(opcode&7); + break; + + case 0x60: + if (decode.big_op) gen_call_function_raw((void *)&dynrec_pusha_dword); + else gen_call_function_raw((void *)&dynrec_pusha_word); + break; + case 0x61: + if (decode.big_op) gen_call_function_raw((void *)&dynrec_popa_dword); + else gen_call_function_raw((void *)&dynrec_popa_word); + break; + +// case 0x62: BOUND missing +// case 0x61: ARPL missing + + case 0x66:decode.big_op=!cpu.code.big;goto restart_prefix; + case 0x67:decode.big_addr=!cpu.code.big;goto restart_prefix; + + // 'push imm8/16/32' + case 0x68: + dyn_push_word_imm(decode.big_op ? decode_fetchd() : decode_fetchw()); + break; + case 0x6a: + dyn_push_byte_imm((Bit8s)decode_fetchb()); + break; + + // signed multiplication + case 0x69:dyn_imul_gvev(decode.big_op ? 4 : 2);break; + case 0x6b:dyn_imul_gvev(1);break; + +// case 0x6c to 0x6f missing (ins/outs) + + // short conditional jumps + case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77: + case 0x78:case 0x79:case 0x7a:case 0x7b:case 0x7c:case 0x7d:case 0x7e:case 0x7f: + dyn_branched_exit((BranchTypes)(opcode&0xf),(Bit8s)decode_fetchb()); + goto finish_block; + + // 'op []/reg8,imm8' + case 0x80: + case 0x82:dyn_grp1_eb_ib();break; + + // 'op []/reg16/32,imm16/32' + case 0x81:dyn_grp1_ev_iv(false);break; + case 0x83:dyn_grp1_ev_iv(true);break; + + // 'test []/reg8/16/32,reg8/16/32' + case 0x84:dyn_dop_gbeb(DOP_TEST);break; + case 0x85:dyn_dop_gvev(DOP_TEST);break; + + // 'xchg reg8/16/32,[]/reg8/16/32' + case 0x86:dyn_dop_ebgb_xchg();break; + case 0x87:dyn_dop_evgv_xchg();break; + + // 'mov []/reg8/16/32,reg8/16/32' + case 0x88:dyn_dop_ebgb_mov();break; + case 0x89:dyn_dop_evgv_mov();break; + // 'mov reg8/16/32,[]/reg8/16/32' + case 0x8a:dyn_dop_gbeb_mov();break; + case 0x8b:dyn_dop_gvev_mov();break; + + // move segment register into memory or a 16bit register + case 0x8c:dyn_mov_ev_seg();break; + + // load effective address + case 0x8d:dyn_lea();break; + + // move a value from memory or a 16bit register into a segment register + case 0x8e:dyn_mov_seg_ev();break; + + // 'pop []' + case 0x8f:dyn_pop_ev();break; + + case 0x90: // nop + case 0x9b: // wait + case 0xf0: // lock + break; + + case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97: + dyn_xchg_ax(opcode&7); + break; + + // sign-extend al into ax/sign-extend ax into eax + case 0x98:dyn_cbw();break; + // sign-extend ax into dx:ax/sign-extend eax into edx:eax + case 0x99:dyn_cwd();break; + + case 0x9a:dyn_call_far_imm();goto finish_block; + + case 0x9c: // pushf + AcquireFlags(FMASK_TEST); + gen_call_function_I((void *)&CPU_PUSHF,decode.big_op); + dyn_check_exception(FC_RETOP); + break; + case 0x9d: // popf + gen_call_function_I((void *)&CPU_POPF,decode.big_op); + dyn_check_exception(FC_RETOP); + InvalidateFlags(); + break; + + case 0x9e:dyn_sahf();break; +// case 0x9f: LAHF missing + + // 'mov al/ax,[]' + case 0xa0: + dyn_mov_byte_al_direct(decode.big_addr ? decode_fetchd() : decode_fetchw()); + break; + case 0xa1: + dyn_mov_byte_ax_direct(decode.big_addr ? decode_fetchd() : decode_fetchw()); + break; + // 'mov [],al/ax' + case 0xa2: + dyn_mov_byte_direct_al(); + break; + case 0xa3: + dyn_mov_byte_direct_ax(decode.big_addr ? decode_fetchd() : decode_fetchw()); + break; + + +// case 0xa6 to 0xaf string operations, some missing + + // movsb/w/d + case 0xa4:dyn_string(STR_MOVSB);break; + case 0xa5:dyn_string(decode.big_op ? STR_MOVSD : STR_MOVSW);break; + + // stosb/w/d + case 0xaa:dyn_string(STR_STOSB);break; + case 0xab:dyn_string(decode.big_op ? STR_STOSD : STR_STOSW);break; + + // lodsb/w/d + case 0xac:dyn_string(STR_LODSB);break; + case 0xad:dyn_string(decode.big_op ? STR_LODSD : STR_LODSW);break; + + + // 'test reg8/16/32,imm8/16/32' + case 0xa8:dyn_dop_byte_imm(DOP_TEST,DRC_REG_EAX,0);break; + case 0xa9:dyn_dop_word_imm_old(DOP_TEST,DRC_REG_EAX,decode.big_op ? decode_fetchd() : decode_fetchw());break; + + // 'mov reg8/16/32,imm8/16/32' + case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7: + dyn_mov_byte_imm(opcode&3,(opcode>>2)&1,decode_fetchb()); + break; + case 0xb8:case 0xb9:case 0xba:case 0xbb:case 0xbc:case 0xbd:case 0xbe:case 0xbf: + dyn_mov_word_imm(opcode&7);break; + break; + + // 'shiftop []/reg8,imm8/1/cl' + case 0xc0:dyn_grp2_eb(grp2_imm);break; + case 0xd0:dyn_grp2_eb(grp2_1);break; + case 0xd2:dyn_grp2_eb(grp2_cl);break; + + // 'shiftop []/reg16/32,imm8/1/cl' + case 0xc1:dyn_grp2_ev(grp2_imm);break; + case 0xd1:dyn_grp2_ev(grp2_1);break; + case 0xd3:dyn_grp2_ev(grp2_cl);break; + + // retn [param] + case 0xc2:dyn_ret_near(decode_fetchw());goto finish_block; + case 0xc3:dyn_ret_near(0);goto finish_block; + + // les + case 0xc4: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(DRC_SEG_ES); + break; + // lds + case 0xc5: + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.mod==3)) goto illegalopcode; + dyn_load_seg_off_ea(DRC_SEG_DS);break; + + // 'mov []/reg8/16/32,imm8/16/32' + case 0xc6:dyn_dop_ebib_mov();break; + case 0xc7:dyn_dop_eviv_mov();break; + + case 0xc8:dyn_enter();break; + case 0xc9:dyn_leave();break; + + // retf [param] + case 0xca:dyn_ret_far(decode_fetchw());goto finish_block; + case 0xcb:dyn_ret_far(0);goto finish_block; + + // int/iret + case 0xcd:dyn_interrupt(decode_fetchb());goto finish_block; + case 0xcf:dyn_iret();goto finish_block; + +// case 0xd4: AAM missing +// case 0xd5: AAD missing + +// case 0xd6: SALC missing +// case 0xd7: XLAT missing + + +#ifdef CPU_FPU + // floating point instructions + case 0xd8: + dyn_fpu_esc0(); + break; + case 0xd9: + dyn_fpu_esc1(); + break; + case 0xda: + dyn_fpu_esc2(); + break; + case 0xdb: + dyn_fpu_esc3(); + break; + case 0xdc: + dyn_fpu_esc4(); + break; + case 0xdd: + dyn_fpu_esc5(); + break; + case 0xde: + dyn_fpu_esc6(); + break; + case 0xdf: + dyn_fpu_esc7(); + break; +#endif + + + // loop instructions + case 0xe0:dyn_loop(LOOP_NE);goto finish_block; + case 0xe1:dyn_loop(LOOP_E);goto finish_block; + case 0xe2:dyn_loop(LOOP_NONE);goto finish_block; + case 0xe3:dyn_loop(LOOP_JCXZ);goto finish_block; + + + // 'in al/ax/eax,port_imm' + case 0xe4:dyn_read_port_byte_direct(decode_fetchb());break; + case 0xe5:dyn_read_port_word_direct(decode_fetchb());break; + // 'out port_imm,al/ax/eax' + case 0xe6:dyn_write_port_byte_direct(decode_fetchb());break; + case 0xe7:dyn_write_port_word_direct(decode_fetchb());break; + + // 'in al/ax/eax,port_dx' + case 0xec:dyn_read_port_byte();break; + case 0xed:dyn_read_port_word();break; + // 'out port_dx,al/ax/eax' + case 0xee:dyn_write_port_byte();break; + case 0xef:dyn_write_port_word();break; + + + // 'call near imm16/32' + case 0xe8: + dyn_call_near_imm(); + goto finish_block; + // 'jmp near imm16/32' + case 0xe9: + dyn_exit_link(decode.big_op ? (Bit32s)decode_fetchd() : (Bit16s)decode_fetchw()); + goto finish_block; + // 'jmp far' + case 0xea: + dyn_jmp_far_imm(); + goto finish_block; + // 'jmp short imm8' + case 0xeb: + dyn_exit_link((Bit8s)decode_fetchb()); + goto finish_block; + + + // repeat prefixes + case 0xf2: + decode.rep=REP_NZ; + goto restart_prefix; + case 0xf3: + decode.rep=REP_Z; + goto restart_prefix; + + case 0xf5: //CMC + gen_call_function_raw((void*)dynrec_cmc); + break; + case 0xf8: //CLC + gen_call_function_raw((void*)dynrec_clc); + break; + case 0xf9: //STC + gen_call_function_raw((void*)dynrec_stc); + break; + + case 0xf6:dyn_grp3_eb();break; + case 0xf7:dyn_grp3_ev();break; + + case 0xfa: //CLI + gen_call_function_raw((void *)&CPU_CLI); + dyn_check_exception(FC_RETOP); + break; + case 0xfb: //STI + gen_call_function_raw((void *)&CPU_STI); + dyn_check_exception(FC_RETOP); + if (max_opcodes<=0) max_opcodes=1; //Allow 1 extra opcode + break; + + case 0xfc: //CLD + gen_call_function_raw((void*)dynrec_cld); + break; + case 0xfd: //STD + gen_call_function_raw((void*)dynrec_std); + break; + + case 0xfe: + if (dyn_grp4_eb()) goto finish_block; + break; + case 0xff: + switch (dyn_grp4_ev()) { + case 0: + break; + case 1: + goto core_close_block; + case 2: + goto illegalopcode; + default: + break; + } + break; + + default: +// DYN_LOG("Dynrec unhandled opcode %X",opcode); + goto illegalopcode; + } + } + // link to next block because the maximal number of opcodes has been reached + dyn_set_eip_end(); + dyn_reduce_cycles(); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); + dyn_closeblock(); + goto finish_block; +core_close_block: + dyn_reduce_cycles(); + dyn_return(BR_Normal); + dyn_closeblock(); + goto finish_block; +illegalopcode: + // some unhandled opcode has been encountered + dyn_set_eip_last(); + dyn_reduce_cycles(); + dyn_return(BR_Opcode); // tell the core what happened + dyn_closeblock(); + goto finish_block; +finish_block: + + // setup the correct end-address + decode.page.index--; + decode.active_block->page.end=(Bit16u)decode.page.index; +// LOG_MSG("Created block size %d start %d end %d",decode.block->cache.size,decode.block->page.start,decode.block->page.end); + + return decode.block; +} diff --git a/src/cpu/core_dynrec/decoder_basic.h b/src/cpu/core_dynrec/decoder_basic.h index 4da8bbe..ad3b035 100644 --- a/src/cpu/core_dynrec/decoder_basic.h +++ b/src/cpu/core_dynrec/decoder_basic.h @@ -1,1267 +1,1267 @@ -/* - * Copyright (C) 2002-2009 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: decoder_basic.h,v 1.16 2009/10/08 20:01:31 c2woody Exp $ */ - - -/* - This file provides some definitions and basic level functions - that use code generating functions from risc_?.h - Important is the function call generation including parameter - loading, the effective address calculation and the memory - access functions. -*/ - - -// instructions that use one operand -enum SingleOps { - SOP_INC,SOP_DEC, - SOP_NOT,SOP_NEG -}; - -// instructions that use two operand -enum DualOps { - DOP_ADD,DOP_ADC, - DOP_SUB,DOP_SBB, - DOP_CMP,DOP_XOR, - DOP_AND,DOP_OR, - DOP_TEST, - DOP_MOV, - DOP_XCHG -}; - -// shift and rotate functions -enum ShiftOps { - SHIFT_ROL,SHIFT_ROR, - SHIFT_RCL,SHIFT_RCR, - SHIFT_SHL,SHIFT_SHR, - SHIFT_SAL,SHIFT_SAR -}; - -// branch conditions -enum BranchTypes { - BR_O,BR_NO,BR_B,BR_NB, - BR_Z,BR_NZ,BR_BE,BR_NBE, - BR_S,BR_NS,BR_P,BR_NP, - BR_L,BR_NL,BR_LE,BR_NLE -}; - -// string instructions -enum StringOps { - STR_OUTSB=0,STR_OUTSW,STR_OUTSD, - STR_INSB=4,STR_INSW,STR_INSD, - STR_MOVSB=8,STR_MOVSW,STR_MOVSD, - STR_LODSB=12,STR_LODSW,STR_LODSD, - STR_STOSB=16,STR_STOSW,STR_STOSD, - STR_SCASB=20,STR_SCASW,STR_SCASD, - STR_CMPSB=24,STR_CMPSW,STR_CMPSD -}; - -// repeat prefix type (for string operations) -enum REP_Type { - REP_NONE=0,REP_NZ,REP_Z -}; - -// loop type -enum LoopTypes { - LOOP_NONE,LOOP_NE,LOOP_E,LOOP_JCXZ -}; - -// rotate operand type -enum grp2_types { - grp2_1,grp2_imm,grp2_cl -}; - -// opcode mapping for group1 instructions -static DualOps grp1_table[8]={ - DOP_ADD,DOP_OR,DOP_ADC,DOP_SBB,DOP_AND,DOP_SUB,DOP_XOR,DOP_CMP -}; - - -// decoding information used during translation of a code block -static struct DynDecode { - PhysPt code; // pointer to next byte in the instruction stream - PhysPt code_start; // pointer to the start of the current code block - PhysPt op_start; // pointer to the start of the current instruction - bool big_op; // operand modifier - bool big_addr; // address modifier - REP_Type rep; // current repeat prefix - Bitu cycles; // number cycles used by currently translated code - bool seg_prefix_used; // segment overridden - Bit8u seg_prefix; // segment prefix (if seg_prefix_used==true) - - // block that contains the first instruction translated - CacheBlockDynRec * block; - // block that contains the current byte of the instruction stream - CacheBlockDynRec * active_block; - - // the active page (containing the current byte of the instruction stream) - struct { - CodePageHandlerDynRec * code; - Bitu index; // index to the current byte of the instruction stream - Bit8u * wmap; // write map that indicates code presence for every byte of this page - Bit8u * invmap; // invalidation map - Bitu first; // page number - } page; - - // modrm state of the current instruction (if used) - struct { - Bitu val; - Bitu mod; - Bitu rm; - Bitu reg; - } modrm; -} decode; - - -static bool MakeCodePage(Bitu lin_addr,CodePageHandlerDynRec * &cph) { - Bit8u rdval; - //Ensure page contains memory: - if (GCC_UNLIKELY(mem_readb_checked(lin_addr,&rdval))) return true; - - PageHandler * handler=get_tlb_readhandler(lin_addr); - if (handler->flags & PFLAG_HASCODE) { - // this is a codepage handler, and the one that we're looking for - cph=(CodePageHandlerDynRec *)handler; - return false; - } - if (handler->flags & PFLAG_NOCODE) { - if (PAGING_ForcePageInit(lin_addr)) { - handler=get_tlb_readhandler(lin_addr); - if (handler->flags & PFLAG_HASCODE) { - cph=(CodePageHandlerDynRec *)handler; - return false; - } - } - if (handler->flags & PFLAG_NOCODE) { - LOG_MSG("DYNREC:Can't run code in this page"); - cph=0; - return false; - } - } - Bitu lin_page=lin_addr>>12; - Bitu phys_page=lin_page; - // find the physical page that the linear page is mapped to - if (!PAGING_MakePhysPage(phys_page)) { - LOG_MSG("DYNREC:Can't find physpage"); - cph=0; - return false; - } - // find a free CodePage - if (!cache.free_pages) { - if (cache.used_pages!=decode.page.code) cache.used_pages->ClearRelease(); - else { - // try another page to avoid clearing our source-crosspage - if ((cache.used_pages->next) && (cache.used_pages->next!=decode.page.code)) - cache.used_pages->next->ClearRelease(); - else { - LOG_MSG("DYNREC:Invalid cache links"); - cache.used_pages->ClearRelease(); - } - } - } - CodePageHandlerDynRec * cpagehandler=cache.free_pages; - cache.free_pages=cache.free_pages->next; - - // adjust previous and next page pointer - cpagehandler->prev=cache.last_page; - cpagehandler->next=0; - if (cache.last_page) cache.last_page->next=cpagehandler; - cache.last_page=cpagehandler; - if (!cache.used_pages) cache.used_pages=cpagehandler; - - // initialize the code page handler and add the handler to the memory page - cpagehandler->SetupAt(phys_page,handler); - MEM_SetPageHandler(phys_page,1,cpagehandler); - PAGING_UnlinkPages(lin_page,1); - cph=cpagehandler; - return false; -} - -static void decode_advancepage(void) { - // Advance to the next page - decode.active_block->page.end=4095; - // trigger possible page fault here - decode.page.first++; - Bitu faddr=decode.page.first << 12; - mem_readb(faddr); - MakeCodePage(faddr,decode.page.code); - CacheBlockDynRec * newblock=cache_getblock(); - decode.active_block->crossblock=newblock; - newblock->crossblock=decode.active_block; - decode.active_block=newblock; - decode.active_block->page.start=0; - decode.page.code->AddCrossBlock(decode.active_block); - decode.page.wmap=decode.page.code->write_map; - decode.page.invmap=decode.page.code->invalidation_map; - decode.page.index=0; -} - -// fetch the next byte of the instruction stream -static Bit8u decode_fetchb(void) { - if (GCC_UNLIKELY(decode.page.index>=4096)) { - decode_advancepage(); - } - decode.page.wmap[decode.page.index]+=0x01; - decode.page.index++; - decode.code+=1; - return mem_readb(decode.code-1); -} -// fetch the next word of the instruction stream -static Bit16u decode_fetchw(void) { - if (GCC_UNLIKELY(decode.page.index>=4095)) { - Bit16u val=decode_fetchb(); - val|=decode_fetchb() << 8; - return val; - } - *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101; - decode.code+=2;decode.page.index+=2; - return mem_readw(decode.code-2); -} -// fetch the next dword of the instruction stream -static Bit32u decode_fetchd(void) { - if (GCC_UNLIKELY(decode.page.index>=4093)) { - Bit32u val=decode_fetchb(); - val|=decode_fetchb() << 8; - val|=decode_fetchb() << 16; - val|=decode_fetchb() << 24; - return val; - /* Advance to the next page */ - } - *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101; - decode.code+=4;decode.page.index+=4; - return mem_readd(decode.code-4); -} - -#define START_WMMEM 64 - -// adjust writemap mask to care for map holes due to special -// codefetch functions -static void INLINE decode_increase_wmapmask(Bitu size) { - Bitu mapidx; - CacheBlockDynRec* activecb=decode.active_block; - if (GCC_UNLIKELY(!activecb->cache.wmapmask)) { - // no mask memory yet allocated, start with a small buffer - activecb->cache.wmapmask=(Bit8u*)malloc(START_WMMEM); - memset(activecb->cache.wmapmask,0,START_WMMEM); - activecb->cache.maskstart=decode.page.index; // start of buffer is current code position - activecb->cache.masklen=START_WMMEM; - mapidx=0; - } else { - mapidx=decode.page.index-activecb->cache.maskstart; - if (GCC_UNLIKELY(mapidx+size>=activecb->cache.masklen)) { - // mask buffer too small, increase - Bitu newmasklen=activecb->cache.masklen*4; - if (newmasklencache.wmapmask,activecb->cache.masklen); - free(activecb->cache.wmapmask); - activecb->cache.wmapmask=tempmem; - activecb->cache.masklen=newmasklen; - } - } - // update mask entries - switch (size) { - case 1 : activecb->cache.wmapmask[mapidx]+=0x01; break; - case 2 : (*(Bit16u*)&activecb->cache.wmapmask[mapidx])+=0x0101; break; - case 4 : (*(Bit32u*)&activecb->cache.wmapmask[mapidx])+=0x01010101; break; - } -} - -// fetch a byte, val points to the code location if possible, -// otherwise val contains the current value read from the position -static bool decode_fetchb_imm(Bitu & val) { - if (GCC_UNLIKELY(decode.page.index>=4096)) { - decode_advancepage(); - } - // see if position is directly accessible - if (decode.page.invmap != NULL) { - if (decode.page.invmap[decode.page.index] == 0) { - // position not yet modified - val=(Bit32u)decode_fetchb(); - return false; - } - - HostPt tlb_addr=get_tlb_read(decode.code); - if (tlb_addr) { - val=(Bitu)(tlb_addr+decode.code); - decode_increase_wmapmask(1); - decode.code++; - decode.page.index++; - return true; - } - } - // first time decoding or not directly accessible, just fetch the value - val=(Bit32u)decode_fetchb(); - return false; -} - -// fetch a word, val points to the code location if possible, -// otherwise val contains the current value read from the position -static bool decode_fetchw_imm(Bitu & val) { - if (decode.page.index<4095) { - if (decode.page.invmap != NULL) { - if ((decode.page.invmap[decode.page.index] == 0) && - (decode.page.invmap[decode.page.index + 1] == 0)) { - // position not yet modified - val=decode_fetchw(); - return false; - } - - HostPt tlb_addr=get_tlb_read(decode.code); - // see if position is directly accessible - if (tlb_addr) { - val=(Bitu)(tlb_addr+decode.code); - decode_increase_wmapmask(2); - decode.code+=2; - decode.page.index+=2; - return true; - } - } - } - // first time decoding or not directly accessible, just fetch the value - val=decode_fetchw(); - return false; -} - -// fetch a dword, val points to the code location if possible, -// otherwise val contains the current value read from the position -static bool decode_fetchd_imm(Bitu & val) { - if (decode.page.index<4093) { - if (decode.page.invmap != NULL) { - if ((decode.page.invmap[decode.page.index] == 0) && - (decode.page.invmap[decode.page.index + 1] == 0) && - (decode.page.invmap[decode.page.index + 2] == 0) && - (decode.page.invmap[decode.page.index + 3] == 0)) { - // position not yet modified - val=decode_fetchd(); - return false; - } - - HostPt tlb_addr=get_tlb_read(decode.code); - // see if position is directly accessible - if (tlb_addr) { - val=(Bitu)(tlb_addr+decode.code); - decode_increase_wmapmask(4); - decode.code+=4; - decode.page.index+=4; - return true; - } - } - } - // first time decoding or not directly accessible, just fetch the value - val=decode_fetchd(); - return false; -} - - -// modrm decoding helper -static void INLINE dyn_get_modrm(void) { - decode.modrm.val=decode_fetchb(); - decode.modrm.mod=(decode.modrm.val >> 6) & 3; - decode.modrm.reg=(decode.modrm.val >> 3) & 7; - decode.modrm.rm=(decode.modrm.val & 7); -} - - -#ifdef DRC_USE_SEGS_ADDR - -#define MOV_SEG_VAL_TO_HOST_REG(host_reg, seg_index) gen_mov_seg16_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_VAL(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs)) - -#define MOV_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_mov_seg32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_PHYS(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs)) -#define ADD_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_add_seg32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_PHYS(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs)) - -#else - -#define MOV_SEG_VAL_TO_HOST_REG(host_reg, seg_index) gen_mov_word_to_reg(host_reg,DRCD_SEG_VAL(seg_index),false) - -#define MOV_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_mov_word_to_reg(host_reg,DRCD_SEG_PHYS(seg_index),true) -#define ADD_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_add(host_reg,DRCD_SEG_PHYS(seg_index)) - -#endif - - -#ifdef DRC_USE_REGS_ADDR - -#define MOV_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_mov_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_VAL(reg_index)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define ADD_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_add_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_VAL(reg_index)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) - -#define MOV_REG_WORD16_TO_HOST_REG(host_reg, reg_index) gen_mov_regval16_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,false)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define MOV_REG_WORD32_TO_HOST_REG(host_reg, reg_index) gen_mov_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,true)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define MOV_REG_WORD_TO_HOST_REG(host_reg, reg_index, dword) gen_mov_regword_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,dword)) - (DRC_PTR_SIZE_IM)(&cpu_regs), dword) - -#define MOV_REG_WORD16_FROM_HOST_REG(host_reg, reg_index) gen_mov_regval16_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,false)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define MOV_REG_WORD32_FROM_HOST_REG(host_reg, reg_index) gen_mov_regval32_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,true)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define MOV_REG_WORD_FROM_HOST_REG(host_reg, reg_index, dword) gen_mov_regword_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,dword)) - (DRC_PTR_SIZE_IM)(&cpu_regs), dword) - -#define MOV_REG_BYTE_TO_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_regbyte_to_reg_low(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(host_reg, reg_index, high_byte) gen_mov_regbyte_to_reg_low_canuseword(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) -#define MOV_REG_BYTE_FROM_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_regbyte_from_reg_low(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) - -#else - -#define MOV_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_VAL(reg_index),true) -#define ADD_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_add(host_reg,DRCD_REG_VAL(reg_index)) - -#define MOV_REG_WORD16_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,false),false) -#define MOV_REG_WORD32_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,true),true) -#define MOV_REG_WORD_TO_HOST_REG(host_reg, reg_index, dword) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,dword),dword) - -#define MOV_REG_WORD16_FROM_HOST_REG(host_reg, reg_index) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,false),false) -#define MOV_REG_WORD32_FROM_HOST_REG(host_reg, reg_index) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,true),true) -#define MOV_REG_WORD_FROM_HOST_REG(host_reg, reg_index, dword) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,dword),dword) - -#define MOV_REG_BYTE_TO_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_byte_to_reg_low(host_reg,DRCD_REG_BYTE(reg_index,high_byte)) -#define MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(host_reg, reg_index, high_byte) gen_mov_byte_to_reg_low_canuseword(host_reg,DRCD_REG_BYTE(reg_index,high_byte)) -#define MOV_REG_BYTE_FROM_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_byte_from_reg_low(host_reg,DRCD_REG_BYTE(reg_index,high_byte)) - -#endif - - -#define DYN_LEA_MEM_MEM(ea_reg, op1, op2, scale, imm) dyn_lea_mem_mem(ea_reg,op1,op2,scale,imm) - -#if defined(DRC_USE_REGS_ADDR) && defined(DRC_USE_SEGS_ADDR) - -#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_segphys_regval(ea_reg,op1_index,op2_index,scale,imm) -#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_regval_regval(ea_reg,op1_index,op2_index,scale,imm) -#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,op1,op2_index,scale,imm) - -#elif defined(DRC_USE_REGS_ADDR) - -#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,DRCD_SEG_PHYS(op1_index),op2_index,scale,imm) -#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_regval_regval(ea_reg,op1_index,op2_index,scale,imm) -#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,op1,op2_index,scale,imm) - -#elif defined(DRC_USE_SEGS_ADDR) - -#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_segphys_mem(ea_reg,op1_index,DRCD_REG_VAL(op2_index),scale,imm) -#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_REG_VAL(op1_index),DRCD_REG_VAL(op2_index),scale,imm) -#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,op1,DRCD_REG_VAL(op2_index),scale,imm) - -#else - -#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_SEG_PHYS(op1_index),DRCD_REG_VAL(op2_index),scale,imm) -#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_REG_VAL(op1_index),DRCD_REG_VAL(op2_index),scale,imm) -#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,op1,DRCD_REG_VAL(op2_index),scale,imm) - -#endif - - - -// adjust CPU_Cycles value -static void dyn_reduce_cycles(void) { - if (!decode.cycles) decode.cycles++; - gen_sub_direct_word(&CPU_Cycles,decode.cycles,true); -} - - -// set reg to the start of the next instruction -// set reg_eip to the start of the current instruction -static INLINE void dyn_set_eip_last_end(HostReg reg) { - gen_mov_word_to_reg(reg,®_eip,true); - gen_add_imm(reg,(Bit32u)(decode.code-decode.code_start)); - gen_add_direct_word(®_eip,decode.op_start-decode.code_start,decode.big_op); -} - -// set reg_eip to the start of the current instruction -static INLINE void dyn_set_eip_last(void) { - gen_add_direct_word(®_eip,decode.op_start-decode.code_start,cpu.code.big); -} - -// set reg_eip to the start of the next instruction -static INLINE void dyn_set_eip_end(void) { - gen_add_direct_word(®_eip,decode.code-decode.code_start,cpu.code.big); -} - -// set reg_eip to the start of the next instruction plus an offset (imm) -static INLINE void dyn_set_eip_end(HostReg reg,Bit32u imm=0) { - gen_mov_word_to_reg(reg,®_eip,decode.big_op); - gen_add_imm(reg,(Bit32u)(decode.code-decode.code_start+imm)); - if (!decode.big_op) gen_extend_word(false,reg); -} - - - -// the following functions generate function calls -// parameters are loaded by generating code using gen_load_param_ which -// is architecture dependent -// R=host register; I=32bit immediate value; A=address value; m=memory - -static DRC_PTR_SIZE_IM INLINE gen_call_function_R(void * func,Bitu op) { - gen_load_param_reg(op,0); - return gen_call_function_setup(func, 1); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_R3(void * func,Bitu op) { - gen_load_param_reg(op,2); - return gen_call_function_setup(func, 3, true); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_RI(void * func,Bitu op1,Bitu op2) { - gen_load_param_imm(op2,1); - gen_load_param_reg(op1,0); - return gen_call_function_setup(func, 2); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_RA(void * func,Bitu op1,DRC_PTR_SIZE_IM op2) { - gen_load_param_addr(op2,1); - gen_load_param_reg(op1,0); - return gen_call_function_setup(func, 2); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_RR(void * func,Bitu op1,Bitu op2) { - gen_load_param_reg(op2,1); - gen_load_param_reg(op1,0); - return gen_call_function_setup(func, 2); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_IR(void * func,Bitu op1,Bitu op2) { - gen_load_param_reg(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 2); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_I(void * func,Bitu op) { - gen_load_param_imm(op,0); - return gen_call_function_setup(func, 1); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_II(void * func,Bitu op1,Bitu op2) { - gen_load_param_imm(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 2); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_III(void * func,Bitu op1,Bitu op2,Bitu op3) { - gen_load_param_imm(op3,2); - gen_load_param_imm(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 3); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_IA(void * func,Bitu op1,DRC_PTR_SIZE_IM op2) { - gen_load_param_addr(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 2); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_IIR(void * func,Bitu op1,Bitu op2,Bitu op3) { - gen_load_param_reg(op3,2); - gen_load_param_imm(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 3); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_IIIR(void * func,Bitu op1,Bitu op2,Bitu op3,Bitu op4) { - gen_load_param_reg(op4,3); - gen_load_param_imm(op3,2); - gen_load_param_imm(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 4); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_IRRR(void * func,Bitu op1,Bitu op2,Bitu op3,Bitu op4) { - gen_load_param_reg(op4,3); - gen_load_param_reg(op3,2); - gen_load_param_reg(op2,1); - gen_load_param_imm(op1,0); - return gen_call_function_setup(func, 4); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_m(void * func,Bitu op) { - gen_load_param_mem(op,2); - return gen_call_function_setup(func, 3, true); -} - -static DRC_PTR_SIZE_IM INLINE gen_call_function_mm(void * func,Bitu op1,Bitu op2) { - gen_load_param_mem(op2,3); - gen_load_param_mem(op1,2); - return gen_call_function_setup(func, 4, true); -} - - - -enum save_info_type {db_exception, cycle_check, string_break}; - - -// function that is called on exceptions -static BlockReturn DynRunException(Bit32u eip_add,Bit32u cycle_sub) { - 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; -} - - -// array with information about code that is generated at the -// end of a cache block because it is rarely reached (like exceptions) -static struct { - save_info_type type; - DRC_PTR_SIZE_IM branch_pos; - Bit32u eip_change; - Bitu cycles; -} save_info_dynrec[512]; - -Bitu used_save_info_dynrec=0; - - -// return from current block, with returncode -static void dyn_return(BlockReturn retcode,bool ret_exception=false) { - if (!ret_exception) { - gen_mov_dword_to_reg_imm(FC_RETOP,retcode); - } - gen_return_function(); -} - -static void dyn_run_code(void) { - gen_run_code(); - gen_return_function(); -} - -// fill in code at the end of the block that contains rarely-executed code -// which is executed conditionally (like exceptions) -static void dyn_fill_blocks(void) { - for (Bitu sct=0; sctcache.start,decode.block->cache.size); -} - - -// add a check that can branch to the exception handling -static void dyn_check_exception(HostReg reg) { - save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_nonzero(reg,false); - if (!decode.cycles) decode.cycles++; - save_info_dynrec[used_save_info_dynrec].cycles=decode.cycles; - // in case of an exception eip will point to the start of the current instruction - save_info_dynrec[used_save_info_dynrec].eip_change=decode.op_start-decode.code_start; - if (!cpu.code.big) save_info_dynrec[used_save_info_dynrec].eip_change&=0xffff; - save_info_dynrec[used_save_info_dynrec].type=db_exception; - used_save_info_dynrec++; -} - - - -bool DRC_CALL_CONV mem_readb_checked_drc(PhysPt address) DRC_FC; -bool DRC_CALL_CONV mem_readb_checked_drc(PhysPt address) { - HostPt tlb_addr=get_tlb_read(address); - if (tlb_addr) { - *((Bit8u*)(&core_dynrec.readdata))=host_readb(tlb_addr+address); - return false; - } else { - return get_tlb_readhandler(address)->readb_checked(address, (Bit8u*)(&core_dynrec.readdata)); - } -} - -bool DRC_CALL_CONV mem_writeb_checked_drc(PhysPt address,Bit8u val) DRC_FC; -bool DRC_CALL_CONV mem_writeb_checked_drc(PhysPt address,Bit8u val) { - HostPt tlb_addr=get_tlb_write(address); - if (tlb_addr) { - host_writeb(tlb_addr+address,val); - return false; - } else return get_tlb_writehandler(address)->writeb_checked(address,val); -} - -bool DRC_CALL_CONV mem_readw_checked_drc(PhysPt address) DRC_FC; -bool DRC_CALL_CONV mem_readw_checked_drc(PhysPt address) { - if ((address & 0xfff)<0xfff) { - HostPt tlb_addr=get_tlb_read(address); - if (tlb_addr) { - *((Bit16u*)(&core_dynrec.readdata))=host_readw(tlb_addr+address); - return false; - } else return get_tlb_readhandler(address)->readw_checked(address, (Bit16u*)(&core_dynrec.readdata)); - } else return mem_unalignedreadw_checked(address, ((Bit16u*)(&core_dynrec.readdata))); -} - -bool DRC_CALL_CONV mem_readd_checked_drc(PhysPt address) DRC_FC; -bool DRC_CALL_CONV mem_readd_checked_drc(PhysPt address) { - if ((address & 0xfff)<0xffd) { - HostPt tlb_addr=get_tlb_read(address); - if (tlb_addr) { - *((Bit32u*)(&core_dynrec.readdata))=host_readd(tlb_addr+address); - return false; - } else return get_tlb_readhandler(address)->readd_checked(address, (Bit32u*)(&core_dynrec.readdata)); - } else return mem_unalignedreadd_checked(address, ((Bit32u*)(&core_dynrec.readdata))); -} - -bool DRC_CALL_CONV mem_writew_checked_drc(PhysPt address,Bit16u val) DRC_FC; -bool DRC_CALL_CONV mem_writew_checked_drc(PhysPt address,Bit16u val) { - if ((address & 0xfff)<0xfff) { - HostPt tlb_addr=get_tlb_write(address); - if (tlb_addr) { - host_writew(tlb_addr+address,val); - return false; - } else return get_tlb_writehandler(address)->writew_checked(address,val); - } else return mem_unalignedwritew_checked(address,val); -} - -bool DRC_CALL_CONV mem_writed_checked_drc(PhysPt address,Bit32u val) DRC_FC; -bool DRC_CALL_CONV mem_writed_checked_drc(PhysPt address,Bit32u val) { - if ((address & 0xfff)<0xffd) { - HostPt tlb_addr=get_tlb_write(address); - if (tlb_addr) { - host_writed(tlb_addr+address,val); - return false; - } else return get_tlb_writehandler(address)->writed_checked(address,val); - } else return mem_unalignedwrited_checked(address,val); -} - - -// functions that enable access to the memory - -// read a byte from a given address and store it in reg_dst -static void dyn_read_byte(HostReg reg_addr,HostReg reg_dst) { - gen_mov_regs(FC_OP1,reg_addr); - gen_call_function_raw((void *)&mem_readb_checked_drc); - dyn_check_exception(FC_RETOP); - gen_mov_byte_to_reg_low(reg_dst,&core_dynrec.readdata); -} -static void dyn_read_byte_canuseword(HostReg reg_addr,HostReg reg_dst) { - gen_mov_regs(FC_OP1,reg_addr); - gen_call_function_raw((void *)&mem_readb_checked_drc); - dyn_check_exception(FC_RETOP); - gen_mov_byte_to_reg_low_canuseword(reg_dst,&core_dynrec.readdata); -} - -// write a byte from reg_val into the memory given by the address -static void dyn_write_byte(HostReg reg_addr,HostReg reg_val) { - gen_mov_regs(FC_OP2,reg_val); - gen_mov_regs(FC_OP1,reg_addr); - gen_call_function_raw((void *)&mem_writeb_checked_drc); - dyn_check_exception(FC_RETOP); -} - -// read a 32bit (dword=true) or 16bit (dword=false) value -// from a given address and store it in reg_dst -static void dyn_read_word(HostReg reg_addr,HostReg reg_dst,bool dword) { - gen_mov_regs(FC_OP1,reg_addr); - if (dword) gen_call_function_raw((void *)&mem_readd_checked_drc); - else gen_call_function_raw((void *)&mem_readw_checked_drc); - dyn_check_exception(FC_RETOP); - gen_mov_word_to_reg(reg_dst,&core_dynrec.readdata,dword); -} - -// write a 32bit (dword=true) or 16bit (dword=false) value -// from reg_val into the memory given by the address -static void dyn_write_word(HostReg reg_addr,HostReg reg_val,bool dword) { -// if (!dword) gen_extend_word(false,reg_val); - gen_mov_regs(FC_OP2,reg_val); - gen_mov_regs(FC_OP1,reg_addr); - if (dword) gen_call_function_raw((void *)&mem_writed_checked_drc); - else gen_call_function_raw((void *)&mem_writew_checked_drc); - dyn_check_exception(FC_RETOP); -} - - - -// effective address calculation helper, op2 has to be present! -// loads op1 into ea_reg and adds the scaled op2 and the immediate to it -static void dyn_lea_mem_mem(HostReg ea_reg,void* op1,void* op2,Bitu scale,Bits imm) { - if (scale || imm) { - if (op1!=NULL) { - gen_mov_word_to_reg(ea_reg,op1,true); - gen_mov_word_to_reg(TEMP_REG_DRC,op2,true); - - gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); - } else { - gen_mov_word_to_reg(ea_reg,op2,true); - gen_lea(ea_reg,scale,imm); - } - } else { - gen_mov_word_to_reg(ea_reg,op2,true); - if (op1!=NULL) gen_add(ea_reg,op1); - } -} - -#ifdef DRC_USE_REGS_ADDR -// effective address calculation helper -// loads op1 into ea_reg and adds the scaled op2 and the immediate to it -// op1 is cpu_regs[op1_index], op2 is cpu_regs[op2_index] -static void dyn_lea_regval_regval(HostReg ea_reg,Bitu op1_index,Bitu op2_index,Bitu scale,Bits imm) { - if (scale || imm) { - MOV_REG_VAL_TO_HOST_REG(ea_reg,op1_index); - MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index); - - gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); - } else { - MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); - ADD_REG_VAL_TO_HOST_REG(ea_reg,op1_index); - } -} - -// effective address calculation helper -// loads op1 into ea_reg and adds the scaled op2 and the immediate to it -// op2 is cpu_regs[op2_index] -static void dyn_lea_mem_regval(HostReg ea_reg,void* op1,Bitu op2_index,Bitu scale,Bits imm) { - if (scale || imm) { - if (op1!=NULL) { - gen_mov_word_to_reg(ea_reg,op1,true); - MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index); - - gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); - } else { - MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); - gen_lea(ea_reg,scale,imm); - } - } else { - MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); - if (op1!=NULL) gen_add(ea_reg,op1); - } -} -#endif - -#ifdef DRC_USE_SEGS_ADDR -#ifdef DRC_USE_REGS_ADDR -// effective address calculation helper -// loads op1 into ea_reg and adds the scaled op2 and the immediate to it -// op1 is Segs[op1_index], op2 is cpu_regs[op2_index] -static void dyn_lea_segphys_regval(HostReg ea_reg,Bitu op1_index,Bitu op2_index,Bitu scale,Bits imm) { - if (scale || imm) { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); - MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index); - - gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); - } else { - MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); - ADD_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); - } -} - -#else - -// effective address calculation helper, op2 has to be present! -// loads op1 into ea_reg and adds the scaled op2 and the immediate to it -// op1 is Segs[op1_index] -static void dyn_lea_segphys_mem(HostReg ea_reg,Bitu op1_index,void* op2,Bitu scale,Bits imm) { - if (scale || imm) { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); - gen_mov_word_to_reg(TEMP_REG_DRC,op2,true); - - gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); - } else { - gen_mov_word_to_reg(ea_reg,op2,true); - ADD_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); - } -} -#endif -#endif - -// calculate the effective address and store it in ea_reg -static void dyn_fill_ea(HostReg ea_reg,bool addseg=true) { - Bit8u seg_base=DRC_SEG_DS; - if (!decode.big_addr) { - Bits imm; - switch (decode.modrm.mod) { - case 0:imm=0;break; - case 1:imm=(Bit8s)decode_fetchb();break; - case 2:imm=(Bit16s)decode_fetchw();break; - } - switch (decode.modrm.rm) { - case 0:// BX+SI - DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBX,DRC_REG_ESI,0,imm); - break; - case 1:// BX+DI - DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBX,DRC_REG_EDI,0,imm); - break; - case 2:// BP+SI - DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBP,DRC_REG_ESI,0,imm); - seg_base=DRC_SEG_SS; - break; - case 3:// BP+DI - DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBP,DRC_REG_EDI,0,imm); - seg_base=DRC_SEG_SS; - break; - case 4:// SI - MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_ESI); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - break; - case 5:// DI - MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EDI); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - break; - case 6:// imm/BP - if (!decode.modrm.mod) { - imm=decode_fetchw(); - gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm); - goto skip_extend_word; - } else { - MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EBP); - gen_add_imm(ea_reg,(Bit32u)imm); - seg_base=DRC_SEG_SS; - } - break; - case 7: // BX - MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EBX); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - break; - } - // zero out the high 16bit so ea_reg can be used as full register - gen_extend_word(false,ea_reg); -skip_extend_word: - if (addseg) { - // add the physical segment value if requested - ADD_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - } - } else { - Bits imm=0; - Bit8u base_reg; - Bit8u scaled_reg; - Bitu scale=0; - switch (decode.modrm.rm) { - case 0:base_reg=DRC_REG_EAX;break; - case 1:base_reg=DRC_REG_ECX;break; - case 2:base_reg=DRC_REG_EDX;break; - case 3:base_reg=DRC_REG_EBX;break; - case 4: // SIB - { - Bitu sib=decode_fetchb(); - bool scaled_reg_used=false; - static Bit8u scaledtable[8]={ - DRC_REG_EAX,DRC_REG_ECX,DRC_REG_EDX,DRC_REG_EBX, - 0,DRC_REG_EBP,DRC_REG_ESI,DRC_REG_EDI - }; - // see if scaling should be used and which register is to be scaled in this case - if (((sib >> 3) &7)!=4) scaled_reg_used=true; - scaled_reg=scaledtable[(sib >> 3) &7]; - scale=(sib >> 6); - - switch (sib & 7) { - case 0:base_reg=DRC_REG_EAX;break; - case 1:base_reg=DRC_REG_ECX;break; - case 2:base_reg=DRC_REG_EDX;break; - case 3:base_reg=DRC_REG_EBX;break; - case 4:base_reg=DRC_REG_ESP;seg_base=DRC_SEG_SS;break; - case 5: - if (decode.modrm.mod) { - base_reg=DRC_REG_EBP;seg_base=DRC_SEG_SS; - } else { - // no basereg, maybe scalereg - Bitu val; - // try to get a pointer to the next dword code position - if (decode_fetchd_imm(val)) { - // succeeded, use the pointer to avoid code invalidation - if (!addseg) { - if (!scaled_reg_used) { - gen_mov_word_to_reg(ea_reg,(void*)val,true); - } else { - DYN_LEA_MEM_REG_VAL(ea_reg,NULL,scaled_reg,scale,0); - gen_add(ea_reg,(void*)val); - } - } else { - if (!scaled_reg_used) { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - } else { - DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,0); - } - gen_add(ea_reg,(void*)val); - } - return; - } - // couldn't get a pointer, use the current value - imm=(Bit32s)val; - - if (!addseg) { - if (!scaled_reg_used) { - gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm); - } else { - DYN_LEA_MEM_REG_VAL(ea_reg,NULL,scaled_reg,scale,imm); - } - } else { - if (!scaled_reg_used) { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - } else { - DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,imm); - } - } - - return; - } - break; - case 6:base_reg=DRC_REG_ESI;break; - case 7:base_reg=DRC_REG_EDI;break; - } - // basereg, maybe scalereg - switch (decode.modrm.mod) { - case 1: - imm=(Bit8s)decode_fetchb(); - break; - case 2: { - Bitu val; - // try to get a pointer to the next dword code position - if (decode_fetchd_imm(val)) { - // succeeded, use the pointer to avoid code invalidation - if (!addseg) { - if (!scaled_reg_used) { - MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - gen_add(ea_reg,(void*)val); - } else { - DYN_LEA_REG_VAL_REG_VAL(ea_reg,base_reg,scaled_reg,scale,0); - gen_add(ea_reg,(void*)val); - } - } else { - if (!scaled_reg_used) { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - } else { - DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,0); - } - ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - gen_add(ea_reg,(void*)val); - } - return; - } - // couldn't get a pointer, use the current value - imm=(Bit32s)val; - break; - } - } - - if (!addseg) { - if (!scaled_reg_used) { - MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - gen_add_imm(ea_reg,(Bit32u)imm); - } else { - DYN_LEA_REG_VAL_REG_VAL(ea_reg,base_reg,scaled_reg,scale,imm); - } - } else { - if (!scaled_reg_used) { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - } else { - DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,imm); - ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - } - } - - return; - } - break; // SIB Break - case 5: - if (decode.modrm.mod) { - base_reg=DRC_REG_EBP;seg_base=DRC_SEG_SS; - } else { - // no base, no scalereg - - imm=(Bit32s)decode_fetchd(); - if (!addseg) { - gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm); - } else { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - } - - return; - } - break; - case 6:base_reg=DRC_REG_ESI;break; - case 7:base_reg=DRC_REG_EDI;break; - } - - // no scalereg, but basereg - - switch (decode.modrm.mod) { - case 1: - imm=(Bit8s)decode_fetchb(); - break; - case 2: { - Bitu val; - // try to get a pointer to the next dword code position - if (decode_fetchd_imm(val)) { - // succeeded, use the pointer to avoid code invalidation - if (!addseg) { - MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - gen_add(ea_reg,(void*)val); - } else { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - gen_add(ea_reg,(void*)val); - } - return; - } - // couldn't get a pointer, use the current value - imm=(Bit32s)val; - break; - } - } - - if (!addseg) { - MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - } else { - MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); - ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); - if (imm) gen_add_imm(ea_reg,(Bit32u)imm); - } - } -} - - - -// add code that checks if port access is allowed -// the port is given in a register -static void dyn_add_iocheck(HostReg reg_port,Bitu access_size) { - if (cpu.pmode) { - gen_call_function_RI((void *)&CPU_IO_Exception,reg_port,access_size); - dyn_check_exception(FC_RETOP); - } -} - -// add code that checks if port access is allowed -// the port is a constant -static void dyn_add_iocheck_var(Bit8u accessed_port,Bitu access_size) { - if (cpu.pmode) { - gen_call_function_II((void *)&CPU_IO_Exception,accessed_port,access_size); - dyn_check_exception(FC_RETOP); - } -} - - - -// save back the address register -static void gen_protect_addr_reg(void) { -#ifdef DRC_PROTECT_ADDR_REG - gen_mov_word_from_reg(FC_ADDR,&core_dynrec.protected_regs[FC_ADDR],true); -#endif -} - -// restore the address register -static void gen_restore_addr_reg(void) { -#ifdef DRC_PROTECT_ADDR_REG - gen_mov_word_to_reg(FC_ADDR,&core_dynrec.protected_regs[FC_ADDR],true); -#endif -} - -// save back an arbitrary register -static void gen_protect_reg(HostReg reg) { - gen_mov_word_from_reg(reg,&core_dynrec.protected_regs[reg],true); -} - -// restore an arbitrary register -static void gen_restore_reg(HostReg reg) { - gen_mov_word_to_reg(reg,&core_dynrec.protected_regs[reg],true); -} - -// restore an arbitrary register into a different register -static void gen_restore_reg(HostReg reg,HostReg dest_reg) { - gen_mov_word_to_reg(dest_reg,&core_dynrec.protected_regs[reg],true); -} - - - -// flags optimization functions -// they try to find out if a function can be replaced by another -// one that does not generate any flags at all - -static Bitu mf_functions_num=0; -static struct { - Bit8u* pos; - void* fct_ptr; - Bitu ftype; -} mf_functions[64]; - -static void InitFlagsOptimization(void) { - mf_functions_num=0; -} - -// replace all queued functions with their simpler variants -// because the current instruction destroys all condition flags and -// the flags are not required before -static void InvalidateFlags(void) { -#ifdef DRC_FLAGS_INVALIDATION - for (Bitu ct=0; ctflags & PFLAG_HASCODE) { + // this is a codepage handler, and the one that we're looking for + cph=(CodePageHandlerDynRec *)handler; + return false; + } + if (handler->flags & PFLAG_NOCODE) { + if (PAGING_ForcePageInit(lin_addr)) { + handler=get_tlb_readhandler(lin_addr); + if (handler->flags & PFLAG_HASCODE) { + cph=(CodePageHandlerDynRec *)handler; + return false; + } + } + if (handler->flags & PFLAG_NOCODE) { + LOG_MSG("DYNREC:Can't run code in this page"); + cph=0; + return false; + } + } + Bitu lin_page=lin_addr>>12; + Bitu phys_page=lin_page; + // find the physical page that the linear page is mapped to + if (!PAGING_MakePhysPage(phys_page)) { + LOG_MSG("DYNREC:Can't find physpage"); + cph=0; + return false; + } + // find a free CodePage + if (!cache.free_pages) { + if (cache.used_pages!=decode.page.code) cache.used_pages->ClearRelease(); + else { + // try another page to avoid clearing our source-crosspage + if ((cache.used_pages->next) && (cache.used_pages->next!=decode.page.code)) + cache.used_pages->next->ClearRelease(); + else { + LOG_MSG("DYNREC:Invalid cache links"); + cache.used_pages->ClearRelease(); + } + } + } + CodePageHandlerDynRec * cpagehandler=cache.free_pages; + cache.free_pages=cache.free_pages->next; + + // adjust previous and next page pointer + cpagehandler->prev=cache.last_page; + cpagehandler->next=0; + if (cache.last_page) cache.last_page->next=cpagehandler; + cache.last_page=cpagehandler; + if (!cache.used_pages) cache.used_pages=cpagehandler; + + // initialize the code page handler and add the handler to the memory page + cpagehandler->SetupAt(phys_page,handler); + MEM_SetPageHandler(phys_page,1,cpagehandler); + PAGING_UnlinkPages(lin_page,1); + cph=cpagehandler; + return false; +} + +static void decode_advancepage(void) { + // Advance to the next page + decode.active_block->page.end=4095; + // trigger possible page fault here + decode.page.first++; + Bitu faddr=decode.page.first << 12; + mem_readb(faddr); + MakeCodePage(faddr,decode.page.code); + CacheBlockDynRec * newblock=cache_getblock(); + decode.active_block->crossblock=newblock; + newblock->crossblock=decode.active_block; + decode.active_block=newblock; + decode.active_block->page.start=0; + decode.page.code->AddCrossBlock(decode.active_block); + decode.page.wmap=decode.page.code->write_map; + decode.page.invmap=decode.page.code->invalidation_map; + decode.page.index=0; +} + +// fetch the next byte of the instruction stream +static Bit8u decode_fetchb(void) { + if (GCC_UNLIKELY(decode.page.index>=4096)) { + decode_advancepage(); + } + decode.page.wmap[decode.page.index]+=0x01; + decode.page.index++; + decode.code+=1; + return mem_readb(decode.code-1); +} +// fetch the next word of the instruction stream +static Bit16u decode_fetchw(void) { + if (GCC_UNLIKELY(decode.page.index>=4095)) { + Bit16u val=decode_fetchb(); + val|=decode_fetchb() << 8; + return val; + } + *(Bit16u *)&decode.page.wmap[decode.page.index]+=0x0101; + decode.code+=2;decode.page.index+=2; + return mem_readw(decode.code-2); +} +// fetch the next dword of the instruction stream +static Bit32u decode_fetchd(void) { + if (GCC_UNLIKELY(decode.page.index>=4093)) { + Bit32u val=decode_fetchb(); + val|=decode_fetchb() << 8; + val|=decode_fetchb() << 16; + val|=decode_fetchb() << 24; + return val; + /* Advance to the next page */ + } + *(Bit32u *)&decode.page.wmap[decode.page.index]+=0x01010101; + decode.code+=4;decode.page.index+=4; + return mem_readd(decode.code-4); +} + +#define START_WMMEM 64 + +// adjust writemap mask to care for map holes due to special +// codefetch functions +static void INLINE decode_increase_wmapmask(Bitu size) { + Bitu mapidx; + CacheBlockDynRec* activecb=decode.active_block; + if (GCC_UNLIKELY(!activecb->cache.wmapmask)) { + // no mask memory yet allocated, start with a small buffer + activecb->cache.wmapmask=(Bit8u*)malloc(START_WMMEM); + memset(activecb->cache.wmapmask,0,START_WMMEM); + activecb->cache.maskstart=decode.page.index; // start of buffer is current code position + activecb->cache.masklen=START_WMMEM; + mapidx=0; + } else { + mapidx=decode.page.index-activecb->cache.maskstart; + if (GCC_UNLIKELY(mapidx+size>=activecb->cache.masklen)) { + // mask buffer too small, increase + Bitu newmasklen=activecb->cache.masklen*4; + if (newmasklencache.wmapmask,activecb->cache.masklen); + free(activecb->cache.wmapmask); + activecb->cache.wmapmask=tempmem; + activecb->cache.masklen=newmasklen; + } + } + // update mask entries + switch (size) { + case 1 : activecb->cache.wmapmask[mapidx]+=0x01; break; + case 2 : (*(Bit16u*)&activecb->cache.wmapmask[mapidx])+=0x0101; break; + case 4 : (*(Bit32u*)&activecb->cache.wmapmask[mapidx])+=0x01010101; break; + } +} + +// fetch a byte, val points to the code location if possible, +// otherwise val contains the current value read from the position +static bool decode_fetchb_imm(Bitu & val) { + if (GCC_UNLIKELY(decode.page.index>=4096)) { + decode_advancepage(); + } + // see if position is directly accessible + if (decode.page.invmap != NULL) { + if (decode.page.invmap[decode.page.index] == 0) { + // position not yet modified + val=(Bit32u)decode_fetchb(); + return false; + } + + HostPt tlb_addr=get_tlb_read(decode.code); + if (tlb_addr) { + val=(Bitu)(tlb_addr+decode.code); + decode_increase_wmapmask(1); + decode.code++; + decode.page.index++; + return true; + } + } + // first time decoding or not directly accessible, just fetch the value + val=(Bit32u)decode_fetchb(); + return false; +} + +// fetch a word, val points to the code location if possible, +// otherwise val contains the current value read from the position +static bool decode_fetchw_imm(Bitu & val) { + if (decode.page.index<4095) { + if (decode.page.invmap != NULL) { + if ((decode.page.invmap[decode.page.index] == 0) && + (decode.page.invmap[decode.page.index + 1] == 0)) { + // position not yet modified + val=decode_fetchw(); + return false; + } + + HostPt tlb_addr=get_tlb_read(decode.code); + // see if position is directly accessible + if (tlb_addr) { + val=(Bitu)(tlb_addr+decode.code); + decode_increase_wmapmask(2); + decode.code+=2; + decode.page.index+=2; + return true; + } + } + } + // first time decoding or not directly accessible, just fetch the value + val=decode_fetchw(); + return false; +} + +// fetch a dword, val points to the code location if possible, +// otherwise val contains the current value read from the position +static bool decode_fetchd_imm(Bitu & val) { + if (decode.page.index<4093) { + if (decode.page.invmap != NULL) { + if ((decode.page.invmap[decode.page.index] == 0) && + (decode.page.invmap[decode.page.index + 1] == 0) && + (decode.page.invmap[decode.page.index + 2] == 0) && + (decode.page.invmap[decode.page.index + 3] == 0)) { + // position not yet modified + val=decode_fetchd(); + return false; + } + + HostPt tlb_addr=get_tlb_read(decode.code); + // see if position is directly accessible + if (tlb_addr) { + val=(Bitu)(tlb_addr+decode.code); + decode_increase_wmapmask(4); + decode.code+=4; + decode.page.index+=4; + return true; + } + } + } + // first time decoding or not directly accessible, just fetch the value + val=decode_fetchd(); + return false; +} + + +// modrm decoding helper +static void INLINE dyn_get_modrm(void) { + decode.modrm.val=decode_fetchb(); + decode.modrm.mod=(decode.modrm.val >> 6) & 3; + decode.modrm.reg=(decode.modrm.val >> 3) & 7; + decode.modrm.rm=(decode.modrm.val & 7); +} + + +#ifdef DRC_USE_SEGS_ADDR + +#define MOV_SEG_VAL_TO_HOST_REG(host_reg, seg_index) gen_mov_seg16_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_VAL(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs)) + +#define MOV_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_mov_seg32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_PHYS(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs)) +#define ADD_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_add_seg32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_SEG_PHYS(seg_index)) - (DRC_PTR_SIZE_IM)(&Segs)) + +#else + +#define MOV_SEG_VAL_TO_HOST_REG(host_reg, seg_index) gen_mov_word_to_reg(host_reg,DRCD_SEG_VAL(seg_index),false) + +#define MOV_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_mov_word_to_reg(host_reg,DRCD_SEG_PHYS(seg_index),true) +#define ADD_SEG_PHYS_TO_HOST_REG(host_reg, seg_index) gen_add(host_reg,DRCD_SEG_PHYS(seg_index)) + +#endif + + +#ifdef DRC_USE_REGS_ADDR + +#define MOV_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_mov_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_VAL(reg_index)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define ADD_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_add_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_VAL(reg_index)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) + +#define MOV_REG_WORD16_TO_HOST_REG(host_reg, reg_index) gen_mov_regval16_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,false)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define MOV_REG_WORD32_TO_HOST_REG(host_reg, reg_index) gen_mov_regval32_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,true)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define MOV_REG_WORD_TO_HOST_REG(host_reg, reg_index, dword) gen_mov_regword_to_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,dword)) - (DRC_PTR_SIZE_IM)(&cpu_regs), dword) + +#define MOV_REG_WORD16_FROM_HOST_REG(host_reg, reg_index) gen_mov_regval16_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,false)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define MOV_REG_WORD32_FROM_HOST_REG(host_reg, reg_index) gen_mov_regval32_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,true)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define MOV_REG_WORD_FROM_HOST_REG(host_reg, reg_index, dword) gen_mov_regword_from_reg(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_WORD(reg_index,dword)) - (DRC_PTR_SIZE_IM)(&cpu_regs), dword) + +#define MOV_REG_BYTE_TO_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_regbyte_to_reg_low(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(host_reg, reg_index, high_byte) gen_mov_regbyte_to_reg_low_canuseword(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) +#define MOV_REG_BYTE_FROM_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_regbyte_from_reg_low(host_reg,(DRC_PTR_SIZE_IM)(DRCD_REG_BYTE(reg_index,high_byte)) - (DRC_PTR_SIZE_IM)(&cpu_regs)) + +#else + +#define MOV_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_VAL(reg_index),true) +#define ADD_REG_VAL_TO_HOST_REG(host_reg, reg_index) gen_add(host_reg,DRCD_REG_VAL(reg_index)) + +#define MOV_REG_WORD16_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,false),false) +#define MOV_REG_WORD32_TO_HOST_REG(host_reg, reg_index) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,true),true) +#define MOV_REG_WORD_TO_HOST_REG(host_reg, reg_index, dword) gen_mov_word_to_reg(host_reg,DRCD_REG_WORD(reg_index,dword),dword) + +#define MOV_REG_WORD16_FROM_HOST_REG(host_reg, reg_index) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,false),false) +#define MOV_REG_WORD32_FROM_HOST_REG(host_reg, reg_index) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,true),true) +#define MOV_REG_WORD_FROM_HOST_REG(host_reg, reg_index, dword) gen_mov_word_from_reg(host_reg,DRCD_REG_WORD(reg_index,dword),dword) + +#define MOV_REG_BYTE_TO_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_byte_to_reg_low(host_reg,DRCD_REG_BYTE(reg_index,high_byte)) +#define MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(host_reg, reg_index, high_byte) gen_mov_byte_to_reg_low_canuseword(host_reg,DRCD_REG_BYTE(reg_index,high_byte)) +#define MOV_REG_BYTE_FROM_HOST_REG_LOW(host_reg, reg_index, high_byte) gen_mov_byte_from_reg_low(host_reg,DRCD_REG_BYTE(reg_index,high_byte)) + +#endif + + +#define DYN_LEA_MEM_MEM(ea_reg, op1, op2, scale, imm) dyn_lea_mem_mem(ea_reg,op1,op2,scale,imm) + +#if defined(DRC_USE_REGS_ADDR) && defined(DRC_USE_SEGS_ADDR) + +#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_segphys_regval(ea_reg,op1_index,op2_index,scale,imm) +#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_regval_regval(ea_reg,op1_index,op2_index,scale,imm) +#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,op1,op2_index,scale,imm) + +#elif defined(DRC_USE_REGS_ADDR) + +#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,DRCD_SEG_PHYS(op1_index),op2_index,scale,imm) +#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_regval_regval(ea_reg,op1_index,op2_index,scale,imm) +#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_regval(ea_reg,op1,op2_index,scale,imm) + +#elif defined(DRC_USE_SEGS_ADDR) + +#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_segphys_mem(ea_reg,op1_index,DRCD_REG_VAL(op2_index),scale,imm) +#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_REG_VAL(op1_index),DRCD_REG_VAL(op2_index),scale,imm) +#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,op1,DRCD_REG_VAL(op2_index),scale,imm) + +#else + +#define DYN_LEA_SEG_PHYS_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_SEG_PHYS(op1_index),DRCD_REG_VAL(op2_index),scale,imm) +#define DYN_LEA_REG_VAL_REG_VAL(ea_reg, op1_index, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,DRCD_REG_VAL(op1_index),DRCD_REG_VAL(op2_index),scale,imm) +#define DYN_LEA_MEM_REG_VAL(ea_reg, op1, op2_index, scale, imm) dyn_lea_mem_mem(ea_reg,op1,DRCD_REG_VAL(op2_index),scale,imm) + +#endif + + + +// adjust CPU_Cycles value +static void dyn_reduce_cycles(void) { + if (!decode.cycles) decode.cycles++; + gen_sub_direct_word(&CPU_Cycles,decode.cycles,true); +} + + +// set reg to the start of the next instruction +// set reg_eip to the start of the current instruction +static INLINE void dyn_set_eip_last_end(HostReg reg) { + gen_mov_word_to_reg(reg,®_eip,true); + gen_add_imm(reg,(Bit32u)(decode.code-decode.code_start)); + gen_add_direct_word(®_eip,decode.op_start-decode.code_start,decode.big_op); +} + +// set reg_eip to the start of the current instruction +static INLINE void dyn_set_eip_last(void) { + gen_add_direct_word(®_eip,decode.op_start-decode.code_start,cpu.code.big); +} + +// set reg_eip to the start of the next instruction +static INLINE void dyn_set_eip_end(void) { + gen_add_direct_word(®_eip,decode.code-decode.code_start,cpu.code.big); +} + +// set reg_eip to the start of the next instruction plus an offset (imm) +static INLINE void dyn_set_eip_end(HostReg reg,Bit32u imm=0) { + gen_mov_word_to_reg(reg,®_eip,decode.big_op); + gen_add_imm(reg,(Bit32u)(decode.code-decode.code_start+imm)); + if (!decode.big_op) gen_extend_word(false,reg); +} + + + +// the following functions generate function calls +// parameters are loaded by generating code using gen_load_param_ which +// is architecture dependent +// R=host register; I=32bit immediate value; A=address value; m=memory + +static DRC_PTR_SIZE_IM INLINE gen_call_function_R(void * func,Bitu op) { + gen_load_param_reg(op,0); + return gen_call_function_setup(func, 1); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_R3(void * func,Bitu op) { + gen_load_param_reg(op,2); + return gen_call_function_setup(func, 3, true); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_RI(void * func,Bitu op1,Bitu op2) { + gen_load_param_imm(op2,1); + gen_load_param_reg(op1,0); + return gen_call_function_setup(func, 2); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_RA(void * func,Bitu op1,DRC_PTR_SIZE_IM op2) { + gen_load_param_addr(op2,1); + gen_load_param_reg(op1,0); + return gen_call_function_setup(func, 2); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_RR(void * func,Bitu op1,Bitu op2) { + gen_load_param_reg(op2,1); + gen_load_param_reg(op1,0); + return gen_call_function_setup(func, 2); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_IR(void * func,Bitu op1,Bitu op2) { + gen_load_param_reg(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 2); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_I(void * func,Bitu op) { + gen_load_param_imm(op,0); + return gen_call_function_setup(func, 1); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_II(void * func,Bitu op1,Bitu op2) { + gen_load_param_imm(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 2); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_III(void * func,Bitu op1,Bitu op2,Bitu op3) { + gen_load_param_imm(op3,2); + gen_load_param_imm(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 3); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_IA(void * func,Bitu op1,DRC_PTR_SIZE_IM op2) { + gen_load_param_addr(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 2); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_IIR(void * func,Bitu op1,Bitu op2,Bitu op3) { + gen_load_param_reg(op3,2); + gen_load_param_imm(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 3); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_IIIR(void * func,Bitu op1,Bitu op2,Bitu op3,Bitu op4) { + gen_load_param_reg(op4,3); + gen_load_param_imm(op3,2); + gen_load_param_imm(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 4); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_IRRR(void * func,Bitu op1,Bitu op2,Bitu op3,Bitu op4) { + gen_load_param_reg(op4,3); + gen_load_param_reg(op3,2); + gen_load_param_reg(op2,1); + gen_load_param_imm(op1,0); + return gen_call_function_setup(func, 4); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_m(void * func,Bitu op) { + gen_load_param_mem(op,2); + return gen_call_function_setup(func, 3, true); +} + +static DRC_PTR_SIZE_IM INLINE gen_call_function_mm(void * func,Bitu op1,Bitu op2) { + gen_load_param_mem(op2,3); + gen_load_param_mem(op1,2); + return gen_call_function_setup(func, 4, true); +} + + + +enum save_info_type {db_exception, cycle_check, string_break}; + + +// function that is called on exceptions +static BlockReturn DynRunException(Bit32u eip_add,Bit32u cycle_sub) { + 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; +} + + +// array with information about code that is generated at the +// end of a cache block because it is rarely reached (like exceptions) +static struct { + save_info_type type; + DRC_PTR_SIZE_IM branch_pos; + Bit32u eip_change; + Bitu cycles; +} save_info_dynrec[512]; + +Bitu used_save_info_dynrec=0; + + +// return from current block, with returncode +static void dyn_return(BlockReturn retcode,bool ret_exception=false) { + if (!ret_exception) { + gen_mov_dword_to_reg_imm(FC_RETOP,retcode); + } + gen_return_function(); +} + +static void dyn_run_code(void) { + gen_run_code(); + gen_return_function(); +} + +// fill in code at the end of the block that contains rarely-executed code +// which is executed conditionally (like exceptions) +static void dyn_fill_blocks(void) { + for (Bitu sct=0; sctcache.start,decode.block->cache.size); +} + + +// add a check that can branch to the exception handling +static void dyn_check_exception(HostReg reg) { + save_info_dynrec[used_save_info_dynrec].branch_pos=gen_create_branch_long_nonzero(reg,false); + if (!decode.cycles) decode.cycles++; + save_info_dynrec[used_save_info_dynrec].cycles=decode.cycles; + // in case of an exception eip will point to the start of the current instruction + save_info_dynrec[used_save_info_dynrec].eip_change=decode.op_start-decode.code_start; + if (!cpu.code.big) save_info_dynrec[used_save_info_dynrec].eip_change&=0xffff; + save_info_dynrec[used_save_info_dynrec].type=db_exception; + used_save_info_dynrec++; +} + + + +bool DRC_CALL_CONV mem_readb_checked_drc(PhysPt address) DRC_FC; +bool DRC_CALL_CONV mem_readb_checked_drc(PhysPt address) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + *((Bit8u*)(&core_dynrec.readdata))=host_readb(tlb_addr+address); + return false; + } else { + return get_tlb_readhandler(address)->readb_checked(address, (Bit8u*)(&core_dynrec.readdata)); + } +} + +bool DRC_CALL_CONV mem_writeb_checked_drc(PhysPt address,Bit8u val) DRC_FC; +bool DRC_CALL_CONV mem_writeb_checked_drc(PhysPt address,Bit8u val) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) { + host_writeb(tlb_addr+address,val); + return false; + } else return get_tlb_writehandler(address)->writeb_checked(address,val); +} + +bool DRC_CALL_CONV mem_readw_checked_drc(PhysPt address) DRC_FC; +bool DRC_CALL_CONV mem_readw_checked_drc(PhysPt address) { + if ((address & 0xfff)<0xfff) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + *((Bit16u*)(&core_dynrec.readdata))=host_readw(tlb_addr+address); + return false; + } else return get_tlb_readhandler(address)->readw_checked(address, (Bit16u*)(&core_dynrec.readdata)); + } else return mem_unalignedreadw_checked(address, ((Bit16u*)(&core_dynrec.readdata))); +} + +bool DRC_CALL_CONV mem_readd_checked_drc(PhysPt address) DRC_FC; +bool DRC_CALL_CONV mem_readd_checked_drc(PhysPt address) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_read(address); + if (tlb_addr) { + *((Bit32u*)(&core_dynrec.readdata))=host_readd(tlb_addr+address); + return false; + } else return get_tlb_readhandler(address)->readd_checked(address, (Bit32u*)(&core_dynrec.readdata)); + } else return mem_unalignedreadd_checked(address, ((Bit32u*)(&core_dynrec.readdata))); +} + +bool DRC_CALL_CONV mem_writew_checked_drc(PhysPt address,Bit16u val) DRC_FC; +bool DRC_CALL_CONV mem_writew_checked_drc(PhysPt address,Bit16u val) { + if ((address & 0xfff)<0xfff) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) { + host_writew(tlb_addr+address,val); + return false; + } else return get_tlb_writehandler(address)->writew_checked(address,val); + } else return mem_unalignedwritew_checked(address,val); +} + +bool DRC_CALL_CONV mem_writed_checked_drc(PhysPt address,Bit32u val) DRC_FC; +bool DRC_CALL_CONV mem_writed_checked_drc(PhysPt address,Bit32u val) { + if ((address & 0xfff)<0xffd) { + HostPt tlb_addr=get_tlb_write(address); + if (tlb_addr) { + host_writed(tlb_addr+address,val); + return false; + } else return get_tlb_writehandler(address)->writed_checked(address,val); + } else return mem_unalignedwrited_checked(address,val); +} + + +// functions that enable access to the memory + +// read a byte from a given address and store it in reg_dst +static void dyn_read_byte(HostReg reg_addr,HostReg reg_dst) { + gen_mov_regs(FC_OP1,reg_addr); + gen_call_function_raw((void *)&mem_readb_checked_drc); + dyn_check_exception(FC_RETOP); + gen_mov_byte_to_reg_low(reg_dst,&core_dynrec.readdata); +} +static void dyn_read_byte_canuseword(HostReg reg_addr,HostReg reg_dst) { + gen_mov_regs(FC_OP1,reg_addr); + gen_call_function_raw((void *)&mem_readb_checked_drc); + dyn_check_exception(FC_RETOP); + gen_mov_byte_to_reg_low_canuseword(reg_dst,&core_dynrec.readdata); +} + +// write a byte from reg_val into the memory given by the address +static void dyn_write_byte(HostReg reg_addr,HostReg reg_val) { + gen_mov_regs(FC_OP2,reg_val); + gen_mov_regs(FC_OP1,reg_addr); + gen_call_function_raw((void *)&mem_writeb_checked_drc); + dyn_check_exception(FC_RETOP); +} + +// read a 32bit (dword=true) or 16bit (dword=false) value +// from a given address and store it in reg_dst +static void dyn_read_word(HostReg reg_addr,HostReg reg_dst,bool dword) { + gen_mov_regs(FC_OP1,reg_addr); + if (dword) gen_call_function_raw((void *)&mem_readd_checked_drc); + else gen_call_function_raw((void *)&mem_readw_checked_drc); + dyn_check_exception(FC_RETOP); + gen_mov_word_to_reg(reg_dst,&core_dynrec.readdata,dword); +} + +// write a 32bit (dword=true) or 16bit (dword=false) value +// from reg_val into the memory given by the address +static void dyn_write_word(HostReg reg_addr,HostReg reg_val,bool dword) { +// if (!dword) gen_extend_word(false,reg_val); + gen_mov_regs(FC_OP2,reg_val); + gen_mov_regs(FC_OP1,reg_addr); + if (dword) gen_call_function_raw((void *)&mem_writed_checked_drc); + else gen_call_function_raw((void *)&mem_writew_checked_drc); + dyn_check_exception(FC_RETOP); +} + + + +// effective address calculation helper, op2 has to be present! +// loads op1 into ea_reg and adds the scaled op2 and the immediate to it +static void dyn_lea_mem_mem(HostReg ea_reg,void* op1,void* op2,Bitu scale,Bits imm) { + if (scale || imm) { + if (op1!=NULL) { + gen_mov_word_to_reg(ea_reg,op1,true); + gen_mov_word_to_reg(TEMP_REG_DRC,op2,true); + + gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); + } else { + gen_mov_word_to_reg(ea_reg,op2,true); + gen_lea(ea_reg,scale,imm); + } + } else { + gen_mov_word_to_reg(ea_reg,op2,true); + if (op1!=NULL) gen_add(ea_reg,op1); + } +} + +#ifdef DRC_USE_REGS_ADDR +// effective address calculation helper +// loads op1 into ea_reg and adds the scaled op2 and the immediate to it +// op1 is cpu_regs[op1_index], op2 is cpu_regs[op2_index] +static void dyn_lea_regval_regval(HostReg ea_reg,Bitu op1_index,Bitu op2_index,Bitu scale,Bits imm) { + if (scale || imm) { + MOV_REG_VAL_TO_HOST_REG(ea_reg,op1_index); + MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index); + + gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); + } else { + MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); + ADD_REG_VAL_TO_HOST_REG(ea_reg,op1_index); + } +} + +// effective address calculation helper +// loads op1 into ea_reg and adds the scaled op2 and the immediate to it +// op2 is cpu_regs[op2_index] +static void dyn_lea_mem_regval(HostReg ea_reg,void* op1,Bitu op2_index,Bitu scale,Bits imm) { + if (scale || imm) { + if (op1!=NULL) { + gen_mov_word_to_reg(ea_reg,op1,true); + MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index); + + gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); + } else { + MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); + gen_lea(ea_reg,scale,imm); + } + } else { + MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); + if (op1!=NULL) gen_add(ea_reg,op1); + } +} +#endif + +#ifdef DRC_USE_SEGS_ADDR +#ifdef DRC_USE_REGS_ADDR +// effective address calculation helper +// loads op1 into ea_reg and adds the scaled op2 and the immediate to it +// op1 is Segs[op1_index], op2 is cpu_regs[op2_index] +static void dyn_lea_segphys_regval(HostReg ea_reg,Bitu op1_index,Bitu op2_index,Bitu scale,Bits imm) { + if (scale || imm) { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); + MOV_REG_VAL_TO_HOST_REG(TEMP_REG_DRC,op2_index); + + gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); + } else { + MOV_REG_VAL_TO_HOST_REG(ea_reg,op2_index); + ADD_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); + } +} + +#else + +// effective address calculation helper, op2 has to be present! +// loads op1 into ea_reg and adds the scaled op2 and the immediate to it +// op1 is Segs[op1_index] +static void dyn_lea_segphys_mem(HostReg ea_reg,Bitu op1_index,void* op2,Bitu scale,Bits imm) { + if (scale || imm) { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); + gen_mov_word_to_reg(TEMP_REG_DRC,op2,true); + + gen_lea(ea_reg,TEMP_REG_DRC,scale,imm); + } else { + gen_mov_word_to_reg(ea_reg,op2,true); + ADD_SEG_PHYS_TO_HOST_REG(ea_reg,op1_index); + } +} +#endif +#endif + +// calculate the effective address and store it in ea_reg +static void dyn_fill_ea(HostReg ea_reg,bool addseg=true) { + Bit8u seg_base=DRC_SEG_DS; + if (!decode.big_addr) { + Bits imm; + switch (decode.modrm.mod) { + case 0:imm=0;break; + case 1:imm=(Bit8s)decode_fetchb();break; + case 2:imm=(Bit16s)decode_fetchw();break; + } + switch (decode.modrm.rm) { + case 0:// BX+SI + DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBX,DRC_REG_ESI,0,imm); + break; + case 1:// BX+DI + DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBX,DRC_REG_EDI,0,imm); + break; + case 2:// BP+SI + DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBP,DRC_REG_ESI,0,imm); + seg_base=DRC_SEG_SS; + break; + case 3:// BP+DI + DYN_LEA_REG_VAL_REG_VAL(ea_reg,DRC_REG_EBP,DRC_REG_EDI,0,imm); + seg_base=DRC_SEG_SS; + break; + case 4:// SI + MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_ESI); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + break; + case 5:// DI + MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EDI); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + break; + case 6:// imm/BP + if (!decode.modrm.mod) { + imm=decode_fetchw(); + gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm); + goto skip_extend_word; + } else { + MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EBP); + gen_add_imm(ea_reg,(Bit32u)imm); + seg_base=DRC_SEG_SS; + } + break; + case 7: // BX + MOV_REG_VAL_TO_HOST_REG(ea_reg,DRC_REG_EBX); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + break; + } + // zero out the high 16bit so ea_reg can be used as full register + gen_extend_word(false,ea_reg); +skip_extend_word: + if (addseg) { + // add the physical segment value if requested + ADD_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + } + } else { + Bits imm=0; + Bit8u base_reg; + Bit8u scaled_reg; + Bitu scale=0; + switch (decode.modrm.rm) { + case 0:base_reg=DRC_REG_EAX;break; + case 1:base_reg=DRC_REG_ECX;break; + case 2:base_reg=DRC_REG_EDX;break; + case 3:base_reg=DRC_REG_EBX;break; + case 4: // SIB + { + Bitu sib=decode_fetchb(); + bool scaled_reg_used=false; + static Bit8u scaledtable[8]={ + DRC_REG_EAX,DRC_REG_ECX,DRC_REG_EDX,DRC_REG_EBX, + 0,DRC_REG_EBP,DRC_REG_ESI,DRC_REG_EDI + }; + // see if scaling should be used and which register is to be scaled in this case + if (((sib >> 3) &7)!=4) scaled_reg_used=true; + scaled_reg=scaledtable[(sib >> 3) &7]; + scale=(sib >> 6); + + switch (sib & 7) { + case 0:base_reg=DRC_REG_EAX;break; + case 1:base_reg=DRC_REG_ECX;break; + case 2:base_reg=DRC_REG_EDX;break; + case 3:base_reg=DRC_REG_EBX;break; + case 4:base_reg=DRC_REG_ESP;seg_base=DRC_SEG_SS;break; + case 5: + if (decode.modrm.mod) { + base_reg=DRC_REG_EBP;seg_base=DRC_SEG_SS; + } else { + // no basereg, maybe scalereg + Bitu val; + // try to get a pointer to the next dword code position + if (decode_fetchd_imm(val)) { + // succeeded, use the pointer to avoid code invalidation + if (!addseg) { + if (!scaled_reg_used) { + gen_mov_word_to_reg(ea_reg,(void*)val,true); + } else { + DYN_LEA_MEM_REG_VAL(ea_reg,NULL,scaled_reg,scale,0); + gen_add(ea_reg,(void*)val); + } + } else { + if (!scaled_reg_used) { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + } else { + DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,0); + } + gen_add(ea_reg,(void*)val); + } + return; + } + // couldn't get a pointer, use the current value + imm=(Bit32s)val; + + if (!addseg) { + if (!scaled_reg_used) { + gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm); + } else { + DYN_LEA_MEM_REG_VAL(ea_reg,NULL,scaled_reg,scale,imm); + } + } else { + if (!scaled_reg_used) { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + } else { + DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,imm); + } + } + + return; + } + break; + case 6:base_reg=DRC_REG_ESI;break; + case 7:base_reg=DRC_REG_EDI;break; + } + // basereg, maybe scalereg + switch (decode.modrm.mod) { + case 1: + imm=(Bit8s)decode_fetchb(); + break; + case 2: { + Bitu val; + // try to get a pointer to the next dword code position + if (decode_fetchd_imm(val)) { + // succeeded, use the pointer to avoid code invalidation + if (!addseg) { + if (!scaled_reg_used) { + MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + gen_add(ea_reg,(void*)val); + } else { + DYN_LEA_REG_VAL_REG_VAL(ea_reg,base_reg,scaled_reg,scale,0); + gen_add(ea_reg,(void*)val); + } + } else { + if (!scaled_reg_used) { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + } else { + DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,0); + } + ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + gen_add(ea_reg,(void*)val); + } + return; + } + // couldn't get a pointer, use the current value + imm=(Bit32s)val; + break; + } + } + + if (!addseg) { + if (!scaled_reg_used) { + MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + gen_add_imm(ea_reg,(Bit32u)imm); + } else { + DYN_LEA_REG_VAL_REG_VAL(ea_reg,base_reg,scaled_reg,scale,imm); + } + } else { + if (!scaled_reg_used) { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + } else { + DYN_LEA_SEG_PHYS_REG_VAL(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base),scaled_reg,scale,imm); + ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + } + } + + return; + } + break; // SIB Break + case 5: + if (decode.modrm.mod) { + base_reg=DRC_REG_EBP;seg_base=DRC_SEG_SS; + } else { + // no base, no scalereg + + imm=(Bit32s)decode_fetchd(); + if (!addseg) { + gen_mov_dword_to_reg_imm(ea_reg,(Bit32u)imm); + } else { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + } + + return; + } + break; + case 6:base_reg=DRC_REG_ESI;break; + case 7:base_reg=DRC_REG_EDI;break; + } + + // no scalereg, but basereg + + switch (decode.modrm.mod) { + case 1: + imm=(Bit8s)decode_fetchb(); + break; + case 2: { + Bitu val; + // try to get a pointer to the next dword code position + if (decode_fetchd_imm(val)) { + // succeeded, use the pointer to avoid code invalidation + if (!addseg) { + MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + gen_add(ea_reg,(void*)val); + } else { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + gen_add(ea_reg,(void*)val); + } + return; + } + // couldn't get a pointer, use the current value + imm=(Bit32s)val; + break; + } + } + + if (!addseg) { + MOV_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + } else { + MOV_SEG_PHYS_TO_HOST_REG(ea_reg,(decode.seg_prefix_used ? decode.seg_prefix : seg_base)); + ADD_REG_VAL_TO_HOST_REG(ea_reg,base_reg); + if (imm) gen_add_imm(ea_reg,(Bit32u)imm); + } + } +} + + + +// add code that checks if port access is allowed +// the port is given in a register +static void dyn_add_iocheck(HostReg reg_port,Bitu access_size) { + if (cpu.pmode) { + gen_call_function_RI((void *)&CPU_IO_Exception,reg_port,access_size); + dyn_check_exception(FC_RETOP); + } +} + +// add code that checks if port access is allowed +// the port is a constant +static void dyn_add_iocheck_var(Bit8u accessed_port,Bitu access_size) { + if (cpu.pmode) { + gen_call_function_II((void *)&CPU_IO_Exception,accessed_port,access_size); + dyn_check_exception(FC_RETOP); + } +} + + + +// save back the address register +static void gen_protect_addr_reg(void) { +#ifdef DRC_PROTECT_ADDR_REG + gen_mov_word_from_reg(FC_ADDR,&core_dynrec.protected_regs[FC_ADDR],true); +#endif +} + +// restore the address register +static void gen_restore_addr_reg(void) { +#ifdef DRC_PROTECT_ADDR_REG + gen_mov_word_to_reg(FC_ADDR,&core_dynrec.protected_regs[FC_ADDR],true); +#endif +} + +// save back an arbitrary register +static void gen_protect_reg(HostReg reg) { + gen_mov_word_from_reg(reg,&core_dynrec.protected_regs[reg],true); +} + +// restore an arbitrary register +static void gen_restore_reg(HostReg reg) { + gen_mov_word_to_reg(reg,&core_dynrec.protected_regs[reg],true); +} + +// restore an arbitrary register into a different register +static void gen_restore_reg(HostReg reg,HostReg dest_reg) { + gen_mov_word_to_reg(dest_reg,&core_dynrec.protected_regs[reg],true); +} + + + +// flags optimization functions +// they try to find out if a function can be replaced by another +// one that does not generate any flags at all + +static Bitu mf_functions_num=0; +static struct { + Bit8u* pos; + void* fct_ptr; + Bitu ftype; +} mf_functions[64]; + +static void InitFlagsOptimization(void) { + mf_functions_num=0; +} + +// replace all queued functions with their simpler variants +// because the current instruction destroys all condition flags and +// the flags are not required before +static void InvalidateFlags(void) { +#ifdef DRC_FLAGS_INVALIDATION + for (Bitu ct=0; ct>2)&1); - dyn_dop_byte_gencall(op); - - if ((op!=DOP_CMP) && (op!=DOP_TEST)) { - gen_restore_addr_reg(); - dyn_write_byte(FC_ADDR,FC_RETOP); - } - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - dyn_dop_byte_gencall(op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_dop_ebgb_mov(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - dyn_write_byte(FC_ADDR,FC_TMP_BA1); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_dop_ebib_mov(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,decode_fetchb()); - dyn_write_byte(FC_ADDR,FC_TMP_BA1); - } else { - gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,decode_fetchb()); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_dop_ebgb_xchg(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_byte(FC_ADDR,FC_TMP_BA1); - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - gen_restore_addr_reg(); - dyn_write_byte(FC_ADDR,FC_TMP_BA2); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_dop_gbeb(DualOps op) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_byte_canuseword(FC_ADDR,FC_OP2); - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - dyn_dop_byte_gencall(op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - dyn_dop_byte_gencall(op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - } -} - -static void dyn_dop_gbeb_mov(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_byte(FC_ADDR,FC_TMP_BA1); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); - } -} - -static void dyn_dop_evgv(DualOps op) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - gen_protect_addr_reg(); - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - dyn_dop_word_gencall(op,decode.big_op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) { - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - dyn_dop_word_gencall(op,decode.big_op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); - } -} - -static void dyn_dop_evgv_mov(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - dyn_write_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } -} - -static void dyn_dop_eviv_mov(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,decode_fetchd()); - else gen_mov_word_to_reg_imm(FC_OP1,decode_fetchw()); - dyn_write_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,decode_fetchd()); - else gen_mov_word_to_reg_imm(FC_OP1,decode_fetchw()); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } -} - -static void dyn_dop_evgv_xchg(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - - gen_protect_reg(FC_OP1); - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_OP2,decode.big_op); - gen_restore_reg(FC_OP1); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP2,decode.modrm.rm,decode.big_op); - } -} - -static void dyn_xchg_ax(Bit8u reg) { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); - MOV_REG_WORD_TO_HOST_REG(FC_OP2,reg,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,reg,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP2,DRC_REG_EAX,decode.big_op); -} - -static void dyn_dop_gvev(DualOps op) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP2,decode.big_op); - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - dyn_dop_word_gencall(op,decode.big_op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) { - gen_restore_addr_reg(); - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op); - } - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.rm,decode.big_op); - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - dyn_dop_word_gencall(op,decode.big_op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op); - } -} - -static void dyn_dop_gvev_mov(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - } -} - -static void dyn_dop_byte_imm(DualOps op,Bit8u reg,Bit8u idx) { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,reg,idx); - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb()); - dyn_dop_byte_gencall(op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,reg,idx); -} - -static void dyn_dop_byte_imm_mem(DualOps op,Bit8u reg,Bit8u idx) { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,reg,idx); - Bitu val; - if (decode_fetchb_imm(val)) { - gen_mov_byte_to_reg_low_canuseword(FC_OP2,(void*)val); - } else { - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,(Bit8u)val); - } - dyn_dop_byte_gencall(op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,reg,idx); -} - -static void dyn_prep_word_imm(Bit8u reg) { - Bitu val; - if (decode.big_op) { - if (decode_fetchd_imm(val)) { - gen_mov_word_to_reg(FC_OP2,(void*)val,true); - return; - } - } else { - if (decode_fetchw_imm(val)) { - gen_mov_word_to_reg(FC_OP2,(void*)val,false); - return; - } - } - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)val); - else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)val); -} - -static void dyn_dop_word_imm(DualOps op,Bit8u reg) { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); - dyn_prep_word_imm(reg); - dyn_dop_word_gencall(op,decode.big_op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); -} - -static void dyn_dop_word_imm_old(DualOps op,Bit8u reg,Bitu imm) { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm); - else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)imm); - dyn_dop_word_gencall(op,decode.big_op); - if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); -} - -static void dyn_mov_byte_imm(Bit8u reg,Bit8u idx,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,imm); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,reg,idx); -} - -static void dyn_mov_word_imm(Bit8u reg) { - Bitu val; - if (decode.big_op) { - if (decode_fetchd_imm(val)) { - gen_mov_word_to_reg(FC_OP1,(void*)val,true); - MOV_REG_WORD32_FROM_HOST_REG(FC_OP1,reg); - return; - } - } else { - if (decode_fetchw_imm(val)) { - gen_mov_word_to_reg(FC_OP1,(void*)val,false); - MOV_REG_WORD16_FROM_HOST_REG(FC_OP1,reg); - return; - } - } - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)val); - else gen_mov_word_to_reg_imm(FC_OP1,(Bit16u)val); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,reg,decode.big_op); -} - - -static void dyn_sop_word(SingleOps op,Bit8u reg) { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); - dyn_sop_word_gencall(op,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); -} - - -static void dyn_mov_byte_al_direct(Bitu imm) { - MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); - gen_add_imm(FC_ADDR,imm); - dyn_read_byte(FC_ADDR,FC_TMP_BA1); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,DRC_REG_EAX,0); -} - -static void dyn_mov_byte_ax_direct(Bitu imm) { - MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); - gen_add_imm(FC_ADDR,imm); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); -} - -static void dyn_mov_byte_direct_al() { - MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); - if (decode.big_addr) { - Bitu val; - if (decode_fetchd_imm(val)) { - gen_add(FC_ADDR,(void*)val); - } else { - gen_add_imm(FC_ADDR,(Bit32u)val); - } - } else { - gen_add_imm(FC_ADDR,decode_fetchw()); - } - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,DRC_REG_EAX,0); - dyn_write_byte(FC_ADDR,FC_TMP_BA1); -} - -static void dyn_mov_byte_direct_ax(Bitu imm) { - MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); - gen_add_imm(FC_ADDR,imm); - MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); - dyn_write_word(FC_ADDR,FC_OP1,decode.big_op); -} - - -static void dyn_movx_ev_gb(bool sign) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_byte(FC_ADDR,FC_TMP_BA1); - gen_extend_byte(sign,FC_TMP_BA1); - MOV_REG_WORD_FROM_HOST_REG(FC_TMP_BA1,decode.modrm.reg,decode.big_op); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - gen_extend_byte(sign,FC_TMP_BA1); - MOV_REG_WORD_FROM_HOST_REG(FC_TMP_BA1,decode.modrm.reg,decode.big_op); - } -} - -static void dyn_movx_ev_gw(bool sign) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_OP1,false); - gen_extend_word(sign,FC_OP1); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - } else { - MOV_REG_WORD16_TO_HOST_REG(FC_OP1,decode.modrm.rm); - gen_extend_word(sign,FC_OP1); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - } -} - - -static void dyn_mov_ev_seg(void) { - dyn_get_modrm(); - MOV_SEG_VAL_TO_HOST_REG(FC_OP1,decode.modrm.reg); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_write_word(FC_ADDR,FC_OP1,false); - } else { - if (decode.big_op) gen_extend_word(false,FC_OP1); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } -} - - -static void dyn_lea(void) { - dyn_get_modrm(); - dyn_fill_ea(FC_ADDR,false); - MOV_REG_WORD_FROM_HOST_REG(FC_ADDR,decode.modrm.reg,decode.big_op); -} - - -static void dyn_push_seg(Bit8u seg) { - MOV_SEG_VAL_TO_HOST_REG(FC_OP1,seg); - if (decode.big_op) { - gen_extend_word(false,FC_OP1); - gen_call_function_raw((void*)&dynrec_push_dword); - } else { - gen_call_function_raw((void*)&dynrec_push_word); - } -} - -static void dyn_pop_seg(Bit8u seg) { - gen_call_function_II((void *)&CPU_PopSeg,seg,decode.big_op); - dyn_check_exception(FC_RETOP); -} - -static void dyn_push_reg(Bit8u reg) { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); - if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); - else gen_call_function_raw((void*)&dynrec_push_word); -} - -static void dyn_pop_reg(Bit8u reg) { - if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); - else gen_call_function_raw((void*)&dynrec_pop_word); - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); -} - -static void dyn_push_byte_imm(Bit8s imm) { - gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm); - if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); - else gen_call_function_raw((void*)&dynrec_push_word); -} - -static void dyn_push_word_imm(Bitu imm) { - if (decode.big_op) { - gen_mov_dword_to_reg_imm(FC_OP1,imm); - gen_call_function_raw((void*)&dynrec_push_dword); - } else { - gen_mov_word_to_reg_imm(FC_OP1,(Bit16u)imm); - gen_call_function_raw((void*)&dynrec_push_word); - } -} - -static void dyn_pop_ev(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { -/* dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); // dummy read to trigger possible page faults */ - if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); - else gen_call_function_raw((void*)&dynrec_pop_word); - dyn_fill_ea(FC_ADDR); -// gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } else { - if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); - else gen_call_function_raw((void*)&dynrec_pop_word); - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); - } -} - - -static void dyn_segprefix(Bit8u seg) { -// if (GCC_UNLIKELY(decode.seg_prefix_used)) IllegalOptionDynrec("dyn_segprefix"); - decode.seg_prefix=seg; - decode.seg_prefix_used=true; -} - - static void dyn_mov_seg_ev(void) { - dyn_get_modrm(); - if (GCC_UNLIKELY(decode.modrm.reg==DRC_SEG_CS)) IllegalOptionDynrec("dyn_mov_seg_ev"); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_RETOP,false); - } else { - MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); - } - gen_call_function_IR((void *)&CPU_SetSegGeneral,decode.modrm.reg,FC_RETOP); - dyn_check_exception(FC_RETOP); -} - -static void dyn_load_seg_off_ea(Bit8u seg) { - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - gen_protect_reg(FC_OP1); - - gen_restore_addr_reg(); - gen_add_imm(FC_ADDR,decode.big_op ? 4:2); - dyn_read_word(FC_ADDR,FC_RETOP,false); - - gen_call_function_IR((void *)&CPU_SetSegGeneral,seg,FC_RETOP); - dyn_check_exception(FC_RETOP); - - gen_restore_reg(FC_OP1); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); - } else { - IllegalOptionDynrec("dyn_load_seg_off_ea"); - } -} - - - -static void dyn_imul_gvev(Bitu immsize) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } - - switch (immsize) { - case 0: - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - break; - case 1: - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit8s)decode_fetchb()); - else gen_mov_word_to_reg_imm(FC_OP2,(Bit8s)decode_fetchb()); - break; - case 2: - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit16s)decode_fetchw()); - else gen_mov_word_to_reg_imm(FC_OP2,(Bit16s)decode_fetchw()); - break; - case 4: - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32s)decode_fetchd()); - else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)((Bit32s)decode_fetchd())); - break; - } - - if (decode.big_op) gen_call_function_raw((void*)dynrec_dimul_dword); - else gen_call_function_raw((void*)dynrec_dimul_word); - - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op); -} - -static void dyn_dshift_ev_gv(bool left,bool immediate) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } - MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - if (immediate) gen_mov_byte_to_reg_low_imm(FC_OP3,decode_fetchb()); - else MOV_REG_BYTE_TO_HOST_REG_LOW(FC_OP3,DRC_REG_ECX,0); - if (decode.big_op) dyn_dpshift_dword_gencall(left); - else dyn_dpshift_word_gencall(left); - - if (decode.modrm.mod<3) { - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } else { - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); - } -} - - -static void dyn_grp1_eb_ib(void) { - dyn_get_modrm(); - DualOps op=grp1_table[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_byte_canuseword(FC_ADDR,FC_OP1); - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb()); - dyn_dop_byte_gencall(op); - - if ((op!=DOP_CMP) && (op!=DOP_TEST)) { - gen_restore_addr_reg(); - dyn_write_byte(FC_ADDR,FC_RETOP); - } - } else { - dyn_dop_byte_imm_mem(op,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_grp1_ev_iv(bool withbyte) { - dyn_get_modrm(); - DualOps op=grp1_table[decode.modrm.reg]; - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - - if (!withbyte) { - dyn_prep_word_imm(FC_OP2); - } else { - Bits imm=(Bit8s)decode_fetchb(); - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm); - else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)imm); - } - - dyn_dop_word_gencall(op,decode.big_op); - - if ((op!=DOP_CMP) && (op!=DOP_TEST)) { - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } - } else { - if (!withbyte) { - dyn_dop_word_imm(op,decode.modrm.rm); - } else { - Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw()); - dyn_dop_word_imm_old(op,decode.modrm.rm,imm); - } - } -} - - -static void dyn_grp2_eb(grp2_types type) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_byte_canuseword(FC_ADDR,FC_OP1); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } - switch (type) { - case grp2_1: - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,1); - dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg); - break; - case grp2_imm: { - Bit8u imm=decode_fetchb(); - if (imm) { - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,imm&0x1f); - dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg); - } else return; - } - break; - case grp2_cl: - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,DRC_REG_ECX,0); - gen_and_imm(FC_OP2,0x1f); - dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg); - break; - } - if (decode.modrm.mod<3) { - gen_restore_addr_reg(); - dyn_write_byte(FC_ADDR,FC_RETOP); - } else { - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_grp2_ev(grp2_types type) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } - switch (type) { - case grp2_1: - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,1); - dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); - break; - case grp2_imm: { - Bitu val; - if (decode_fetchb_imm(val)) { - gen_mov_byte_to_reg_low_canuseword(FC_OP2,(void*)val); - gen_and_imm(FC_OP2,0x1f); - dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); - break; - } - Bit8u imm=(Bit8u)val; - if (imm) { - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,imm&0x1f); - dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); - } else return; - } - break; - case grp2_cl: - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,DRC_REG_ECX,0); - gen_and_imm(FC_OP2,0x1f); - dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); - break; - } - if (decode.modrm.mod<3) { - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } else { - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); - } -} - - -static void dyn_grp3_eb(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - if ((decode.modrm.reg==2) || (decode.modrm.reg==3)) gen_protect_addr_reg(); - dyn_read_byte_canuseword(FC_ADDR,FC_OP1); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } - switch (decode.modrm.reg) { - case 0x0: // test eb,ib - gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb()); - dyn_dop_byte_gencall(DOP_TEST); - return; - case 0x2: // NOT Eb - dyn_sop_byte_gencall(SOP_NOT); - break; - case 0x3: // NEG Eb - dyn_sop_byte_gencall(SOP_NEG); - break; - case 0x4: // mul Eb - gen_call_function_raw((void*)&dynrec_mul_byte); - return; - case 0x5: // imul Eb - gen_call_function_raw((void*)&dynrec_imul_byte); - return; - case 0x6: // div Eb - gen_call_function_raw((void*)&dynrec_div_byte); - dyn_check_exception(FC_RETOP); - return; - case 0x7: // idiv Eb - gen_call_function_raw((void*)&dynrec_idiv_byte); - dyn_check_exception(FC_RETOP); - return; - } - // Save the result if memory op - if (decode.modrm.mod<3) { - gen_restore_addr_reg(); - dyn_write_byte(FC_ADDR,FC_RETOP); - } else { - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} - -static void dyn_grp3_ev(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - if ((decode.modrm.reg==2) || (decode.modrm.reg==3)) gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } - switch (decode.modrm.reg) { - case 0x0: // test ev,iv - if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,decode_fetchd()); - else gen_mov_word_to_reg_imm(FC_OP2,decode_fetchw()); - dyn_dop_word_gencall(DOP_TEST,decode.big_op); - return; - case 0x2: // NOT Ev - dyn_sop_word_gencall(SOP_NOT,decode.big_op); - break; - case 0x3: // NEG Eb - dyn_sop_word_gencall(SOP_NEG,decode.big_op); - break; - case 0x4: // mul Eb - if (decode.big_op) gen_call_function_raw((void*)&dynrec_mul_dword); - else gen_call_function_raw((void*)&dynrec_mul_word); - return; - case 0x5: // imul Eb - if (decode.big_op) gen_call_function_raw((void*)&dynrec_imul_dword); - else gen_call_function_raw((void*)&dynrec_imul_word); - return; - case 0x6: // div Eb - if (decode.big_op) gen_call_function_raw((void*)&dynrec_div_dword); - else gen_call_function_raw((void*)&dynrec_div_word); - dyn_check_exception(FC_RETOP); - return; - case 0x7: // idiv Eb - if (decode.big_op) gen_call_function_raw((void*)&dynrec_idiv_dword); - else gen_call_function_raw((void*)&dynrec_idiv_word); - dyn_check_exception(FC_RETOP); - return; - } - // Save the result if memory op - if (decode.modrm.mod<3) { - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } else { - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); - } -} - - -static bool dyn_grp4_eb(void) { - dyn_get_modrm(); - switch (decode.modrm.reg) { - case 0x0://INC Eb - case 0x1://DEC Eb - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_byte_canuseword(FC_ADDR,FC_OP1); - dyn_sop_byte_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC); - gen_restore_addr_reg(); - dyn_write_byte(FC_ADDR,FC_RETOP); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - dyn_sop_byte_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC); - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } - break; - case 0x7: //CALBACK Iw - gen_mov_direct_dword(&core_dynrec.callback,decode_fetchw()); - dyn_set_eip_end(); - dyn_reduce_cycles(); - dyn_return(BR_CallBack); - dyn_closeblock(); - return true; - default: - IllegalOptionDynrec("dyn_grp4_eb"); - break; - } - return false; -} - -static Bitu dyn_grp4_ev(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - if ((decode.modrm.reg<2) || (decode.modrm.reg==3) || (decode.modrm.reg==5)) gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); - } else { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); - } - switch (decode.modrm.reg) { - case 0x0://INC Ev - case 0x1://DEC Ev - dyn_sop_word_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op); - if (decode.modrm.mod<3) { - gen_restore_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); - } else { - MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); - } - break; - case 0x2: // CALL Ev - gen_mov_regs(FC_ADDR,FC_OP1); - gen_protect_addr_reg(); - gen_mov_word_to_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); - gen_add_imm(FC_OP1,(Bit32u)(decode.code-decode.code_start)); - if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); - else gen_call_function_raw((void*)&dynrec_push_word); - - gen_restore_addr_reg(); - gen_mov_word_from_reg(FC_ADDR,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); - return 1; - case 0x4: // JMP Ev - gen_mov_word_from_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); - return 1; - case 0x3: // CALL Ep - case 0x5: // JMP Ep - if (!decode.big_op) gen_extend_word(false,FC_OP1); - if (decode.modrm.mod<3) gen_restore_addr_reg(); - gen_protect_reg(FC_OP1); - gen_add_imm(FC_ADDR,decode.big_op?4:2); - dyn_read_word(FC_ADDR,FC_OP2,decode.big_op); - gen_extend_word(false,FC_OP2); - - dyn_set_eip_last_end(FC_RETOP); - gen_restore_reg(FC_OP1,FC_ADDR); - gen_call_function_IRRR(decode.modrm.reg == 3 ? (void*)(&CPU_CALL) : (void*)(&CPU_JMP), - decode.big_op,FC_OP2,FC_ADDR,FC_RETOP); - return 1; - case 0x6: // PUSH Ev - if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); - else gen_call_function_raw((void*)&dynrec_push_word); - break; - default: -// IllegalOptionDynrec("dyn_grp4_ev"); - return 2; - } - return 0; -} - - -static bool dyn_grp6(void) { - dyn_get_modrm(); - switch (decode.modrm.reg) { - case 0x00: // SLDT - case 0x01: // STR - if (decode.modrm.reg==0) gen_call_function_raw((void*)CPU_SLDT); - else gen_call_function_raw((void*)CPU_STR); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_write_word(FC_ADDR,FC_RETOP,false); - } else { - MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,decode.modrm.rm); - } - break; - case 0x02: // LLDT - case 0x03: // LTR - case 0x04: // VERR - case 0x05: // VERW - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_RETOP,false); - } else { - MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); - } - gen_extend_word(false,FC_RETOP); - switch (decode.modrm.reg) { - case 0x02: // LLDT -// if (cpu.cpl) return CPU_PrepareException(EXCEPTION_GP,0); - if (cpu.cpl) E_Exit("lldt cpl>0"); - gen_call_function_R((void*)CPU_LLDT,FC_RETOP); - dyn_check_exception(FC_RETOP); - break; - case 0x03: // LTR -// if (cpu.cpl) return CPU_PrepareException(EXCEPTION_GP,0); - if (cpu.cpl) E_Exit("ltr cpl>0"); - gen_call_function_R((void*)CPU_LTR,FC_RETOP); - dyn_check_exception(FC_RETOP); - break; - case 0x04: // VERR - gen_call_function_R((void*)CPU_VERR,FC_RETOP); - break; - case 0x05: // VERW - gen_call_function_R((void*)CPU_VERW,FC_RETOP); - break; - } - break; - default: IllegalOptionDynrec("dyn_grp6"); - } - return false; -} - -static bool dyn_grp7(void) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - switch (decode.modrm.reg) { - case 0x00: // SGDT - gen_call_function_raw((void*)CPU_SGDT_limit); - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,false); - gen_call_function_raw((void*)CPU_SGDT_base); - gen_restore_addr_reg(); - gen_add_imm(FC_ADDR,2); - dyn_write_word(FC_ADDR,FC_RETOP,true); - break; - case 0x01: // SIDT - gen_call_function_raw((void*)CPU_SIDT_limit); - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_write_word(FC_ADDR,FC_RETOP,false); - gen_call_function_raw((void*)CPU_SIDT_base); - gen_restore_addr_reg(); - gen_add_imm(FC_ADDR,2); - dyn_write_word(FC_ADDR,FC_RETOP,true); - break; - case 0x02: // LGDT - case 0x03: // LIDT -// if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); - if (cpu.pmode && cpu.cpl) IllegalOptionDynrec("lgdt nonpriviledged"); - dyn_fill_ea(FC_ADDR); - gen_protect_addr_reg(); - dyn_read_word(FC_ADDR,FC_OP1,false); - gen_extend_word(false,FC_OP1); - gen_protect_reg(FC_OP1); - - gen_restore_addr_reg(); - gen_add_imm(FC_ADDR,2); - dyn_read_word(FC_ADDR,FC_OP2,true); - if (!decode.big_op) gen_and_imm(FC_OP2,0xffffff); - - gen_restore_reg(FC_OP1); - if (decode.modrm.reg==2) gen_call_function_RR((void*)CPU_LGDT,FC_OP1,FC_OP2); - else gen_call_function_RR((void*)CPU_LIDT,FC_OP1,FC_OP2); - break; - case 0x04: // SMSW - gen_call_function_raw((void*)CPU_SMSW); - dyn_fill_ea(FC_ADDR); - dyn_write_word(FC_ADDR,FC_RETOP,false); - break; - case 0x06: // LMSW - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_RETOP,false); - gen_call_function_R((void*)CPU_LMSW,FC_RETOP); - dyn_check_exception(FC_RETOP); - dyn_set_eip_end(); - dyn_reduce_cycles(); - dyn_return(BR_Normal); - dyn_closeblock(); - return true; - case 0x07: // INVLPG -// if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); - if (cpu.pmode && cpu.cpl) IllegalOptionDynrec("invlpg nonpriviledged"); - gen_call_function_raw((void*)PAGING_ClearTLB); - break; - default: IllegalOptionDynrec("dyn_grp7_1"); - } - } else { - switch (decode.modrm.reg) { - case 0x04: // SMSW - gen_call_function_raw((void*)CPU_SMSW); - MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,decode.modrm.rm); - break; - case 0x06: // LMSW - MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); - gen_call_function_R((void*)CPU_LMSW,FC_RETOP); - dyn_check_exception(FC_RETOP); - dyn_set_eip_end(); - dyn_reduce_cycles(); - dyn_return(BR_Normal); - dyn_closeblock(); - return true; - default: IllegalOptionDynrec("dyn_grp7_2"); - } - } - return false; -} - - -/* -static void dyn_larlsl(bool is_lar) { - dyn_get_modrm(); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_read_word(FC_ADDR,FC_RETOP,false); - } else { - MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); - } - gen_extend_word(false,FC_RETOP); - if (is_lar) gen_call_function((void*)CPU_LAR,"%R%A",FC_RETOP,(DRC_PTR_SIZE_IM)&core_dynrec.readdata); - else gen_call_function((void*)CPU_LSL,"%R%A",FC_RETOP,(DRC_PTR_SIZE_IM)&core_dynrec.readdata); - DRC_PTR_SIZE_IM brnz=gen_create_branch_on_nonzero(FC_RETOP,true); - gen_mov_word_to_reg(FC_OP2,&core_dynrec.readdata,true); - MOV_REG_WORD_FROM_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); - gen_fill_branch(brnz); -} -*/ - - -static void dyn_mov_from_crx(void) { - dyn_get_modrm(); - gen_call_function_IA((void*)CPU_READ_CRX,decode.modrm.reg,(DRC_PTR_SIZE_IM)&core_dynrec.readdata); - dyn_check_exception(FC_RETOP); - gen_mov_word_to_reg(FC_OP2,&core_dynrec.readdata,true); - MOV_REG_WORD32_FROM_HOST_REG(FC_OP2,decode.modrm.rm); -} - -static void dyn_mov_to_crx(void) { - dyn_get_modrm(); - MOV_REG_WORD32_TO_HOST_REG(FC_RETOP,decode.modrm.rm); - gen_call_function_IR((void*)CPU_WRITE_CRX,decode.modrm.reg,FC_RETOP); - dyn_check_exception(FC_RETOP); - dyn_set_eip_end(); - dyn_reduce_cycles(); - dyn_return(BR_Normal); - dyn_closeblock(); -} - - -static void dyn_cbw(void) { - if (decode.big_op) { - MOV_REG_WORD16_TO_HOST_REG(FC_OP1,DRC_REG_EAX); - gen_call_function_raw((void *)&dynrec_cwde); - MOV_REG_WORD32_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX); - } else { - MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,DRC_REG_EAX,0); - gen_call_function_raw((void *)&dynrec_cbw); - MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX); - } -} - -static void dyn_cwd(void) { - MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); - if (decode.big_op) { - gen_call_function_raw((void *)&dynrec_cdq); - MOV_REG_WORD32_FROM_HOST_REG(FC_RETOP,DRC_REG_EDX); - } else { - gen_call_function_raw((void *)&dynrec_cwd); - MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,DRC_REG_EDX); - } -} - -static void dyn_sahf(void) { - MOV_REG_WORD16_TO_HOST_REG(FC_OP1,DRC_REG_EAX); - gen_call_function_raw((void *)&dynrec_sahf); - InvalidateFlags(); -} - - -static void dyn_exit_link(Bits eip_change) { - gen_add_direct_word(®_eip,(decode.code-decode.code_start)+eip_change,decode.big_op); - dyn_reduce_cycles(); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); - dyn_closeblock(); -} - - -static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) { - Bitu eip_base=decode.code-decode.code_start; - dyn_reduce_cycles(); - - dyn_branchflag_to_reg(btype); - DRC_PTR_SIZE_IM data=gen_create_branch_on_nonzero(FC_RETOP,true); - - // Branch not taken - gen_add_direct_word(®_eip,eip_base,decode.big_op); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); - gen_fill_branch(data); - - // Branch taken - gen_add_direct_word(®_eip,eip_base+eip_add,decode.big_op); - gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlockDynRec,cache.start)); - dyn_closeblock(); -} - -/* -static void dyn_set_byte_on_condition(BranchTypes btype) { - dyn_get_modrm(); - dyn_branchflag_to_reg(btype); - gen_and_imm(FC_RETOP,1); - if (decode.modrm.mod<3) { - dyn_fill_ea(FC_ADDR); - dyn_write_byte(FC_ADDR,FC_RETOP); - } else { - MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); - } -} -*/ - -static void dyn_loop(LoopTypes type) { - dyn_reduce_cycles(); - Bits eip_add=(Bit8s)decode_fetchb(); - Bitu eip_base=decode.code-decode.code_start; - DRC_PTR_SIZE_IM branch1=0; - DRC_PTR_SIZE_IM branch2=0; - switch (type) { - case LOOP_E: - dyn_branchflag_to_reg(BR_NZ); - branch1=gen_create_branch_on_nonzero(FC_RETOP,true); - break; - case LOOP_NE: - dyn_branchflag_to_reg(BR_Z); - branch1=gen_create_branch_on_nonzero(FC_RETOP,true); - break; - } - switch (type) { - case LOOP_E: - case LOOP_NE: - case LOOP_NONE: - MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); - gen_add_imm(FC_OP1,(Bit32u)(-1)); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); - branch2=gen_create_branch_on_zero(FC_OP1,decode.big_addr); - break; - case LOOP_JCXZ: - MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); - branch2=gen_create_branch_on_nonzero(FC_OP1,decode.big_addr); - break; - } - gen_add_direct_word(®_eip,eip_base+eip_add,true); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); - if (branch1) { - gen_fill_branch(branch1); - MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); - gen_add_imm(FC_OP1,(Bit32u)(-1)); - MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); - } - // Branch taken - gen_fill_branch(branch2); - gen_add_direct_word(®_eip,eip_base,decode.big_op); - gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlockDynRec,cache.start)); - dyn_closeblock(); -} - - -static void dyn_ret_near(Bitu bytes) { - dyn_reduce_cycles(); - - if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); - else { - gen_call_function_raw((void*)&dynrec_pop_word); - gen_extend_word(false,FC_RETOP); - } - gen_mov_word_from_reg(FC_RETOP,decode.big_op?(void*)(®_eip):(void*)(®_ip),true); - - if (bytes) gen_add_direct_word(®_esp,bytes,true); - dyn_return(BR_Normal); - dyn_closeblock(); -} - -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(FC_OP1); - if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); - else gen_call_function_raw((void*)&dynrec_push_word); - - dyn_set_eip_end(FC_OP1,imm); - gen_mov_word_from_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); - - dyn_reduce_cycles(); - gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); - dyn_closeblock(); -} - -static void dyn_ret_far(Bitu bytes) { - dyn_reduce_cycles(); - dyn_set_eip_last_end(FC_RETOP); - gen_call_function_IIR((void*)&CPU_RET,decode.big_op,bytes,FC_RETOP); - dyn_return(BR_Normal); - dyn_closeblock(); -} - -static void dyn_call_far_imm(void) { - Bitu sel,off; - off=decode.big_op ? decode_fetchd() : decode_fetchw(); - sel=decode_fetchw(); - dyn_reduce_cycles(); - dyn_set_eip_last_end(FC_RETOP); - gen_call_function_IIIR((void*)&CPU_CALL,decode.big_op,sel,off,FC_RETOP); - dyn_return(BR_Normal); - dyn_closeblock(); -} - -static void dyn_jmp_far_imm(void) { - Bitu sel,off; - off=decode.big_op ? decode_fetchd() : decode_fetchw(); - sel=decode_fetchw(); - dyn_reduce_cycles(); - dyn_set_eip_last_end(FC_RETOP); - gen_call_function_IIIR((void*)&CPU_JMP,decode.big_op,sel,off,FC_RETOP); - dyn_return(BR_Normal); - dyn_closeblock(); -} - -static void dyn_iret(void) { - dyn_reduce_cycles(); - dyn_set_eip_last_end(FC_RETOP); - gen_call_function_IR((void*)&CPU_IRET,decode.big_op,FC_RETOP); - dyn_return(BR_Iret); - dyn_closeblock(); -} - -static void dyn_interrupt(Bit8u num) { - dyn_reduce_cycles(); - dyn_set_eip_last_end(FC_RETOP); - gen_call_function_IIR((void*)&CPU_Interrupt,num,CPU_INT_SOFTWARE,FC_RETOP); - dyn_return(BR_Normal); - dyn_closeblock(); -} - - - -static void dyn_string(StringOps op) { - if (decode.rep) MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); - else gen_mov_dword_to_reg_imm(FC_OP1,1); - gen_mov_word_to_reg(FC_OP2,&cpu.direction,true); - Bit8u di_base_addr=decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS; - switch (op) { - case STR_MOVSB: - if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsb_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - else gen_call_function_mm((void*)&dynrec_movsb_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - break; - case STR_MOVSW: - if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsw_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - else gen_call_function_mm((void*)&dynrec_movsw_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - break; - case STR_MOVSD: - if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsd_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - else gen_call_function_mm((void*)&dynrec_movsd_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - break; - - case STR_LODSB: - if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsb_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr)); - else gen_call_function_m((void*)&dynrec_lodsb_word,(Bitu)DRCD_SEG_PHYS(di_base_addr)); - break; - case STR_LODSW: - if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsw_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr)); - else gen_call_function_m((void*)&dynrec_lodsw_word,(Bitu)DRCD_SEG_PHYS(di_base_addr)); - break; - case STR_LODSD: - if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsd_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr)); - else gen_call_function_m((void*)&dynrec_lodsd_word,(Bitu)DRCD_SEG_PHYS(di_base_addr)); - break; - - case STR_STOSB: - if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosb_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - else gen_call_function_m((void*)&dynrec_stosb_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - break; - case STR_STOSW: - if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosw_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - else gen_call_function_m((void*)&dynrec_stosw_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - break; - case STR_STOSD: - if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosd_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - else gen_call_function_m((void*)&dynrec_stosd_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); - break; - default: IllegalOptionDynrec("dyn_string"); - } - if (decode.rep) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,DRC_REG_ECX,decode.big_addr); - - if (op>2)&1); + dyn_dop_byte_gencall(op); + + if ((op!=DOP_CMP) && (op!=DOP_TEST)) { + gen_restore_addr_reg(); + dyn_write_byte(FC_ADDR,FC_RETOP); + } + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + dyn_dop_byte_gencall(op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_dop_ebgb_mov(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + dyn_write_byte(FC_ADDR,FC_TMP_BA1); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_dop_ebib_mov(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,decode_fetchb()); + dyn_write_byte(FC_ADDR,FC_TMP_BA1); + } else { + gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,decode_fetchb()); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_dop_ebgb_xchg(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_byte(FC_ADDR,FC_TMP_BA1); + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + gen_restore_addr_reg(); + dyn_write_byte(FC_ADDR,FC_TMP_BA2); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA2,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_dop_gbeb(DualOps op) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_byte_canuseword(FC_ADDR,FC_OP2); + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + dyn_dop_byte_gencall(op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + dyn_dop_byte_gencall(op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + } +} + +static void dyn_dop_gbeb_mov(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_byte(FC_ADDR,FC_TMP_BA1); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.reg&3,(decode.modrm.reg>>2)&1); + } +} + +static void dyn_dop_evgv(DualOps op) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + gen_protect_addr_reg(); + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + dyn_dop_word_gencall(op,decode.big_op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) { + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + dyn_dop_word_gencall(op,decode.big_op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); + } +} + +static void dyn_dop_evgv_mov(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + dyn_write_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } +} + +static void dyn_dop_eviv_mov(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,decode_fetchd()); + else gen_mov_word_to_reg_imm(FC_OP1,decode_fetchw()); + dyn_write_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,decode_fetchd()); + else gen_mov_word_to_reg_imm(FC_OP1,decode_fetchw()); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } +} + +static void dyn_dop_evgv_xchg(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + + gen_protect_reg(FC_OP1); + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_OP2,decode.big_op); + gen_restore_reg(FC_OP1); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP2,decode.modrm.rm,decode.big_op); + } +} + +static void dyn_xchg_ax(Bit8u reg) { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); + MOV_REG_WORD_TO_HOST_REG(FC_OP2,reg,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,reg,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP2,DRC_REG_EAX,decode.big_op); +} + +static void dyn_dop_gvev(DualOps op) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP2,decode.big_op); + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + dyn_dop_word_gencall(op,decode.big_op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) { + gen_restore_addr_reg(); + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op); + } + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.rm,decode.big_op); + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + dyn_dop_word_gencall(op,decode.big_op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op); + } +} + +static void dyn_dop_gvev_mov(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + } +} + +static void dyn_dop_byte_imm(DualOps op,Bit8u reg,Bit8u idx) { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,reg,idx); + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb()); + dyn_dop_byte_gencall(op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,reg,idx); +} + +static void dyn_dop_byte_imm_mem(DualOps op,Bit8u reg,Bit8u idx) { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,reg,idx); + Bitu val; + if (decode_fetchb_imm(val)) { + gen_mov_byte_to_reg_low_canuseword(FC_OP2,(void*)val); + } else { + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,(Bit8u)val); + } + dyn_dop_byte_gencall(op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,reg,idx); +} + +static void dyn_prep_word_imm(Bit8u reg) { + Bitu val; + if (decode.big_op) { + if (decode_fetchd_imm(val)) { + gen_mov_word_to_reg(FC_OP2,(void*)val,true); + return; + } + } else { + if (decode_fetchw_imm(val)) { + gen_mov_word_to_reg(FC_OP2,(void*)val,false); + return; + } + } + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)val); + else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)val); +} + +static void dyn_dop_word_imm(DualOps op,Bit8u reg) { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); + dyn_prep_word_imm(reg); + dyn_dop_word_gencall(op,decode.big_op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); +} + +static void dyn_dop_word_imm_old(DualOps op,Bit8u reg,Bitu imm) { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm); + else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)imm); + dyn_dop_word_gencall(op,decode.big_op); + if ((op!=DOP_CMP) && (op!=DOP_TEST)) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); +} + +static void dyn_mov_byte_imm(Bit8u reg,Bit8u idx,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(FC_TMP_BA1,imm); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,reg,idx); +} + +static void dyn_mov_word_imm(Bit8u reg) { + Bitu val; + if (decode.big_op) { + if (decode_fetchd_imm(val)) { + gen_mov_word_to_reg(FC_OP1,(void*)val,true); + MOV_REG_WORD32_FROM_HOST_REG(FC_OP1,reg); + return; + } + } else { + if (decode_fetchw_imm(val)) { + gen_mov_word_to_reg(FC_OP1,(void*)val,false); + MOV_REG_WORD16_FROM_HOST_REG(FC_OP1,reg); + return; + } + } + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)val); + else gen_mov_word_to_reg_imm(FC_OP1,(Bit16u)val); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,reg,decode.big_op); +} + + +static void dyn_sop_word(SingleOps op,Bit8u reg) { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); + dyn_sop_word_gencall(op,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); +} + + +static void dyn_mov_byte_al_direct(Bitu imm) { + MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); + gen_add_imm(FC_ADDR,imm); + dyn_read_byte(FC_ADDR,FC_TMP_BA1); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_TMP_BA1,DRC_REG_EAX,0); +} + +static void dyn_mov_byte_ax_direct(Bitu imm) { + MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); + gen_add_imm(FC_ADDR,imm); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); +} + +static void dyn_mov_byte_direct_al() { + MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); + if (decode.big_addr) { + Bitu val; + if (decode_fetchd_imm(val)) { + gen_add(FC_ADDR,(void*)val); + } else { + gen_add_imm(FC_ADDR,(Bit32u)val); + } + } else { + gen_add_imm(FC_ADDR,decode_fetchw()); + } + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,DRC_REG_EAX,0); + dyn_write_byte(FC_ADDR,FC_TMP_BA1); +} + +static void dyn_mov_byte_direct_ax(Bitu imm) { + MOV_SEG_PHYS_TO_HOST_REG(FC_ADDR,(decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS)); + gen_add_imm(FC_ADDR,imm); + MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); + dyn_write_word(FC_ADDR,FC_OP1,decode.big_op); +} + + +static void dyn_movx_ev_gb(bool sign) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_byte(FC_ADDR,FC_TMP_BA1); + gen_extend_byte(sign,FC_TMP_BA1); + MOV_REG_WORD_FROM_HOST_REG(FC_TMP_BA1,decode.modrm.reg,decode.big_op); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW(FC_TMP_BA1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + gen_extend_byte(sign,FC_TMP_BA1); + MOV_REG_WORD_FROM_HOST_REG(FC_TMP_BA1,decode.modrm.reg,decode.big_op); + } +} + +static void dyn_movx_ev_gw(bool sign) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_OP1,false); + gen_extend_word(sign,FC_OP1); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + } else { + MOV_REG_WORD16_TO_HOST_REG(FC_OP1,decode.modrm.rm); + gen_extend_word(sign,FC_OP1); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + } +} + + +static void dyn_mov_ev_seg(void) { + dyn_get_modrm(); + MOV_SEG_VAL_TO_HOST_REG(FC_OP1,decode.modrm.reg); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_write_word(FC_ADDR,FC_OP1,false); + } else { + if (decode.big_op) gen_extend_word(false,FC_OP1); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } +} + + +static void dyn_lea(void) { + dyn_get_modrm(); + dyn_fill_ea(FC_ADDR,false); + MOV_REG_WORD_FROM_HOST_REG(FC_ADDR,decode.modrm.reg,decode.big_op); +} + + +static void dyn_push_seg(Bit8u seg) { + MOV_SEG_VAL_TO_HOST_REG(FC_OP1,seg); + if (decode.big_op) { + gen_extend_word(false,FC_OP1); + gen_call_function_raw((void*)&dynrec_push_dword); + } else { + gen_call_function_raw((void*)&dynrec_push_word); + } +} + +static void dyn_pop_seg(Bit8u seg) { + gen_call_function_II((void *)&CPU_PopSeg,seg,decode.big_op); + dyn_check_exception(FC_RETOP); +} + +static void dyn_push_reg(Bit8u reg) { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,reg,decode.big_op); + if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); + else gen_call_function_raw((void*)&dynrec_push_word); +} + +static void dyn_pop_reg(Bit8u reg) { + if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); + else gen_call_function_raw((void*)&dynrec_pop_word); + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,reg,decode.big_op); +} + +static void dyn_push_byte_imm(Bit8s imm) { + gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm); + if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); + else gen_call_function_raw((void*)&dynrec_push_word); +} + +static void dyn_push_word_imm(Bitu imm) { + if (decode.big_op) { + gen_mov_dword_to_reg_imm(FC_OP1,imm); + gen_call_function_raw((void*)&dynrec_push_dword); + } else { + gen_mov_word_to_reg_imm(FC_OP1,(Bit16u)imm); + gen_call_function_raw((void*)&dynrec_push_word); + } +} + +static void dyn_pop_ev(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { +/* dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); // dummy read to trigger possible page faults */ + if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); + else gen_call_function_raw((void*)&dynrec_pop_word); + dyn_fill_ea(FC_ADDR); +// gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } else { + if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); + else gen_call_function_raw((void*)&dynrec_pop_word); + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); + } +} + + +static void dyn_segprefix(Bit8u seg) { +// if (GCC_UNLIKELY(decode.seg_prefix_used)) IllegalOptionDynrec("dyn_segprefix"); + decode.seg_prefix=seg; + decode.seg_prefix_used=true; +} + + static void dyn_mov_seg_ev(void) { + dyn_get_modrm(); + if (GCC_UNLIKELY(decode.modrm.reg==DRC_SEG_CS)) IllegalOptionDynrec("dyn_mov_seg_ev"); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_RETOP,false); + } else { + MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); + } + gen_call_function_IR((void *)&CPU_SetSegGeneral,decode.modrm.reg,FC_RETOP); + dyn_check_exception(FC_RETOP); +} + +static void dyn_load_seg_off_ea(Bit8u seg) { + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + gen_protect_reg(FC_OP1); + + gen_restore_addr_reg(); + gen_add_imm(FC_ADDR,decode.big_op ? 4:2); + dyn_read_word(FC_ADDR,FC_RETOP,false); + + gen_call_function_IR((void *)&CPU_SetSegGeneral,seg,FC_RETOP); + dyn_check_exception(FC_RETOP); + + gen_restore_reg(FC_OP1); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,decode.modrm.reg,decode.big_op); + } else { + IllegalOptionDynrec("dyn_load_seg_off_ea"); + } +} + + + +static void dyn_imul_gvev(Bitu immsize) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } + + switch (immsize) { + case 0: + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + break; + case 1: + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit8s)decode_fetchb()); + else gen_mov_word_to_reg_imm(FC_OP2,(Bit8s)decode_fetchb()); + break; + case 2: + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit16s)decode_fetchw()); + else gen_mov_word_to_reg_imm(FC_OP2,(Bit16s)decode_fetchw()); + break; + case 4: + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32s)decode_fetchd()); + else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)((Bit32s)decode_fetchd())); + break; + } + + if (decode.big_op) gen_call_function_raw((void*)dynrec_dimul_dword); + else gen_call_function_raw((void*)dynrec_dimul_word); + + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.reg,decode.big_op); +} + +static void dyn_dshift_ev_gv(bool left,bool immediate) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } + MOV_REG_WORD_TO_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + if (immediate) gen_mov_byte_to_reg_low_imm(FC_OP3,decode_fetchb()); + else MOV_REG_BYTE_TO_HOST_REG_LOW(FC_OP3,DRC_REG_ECX,0); + if (decode.big_op) dyn_dpshift_dword_gencall(left); + else dyn_dpshift_word_gencall(left); + + if (decode.modrm.mod<3) { + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } else { + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); + } +} + + +static void dyn_grp1_eb_ib(void) { + dyn_get_modrm(); + DualOps op=grp1_table[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_byte_canuseword(FC_ADDR,FC_OP1); + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb()); + dyn_dop_byte_gencall(op); + + if ((op!=DOP_CMP) && (op!=DOP_TEST)) { + gen_restore_addr_reg(); + dyn_write_byte(FC_ADDR,FC_RETOP); + } + } else { + dyn_dop_byte_imm_mem(op,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_grp1_ev_iv(bool withbyte) { + dyn_get_modrm(); + DualOps op=grp1_table[decode.modrm.reg]; + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + + if (!withbyte) { + dyn_prep_word_imm(FC_OP2); + } else { + Bits imm=(Bit8s)decode_fetchb(); + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm); + else gen_mov_word_to_reg_imm(FC_OP2,(Bit16u)imm); + } + + dyn_dop_word_gencall(op,decode.big_op); + + if ((op!=DOP_CMP) && (op!=DOP_TEST)) { + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } + } else { + if (!withbyte) { + dyn_dop_word_imm(op,decode.modrm.rm); + } else { + Bits imm=withbyte ? (Bit8s)decode_fetchb() : (decode.big_op ? decode_fetchd(): decode_fetchw()); + dyn_dop_word_imm_old(op,decode.modrm.rm,imm); + } + } +} + + +static void dyn_grp2_eb(grp2_types type) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_byte_canuseword(FC_ADDR,FC_OP1); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } + switch (type) { + case grp2_1: + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,1); + dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg); + break; + case grp2_imm: { + Bit8u imm=decode_fetchb(); + if (imm) { + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,imm&0x1f); + dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg); + } else return; + } + break; + case grp2_cl: + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,DRC_REG_ECX,0); + gen_and_imm(FC_OP2,0x1f); + dyn_shift_byte_gencall((ShiftOps)decode.modrm.reg); + break; + } + if (decode.modrm.mod<3) { + gen_restore_addr_reg(); + dyn_write_byte(FC_ADDR,FC_RETOP); + } else { + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_grp2_ev(grp2_types type) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } + switch (type) { + case grp2_1: + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,1); + dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); + break; + case grp2_imm: { + Bitu val; + if (decode_fetchb_imm(val)) { + gen_mov_byte_to_reg_low_canuseword(FC_OP2,(void*)val); + gen_and_imm(FC_OP2,0x1f); + dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); + break; + } + Bit8u imm=(Bit8u)val; + if (imm) { + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,imm&0x1f); + dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); + } else return; + } + break; + case grp2_cl: + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP2,DRC_REG_ECX,0); + gen_and_imm(FC_OP2,0x1f); + dyn_shift_word_gencall((ShiftOps)decode.modrm.reg,decode.big_op); + break; + } + if (decode.modrm.mod<3) { + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } else { + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); + } +} + + +static void dyn_grp3_eb(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + if ((decode.modrm.reg==2) || (decode.modrm.reg==3)) gen_protect_addr_reg(); + dyn_read_byte_canuseword(FC_ADDR,FC_OP1); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } + switch (decode.modrm.reg) { + case 0x0: // test eb,ib + gen_mov_byte_to_reg_low_imm_canuseword(FC_OP2,decode_fetchb()); + dyn_dop_byte_gencall(DOP_TEST); + return; + case 0x2: // NOT Eb + dyn_sop_byte_gencall(SOP_NOT); + break; + case 0x3: // NEG Eb + dyn_sop_byte_gencall(SOP_NEG); + break; + case 0x4: // mul Eb + gen_call_function_raw((void*)&dynrec_mul_byte); + return; + case 0x5: // imul Eb + gen_call_function_raw((void*)&dynrec_imul_byte); + return; + case 0x6: // div Eb + gen_call_function_raw((void*)&dynrec_div_byte); + dyn_check_exception(FC_RETOP); + return; + case 0x7: // idiv Eb + gen_call_function_raw((void*)&dynrec_idiv_byte); + dyn_check_exception(FC_RETOP); + return; + } + // Save the result if memory op + if (decode.modrm.mod<3) { + gen_restore_addr_reg(); + dyn_write_byte(FC_ADDR,FC_RETOP); + } else { + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} + +static void dyn_grp3_ev(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + if ((decode.modrm.reg==2) || (decode.modrm.reg==3)) gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } + switch (decode.modrm.reg) { + case 0x0: // test ev,iv + if (decode.big_op) gen_mov_dword_to_reg_imm(FC_OP2,decode_fetchd()); + else gen_mov_word_to_reg_imm(FC_OP2,decode_fetchw()); + dyn_dop_word_gencall(DOP_TEST,decode.big_op); + return; + case 0x2: // NOT Ev + dyn_sop_word_gencall(SOP_NOT,decode.big_op); + break; + case 0x3: // NEG Eb + dyn_sop_word_gencall(SOP_NEG,decode.big_op); + break; + case 0x4: // mul Eb + if (decode.big_op) gen_call_function_raw((void*)&dynrec_mul_dword); + else gen_call_function_raw((void*)&dynrec_mul_word); + return; + case 0x5: // imul Eb + if (decode.big_op) gen_call_function_raw((void*)&dynrec_imul_dword); + else gen_call_function_raw((void*)&dynrec_imul_word); + return; + case 0x6: // div Eb + if (decode.big_op) gen_call_function_raw((void*)&dynrec_div_dword); + else gen_call_function_raw((void*)&dynrec_div_word); + dyn_check_exception(FC_RETOP); + return; + case 0x7: // idiv Eb + if (decode.big_op) gen_call_function_raw((void*)&dynrec_idiv_dword); + else gen_call_function_raw((void*)&dynrec_idiv_word); + dyn_check_exception(FC_RETOP); + return; + } + // Save the result if memory op + if (decode.modrm.mod<3) { + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } else { + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); + } +} + + +static bool dyn_grp4_eb(void) { + dyn_get_modrm(); + switch (decode.modrm.reg) { + case 0x0://INC Eb + case 0x1://DEC Eb + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_byte_canuseword(FC_ADDR,FC_OP1); + dyn_sop_byte_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC); + gen_restore_addr_reg(); + dyn_write_byte(FC_ADDR,FC_RETOP); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + dyn_sop_byte_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC); + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } + break; + case 0x7: //CALBACK Iw + gen_mov_direct_dword(&core_dynrec.callback,decode_fetchw()); + dyn_set_eip_end(); + dyn_reduce_cycles(); + dyn_return(BR_CallBack); + dyn_closeblock(); + return true; + default: + IllegalOptionDynrec("dyn_grp4_eb"); + break; + } + return false; +} + +static Bitu dyn_grp4_ev(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + if ((decode.modrm.reg<2) || (decode.modrm.reg==3) || (decode.modrm.reg==5)) gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,decode.big_op); + } else { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,decode.modrm.rm,decode.big_op); + } + switch (decode.modrm.reg) { + case 0x0://INC Ev + case 0x1://DEC Ev + dyn_sop_word_gencall(decode.modrm.reg==0 ? SOP_INC : SOP_DEC,decode.big_op); + if (decode.modrm.mod<3) { + gen_restore_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,decode.big_op); + } else { + MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,decode.modrm.rm,decode.big_op); + } + break; + case 0x2: // CALL Ev + gen_mov_regs(FC_ADDR,FC_OP1); + gen_protect_addr_reg(); + gen_mov_word_to_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); + gen_add_imm(FC_OP1,(Bit32u)(decode.code-decode.code_start)); + if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); + else gen_call_function_raw((void*)&dynrec_push_word); + + gen_restore_addr_reg(); + gen_mov_word_from_reg(FC_ADDR,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); + return 1; + case 0x4: // JMP Ev + gen_mov_word_from_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); + return 1; + case 0x3: // CALL Ep + case 0x5: // JMP Ep + if (!decode.big_op) gen_extend_word(false,FC_OP1); + if (decode.modrm.mod<3) gen_restore_addr_reg(); + gen_protect_reg(FC_OP1); + gen_add_imm(FC_ADDR,decode.big_op?4:2); + dyn_read_word(FC_ADDR,FC_OP2,decode.big_op); + gen_extend_word(false,FC_OP2); + + dyn_set_eip_last_end(FC_RETOP); + gen_restore_reg(FC_OP1,FC_ADDR); + gen_call_function_IRRR(decode.modrm.reg == 3 ? (void*)(&CPU_CALL) : (void*)(&CPU_JMP), + decode.big_op,FC_OP2,FC_ADDR,FC_RETOP); + return 1; + case 0x6: // PUSH Ev + if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); + else gen_call_function_raw((void*)&dynrec_push_word); + break; + default: +// IllegalOptionDynrec("dyn_grp4_ev"); + return 2; + } + return 0; +} + + +static bool dyn_grp6(void) { + dyn_get_modrm(); + switch (decode.modrm.reg) { + case 0x00: // SLDT + case 0x01: // STR + if (decode.modrm.reg==0) gen_call_function_raw((void*)CPU_SLDT); + else gen_call_function_raw((void*)CPU_STR); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_write_word(FC_ADDR,FC_RETOP,false); + } else { + MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,decode.modrm.rm); + } + break; + case 0x02: // LLDT + case 0x03: // LTR + case 0x04: // VERR + case 0x05: // VERW + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_RETOP,false); + } else { + MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); + } + gen_extend_word(false,FC_RETOP); + switch (decode.modrm.reg) { + case 0x02: // LLDT +// if (cpu.cpl) return CPU_PrepareException(EXCEPTION_GP,0); + if (cpu.cpl) E_Exit("lldt cpl>0"); + gen_call_function_R((void*)CPU_LLDT,FC_RETOP); + dyn_check_exception(FC_RETOP); + break; + case 0x03: // LTR +// if (cpu.cpl) return CPU_PrepareException(EXCEPTION_GP,0); + if (cpu.cpl) E_Exit("ltr cpl>0"); + gen_call_function_R((void*)CPU_LTR,FC_RETOP); + dyn_check_exception(FC_RETOP); + break; + case 0x04: // VERR + gen_call_function_R((void*)CPU_VERR,FC_RETOP); + break; + case 0x05: // VERW + gen_call_function_R((void*)CPU_VERW,FC_RETOP); + break; + } + break; + default: IllegalOptionDynrec("dyn_grp6"); + } + return false; +} + +static bool dyn_grp7(void) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + switch (decode.modrm.reg) { + case 0x00: // SGDT + gen_call_function_raw((void*)CPU_SGDT_limit); + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,false); + gen_call_function_raw((void*)CPU_SGDT_base); + gen_restore_addr_reg(); + gen_add_imm(FC_ADDR,2); + dyn_write_word(FC_ADDR,FC_RETOP,true); + break; + case 0x01: // SIDT + gen_call_function_raw((void*)CPU_SIDT_limit); + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_write_word(FC_ADDR,FC_RETOP,false); + gen_call_function_raw((void*)CPU_SIDT_base); + gen_restore_addr_reg(); + gen_add_imm(FC_ADDR,2); + dyn_write_word(FC_ADDR,FC_RETOP,true); + break; + case 0x02: // LGDT + case 0x03: // LIDT +// if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (cpu.pmode && cpu.cpl) IllegalOptionDynrec("lgdt nonpriviledged"); + dyn_fill_ea(FC_ADDR); + gen_protect_addr_reg(); + dyn_read_word(FC_ADDR,FC_OP1,false); + gen_extend_word(false,FC_OP1); + gen_protect_reg(FC_OP1); + + gen_restore_addr_reg(); + gen_add_imm(FC_ADDR,2); + dyn_read_word(FC_ADDR,FC_OP2,true); + if (!decode.big_op) gen_and_imm(FC_OP2,0xffffff); + + gen_restore_reg(FC_OP1); + if (decode.modrm.reg==2) gen_call_function_RR((void*)CPU_LGDT,FC_OP1,FC_OP2); + else gen_call_function_RR((void*)CPU_LIDT,FC_OP1,FC_OP2); + break; + case 0x04: // SMSW + gen_call_function_raw((void*)CPU_SMSW); + dyn_fill_ea(FC_ADDR); + dyn_write_word(FC_ADDR,FC_RETOP,false); + break; + case 0x06: // LMSW + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_RETOP,false); + gen_call_function_R((void*)CPU_LMSW,FC_RETOP); + dyn_check_exception(FC_RETOP); + dyn_set_eip_end(); + dyn_reduce_cycles(); + dyn_return(BR_Normal); + dyn_closeblock(); + return true; + case 0x07: // INVLPG +// if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP); + if (cpu.pmode && cpu.cpl) IllegalOptionDynrec("invlpg nonpriviledged"); + gen_call_function_raw((void*)PAGING_ClearTLB); + break; + default: IllegalOptionDynrec("dyn_grp7_1"); + } + } else { + switch (decode.modrm.reg) { + case 0x04: // SMSW + gen_call_function_raw((void*)CPU_SMSW); + MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,decode.modrm.rm); + break; + case 0x06: // LMSW + MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); + gen_call_function_R((void*)CPU_LMSW,FC_RETOP); + dyn_check_exception(FC_RETOP); + dyn_set_eip_end(); + dyn_reduce_cycles(); + dyn_return(BR_Normal); + dyn_closeblock(); + return true; + default: IllegalOptionDynrec("dyn_grp7_2"); + } + } + return false; +} + + +/* +static void dyn_larlsl(bool is_lar) { + dyn_get_modrm(); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_read_word(FC_ADDR,FC_RETOP,false); + } else { + MOV_REG_WORD16_TO_HOST_REG(FC_RETOP,decode.modrm.rm); + } + gen_extend_word(false,FC_RETOP); + if (is_lar) gen_call_function((void*)CPU_LAR,"%R%A",FC_RETOP,(DRC_PTR_SIZE_IM)&core_dynrec.readdata); + else gen_call_function((void*)CPU_LSL,"%R%A",FC_RETOP,(DRC_PTR_SIZE_IM)&core_dynrec.readdata); + DRC_PTR_SIZE_IM brnz=gen_create_branch_on_nonzero(FC_RETOP,true); + gen_mov_word_to_reg(FC_OP2,&core_dynrec.readdata,true); + MOV_REG_WORD_FROM_HOST_REG(FC_OP2,decode.modrm.reg,decode.big_op); + gen_fill_branch(brnz); +} +*/ + + +static void dyn_mov_from_crx(void) { + dyn_get_modrm(); + gen_call_function_IA((void*)CPU_READ_CRX,decode.modrm.reg,(DRC_PTR_SIZE_IM)&core_dynrec.readdata); + dyn_check_exception(FC_RETOP); + gen_mov_word_to_reg(FC_OP2,&core_dynrec.readdata,true); + MOV_REG_WORD32_FROM_HOST_REG(FC_OP2,decode.modrm.rm); +} + +static void dyn_mov_to_crx(void) { + dyn_get_modrm(); + MOV_REG_WORD32_TO_HOST_REG(FC_RETOP,decode.modrm.rm); + gen_call_function_IR((void*)CPU_WRITE_CRX,decode.modrm.reg,FC_RETOP); + dyn_check_exception(FC_RETOP); + dyn_set_eip_end(); + dyn_reduce_cycles(); + dyn_return(BR_Normal); + dyn_closeblock(); +} + + +static void dyn_cbw(void) { + if (decode.big_op) { + MOV_REG_WORD16_TO_HOST_REG(FC_OP1,DRC_REG_EAX); + gen_call_function_raw((void *)&dynrec_cwde); + MOV_REG_WORD32_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX); + } else { + MOV_REG_BYTE_TO_HOST_REG_LOW_CANUSEWORD(FC_OP1,DRC_REG_EAX,0); + gen_call_function_raw((void *)&dynrec_cbw); + MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,DRC_REG_EAX); + } +} + +static void dyn_cwd(void) { + MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_EAX,decode.big_op); + if (decode.big_op) { + gen_call_function_raw((void *)&dynrec_cdq); + MOV_REG_WORD32_FROM_HOST_REG(FC_RETOP,DRC_REG_EDX); + } else { + gen_call_function_raw((void *)&dynrec_cwd); + MOV_REG_WORD16_FROM_HOST_REG(FC_RETOP,DRC_REG_EDX); + } +} + +static void dyn_sahf(void) { + MOV_REG_WORD16_TO_HOST_REG(FC_OP1,DRC_REG_EAX); + gen_call_function_raw((void *)&dynrec_sahf); + InvalidateFlags(); +} + + +static void dyn_exit_link(Bits eip_change) { + gen_add_direct_word(®_eip,(decode.code-decode.code_start)+eip_change,decode.big_op); + dyn_reduce_cycles(); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); + dyn_closeblock(); +} + + +static void dyn_branched_exit(BranchTypes btype,Bit32s eip_add) { + Bitu eip_base=decode.code-decode.code_start; + dyn_reduce_cycles(); + + dyn_branchflag_to_reg(btype); + DRC_PTR_SIZE_IM data=gen_create_branch_on_nonzero(FC_RETOP,true); + + // Branch not taken + gen_add_direct_word(®_eip,eip_base,decode.big_op); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); + gen_fill_branch(data); + + // Branch taken + gen_add_direct_word(®_eip,eip_base+eip_add,decode.big_op); + gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlockDynRec,cache.start)); + dyn_closeblock(); +} + +/* +static void dyn_set_byte_on_condition(BranchTypes btype) { + dyn_get_modrm(); + dyn_branchflag_to_reg(btype); + gen_and_imm(FC_RETOP,1); + if (decode.modrm.mod<3) { + dyn_fill_ea(FC_ADDR); + dyn_write_byte(FC_ADDR,FC_RETOP); + } else { + MOV_REG_BYTE_FROM_HOST_REG_LOW(FC_RETOP,decode.modrm.rm&3,(decode.modrm.rm>>2)&1); + } +} +*/ + +static void dyn_loop(LoopTypes type) { + dyn_reduce_cycles(); + Bits eip_add=(Bit8s)decode_fetchb(); + Bitu eip_base=decode.code-decode.code_start; + DRC_PTR_SIZE_IM branch1=0; + DRC_PTR_SIZE_IM branch2=0; + switch (type) { + case LOOP_E: + dyn_branchflag_to_reg(BR_NZ); + branch1=gen_create_branch_on_nonzero(FC_RETOP,true); + break; + case LOOP_NE: + dyn_branchflag_to_reg(BR_Z); + branch1=gen_create_branch_on_nonzero(FC_RETOP,true); + break; + } + switch (type) { + case LOOP_E: + case LOOP_NE: + case LOOP_NONE: + MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); + gen_add_imm(FC_OP1,(Bit32u)(-1)); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); + branch2=gen_create_branch_on_zero(FC_OP1,decode.big_addr); + break; + case LOOP_JCXZ: + MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); + branch2=gen_create_branch_on_nonzero(FC_OP1,decode.big_addr); + break; + } + gen_add_direct_word(®_eip,eip_base+eip_add,true); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); + if (branch1) { + gen_fill_branch(branch1); + MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); + gen_add_imm(FC_OP1,(Bit32u)(-1)); + MOV_REG_WORD_FROM_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); + } + // Branch taken + gen_fill_branch(branch2); + gen_add_direct_word(®_eip,eip_base,decode.big_op); + gen_jmp_ptr(&decode.block->link[1].to,offsetof(CacheBlockDynRec,cache.start)); + dyn_closeblock(); +} + + +static void dyn_ret_near(Bitu bytes) { + dyn_reduce_cycles(); + + if (decode.big_op) gen_call_function_raw((void*)&dynrec_pop_dword); + else { + gen_call_function_raw((void*)&dynrec_pop_word); + gen_extend_word(false,FC_RETOP); + } + gen_mov_word_from_reg(FC_RETOP,decode.big_op?(void*)(®_eip):(void*)(®_ip),true); + + if (bytes) gen_add_direct_word(®_esp,bytes,true); + dyn_return(BR_Normal); + dyn_closeblock(); +} + +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(FC_OP1); + if (decode.big_op) gen_call_function_raw((void*)&dynrec_push_dword); + else gen_call_function_raw((void*)&dynrec_push_word); + + dyn_set_eip_end(FC_OP1,imm); + gen_mov_word_from_reg(FC_OP1,decode.big_op?(void*)(®_eip):(void*)(®_ip),decode.big_op); + + dyn_reduce_cycles(); + gen_jmp_ptr(&decode.block->link[0].to,offsetof(CacheBlockDynRec,cache.start)); + dyn_closeblock(); +} + +static void dyn_ret_far(Bitu bytes) { + dyn_reduce_cycles(); + dyn_set_eip_last_end(FC_RETOP); + gen_call_function_IIR((void*)&CPU_RET,decode.big_op,bytes,FC_RETOP); + dyn_return(BR_Normal); + dyn_closeblock(); +} + +static void dyn_call_far_imm(void) { + Bitu sel,off; + off=decode.big_op ? decode_fetchd() : decode_fetchw(); + sel=decode_fetchw(); + dyn_reduce_cycles(); + dyn_set_eip_last_end(FC_RETOP); + gen_call_function_IIIR((void*)&CPU_CALL,decode.big_op,sel,off,FC_RETOP); + dyn_return(BR_Normal); + dyn_closeblock(); +} + +static void dyn_jmp_far_imm(void) { + Bitu sel,off; + off=decode.big_op ? decode_fetchd() : decode_fetchw(); + sel=decode_fetchw(); + dyn_reduce_cycles(); + dyn_set_eip_last_end(FC_RETOP); + gen_call_function_IIIR((void*)&CPU_JMP,decode.big_op,sel,off,FC_RETOP); + dyn_return(BR_Normal); + dyn_closeblock(); +} + +static void dyn_iret(void) { + dyn_reduce_cycles(); + dyn_set_eip_last_end(FC_RETOP); + gen_call_function_IR((void*)&CPU_IRET,decode.big_op,FC_RETOP); + dyn_return(BR_Iret); + dyn_closeblock(); +} + +static void dyn_interrupt(Bit8u num) { + dyn_reduce_cycles(); + dyn_set_eip_last_end(FC_RETOP); + gen_call_function_IIR((void*)&CPU_Interrupt,num,CPU_INT_SOFTWARE,FC_RETOP); + dyn_return(BR_Normal); + dyn_closeblock(); +} + + + +static void dyn_string(StringOps op) { + if (decode.rep) MOV_REG_WORD_TO_HOST_REG(FC_OP1,DRC_REG_ECX,decode.big_addr); + else gen_mov_dword_to_reg_imm(FC_OP1,1); + gen_mov_word_to_reg(FC_OP2,&cpu.direction,true); + Bit8u di_base_addr=decode.seg_prefix_used ? decode.seg_prefix : DRC_SEG_DS; + switch (op) { + case STR_MOVSB: + if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsb_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + else gen_call_function_mm((void*)&dynrec_movsb_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + break; + case STR_MOVSW: + if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsw_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + else gen_call_function_mm((void*)&dynrec_movsw_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + break; + case STR_MOVSD: + if (decode.big_addr) gen_call_function_mm((void*)&dynrec_movsd_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + else gen_call_function_mm((void*)&dynrec_movsd_word,(Bitu)DRCD_SEG_PHYS(di_base_addr),(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + break; + + case STR_LODSB: + if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsb_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr)); + else gen_call_function_m((void*)&dynrec_lodsb_word,(Bitu)DRCD_SEG_PHYS(di_base_addr)); + break; + case STR_LODSW: + if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsw_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr)); + else gen_call_function_m((void*)&dynrec_lodsw_word,(Bitu)DRCD_SEG_PHYS(di_base_addr)); + break; + case STR_LODSD: + if (decode.big_addr) gen_call_function_m((void*)&dynrec_lodsd_dword,(Bitu)DRCD_SEG_PHYS(di_base_addr)); + else gen_call_function_m((void*)&dynrec_lodsd_word,(Bitu)DRCD_SEG_PHYS(di_base_addr)); + break; + + case STR_STOSB: + if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosb_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + else gen_call_function_m((void*)&dynrec_stosb_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + break; + case STR_STOSW: + if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosw_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + else gen_call_function_m((void*)&dynrec_stosw_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + break; + case STR_STOSD: + if (decode.big_addr) gen_call_function_m((void*)&dynrec_stosd_dword,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + else gen_call_function_m((void*)&dynrec_stosd_word,(Bitu)DRCD_SEG_PHYS(DRC_SEG_ES)); + break; + default: IllegalOptionDynrec("dyn_string"); + } + if (decode.rep) MOV_REG_WORD_FROM_HOST_REG(FC_RETOP,DRC_REG_ECX,decode.big_addr); + + if (op -#include -#include "cross.h" -#include "mem.h" -#include "fpu.h" -#include "cpu.h" - - -static void FPU_FDECSTP(){ - TOP = (TOP - 1) & 7; -} - -static void FPU_FINCSTP(){ - TOP = (TOP + 1) & 7; -} - -static void FPU_FNSTCW(PhysPt addr){ - mem_writew(addr,fpu.cw); -} - -static void FPU_FFREE(Bitu st) { - fpu.tags[st]=TAG_Empty; -} - - -#if C_FPU_X86 -#include "../../fpu/fpu_instructions_x86.h" -#else -#include "../../fpu/fpu_instructions.h" -#endif - - -static INLINE void dyn_fpu_top() { - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_add_imm(FC_OP2,decode.modrm.rm); - gen_and_imm(FC_OP2,7); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); -} - -static INLINE void dyn_fpu_top_swapped() { - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - gen_add_imm(FC_OP1,decode.modrm.rm); - gen_and_imm(FC_OP1,7); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); -} - -static void dyn_eatree() { - Bitu group=(decode.modrm.val >> 3) & 7; - switch (group){ - case 0x00: // FADD ST,STi - gen_call_function_R((void*)&FPU_FADD_EA,FC_OP1); - break; - case 0x01: // FMUL ST,STi - gen_call_function_R((void*)&FPU_FMUL_EA,FC_OP1); - break; - case 0x02: // FCOM STi - gen_call_function_R((void*)&FPU_FCOM_EA,FC_OP1); - break; - case 0x03: // FCOMP STi - gen_call_function_R((void*)&FPU_FCOM_EA,FC_OP1); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: // FSUB ST,STi - gen_call_function_R((void*)&FPU_FSUB_EA,FC_OP1); - break; - case 0x05: // FSUBR ST,STi - gen_call_function_R((void*)&FPU_FSUBR_EA,FC_OP1); - break; - case 0x06: // FDIV ST,STi - gen_call_function_R((void*)&FPU_FDIV_EA,FC_OP1); - break; - case 0x07: // FDIVR ST,STi - gen_call_function_R((void*)&FPU_FDIVR_EA,FC_OP1); - break; - default: - break; - } -} - -static void dyn_fpu_esc0(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - dyn_fpu_top(); - switch (decode.modrm.reg){ - case 0x00: //FADD ST,STi - gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2); - break; - case 0x01: // FMUL ST,STi - gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2); - break; - case 0x02: // FCOM STi - gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); - break; - case 0x03: // FCOMP STi - gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: // FSUB ST,STi - gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2); - break; - case 0x05: // FSUBR ST,STi - gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2); - break; - case 0x06: // FDIV ST,STi - gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2); - break; - case 0x07: // FDIVR ST,STi - gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2); - break; - default: - break; - } - } else { - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FLD_F32_EA,FC_ADDR); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - dyn_eatree(); - } -} - - -static void dyn_fpu_esc1(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - switch (decode.modrm.reg){ - case 0x00: /* FLD STi */ - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - gen_add_imm(FC_OP1,decode.modrm.rm); - gen_and_imm(FC_OP1,7); - gen_protect_reg(FC_OP1); - gen_call_function_raw((void*)&FPU_PREP_PUSH); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_restore_reg(FC_OP1); - gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); - break; - case 0x01: /* FXCH STi */ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2); - break; - case 0x02: /* FNOP */ - gen_call_function_raw((void*)&FPU_FNOP); - break; - case 0x03: /* FSTP STi */ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: - switch(decode.modrm.rm){ - case 0x00: /* FCHS */ - gen_call_function_raw((void*)&FPU_FCHS); - break; - case 0x01: /* FABS */ - gen_call_function_raw((void*)&FPU_FABS); - break; - case 0x02: /* UNKNOWN */ - case 0x03: /* ILLEGAL */ - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); - break; - case 0x04: /* FTST */ - gen_call_function_raw((void*)&FPU_FTST); - break; - case 0x05: /* FXAM */ - gen_call_function_raw((void*)&FPU_FXAM); - break; - case 0x06: /* FTSTP (cyrix)*/ - case 0x07: /* UNKNOWN */ - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); - break; - } - break; - case 0x05: - switch(decode.modrm.rm){ - case 0x00: /* FLD1 */ - gen_call_function_raw((void*)&FPU_FLD1); - break; - case 0x01: /* FLDL2T */ - gen_call_function_raw((void*)&FPU_FLDL2T); - break; - case 0x02: /* FLDL2E */ - gen_call_function_raw((void*)&FPU_FLDL2E); - break; - case 0x03: /* FLDPI */ - gen_call_function_raw((void*)&FPU_FLDPI); - break; - case 0x04: /* FLDLG2 */ - gen_call_function_raw((void*)&FPU_FLDLG2); - break; - case 0x05: /* FLDLN2 */ - gen_call_function_raw((void*)&FPU_FLDLN2); - break; - case 0x06: /* FLDZ*/ - gen_call_function_raw((void*)&FPU_FLDZ); - break; - case 0x07: /* ILLEGAL */ - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); - break; - } - break; - case 0x06: - switch(decode.modrm.rm){ - case 0x00: /* F2XM1 */ - gen_call_function_raw((void*)&FPU_F2XM1); - break; - case 0x01: /* FYL2X */ - gen_call_function_raw((void*)&FPU_FYL2X); - break; - case 0x02: /* FPTAN */ - gen_call_function_raw((void*)&FPU_FPTAN); - break; - case 0x03: /* FPATAN */ - gen_call_function_raw((void*)&FPU_FPATAN); - break; - case 0x04: /* FXTRACT */ - gen_call_function_raw((void*)&FPU_FXTRACT); - break; - case 0x05: /* FPREM1 */ - gen_call_function_raw((void*)&FPU_FPREM1); - break; - case 0x06: /* FDECSTP */ - gen_call_function_raw((void*)&FPU_FDECSTP); - break; - case 0x07: /* FINCSTP */ - gen_call_function_raw((void*)&FPU_FINCSTP); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); - break; - } - break; - case 0x07: - switch(decode.modrm.rm){ - case 0x00: /* FPREM */ - gen_call_function_raw((void*)&FPU_FPREM); - break; - case 0x01: /* FYL2XP1 */ - gen_call_function_raw((void*)&FPU_FYL2XP1); - break; - case 0x02: /* FSQRT */ - gen_call_function_raw((void*)&FPU_FSQRT); - break; - case 0x03: /* FSINCOS */ - gen_call_function_raw((void*)&FPU_FSINCOS); - break; - case 0x04: /* FRNDINT */ - gen_call_function_raw((void*)&FPU_FRNDINT); - break; - case 0x05: /* FSCALE */ - gen_call_function_raw((void*)&FPU_FSCALE); - break; - case 0x06: /* FSIN */ - gen_call_function_raw((void*)&FPU_FSIN); - break; - case 0x07: /* FCOS */ - gen_call_function_raw((void*)&FPU_FCOS); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); - break; - } - } else { - switch(decode.modrm.reg){ - case 0x00: /* FLD float*/ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FLD_F32,FC_OP1,FC_OP2); - break; - case 0x01: /* UNKNOWN */ - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - case 0x02: /* FST float*/ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_F32,FC_ADDR); - break; - case 0x03: /* FSTP float*/ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_F32,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: /* FLDENV */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FLDENV,FC_ADDR); - break; - case 0x05: /* FLDCW */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void *)&FPU_FLDCW,FC_ADDR); - break; - case 0x06: /* FSTENV */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void *)&FPU_FSTENV,FC_ADDR); - break; - case 0x07: /* FNSTCW*/ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void *)&FPU_FNSTCW,FC_ADDR); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - } -} - -static void dyn_fpu_esc2(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - switch(decode.modrm.reg){ - case 0x05: - switch(decode.modrm.rm){ - case 0x01: /* FUCOMPP */ - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_add_imm(FC_OP2,1); - gen_and_imm(FC_OP2,7); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - gen_call_function_RR((void *)&FPU_FUCOM,FC_OP1,FC_OP2); - gen_call_function_raw((void *)&FPU_FPOP); - gen_call_function_raw((void *)&FPU_FPOP); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - } else { - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FLD_I32_EA,FC_ADDR); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - dyn_eatree(); - } -} - -static void dyn_fpu_esc3(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - switch (decode.modrm.reg) { - case 0x04: - switch (decode.modrm.rm) { - case 0x00: //FNENI - case 0x01: //FNDIS - LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion: %d",decode.modrm.rm); - break; - case 0x02: //FNCLEX FCLEX - gen_call_function_raw((void*)&FPU_FCLEX); - break; - case 0x03: //FNINIT FINIT - gen_call_function_raw((void*)&FPU_FINIT); - break; - case 0x04: //FNSETPM - case 0x05: //FRSTPM -// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); - break; - default: - E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - } else { - switch(decode.modrm.reg){ - case 0x00: /* FILD */ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FLD_I32,FC_OP1,FC_OP2); - break; - case 0x01: /* FISTTP */ - LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - case 0x02: /* FIST */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_I32,FC_ADDR); - break; - case 0x03: /* FISTP */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_I32,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x05: /* FLD 80 Bits Real */ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FLD_F80,FC_ADDR); - break; - case 0x07: /* FSTP 80 Bits Real */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_F80,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - } - } -} - -static void dyn_fpu_esc4(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - switch(decode.modrm.reg){ - case 0x00: /* FADD STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2); - break; - case 0x01: /* FMUL STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2); - break; - case 0x02: /* FCOM*/ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); - break; - case 0x03: /* FCOMP*/ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: /* FSUBR STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2); - break; - case 0x05: /* FSUB STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2); - break; - case 0x06: /* FDIVR STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2); - break; - case 0x07: /* FDIV STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2); - break; - default: - break; - } - } else { - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FLD_F64_EA,FC_ADDR); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - dyn_eatree(); - } -} - -static void dyn_fpu_esc5(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - dyn_fpu_top(); - switch(decode.modrm.reg){ - case 0x00: /* FFREE STi */ - gen_call_function_R((void*)&FPU_FFREE,FC_OP2); - break; - case 0x01: /* FXCH STi*/ - gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2); - break; - case 0x02: /* FST STi */ - gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); - break; - case 0x03: /* FSTP STi*/ - gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: /* FUCOM STi */ - gen_call_function_RR((void*)&FPU_FUCOM,FC_OP1,FC_OP2); - break; - case 0x05: /*FUCOMP STi */ - gen_call_function_RR((void*)&FPU_FUCOM,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - } else { - switch(decode.modrm.reg){ - case 0x00: /* FLD double real*/ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FLD_F64,FC_OP1,FC_OP2); - break; - case 0x01: /* FISTTP longint*/ - LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - case 0x02: /* FST double real*/ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_F64,FC_ADDR); - break; - case 0x03: /* FSTP double real*/ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_F64,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: /* FRSTOR */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FRSTOR,FC_ADDR); - break; - case 0x06: /* FSAVE */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FSAVE,FC_ADDR); - break; - case 0x07: /*FNSTSW */ - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - gen_call_function_R((void*)&FPU_SET_TOP,FC_OP1); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&fpu.sw),true); - gen_call_function_RR((void*)&mem_writew,FC_OP1,FC_OP2); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - } - } -} - -static void dyn_fpu_esc6(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - switch(decode.modrm.reg){ - case 0x00: /*FADDP STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2); - break; - case 0x01: /* FMULP STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2); - break; - case 0x02: /* FCOMP5*/ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); - break; /* TODO IS THIS ALLRIGHT ????????? */ - case 0x03: /*FCOMPP*/ - if(decode.modrm.rm != 1) { - LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - return; - } - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_add_imm(FC_OP2,1); - gen_and_imm(FC_OP2,7); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); /* extra pop at the bottom*/ - break; - case 0x04: /* FSUBRP STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2); - break; - case 0x05: /* FSUBP STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2); - break; - case 0x06: /* FDIVRP STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2); - break; - case 0x07: /* FDIVP STi,ST*/ - dyn_fpu_top_swapped(); - gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2); - break; - default: - break; - } - gen_call_function_raw((void*)&FPU_FPOP); - } else { - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FLD_I16_EA,FC_ADDR); - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - dyn_eatree(); - } -} - -static void dyn_fpu_esc7(){ - dyn_get_modrm(); - if (decode.modrm.val >= 0xc0) { - switch (decode.modrm.reg){ - case 0x00: /* FFREEP STi */ - dyn_fpu_top(); - gen_call_function_R((void*)&FPU_FFREE,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x01: /* FXCH STi*/ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2); - break; - case 0x02: /* FSTP STi*/ - case 0x03: /* FSTP STi*/ - dyn_fpu_top(); - gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: - switch(decode.modrm.rm){ - case 0x00: /* FNSTSW AX*/ - gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); - gen_call_function_R((void*)&FPU_SET_TOP,FC_OP1); - gen_mov_word_to_reg(FC_OP1,(void*)(&fpu.sw),false); - MOV_REG_WORD16_FROM_HOST_REG(FC_OP1,DRC_REG_EAX); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - } else { - switch(decode.modrm.reg){ - case 0x00: /* FILD Bit16s */ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FLD_I16,FC_OP1,FC_OP2); - break; - case 0x01: - LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - case 0x02: /* FIST Bit16s */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_I16,FC_ADDR); - break; - case 0x03: /* FISTP Bit16s */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_I16,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x04: /* FBLD packed BCD */ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FBLD,FC_OP1,FC_OP2); - break; - case 0x05: /* FILD Bit64s */ - gen_call_function_raw((void*)&FPU_PREP_PUSH); - dyn_fill_ea(FC_OP1); - gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); - gen_call_function_RR((void*)&FPU_FLD_I64,FC_OP1,FC_OP2); - break; - case 0x06: /* FBSTP packed BCD */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FBST,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - case 0x07: /* FISTP Bit64s */ - dyn_fill_ea(FC_ADDR); - gen_call_function_R((void*)&FPU_FST_I64,FC_ADDR); - gen_call_function_raw((void*)&FPU_FPOP); - break; - default: - LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); - break; - } - } -} - -#endif +/* + * Copyright (C) 2002-2010 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: dyn_fpu.h,v 1.8 2009-09-23 20:55:19 c2woody Exp $ */ + + +#include "dosbox.h" +#if C_FPU + +#include +#include +#include "cross.h" +#include "mem.h" +#include "fpu.h" +#include "cpu.h" + + +static void FPU_FDECSTP(){ + TOP = (TOP - 1) & 7; +} + +static void FPU_FINCSTP(){ + TOP = (TOP + 1) & 7; +} + +static void FPU_FNSTCW(PhysPt addr){ + mem_writew(addr,fpu.cw); +} + +static void FPU_FFREE(Bitu st) { + fpu.tags[st]=TAG_Empty; +} + + +#if C_FPU_X86 +#include "../../fpu/fpu_instructions_x86.h" +#else +#include "../../fpu/fpu_instructions.h" +#endif + + +static INLINE void dyn_fpu_top() { + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_add_imm(FC_OP2,decode.modrm.rm); + gen_and_imm(FC_OP2,7); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); +} + +static INLINE void dyn_fpu_top_swapped() { + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + gen_add_imm(FC_OP1,decode.modrm.rm); + gen_and_imm(FC_OP1,7); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); +} + +static void dyn_eatree() { + Bitu group=(decode.modrm.val >> 3) & 7; + switch (group){ + case 0x00: // FADD ST,STi + gen_call_function_R((void*)&FPU_FADD_EA,FC_OP1); + break; + case 0x01: // FMUL ST,STi + gen_call_function_R((void*)&FPU_FMUL_EA,FC_OP1); + break; + case 0x02: // FCOM STi + gen_call_function_R((void*)&FPU_FCOM_EA,FC_OP1); + break; + case 0x03: // FCOMP STi + gen_call_function_R((void*)&FPU_FCOM_EA,FC_OP1); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: // FSUB ST,STi + gen_call_function_R((void*)&FPU_FSUB_EA,FC_OP1); + break; + case 0x05: // FSUBR ST,STi + gen_call_function_R((void*)&FPU_FSUBR_EA,FC_OP1); + break; + case 0x06: // FDIV ST,STi + gen_call_function_R((void*)&FPU_FDIV_EA,FC_OP1); + break; + case 0x07: // FDIVR ST,STi + gen_call_function_R((void*)&FPU_FDIVR_EA,FC_OP1); + break; + default: + break; + } +} + +static void dyn_fpu_esc0(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + dyn_fpu_top(); + switch (decode.modrm.reg){ + case 0x00: //FADD ST,STi + gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2); + break; + case 0x01: // FMUL ST,STi + gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2); + break; + case 0x02: // FCOM STi + gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); + break; + case 0x03: // FCOMP STi + gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: // FSUB ST,STi + gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2); + break; + case 0x05: // FSUBR ST,STi + gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2); + break; + case 0x06: // FDIV ST,STi + gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2); + break; + case 0x07: // FDIVR ST,STi + gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2); + break; + default: + break; + } + } else { + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FLD_F32_EA,FC_ADDR); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + dyn_eatree(); + } +} + + +static void dyn_fpu_esc1(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + switch (decode.modrm.reg){ + case 0x00: /* FLD STi */ + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + gen_add_imm(FC_OP1,decode.modrm.rm); + gen_and_imm(FC_OP1,7); + gen_protect_reg(FC_OP1); + gen_call_function_raw((void*)&FPU_PREP_PUSH); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_restore_reg(FC_OP1); + gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); + break; + case 0x01: /* FXCH STi */ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2); + break; + case 0x02: /* FNOP */ + gen_call_function_raw((void*)&FPU_FNOP); + break; + case 0x03: /* FSTP STi */ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: + switch(decode.modrm.rm){ + case 0x00: /* FCHS */ + gen_call_function_raw((void*)&FPU_FCHS); + break; + case 0x01: /* FABS */ + gen_call_function_raw((void*)&FPU_FABS); + break; + case 0x02: /* UNKNOWN */ + case 0x03: /* ILLEGAL */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); + break; + case 0x04: /* FTST */ + gen_call_function_raw((void*)&FPU_FTST); + break; + case 0x05: /* FXAM */ + gen_call_function_raw((void*)&FPU_FXAM); + break; + case 0x06: /* FTSTP (cyrix)*/ + case 0x07: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); + break; + } + break; + case 0x05: + switch(decode.modrm.rm){ + case 0x00: /* FLD1 */ + gen_call_function_raw((void*)&FPU_FLD1); + break; + case 0x01: /* FLDL2T */ + gen_call_function_raw((void*)&FPU_FLDL2T); + break; + case 0x02: /* FLDL2E */ + gen_call_function_raw((void*)&FPU_FLDL2E); + break; + case 0x03: /* FLDPI */ + gen_call_function_raw((void*)&FPU_FLDPI); + break; + case 0x04: /* FLDLG2 */ + gen_call_function_raw((void*)&FPU_FLDLG2); + break; + case 0x05: /* FLDLN2 */ + gen_call_function_raw((void*)&FPU_FLDLN2); + break; + case 0x06: /* FLDZ*/ + gen_call_function_raw((void*)&FPU_FLDZ); + break; + case 0x07: /* ILLEGAL */ + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); + break; + } + break; + case 0x06: + switch(decode.modrm.rm){ + case 0x00: /* F2XM1 */ + gen_call_function_raw((void*)&FPU_F2XM1); + break; + case 0x01: /* FYL2X */ + gen_call_function_raw((void*)&FPU_FYL2X); + break; + case 0x02: /* FPTAN */ + gen_call_function_raw((void*)&FPU_FPTAN); + break; + case 0x03: /* FPATAN */ + gen_call_function_raw((void*)&FPU_FPATAN); + break; + case 0x04: /* FXTRACT */ + gen_call_function_raw((void*)&FPU_FXTRACT); + break; + case 0x05: /* FPREM1 */ + gen_call_function_raw((void*)&FPU_FPREM1); + break; + case 0x06: /* FDECSTP */ + gen_call_function_raw((void*)&FPU_FDECSTP); + break; + case 0x07: /* FINCSTP */ + gen_call_function_raw((void*)&FPU_FINCSTP); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); + break; + } + break; + case 0x07: + switch(decode.modrm.rm){ + case 0x00: /* FPREM */ + gen_call_function_raw((void*)&FPU_FPREM); + break; + case 0x01: /* FYL2XP1 */ + gen_call_function_raw((void*)&FPU_FYL2XP1); + break; + case 0x02: /* FSQRT */ + gen_call_function_raw((void*)&FPU_FSQRT); + break; + case 0x03: /* FSINCOS */ + gen_call_function_raw((void*)&FPU_FSINCOS); + break; + case 0x04: /* FRNDINT */ + gen_call_function_raw((void*)&FPU_FRNDINT); + break; + case 0x05: /* FSCALE */ + gen_call_function_raw((void*)&FPU_FSCALE); + break; + case 0x06: /* FSIN */ + gen_call_function_raw((void*)&FPU_FSIN); + break; + case 0x07: /* FCOS */ + gen_call_function_raw((void*)&FPU_FCOS); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 1:Unhandled group %X subfunction %X",decode.modrm.reg,decode.modrm.rm); + break; + } + } else { + switch(decode.modrm.reg){ + case 0x00: /* FLD float*/ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FLD_F32,FC_OP1,FC_OP2); + break; + case 0x01: /* UNKNOWN */ + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + case 0x02: /* FST float*/ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_F32,FC_ADDR); + break; + case 0x03: /* FSTP float*/ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_F32,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: /* FLDENV */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FLDENV,FC_ADDR); + break; + case 0x05: /* FLDCW */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void *)&FPU_FLDCW,FC_ADDR); + break; + case 0x06: /* FSTENV */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void *)&FPU_FSTENV,FC_ADDR); + break; + case 0x07: /* FNSTCW*/ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void *)&FPU_FNSTCW,FC_ADDR); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC EA 1:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + } +} + +static void dyn_fpu_esc2(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + switch(decode.modrm.reg){ + case 0x05: + switch(decode.modrm.rm){ + case 0x01: /* FUCOMPP */ + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_add_imm(FC_OP2,1); + gen_and_imm(FC_OP2,7); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + gen_call_function_RR((void *)&FPU_FUCOM,FC_OP1,FC_OP2); + gen_call_function_raw((void *)&FPU_FPOP); + gen_call_function_raw((void *)&FPU_FPOP); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 2:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + } else { + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FLD_I32_EA,FC_ADDR); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + dyn_eatree(); + } +} + +static void dyn_fpu_esc3(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + switch (decode.modrm.reg) { + case 0x04: + switch (decode.modrm.rm) { + case 0x00: //FNENI + case 0x01: //FNDIS + LOG(LOG_FPU,LOG_ERROR)("8087 only fpu code used esc 3: group 4: subfuntion: %d",decode.modrm.rm); + break; + case 0x02: //FNCLEX FCLEX + gen_call_function_raw((void*)&FPU_FCLEX); + break; + case 0x03: //FNINIT FINIT + gen_call_function_raw((void*)&FPU_FINIT); + break; + case 0x04: //FNSETPM + case 0x05: //FRSTPM +// LOG(LOG_FPU,LOG_ERROR)("80267 protected mode (un)set. Nothing done"); + break; + default: + E_Exit("ESC 3:ILLEGAL OPCODE group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + } else { + switch(decode.modrm.reg){ + case 0x00: /* FILD */ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FLD_I32,FC_OP1,FC_OP2); + break; + case 0x01: /* FISTTP */ + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + case 0x02: /* FIST */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_I32,FC_ADDR); + break; + case 0x03: /* FISTP */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_I32,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x05: /* FLD 80 Bits Real */ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FLD_F80,FC_ADDR); + break; + case 0x07: /* FSTP 80 Bits Real */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_F80,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 3 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + } + } +} + +static void dyn_fpu_esc4(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + switch(decode.modrm.reg){ + case 0x00: /* FADD STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2); + break; + case 0x01: /* FMUL STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2); + break; + case 0x02: /* FCOM*/ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); + break; + case 0x03: /* FCOMP*/ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: /* FSUBR STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2); + break; + case 0x05: /* FSUB STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2); + break; + case 0x06: /* FDIVR STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2); + break; + case 0x07: /* FDIV STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2); + break; + default: + break; + } + } else { + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FLD_F64_EA,FC_ADDR); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + dyn_eatree(); + } +} + +static void dyn_fpu_esc5(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + dyn_fpu_top(); + switch(decode.modrm.reg){ + case 0x00: /* FFREE STi */ + gen_call_function_R((void*)&FPU_FFREE,FC_OP2); + break; + case 0x01: /* FXCH STi*/ + gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2); + break; + case 0x02: /* FST STi */ + gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); + break; + case 0x03: /* FSTP STi*/ + gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: /* FUCOM STi */ + gen_call_function_RR((void*)&FPU_FUCOM,FC_OP1,FC_OP2); + break; + case 0x05: /*FUCOMP STi */ + gen_call_function_RR((void*)&FPU_FUCOM,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + } else { + switch(decode.modrm.reg){ + case 0x00: /* FLD double real*/ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FLD_F64,FC_OP1,FC_OP2); + break; + case 0x01: /* FISTTP longint*/ + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + case 0x02: /* FST double real*/ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_F64,FC_ADDR); + break; + case 0x03: /* FSTP double real*/ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_F64,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: /* FRSTOR */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FRSTOR,FC_ADDR); + break; + case 0x06: /* FSAVE */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FSAVE,FC_ADDR); + break; + case 0x07: /*FNSTSW */ + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + gen_call_function_R((void*)&FPU_SET_TOP,FC_OP1); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&fpu.sw),true); + gen_call_function_RR((void*)&mem_writew,FC_OP1,FC_OP2); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 5 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + } + } +} + +static void dyn_fpu_esc6(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + switch(decode.modrm.reg){ + case 0x00: /*FADDP STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FADD,FC_OP1,FC_OP2); + break; + case 0x01: /* FMULP STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FMUL,FC_OP1,FC_OP2); + break; + case 0x02: /* FCOMP5*/ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); + break; /* TODO IS THIS ALLRIGHT ????????? */ + case 0x03: /*FCOMPP*/ + if(decode.modrm.rm != 1) { + LOG(LOG_FPU,LOG_WARN)("ESC 6:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + return; + } + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_add_imm(FC_OP2,1); + gen_and_imm(FC_OP2,7); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FCOM,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); /* extra pop at the bottom*/ + break; + case 0x04: /* FSUBRP STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FSUBR,FC_OP1,FC_OP2); + break; + case 0x05: /* FSUBP STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FSUB,FC_OP1,FC_OP2); + break; + case 0x06: /* FDIVRP STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FDIVR,FC_OP1,FC_OP2); + break; + case 0x07: /* FDIVP STi,ST*/ + dyn_fpu_top_swapped(); + gen_call_function_RR((void*)&FPU_FDIV,FC_OP1,FC_OP2); + break; + default: + break; + } + gen_call_function_raw((void*)&FPU_FPOP); + } else { + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FLD_I16_EA,FC_ADDR); + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + dyn_eatree(); + } +} + +static void dyn_fpu_esc7(){ + dyn_get_modrm(); + if (decode.modrm.val >= 0xc0) { + switch (decode.modrm.reg){ + case 0x00: /* FFREEP STi */ + dyn_fpu_top(); + gen_call_function_R((void*)&FPU_FFREE,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x01: /* FXCH STi*/ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FXCH,FC_OP1,FC_OP2); + break; + case 0x02: /* FSTP STi*/ + case 0x03: /* FSTP STi*/ + dyn_fpu_top(); + gen_call_function_RR((void*)&FPU_FST,FC_OP1,FC_OP2); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: + switch(decode.modrm.rm){ + case 0x00: /* FNSTSW AX*/ + gen_mov_word_to_reg(FC_OP1,(void*)(&TOP),true); + gen_call_function_R((void*)&FPU_SET_TOP,FC_OP1); + gen_mov_word_to_reg(FC_OP1,(void*)(&fpu.sw),false); + MOV_REG_WORD16_FROM_HOST_REG(FC_OP1,DRC_REG_EAX); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + } else { + switch(decode.modrm.reg){ + case 0x00: /* FILD Bit16s */ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FLD_I16,FC_OP1,FC_OP2); + break; + case 0x01: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + case 0x02: /* FIST Bit16s */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_I16,FC_ADDR); + break; + case 0x03: /* FISTP Bit16s */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_I16,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x04: /* FBLD packed BCD */ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FBLD,FC_OP1,FC_OP2); + break; + case 0x05: /* FILD Bit64s */ + gen_call_function_raw((void*)&FPU_PREP_PUSH); + dyn_fill_ea(FC_OP1); + gen_mov_word_to_reg(FC_OP2,(void*)(&TOP),true); + gen_call_function_RR((void*)&FPU_FLD_I64,FC_OP1,FC_OP2); + break; + case 0x06: /* FBSTP packed BCD */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FBST,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + case 0x07: /* FISTP Bit64s */ + dyn_fill_ea(FC_ADDR); + gen_call_function_R((void*)&FPU_FST_I64,FC_ADDR); + gen_call_function_raw((void*)&FPU_FPOP); + break; + default: + LOG(LOG_FPU,LOG_WARN)("ESC 7 EA:Unhandled group %d subfunction %d",decode.modrm.reg,decode.modrm.rm); + break; + } + } +} + +#endif diff --git a/src/cpu/core_dynrec/operators.h b/src/cpu/core_dynrec/operators.h index cde94dc..2ce2e17 100644 --- a/src/cpu/core_dynrec/operators.h +++ b/src/cpu/core_dynrec/operators.h @@ -1,1997 +1,1997 @@ -/* - * Copyright (C) 2002-2009 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: operators.h,v 1.8 2009/06/25 19:31:43 c2woody Exp $ */ - - -static Bit8u DRC_CALL_CONV dynrec_add_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_add_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=(Bit8u)(lf_var1b+lf_var2b); - lflags.type=t_ADDb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_add_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_add_byte_simple(Bit8u op1,Bit8u op2) { - return op1+op2; -} - -static Bit8u DRC_CALL_CONV dynrec_adc_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_adc_byte(Bit8u op1,Bit8u op2) { - lflags.oldcf=get_CF()!=0; - lf_var1b=op1; - lf_var2b=op2; - lf_resb=(Bit8u)(lf_var1b+lf_var2b+lflags.oldcf); - lflags.type=t_ADCb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_adc_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_adc_byte_simple(Bit8u op1,Bit8u op2) { - return (Bit8u)(op1+op2+(Bitu)(get_CF()!=0)); -} - -static Bit8u DRC_CALL_CONV dynrec_sub_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_sub_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=(Bit8u)(lf_var1b-lf_var2b); - lflags.type=t_SUBb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_sub_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_sub_byte_simple(Bit8u op1,Bit8u op2) { - return op1-op2; -} - -static Bit8u DRC_CALL_CONV dynrec_sbb_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_sbb_byte(Bit8u op1,Bit8u op2) { - lflags.oldcf=get_CF()!=0; - lf_var1b=op1; - lf_var2b=op2; - lf_resb=(Bit8u)(lf_var1b-(lf_var2b+lflags.oldcf)); - lflags.type=t_SBBb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_sbb_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_sbb_byte_simple(Bit8u op1,Bit8u op2) { - return (Bit8u)(op1-(op2+(Bitu)(get_CF()!=0))); -} - -static void DRC_CALL_CONV dynrec_cmp_byte(Bit8u op1,Bit8u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_cmp_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=(Bit8u)(lf_var1b-lf_var2b); - lflags.type=t_CMPb; -} - -static void DRC_CALL_CONV dynrec_cmp_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_cmp_byte_simple(Bit8u op1,Bit8u op2) { -} - -static Bit8u DRC_CALL_CONV dynrec_xor_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_xor_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=lf_var1b ^ lf_var2b; - lflags.type=t_XORb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_xor_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_xor_byte_simple(Bit8u op1,Bit8u op2) { - return op1 ^ op2; -} - -static Bit8u DRC_CALL_CONV dynrec_and_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_and_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=lf_var1b & lf_var2b; - lflags.type=t_ANDb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_and_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_and_byte_simple(Bit8u op1,Bit8u op2) { - return op1 & op2; -} - -static Bit8u DRC_CALL_CONV dynrec_or_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_or_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=lf_var1b | lf_var2b; - lflags.type=t_ORb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_or_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_or_byte_simple(Bit8u op1,Bit8u op2) { - return op1 | op2; -} - -static void DRC_CALL_CONV dynrec_test_byte(Bit8u op1,Bit8u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_test_byte(Bit8u op1,Bit8u op2) { - lf_var1b=op1; - lf_var2b=op2; - lf_resb=lf_var1b & lf_var2b; - lflags.type=t_TESTb; -} - -static void DRC_CALL_CONV dynrec_test_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_test_byte_simple(Bit8u op1,Bit8u op2) { -} - -static Bit16u DRC_CALL_CONV dynrec_add_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_add_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=(Bit16u)(lf_var1w+lf_var2w); - lflags.type=t_ADDw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_add_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_add_word_simple(Bit16u op1,Bit16u op2) { - return op1+op2; -} - -static Bit16u DRC_CALL_CONV dynrec_adc_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_adc_word(Bit16u op1,Bit16u op2) { - lflags.oldcf=get_CF()!=0; - lf_var1w=op1; - lf_var2w=op2; - lf_resw=(Bit16u)(lf_var1w+lf_var2w+lflags.oldcf); - lflags.type=t_ADCw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_adc_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_adc_word_simple(Bit16u op1,Bit16u op2) { - return (Bit16u)(op1+op2+(Bitu)(get_CF()!=0)); -} - -static Bit16u DRC_CALL_CONV dynrec_sub_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_sub_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=(Bit16u)(lf_var1w-lf_var2w); - lflags.type=t_SUBw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_sub_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_sub_word_simple(Bit16u op1,Bit16u op2) { - return op1-op2; -} - -static Bit16u DRC_CALL_CONV dynrec_sbb_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_sbb_word(Bit16u op1,Bit16u op2) { - lflags.oldcf=get_CF()!=0; - lf_var1w=op1; - lf_var2w=op2; - lf_resw=(Bit16u)(lf_var1w-(lf_var2w+lflags.oldcf)); - lflags.type=t_SBBw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_sbb_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_sbb_word_simple(Bit16u op1,Bit16u op2) { - return (Bit16u)(op1-(op2+(Bitu)(get_CF()!=0))); -} - -static void DRC_CALL_CONV dynrec_cmp_word(Bit16u op1,Bit16u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_cmp_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=(Bit16u)(lf_var1w-lf_var2w); - lflags.type=t_CMPw; -} - -static void DRC_CALL_CONV dynrec_cmp_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_cmp_word_simple(Bit16u op1,Bit16u op2) { -} - -static Bit16u DRC_CALL_CONV dynrec_xor_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_xor_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=lf_var1w ^ lf_var2w; - lflags.type=t_XORw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_xor_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_xor_word_simple(Bit16u op1,Bit16u op2) { - return op1 ^ op2; -} - -static Bit16u DRC_CALL_CONV dynrec_and_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_and_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=lf_var1w & lf_var2w; - lflags.type=t_ANDw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_and_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_and_word_simple(Bit16u op1,Bit16u op2) { - return op1 & op2; -} - -static Bit16u DRC_CALL_CONV dynrec_or_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_or_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=lf_var1w | lf_var2w; - lflags.type=t_ORw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_or_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_or_word_simple(Bit16u op1,Bit16u op2) { - return op1 | op2; -} - -static void DRC_CALL_CONV dynrec_test_word(Bit16u op1,Bit16u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_test_word(Bit16u op1,Bit16u op2) { - lf_var1w=op1; - lf_var2w=op2; - lf_resw=lf_var1w & lf_var2w; - lflags.type=t_TESTw; -} - -static void DRC_CALL_CONV dynrec_test_word_simple(Bit16u op1,Bit16u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_test_word_simple(Bit16u op1,Bit16u op2) { -} - -static Bit32u DRC_CALL_CONV dynrec_add_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_add_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d+lf_var2d; - lflags.type=t_ADDd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_add_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_add_dword_simple(Bit32u op1,Bit32u op2) { - return op1 + op2; -} - -static Bit32u DRC_CALL_CONV dynrec_adc_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_adc_dword(Bit32u op1,Bit32u op2) { - lflags.oldcf=get_CF()!=0; - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d+lf_var2d+lflags.oldcf; - lflags.type=t_ADCd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_adc_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_adc_dword_simple(Bit32u op1,Bit32u op2) { - return op1+op2+(Bitu)(get_CF()!=0); -} - -static Bit32u DRC_CALL_CONV dynrec_sub_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_sub_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d-lf_var2d; - lflags.type=t_SUBd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_sub_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_sub_dword_simple(Bit32u op1,Bit32u op2) { - return op1-op2; -} - -static Bit32u DRC_CALL_CONV dynrec_sbb_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_sbb_dword(Bit32u op1,Bit32u op2) { - lflags.oldcf=get_CF()!=0; - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d-(lf_var2d+lflags.oldcf); - lflags.type=t_SBBd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_sbb_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_sbb_dword_simple(Bit32u op1,Bit32u op2) { - return op1-(op2+(Bitu)(get_CF()!=0)); -} - -static void DRC_CALL_CONV dynrec_cmp_dword(Bit32u op1,Bit32u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_cmp_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d-lf_var2d; - lflags.type=t_CMPd; -} - -static void DRC_CALL_CONV dynrec_cmp_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_cmp_dword_simple(Bit32u op1,Bit32u op2) { -} - -static Bit32u DRC_CALL_CONV dynrec_xor_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_xor_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d ^ lf_var2d; - lflags.type=t_XORd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_xor_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_xor_dword_simple(Bit32u op1,Bit32u op2) { - return op1 ^ op2; -} - -static Bit32u DRC_CALL_CONV dynrec_and_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_and_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d & lf_var2d; - lflags.type=t_ANDd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_and_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_and_dword_simple(Bit32u op1,Bit32u op2) { - return op1 & op2; -} - -static Bit32u DRC_CALL_CONV dynrec_or_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_or_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d | lf_var2d; - lflags.type=t_ORd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_or_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_or_dword_simple(Bit32u op1,Bit32u op2) { - return op1 | op2; -} - -static void DRC_CALL_CONV dynrec_test_dword(Bit32u op1,Bit32u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_test_dword(Bit32u op1,Bit32u op2) { - lf_var1d=op1; - lf_var2d=op2; - lf_resd=lf_var1d & lf_var2d; - lflags.type=t_TESTd; -} - -static void DRC_CALL_CONV dynrec_test_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; -static void DRC_CALL_CONV dynrec_test_dword_simple(Bit32u op1,Bit32u op2) { -} - - -static void dyn_dop_byte_gencall(DualOps op) { - switch (op) { - case DOP_ADD: - InvalidateFlags((void*)&dynrec_add_byte_simple,t_ADDb); - gen_call_function_raw((void*)&dynrec_add_byte); - break; - case DOP_ADC: - AcquireFlags(FLAG_CF); - InvalidateFlagsPartially((void*)&dynrec_adc_byte_simple,t_ADCb); - gen_call_function_raw((void*)&dynrec_adc_byte); - break; - case DOP_SUB: - InvalidateFlags((void*)&dynrec_sub_byte_simple,t_SUBb); - gen_call_function_raw((void*)&dynrec_sub_byte); - break; - case DOP_SBB: - AcquireFlags(FLAG_CF); - InvalidateFlagsPartially((void*)&dynrec_sbb_byte_simple,t_SBBb); - gen_call_function_raw((void*)&dynrec_sbb_byte); - break; - case DOP_CMP: - InvalidateFlags((void*)&dynrec_cmp_byte_simple,t_CMPb); - gen_call_function_raw((void*)&dynrec_cmp_byte); - break; - case DOP_XOR: - InvalidateFlags((void*)&dynrec_xor_byte_simple,t_XORb); - gen_call_function_raw((void*)&dynrec_xor_byte); - break; - case DOP_AND: - InvalidateFlags((void*)&dynrec_and_byte_simple,t_ANDb); - gen_call_function_raw((void*)&dynrec_and_byte); - break; - case DOP_OR: - InvalidateFlags((void*)&dynrec_or_byte_simple,t_ORb); - gen_call_function_raw((void*)&dynrec_or_byte); - break; - case DOP_TEST: - InvalidateFlags((void*)&dynrec_test_byte_simple,t_TESTb); - gen_call_function_raw((void*)&dynrec_test_byte); - break; - default: IllegalOptionDynrec("dyn_dop_byte_gencall"); - } -} - -static void dyn_dop_word_gencall(DualOps op,bool dword) { - if (dword) { - switch (op) { - case DOP_ADD: - InvalidateFlags((void*)&dynrec_add_dword_simple,t_ADDd); - gen_call_function_raw((void*)&dynrec_add_dword); - break; - case DOP_ADC: - AcquireFlags(FLAG_CF); - InvalidateFlagsPartially((void*)&dynrec_adc_dword_simple,t_ADCd); - gen_call_function_raw((void*)&dynrec_adc_dword); - break; - case DOP_SUB: - InvalidateFlags((void*)&dynrec_sub_dword_simple,t_SUBd); - gen_call_function_raw((void*)&dynrec_sub_dword); - break; - case DOP_SBB: - AcquireFlags(FLAG_CF); - InvalidateFlagsPartially((void*)&dynrec_sbb_dword_simple,t_SBBd); - gen_call_function_raw((void*)&dynrec_sbb_dword); - break; - case DOP_CMP: - InvalidateFlags((void*)&dynrec_cmp_dword_simple,t_CMPd); - gen_call_function_raw((void*)&dynrec_cmp_dword); - break; - case DOP_XOR: - InvalidateFlags((void*)&dynrec_xor_dword_simple,t_XORd); - gen_call_function_raw((void*)&dynrec_xor_dword); - break; - case DOP_AND: - InvalidateFlags((void*)&dynrec_and_dword_simple,t_ANDd); - gen_call_function_raw((void*)&dynrec_and_dword); - break; - case DOP_OR: - InvalidateFlags((void*)&dynrec_or_dword_simple,t_ORd); - gen_call_function_raw((void*)&dynrec_or_dword); - break; - case DOP_TEST: - InvalidateFlags((void*)&dynrec_test_dword_simple,t_TESTd); - gen_call_function_raw((void*)&dynrec_test_dword); - break; - default: IllegalOptionDynrec("dyn_dop_dword_gencall"); - } - } else { - switch (op) { - case DOP_ADD: - InvalidateFlags((void*)&dynrec_add_word_simple,t_ADDw); - gen_call_function_raw((void*)&dynrec_add_word); - break; - case DOP_ADC: - AcquireFlags(FLAG_CF); - InvalidateFlagsPartially((void*)&dynrec_adc_word_simple,t_ADCw); - gen_call_function_raw((void*)&dynrec_adc_word); - break; - case DOP_SUB: - InvalidateFlags((void*)&dynrec_sub_word_simple,t_SUBw); - gen_call_function_raw((void*)&dynrec_sub_word); - break; - case DOP_SBB: - AcquireFlags(FLAG_CF); - InvalidateFlagsPartially((void*)&dynrec_sbb_word_simple,t_SBBw); - gen_call_function_raw((void*)&dynrec_sbb_word); - break; - case DOP_CMP: - InvalidateFlags((void*)&dynrec_cmp_word_simple,t_CMPw); - gen_call_function_raw((void*)&dynrec_cmp_word); - break; - case DOP_XOR: - InvalidateFlags((void*)&dynrec_xor_word_simple,t_XORw); - gen_call_function_raw((void*)&dynrec_xor_word); - break; - case DOP_AND: - InvalidateFlags((void*)&dynrec_and_word_simple,t_ANDw); - gen_call_function_raw((void*)&dynrec_and_word); - break; - case DOP_OR: - InvalidateFlags((void*)&dynrec_or_word_simple,t_ORw); - gen_call_function_raw((void*)&dynrec_or_word); - break; - case DOP_TEST: - InvalidateFlags((void*)&dynrec_test_word_simple,t_TESTw); - gen_call_function_raw((void*)&dynrec_test_word); - break; - default: IllegalOptionDynrec("dyn_dop_word_gencall"); - } - } -} - - -static Bit8u DRC_CALL_CONV dynrec_inc_byte(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_inc_byte(Bit8u op) { - LoadCF; - lf_var1b=op; - lf_resb=lf_var1b+1; - lflags.type=t_INCb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_inc_byte_simple(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_inc_byte_simple(Bit8u op) { - return op+1; -} - -static Bit8u DRC_CALL_CONV dynrec_dec_byte(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_dec_byte(Bit8u op) { - LoadCF; - lf_var1b=op; - lf_resb=lf_var1b-1; - lflags.type=t_DECb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_dec_byte_simple(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_dec_byte_simple(Bit8u op) { - return op-1; -} - -static Bit8u DRC_CALL_CONV dynrec_not_byte(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_not_byte(Bit8u op) { - return ~op; -} - -static Bit8u DRC_CALL_CONV dynrec_neg_byte(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_neg_byte(Bit8u op) { - lf_var1b=op; - lf_resb=0-lf_var1b; - lflags.type=t_NEGb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_neg_byte_simple(Bit8u op) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_neg_byte_simple(Bit8u op) { - return 0-op; -} - -static Bit16u DRC_CALL_CONV dynrec_inc_word(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_inc_word(Bit16u op) { - LoadCF; - lf_var1w=op; - lf_resw=lf_var1w+1; - lflags.type=t_INCw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_inc_word_simple(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_inc_word_simple(Bit16u op) { - return op+1; -} - -static Bit16u DRC_CALL_CONV dynrec_dec_word(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dec_word(Bit16u op) { - LoadCF; - lf_var1w=op; - lf_resw=lf_var1w-1; - lflags.type=t_DECw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_dec_word_simple(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dec_word_simple(Bit16u op) { - return op-1; -} - -static Bit16u DRC_CALL_CONV dynrec_not_word(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_not_word(Bit16u op) { - return ~op; -} - -static Bit16u DRC_CALL_CONV dynrec_neg_word(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_neg_word(Bit16u op) { - lf_var1w=op; - lf_resw=0-lf_var1w; - lflags.type=t_NEGw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_neg_word_simple(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_neg_word_simple(Bit16u op) { - return 0-op; -} - -static Bit32u DRC_CALL_CONV dynrec_inc_dword(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_inc_dword(Bit32u op) { - LoadCF; - lf_var1d=op; - lf_resd=lf_var1d+1; - lflags.type=t_INCd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_inc_dword_simple(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_inc_dword_simple(Bit32u op) { - return op+1; -} - -static Bit32u DRC_CALL_CONV dynrec_dec_dword(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dec_dword(Bit32u op) { - LoadCF; - lf_var1d=op; - lf_resd=lf_var1d-1; - lflags.type=t_DECd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_dec_dword_simple(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dec_dword_simple(Bit32u op) { - return op-1; -} - -static Bit32u DRC_CALL_CONV dynrec_not_dword(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_not_dword(Bit32u op) { - return ~op; -} - -static Bit32u DRC_CALL_CONV dynrec_neg_dword(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_neg_dword(Bit32u op) { - lf_var1d=op; - lf_resd=0-lf_var1d; - lflags.type=t_NEGd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_neg_dword_simple(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_neg_dword_simple(Bit32u op) { - return 0-op; -} - - -static void dyn_sop_byte_gencall(SingleOps op) { - switch (op) { - case SOP_INC: - InvalidateFlagsPartially((void*)&dynrec_inc_byte_simple,t_INCb); - gen_call_function_raw((void*)&dynrec_inc_byte); - break; - case SOP_DEC: - InvalidateFlagsPartially((void*)&dynrec_dec_byte_simple,t_DECb); - gen_call_function_raw((void*)&dynrec_dec_byte); - break; - case SOP_NOT: - gen_call_function_raw((void*)&dynrec_not_byte); - break; - case SOP_NEG: - InvalidateFlags((void*)&dynrec_neg_byte_simple,t_NEGb); - gen_call_function_raw((void*)&dynrec_neg_byte); - break; - default: IllegalOptionDynrec("dyn_sop_byte_gencall"); - } -} - -static void dyn_sop_word_gencall(SingleOps op,bool dword) { - if (dword) { - switch (op) { - case SOP_INC: - InvalidateFlagsPartially((void*)&dynrec_inc_dword_simple,t_INCd); - gen_call_function_raw((void*)&dynrec_inc_dword); - break; - case SOP_DEC: - InvalidateFlagsPartially((void*)&dynrec_dec_dword_simple,t_DECd); - gen_call_function_raw((void*)&dynrec_dec_dword); - break; - case SOP_NOT: - gen_call_function_raw((void*)&dynrec_not_dword); - break; - case SOP_NEG: - InvalidateFlags((void*)&dynrec_neg_dword_simple,t_NEGd); - gen_call_function_raw((void*)&dynrec_neg_dword); - break; - default: IllegalOptionDynrec("dyn_sop_dword_gencall"); - } - } else { - switch (op) { - case SOP_INC: - InvalidateFlagsPartially((void*)&dynrec_inc_word_simple,t_INCw); - gen_call_function_raw((void*)&dynrec_inc_word); - break; - case SOP_DEC: - InvalidateFlagsPartially((void*)&dynrec_dec_word_simple,t_DECw); - gen_call_function_raw((void*)&dynrec_dec_word); - break; - case SOP_NOT: - gen_call_function_raw((void*)&dynrec_not_word); - break; - case SOP_NEG: - InvalidateFlags((void*)&dynrec_neg_word_simple,t_NEGw); - gen_call_function_raw((void*)&dynrec_neg_word); - break; - default: IllegalOptionDynrec("dyn_sop_word_gencall"); - } - } -} - - -static Bit8u DRC_CALL_CONV dynrec_rol_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_rol_byte(Bit8u op1,Bit8u op2) { - if (!(op2&0x7)) { - if (op2&0x18) { - FillFlagsNoCFOF(); - SETFLAGBIT(CF,op1 & 1); - SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 7)); - } - return op1; - } - FillFlagsNoCFOF(); - lf_var1b=op1; - lf_var2b=op2&0x07; - lf_resb=(lf_var1b << lf_var2b) | (lf_var1b >> (8-lf_var2b)); - SETFLAGBIT(CF,lf_resb & 1); - SETFLAGBIT(OF,(lf_resb & 1) ^ (lf_resb >> 7)); - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_rol_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_rol_byte_simple(Bit8u op1,Bit8u op2) { - if (!(op2&0x7)) return op1; - return (op1 << (op2&0x07)) | (op1 >> (8-(op2&0x07))); -} - -static Bit8u DRC_CALL_CONV dynrec_ror_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_ror_byte(Bit8u op1,Bit8u op2) { - if (!(op2&0x7)) { - if (op2&0x18) { - FillFlagsNoCFOF(); - SETFLAGBIT(CF,op1>>7); - SETFLAGBIT(OF,(op1>>7) ^ ((op1>>6) & 1)); - } - return op1; - } - FillFlagsNoCFOF(); - lf_var1b=op1; - lf_var2b=op2&0x07; - lf_resb=(lf_var1b >> lf_var2b) | (lf_var1b << (8-lf_var2b)); - SETFLAGBIT(CF,lf_resb & 0x80); - SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_ror_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_ror_byte_simple(Bit8u op1,Bit8u op2) { - if (!(op2&0x7)) return op1; - return (op1 >> (op2&0x07)) | (op1 << (8-(op2&0x07))); -} - -static Bit8u DRC_CALL_CONV dynrec_rcl_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_rcl_byte(Bit8u op1,Bit8u op2) { - if (op2%9) { - Bit8u cf=(Bit8u)FillFlags()&0x1; - lf_var1b=op1; - lf_var2b=op2%9; - lf_resb=(lf_var1b << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1b >> (9-lf_var2b)); - SETFLAGBIT(CF,((lf_var1b >> (8-lf_var2b)) & 1)); - SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resb >> 7)); - return lf_resb; - } else return op1; -} - -static Bit8u DRC_CALL_CONV dynrec_rcr_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_rcr_byte(Bit8u op1,Bit8u op2) { - if (op2%9) { - Bit8u cf=(Bit8u)FillFlags()&0x1; - lf_var1b=op1; - lf_var2b=op2%9; - lf_resb=(lf_var1b >> lf_var2b) | (cf << (8-lf_var2b)) | (lf_var1b << (9-lf_var2b)); \ - SETFLAGBIT(CF,(lf_var1b >> (lf_var2b - 1)) & 1); - SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); - return lf_resb; - } else return op1; -} - -static Bit8u DRC_CALL_CONV dynrec_shl_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_shl_byte(Bit8u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1b=op1; - lf_var2b=op2; - lf_resb=lf_var1b << lf_var2b; - lflags.type=t_SHLb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_shl_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_shl_byte_simple(Bit8u op1,Bit8u op2) { - if (!op2) return op1; - return op1 << op2; -} - -static Bit8u DRC_CALL_CONV dynrec_shr_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_shr_byte(Bit8u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1b=op1; - lf_var2b=op2; - lf_resb=lf_var1b >> lf_var2b; - lflags.type=t_SHRb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_shr_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_shr_byte_simple(Bit8u op1,Bit8u op2) { - if (!op2) return op1; - return op1 >> op2; -} - -static Bit8u DRC_CALL_CONV dynrec_sar_byte(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_sar_byte(Bit8u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1b=op1; - lf_var2b=op2; - if (lf_var2b>8) lf_var2b=8; - if (lf_var1b & 0x80) { - lf_resb=(lf_var1b >> lf_var2b)| (0xff << (8 - lf_var2b)); - } else { - lf_resb=lf_var1b >> lf_var2b; - } - lflags.type=t_SARb; - return lf_resb; -} - -static Bit8u DRC_CALL_CONV dynrec_sar_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; -static Bit8u DRC_CALL_CONV dynrec_sar_byte_simple(Bit8u op1,Bit8u op2) { - if (!op2) return op1; - if (op2>8) op2=8; - if (op1 & 0x80) return (op1 >> op2) | (0xff << (8 - op2)); - else return op1 >> op2; -} - -static Bit16u DRC_CALL_CONV dynrec_rol_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_rol_word(Bit16u op1,Bit8u op2) { - if (!(op2&0xf)) { - if (op2&0x10) { - FillFlagsNoCFOF(); - SETFLAGBIT(CF,op1 & 1); - SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 15)); - } - return op1; - } - FillFlagsNoCFOF(); - lf_var1w=op1; - lf_var2b=op2&0xf; - lf_resw=(lf_var1w << lf_var2b) | (lf_var1w >> (16-lf_var2b)); - SETFLAGBIT(CF,lf_resw & 1); - SETFLAGBIT(OF,(lf_resw & 1) ^ (lf_resw >> 15)); - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_rol_word_simple(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_rol_word_simple(Bit16u op1,Bit8u op2) { - if (!(op2&0xf)) return op1; - return (op1 << (op2&0xf)) | (op1 >> (16-(op2&0xf))); -} - -static Bit16u DRC_CALL_CONV dynrec_ror_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_ror_word(Bit16u op1,Bit8u op2) { - if (!(op2&0xf)) { - if (op2&0x10) { - FillFlagsNoCFOF(); - SETFLAGBIT(CF,op1>>15); - SETFLAGBIT(OF,(op1>>15) ^ ((op1>>14) & 1)); - } - return op1; - } - FillFlagsNoCFOF(); - lf_var1w=op1; - lf_var2b=op2&0xf; - lf_resw=(lf_var1w >> lf_var2b) | (lf_var1w << (16-lf_var2b)); - SETFLAGBIT(CF,lf_resw & 0x8000); - SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_ror_word_simple(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_ror_word_simple(Bit16u op1,Bit8u op2) { - if (!(op2&0xf)) return op1; - return (op1 >> (op2&0xf)) | (op1 << (16-(op2&0xf))); -} - -static Bit16u DRC_CALL_CONV dynrec_rcl_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_rcl_word(Bit16u op1,Bit8u op2) { - if (op2%17) { - Bit16u cf=(Bit16u)FillFlags()&0x1; - lf_var1w=op1; - lf_var2b=op2%17; - lf_resw=(lf_var1w << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1w >> (17-lf_var2b)); - SETFLAGBIT(CF,((lf_var1w >> (16-lf_var2b)) & 1)); - SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resw >> 15)); - return lf_resw; - } else return op1; -} - -static Bit16u DRC_CALL_CONV dynrec_rcr_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_rcr_word(Bit16u op1,Bit8u op2) { - if (op2%17) { - Bit16u cf=(Bit16u)FillFlags()&0x1; - lf_var1w=op1; - lf_var2b=op2%17; - lf_resw=(lf_var1w >> lf_var2b) | (cf << (16-lf_var2b)) | (lf_var1w << (17-lf_var2b)); - SETFLAGBIT(CF,(lf_var1w >> (lf_var2b - 1)) & 1); - SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); - return lf_resw; - } else return op1; -} - -static Bit16u DRC_CALL_CONV dynrec_shl_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_shl_word(Bit16u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1w=op1; - lf_var2b=op2; - lf_resw=lf_var1w << lf_var2b; - lflags.type=t_SHLw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_shl_word_simple(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_shl_word_simple(Bit16u op1,Bit8u op2) { - if (!op2) return op1; - return op1 << op2; -} - -static Bit16u DRC_CALL_CONV dynrec_shr_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_shr_word(Bit16u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1w=op1; - lf_var2b=op2; - lf_resw=lf_var1w >> lf_var2b; - lflags.type=t_SHRw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_shr_word_simple(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_shr_word_simple(Bit16u op1,Bit8u op2) { - if (!op2) return op1; - return op1 >> op2; -} - -static Bit16u DRC_CALL_CONV dynrec_sar_word(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_sar_word(Bit16u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1w=op1; - lf_var2b=op2; - if (lf_var2b>16) lf_var2b=16; - if (lf_var1w & 0x8000) { - lf_resw=(lf_var1w >> lf_var2b) | (0xffff << (16 - lf_var2b)); - } else { - lf_resw=lf_var1w >> lf_var2b; - } - lflags.type=t_SARw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_sar_word_simple(Bit16u op1,Bit8u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_sar_word_simple(Bit16u op1,Bit8u op2) { - if (!op2) return op1; - if (op2>16) op2=16; - if (op1 & 0x8000) return (op1 >> op2) | (0xffff << (16 - op2)); - else return op1 >> op2; -} - -static Bit32u DRC_CALL_CONV dynrec_rol_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_rol_dword(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - FillFlagsNoCFOF(); - lf_var1d=op1; - lf_var2b=op2; - lf_resd=(lf_var1d << lf_var2b) | (lf_var1d >> (32-lf_var2b)); - SETFLAGBIT(CF,lf_resd & 1); - SETFLAGBIT(OF,(lf_resd & 1) ^ (lf_resd >> 31)); - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_rol_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_rol_dword_simple(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - return (op1 << op2) | (op1 >> (32-op2)); -} - -static Bit32u DRC_CALL_CONV dynrec_ror_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_ror_dword(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - FillFlagsNoCFOF(); - lf_var1d=op1; - lf_var2b=op2; - lf_resd=(lf_var1d >> lf_var2b) | (lf_var1d << (32-lf_var2b)); - SETFLAGBIT(CF,lf_resd & 0x80000000); - SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_ror_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_ror_dword_simple(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - return (op1 >> op2) | (op1 << (32-op2)); -} - -static Bit32u DRC_CALL_CONV dynrec_rcl_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_rcl_dword(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - Bit32u cf=(Bit32u)FillFlags()&0x1; - lf_var1d=op1; - lf_var2b=op2; - if (lf_var2b==1) { - lf_resd=(lf_var1d << 1) | cf; - } else { - lf_resd=(lf_var1d << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1d >> (33-lf_var2b)); - } - SETFLAGBIT(CF,((lf_var1d >> (32-lf_var2b)) & 1)); - SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resd >> 31)); - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_rcr_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_rcr_dword(Bit32u op1,Bit8u op2) { - if (op2) { - Bit32u cf=(Bit32u)FillFlags()&0x1; - lf_var1d=op1; - lf_var2b=op2; - if (lf_var2b==1) { - lf_resd=lf_var1d >> 1 | cf << 31; - } else { - lf_resd=(lf_var1d >> lf_var2b) | (cf << (32-lf_var2b)) | (lf_var1d << (33-lf_var2b)); - } - SETFLAGBIT(CF,(lf_var1d >> (lf_var2b - 1)) & 1); - SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); - return lf_resd; - } else return op1; -} - -static Bit32u DRC_CALL_CONV dynrec_shl_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_shl_dword(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1d=op1; - lf_var2b=op2; - lf_resd=lf_var1d << lf_var2b; - lflags.type=t_SHLd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_shl_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_shl_dword_simple(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - return op1 << op2; -} - -static Bit32u DRC_CALL_CONV dynrec_shr_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_shr_dword(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - lf_var1d=op1; - lf_var2b=op2; - lf_resd=lf_var1d >> lf_var2b; - lflags.type=t_SHRd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_shr_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_shr_dword_simple(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - return op1 >> op2; -} - -static Bit32u DRC_CALL_CONV dynrec_sar_dword(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_sar_dword(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - lf_var2b=op2; - lf_var1d=op1; - if (lf_var1d & 0x80000000) { - lf_resd=(lf_var1d >> lf_var2b) | (0xffffffff << (32 - lf_var2b)); - } else { - lf_resd=lf_var1d >> lf_var2b; - } - lflags.type=t_SARd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_sar_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_sar_dword_simple(Bit32u op1,Bit8u op2) { - if (!op2) return op1; - if (op1 & 0x80000000) return (op1 >> op2) | (0xffffffff << (32 - op2)); - else return op1 >> op2; -} - -static void dyn_shift_byte_gencall(ShiftOps op) { - switch (op) { - case SHIFT_ROL: - InvalidateFlagsPartially((void*)&dynrec_rol_byte_simple,t_ROLb); - gen_call_function_raw((void*)&dynrec_rol_byte); - break; - case SHIFT_ROR: - InvalidateFlagsPartially((void*)&dynrec_ror_byte_simple,t_RORb); - gen_call_function_raw((void*)&dynrec_ror_byte); - break; - case SHIFT_RCL: - AcquireFlags(FLAG_CF); - gen_call_function_raw((void*)&dynrec_rcl_byte); - break; - case SHIFT_RCR: - AcquireFlags(FLAG_CF); - gen_call_function_raw((void*)&dynrec_rcr_byte); - break; - case SHIFT_SHL: - case SHIFT_SAL: - InvalidateFlagsPartially((void*)&dynrec_shl_byte_simple,t_SHLb); - gen_call_function_raw((void*)&dynrec_shl_byte); - break; - case SHIFT_SHR: - InvalidateFlagsPartially((void*)&dynrec_shr_byte_simple,t_SHRb); - gen_call_function_raw((void*)&dynrec_shr_byte); - break; - case SHIFT_SAR: - InvalidateFlagsPartially((void*)&dynrec_sar_byte_simple,t_SARb); - gen_call_function_raw((void*)&dynrec_sar_byte); - break; - default: IllegalOptionDynrec("dyn_shift_byte_gencall"); - } -} - -static void dyn_shift_word_gencall(ShiftOps op,bool dword) { - if (dword) { - switch (op) { - case SHIFT_ROL: - InvalidateFlagsPartially((void*)&dynrec_rol_dword_simple,t_ROLd); - gen_call_function_raw((void*)&dynrec_rol_dword); - break; - case SHIFT_ROR: - InvalidateFlagsPartially((void*)&dynrec_ror_dword_simple,t_RORd); - gen_call_function_raw((void*)&dynrec_ror_dword); - break; - case SHIFT_RCL: - AcquireFlags(FLAG_CF); - gen_call_function_raw((void*)&dynrec_rcl_dword); - break; - case SHIFT_RCR: - AcquireFlags(FLAG_CF); - gen_call_function_raw((void*)&dynrec_rcr_dword); - break; - case SHIFT_SHL: - case SHIFT_SAL: - InvalidateFlagsPartially((void*)&dynrec_shl_dword_simple,t_SHLd); - gen_call_function_raw((void*)&dynrec_shl_dword); - break; - case SHIFT_SHR: - InvalidateFlagsPartially((void*)&dynrec_shr_dword_simple,t_SHRd); - gen_call_function_raw((void*)&dynrec_shr_dword); - break; - case SHIFT_SAR: - InvalidateFlagsPartially((void*)&dynrec_sar_dword_simple,t_SARd); - gen_call_function_raw((void*)&dynrec_sar_dword); - break; - default: IllegalOptionDynrec("dyn_shift_dword_gencall"); - } - } else { - switch (op) { - case SHIFT_ROL: - InvalidateFlagsPartially((void*)&dynrec_rol_word_simple,t_ROLw); - gen_call_function_raw((void*)&dynrec_rol_word); - break; - case SHIFT_ROR: - InvalidateFlagsPartially((void*)&dynrec_ror_word_simple,t_RORw); - gen_call_function_raw((void*)&dynrec_ror_word); - break; - case SHIFT_RCL: - AcquireFlags(FLAG_CF); - gen_call_function_raw((void*)&dynrec_rcl_word); - break; - case SHIFT_RCR: - AcquireFlags(FLAG_CF); - gen_call_function_raw((void*)&dynrec_rcr_word); - break; - case SHIFT_SHL: - case SHIFT_SAL: - InvalidateFlagsPartially((void*)&dynrec_shl_word_simple,t_SHLw); - gen_call_function_raw((void*)&dynrec_shl_word); - break; - case SHIFT_SHR: - InvalidateFlagsPartially((void*)&dynrec_shr_word_simple,t_SHRw); - gen_call_function_raw((void*)&dynrec_shr_word); - break; - case SHIFT_SAR: - InvalidateFlagsPartially((void*)&dynrec_sar_word_simple,t_SARw); - gen_call_function_raw((void*)&dynrec_sar_word); - break; - default: IllegalOptionDynrec("dyn_shift_word_gencall"); - } - } -} - -static Bit16u DRC_CALL_CONV dynrec_dshl_word(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dshl_word(Bit16u op1,Bit16u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - lf_var2b=val; - lf_var1d=(op1<<16)|op2; - Bit32u tempd=lf_var1d << lf_var2b; - if (lf_var2b>16) tempd |= (op2 << (lf_var2b - 16)); - lf_resw=(Bit16u)(tempd >> 16); - lflags.type=t_DSHLw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_dshl_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dshl_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - Bit32u tempd=(Bit32u)((((Bit32u)op1)<<16)|op2) << val; - if (val>16) tempd |= (op2 << (val - 16)); - return (Bit16u)(tempd >> 16); -} - -static Bit32u DRC_CALL_CONV dynrec_dshl_dword(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dshl_dword(Bit32u op1,Bit32u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - lf_var2b=val; - lf_var1d=op1; - lf_resd=(lf_var1d << lf_var2b) | (op2 >> (32-lf_var2b)); - lflags.type=t_DSHLd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_dshl_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dshl_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - return (op1 << val) | (op2 >> (32-val)); -} - -static Bit16u DRC_CALL_CONV dynrec_dshr_word(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dshr_word(Bit16u op1,Bit16u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - lf_var2b=val; - lf_var1d=(op2<<16)|op1; - Bit32u tempd=lf_var1d >> lf_var2b; - if (lf_var2b>16) tempd |= (op2 << (32-lf_var2b )); - lf_resw=(Bit16u)(tempd); - lflags.type=t_DSHRw; - return lf_resw; -} - -static Bit16u DRC_CALL_CONV dynrec_dshr_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dshr_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - Bit32u tempd=(Bit32u)((((Bit32u)op2)<<16)|op1) >> val; - if (val>16) tempd |= (op2 << (32-val)); - return (Bit16u)(tempd); -} - -static Bit32u DRC_CALL_CONV dynrec_dshr_dword(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dshr_dword(Bit32u op1,Bit32u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - lf_var2b=val; - lf_var1d=op1; - lf_resd=(lf_var1d >> lf_var2b) | (op2 << (32-lf_var2b)); - lflags.type=t_DSHRd; - return lf_resd; -} - -static Bit32u DRC_CALL_CONV dynrec_dshr_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dshr_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) { - Bit8u val=op3 & 0x1f; - if (!val) return op1; - return (op1 >> val) | (op2 << (32-val)); -} - -static void dyn_dpshift_word_gencall(bool left) { - if (left) { - DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshl_word,FC_OP3); - InvalidateFlagsPartially((void*)&dynrec_dshl_word_simple,proc_addr,t_DSHLw); - } else { - DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshr_word,FC_OP3); - InvalidateFlagsPartially((void*)&dynrec_dshr_word_simple,proc_addr,t_DSHRw); - } -} - -static void dyn_dpshift_dword_gencall(bool left) { - if (left) { - DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshl_dword,FC_OP3); - InvalidateFlagsPartially((void*)&dynrec_dshl_dword_simple,proc_addr,t_DSHLd); - } else { - DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshr_dword,FC_OP3); - InvalidateFlagsPartially((void*)&dynrec_dshr_dword_simple,proc_addr,t_DSHRd); - } -} - - - -static Bit32u DRC_CALL_CONV dynrec_get_of(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_of(void) { return TFLG_O; } -static Bit32u DRC_CALL_CONV dynrec_get_nof(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_nof(void) { return TFLG_NO; } -static Bit32u DRC_CALL_CONV dynrec_get_cf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_cf(void) { return TFLG_B; } -static Bit32u DRC_CALL_CONV dynrec_get_ncf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_ncf(void) { return TFLG_NB; } -static Bit32u DRC_CALL_CONV dynrec_get_zf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_zf(void) { return TFLG_Z; } -static Bit32u DRC_CALL_CONV dynrec_get_nzf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_nzf(void) { return TFLG_NZ; } -static Bit32u DRC_CALL_CONV dynrec_get_sf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_sf(void) { return TFLG_S; } -static Bit32u DRC_CALL_CONV dynrec_get_nsf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_nsf(void) { return TFLG_NS; } -static Bit32u DRC_CALL_CONV dynrec_get_pf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_pf(void) { return TFLG_P; } -static Bit32u DRC_CALL_CONV dynrec_get_npf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_npf(void) { return TFLG_NP; } - -static Bit32u DRC_CALL_CONV dynrec_get_cf_or_zf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_cf_or_zf(void) { return TFLG_BE; } -static Bit32u DRC_CALL_CONV dynrec_get_ncf_and_nzf(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_ncf_and_nzf(void) { return TFLG_NBE; } -static Bit32u DRC_CALL_CONV dynrec_get_sf_neq_of(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_sf_neq_of(void) { return TFLG_L; } -static Bit32u DRC_CALL_CONV dynrec_get_sf_eq_of(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_sf_eq_of(void) { return TFLG_NL; } -static Bit32u DRC_CALL_CONV dynrec_get_zf_or_sf_neq_of(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_zf_or_sf_neq_of(void) { return TFLG_LE; } -static Bit32u DRC_CALL_CONV dynrec_get_nzf_and_sf_eq_of(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_get_nzf_and_sf_eq_of(void) { return TFLG_NLE; } - - -static void dyn_branchflag_to_reg(BranchTypes btype) { - switch (btype) { - case BR_O:gen_call_function_raw((void*)&dynrec_get_of);break; - case BR_NO:gen_call_function_raw((void*)&dynrec_get_nof);break; - case BR_B:gen_call_function_raw((void*)&dynrec_get_cf);break; - case BR_NB:gen_call_function_raw((void*)&dynrec_get_ncf);break; - case BR_Z:gen_call_function_raw((void*)&dynrec_get_zf);break; - case BR_NZ:gen_call_function_raw((void*)&dynrec_get_nzf);break; - case BR_BE:gen_call_function_raw((void*)&dynrec_get_cf_or_zf);break; - case BR_NBE:gen_call_function_raw((void*)&dynrec_get_ncf_and_nzf);break; - - case BR_S:gen_call_function_raw((void*)&dynrec_get_sf);break; - case BR_NS:gen_call_function_raw((void*)&dynrec_get_nsf);break; - case BR_P:gen_call_function_raw((void*)&dynrec_get_pf);break; - case BR_NP:gen_call_function_raw((void*)&dynrec_get_npf);break; - case BR_L:gen_call_function_raw((void*)&dynrec_get_sf_neq_of);break; - case BR_NL:gen_call_function_raw((void*)&dynrec_get_sf_eq_of);break; - case BR_LE:gen_call_function_raw((void*)&dynrec_get_zf_or_sf_neq_of);break; - case BR_NLE:gen_call_function_raw((void*)&dynrec_get_nzf_and_sf_eq_of);break; - } -} - - -static void DRC_CALL_CONV dynrec_mul_byte(Bit8u op) DRC_FC; -static void DRC_CALL_CONV dynrec_mul_byte(Bit8u op) { - FillFlagsNoCFOF(); - reg_ax=reg_al*op; - SETFLAGBIT(ZF,reg_al == 0); - if (reg_ax & 0xff00) { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } else { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } -} - -static void DRC_CALL_CONV dynrec_imul_byte(Bit8u op) DRC_FC; -static void DRC_CALL_CONV dynrec_imul_byte(Bit8u op) { - FillFlagsNoCFOF(); - reg_ax=((Bit8s)reg_al) * ((Bit8s)op); - if ((reg_ax & 0xff80)==0xff80 || (reg_ax & 0xff80)==0x0000) { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } else { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } -} - -static void DRC_CALL_CONV dynrec_mul_word(Bit16u op) DRC_FC; -static void DRC_CALL_CONV dynrec_mul_word(Bit16u op) { - FillFlagsNoCFOF(); - Bitu tempu=(Bitu)reg_ax*(Bitu)op; - reg_ax=(Bit16u)(tempu); - reg_dx=(Bit16u)(tempu >> 16); - SETFLAGBIT(ZF,reg_ax == 0); - if (reg_dx) { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } else { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } -} - -static void DRC_CALL_CONV dynrec_imul_word(Bit16u op) DRC_FC; -static void DRC_CALL_CONV dynrec_imul_word(Bit16u op) { - FillFlagsNoCFOF(); - Bits temps=((Bit16s)reg_ax)*((Bit16s)op); - reg_ax=(Bit16s)(temps); - reg_dx=(Bit16s)(temps >> 16); - if (((temps & 0xffff8000)==0xffff8000 || (temps & 0xffff8000)==0x0000)) { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } else { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } -} - -static void DRC_CALL_CONV dynrec_mul_dword(Bit32u op) DRC_FC; -static void DRC_CALL_CONV dynrec_mul_dword(Bit32u op) { - FillFlagsNoCFOF(); - Bit64u tempu=(Bit64u)reg_eax*(Bit64u)op; - reg_eax=(Bit32u)(tempu); - reg_edx=(Bit32u)(tempu >> 32); - SETFLAGBIT(ZF,reg_eax == 0); - if (reg_edx) { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } else { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } -} - -static void DRC_CALL_CONV dynrec_imul_dword(Bit32u op) DRC_FC; -static void DRC_CALL_CONV dynrec_imul_dword(Bit32u op) { - FillFlagsNoCFOF(); - Bit64s temps=((Bit64s)((Bit32s)reg_eax))*((Bit64s)((Bit32s)op)); - reg_eax=(Bit32u)(temps); - reg_edx=(Bit32u)(temps >> 32); - if ((reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } else if ( (reg_edx==0x00000000) && (reg_eax< 0x80000000) ) { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } else { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } -} - - -static bool DRC_CALL_CONV dynrec_div_byte(Bit8u op) DRC_FC; -static bool DRC_CALL_CONV dynrec_div_byte(Bit8u op) { - Bitu val=op; - if (val==0) return CPU_PrepareException(0,0); - Bitu quo=reg_ax / val; - 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 DRC_CALL_CONV dynrec_idiv_byte(Bit8u op) DRC_FC; -static bool DRC_CALL_CONV dynrec_idiv_byte(Bit8u op) { - Bits val=(Bit8s)op; - if (val==0) return CPU_PrepareException(0,0); - Bits quo=((Bit16s)reg_ax) / val; - 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; -} - -static bool DRC_CALL_CONV dynrec_div_word(Bit16u op) DRC_FC; -static bool DRC_CALL_CONV dynrec_div_word(Bit16u op) { - Bitu val=op; - if (val==0) return CPU_PrepareException(0,0); - Bitu num=((Bit32u)reg_dx<<16)|reg_ax; - Bitu quo=num/val; - 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; -} - -static bool DRC_CALL_CONV dynrec_idiv_word(Bit16u op) DRC_FC; -static bool DRC_CALL_CONV dynrec_idiv_word(Bit16u op) { - Bits val=(Bit16s)op; - if (val==0) return CPU_PrepareException(0,0); - Bits num=(Bit32s)((reg_dx<<16)|reg_ax); - Bits quo=num/val; - 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; -} - -static bool DRC_CALL_CONV dynrec_div_dword(Bit32u op) DRC_FC; -static bool DRC_CALL_CONV dynrec_div_dword(Bit32u op) { - Bitu val=op; - if (val==0) return CPU_PrepareException(0,0); - Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax; - Bit64u quo=num/val; - 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; -} - -static bool DRC_CALL_CONV dynrec_idiv_dword(Bit32u op) DRC_FC; -static bool DRC_CALL_CONV dynrec_idiv_dword(Bit32u op) { - Bits val=(Bit32s)op; - if (val==0) return CPU_PrepareException(0,0); - Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax; - Bit64s quo=num/val; - 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; -} - - -static Bit16u DRC_CALL_CONV dynrec_dimul_word(Bit16u op1,Bit16u op2) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_dimul_word(Bit16u op1,Bit16u op2) { - FillFlagsNoCFOF(); - Bits res=((Bit16s)op1) * ((Bit16s)op2); - if ((res>-32768) && (res<32767)) { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } else { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } - return (Bit16u)(res & 0xffff); -} - -static Bit32u DRC_CALL_CONV dynrec_dimul_dword(Bit32u op1,Bit32u op2) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_dimul_dword(Bit32u op1,Bit32u op2) { - FillFlagsNoCFOF(); - Bit64s res=((Bit64s)((Bit32s)op1))*((Bit64s)((Bit32s)op2)); - if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) { - SETFLAGBIT(CF,false); - SETFLAGBIT(OF,false); - } else { - SETFLAGBIT(CF,true); - SETFLAGBIT(OF,true); - } - return (Bit32s)res; -} - - - -static Bit16u DRC_CALL_CONV dynrec_cbw(Bit8u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_cbw(Bit8u op) { - return (Bit8s)op; -} - -static Bit32u DRC_CALL_CONV dynrec_cwde(Bit16u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_cwde(Bit16u op) { - return (Bit16s)op; -} - -static Bit16u DRC_CALL_CONV dynrec_cwd(Bit16u op) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_cwd(Bit16u op) { - if (op & 0x8000) return 0xffff; - else return 0; -} - -static Bit32u DRC_CALL_CONV dynrec_cdq(Bit32u op) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_cdq(Bit32u op) { - if (op & 0x80000000) return 0xffffffff; - else return 0; -} - - -static void DRC_CALL_CONV dynrec_sahf(Bit16u op) DRC_FC; -static void DRC_CALL_CONV dynrec_sahf(Bit16u op) { - SETFLAGBIT(OF,get_OF()); - lflags.type=t_UNKNOWN; - CPU_SetFlags(op>>8,FMASK_NORMAL & 0xff); -} - - -static void DRC_CALL_CONV dynrec_cmc(void) DRC_FC; -static void DRC_CALL_CONV dynrec_cmc(void) { - FillFlags(); - SETFLAGBIT(CF,!(reg_flags & FLAG_CF)); -} -static void DRC_CALL_CONV dynrec_clc(void) DRC_FC; -static void DRC_CALL_CONV dynrec_clc(void) { - FillFlags(); - SETFLAGBIT(CF,false); -} -static void DRC_CALL_CONV dynrec_stc(void) DRC_FC; -static void DRC_CALL_CONV dynrec_stc(void) { - FillFlags(); - SETFLAGBIT(CF,true); -} -static void DRC_CALL_CONV dynrec_cld(void) DRC_FC; -static void DRC_CALL_CONV dynrec_cld(void) { - SETFLAGBIT(DF,false); - cpu.direction=1; -} -static void DRC_CALL_CONV dynrec_std(void) DRC_FC; -static void DRC_CALL_CONV dynrec_std(void) { - SETFLAGBIT(DF,true); - cpu.direction=-1; -} - - -static Bit16u DRC_CALL_CONV dynrec_movsb_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_movsb_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - for (;count>0;count--) { - mem_writeb(di_base+reg_di,mem_readb(si_base+reg_si)); - reg_si+=add_index; - reg_di+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_movsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_movsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - for (;count>0;count--) { - mem_writeb(di_base+reg_edi,mem_readb(si_base+reg_esi)); - reg_esi+=add_index; - reg_edi+=add_index; - } - return count_left; -} - -static Bit16u DRC_CALL_CONV dynrec_movsw_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_movsw_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=1; - for (;count>0;count--) { - mem_writew(di_base+reg_di,mem_readw(si_base+reg_si)); - reg_si+=add_index; - reg_di+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_movsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_movsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=1; - for (;count>0;count--) { - mem_writew(di_base+reg_edi,mem_readw(si_base+reg_esi)); - reg_esi+=add_index; - reg_edi+=add_index; - } - return count_left; -} - -static Bit16u DRC_CALL_CONV dynrec_movsd_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_movsd_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=2; - for (;count>0;count--) { - mem_writed(di_base+reg_di,mem_readd(si_base+reg_si)); - reg_si+=add_index; - reg_di+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_movsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_movsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=2; - for (;count>0;count--) { - mem_writed(di_base+reg_edi,mem_readd(si_base+reg_esi)); - reg_esi+=add_index; - reg_edi+=add_index; - } - return count_left; -} - - -static Bit16u DRC_CALL_CONV dynrec_lodsb_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_lodsb_word(Bit16u count,Bit16s add_index,PhysPt si_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - for (;count>0;count--) { - reg_al=mem_readb(si_base+reg_si); - reg_si+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_lodsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_lodsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - for (;count>0;count--) { - reg_al=mem_readb(si_base+reg_esi); - reg_esi+=add_index; - } - return count_left; -} - -static Bit16u DRC_CALL_CONV dynrec_lodsw_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_lodsw_word(Bit16u count,Bit16s add_index,PhysPt si_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=1; - for (;count>0;count--) { - reg_ax=mem_readw(si_base+reg_si); - reg_si+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_lodsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_lodsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=1; - for (;count>0;count--) { - reg_ax=mem_readw(si_base+reg_esi); - reg_esi+=add_index; - } - return count_left; -} - -static Bit16u DRC_CALL_CONV dynrec_lodsd_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_lodsd_word(Bit16u count,Bit16s add_index,PhysPt si_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=2; - for (;count>0;count--) { - reg_eax=mem_readd(si_base+reg_si); - reg_si+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_lodsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_lodsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=2; - for (;count>0;count--) { - reg_eax=mem_readd(si_base+reg_esi); - reg_esi+=add_index; - } - return count_left; -} - - -static Bit16u DRC_CALL_CONV dynrec_stosb_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_stosb_word(Bit16u count,Bit16s add_index,PhysPt di_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - for (;count>0;count--) { - mem_writeb(di_base+reg_di,reg_al); - reg_di+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_stosb_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_stosb_dword(Bit32u count,Bit32s add_index,PhysPt di_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - for (;count>0;count--) { - mem_writeb(di_base+reg_edi,reg_al); - reg_edi+=add_index; - } - return count_left; -} - -static Bit16u DRC_CALL_CONV dynrec_stosw_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_stosw_word(Bit16u count,Bit16s add_index,PhysPt di_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=1; - for (;count>0;count--) { - mem_writew(di_base+reg_di,reg_ax); - reg_di+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_stosw_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_stosw_dword(Bit32u count,Bit32s add_index,PhysPt di_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=1; - for (;count>0;count--) { - mem_writew(di_base+reg_edi,reg_ax); - reg_edi+=add_index; - } - return count_left; -} - -static Bit16u DRC_CALL_CONV dynrec_stosd_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_stosd_word(Bit16u count,Bit16s add_index,PhysPt di_base) { - Bit16u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=(Bit16u)(count-CPU_Cycles); - count=(Bit16u)CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=2; - for (;count>0;count--) { - mem_writed(di_base+reg_di,reg_eax); - reg_di+=add_index; - } - return count_left; -} - -static Bit32u DRC_CALL_CONV dynrec_stosd_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_stosd_dword(Bit32u count,Bit32s add_index,PhysPt di_base) { - Bit32u count_left; - if (count<(Bitu)CPU_Cycles) { - count_left=0; - } else { - count_left=count-CPU_Cycles; - count=CPU_Cycles; - CPU_Cycles=0; - } - add_index<<=2; - for (;count>0;count--) { - mem_writed(di_base+reg_edi,reg_eax); - reg_edi+=add_index; - } - return count_left; -} - - -static void DRC_CALL_CONV dynrec_push_word(Bit16u value) DRC_FC; -static void DRC_CALL_CONV dynrec_push_word(Bit16u value) { - Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask); - mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask),value); - reg_esp=new_esp; -} - -static void DRC_CALL_CONV dynrec_push_dword(Bit32u value) DRC_FC; -static void DRC_CALL_CONV dynrec_push_dword(Bit32u value) { - Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask); - mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value); - reg_esp=new_esp; -} - -static Bit16u DRC_CALL_CONV dynrec_pop_word(void) DRC_FC; -static Bit16u DRC_CALL_CONV dynrec_pop_word(void) { - Bit16u val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); - reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask); - return val; -} - -static Bit32u DRC_CALL_CONV dynrec_pop_dword(void) DRC_FC; -static Bit32u DRC_CALL_CONV dynrec_pop_dword(void) { - Bit32u val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask)); - reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask); - return val; -} +/* + * Copyright (C) 2002-2010 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: operators.h,v 1.8 2009-06-25 19:31:43 c2woody Exp $ */ + + +static Bit8u DRC_CALL_CONV dynrec_add_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_add_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=(Bit8u)(lf_var1b+lf_var2b); + lflags.type=t_ADDb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_add_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_add_byte_simple(Bit8u op1,Bit8u op2) { + return op1+op2; +} + +static Bit8u DRC_CALL_CONV dynrec_adc_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_adc_byte(Bit8u op1,Bit8u op2) { + lflags.oldcf=get_CF()!=0; + lf_var1b=op1; + lf_var2b=op2; + lf_resb=(Bit8u)(lf_var1b+lf_var2b+lflags.oldcf); + lflags.type=t_ADCb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_adc_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_adc_byte_simple(Bit8u op1,Bit8u op2) { + return (Bit8u)(op1+op2+(Bitu)(get_CF()!=0)); +} + +static Bit8u DRC_CALL_CONV dynrec_sub_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_sub_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=(Bit8u)(lf_var1b-lf_var2b); + lflags.type=t_SUBb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_sub_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_sub_byte_simple(Bit8u op1,Bit8u op2) { + return op1-op2; +} + +static Bit8u DRC_CALL_CONV dynrec_sbb_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_sbb_byte(Bit8u op1,Bit8u op2) { + lflags.oldcf=get_CF()!=0; + lf_var1b=op1; + lf_var2b=op2; + lf_resb=(Bit8u)(lf_var1b-(lf_var2b+lflags.oldcf)); + lflags.type=t_SBBb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_sbb_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_sbb_byte_simple(Bit8u op1,Bit8u op2) { + return (Bit8u)(op1-(op2+(Bitu)(get_CF()!=0))); +} + +static void DRC_CALL_CONV dynrec_cmp_byte(Bit8u op1,Bit8u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_cmp_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=(Bit8u)(lf_var1b-lf_var2b); + lflags.type=t_CMPb; +} + +static void DRC_CALL_CONV dynrec_cmp_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_cmp_byte_simple(Bit8u op1,Bit8u op2) { +} + +static Bit8u DRC_CALL_CONV dynrec_xor_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_xor_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=lf_var1b ^ lf_var2b; + lflags.type=t_XORb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_xor_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_xor_byte_simple(Bit8u op1,Bit8u op2) { + return op1 ^ op2; +} + +static Bit8u DRC_CALL_CONV dynrec_and_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_and_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=lf_var1b & lf_var2b; + lflags.type=t_ANDb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_and_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_and_byte_simple(Bit8u op1,Bit8u op2) { + return op1 & op2; +} + +static Bit8u DRC_CALL_CONV dynrec_or_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_or_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=lf_var1b | lf_var2b; + lflags.type=t_ORb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_or_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_or_byte_simple(Bit8u op1,Bit8u op2) { + return op1 | op2; +} + +static void DRC_CALL_CONV dynrec_test_byte(Bit8u op1,Bit8u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_test_byte(Bit8u op1,Bit8u op2) { + lf_var1b=op1; + lf_var2b=op2; + lf_resb=lf_var1b & lf_var2b; + lflags.type=t_TESTb; +} + +static void DRC_CALL_CONV dynrec_test_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_test_byte_simple(Bit8u op1,Bit8u op2) { +} + +static Bit16u DRC_CALL_CONV dynrec_add_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_add_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=(Bit16u)(lf_var1w+lf_var2w); + lflags.type=t_ADDw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_add_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_add_word_simple(Bit16u op1,Bit16u op2) { + return op1+op2; +} + +static Bit16u DRC_CALL_CONV dynrec_adc_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_adc_word(Bit16u op1,Bit16u op2) { + lflags.oldcf=get_CF()!=0; + lf_var1w=op1; + lf_var2w=op2; + lf_resw=(Bit16u)(lf_var1w+lf_var2w+lflags.oldcf); + lflags.type=t_ADCw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_adc_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_adc_word_simple(Bit16u op1,Bit16u op2) { + return (Bit16u)(op1+op2+(Bitu)(get_CF()!=0)); +} + +static Bit16u DRC_CALL_CONV dynrec_sub_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_sub_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=(Bit16u)(lf_var1w-lf_var2w); + lflags.type=t_SUBw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_sub_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_sub_word_simple(Bit16u op1,Bit16u op2) { + return op1-op2; +} + +static Bit16u DRC_CALL_CONV dynrec_sbb_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_sbb_word(Bit16u op1,Bit16u op2) { + lflags.oldcf=get_CF()!=0; + lf_var1w=op1; + lf_var2w=op2; + lf_resw=(Bit16u)(lf_var1w-(lf_var2w+lflags.oldcf)); + lflags.type=t_SBBw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_sbb_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_sbb_word_simple(Bit16u op1,Bit16u op2) { + return (Bit16u)(op1-(op2+(Bitu)(get_CF()!=0))); +} + +static void DRC_CALL_CONV dynrec_cmp_word(Bit16u op1,Bit16u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_cmp_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=(Bit16u)(lf_var1w-lf_var2w); + lflags.type=t_CMPw; +} + +static void DRC_CALL_CONV dynrec_cmp_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_cmp_word_simple(Bit16u op1,Bit16u op2) { +} + +static Bit16u DRC_CALL_CONV dynrec_xor_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_xor_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=lf_var1w ^ lf_var2w; + lflags.type=t_XORw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_xor_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_xor_word_simple(Bit16u op1,Bit16u op2) { + return op1 ^ op2; +} + +static Bit16u DRC_CALL_CONV dynrec_and_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_and_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=lf_var1w & lf_var2w; + lflags.type=t_ANDw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_and_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_and_word_simple(Bit16u op1,Bit16u op2) { + return op1 & op2; +} + +static Bit16u DRC_CALL_CONV dynrec_or_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_or_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=lf_var1w | lf_var2w; + lflags.type=t_ORw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_or_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_or_word_simple(Bit16u op1,Bit16u op2) { + return op1 | op2; +} + +static void DRC_CALL_CONV dynrec_test_word(Bit16u op1,Bit16u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_test_word(Bit16u op1,Bit16u op2) { + lf_var1w=op1; + lf_var2w=op2; + lf_resw=lf_var1w & lf_var2w; + lflags.type=t_TESTw; +} + +static void DRC_CALL_CONV dynrec_test_word_simple(Bit16u op1,Bit16u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_test_word_simple(Bit16u op1,Bit16u op2) { +} + +static Bit32u DRC_CALL_CONV dynrec_add_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_add_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d+lf_var2d; + lflags.type=t_ADDd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_add_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_add_dword_simple(Bit32u op1,Bit32u op2) { + return op1 + op2; +} + +static Bit32u DRC_CALL_CONV dynrec_adc_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_adc_dword(Bit32u op1,Bit32u op2) { + lflags.oldcf=get_CF()!=0; + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d+lf_var2d+lflags.oldcf; + lflags.type=t_ADCd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_adc_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_adc_dword_simple(Bit32u op1,Bit32u op2) { + return op1+op2+(Bitu)(get_CF()!=0); +} + +static Bit32u DRC_CALL_CONV dynrec_sub_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_sub_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d-lf_var2d; + lflags.type=t_SUBd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_sub_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_sub_dword_simple(Bit32u op1,Bit32u op2) { + return op1-op2; +} + +static Bit32u DRC_CALL_CONV dynrec_sbb_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_sbb_dword(Bit32u op1,Bit32u op2) { + lflags.oldcf=get_CF()!=0; + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d-(lf_var2d+lflags.oldcf); + lflags.type=t_SBBd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_sbb_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_sbb_dword_simple(Bit32u op1,Bit32u op2) { + return op1-(op2+(Bitu)(get_CF()!=0)); +} + +static void DRC_CALL_CONV dynrec_cmp_dword(Bit32u op1,Bit32u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_cmp_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d-lf_var2d; + lflags.type=t_CMPd; +} + +static void DRC_CALL_CONV dynrec_cmp_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_cmp_dword_simple(Bit32u op1,Bit32u op2) { +} + +static Bit32u DRC_CALL_CONV dynrec_xor_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_xor_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d ^ lf_var2d; + lflags.type=t_XORd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_xor_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_xor_dword_simple(Bit32u op1,Bit32u op2) { + return op1 ^ op2; +} + +static Bit32u DRC_CALL_CONV dynrec_and_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_and_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d & lf_var2d; + lflags.type=t_ANDd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_and_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_and_dword_simple(Bit32u op1,Bit32u op2) { + return op1 & op2; +} + +static Bit32u DRC_CALL_CONV dynrec_or_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_or_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d | lf_var2d; + lflags.type=t_ORd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_or_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_or_dword_simple(Bit32u op1,Bit32u op2) { + return op1 | op2; +} + +static void DRC_CALL_CONV dynrec_test_dword(Bit32u op1,Bit32u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_test_dword(Bit32u op1,Bit32u op2) { + lf_var1d=op1; + lf_var2d=op2; + lf_resd=lf_var1d & lf_var2d; + lflags.type=t_TESTd; +} + +static void DRC_CALL_CONV dynrec_test_dword_simple(Bit32u op1,Bit32u op2) DRC_FC; +static void DRC_CALL_CONV dynrec_test_dword_simple(Bit32u op1,Bit32u op2) { +} + + +static void dyn_dop_byte_gencall(DualOps op) { + switch (op) { + case DOP_ADD: + InvalidateFlags((void*)&dynrec_add_byte_simple,t_ADDb); + gen_call_function_raw((void*)&dynrec_add_byte); + break; + case DOP_ADC: + AcquireFlags(FLAG_CF); + InvalidateFlagsPartially((void*)&dynrec_adc_byte_simple,t_ADCb); + gen_call_function_raw((void*)&dynrec_adc_byte); + break; + case DOP_SUB: + InvalidateFlags((void*)&dynrec_sub_byte_simple,t_SUBb); + gen_call_function_raw((void*)&dynrec_sub_byte); + break; + case DOP_SBB: + AcquireFlags(FLAG_CF); + InvalidateFlagsPartially((void*)&dynrec_sbb_byte_simple,t_SBBb); + gen_call_function_raw((void*)&dynrec_sbb_byte); + break; + case DOP_CMP: + InvalidateFlags((void*)&dynrec_cmp_byte_simple,t_CMPb); + gen_call_function_raw((void*)&dynrec_cmp_byte); + break; + case DOP_XOR: + InvalidateFlags((void*)&dynrec_xor_byte_simple,t_XORb); + gen_call_function_raw((void*)&dynrec_xor_byte); + break; + case DOP_AND: + InvalidateFlags((void*)&dynrec_and_byte_simple,t_ANDb); + gen_call_function_raw((void*)&dynrec_and_byte); + break; + case DOP_OR: + InvalidateFlags((void*)&dynrec_or_byte_simple,t_ORb); + gen_call_function_raw((void*)&dynrec_or_byte); + break; + case DOP_TEST: + InvalidateFlags((void*)&dynrec_test_byte_simple,t_TESTb); + gen_call_function_raw((void*)&dynrec_test_byte); + break; + default: IllegalOptionDynrec("dyn_dop_byte_gencall"); + } +} + +static void dyn_dop_word_gencall(DualOps op,bool dword) { + if (dword) { + switch (op) { + case DOP_ADD: + InvalidateFlags((void*)&dynrec_add_dword_simple,t_ADDd); + gen_call_function_raw((void*)&dynrec_add_dword); + break; + case DOP_ADC: + AcquireFlags(FLAG_CF); + InvalidateFlagsPartially((void*)&dynrec_adc_dword_simple,t_ADCd); + gen_call_function_raw((void*)&dynrec_adc_dword); + break; + case DOP_SUB: + InvalidateFlags((void*)&dynrec_sub_dword_simple,t_SUBd); + gen_call_function_raw((void*)&dynrec_sub_dword); + break; + case DOP_SBB: + AcquireFlags(FLAG_CF); + InvalidateFlagsPartially((void*)&dynrec_sbb_dword_simple,t_SBBd); + gen_call_function_raw((void*)&dynrec_sbb_dword); + break; + case DOP_CMP: + InvalidateFlags((void*)&dynrec_cmp_dword_simple,t_CMPd); + gen_call_function_raw((void*)&dynrec_cmp_dword); + break; + case DOP_XOR: + InvalidateFlags((void*)&dynrec_xor_dword_simple,t_XORd); + gen_call_function_raw((void*)&dynrec_xor_dword); + break; + case DOP_AND: + InvalidateFlags((void*)&dynrec_and_dword_simple,t_ANDd); + gen_call_function_raw((void*)&dynrec_and_dword); + break; + case DOP_OR: + InvalidateFlags((void*)&dynrec_or_dword_simple,t_ORd); + gen_call_function_raw((void*)&dynrec_or_dword); + break; + case DOP_TEST: + InvalidateFlags((void*)&dynrec_test_dword_simple,t_TESTd); + gen_call_function_raw((void*)&dynrec_test_dword); + break; + default: IllegalOptionDynrec("dyn_dop_dword_gencall"); + } + } else { + switch (op) { + case DOP_ADD: + InvalidateFlags((void*)&dynrec_add_word_simple,t_ADDw); + gen_call_function_raw((void*)&dynrec_add_word); + break; + case DOP_ADC: + AcquireFlags(FLAG_CF); + InvalidateFlagsPartially((void*)&dynrec_adc_word_simple,t_ADCw); + gen_call_function_raw((void*)&dynrec_adc_word); + break; + case DOP_SUB: + InvalidateFlags((void*)&dynrec_sub_word_simple,t_SUBw); + gen_call_function_raw((void*)&dynrec_sub_word); + break; + case DOP_SBB: + AcquireFlags(FLAG_CF); + InvalidateFlagsPartially((void*)&dynrec_sbb_word_simple,t_SBBw); + gen_call_function_raw((void*)&dynrec_sbb_word); + break; + case DOP_CMP: + InvalidateFlags((void*)&dynrec_cmp_word_simple,t_CMPw); + gen_call_function_raw((void*)&dynrec_cmp_word); + break; + case DOP_XOR: + InvalidateFlags((void*)&dynrec_xor_word_simple,t_XORw); + gen_call_function_raw((void*)&dynrec_xor_word); + break; + case DOP_AND: + InvalidateFlags((void*)&dynrec_and_word_simple,t_ANDw); + gen_call_function_raw((void*)&dynrec_and_word); + break; + case DOP_OR: + InvalidateFlags((void*)&dynrec_or_word_simple,t_ORw); + gen_call_function_raw((void*)&dynrec_or_word); + break; + case DOP_TEST: + InvalidateFlags((void*)&dynrec_test_word_simple,t_TESTw); + gen_call_function_raw((void*)&dynrec_test_word); + break; + default: IllegalOptionDynrec("dyn_dop_word_gencall"); + } + } +} + + +static Bit8u DRC_CALL_CONV dynrec_inc_byte(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_inc_byte(Bit8u op) { + LoadCF; + lf_var1b=op; + lf_resb=lf_var1b+1; + lflags.type=t_INCb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_inc_byte_simple(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_inc_byte_simple(Bit8u op) { + return op+1; +} + +static Bit8u DRC_CALL_CONV dynrec_dec_byte(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_dec_byte(Bit8u op) { + LoadCF; + lf_var1b=op; + lf_resb=lf_var1b-1; + lflags.type=t_DECb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_dec_byte_simple(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_dec_byte_simple(Bit8u op) { + return op-1; +} + +static Bit8u DRC_CALL_CONV dynrec_not_byte(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_not_byte(Bit8u op) { + return ~op; +} + +static Bit8u DRC_CALL_CONV dynrec_neg_byte(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_neg_byte(Bit8u op) { + lf_var1b=op; + lf_resb=0-lf_var1b; + lflags.type=t_NEGb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_neg_byte_simple(Bit8u op) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_neg_byte_simple(Bit8u op) { + return 0-op; +} + +static Bit16u DRC_CALL_CONV dynrec_inc_word(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_inc_word(Bit16u op) { + LoadCF; + lf_var1w=op; + lf_resw=lf_var1w+1; + lflags.type=t_INCw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_inc_word_simple(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_inc_word_simple(Bit16u op) { + return op+1; +} + +static Bit16u DRC_CALL_CONV dynrec_dec_word(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dec_word(Bit16u op) { + LoadCF; + lf_var1w=op; + lf_resw=lf_var1w-1; + lflags.type=t_DECw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_dec_word_simple(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dec_word_simple(Bit16u op) { + return op-1; +} + +static Bit16u DRC_CALL_CONV dynrec_not_word(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_not_word(Bit16u op) { + return ~op; +} + +static Bit16u DRC_CALL_CONV dynrec_neg_word(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_neg_word(Bit16u op) { + lf_var1w=op; + lf_resw=0-lf_var1w; + lflags.type=t_NEGw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_neg_word_simple(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_neg_word_simple(Bit16u op) { + return 0-op; +} + +static Bit32u DRC_CALL_CONV dynrec_inc_dword(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_inc_dword(Bit32u op) { + LoadCF; + lf_var1d=op; + lf_resd=lf_var1d+1; + lflags.type=t_INCd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_inc_dword_simple(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_inc_dword_simple(Bit32u op) { + return op+1; +} + +static Bit32u DRC_CALL_CONV dynrec_dec_dword(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dec_dword(Bit32u op) { + LoadCF; + lf_var1d=op; + lf_resd=lf_var1d-1; + lflags.type=t_DECd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_dec_dword_simple(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dec_dword_simple(Bit32u op) { + return op-1; +} + +static Bit32u DRC_CALL_CONV dynrec_not_dword(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_not_dword(Bit32u op) { + return ~op; +} + +static Bit32u DRC_CALL_CONV dynrec_neg_dword(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_neg_dword(Bit32u op) { + lf_var1d=op; + lf_resd=0-lf_var1d; + lflags.type=t_NEGd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_neg_dword_simple(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_neg_dword_simple(Bit32u op) { + return 0-op; +} + + +static void dyn_sop_byte_gencall(SingleOps op) { + switch (op) { + case SOP_INC: + InvalidateFlagsPartially((void*)&dynrec_inc_byte_simple,t_INCb); + gen_call_function_raw((void*)&dynrec_inc_byte); + break; + case SOP_DEC: + InvalidateFlagsPartially((void*)&dynrec_dec_byte_simple,t_DECb); + gen_call_function_raw((void*)&dynrec_dec_byte); + break; + case SOP_NOT: + gen_call_function_raw((void*)&dynrec_not_byte); + break; + case SOP_NEG: + InvalidateFlags((void*)&dynrec_neg_byte_simple,t_NEGb); + gen_call_function_raw((void*)&dynrec_neg_byte); + break; + default: IllegalOptionDynrec("dyn_sop_byte_gencall"); + } +} + +static void dyn_sop_word_gencall(SingleOps op,bool dword) { + if (dword) { + switch (op) { + case SOP_INC: + InvalidateFlagsPartially((void*)&dynrec_inc_dword_simple,t_INCd); + gen_call_function_raw((void*)&dynrec_inc_dword); + break; + case SOP_DEC: + InvalidateFlagsPartially((void*)&dynrec_dec_dword_simple,t_DECd); + gen_call_function_raw((void*)&dynrec_dec_dword); + break; + case SOP_NOT: + gen_call_function_raw((void*)&dynrec_not_dword); + break; + case SOP_NEG: + InvalidateFlags((void*)&dynrec_neg_dword_simple,t_NEGd); + gen_call_function_raw((void*)&dynrec_neg_dword); + break; + default: IllegalOptionDynrec("dyn_sop_dword_gencall"); + } + } else { + switch (op) { + case SOP_INC: + InvalidateFlagsPartially((void*)&dynrec_inc_word_simple,t_INCw); + gen_call_function_raw((void*)&dynrec_inc_word); + break; + case SOP_DEC: + InvalidateFlagsPartially((void*)&dynrec_dec_word_simple,t_DECw); + gen_call_function_raw((void*)&dynrec_dec_word); + break; + case SOP_NOT: + gen_call_function_raw((void*)&dynrec_not_word); + break; + case SOP_NEG: + InvalidateFlags((void*)&dynrec_neg_word_simple,t_NEGw); + gen_call_function_raw((void*)&dynrec_neg_word); + break; + default: IllegalOptionDynrec("dyn_sop_word_gencall"); + } + } +} + + +static Bit8u DRC_CALL_CONV dynrec_rol_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_rol_byte(Bit8u op1,Bit8u op2) { + if (!(op2&0x7)) { + if (op2&0x18) { + FillFlagsNoCFOF(); + SETFLAGBIT(CF,op1 & 1); + SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 7)); + } + return op1; + } + FillFlagsNoCFOF(); + lf_var1b=op1; + lf_var2b=op2&0x07; + lf_resb=(lf_var1b << lf_var2b) | (lf_var1b >> (8-lf_var2b)); + SETFLAGBIT(CF,lf_resb & 1); + SETFLAGBIT(OF,(lf_resb & 1) ^ (lf_resb >> 7)); + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_rol_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_rol_byte_simple(Bit8u op1,Bit8u op2) { + if (!(op2&0x7)) return op1; + return (op1 << (op2&0x07)) | (op1 >> (8-(op2&0x07))); +} + +static Bit8u DRC_CALL_CONV dynrec_ror_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_ror_byte(Bit8u op1,Bit8u op2) { + if (!(op2&0x7)) { + if (op2&0x18) { + FillFlagsNoCFOF(); + SETFLAGBIT(CF,op1>>7); + SETFLAGBIT(OF,(op1>>7) ^ ((op1>>6) & 1)); + } + return op1; + } + FillFlagsNoCFOF(); + lf_var1b=op1; + lf_var2b=op2&0x07; + lf_resb=(lf_var1b >> lf_var2b) | (lf_var1b << (8-lf_var2b)); + SETFLAGBIT(CF,lf_resb & 0x80); + SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_ror_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_ror_byte_simple(Bit8u op1,Bit8u op2) { + if (!(op2&0x7)) return op1; + return (op1 >> (op2&0x07)) | (op1 << (8-(op2&0x07))); +} + +static Bit8u DRC_CALL_CONV dynrec_rcl_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_rcl_byte(Bit8u op1,Bit8u op2) { + if (op2%9) { + Bit8u cf=(Bit8u)FillFlags()&0x1; + lf_var1b=op1; + lf_var2b=op2%9; + lf_resb=(lf_var1b << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1b >> (9-lf_var2b)); + SETFLAGBIT(CF,((lf_var1b >> (8-lf_var2b)) & 1)); + SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resb >> 7)); + return lf_resb; + } else return op1; +} + +static Bit8u DRC_CALL_CONV dynrec_rcr_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_rcr_byte(Bit8u op1,Bit8u op2) { + if (op2%9) { + Bit8u cf=(Bit8u)FillFlags()&0x1; + lf_var1b=op1; + lf_var2b=op2%9; + lf_resb=(lf_var1b >> lf_var2b) | (cf << (8-lf_var2b)) | (lf_var1b << (9-lf_var2b)); \ + SETFLAGBIT(CF,(lf_var1b >> (lf_var2b - 1)) & 1); + SETFLAGBIT(OF,(lf_resb ^ (lf_resb<<1)) & 0x80); + return lf_resb; + } else return op1; +} + +static Bit8u DRC_CALL_CONV dynrec_shl_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_shl_byte(Bit8u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1b=op1; + lf_var2b=op2; + lf_resb=lf_var1b << lf_var2b; + lflags.type=t_SHLb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_shl_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_shl_byte_simple(Bit8u op1,Bit8u op2) { + if (!op2) return op1; + return op1 << op2; +} + +static Bit8u DRC_CALL_CONV dynrec_shr_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_shr_byte(Bit8u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1b=op1; + lf_var2b=op2; + lf_resb=lf_var1b >> lf_var2b; + lflags.type=t_SHRb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_shr_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_shr_byte_simple(Bit8u op1,Bit8u op2) { + if (!op2) return op1; + return op1 >> op2; +} + +static Bit8u DRC_CALL_CONV dynrec_sar_byte(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_sar_byte(Bit8u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1b=op1; + lf_var2b=op2; + if (lf_var2b>8) lf_var2b=8; + if (lf_var1b & 0x80) { + lf_resb=(lf_var1b >> lf_var2b)| (0xff << (8 - lf_var2b)); + } else { + lf_resb=lf_var1b >> lf_var2b; + } + lflags.type=t_SARb; + return lf_resb; +} + +static Bit8u DRC_CALL_CONV dynrec_sar_byte_simple(Bit8u op1,Bit8u op2) DRC_FC; +static Bit8u DRC_CALL_CONV dynrec_sar_byte_simple(Bit8u op1,Bit8u op2) { + if (!op2) return op1; + if (op2>8) op2=8; + if (op1 & 0x80) return (op1 >> op2) | (0xff << (8 - op2)); + else return op1 >> op2; +} + +static Bit16u DRC_CALL_CONV dynrec_rol_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_rol_word(Bit16u op1,Bit8u op2) { + if (!(op2&0xf)) { + if (op2&0x10) { + FillFlagsNoCFOF(); + SETFLAGBIT(CF,op1 & 1); + SETFLAGBIT(OF,(op1 & 1) ^ (op1 >> 15)); + } + return op1; + } + FillFlagsNoCFOF(); + lf_var1w=op1; + lf_var2b=op2&0xf; + lf_resw=(lf_var1w << lf_var2b) | (lf_var1w >> (16-lf_var2b)); + SETFLAGBIT(CF,lf_resw & 1); + SETFLAGBIT(OF,(lf_resw & 1) ^ (lf_resw >> 15)); + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_rol_word_simple(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_rol_word_simple(Bit16u op1,Bit8u op2) { + if (!(op2&0xf)) return op1; + return (op1 << (op2&0xf)) | (op1 >> (16-(op2&0xf))); +} + +static Bit16u DRC_CALL_CONV dynrec_ror_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_ror_word(Bit16u op1,Bit8u op2) { + if (!(op2&0xf)) { + if (op2&0x10) { + FillFlagsNoCFOF(); + SETFLAGBIT(CF,op1>>15); + SETFLAGBIT(OF,(op1>>15) ^ ((op1>>14) & 1)); + } + return op1; + } + FillFlagsNoCFOF(); + lf_var1w=op1; + lf_var2b=op2&0xf; + lf_resw=(lf_var1w >> lf_var2b) | (lf_var1w << (16-lf_var2b)); + SETFLAGBIT(CF,lf_resw & 0x8000); + SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_ror_word_simple(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_ror_word_simple(Bit16u op1,Bit8u op2) { + if (!(op2&0xf)) return op1; + return (op1 >> (op2&0xf)) | (op1 << (16-(op2&0xf))); +} + +static Bit16u DRC_CALL_CONV dynrec_rcl_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_rcl_word(Bit16u op1,Bit8u op2) { + if (op2%17) { + Bit16u cf=(Bit16u)FillFlags()&0x1; + lf_var1w=op1; + lf_var2b=op2%17; + lf_resw=(lf_var1w << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1w >> (17-lf_var2b)); + SETFLAGBIT(CF,((lf_var1w >> (16-lf_var2b)) & 1)); + SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resw >> 15)); + return lf_resw; + } else return op1; +} + +static Bit16u DRC_CALL_CONV dynrec_rcr_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_rcr_word(Bit16u op1,Bit8u op2) { + if (op2%17) { + Bit16u cf=(Bit16u)FillFlags()&0x1; + lf_var1w=op1; + lf_var2b=op2%17; + lf_resw=(lf_var1w >> lf_var2b) | (cf << (16-lf_var2b)) | (lf_var1w << (17-lf_var2b)); + SETFLAGBIT(CF,(lf_var1w >> (lf_var2b - 1)) & 1); + SETFLAGBIT(OF,(lf_resw ^ (lf_resw<<1)) & 0x8000); + return lf_resw; + } else return op1; +} + +static Bit16u DRC_CALL_CONV dynrec_shl_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_shl_word(Bit16u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1w=op1; + lf_var2b=op2; + lf_resw=lf_var1w << lf_var2b; + lflags.type=t_SHLw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_shl_word_simple(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_shl_word_simple(Bit16u op1,Bit8u op2) { + if (!op2) return op1; + return op1 << op2; +} + +static Bit16u DRC_CALL_CONV dynrec_shr_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_shr_word(Bit16u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1w=op1; + lf_var2b=op2; + lf_resw=lf_var1w >> lf_var2b; + lflags.type=t_SHRw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_shr_word_simple(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_shr_word_simple(Bit16u op1,Bit8u op2) { + if (!op2) return op1; + return op1 >> op2; +} + +static Bit16u DRC_CALL_CONV dynrec_sar_word(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_sar_word(Bit16u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1w=op1; + lf_var2b=op2; + if (lf_var2b>16) lf_var2b=16; + if (lf_var1w & 0x8000) { + lf_resw=(lf_var1w >> lf_var2b) | (0xffff << (16 - lf_var2b)); + } else { + lf_resw=lf_var1w >> lf_var2b; + } + lflags.type=t_SARw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_sar_word_simple(Bit16u op1,Bit8u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_sar_word_simple(Bit16u op1,Bit8u op2) { + if (!op2) return op1; + if (op2>16) op2=16; + if (op1 & 0x8000) return (op1 >> op2) | (0xffff << (16 - op2)); + else return op1 >> op2; +} + +static Bit32u DRC_CALL_CONV dynrec_rol_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_rol_dword(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + FillFlagsNoCFOF(); + lf_var1d=op1; + lf_var2b=op2; + lf_resd=(lf_var1d << lf_var2b) | (lf_var1d >> (32-lf_var2b)); + SETFLAGBIT(CF,lf_resd & 1); + SETFLAGBIT(OF,(lf_resd & 1) ^ (lf_resd >> 31)); + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_rol_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_rol_dword_simple(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + return (op1 << op2) | (op1 >> (32-op2)); +} + +static Bit32u DRC_CALL_CONV dynrec_ror_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_ror_dword(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + FillFlagsNoCFOF(); + lf_var1d=op1; + lf_var2b=op2; + lf_resd=(lf_var1d >> lf_var2b) | (lf_var1d << (32-lf_var2b)); + SETFLAGBIT(CF,lf_resd & 0x80000000); + SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_ror_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_ror_dword_simple(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + return (op1 >> op2) | (op1 << (32-op2)); +} + +static Bit32u DRC_CALL_CONV dynrec_rcl_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_rcl_dword(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + Bit32u cf=(Bit32u)FillFlags()&0x1; + lf_var1d=op1; + lf_var2b=op2; + if (lf_var2b==1) { + lf_resd=(lf_var1d << 1) | cf; + } else { + lf_resd=(lf_var1d << lf_var2b) | (cf << (lf_var2b-1)) | (lf_var1d >> (33-lf_var2b)); + } + SETFLAGBIT(CF,((lf_var1d >> (32-lf_var2b)) & 1)); + SETFLAGBIT(OF,(reg_flags & 1) ^ (lf_resd >> 31)); + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_rcr_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_rcr_dword(Bit32u op1,Bit8u op2) { + if (op2) { + Bit32u cf=(Bit32u)FillFlags()&0x1; + lf_var1d=op1; + lf_var2b=op2; + if (lf_var2b==1) { + lf_resd=lf_var1d >> 1 | cf << 31; + } else { + lf_resd=(lf_var1d >> lf_var2b) | (cf << (32-lf_var2b)) | (lf_var1d << (33-lf_var2b)); + } + SETFLAGBIT(CF,(lf_var1d >> (lf_var2b - 1)) & 1); + SETFLAGBIT(OF,(lf_resd ^ (lf_resd<<1)) & 0x80000000); + return lf_resd; + } else return op1; +} + +static Bit32u DRC_CALL_CONV dynrec_shl_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_shl_dword(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1d=op1; + lf_var2b=op2; + lf_resd=lf_var1d << lf_var2b; + lflags.type=t_SHLd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_shl_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_shl_dword_simple(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + return op1 << op2; +} + +static Bit32u DRC_CALL_CONV dynrec_shr_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_shr_dword(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + lf_var1d=op1; + lf_var2b=op2; + lf_resd=lf_var1d >> lf_var2b; + lflags.type=t_SHRd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_shr_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_shr_dword_simple(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + return op1 >> op2; +} + +static Bit32u DRC_CALL_CONV dynrec_sar_dword(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_sar_dword(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + lf_var2b=op2; + lf_var1d=op1; + if (lf_var1d & 0x80000000) { + lf_resd=(lf_var1d >> lf_var2b) | (0xffffffff << (32 - lf_var2b)); + } else { + lf_resd=lf_var1d >> lf_var2b; + } + lflags.type=t_SARd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_sar_dword_simple(Bit32u op1,Bit8u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_sar_dword_simple(Bit32u op1,Bit8u op2) { + if (!op2) return op1; + if (op1 & 0x80000000) return (op1 >> op2) | (0xffffffff << (32 - op2)); + else return op1 >> op2; +} + +static void dyn_shift_byte_gencall(ShiftOps op) { + switch (op) { + case SHIFT_ROL: + InvalidateFlagsPartially((void*)&dynrec_rol_byte_simple,t_ROLb); + gen_call_function_raw((void*)&dynrec_rol_byte); + break; + case SHIFT_ROR: + InvalidateFlagsPartially((void*)&dynrec_ror_byte_simple,t_RORb); + gen_call_function_raw((void*)&dynrec_ror_byte); + break; + case SHIFT_RCL: + AcquireFlags(FLAG_CF); + gen_call_function_raw((void*)&dynrec_rcl_byte); + break; + case SHIFT_RCR: + AcquireFlags(FLAG_CF); + gen_call_function_raw((void*)&dynrec_rcr_byte); + break; + case SHIFT_SHL: + case SHIFT_SAL: + InvalidateFlagsPartially((void*)&dynrec_shl_byte_simple,t_SHLb); + gen_call_function_raw((void*)&dynrec_shl_byte); + break; + case SHIFT_SHR: + InvalidateFlagsPartially((void*)&dynrec_shr_byte_simple,t_SHRb); + gen_call_function_raw((void*)&dynrec_shr_byte); + break; + case SHIFT_SAR: + InvalidateFlagsPartially((void*)&dynrec_sar_byte_simple,t_SARb); + gen_call_function_raw((void*)&dynrec_sar_byte); + break; + default: IllegalOptionDynrec("dyn_shift_byte_gencall"); + } +} + +static void dyn_shift_word_gencall(ShiftOps op,bool dword) { + if (dword) { + switch (op) { + case SHIFT_ROL: + InvalidateFlagsPartially((void*)&dynrec_rol_dword_simple,t_ROLd); + gen_call_function_raw((void*)&dynrec_rol_dword); + break; + case SHIFT_ROR: + InvalidateFlagsPartially((void*)&dynrec_ror_dword_simple,t_RORd); + gen_call_function_raw((void*)&dynrec_ror_dword); + break; + case SHIFT_RCL: + AcquireFlags(FLAG_CF); + gen_call_function_raw((void*)&dynrec_rcl_dword); + break; + case SHIFT_RCR: + AcquireFlags(FLAG_CF); + gen_call_function_raw((void*)&dynrec_rcr_dword); + break; + case SHIFT_SHL: + case SHIFT_SAL: + InvalidateFlagsPartially((void*)&dynrec_shl_dword_simple,t_SHLd); + gen_call_function_raw((void*)&dynrec_shl_dword); + break; + case SHIFT_SHR: + InvalidateFlagsPartially((void*)&dynrec_shr_dword_simple,t_SHRd); + gen_call_function_raw((void*)&dynrec_shr_dword); + break; + case SHIFT_SAR: + InvalidateFlagsPartially((void*)&dynrec_sar_dword_simple,t_SARd); + gen_call_function_raw((void*)&dynrec_sar_dword); + break; + default: IllegalOptionDynrec("dyn_shift_dword_gencall"); + } + } else { + switch (op) { + case SHIFT_ROL: + InvalidateFlagsPartially((void*)&dynrec_rol_word_simple,t_ROLw); + gen_call_function_raw((void*)&dynrec_rol_word); + break; + case SHIFT_ROR: + InvalidateFlagsPartially((void*)&dynrec_ror_word_simple,t_RORw); + gen_call_function_raw((void*)&dynrec_ror_word); + break; + case SHIFT_RCL: + AcquireFlags(FLAG_CF); + gen_call_function_raw((void*)&dynrec_rcl_word); + break; + case SHIFT_RCR: + AcquireFlags(FLAG_CF); + gen_call_function_raw((void*)&dynrec_rcr_word); + break; + case SHIFT_SHL: + case SHIFT_SAL: + InvalidateFlagsPartially((void*)&dynrec_shl_word_simple,t_SHLw); + gen_call_function_raw((void*)&dynrec_shl_word); + break; + case SHIFT_SHR: + InvalidateFlagsPartially((void*)&dynrec_shr_word_simple,t_SHRw); + gen_call_function_raw((void*)&dynrec_shr_word); + break; + case SHIFT_SAR: + InvalidateFlagsPartially((void*)&dynrec_sar_word_simple,t_SARw); + gen_call_function_raw((void*)&dynrec_sar_word); + break; + default: IllegalOptionDynrec("dyn_shift_word_gencall"); + } + } +} + +static Bit16u DRC_CALL_CONV dynrec_dshl_word(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dshl_word(Bit16u op1,Bit16u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + lf_var2b=val; + lf_var1d=(op1<<16)|op2; + Bit32u tempd=lf_var1d << lf_var2b; + if (lf_var2b>16) tempd |= (op2 << (lf_var2b - 16)); + lf_resw=(Bit16u)(tempd >> 16); + lflags.type=t_DSHLw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_dshl_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dshl_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + Bit32u tempd=(Bit32u)((((Bit32u)op1)<<16)|op2) << val; + if (val>16) tempd |= (op2 << (val - 16)); + return (Bit16u)(tempd >> 16); +} + +static Bit32u DRC_CALL_CONV dynrec_dshl_dword(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dshl_dword(Bit32u op1,Bit32u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + lf_var2b=val; + lf_var1d=op1; + lf_resd=(lf_var1d << lf_var2b) | (op2 >> (32-lf_var2b)); + lflags.type=t_DSHLd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_dshl_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dshl_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + return (op1 << val) | (op2 >> (32-val)); +} + +static Bit16u DRC_CALL_CONV dynrec_dshr_word(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dshr_word(Bit16u op1,Bit16u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + lf_var2b=val; + lf_var1d=(op2<<16)|op1; + Bit32u tempd=lf_var1d >> lf_var2b; + if (lf_var2b>16) tempd |= (op2 << (32-lf_var2b )); + lf_resw=(Bit16u)(tempd); + lflags.type=t_DSHRw; + return lf_resw; +} + +static Bit16u DRC_CALL_CONV dynrec_dshr_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dshr_word_simple(Bit16u op1,Bit16u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + Bit32u tempd=(Bit32u)((((Bit32u)op2)<<16)|op1) >> val; + if (val>16) tempd |= (op2 << (32-val)); + return (Bit16u)(tempd); +} + +static Bit32u DRC_CALL_CONV dynrec_dshr_dword(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dshr_dword(Bit32u op1,Bit32u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + lf_var2b=val; + lf_var1d=op1; + lf_resd=(lf_var1d >> lf_var2b) | (op2 << (32-lf_var2b)); + lflags.type=t_DSHRd; + return lf_resd; +} + +static Bit32u DRC_CALL_CONV dynrec_dshr_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dshr_dword_simple(Bit32u op1,Bit32u op2,Bit8u op3) { + Bit8u val=op3 & 0x1f; + if (!val) return op1; + return (op1 >> val) | (op2 << (32-val)); +} + +static void dyn_dpshift_word_gencall(bool left) { + if (left) { + DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshl_word,FC_OP3); + InvalidateFlagsPartially((void*)&dynrec_dshl_word_simple,proc_addr,t_DSHLw); + } else { + DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshr_word,FC_OP3); + InvalidateFlagsPartially((void*)&dynrec_dshr_word_simple,proc_addr,t_DSHRw); + } +} + +static void dyn_dpshift_dword_gencall(bool left) { + if (left) { + DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshl_dword,FC_OP3); + InvalidateFlagsPartially((void*)&dynrec_dshl_dword_simple,proc_addr,t_DSHLd); + } else { + DRC_PTR_SIZE_IM proc_addr=gen_call_function_R3((void*)&dynrec_dshr_dword,FC_OP3); + InvalidateFlagsPartially((void*)&dynrec_dshr_dword_simple,proc_addr,t_DSHRd); + } +} + + + +static Bit32u DRC_CALL_CONV dynrec_get_of(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_of(void) { return TFLG_O; } +static Bit32u DRC_CALL_CONV dynrec_get_nof(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_nof(void) { return TFLG_NO; } +static Bit32u DRC_CALL_CONV dynrec_get_cf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_cf(void) { return TFLG_B; } +static Bit32u DRC_CALL_CONV dynrec_get_ncf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_ncf(void) { return TFLG_NB; } +static Bit32u DRC_CALL_CONV dynrec_get_zf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_zf(void) { return TFLG_Z; } +static Bit32u DRC_CALL_CONV dynrec_get_nzf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_nzf(void) { return TFLG_NZ; } +static Bit32u DRC_CALL_CONV dynrec_get_sf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_sf(void) { return TFLG_S; } +static Bit32u DRC_CALL_CONV dynrec_get_nsf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_nsf(void) { return TFLG_NS; } +static Bit32u DRC_CALL_CONV dynrec_get_pf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_pf(void) { return TFLG_P; } +static Bit32u DRC_CALL_CONV dynrec_get_npf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_npf(void) { return TFLG_NP; } + +static Bit32u DRC_CALL_CONV dynrec_get_cf_or_zf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_cf_or_zf(void) { return TFLG_BE; } +static Bit32u DRC_CALL_CONV dynrec_get_ncf_and_nzf(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_ncf_and_nzf(void) { return TFLG_NBE; } +static Bit32u DRC_CALL_CONV dynrec_get_sf_neq_of(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_sf_neq_of(void) { return TFLG_L; } +static Bit32u DRC_CALL_CONV dynrec_get_sf_eq_of(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_sf_eq_of(void) { return TFLG_NL; } +static Bit32u DRC_CALL_CONV dynrec_get_zf_or_sf_neq_of(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_zf_or_sf_neq_of(void) { return TFLG_LE; } +static Bit32u DRC_CALL_CONV dynrec_get_nzf_and_sf_eq_of(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_get_nzf_and_sf_eq_of(void) { return TFLG_NLE; } + + +static void dyn_branchflag_to_reg(BranchTypes btype) { + switch (btype) { + case BR_O:gen_call_function_raw((void*)&dynrec_get_of);break; + case BR_NO:gen_call_function_raw((void*)&dynrec_get_nof);break; + case BR_B:gen_call_function_raw((void*)&dynrec_get_cf);break; + case BR_NB:gen_call_function_raw((void*)&dynrec_get_ncf);break; + case BR_Z:gen_call_function_raw((void*)&dynrec_get_zf);break; + case BR_NZ:gen_call_function_raw((void*)&dynrec_get_nzf);break; + case BR_BE:gen_call_function_raw((void*)&dynrec_get_cf_or_zf);break; + case BR_NBE:gen_call_function_raw((void*)&dynrec_get_ncf_and_nzf);break; + + case BR_S:gen_call_function_raw((void*)&dynrec_get_sf);break; + case BR_NS:gen_call_function_raw((void*)&dynrec_get_nsf);break; + case BR_P:gen_call_function_raw((void*)&dynrec_get_pf);break; + case BR_NP:gen_call_function_raw((void*)&dynrec_get_npf);break; + case BR_L:gen_call_function_raw((void*)&dynrec_get_sf_neq_of);break; + case BR_NL:gen_call_function_raw((void*)&dynrec_get_sf_eq_of);break; + case BR_LE:gen_call_function_raw((void*)&dynrec_get_zf_or_sf_neq_of);break; + case BR_NLE:gen_call_function_raw((void*)&dynrec_get_nzf_and_sf_eq_of);break; + } +} + + +static void DRC_CALL_CONV dynrec_mul_byte(Bit8u op) DRC_FC; +static void DRC_CALL_CONV dynrec_mul_byte(Bit8u op) { + FillFlagsNoCFOF(); + reg_ax=reg_al*op; + SETFLAGBIT(ZF,reg_al == 0); + if (reg_ax & 0xff00) { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } else { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } +} + +static void DRC_CALL_CONV dynrec_imul_byte(Bit8u op) DRC_FC; +static void DRC_CALL_CONV dynrec_imul_byte(Bit8u op) { + FillFlagsNoCFOF(); + reg_ax=((Bit8s)reg_al) * ((Bit8s)op); + if ((reg_ax & 0xff80)==0xff80 || (reg_ax & 0xff80)==0x0000) { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } else { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } +} + +static void DRC_CALL_CONV dynrec_mul_word(Bit16u op) DRC_FC; +static void DRC_CALL_CONV dynrec_mul_word(Bit16u op) { + FillFlagsNoCFOF(); + Bitu tempu=(Bitu)reg_ax*(Bitu)op; + reg_ax=(Bit16u)(tempu); + reg_dx=(Bit16u)(tempu >> 16); + SETFLAGBIT(ZF,reg_ax == 0); + if (reg_dx) { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } else { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } +} + +static void DRC_CALL_CONV dynrec_imul_word(Bit16u op) DRC_FC; +static void DRC_CALL_CONV dynrec_imul_word(Bit16u op) { + FillFlagsNoCFOF(); + Bits temps=((Bit16s)reg_ax)*((Bit16s)op); + reg_ax=(Bit16s)(temps); + reg_dx=(Bit16s)(temps >> 16); + if (((temps & 0xffff8000)==0xffff8000 || (temps & 0xffff8000)==0x0000)) { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } else { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } +} + +static void DRC_CALL_CONV dynrec_mul_dword(Bit32u op) DRC_FC; +static void DRC_CALL_CONV dynrec_mul_dword(Bit32u op) { + FillFlagsNoCFOF(); + Bit64u tempu=(Bit64u)reg_eax*(Bit64u)op; + reg_eax=(Bit32u)(tempu); + reg_edx=(Bit32u)(tempu >> 32); + SETFLAGBIT(ZF,reg_eax == 0); + if (reg_edx) { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } else { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } +} + +static void DRC_CALL_CONV dynrec_imul_dword(Bit32u op) DRC_FC; +static void DRC_CALL_CONV dynrec_imul_dword(Bit32u op) { + FillFlagsNoCFOF(); + Bit64s temps=((Bit64s)((Bit32s)reg_eax))*((Bit64s)((Bit32s)op)); + reg_eax=(Bit32u)(temps); + reg_edx=(Bit32u)(temps >> 32); + if ((reg_edx==0xffffffff) && (reg_eax & 0x80000000) ) { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } else if ( (reg_edx==0x00000000) && (reg_eax< 0x80000000) ) { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } else { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } +} + + +static bool DRC_CALL_CONV dynrec_div_byte(Bit8u op) DRC_FC; +static bool DRC_CALL_CONV dynrec_div_byte(Bit8u op) { + Bitu val=op; + if (val==0) return CPU_PrepareException(0,0); + Bitu quo=reg_ax / val; + 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 DRC_CALL_CONV dynrec_idiv_byte(Bit8u op) DRC_FC; +static bool DRC_CALL_CONV dynrec_idiv_byte(Bit8u op) { + Bits val=(Bit8s)op; + if (val==0) return CPU_PrepareException(0,0); + Bits quo=((Bit16s)reg_ax) / val; + 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; +} + +static bool DRC_CALL_CONV dynrec_div_word(Bit16u op) DRC_FC; +static bool DRC_CALL_CONV dynrec_div_word(Bit16u op) { + Bitu val=op; + if (val==0) return CPU_PrepareException(0,0); + Bitu num=((Bit32u)reg_dx<<16)|reg_ax; + Bitu quo=num/val; + 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; +} + +static bool DRC_CALL_CONV dynrec_idiv_word(Bit16u op) DRC_FC; +static bool DRC_CALL_CONV dynrec_idiv_word(Bit16u op) { + Bits val=(Bit16s)op; + if (val==0) return CPU_PrepareException(0,0); + Bits num=(Bit32s)((reg_dx<<16)|reg_ax); + Bits quo=num/val; + 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; +} + +static bool DRC_CALL_CONV dynrec_div_dword(Bit32u op) DRC_FC; +static bool DRC_CALL_CONV dynrec_div_dword(Bit32u op) { + Bitu val=op; + if (val==0) return CPU_PrepareException(0,0); + Bit64u num=(((Bit64u)reg_edx)<<32)|reg_eax; + Bit64u quo=num/val; + 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; +} + +static bool DRC_CALL_CONV dynrec_idiv_dword(Bit32u op) DRC_FC; +static bool DRC_CALL_CONV dynrec_idiv_dword(Bit32u op) { + Bits val=(Bit32s)op; + if (val==0) return CPU_PrepareException(0,0); + Bit64s num=(((Bit64u)reg_edx)<<32)|reg_eax; + Bit64s quo=num/val; + 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; +} + + +static Bit16u DRC_CALL_CONV dynrec_dimul_word(Bit16u op1,Bit16u op2) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_dimul_word(Bit16u op1,Bit16u op2) { + FillFlagsNoCFOF(); + Bits res=((Bit16s)op1) * ((Bit16s)op2); + if ((res>-32768) && (res<32767)) { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } else { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } + return (Bit16u)(res & 0xffff); +} + +static Bit32u DRC_CALL_CONV dynrec_dimul_dword(Bit32u op1,Bit32u op2) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_dimul_dword(Bit32u op1,Bit32u op2) { + FillFlagsNoCFOF(); + Bit64s res=((Bit64s)((Bit32s)op1))*((Bit64s)((Bit32s)op2)); + if ((res>-((Bit64s)(2147483647)+1)) && (res<(Bit64s)2147483647)) { + SETFLAGBIT(CF,false); + SETFLAGBIT(OF,false); + } else { + SETFLAGBIT(CF,true); + SETFLAGBIT(OF,true); + } + return (Bit32s)res; +} + + + +static Bit16u DRC_CALL_CONV dynrec_cbw(Bit8u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_cbw(Bit8u op) { + return (Bit8s)op; +} + +static Bit32u DRC_CALL_CONV dynrec_cwde(Bit16u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_cwde(Bit16u op) { + return (Bit16s)op; +} + +static Bit16u DRC_CALL_CONV dynrec_cwd(Bit16u op) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_cwd(Bit16u op) { + if (op & 0x8000) return 0xffff; + else return 0; +} + +static Bit32u DRC_CALL_CONV dynrec_cdq(Bit32u op) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_cdq(Bit32u op) { + if (op & 0x80000000) return 0xffffffff; + else return 0; +} + + +static void DRC_CALL_CONV dynrec_sahf(Bit16u op) DRC_FC; +static void DRC_CALL_CONV dynrec_sahf(Bit16u op) { + SETFLAGBIT(OF,get_OF()); + lflags.type=t_UNKNOWN; + CPU_SetFlags(op>>8,FMASK_NORMAL & 0xff); +} + + +static void DRC_CALL_CONV dynrec_cmc(void) DRC_FC; +static void DRC_CALL_CONV dynrec_cmc(void) { + FillFlags(); + SETFLAGBIT(CF,!(reg_flags & FLAG_CF)); +} +static void DRC_CALL_CONV dynrec_clc(void) DRC_FC; +static void DRC_CALL_CONV dynrec_clc(void) { + FillFlags(); + SETFLAGBIT(CF,false); +} +static void DRC_CALL_CONV dynrec_stc(void) DRC_FC; +static void DRC_CALL_CONV dynrec_stc(void) { + FillFlags(); + SETFLAGBIT(CF,true); +} +static void DRC_CALL_CONV dynrec_cld(void) DRC_FC; +static void DRC_CALL_CONV dynrec_cld(void) { + SETFLAGBIT(DF,false); + cpu.direction=1; +} +static void DRC_CALL_CONV dynrec_std(void) DRC_FC; +static void DRC_CALL_CONV dynrec_std(void) { + SETFLAGBIT(DF,true); + cpu.direction=-1; +} + + +static Bit16u DRC_CALL_CONV dynrec_movsb_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_movsb_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + for (;count>0;count--) { + mem_writeb(di_base+reg_di,mem_readb(si_base+reg_si)); + reg_si+=add_index; + reg_di+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_movsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_movsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + for (;count>0;count--) { + mem_writeb(di_base+reg_edi,mem_readb(si_base+reg_esi)); + reg_esi+=add_index; + reg_edi+=add_index; + } + return count_left; +} + +static Bit16u DRC_CALL_CONV dynrec_movsw_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_movsw_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=1; + for (;count>0;count--) { + mem_writew(di_base+reg_di,mem_readw(si_base+reg_si)); + reg_si+=add_index; + reg_di+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_movsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_movsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=1; + for (;count>0;count--) { + mem_writew(di_base+reg_edi,mem_readw(si_base+reg_esi)); + reg_esi+=add_index; + reg_edi+=add_index; + } + return count_left; +} + +static Bit16u DRC_CALL_CONV dynrec_movsd_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_movsd_word(Bit16u count,Bit16s add_index,PhysPt si_base,PhysPt di_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=2; + for (;count>0;count--) { + mem_writed(di_base+reg_di,mem_readd(si_base+reg_si)); + reg_si+=add_index; + reg_di+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_movsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_movsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base,PhysPt di_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=2; + for (;count>0;count--) { + mem_writed(di_base+reg_edi,mem_readd(si_base+reg_esi)); + reg_esi+=add_index; + reg_edi+=add_index; + } + return count_left; +} + + +static Bit16u DRC_CALL_CONV dynrec_lodsb_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_lodsb_word(Bit16u count,Bit16s add_index,PhysPt si_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + for (;count>0;count--) { + reg_al=mem_readb(si_base+reg_si); + reg_si+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_lodsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_lodsb_dword(Bit32u count,Bit32s add_index,PhysPt si_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + for (;count>0;count--) { + reg_al=mem_readb(si_base+reg_esi); + reg_esi+=add_index; + } + return count_left; +} + +static Bit16u DRC_CALL_CONV dynrec_lodsw_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_lodsw_word(Bit16u count,Bit16s add_index,PhysPt si_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=1; + for (;count>0;count--) { + reg_ax=mem_readw(si_base+reg_si); + reg_si+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_lodsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_lodsw_dword(Bit32u count,Bit32s add_index,PhysPt si_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=1; + for (;count>0;count--) { + reg_ax=mem_readw(si_base+reg_esi); + reg_esi+=add_index; + } + return count_left; +} + +static Bit16u DRC_CALL_CONV dynrec_lodsd_word(Bit16u count,Bit16s add_index,PhysPt si_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_lodsd_word(Bit16u count,Bit16s add_index,PhysPt si_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=2; + for (;count>0;count--) { + reg_eax=mem_readd(si_base+reg_si); + reg_si+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_lodsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_lodsd_dword(Bit32u count,Bit32s add_index,PhysPt si_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=2; + for (;count>0;count--) { + reg_eax=mem_readd(si_base+reg_esi); + reg_esi+=add_index; + } + return count_left; +} + + +static Bit16u DRC_CALL_CONV dynrec_stosb_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_stosb_word(Bit16u count,Bit16s add_index,PhysPt di_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + for (;count>0;count--) { + mem_writeb(di_base+reg_di,reg_al); + reg_di+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_stosb_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_stosb_dword(Bit32u count,Bit32s add_index,PhysPt di_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + for (;count>0;count--) { + mem_writeb(di_base+reg_edi,reg_al); + reg_edi+=add_index; + } + return count_left; +} + +static Bit16u DRC_CALL_CONV dynrec_stosw_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_stosw_word(Bit16u count,Bit16s add_index,PhysPt di_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=1; + for (;count>0;count--) { + mem_writew(di_base+reg_di,reg_ax); + reg_di+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_stosw_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_stosw_dword(Bit32u count,Bit32s add_index,PhysPt di_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=1; + for (;count>0;count--) { + mem_writew(di_base+reg_edi,reg_ax); + reg_edi+=add_index; + } + return count_left; +} + +static Bit16u DRC_CALL_CONV dynrec_stosd_word(Bit16u count,Bit16s add_index,PhysPt di_base) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_stosd_word(Bit16u count,Bit16s add_index,PhysPt di_base) { + Bit16u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=(Bit16u)(count-CPU_Cycles); + count=(Bit16u)CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=2; + for (;count>0;count--) { + mem_writed(di_base+reg_di,reg_eax); + reg_di+=add_index; + } + return count_left; +} + +static Bit32u DRC_CALL_CONV dynrec_stosd_dword(Bit32u count,Bit32s add_index,PhysPt di_base) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_stosd_dword(Bit32u count,Bit32s add_index,PhysPt di_base) { + Bit32u count_left; + if (count<(Bitu)CPU_Cycles) { + count_left=0; + } else { + count_left=count-CPU_Cycles; + count=CPU_Cycles; + CPU_Cycles=0; + } + add_index<<=2; + for (;count>0;count--) { + mem_writed(di_base+reg_edi,reg_eax); + reg_edi+=add_index; + } + return count_left; +} + + +static void DRC_CALL_CONV dynrec_push_word(Bit16u value) DRC_FC; +static void DRC_CALL_CONV dynrec_push_word(Bit16u value) { + Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-2)&cpu.stack.mask); + mem_writew(SegPhys(ss) + (new_esp & cpu.stack.mask),value); + reg_esp=new_esp; +} + +static void DRC_CALL_CONV dynrec_push_dword(Bit32u value) DRC_FC; +static void DRC_CALL_CONV dynrec_push_dword(Bit32u value) { + Bit32u new_esp=(reg_esp&cpu.stack.notmask)|((reg_esp-4)&cpu.stack.mask); + mem_writed(SegPhys(ss) + (new_esp & cpu.stack.mask) ,value); + reg_esp=new_esp; +} + +static Bit16u DRC_CALL_CONV dynrec_pop_word(void) DRC_FC; +static Bit16u DRC_CALL_CONV dynrec_pop_word(void) { + Bit16u val=mem_readw(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+2)&cpu.stack.mask); + return val; +} + +static Bit32u DRC_CALL_CONV dynrec_pop_dword(void) DRC_FC; +static Bit32u DRC_CALL_CONV dynrec_pop_dword(void) { + Bit32u val=mem_readd(SegPhys(ss) + (reg_esp & cpu.stack.mask)); + reg_esp=(reg_esp&cpu.stack.notmask)|((reg_esp+4)&cpu.stack.mask); + return val; +} diff --git a/src/cpu/core_dynrec/risc_armv4le-common.h b/src/cpu/core_dynrec/risc_armv4le-common.h index fea54bc..0bfb281 100644 --- a/src/cpu/core_dynrec/risc_armv4le-common.h +++ b/src/cpu/core_dynrec/risc_armv4le-common.h @@ -1,114 +1,114 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le-common.h,v 1.3 2009/05/16 21:52:47 c2woody Exp $ */ - - -/* ARMv4 (little endian) backend by M-HT (common data/functions) */ - - -// some configuring defines that specify the capabilities of this architecture -// or aspects of the recompiling - -// protect FC_ADDR over function calls if necessaray -// #define DRC_PROTECT_ADDR_REG - -// try to use non-flags generating functions if possible -#define DRC_FLAGS_INVALIDATION -// try to replace _simple functions by code -#define DRC_FLAGS_INVALIDATION_DCODE - -// type with the same size as a pointer -#define DRC_PTR_SIZE_IM Bit32u - -// calling convention modifier -#define DRC_CALL_CONV /* nothing */ -#define DRC_FC /* nothing */ - -// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR -#define DRC_USE_REGS_ADDR -// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR -#define DRC_USE_SEGS_ADDR - -// register mapping -typedef Bit8u HostReg; - -// "lo" registers -#define HOST_r0 0 -#define HOST_r1 1 -#define HOST_r2 2 -#define HOST_r3 3 -#define HOST_r4 4 -#define HOST_r5 5 -#define HOST_r6 6 -#define HOST_r7 7 -// "hi" registers -#define HOST_r8 8 -#define HOST_r9 9 -#define HOST_r10 10 -#define HOST_r11 11 -#define HOST_r12 12 -#define HOST_r13 13 -#define HOST_r14 14 -#define HOST_r15 15 - -// register aliases -// "lo" registers -#define HOST_a1 HOST_r0 -#define HOST_a2 HOST_r1 -#define HOST_a3 HOST_r2 -#define HOST_a4 HOST_r3 -#define HOST_v1 HOST_r4 -#define HOST_v2 HOST_r5 -#define HOST_v3 HOST_r6 -#define HOST_v4 HOST_r7 -// "hi" registers -#define HOST_v5 HOST_r8 -#define HOST_v6 HOST_r9 -#define HOST_v7 HOST_r10 -#define HOST_v8 HOST_r11 -#define HOST_ip HOST_r12 -#define HOST_sp HOST_r13 -#define HOST_lr HOST_r14 -#define HOST_pc HOST_r15 - - -static void cache_block_closing(Bit8u* block_start,Bitu block_size) { -#if (__ARM_EABI__) - //flush cache - eabi - register unsigned long _beg __asm ("a1") = (unsigned long)(block_start); // block start - register unsigned long _end __asm ("a2") = (unsigned long)(block_start+block_size); // block end - register unsigned long _flg __asm ("a3") = 0; - register unsigned long _par __asm ("r7") = 0xf0002; // sys_cacheflush - __asm __volatile ("swi 0x0" - : // no outputs - : "r" (_beg), "r" (_end), "r" (_flg), "r" (_par) - ); -#else -// GP2X BEGIN - //flush cache - old abi - register unsigned long _beg __asm ("a1") = (unsigned long)(block_start); // block start - register unsigned long _end __asm ("a2") = (unsigned long)(block_start+block_size); // block end - register unsigned long _flg __asm ("a3") = 0; - __asm __volatile ("swi 0x9f0002 @ sys_cacheflush" - : // no outputs - : "r" (_beg), "r" (_end), "r" (_flg) - ); -// GP2X END -#endif -} +/* + * Copyright (C) 2002-2010 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: risc_armv4le-common.h,v 1.3 2009-05-16 21:52:47 c2woody Exp $ */ + + +/* ARMv4 (little endian) backend by M-HT (common data/functions) */ + + +// some configuring defines that specify the capabilities of this architecture +// or aspects of the recompiling + +// protect FC_ADDR over function calls if necessaray +// #define DRC_PROTECT_ADDR_REG + +// try to use non-flags generating functions if possible +#define DRC_FLAGS_INVALIDATION +// try to replace _simple functions by code +#define DRC_FLAGS_INVALIDATION_DCODE + +// type with the same size as a pointer +#define DRC_PTR_SIZE_IM Bit32u + +// calling convention modifier +#define DRC_CALL_CONV /* nothing */ +#define DRC_FC /* nothing */ + +// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR +#define DRC_USE_REGS_ADDR +// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR +#define DRC_USE_SEGS_ADDR + +// register mapping +typedef Bit8u HostReg; + +// "lo" registers +#define HOST_r0 0 +#define HOST_r1 1 +#define HOST_r2 2 +#define HOST_r3 3 +#define HOST_r4 4 +#define HOST_r5 5 +#define HOST_r6 6 +#define HOST_r7 7 +// "hi" registers +#define HOST_r8 8 +#define HOST_r9 9 +#define HOST_r10 10 +#define HOST_r11 11 +#define HOST_r12 12 +#define HOST_r13 13 +#define HOST_r14 14 +#define HOST_r15 15 + +// register aliases +// "lo" registers +#define HOST_a1 HOST_r0 +#define HOST_a2 HOST_r1 +#define HOST_a3 HOST_r2 +#define HOST_a4 HOST_r3 +#define HOST_v1 HOST_r4 +#define HOST_v2 HOST_r5 +#define HOST_v3 HOST_r6 +#define HOST_v4 HOST_r7 +// "hi" registers +#define HOST_v5 HOST_r8 +#define HOST_v6 HOST_r9 +#define HOST_v7 HOST_r10 +#define HOST_v8 HOST_r11 +#define HOST_ip HOST_r12 +#define HOST_sp HOST_r13 +#define HOST_lr HOST_r14 +#define HOST_pc HOST_r15 + + +static void cache_block_closing(Bit8u* block_start,Bitu block_size) { +#if (__ARM_EABI__) + //flush cache - eabi + register unsigned long _beg __asm ("a1") = (unsigned long)(block_start); // block start + register unsigned long _end __asm ("a2") = (unsigned long)(block_start+block_size); // block end + register unsigned long _flg __asm ("a3") = 0; + register unsigned long _par __asm ("r7") = 0xf0002; // sys_cacheflush + __asm __volatile ("swi 0x0" + : // no outputs + : "r" (_beg), "r" (_end), "r" (_flg), "r" (_par) + ); +#else +// GP2X BEGIN + //flush cache - old abi + register unsigned long _beg __asm ("a1") = (unsigned long)(block_start); // block start + register unsigned long _end __asm ("a2") = (unsigned long)(block_start+block_size); // block end + register unsigned long _flg __asm ("a3") = 0; + __asm __volatile ("swi 0x9f0002 @ sys_cacheflush" + : // no outputs + : "r" (_beg), "r" (_end), "r" (_flg) + ); +// GP2X END +#endif +} diff --git a/src/cpu/core_dynrec/risc_armv4le-o3.h b/src/cpu/core_dynrec/risc_armv4le-o3.h index 7501262..02bc9f5 100644 --- a/src/cpu/core_dynrec/risc_armv4le-o3.h +++ b/src/cpu/core_dynrec/risc_armv4le-o3.h @@ -1,1083 +1,1083 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le-o3.h,v 1.6 2009/06/27 12:51:10 c2woody Exp $ */ - - -/* ARMv4 (little endian) backend by M-HT (size-tweaked arm version) */ - - -// temporary registers -#define temp1 HOST_ip -#define temp2 HOST_v3 -#define temp3 HOST_v4 - -// register that holds function return values -#define FC_RETOP HOST_a1 - -// register used for address calculations, -#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG - -// register that holds the first parameter -#define FC_OP1 HOST_a1 - -// register that holds the second parameter -#define FC_OP2 HOST_a2 - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_v2 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_a1 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_a2 - -// temporary register for LEA -#define TEMP_REG_DRC HOST_v2 - -#ifdef DRC_USE_REGS_ADDR -// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code -#define FC_REGS_ADDR HOST_v7 -#endif - -#ifdef DRC_USE_SEGS_ADDR -// used to hold the address of "Segs" - preferably filled in function gen_run_code -#define FC_SEGS_ADDR HOST_v8 -#endif - - -// helper macro -#define ROTATE_SCALE(x) ( (x)?(32 - x):(0) ) - - -// instruction encodings - -// move -// mov dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define MOV_IMM(dst, imm, rimm) (0xe3a00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) -// mov dst, src, lsl #imm -#define MOV_REG_LSL_IMM(dst, src, imm) (0xe1a00000 + ((dst) << 12) + (src) + ((imm) << 7) ) -// movs dst, src, lsl #imm -#define MOVS_REG_LSL_IMM(dst, src, imm) (0xe1b00000 + ((dst) << 12) + (src) + ((imm) << 7) ) -// mov dst, src, lsr #imm -#define MOV_REG_LSR_IMM(dst, src, imm) (0xe1a00020 + ((dst) << 12) + (src) + ((imm) << 7) ) -// mov dst, src, asr #imm -#define MOV_REG_ASR_IMM(dst, src, imm) (0xe1a00040 + ((dst) << 12) + (src) + ((imm) << 7) ) -// mov dst, src, lsl rreg -#define MOV_REG_LSL_REG(dst, src, rreg) (0xe1a00010 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mov dst, src, lsr rreg -#define MOV_REG_LSR_REG(dst, src, rreg) (0xe1a00030 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mov dst, src, asr rreg -#define MOV_REG_ASR_REG(dst, src, rreg) (0xe1a00050 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mov dst, src, ror rreg -#define MOV_REG_ROR_REG(dst, src, rreg) (0xe1a00070 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mvn dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define MVN_IMM(dst, imm, rimm) (0xe3e00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) - -// arithmetic -// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// add dst, src1, src2, lsl #imm -#define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0xe0800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// sub dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define SUB_IMM(dst, src, imm, rimm) (0xe2400000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// sub dst, src1, src2, lsl #imm -#define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0xe0400000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// rsb dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define RSB_IMM(dst, src, imm, rimm) (0xe2600000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// cmp src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define CMP_IMM(src, imm, rimm) (0xe3500000 + ((src) << 16) + (imm) + ((rimm) << 7) ) -// nop -#define NOP MOV_REG_LSL_IMM(HOST_r0, HOST_r0, 0) - -// logical -// tst src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define TST_IMM(src, imm, rimm) (0xe3100000 + ((src) << 16) + (imm) + ((rimm) << 7) ) -// and dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define AND_IMM(dst, src, imm, rimm) (0xe2000000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// and dst, src1, src2, lsl #imm -#define AND_REG_LSL_IMM(dst, src1, src2, imm) (0xe0000000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// orr dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define ORR_IMM(dst, src, imm, rimm) (0xe3800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// orr dst, src1, src2, lsl #imm -#define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0xe1800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// orr dst, src1, src2, lsr #imm -#define ORR_REG_LSR_IMM(dst, src1, src2, imm) (0xe1800020 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// eor dst, src1, src2, lsl #imm -#define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0xe0200000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// bic dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define BIC_IMM(dst, src, imm, rimm) (0xe3c00000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) - -// load -// ldr reg, [addr, #imm] @ 0 <= imm < 4096 -#define LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) ) -// ldrh reg, [addr, #imm] @ 0 <= imm < 256 -#define LDRH_IMM(reg, addr, imm) (0xe1d000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) -// ldrb reg, [addr, #imm] @ 0 <= imm < 4096 -#define LDRB_IMM(reg, addr, imm) (0xe5d00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) - -// store -// str reg, [addr, #imm] @ 0 <= imm < 4096 -#define STR_IMM(reg, addr, imm) (0xe5800000 + ((reg) << 12) + ((addr) << 16) + (imm) ) -// strh reg, [addr, #imm] @ 0 <= imm < 256 -#define STRH_IMM(reg, addr, imm) (0xe1c000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) -// strb reg, [addr, #imm] @ 0 <= imm < 4096 -#define STRB_IMM(reg, addr, imm) (0xe5c00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) - -// branch -// beq pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define BEQ_FWD(imm) (0x0a000000 + ((imm) >> 2) ) -// bne pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define BNE_FWD(imm) (0x1a000000 + ((imm) >> 2) ) -// bgt pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define BGT_FWD(imm) (0xca000000 + ((imm) >> 2) ) -// b pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define B_FWD(imm) (0xea000000 + ((imm) >> 2) ) -// bx reg -#define BX(reg) (0xe12fff10 + (reg) ) - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - if(reg_src == reg_dst) return; - cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) ); // mov reg_dst, reg_src -} - -// helper function -static Bits get_imm_gen_len(Bit32u imm) { - Bits ret; - if (imm == 0) { - return 1; - } else { - ret = 0; - while (imm) { - while ((imm & 3) == 0) { - imm>>=2; - } - ret++; - imm>>=8; - } - return ret; - } -} - -// helper function -static Bits get_method_imm_gen_len(Bit32u imm, Bits preffer00, Bits *num) { - Bits num00, num15, numadd, numsub, numret, ret; - num00 = get_imm_gen_len(imm); - num15 = get_imm_gen_len(~imm); - numadd = get_imm_gen_len(imm - ((Bit32u)cache.pos+8)); - numsub = get_imm_gen_len(((Bit32u)cache.pos+8) - imm); - if (numsub < numadd && numsub < num00 && numsub < num15) { - ret = 0; - numret = numsub; - } else if (numadd < num00 && numadd < num15) { - ret = 1; - numret = numadd; - } else if (num00 < num15 || (num00 == num15 && preffer00)) { - ret = 2; - numret = num00; - } else { - ret = 3; - numret = num15; - } - if (num != NULL) *num = numret; - return ret; -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - Bits first, method, scale; - Bit32u imm2, dist; - if (imm == 0) { - cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0 - } else if (imm == 0xffffffff) { - cache_addd( MVN_IMM(dest_reg, 0, 0) ); // mvn dest_reg, #0 - } else { - method = get_method_imm_gen_len(imm, 1, NULL); - - scale = 0; - first = 1; - if (method == 0) { - dist = ((Bit32u)cache.pos+8) - imm; - while (dist) { - while ((dist & 3) == 0) { - dist>>=2; - scale+=2; - } - if (first) { - cache_addd( SUB_IMM(dest_reg, HOST_pc, dist & 0xff, ROTATE_SCALE(scale)) ); // sub dest_reg, pc, #((dist & 0xff) << scale) - first = 0; - } else { - cache_addd( SUB_IMM(dest_reg, dest_reg, dist & 0xff, ROTATE_SCALE(scale)) ); // sub dest_reg, dest_reg, #((dist & 0xff) << scale) - } - dist>>=8; - scale+=8; - } - } else if (method == 1) { - dist = imm - ((Bit32u)cache.pos+8); - if (dist == 0) { - cache_addd( MOV_REG_LSL_IMM(dest_reg, HOST_pc, 0) ); // mov dest_reg, pc - } else { - while (dist) { - while ((dist & 3) == 0) { - dist>>=2; - scale+=2; - } - if (first) { - cache_addd( ADD_IMM(dest_reg, HOST_pc, dist & 0xff, ROTATE_SCALE(scale)) ); // add dest_reg, pc, #((dist & 0xff) << scale) - first = 0; - } else { - cache_addd( ADD_IMM(dest_reg, dest_reg, dist & 0xff, ROTATE_SCALE(scale)) ); // add dest_reg, dest_reg, #((dist & 0xff) << scale) - } - dist>>=8; - scale+=8; - } - } - } else if (method == 2) { - while (imm) { - while ((imm & 3) == 0) { - imm>>=2; - scale+=2; - } - if (first) { - cache_addd( MOV_IMM(dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm & 0xff) << scale) - first = 0; - } else { - cache_addd( ORR_IMM(dest_reg, dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm & 0xff) << scale) - } - imm>>=8; - scale+=8; - } - } else { - imm2 = ~imm; - while (imm2) { - while ((imm2 & 3) == 0) { - imm2>>=2; - scale+=2; - } - if (first) { - cache_addd( MVN_IMM(dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // mvn dest_reg, #((imm2 & 0xff) << scale) - first = 0; - } else { - cache_addd( BIC_IMM(dest_reg, dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic dest_reg, dest_reg, #((imm2 & 0xff) << scale) - } - imm2>>=8; - scale+=8; - } - } - } -} - -// helper function for gen_mov_word_to_reg -static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)data & 3) { - if ( ((Bit32u)data & 3) == 2 ) { - cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - cache_addd( LDRH_IMM(temp2, data_reg, 2) ); // ldrh temp2, [data_reg, #2] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 16) ); // orr dest_reg, dest_reg, temp2, lsl #16 - } else { - cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addd( LDRH_IMM(temp2, data_reg, 1) ); // ldrh temp2, [data_reg, #1] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 - cache_addd( LDRB_IMM(temp2, data_reg, 3) ); // ldrb temp2, [data_reg, #3] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 24) ); // orr dest_reg, dest_reg, temp2, lsl #24 - } - } else { - cache_addd( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] - } - } else { - if ((Bit32u)data & 1) { - cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addd( LDRB_IMM(temp2, data_reg, 1) ); // ldrb temp2, [data_reg, #1] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 - } else { - cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - } - } -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); - gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - Bits first, scale; - Bit32u imm2; - if (imm == 0) { - cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0 - } else { - scale = 0; - first = 1; - imm2 = (Bit32u)imm; - while (imm2) { - while ((imm2 & 3) == 0) { - imm2>>=2; - scale+=2; - } - if (first) { - cache_addd( MOV_IMM(dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm2 & 0xff) << scale) - first = 0; - } else { - cache_addd( ORR_IMM(dest_reg, dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm2 & 0xff) << scale) - } - imm2>>=8; - scale+=8; - } - } -} - -// helper function for gen_mov_word_from_reg -static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)dest & 3) { - if ( ((Bit32u)dest & 3) == 2 ) { - cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 16) ); // mov temp2, src_reg, lsr #16 - cache_addd( STRH_IMM(temp2, data_reg, 2) ); // strh temp2, [data_reg, #2] - } else { - cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 - cache_addd( STRH_IMM(temp2, data_reg, 1) ); // strh temp2, [data_reg, #1] - cache_addd( MOV_REG_LSR_IMM(temp2, temp2, 16) ); // mov temp2, temp2, lsr #16 - cache_addd( STRB_IMM(temp2, data_reg, 3) ); // strb temp2, [data_reg, #3] - } - } else { - cache_addd( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] - } - } else { - if ((Bit32u)dest & 1) { - cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 - cache_addd( STRB_IMM(temp2, data_reg, 1) ); // strb temp2, [data_reg, #1] - } else { - cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - } - } -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); - cache_addd( LDRB_IMM(dest_reg, temp1, 0) ); // ldrb dest_reg, [temp1] -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - gen_mov_byte_to_reg_low(dest_reg, data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_addd( MOV_IMM(dest_reg, imm, 0) ); // mov dest_reg, #(imm) -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(dest_reg, imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - cache_addd( STRB_IMM(src_reg, temp1, 0) ); // strb src_reg, [temp1] -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - if (sign) { - cache_addd( MOV_REG_LSL_IMM(reg, reg, 24) ); // mov reg, reg, lsl #24 - cache_addd( MOV_REG_ASR_IMM(reg, reg, 24) ); // mov reg, reg, asr #24 - } else { - cache_addd( AND_IMM(reg, reg, 0xff, 0) ); // and reg, reg, #0xff - } -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - if (sign) { - cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 - cache_addd( MOV_REG_ASR_IMM(reg, reg, 16) ); // mov reg, reg, asr #16 - } else { - cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 - cache_addd( MOV_REG_LSR_IMM(reg, reg, 16) ); // mov reg, reg, lsr #16 - } -} - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - gen_mov_word_to_reg(temp3, op, 1); - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3 -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - Bits method1, method2, num1, num2, scale, sub; - if(!imm) return; - if (imm == 1) { - cache_addd( ADD_IMM(reg, reg, 1, 0) ); // add reg, reg, #1 - } else if (imm == 0xffffffff) { - cache_addd( SUB_IMM(reg, reg, 1, 0) ); // sub reg, reg, #1 - } else { - method1 = get_method_imm_gen_len(imm, 1, &num1); - method2 = get_method_imm_gen_len(-((Bit32s)imm), 1, &num2); - if (num2 < num1) { - method1 = method2; - imm = (Bit32u)(-((Bit32s)imm)); - sub = 1; - } else sub = 0; - - if (method1 != 2) { - gen_mov_dword_to_reg_imm(temp3, imm); - if (sub) { - cache_addd( SUB_REG_LSL_IMM(reg, reg, temp3, 0) ); // sub reg, reg, temp3 - } else { - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3 - } - } else { - scale = 0; - while (imm) { - while ((imm & 3) == 0) { - imm>>=2; - scale+=2; - } - if (sub) { - cache_addd( SUB_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // sub reg, reg, #((imm & 0xff) << scale) - } else { - cache_addd( ADD_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // add reg, reg, #((imm & 0xff) << scale) - } - imm>>=8; - scale+=8; - } - } - } -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - Bits method, scale; - Bit32u imm2; - imm2 = ~imm; - if(!imm2) return; - if (!imm) { - cache_addd( MOV_IMM(reg, 0, 0) ); // mov reg, #0 - } else { - method = get_method_imm_gen_len(imm, 0, NULL); - if (method != 3) { - gen_mov_dword_to_reg_imm(temp3, imm); - cache_addd( AND_REG_LSL_IMM(reg, reg, temp3, 0) ); // and reg, reg, temp3 - } else { - scale = 0; - while (imm2) { - while ((imm2 & 3) == 0) { - imm2>>=2; - scale+=2; - } - cache_addd( BIC_IMM(reg, reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic reg, reg, #((imm2 & 0xff) << scale) - imm2>>=8; - scale+=8; - } - } - } -} - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - gen_mov_dword_to_reg_imm(temp3, imm); - gen_mov_word_from_reg(temp3, dest, 1); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - -// add an 8bit constant value to a dword memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); - if (imm >= 0) { - cache_addd( ADD_IMM(temp3, temp3, (Bit32s)imm, 0) ); // add temp3, temp3, #(imm) - } else { - cache_addd( SUB_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // sub temp3, temp3, #(-imm) - } - gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); - // maybe use function gen_add_imm - if (dword) { - gen_mov_dword_to_reg_imm(temp2, imm); - } else { - gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); - } - cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2 - gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); -} - -// subtract an 8bit constant value from a dword memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); - if (imm >= 0) { - cache_addd( SUB_IMM(temp3, temp3, (Bit32s)imm, 0) ); // sub temp3, temp3, #(imm) - } else { - cache_addd( ADD_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // add temp3, temp3, #(-imm) - } - gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); - // maybe use function gen_add_imm/gen_sub_imm - if (dword) { - gen_mov_dword_to_reg_imm(temp2, imm); - } else { - gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); - } - cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // sub temp3, temp3, temp2 - gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); -} - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) ); // add dest_reg, dest_reg, scale_reg, lsl #(scale) - gen_add_imm(dest_reg, imm); -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - if (scale) { - cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) ); // mov dest_reg, dest_reg, lsl #(scale) - } - gen_add_imm(dest_reg, imm); -} - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - cache_addd( LDR_IMM(temp1, HOST_pc, 4) ); // ldr temp1, [pc, #4] - cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 - cache_addd( BX(temp1) ); // bx temp1 - cache_addd((Bit32u)func); // .int func -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - Bit32u proc_addr = (Bit32u)cache.pos; - gen_call_function_raw(func); - return proc_addr; -} - -#if (1) -// max of 4 parameters in a1-a4 - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - gen_mov_dword_to_reg_imm(param, imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - gen_mov_dword_to_reg_imm(param, addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - gen_mov_regs(param, reg); -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - gen_mov_word_to_reg(param, (void *)mem, 1); -} -#else - other arm abis -#endif - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - Bits num1, num2, scale, sub; - Bitu imm2; - gen_mov_word_to_reg(temp3, ptr, 1); - - if (imm) { - num1 = get_imm_gen_len(imm); - num2 = get_imm_gen_len(-imm); - - if (num2 < num1) { - imm = -imm; - sub = 1; - } else sub = 0; - - scale = 0; - imm2 = (Bitu)imm; - while (imm2) { - while ((imm2 & 3) == 0) { - imm2>>=2; - scale+=2; - } - if (sub) { - cache_addd( SUB_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // sub temp3, temp3, #((imm2 & 0xff) << scale) - } else { - cache_addd( ADD_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // add temp3, temp3, #((imm2 & 0xff) << scale) - } - imm2>>=8; - scale+=8; - } - } - -#if (1) -// (*ptr) should be word aligned - if ((imm & 0x03) == 0) { - cache_addd( LDR_IMM(temp1, temp3, 0) ); // ldr temp1, [temp3] - } else -#endif - { - cache_addd( LDRB_IMM(temp1, temp3, 0) ); // ldrb temp1, [temp3] - cache_addd( LDRB_IMM(temp2, temp3, 1) ); // ldrb temp2, [temp3, #1] - cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 8) ); // orr temp1, temp1, temp2, lsl #8 - cache_addd( LDRB_IMM(temp2, temp3, 2) ); // ldrb temp2, [temp3, #2] - cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 16) ); // orr temp1, temp1, temp2, lsl #16 - cache_addd( LDRB_IMM(temp2, temp3, 3) ); // ldrb temp2, [temp3, #3] - cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 24) ); // orr temp1, temp1, temp2, lsl #24 - } - - cache_addd( BX(temp1) ); // bx temp1 -} - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { - if (dword) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - } else { - cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 - } - cache_addd( BEQ_FWD(0) ); // beq j - return ((Bit32u)cache.pos-4); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - if (dword) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - } else { - cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 - } - cache_addd( BNE_FWD(0) ); // bne j - return ((Bit32u)cache.pos-4); -} - -// calculate relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-(data+8); - if (len<0) len=-len; - if (len>0x02000000) LOG_MSG("Big jump %d",len); -#endif - *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff ); -} - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - if (isdword) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - } else { - cache_addd( TST_IMM(reg, 0xff, 0) ); // tst reg, #0xff - } - cache_addd( BEQ_FWD(8) ); // beq nobranch (pc +8) - cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] - cache_addd( BX(temp1) ); // bx temp1 - cache_addd(0); // fill j - // nobranch: - return ((Bit32u)cache.pos-4); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u gen_create_branch_long_leqzero(HostReg reg) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - cache_addd( BGT_FWD(8) ); // bgt nobranch (pc+8) - cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] - cache_addd( BX(temp1) ); // bx temp1 - cache_addd(0); // fill j - // nobranch: - return ((Bit32u)cache.pos-4); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - // this is an absolute branch - *(Bit32u*)data=(Bit32u)cache.pos; -} - -static void gen_run_code(void) { - cache_addd(0xe92d4000); // stmfd sp!, {lr} - cache_addd(0xe92d0cf0); // stmfd sp!, {v1-v4,v7,v8} - - // adr: 8 - cache_addd( LDR_IMM(FC_SEGS_ADDR, HOST_pc, 64 - (8 + 8)) ); // ldr FC_SEGS_ADDR, [pc, #(&Segs)] - // adr: 12 - cache_addd( LDR_IMM(FC_REGS_ADDR, HOST_pc, 68 - (12 + 8)) ); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)] - - cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 - cache_addd(0xe92d4000); // stmfd sp!, {lr} - cache_addd( BX(HOST_r0) ); // bx r0 - - cache_addd(0xe8bd0cf0); // ldmfd sp!, {v1-v4,v7,v8} - - cache_addd(0xe8bd4000); // ldmfd sp!, {lr} - cache_addd( BX(HOST_lr) ); // bx lr - - // fill up to 64 bytes - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - - // adr: 64 - cache_addd((Bit32u)&Segs); // address of "Segs" - // adr: 68 - cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" -} - -// return from a function -static void gen_return_function(void) { - cache_addd(0xe8bd4000); // ldmfd sp!, {lr} - cache_addd( BX(HOST_lr) ); // bx lr -} - -#ifdef DRC_FLAGS_INVALIDATION - -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { -#ifdef DRC_FLAGS_INVALIDATION_DCODE - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit32u*)pos=ADD_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // add FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit32u*)pos=ORR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // orr FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit32u*)pos=AND_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // and FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit32u*)pos=SUB_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // sub FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit32u*)pos=EOR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // eor FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit32u*)pos=B_FWD(8); // b (pc+2*4) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit32u*)pos=ADD_IMM(FC_RETOP, HOST_a1, 1, 0); // add FC_RETOP, a1, #1 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit32u*)pos=SUB_IMM(FC_RETOP, HOST_a1, 1, 0); // sub FC_RETOP, a1, #1 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit32u*)pos=MOV_REG_LSL_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsl a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHRb: - *(Bit32u*)pos=AND_IMM(FC_RETOP, HOST_a1, 0xff, 0); // and FC_RETOP, a1, #0xff - *(Bit32u*)(pos+4)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHRw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=MOV_REG_LSR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHRd: - *(Bit32u*)pos=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SARb: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 - *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 24); // mov FC_RETOP, FC_RETOP, asr #24 - *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SARw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, asr #16 - *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SARd: - *(Bit32u*)pos=MOV_REG_ASR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, asr a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_RORb: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 - *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 8); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8 - *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 - break; - case t_RORw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_RORd: - *(Bit32u*)pos=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_ROLw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 - *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 - break; - case t_ROLd: - *(Bit32u*)pos=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 - *(Bit32u*)(pos+4)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit32u*)pos=RSB_IMM(FC_RETOP, HOST_a1, 0, 0); // rsb FC_RETOP, a1, #0 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - default: - *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func - break; - - } -#else - *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func -#endif -} -#endif - -static void cache_block_before_close(void) { } - -#ifdef DRC_USE_SEGS_ADDR - -// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldrh dest_reg, [FC_SEGS_ADDR, #index] -} - -// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldr dest_reg, [FC_SEGS_ADDR, #index] -} - -// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { - cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) ); // ldr temp1, [FC_SEGS_ADDR, #index] - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) ); // add reg, reg, temp1 -} - -#endif - -#ifdef DRC_USE_REGS_ADDR - -// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] -} - -// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { - if (dword) { - cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] - } else { - cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] - } -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { - cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { - cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] -} - - -// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { - cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) ); // ldr temp2, [FC_REGS_ADDR, #index] - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2 -} - - -// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) -static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { - cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] -} - -// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { - cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { - if (dword) { - cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] - } else { - cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] - } -} - -// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR -static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { - cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) ); // strb src_reg, [FC_REGS_ADDR, #index] -} - -#endif +/* + * Copyright (C) 2002-2010 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: risc_armv4le-o3.h,v 1.6 2009-06-27 12:51:10 c2woody Exp $ */ + + +/* ARMv4 (little endian) backend by M-HT (size-tweaked arm version) */ + + +// temporary registers +#define temp1 HOST_ip +#define temp2 HOST_v3 +#define temp3 HOST_v4 + +// register that holds function return values +#define FC_RETOP HOST_a1 + +// register used for address calculations, +#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG + +// register that holds the first parameter +#define FC_OP1 HOST_a1 + +// register that holds the second parameter +#define FC_OP2 HOST_a2 + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_v2 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_a1 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_a2 + +// temporary register for LEA +#define TEMP_REG_DRC HOST_v2 + +#ifdef DRC_USE_REGS_ADDR +// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code +#define FC_REGS_ADDR HOST_v7 +#endif + +#ifdef DRC_USE_SEGS_ADDR +// used to hold the address of "Segs" - preferably filled in function gen_run_code +#define FC_SEGS_ADDR HOST_v8 +#endif + + +// helper macro +#define ROTATE_SCALE(x) ( (x)?(32 - x):(0) ) + + +// instruction encodings + +// move +// mov dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define MOV_IMM(dst, imm, rimm) (0xe3a00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) +// mov dst, src, lsl #imm +#define MOV_REG_LSL_IMM(dst, src, imm) (0xe1a00000 + ((dst) << 12) + (src) + ((imm) << 7) ) +// movs dst, src, lsl #imm +#define MOVS_REG_LSL_IMM(dst, src, imm) (0xe1b00000 + ((dst) << 12) + (src) + ((imm) << 7) ) +// mov dst, src, lsr #imm +#define MOV_REG_LSR_IMM(dst, src, imm) (0xe1a00020 + ((dst) << 12) + (src) + ((imm) << 7) ) +// mov dst, src, asr #imm +#define MOV_REG_ASR_IMM(dst, src, imm) (0xe1a00040 + ((dst) << 12) + (src) + ((imm) << 7) ) +// mov dst, src, lsl rreg +#define MOV_REG_LSL_REG(dst, src, rreg) (0xe1a00010 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mov dst, src, lsr rreg +#define MOV_REG_LSR_REG(dst, src, rreg) (0xe1a00030 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mov dst, src, asr rreg +#define MOV_REG_ASR_REG(dst, src, rreg) (0xe1a00050 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mov dst, src, ror rreg +#define MOV_REG_ROR_REG(dst, src, rreg) (0xe1a00070 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mvn dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define MVN_IMM(dst, imm, rimm) (0xe3e00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) + +// arithmetic +// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// add dst, src1, src2, lsl #imm +#define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0xe0800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// sub dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define SUB_IMM(dst, src, imm, rimm) (0xe2400000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// sub dst, src1, src2, lsl #imm +#define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0xe0400000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// rsb dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define RSB_IMM(dst, src, imm, rimm) (0xe2600000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// cmp src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define CMP_IMM(src, imm, rimm) (0xe3500000 + ((src) << 16) + (imm) + ((rimm) << 7) ) +// nop +#define NOP MOV_REG_LSL_IMM(HOST_r0, HOST_r0, 0) + +// logical +// tst src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define TST_IMM(src, imm, rimm) (0xe3100000 + ((src) << 16) + (imm) + ((rimm) << 7) ) +// and dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define AND_IMM(dst, src, imm, rimm) (0xe2000000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// and dst, src1, src2, lsl #imm +#define AND_REG_LSL_IMM(dst, src1, src2, imm) (0xe0000000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// orr dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define ORR_IMM(dst, src, imm, rimm) (0xe3800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// orr dst, src1, src2, lsl #imm +#define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0xe1800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// orr dst, src1, src2, lsr #imm +#define ORR_REG_LSR_IMM(dst, src1, src2, imm) (0xe1800020 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// eor dst, src1, src2, lsl #imm +#define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0xe0200000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// bic dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define BIC_IMM(dst, src, imm, rimm) (0xe3c00000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) + +// load +// ldr reg, [addr, #imm] @ 0 <= imm < 4096 +#define LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) ) +// ldrh reg, [addr, #imm] @ 0 <= imm < 256 +#define LDRH_IMM(reg, addr, imm) (0xe1d000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) +// ldrb reg, [addr, #imm] @ 0 <= imm < 4096 +#define LDRB_IMM(reg, addr, imm) (0xe5d00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) + +// store +// str reg, [addr, #imm] @ 0 <= imm < 4096 +#define STR_IMM(reg, addr, imm) (0xe5800000 + ((reg) << 12) + ((addr) << 16) + (imm) ) +// strh reg, [addr, #imm] @ 0 <= imm < 256 +#define STRH_IMM(reg, addr, imm) (0xe1c000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) +// strb reg, [addr, #imm] @ 0 <= imm < 4096 +#define STRB_IMM(reg, addr, imm) (0xe5c00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) + +// branch +// beq pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define BEQ_FWD(imm) (0x0a000000 + ((imm) >> 2) ) +// bne pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define BNE_FWD(imm) (0x1a000000 + ((imm) >> 2) ) +// bgt pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define BGT_FWD(imm) (0xca000000 + ((imm) >> 2) ) +// b pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define B_FWD(imm) (0xea000000 + ((imm) >> 2) ) +// bx reg +#define BX(reg) (0xe12fff10 + (reg) ) + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + if(reg_src == reg_dst) return; + cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) ); // mov reg_dst, reg_src +} + +// helper function +static Bits get_imm_gen_len(Bit32u imm) { + Bits ret; + if (imm == 0) { + return 1; + } else { + ret = 0; + while (imm) { + while ((imm & 3) == 0) { + imm>>=2; + } + ret++; + imm>>=8; + } + return ret; + } +} + +// helper function +static Bits get_method_imm_gen_len(Bit32u imm, Bits preffer00, Bits *num) { + Bits num00, num15, numadd, numsub, numret, ret; + num00 = get_imm_gen_len(imm); + num15 = get_imm_gen_len(~imm); + numadd = get_imm_gen_len(imm - ((Bit32u)cache.pos+8)); + numsub = get_imm_gen_len(((Bit32u)cache.pos+8) - imm); + if (numsub < numadd && numsub < num00 && numsub < num15) { + ret = 0; + numret = numsub; + } else if (numadd < num00 && numadd < num15) { + ret = 1; + numret = numadd; + } else if (num00 < num15 || (num00 == num15 && preffer00)) { + ret = 2; + numret = num00; + } else { + ret = 3; + numret = num15; + } + if (num != NULL) *num = numret; + return ret; +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + Bits first, method, scale; + Bit32u imm2, dist; + if (imm == 0) { + cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0 + } else if (imm == 0xffffffff) { + cache_addd( MVN_IMM(dest_reg, 0, 0) ); // mvn dest_reg, #0 + } else { + method = get_method_imm_gen_len(imm, 1, NULL); + + scale = 0; + first = 1; + if (method == 0) { + dist = ((Bit32u)cache.pos+8) - imm; + while (dist) { + while ((dist & 3) == 0) { + dist>>=2; + scale+=2; + } + if (first) { + cache_addd( SUB_IMM(dest_reg, HOST_pc, dist & 0xff, ROTATE_SCALE(scale)) ); // sub dest_reg, pc, #((dist & 0xff) << scale) + first = 0; + } else { + cache_addd( SUB_IMM(dest_reg, dest_reg, dist & 0xff, ROTATE_SCALE(scale)) ); // sub dest_reg, dest_reg, #((dist & 0xff) << scale) + } + dist>>=8; + scale+=8; + } + } else if (method == 1) { + dist = imm - ((Bit32u)cache.pos+8); + if (dist == 0) { + cache_addd( MOV_REG_LSL_IMM(dest_reg, HOST_pc, 0) ); // mov dest_reg, pc + } else { + while (dist) { + while ((dist & 3) == 0) { + dist>>=2; + scale+=2; + } + if (first) { + cache_addd( ADD_IMM(dest_reg, HOST_pc, dist & 0xff, ROTATE_SCALE(scale)) ); // add dest_reg, pc, #((dist & 0xff) << scale) + first = 0; + } else { + cache_addd( ADD_IMM(dest_reg, dest_reg, dist & 0xff, ROTATE_SCALE(scale)) ); // add dest_reg, dest_reg, #((dist & 0xff) << scale) + } + dist>>=8; + scale+=8; + } + } + } else if (method == 2) { + while (imm) { + while ((imm & 3) == 0) { + imm>>=2; + scale+=2; + } + if (first) { + cache_addd( MOV_IMM(dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm & 0xff) << scale) + first = 0; + } else { + cache_addd( ORR_IMM(dest_reg, dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm & 0xff) << scale) + } + imm>>=8; + scale+=8; + } + } else { + imm2 = ~imm; + while (imm2) { + while ((imm2 & 3) == 0) { + imm2>>=2; + scale+=2; + } + if (first) { + cache_addd( MVN_IMM(dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // mvn dest_reg, #((imm2 & 0xff) << scale) + first = 0; + } else { + cache_addd( BIC_IMM(dest_reg, dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic dest_reg, dest_reg, #((imm2 & 0xff) << scale) + } + imm2>>=8; + scale+=8; + } + } + } +} + +// helper function for gen_mov_word_to_reg +static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)data & 3) { + if ( ((Bit32u)data & 3) == 2 ) { + cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + cache_addd( LDRH_IMM(temp2, data_reg, 2) ); // ldrh temp2, [data_reg, #2] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 16) ); // orr dest_reg, dest_reg, temp2, lsl #16 + } else { + cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addd( LDRH_IMM(temp2, data_reg, 1) ); // ldrh temp2, [data_reg, #1] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 + cache_addd( LDRB_IMM(temp2, data_reg, 3) ); // ldrb temp2, [data_reg, #3] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 24) ); // orr dest_reg, dest_reg, temp2, lsl #24 + } + } else { + cache_addd( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] + } + } else { + if ((Bit32u)data & 1) { + cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addd( LDRB_IMM(temp2, data_reg, 1) ); // ldrb temp2, [data_reg, #1] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 + } else { + cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + } + } +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); + gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + Bits first, scale; + Bit32u imm2; + if (imm == 0) { + cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0 + } else { + scale = 0; + first = 1; + imm2 = (Bit32u)imm; + while (imm2) { + while ((imm2 & 3) == 0) { + imm2>>=2; + scale+=2; + } + if (first) { + cache_addd( MOV_IMM(dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm2 & 0xff) << scale) + first = 0; + } else { + cache_addd( ORR_IMM(dest_reg, dest_reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm2 & 0xff) << scale) + } + imm2>>=8; + scale+=8; + } + } +} + +// helper function for gen_mov_word_from_reg +static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)dest & 3) { + if ( ((Bit32u)dest & 3) == 2 ) { + cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 16) ); // mov temp2, src_reg, lsr #16 + cache_addd( STRH_IMM(temp2, data_reg, 2) ); // strh temp2, [data_reg, #2] + } else { + cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 + cache_addd( STRH_IMM(temp2, data_reg, 1) ); // strh temp2, [data_reg, #1] + cache_addd( MOV_REG_LSR_IMM(temp2, temp2, 16) ); // mov temp2, temp2, lsr #16 + cache_addd( STRB_IMM(temp2, data_reg, 3) ); // strb temp2, [data_reg, #3] + } + } else { + cache_addd( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] + } + } else { + if ((Bit32u)dest & 1) { + cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 + cache_addd( STRB_IMM(temp2, data_reg, 1) ); // strb temp2, [data_reg, #1] + } else { + cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + } + } +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); + cache_addd( LDRB_IMM(dest_reg, temp1, 0) ); // ldrb dest_reg, [temp1] +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + gen_mov_byte_to_reg_low(dest_reg, data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_addd( MOV_IMM(dest_reg, imm, 0) ); // mov dest_reg, #(imm) +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(dest_reg, imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + cache_addd( STRB_IMM(src_reg, temp1, 0) ); // strb src_reg, [temp1] +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + if (sign) { + cache_addd( MOV_REG_LSL_IMM(reg, reg, 24) ); // mov reg, reg, lsl #24 + cache_addd( MOV_REG_ASR_IMM(reg, reg, 24) ); // mov reg, reg, asr #24 + } else { + cache_addd( AND_IMM(reg, reg, 0xff, 0) ); // and reg, reg, #0xff + } +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + if (sign) { + cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 + cache_addd( MOV_REG_ASR_IMM(reg, reg, 16) ); // mov reg, reg, asr #16 + } else { + cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 + cache_addd( MOV_REG_LSR_IMM(reg, reg, 16) ); // mov reg, reg, lsr #16 + } +} + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + gen_mov_word_to_reg(temp3, op, 1); + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3 +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + Bits method1, method2, num1, num2, scale, sub; + if(!imm) return; + if (imm == 1) { + cache_addd( ADD_IMM(reg, reg, 1, 0) ); // add reg, reg, #1 + } else if (imm == 0xffffffff) { + cache_addd( SUB_IMM(reg, reg, 1, 0) ); // sub reg, reg, #1 + } else { + method1 = get_method_imm_gen_len(imm, 1, &num1); + method2 = get_method_imm_gen_len(-((Bit32s)imm), 1, &num2); + if (num2 < num1) { + method1 = method2; + imm = (Bit32u)(-((Bit32s)imm)); + sub = 1; + } else sub = 0; + + if (method1 != 2) { + gen_mov_dword_to_reg_imm(temp3, imm); + if (sub) { + cache_addd( SUB_REG_LSL_IMM(reg, reg, temp3, 0) ); // sub reg, reg, temp3 + } else { + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3 + } + } else { + scale = 0; + while (imm) { + while ((imm & 3) == 0) { + imm>>=2; + scale+=2; + } + if (sub) { + cache_addd( SUB_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // sub reg, reg, #((imm & 0xff) << scale) + } else { + cache_addd( ADD_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // add reg, reg, #((imm & 0xff) << scale) + } + imm>>=8; + scale+=8; + } + } + } +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + Bits method, scale; + Bit32u imm2; + imm2 = ~imm; + if(!imm2) return; + if (!imm) { + cache_addd( MOV_IMM(reg, 0, 0) ); // mov reg, #0 + } else { + method = get_method_imm_gen_len(imm, 0, NULL); + if (method != 3) { + gen_mov_dword_to_reg_imm(temp3, imm); + cache_addd( AND_REG_LSL_IMM(reg, reg, temp3, 0) ); // and reg, reg, temp3 + } else { + scale = 0; + while (imm2) { + while ((imm2 & 3) == 0) { + imm2>>=2; + scale+=2; + } + cache_addd( BIC_IMM(reg, reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic reg, reg, #((imm2 & 0xff) << scale) + imm2>>=8; + scale+=8; + } + } + } +} + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + gen_mov_dword_to_reg_imm(temp3, imm); + gen_mov_word_from_reg(temp3, dest, 1); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + +// add an 8bit constant value to a dword memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); + if (imm >= 0) { + cache_addd( ADD_IMM(temp3, temp3, (Bit32s)imm, 0) ); // add temp3, temp3, #(imm) + } else { + cache_addd( SUB_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // sub temp3, temp3, #(-imm) + } + gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); + // maybe use function gen_add_imm + if (dword) { + gen_mov_dword_to_reg_imm(temp2, imm); + } else { + gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); + } + cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2 + gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); +} + +// subtract an 8bit constant value from a dword memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); + if (imm >= 0) { + cache_addd( SUB_IMM(temp3, temp3, (Bit32s)imm, 0) ); // sub temp3, temp3, #(imm) + } else { + cache_addd( ADD_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // add temp3, temp3, #(-imm) + } + gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); + // maybe use function gen_add_imm/gen_sub_imm + if (dword) { + gen_mov_dword_to_reg_imm(temp2, imm); + } else { + gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); + } + cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // sub temp3, temp3, temp2 + gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); +} + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) ); // add dest_reg, dest_reg, scale_reg, lsl #(scale) + gen_add_imm(dest_reg, imm); +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + if (scale) { + cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) ); // mov dest_reg, dest_reg, lsl #(scale) + } + gen_add_imm(dest_reg, imm); +} + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + cache_addd( LDR_IMM(temp1, HOST_pc, 4) ); // ldr temp1, [pc, #4] + cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 + cache_addd( BX(temp1) ); // bx temp1 + cache_addd((Bit32u)func); // .int func +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + Bit32u proc_addr = (Bit32u)cache.pos; + gen_call_function_raw(func); + return proc_addr; +} + +#if (1) +// max of 4 parameters in a1-a4 + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + gen_mov_dword_to_reg_imm(param, imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + gen_mov_dword_to_reg_imm(param, addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + gen_mov_regs(param, reg); +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + gen_mov_word_to_reg(param, (void *)mem, 1); +} +#else + other arm abis +#endif + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + Bits num1, num2, scale, sub; + Bitu imm2; + gen_mov_word_to_reg(temp3, ptr, 1); + + if (imm) { + num1 = get_imm_gen_len(imm); + num2 = get_imm_gen_len(-imm); + + if (num2 < num1) { + imm = -imm; + sub = 1; + } else sub = 0; + + scale = 0; + imm2 = (Bitu)imm; + while (imm2) { + while ((imm2 & 3) == 0) { + imm2>>=2; + scale+=2; + } + if (sub) { + cache_addd( SUB_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // sub temp3, temp3, #((imm2 & 0xff) << scale) + } else { + cache_addd( ADD_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // add temp3, temp3, #((imm2 & 0xff) << scale) + } + imm2>>=8; + scale+=8; + } + } + +#if (1) +// (*ptr) should be word aligned + if ((imm & 0x03) == 0) { + cache_addd( LDR_IMM(temp1, temp3, 0) ); // ldr temp1, [temp3] + } else +#endif + { + cache_addd( LDRB_IMM(temp1, temp3, 0) ); // ldrb temp1, [temp3] + cache_addd( LDRB_IMM(temp2, temp3, 1) ); // ldrb temp2, [temp3, #1] + cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 8) ); // orr temp1, temp1, temp2, lsl #8 + cache_addd( LDRB_IMM(temp2, temp3, 2) ); // ldrb temp2, [temp3, #2] + cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 16) ); // orr temp1, temp1, temp2, lsl #16 + cache_addd( LDRB_IMM(temp2, temp3, 3) ); // ldrb temp2, [temp3, #3] + cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 24) ); // orr temp1, temp1, temp2, lsl #24 + } + + cache_addd( BX(temp1) ); // bx temp1 +} + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { + if (dword) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + } else { + cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 + } + cache_addd( BEQ_FWD(0) ); // beq j + return ((Bit32u)cache.pos-4); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + if (dword) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + } else { + cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 + } + cache_addd( BNE_FWD(0) ); // bne j + return ((Bit32u)cache.pos-4); +} + +// calculate relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-(data+8); + if (len<0) len=-len; + if (len>0x02000000) LOG_MSG("Big jump %d",len); +#endif + *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff ); +} + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + if (isdword) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + } else { + cache_addd( TST_IMM(reg, 0xff, 0) ); // tst reg, #0xff + } + cache_addd( BEQ_FWD(8) ); // beq nobranch (pc +8) + cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] + cache_addd( BX(temp1) ); // bx temp1 + cache_addd(0); // fill j + // nobranch: + return ((Bit32u)cache.pos-4); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u gen_create_branch_long_leqzero(HostReg reg) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + cache_addd( BGT_FWD(8) ); // bgt nobranch (pc+8) + cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] + cache_addd( BX(temp1) ); // bx temp1 + cache_addd(0); // fill j + // nobranch: + return ((Bit32u)cache.pos-4); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + // this is an absolute branch + *(Bit32u*)data=(Bit32u)cache.pos; +} + +static void gen_run_code(void) { + cache_addd(0xe92d4000); // stmfd sp!, {lr} + cache_addd(0xe92d0cf0); // stmfd sp!, {v1-v4,v7,v8} + + // adr: 8 + cache_addd( LDR_IMM(FC_SEGS_ADDR, HOST_pc, 64 - (8 + 8)) ); // ldr FC_SEGS_ADDR, [pc, #(&Segs)] + // adr: 12 + cache_addd( LDR_IMM(FC_REGS_ADDR, HOST_pc, 68 - (12 + 8)) ); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)] + + cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 + cache_addd(0xe92d4000); // stmfd sp!, {lr} + cache_addd( BX(HOST_r0) ); // bx r0 + + cache_addd(0xe8bd0cf0); // ldmfd sp!, {v1-v4,v7,v8} + + cache_addd(0xe8bd4000); // ldmfd sp!, {lr} + cache_addd( BX(HOST_lr) ); // bx lr + + // fill up to 64 bytes + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + + // adr: 64 + cache_addd((Bit32u)&Segs); // address of "Segs" + // adr: 68 + cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" +} + +// return from a function +static void gen_return_function(void) { + cache_addd(0xe8bd4000); // ldmfd sp!, {lr} + cache_addd( BX(HOST_lr) ); // bx lr +} + +#ifdef DRC_FLAGS_INVALIDATION + +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { +#ifdef DRC_FLAGS_INVALIDATION_DCODE + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit32u*)pos=ADD_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // add FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit32u*)pos=ORR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // orr FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit32u*)pos=AND_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // and FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit32u*)pos=SUB_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // sub FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit32u*)pos=EOR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // eor FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit32u*)pos=B_FWD(8); // b (pc+2*4) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit32u*)pos=ADD_IMM(FC_RETOP, HOST_a1, 1, 0); // add FC_RETOP, a1, #1 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit32u*)pos=SUB_IMM(FC_RETOP, HOST_a1, 1, 0); // sub FC_RETOP, a1, #1 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit32u*)pos=MOV_REG_LSL_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsl a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHRb: + *(Bit32u*)pos=AND_IMM(FC_RETOP, HOST_a1, 0xff, 0); // and FC_RETOP, a1, #0xff + *(Bit32u*)(pos+4)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHRw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=MOV_REG_LSR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHRd: + *(Bit32u*)pos=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SARb: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 + *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 24); // mov FC_RETOP, FC_RETOP, asr #24 + *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SARw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, asr #16 + *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SARd: + *(Bit32u*)pos=MOV_REG_ASR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, asr a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_RORb: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 + *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 8); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8 + *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 + break; + case t_RORw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_RORd: + *(Bit32u*)pos=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_ROLw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 + *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 + break; + case t_ROLd: + *(Bit32u*)pos=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 + *(Bit32u*)(pos+4)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit32u*)pos=RSB_IMM(FC_RETOP, HOST_a1, 0, 0); // rsb FC_RETOP, a1, #0 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + default: + *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func + break; + + } +#else + *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func +#endif +} +#endif + +static void cache_block_before_close(void) { } + +#ifdef DRC_USE_SEGS_ADDR + +// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldrh dest_reg, [FC_SEGS_ADDR, #index] +} + +// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldr dest_reg, [FC_SEGS_ADDR, #index] +} + +// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { + cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) ); // ldr temp1, [FC_SEGS_ADDR, #index] + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) ); // add reg, reg, temp1 +} + +#endif + +#ifdef DRC_USE_REGS_ADDR + +// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] +} + +// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { + if (dword) { + cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] + } else { + cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] + } +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { + cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { + cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] +} + + +// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { + cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) ); // ldr temp2, [FC_REGS_ADDR, #index] + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2 +} + + +// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) +static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { + cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] +} + +// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { + cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { + if (dword) { + cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] + } else { + cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] + } +} + +// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR +static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { + cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) ); // strb src_reg, [FC_REGS_ADDR, #index] +} + +#endif diff --git a/src/cpu/core_dynrec/risc_armv4le-s3.h b/src/cpu/core_dynrec/risc_armv4le-s3.h index c33423f..8690802 100644 --- a/src/cpu/core_dynrec/risc_armv4le-s3.h +++ b/src/cpu/core_dynrec/risc_armv4le-s3.h @@ -1,919 +1,919 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le-s3.h,v 1.6 2009/06/27 12:51:10 c2woody Exp $ */ - - -/* ARMv4 (little endian) backend by M-HT (speed-tweaked arm version) */ - - -// temporary registers -#define temp1 HOST_ip -#define temp2 HOST_v3 -#define temp3 HOST_v4 - -// register that holds function return values -#define FC_RETOP HOST_a1 - -// register used for address calculations, -#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG - -// register that holds the first parameter -#define FC_OP1 HOST_a1 - -// register that holds the second parameter -#define FC_OP2 HOST_a2 - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_v2 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_a1 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_a2 - -// temporary register for LEA -#define TEMP_REG_DRC HOST_v2 - -#ifdef DRC_USE_REGS_ADDR -// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code -#define FC_REGS_ADDR HOST_v7 -#endif - -#ifdef DRC_USE_SEGS_ADDR -// used to hold the address of "Segs" - preferably filled in function gen_run_code -#define FC_SEGS_ADDR HOST_v8 -#endif - - -// helper macro -#define ROTATE_SCALE(x) ( (x)?(32 - x):(0) ) - - -// instruction encodings - -// move -// mov dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define MOV_IMM(dst, imm, rimm) (0xe3a00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) -// mov dst, src, lsl #imm -#define MOV_REG_LSL_IMM(dst, src, imm) (0xe1a00000 + ((dst) << 12) + (src) + ((imm) << 7) ) -// movs dst, src, lsl #imm -#define MOVS_REG_LSL_IMM(dst, src, imm) (0xe1b00000 + ((dst) << 12) + (src) + ((imm) << 7) ) -// mov dst, src, lsr #imm -#define MOV_REG_LSR_IMM(dst, src, imm) (0xe1a00020 + ((dst) << 12) + (src) + ((imm) << 7) ) -// mov dst, src, asr #imm -#define MOV_REG_ASR_IMM(dst, src, imm) (0xe1a00040 + ((dst) << 12) + (src) + ((imm) << 7) ) -// mov dst, src, lsl rreg -#define MOV_REG_LSL_REG(dst, src, rreg) (0xe1a00010 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mov dst, src, lsr rreg -#define MOV_REG_LSR_REG(dst, src, rreg) (0xe1a00030 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mov dst, src, asr rreg -#define MOV_REG_ASR_REG(dst, src, rreg) (0xe1a00050 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mov dst, src, ror rreg -#define MOV_REG_ROR_REG(dst, src, rreg) (0xe1a00070 + ((dst) << 12) + (src) + ((rreg) << 8) ) -// mvn dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define MVN_IMM(dst, imm, rimm) (0xe3e00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) - -// arithmetic -// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// add dst, src1, src2, lsl #imm -#define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0xe0800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// sub dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define SUB_IMM(dst, src, imm, rimm) (0xe2400000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// sub dst, src1, src2, lsl #imm -#define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0xe0400000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// rsb dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define RSB_IMM(dst, src, imm, rimm) (0xe2600000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// cmp src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define CMP_IMM(src, imm, rimm) (0xe3500000 + ((src) << 16) + (imm) + ((rimm) << 7) ) -// nop -#define NOP MOV_REG_LSL_IMM(HOST_r0, HOST_r0, 0) - -// logical -// tst src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define TST_IMM(src, imm, rimm) (0xe3100000 + ((src) << 16) + (imm) + ((rimm) << 7) ) -// and dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define AND_IMM(dst, src, imm, rimm) (0xe2000000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// and dst, src1, src2, lsl #imm -#define AND_REG_LSL_IMM(dst, src1, src2, imm) (0xe0000000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// orr dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define ORR_IMM(dst, src, imm, rimm) (0xe3800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) -// orr dst, src1, src2, lsl #imm -#define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0xe1800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// orr dst, src1, src2, lsr #imm -#define ORR_REG_LSR_IMM(dst, src1, src2, imm) (0xe1800020 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// eor dst, src1, src2, lsl #imm -#define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0xe0200000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) -// bic dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 -#define BIC_IMM(dst, src, imm, rimm) (0xe3c00000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) - -// load -// ldr reg, [addr, #imm] @ 0 <= imm < 4096 -#define LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) ) -// ldrh reg, [addr, #imm] @ 0 <= imm < 256 -#define LDRH_IMM(reg, addr, imm) (0xe1d000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) -// ldrb reg, [addr, #imm] @ 0 <= imm < 4096 -#define LDRB_IMM(reg, addr, imm) (0xe5d00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) - -// store -// str reg, [addr, #imm] @ 0 <= imm < 4096 -#define STR_IMM(reg, addr, imm) (0xe5800000 + ((reg) << 12) + ((addr) << 16) + (imm) ) -// strh reg, [addr, #imm] @ 0 <= imm < 256 -#define STRH_IMM(reg, addr, imm) (0xe1c000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) -// strb reg, [addr, #imm] @ 0 <= imm < 4096 -#define STRB_IMM(reg, addr, imm) (0xe5c00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) - -// branch -// beq pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define BEQ_FWD(imm) (0x0a000000 + ((imm) >> 2) ) -// bne pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define BNE_FWD(imm) (0x1a000000 + ((imm) >> 2) ) -// bgt pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define BGT_FWD(imm) (0xca000000 + ((imm) >> 2) ) -// b pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 -#define B_FWD(imm) (0xea000000 + ((imm) >> 2) ) -// bx reg -#define BX(reg) (0xe12fff10 + (reg) ) - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - if(reg_src == reg_dst) return; - cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) ); // mov reg_dst, reg_src -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - Bits first, scale; - if (imm == 0) { - cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0 - } else { - scale = 0; - first = 1; - while (imm) { - while ((imm & 3) == 0) { - imm>>=2; - scale+=2; - } - if (first) { - cache_addd( MOV_IMM(dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm & 0xff) << scale) - first = 0; - } else { - cache_addd( ORR_IMM(dest_reg, dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm & 0xff) << scale) - } - imm>>=8; - scale+=8; - } - } -} - -// helper function for gen_mov_word_to_reg -static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)data & 3) { - if ( ((Bit32u)data & 3) == 2 ) { - cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - cache_addd( LDRH_IMM(temp2, data_reg, 2) ); // ldrh temp2, [data_reg, #2] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 16) ); // orr dest_reg, dest_reg, temp2, lsl #16 - } else { - cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addd( LDRH_IMM(temp2, data_reg, 1) ); // ldrh temp2, [data_reg, #1] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 - cache_addd( LDRB_IMM(temp2, data_reg, 3) ); // ldrb temp2, [data_reg, #3] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 24) ); // orr dest_reg, dest_reg, temp2, lsl #24 - } - } else { - cache_addd( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] - } - } else { - if ((Bit32u)data & 1) { - cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addd( LDRB_IMM(temp2, data_reg, 1) ); // ldrb temp2, [data_reg, #1] - cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 - } else { - cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - } - } -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); - gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); -} - -// helper function for gen_mov_word_from_reg -static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)dest & 3) { - if ( ((Bit32u)dest & 3) == 2 ) { - cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 16) ); // mov temp2, src_reg, lsr #16 - cache_addd( STRH_IMM(temp2, data_reg, 2) ); // strh temp2, [data_reg, #2] - } else { - cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 - cache_addd( STRH_IMM(temp2, data_reg, 1) ); // strh temp2, [data_reg, #1] - cache_addd( MOV_REG_LSR_IMM(temp2, temp2, 16) ); // mov temp2, temp2, lsr #16 - cache_addd( STRB_IMM(temp2, data_reg, 3) ); // strb temp2, [data_reg, #3] - } - } else { - cache_addd( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] - } - } else { - if ((Bit32u)dest & 1) { - cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 - cache_addd( STRB_IMM(temp2, data_reg, 1) ); // strb temp2, [data_reg, #1] - } else { - cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - } - } -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); - cache_addd( LDRB_IMM(dest_reg, temp1, 0) ); // ldrb dest_reg, [temp1] -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - gen_mov_byte_to_reg_low(dest_reg, data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_addd( MOV_IMM(dest_reg, imm, 0) ); // mov dest_reg, #(imm) -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(dest_reg, imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - cache_addd( STRB_IMM(src_reg, temp1, 0) ); // strb src_reg, [temp1] -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - if (sign) { - cache_addd( MOV_REG_LSL_IMM(reg, reg, 24) ); // mov reg, reg, lsl #24 - cache_addd( MOV_REG_ASR_IMM(reg, reg, 24) ); // mov reg, reg, asr #24 - } else { - cache_addd( AND_IMM(reg, reg, 0xff, 0) ); // and reg, reg, #0xff - } -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - if (sign) { - cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 - cache_addd( MOV_REG_ASR_IMM(reg, reg, 16) ); // mov reg, reg, asr #16 - } else { - cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 - cache_addd( MOV_REG_LSR_IMM(reg, reg, 16) ); // mov reg, reg, lsr #16 - } -} - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - gen_mov_word_to_reg(temp3, op, 1); - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3 -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - Bits scale; - if(!imm) return; - if (imm == 0xffffffff) { - cache_addd( SUB_IMM(reg, reg, 1, 0) ); // sub reg, reg, #1 - } else { - scale = 0; - while (imm) { - while ((imm & 3) == 0) { - imm>>=2; - scale+=2; - } - cache_addd( ADD_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // add reg, reg, #((imm & 0xff) << scale) - imm>>=8; - scale+=8; - } - } -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - Bits scale; - Bit32u imm2; - imm2 = ~imm; - if(!imm2) return; - if (!imm) { - cache_addd( MOV_IMM(reg, 0, 0) ); // mov reg, #0 - } else { - scale = 0; - while (imm2) { - while ((imm2 & 3) == 0) { - imm2>>=2; - scale+=2; - } - cache_addd( BIC_IMM(reg, reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic reg, reg, #((imm2 & 0xff) << scale) - imm2>>=8; - scale+=8; - } - } -} - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - gen_mov_dword_to_reg_imm(temp3, imm); - gen_mov_word_from_reg(temp3, dest, 1); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - -// add an 8bit constant value to a dword memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); - if (imm >= 0) { - cache_addd( ADD_IMM(temp3, temp3, (Bit32s)imm, 0) ); // add temp3, temp3, #(imm) - } else { - cache_addd( SUB_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // sub temp3, temp3, #(-imm) - } - gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); - // maybe use function gen_add_imm - if (dword) { - gen_mov_dword_to_reg_imm(temp2, imm); - } else { - gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); - } - cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2 - gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); -} - -// subtract an 8bit constant value from a dword memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); - if (imm >= 0) { - cache_addd( SUB_IMM(temp3, temp3, (Bit32s)imm, 0) ); // sub temp3, temp3, #(imm) - } else { - cache_addd( ADD_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // add temp3, temp3, #(-imm) - } - gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); - gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); - // maybe use function gen_add_imm/gen_sub_imm - if (dword) { - gen_mov_dword_to_reg_imm(temp2, imm); - } else { - gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); - } - cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // sub temp3, temp3, temp2 - gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); -} - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) ); // add dest_reg, dest_reg, scale_reg, lsl #(scale) - gen_add_imm(dest_reg, imm); -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - if (scale) { - cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) ); // mov dest_reg, dest_reg, lsl #(scale) - } - gen_add_imm(dest_reg, imm); -} - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - cache_addd( LDR_IMM(temp1, HOST_pc, 4) ); // ldr temp1, [pc, #4] - cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 - cache_addd( BX(temp1) ); // bx temp1 - cache_addd((Bit32u)func); // .int func -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - Bit32u proc_addr = (Bit32u)cache.pos; - gen_call_function_raw(func); - return proc_addr; -} - -#if (1) -// max of 4 parameters in a1-a4 - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - gen_mov_dword_to_reg_imm(param, imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - gen_mov_dword_to_reg_imm(param, addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - gen_mov_regs(param, reg); -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - gen_mov_word_to_reg(param, (void *)mem, 1); -} -#else - other arm abis -#endif - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - Bits scale; - Bitu imm2; - gen_mov_word_to_reg(temp3, ptr, 1); - - if (imm) { - scale = 0; - imm2 = (Bitu)imm; - while (imm2) { - while ((imm2 & 3) == 0) { - imm2>>=2; - scale+=2; - } - cache_addd( ADD_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // add temp3, temp3, #((imm2 & 0xff) << scale) - imm2>>=8; - scale+=8; - } - } - -#if (1) -// (*ptr) should be word aligned - if ((imm & 0x03) == 0) { - cache_addd( LDR_IMM(temp1, temp3, 0) ); // ldr temp1, [temp3] - } else -#endif - { - cache_addd( LDRB_IMM(temp1, temp3, 0) ); // ldrb temp1, [temp3] - cache_addd( LDRB_IMM(temp2, temp3, 1) ); // ldrb temp2, [temp3, #1] - cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 8) ); // orr temp1, temp1, temp2, lsl #8 - cache_addd( LDRB_IMM(temp2, temp3, 2) ); // ldrb temp2, [temp3, #2] - cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 16) ); // orr temp1, temp1, temp2, lsl #16 - cache_addd( LDRB_IMM(temp2, temp3, 3) ); // ldrb temp2, [temp3, #3] - cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 24) ); // orr temp1, temp1, temp2, lsl #24 - } - - cache_addd( BX(temp1) ); // bx temp1 -} - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { - if (dword) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - } else { - cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 - } - cache_addd( BEQ_FWD(0) ); // beq j - return ((Bit32u)cache.pos-4); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - if (dword) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - } else { - cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 - } - cache_addd( BNE_FWD(0) ); // bne j - return ((Bit32u)cache.pos-4); -} - -// calculate relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-(data+8); - if (len<0) len=-len; - if (len>0x02000000) LOG_MSG("Big jump %d",len); -#endif - *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff ); -} - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - if (isdword) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - } else { - cache_addd( TST_IMM(reg, 0xff, 0) ); // tst reg, #0xff - } - cache_addd( BEQ_FWD(8) ); // beq nobranch (pc +8) - cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] - cache_addd( BX(temp1) ); // bx temp1 - cache_addd(0); // fill j - // nobranch: - return ((Bit32u)cache.pos-4); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u gen_create_branch_long_leqzero(HostReg reg) { - cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 - cache_addd( BGT_FWD(8) ); // bgt nobranch (pc+8) - cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] - cache_addd( BX(temp1) ); // bx temp1 - cache_addd(0); // fill j - // nobranch: - return ((Bit32u)cache.pos-4); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - // this is an absolute branch - *(Bit32u*)data=(Bit32u)cache.pos; -} - -static void gen_run_code(void) { - cache_addd(0xe92d4000); // stmfd sp!, {lr} - cache_addd(0xe92d0cf0); // stmfd sp!, {v1-v4,v7,v8} - - // adr: 8 - cache_addd( LDR_IMM(FC_SEGS_ADDR, HOST_pc, 64 - (8 + 8)) ); // ldr FC_SEGS_ADDR, [pc, #(&Segs)] - // adr: 12 - cache_addd( LDR_IMM(FC_REGS_ADDR, HOST_pc, 68 - (12 + 8)) ); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)] - - cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 - cache_addd(0xe92d4000); // stmfd sp!, {lr} - cache_addd( BX(HOST_r0) ); // bx r0 - - cache_addd(0xe8bd0cf0); // ldmfd sp!, {v1-v4,v7,v8} - - cache_addd(0xe8bd4000); // ldmfd sp!, {lr} - cache_addd( BX(HOST_lr) ); // bx lr - - // fill up to 64 bytes - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - cache_addd( NOP ); // nop - - // adr: 64 - cache_addd((Bit32u)&Segs); // address of "Segs" - // adr: 68 - cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" -} - -// return from a function -static void gen_return_function(void) { - cache_addd(0xe8bd4000); // ldmfd sp!, {lr} - cache_addd( BX(HOST_lr) ); // bx lr -} - -#ifdef DRC_FLAGS_INVALIDATION - -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { -#ifdef DRC_FLAGS_INVALIDATION_DCODE - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit32u*)pos=ADD_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // add FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit32u*)pos=ORR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // orr FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit32u*)pos=AND_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // and FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit32u*)pos=SUB_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // sub FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit32u*)pos=EOR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // eor FC_RETOP, a1, a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit32u*)pos=B_FWD(8); // b (pc+2*4) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit32u*)pos=ADD_IMM(FC_RETOP, HOST_a1, 1, 0); // add FC_RETOP, a1, #1 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit32u*)pos=SUB_IMM(FC_RETOP, HOST_a1, 1, 0); // sub FC_RETOP, a1, #1 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit32u*)pos=MOV_REG_LSL_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsl a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHRb: - *(Bit32u*)pos=AND_IMM(FC_RETOP, HOST_a1, 0xff, 0); // and FC_RETOP, a1, #0xff - *(Bit32u*)(pos+4)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHRw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=MOV_REG_LSR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SHRd: - *(Bit32u*)pos=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SARb: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 - *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 24); // mov FC_RETOP, FC_RETOP, asr #24 - *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SARw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, asr #16 - *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_SARd: - *(Bit32u*)pos=MOV_REG_ASR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, asr a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_RORb: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 - *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 8); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8 - *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 - break; - case t_RORw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_RORd: - *(Bit32u*)pos=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_ROLw: - *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 - *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 - *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 - *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 - break; - case t_ROLd: - *(Bit32u*)pos=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 - *(Bit32u*)(pos+4)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit32u*)pos=RSB_IMM(FC_RETOP, HOST_a1, 0, 0); // rsb FC_RETOP, a1, #0 - *(Bit32u*)(pos+4)=NOP; // nop - *(Bit32u*)(pos+8)=NOP; // nop - *(Bit32u*)(pos+12)=NOP; // nop - break; - default: - *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func - break; - - } -#else - *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func -#endif -} -#endif - -static void cache_block_before_close(void) { } - -#ifdef DRC_USE_SEGS_ADDR - -// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldrh dest_reg, [FC_SEGS_ADDR, #index] -} - -// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldr dest_reg, [FC_SEGS_ADDR, #index] -} - -// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { - cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) ); // ldr temp1, [FC_SEGS_ADDR, #index] - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) ); // add reg, reg, temp1 -} - -#endif - -#ifdef DRC_USE_REGS_ADDR - -// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] -} - -// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { - cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { - if (dword) { - cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] - } else { - cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] - } -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { - cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { - cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] -} - - -// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { - cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) ); // ldr temp2, [FC_REGS_ADDR, #index] - cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2 -} - - -// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) -static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { - cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] -} - -// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { - cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { - if (dword) { - cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] - } else { - cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] - } -} - -// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR -static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { - cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) ); // strb src_reg, [FC_REGS_ADDR, #index] -} - -#endif +/* + * Copyright (C) 2002-2010 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: risc_armv4le-s3.h,v 1.6 2009-06-27 12:51:10 c2woody Exp $ */ + + +/* ARMv4 (little endian) backend by M-HT (speed-tweaked arm version) */ + + +// temporary registers +#define temp1 HOST_ip +#define temp2 HOST_v3 +#define temp3 HOST_v4 + +// register that holds function return values +#define FC_RETOP HOST_a1 + +// register used for address calculations, +#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG + +// register that holds the first parameter +#define FC_OP1 HOST_a1 + +// register that holds the second parameter +#define FC_OP2 HOST_a2 + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_v2 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_a1 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_a2 + +// temporary register for LEA +#define TEMP_REG_DRC HOST_v2 + +#ifdef DRC_USE_REGS_ADDR +// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code +#define FC_REGS_ADDR HOST_v7 +#endif + +#ifdef DRC_USE_SEGS_ADDR +// used to hold the address of "Segs" - preferably filled in function gen_run_code +#define FC_SEGS_ADDR HOST_v8 +#endif + + +// helper macro +#define ROTATE_SCALE(x) ( (x)?(32 - x):(0) ) + + +// instruction encodings + +// move +// mov dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define MOV_IMM(dst, imm, rimm) (0xe3a00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) +// mov dst, src, lsl #imm +#define MOV_REG_LSL_IMM(dst, src, imm) (0xe1a00000 + ((dst) << 12) + (src) + ((imm) << 7) ) +// movs dst, src, lsl #imm +#define MOVS_REG_LSL_IMM(dst, src, imm) (0xe1b00000 + ((dst) << 12) + (src) + ((imm) << 7) ) +// mov dst, src, lsr #imm +#define MOV_REG_LSR_IMM(dst, src, imm) (0xe1a00020 + ((dst) << 12) + (src) + ((imm) << 7) ) +// mov dst, src, asr #imm +#define MOV_REG_ASR_IMM(dst, src, imm) (0xe1a00040 + ((dst) << 12) + (src) + ((imm) << 7) ) +// mov dst, src, lsl rreg +#define MOV_REG_LSL_REG(dst, src, rreg) (0xe1a00010 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mov dst, src, lsr rreg +#define MOV_REG_LSR_REG(dst, src, rreg) (0xe1a00030 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mov dst, src, asr rreg +#define MOV_REG_ASR_REG(dst, src, rreg) (0xe1a00050 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mov dst, src, ror rreg +#define MOV_REG_ROR_REG(dst, src, rreg) (0xe1a00070 + ((dst) << 12) + (src) + ((rreg) << 8) ) +// mvn dst, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define MVN_IMM(dst, imm, rimm) (0xe3e00000 + ((dst) << 12) + (imm) + ((rimm) << 7) ) + +// arithmetic +// add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// add dst, src1, src2, lsl #imm +#define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0xe0800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// sub dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define SUB_IMM(dst, src, imm, rimm) (0xe2400000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// sub dst, src1, src2, lsl #imm +#define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0xe0400000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// rsb dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define RSB_IMM(dst, src, imm, rimm) (0xe2600000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// cmp src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define CMP_IMM(src, imm, rimm) (0xe3500000 + ((src) << 16) + (imm) + ((rimm) << 7) ) +// nop +#define NOP MOV_REG_LSL_IMM(HOST_r0, HOST_r0, 0) + +// logical +// tst src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define TST_IMM(src, imm, rimm) (0xe3100000 + ((src) << 16) + (imm) + ((rimm) << 7) ) +// and dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define AND_IMM(dst, src, imm, rimm) (0xe2000000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// and dst, src1, src2, lsl #imm +#define AND_REG_LSL_IMM(dst, src1, src2, imm) (0xe0000000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// orr dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define ORR_IMM(dst, src, imm, rimm) (0xe3800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) +// orr dst, src1, src2, lsl #imm +#define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0xe1800000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// orr dst, src1, src2, lsr #imm +#define ORR_REG_LSR_IMM(dst, src1, src2, imm) (0xe1800020 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// eor dst, src1, src2, lsl #imm +#define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0xe0200000 + ((dst) << 12) + ((src1) << 16) + (src2) + ((imm) << 7) ) +// bic dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 +#define BIC_IMM(dst, src, imm, rimm) (0xe3c00000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) + +// load +// ldr reg, [addr, #imm] @ 0 <= imm < 4096 +#define LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) ) +// ldrh reg, [addr, #imm] @ 0 <= imm < 256 +#define LDRH_IMM(reg, addr, imm) (0xe1d000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) +// ldrb reg, [addr, #imm] @ 0 <= imm < 4096 +#define LDRB_IMM(reg, addr, imm) (0xe5d00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) + +// store +// str reg, [addr, #imm] @ 0 <= imm < 4096 +#define STR_IMM(reg, addr, imm) (0xe5800000 + ((reg) << 12) + ((addr) << 16) + (imm) ) +// strh reg, [addr, #imm] @ 0 <= imm < 256 +#define STRH_IMM(reg, addr, imm) (0xe1c000b0 + ((reg) << 12) + ((addr) << 16) + (((imm) & 0xf0) << 4) + ((imm) & 0x0f) ) +// strb reg, [addr, #imm] @ 0 <= imm < 4096 +#define STRB_IMM(reg, addr, imm) (0xe5c00000 + ((reg) << 12) + ((addr) << 16) + (imm) ) + +// branch +// beq pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define BEQ_FWD(imm) (0x0a000000 + ((imm) >> 2) ) +// bne pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define BNE_FWD(imm) (0x1a000000 + ((imm) >> 2) ) +// bgt pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define BGT_FWD(imm) (0xca000000 + ((imm) >> 2) ) +// b pc+imm @ 0 <= imm < 32M & imm mod 4 = 0 +#define B_FWD(imm) (0xea000000 + ((imm) >> 2) ) +// bx reg +#define BX(reg) (0xe12fff10 + (reg) ) + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + if(reg_src == reg_dst) return; + cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) ); // mov reg_dst, reg_src +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + Bits first, scale; + if (imm == 0) { + cache_addd( MOV_IMM(dest_reg, 0, 0) ); // mov dest_reg, #0 + } else { + scale = 0; + first = 1; + while (imm) { + while ((imm & 3) == 0) { + imm>>=2; + scale+=2; + } + if (first) { + cache_addd( MOV_IMM(dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // mov dest_reg, #((imm & 0xff) << scale) + first = 0; + } else { + cache_addd( ORR_IMM(dest_reg, dest_reg, imm & 0xff, ROTATE_SCALE(scale)) ); // orr dest_reg, dest_reg, #((imm & 0xff) << scale) + } + imm>>=8; + scale+=8; + } + } +} + +// helper function for gen_mov_word_to_reg +static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)data & 3) { + if ( ((Bit32u)data & 3) == 2 ) { + cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + cache_addd( LDRH_IMM(temp2, data_reg, 2) ); // ldrh temp2, [data_reg, #2] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 16) ); // orr dest_reg, dest_reg, temp2, lsl #16 + } else { + cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addd( LDRH_IMM(temp2, data_reg, 1) ); // ldrh temp2, [data_reg, #1] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 + cache_addd( LDRB_IMM(temp2, data_reg, 3) ); // ldrb temp2, [data_reg, #3] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 24) ); // orr dest_reg, dest_reg, temp2, lsl #24 + } + } else { + cache_addd( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] + } + } else { + if ((Bit32u)data & 1) { + cache_addd( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addd( LDRB_IMM(temp2, data_reg, 1) ); // ldrb temp2, [data_reg, #1] + cache_addd( ORR_REG_LSL_IMM(dest_reg, dest_reg, temp2, 8) ); // orr dest_reg, dest_reg, temp2, lsl #8 + } else { + cache_addd( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + } + } +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); + gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); +} + +// helper function for gen_mov_word_from_reg +static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)dest & 3) { + if ( ((Bit32u)dest & 3) == 2 ) { + cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 16) ); // mov temp2, src_reg, lsr #16 + cache_addd( STRH_IMM(temp2, data_reg, 2) ); // strh temp2, [data_reg, #2] + } else { + cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 + cache_addd( STRH_IMM(temp2, data_reg, 1) ); // strh temp2, [data_reg, #1] + cache_addd( MOV_REG_LSR_IMM(temp2, temp2, 16) ); // mov temp2, temp2, lsr #16 + cache_addd( STRB_IMM(temp2, data_reg, 3) ); // strb temp2, [data_reg, #3] + } + } else { + cache_addd( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] + } + } else { + if ((Bit32u)dest & 1) { + cache_addd( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addd( MOV_REG_LSR_IMM(temp2, src_reg, 8) ); // mov temp2, src_reg, lsr #8 + cache_addd( STRB_IMM(temp2, data_reg, 1) ); // strb temp2, [data_reg, #1] + } else { + cache_addd( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + } + } +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)data); + cache_addd( LDRB_IMM(dest_reg, temp1, 0) ); // ldrb dest_reg, [temp1] +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + gen_mov_byte_to_reg_low(dest_reg, data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_addd( MOV_IMM(dest_reg, imm, 0) ); // mov dest_reg, #(imm) +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(dest_reg, imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + cache_addd( STRB_IMM(src_reg, temp1, 0) ); // strb src_reg, [temp1] +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + if (sign) { + cache_addd( MOV_REG_LSL_IMM(reg, reg, 24) ); // mov reg, reg, lsl #24 + cache_addd( MOV_REG_ASR_IMM(reg, reg, 24) ); // mov reg, reg, asr #24 + } else { + cache_addd( AND_IMM(reg, reg, 0xff, 0) ); // and reg, reg, #0xff + } +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + if (sign) { + cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 + cache_addd( MOV_REG_ASR_IMM(reg, reg, 16) ); // mov reg, reg, asr #16 + } else { + cache_addd( MOV_REG_LSL_IMM(reg, reg, 16) ); // mov reg, reg, lsl #16 + cache_addd( MOV_REG_LSR_IMM(reg, reg, 16) ); // mov reg, reg, lsr #16 + } +} + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + gen_mov_word_to_reg(temp3, op, 1); + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) ); // add reg, reg, temp3 +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + Bits scale; + if(!imm) return; + if (imm == 0xffffffff) { + cache_addd( SUB_IMM(reg, reg, 1, 0) ); // sub reg, reg, #1 + } else { + scale = 0; + while (imm) { + while ((imm & 3) == 0) { + imm>>=2; + scale+=2; + } + cache_addd( ADD_IMM(reg, reg, imm & 0xff, ROTATE_SCALE(scale)) ); // add reg, reg, #((imm & 0xff) << scale) + imm>>=8; + scale+=8; + } + } +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + Bits scale; + Bit32u imm2; + imm2 = ~imm; + if(!imm2) return; + if (!imm) { + cache_addd( MOV_IMM(reg, 0, 0) ); // mov reg, #0 + } else { + scale = 0; + while (imm2) { + while ((imm2 & 3) == 0) { + imm2>>=2; + scale+=2; + } + cache_addd( BIC_IMM(reg, reg, imm2 & 0xff, ROTATE_SCALE(scale)) ); // bic reg, reg, #((imm2 & 0xff) << scale) + imm2>>=8; + scale+=8; + } + } +} + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + gen_mov_dword_to_reg_imm(temp3, imm); + gen_mov_word_from_reg(temp3, dest, 1); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + +// add an 8bit constant value to a dword memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); + if (imm >= 0) { + cache_addd( ADD_IMM(temp3, temp3, (Bit32s)imm, 0) ); // add temp3, temp3, #(imm) + } else { + cache_addd( SUB_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // sub temp3, temp3, #(-imm) + } + gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); + // maybe use function gen_add_imm + if (dword) { + gen_mov_dword_to_reg_imm(temp2, imm); + } else { + gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); + } + cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // add temp3, temp3, temp2 + gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); +} + +// subtract an 8bit constant value from a dword memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, 1, temp1); + if (imm >= 0) { + cache_addd( SUB_IMM(temp3, temp3, (Bit32s)imm, 0) ); // sub temp3, temp3, #(imm) + } else { + cache_addd( ADD_IMM(temp3, temp3, -((Bit32s)imm), 0) ); // add temp3, temp3, #(-imm) + } + gen_mov_word_from_reg_helper(temp3, dest, 1, temp1); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(temp1, (Bit32u)dest); + gen_mov_word_to_reg_helper(temp3, dest, dword, temp1); + // maybe use function gen_add_imm/gen_sub_imm + if (dword) { + gen_mov_dword_to_reg_imm(temp2, imm); + } else { + gen_mov_word_to_reg_imm(temp2, (Bit16u)imm); + } + cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) ); // sub temp3, temp3, temp2 + gen_mov_word_from_reg_helper(temp3, dest, dword, temp1); +} + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) ); // add dest_reg, dest_reg, scale_reg, lsl #(scale) + gen_add_imm(dest_reg, imm); +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + if (scale) { + cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) ); // mov dest_reg, dest_reg, lsl #(scale) + } + gen_add_imm(dest_reg, imm); +} + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + cache_addd( LDR_IMM(temp1, HOST_pc, 4) ); // ldr temp1, [pc, #4] + cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 + cache_addd( BX(temp1) ); // bx temp1 + cache_addd((Bit32u)func); // .int func +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + Bit32u proc_addr = (Bit32u)cache.pos; + gen_call_function_raw(func); + return proc_addr; +} + +#if (1) +// max of 4 parameters in a1-a4 + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + gen_mov_dword_to_reg_imm(param, imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + gen_mov_dword_to_reg_imm(param, addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + gen_mov_regs(param, reg); +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + gen_mov_word_to_reg(param, (void *)mem, 1); +} +#else + other arm abis +#endif + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + Bits scale; + Bitu imm2; + gen_mov_word_to_reg(temp3, ptr, 1); + + if (imm) { + scale = 0; + imm2 = (Bitu)imm; + while (imm2) { + while ((imm2 & 3) == 0) { + imm2>>=2; + scale+=2; + } + cache_addd( ADD_IMM(temp3, temp3, imm2 & 0xff, ROTATE_SCALE(scale)) ); // add temp3, temp3, #((imm2 & 0xff) << scale) + imm2>>=8; + scale+=8; + } + } + +#if (1) +// (*ptr) should be word aligned + if ((imm & 0x03) == 0) { + cache_addd( LDR_IMM(temp1, temp3, 0) ); // ldr temp1, [temp3] + } else +#endif + { + cache_addd( LDRB_IMM(temp1, temp3, 0) ); // ldrb temp1, [temp3] + cache_addd( LDRB_IMM(temp2, temp3, 1) ); // ldrb temp2, [temp3, #1] + cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 8) ); // orr temp1, temp1, temp2, lsl #8 + cache_addd( LDRB_IMM(temp2, temp3, 2) ); // ldrb temp2, [temp3, #2] + cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 16) ); // orr temp1, temp1, temp2, lsl #16 + cache_addd( LDRB_IMM(temp2, temp3, 3) ); // ldrb temp2, [temp3, #3] + cache_addd( ORR_REG_LSL_IMM(temp1, temp1, temp2, 24) ); // orr temp1, temp1, temp2, lsl #24 + } + + cache_addd( BX(temp1) ); // bx temp1 +} + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { + if (dword) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + } else { + cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 + } + cache_addd( BEQ_FWD(0) ); // beq j + return ((Bit32u)cache.pos-4); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + if (dword) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + } else { + cache_addd( MOVS_REG_LSL_IMM(temp1, reg, 16) ); // movs temp1, reg, lsl #16 + } + cache_addd( BNE_FWD(0) ); // bne j + return ((Bit32u)cache.pos-4); +} + +// calculate relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-(data+8); + if (len<0) len=-len; + if (len>0x02000000) LOG_MSG("Big jump %d",len); +#endif + *(Bit32u*)data=( (*(Bit32u*)data) & 0xff000000 ) | ( ( ((Bit32u)cache.pos - (data+8)) >> 2 ) & 0x00ffffff ); +} + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + if (isdword) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + } else { + cache_addd( TST_IMM(reg, 0xff, 0) ); // tst reg, #0xff + } + cache_addd( BEQ_FWD(8) ); // beq nobranch (pc +8) + cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] + cache_addd( BX(temp1) ); // bx temp1 + cache_addd(0); // fill j + // nobranch: + return ((Bit32u)cache.pos-4); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u gen_create_branch_long_leqzero(HostReg reg) { + cache_addd( CMP_IMM(reg, 0, 0) ); // cmp reg, #0 + cache_addd( BGT_FWD(8) ); // bgt nobranch (pc+8) + cache_addd( LDR_IMM(temp1, HOST_pc, 0) ); // ldr temp1, [pc, #0] + cache_addd( BX(temp1) ); // bx temp1 + cache_addd(0); // fill j + // nobranch: + return ((Bit32u)cache.pos-4); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + // this is an absolute branch + *(Bit32u*)data=(Bit32u)cache.pos; +} + +static void gen_run_code(void) { + cache_addd(0xe92d4000); // stmfd sp!, {lr} + cache_addd(0xe92d0cf0); // stmfd sp!, {v1-v4,v7,v8} + + // adr: 8 + cache_addd( LDR_IMM(FC_SEGS_ADDR, HOST_pc, 64 - (8 + 8)) ); // ldr FC_SEGS_ADDR, [pc, #(&Segs)] + // adr: 12 + cache_addd( LDR_IMM(FC_REGS_ADDR, HOST_pc, 68 - (12 + 8)) ); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)] + + cache_addd( ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 + cache_addd(0xe92d4000); // stmfd sp!, {lr} + cache_addd( BX(HOST_r0) ); // bx r0 + + cache_addd(0xe8bd0cf0); // ldmfd sp!, {v1-v4,v7,v8} + + cache_addd(0xe8bd4000); // ldmfd sp!, {lr} + cache_addd( BX(HOST_lr) ); // bx lr + + // fill up to 64 bytes + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + cache_addd( NOP ); // nop + + // adr: 64 + cache_addd((Bit32u)&Segs); // address of "Segs" + // adr: 68 + cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" +} + +// return from a function +static void gen_return_function(void) { + cache_addd(0xe8bd4000); // ldmfd sp!, {lr} + cache_addd( BX(HOST_lr) ); // bx lr +} + +#ifdef DRC_FLAGS_INVALIDATION + +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { +#ifdef DRC_FLAGS_INVALIDATION_DCODE + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit32u*)pos=ADD_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // add FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit32u*)pos=ORR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // orr FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit32u*)pos=AND_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // and FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit32u*)pos=SUB_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // sub FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit32u*)pos=EOR_REG_LSL_IMM(FC_RETOP, HOST_a1, HOST_a2, 0); // eor FC_RETOP, a1, a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit32u*)pos=B_FWD(8); // b (pc+2*4) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit32u*)pos=ADD_IMM(FC_RETOP, HOST_a1, 1, 0); // add FC_RETOP, a1, #1 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit32u*)pos=SUB_IMM(FC_RETOP, HOST_a1, 1, 0); // sub FC_RETOP, a1, #1 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit32u*)pos=MOV_REG_LSL_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsl a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHRb: + *(Bit32u*)pos=AND_IMM(FC_RETOP, HOST_a1, 0xff, 0); // and FC_RETOP, a1, #0xff + *(Bit32u*)(pos+4)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHRw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=MOV_REG_LSR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+8)=MOV_REG_LSR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, lsr a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SHRd: + *(Bit32u*)pos=MOV_REG_LSR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, lsr a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SARb: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 + *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 24); // mov FC_RETOP, FC_RETOP, asr #24 + *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SARw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=MOV_REG_ASR_IMM(FC_RETOP, FC_RETOP, 16); // mov FC_RETOP, FC_RETOP, asr #16 + *(Bit32u*)(pos+8)=MOV_REG_ASR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, asr a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_SARd: + *(Bit32u*)pos=MOV_REG_ASR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, asr a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_RORb: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 24); // mov FC_RETOP, a1, lsl #24 + *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 8); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8 + *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 + break; + case t_RORw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+8)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_RORd: + *(Bit32u*)pos=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_ROLw: + *(Bit32u*)pos=MOV_REG_LSL_IMM(FC_RETOP, HOST_a1, 16); // mov FC_RETOP, a1, lsl #16 + *(Bit32u*)(pos+4)=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 + *(Bit32u*)(pos+8)=ORR_REG_LSR_IMM(FC_RETOP, FC_RETOP, FC_RETOP, 16); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16 + *(Bit32u*)(pos+12)=MOV_REG_ROR_REG(FC_RETOP, FC_RETOP, HOST_a2); // mov FC_RETOP, FC_RETOP, ror a2 + break; + case t_ROLd: + *(Bit32u*)pos=RSB_IMM(HOST_a2, HOST_a2, 32, 0); // rsb a2, a2, #32 + *(Bit32u*)(pos+4)=MOV_REG_ROR_REG(FC_RETOP, HOST_a1, HOST_a2); // mov FC_RETOP, a1, ror a2 + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit32u*)pos=RSB_IMM(FC_RETOP, HOST_a1, 0, 0); // rsb FC_RETOP, a1, #0 + *(Bit32u*)(pos+4)=NOP; // nop + *(Bit32u*)(pos+8)=NOP; // nop + *(Bit32u*)(pos+12)=NOP; // nop + break; + default: + *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func + break; + + } +#else + *(Bit32u*)(pos+12)=(Bit32u)fct_ptr; // simple_func +#endif +} +#endif + +static void cache_block_before_close(void) { } + +#ifdef DRC_USE_SEGS_ADDR + +// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldrh dest_reg, [FC_SEGS_ADDR, #index] +} + +// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) ); // ldr dest_reg, [FC_SEGS_ADDR, #index] +} + +// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { + cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) ); // ldr temp1, [FC_SEGS_ADDR, #index] + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) ); // add reg, reg, temp1 +} + +#endif + +#ifdef DRC_USE_REGS_ADDR + +// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] +} + +// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { + cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { + if (dword) { + cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldr dest_reg, [FC_REGS_ADDR, #index] + } else { + cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrh dest_reg, [FC_REGS_ADDR, #index] + } +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { + cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { + cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) ); // ldrb dest_reg, [FC_REGS_ADDR, #index] +} + + +// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { + cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) ); // ldr temp2, [FC_REGS_ADDR, #index] + cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) ); // add reg, reg, temp2 +} + + +// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) +static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { + cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] +} + +// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { + cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { + if (dword) { + cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) ); // str src_reg, [FC_REGS_ADDR, #index] + } else { + cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) ); // strh src_reg, [FC_REGS_ADDR, #index] + } +} + +// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR +static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { + cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) ); // strb src_reg, [FC_REGS_ADDR, #index] +} + +#endif diff --git a/src/cpu/core_dynrec/risc_armv4le-thumb-iw.h b/src/cpu/core_dynrec/risc_armv4le-thumb-iw.h index af279bd..d6b8d46 100644 --- a/src/cpu/core_dynrec/risc_armv4le-thumb-iw.h +++ b/src/cpu/core_dynrec/risc_armv4le-thumb-iw.h @@ -1,1298 +1,1298 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le-thumb-iw.h,v 1.5 2009/06/27 12:51:10 c2woody Exp $ */ - - -/* ARMv4 (little endian) backend by M-HT (thumb version with data pool, requires -mthumb-interwork switch when compiling dosbox) */ - - -// temporary "lo" registers -#define templo1 HOST_v3 -#define templo2 HOST_v4 -#define templo3 HOST_v2 - -// register that holds function return values -#define FC_RETOP HOST_a1 - -// register used for address calculations, -#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG - -// register that holds the first parameter -#define FC_OP1 HOST_a1 - -// register that holds the second parameter -#define FC_OP2 HOST_a2 - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_a4 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_a1 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_a2 - -// temporary register for LEA -#define TEMP_REG_DRC HOST_a4 - -#ifdef DRC_USE_REGS_ADDR -// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code -#define FC_REGS_ADDR HOST_v7 -#endif - -#ifdef DRC_USE_SEGS_ADDR -// used to hold the address of "Segs" - preferably filled in function gen_run_code -#define FC_SEGS_ADDR HOST_v8 -#endif - - -// instruction encodings - -// move -// mov dst, #imm @ 0 <= imm <= 255 -#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) -// mov dst, src -#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) -// mov dst, src -#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) -// mov dst, src -#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) - -// arithmetic -// add dst, src, #imm @ 0 <= imm <= 7 -#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) -// add dst, #imm @ 0 <= imm <= 255 -#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) -// add dst, src1, src2 -#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) -// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 -#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) -// sub dst, src1, src2 -#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) -// sub dst, src, #imm @ 0 <= imm <= 7 -#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) -// sub dst, #imm @ 0 <= imm <= 255 -#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) -// neg dst, src -#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) -// cmp dst, #imm @ 0 <= imm <= 255 -#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) -// nop -#define NOP (0x46c0) - -// logical -// and dst, src -#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) -// eor dst, src -#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) -// orr dst, src -#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) - -// shift/rotate -// lsl dst, src, #imm -#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) -// lsl dst, reg -#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) -// lsr dst, src, #imm -#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) -// lsr dst, reg -#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) -// asr dst, src, #imm -#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) -// asr dst, reg -#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) -// ror dst, reg -#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) - -// load -// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 -#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) -// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 -#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) -// ldrb reg, [addr, #imm] @ 0 <= imm < 32 -#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) -// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 -#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) - -// store -// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 -#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) -// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 -#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) -// strb reg, [addr, #imm] @ 0 <= imm < 32 -#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) - -// branch -// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) -// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) -// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) -// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 -#define B_FWD(imm) (0xe000 + ((imm) >> 1) ) -// bx reg -#define BX(reg) (0x4700 + ((reg) << 3) ) - - -// data pool defines -#define CACHE_DATA_JUMP (2) -#define CACHE_DATA_ALIGN (32) -#define CACHE_DATA_MIN (32) -#define CACHE_DATA_MAX (288) - -// data pool variables -static Bit8u * cache_datapos = NULL; // position of data pool in the cache block -static Bit32u cache_datasize = 0; // total size of data pool -static Bit32u cache_dataindex = 0; // used size of data pool = index of free data item (in bytes) in data pool - - -// forwarded function -static void INLINE gen_create_branch_short(void * func); - -// function to check distance to data pool -// if too close, then generate jump after data pool -static void cache_checkinstr(Bit32u size) { - if (cache_datasize == 0) { - if (cache_datapos != NULL) { - if (cache.pos + size + CACHE_DATA_JUMP >= cache_datapos) { - cache_datapos = NULL; - } - } - return; - } - - if (cache.pos + size + CACHE_DATA_JUMP <= cache_datapos) return; - - { - register Bit8u * newcachepos; - - newcachepos = cache_datapos + cache_datasize; - gen_create_branch_short(newcachepos); - cache.pos = newcachepos; - } - - if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && - cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) - { - cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); - } else { - register Bit32u cachemodsize; - - cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); - - if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || - cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) - { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); - } else { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); - } - } - - cache_datasize = 0; - cache_dataindex = 0; -} - -// function to reserve item in data pool -// returns address of item -static Bit8u * cache_reservedata(void) { - // if data pool not yet initialized, then initialize data pool - if (GCC_UNLIKELY(cache_datapos == NULL)) { - if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN < cache.block.active->cache.start + CACHE_DATA_MAX) { - cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); - } - } - - // if data pool not yet used, then set data pool - if (cache_datasize == 0) { - // set data pool address is too close (or behind) cache.pos then set new data pool size - if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_JUMP /*+ CACHE_DATA_ALIGN*/ > cache_datapos) { - if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && - cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) - { - cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); - } else { - register Bit32u cachemodsize; - - cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); - - if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || - cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) - { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); - } else { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); - } - } - } - // set initial data pool size - cache_datasize = CACHE_DATA_ALIGN; - } - - // if data pool is full, then enlarge data pool - if (cache_dataindex == cache_datasize) { - cache_datasize += CACHE_DATA_ALIGN; - } - - cache_dataindex += 4; - return (cache_datapos + (cache_dataindex - 4)); -} - -static void cache_block_before_close(void) { - // if data pool in use, then resize cache block to include the data pool - if (cache_datasize != 0) - { - cache.pos = cache_datapos + cache_dataindex; - } - - // clear the values before next use - cache_datapos = NULL; - cache_datasize = 0; - cache_dataindex = 0; -} - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - if(reg_src == reg_dst) return; - cache_checkinstr(2); - cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - if ((imm & 0xffffff00) == 0) { - cache_checkinstr(2); - cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) - } else if ((imm & 0xffff00ff) == 0) { - cache_checkinstr(4); - cache_addw( MOV_IMM(dest_reg, imm >> 8) ); // mov dest_reg, #(imm >> 8) - cache_addw( LSL_IMM(dest_reg, dest_reg, 8) ); // lsl dest_reg, dest_reg, #8 - } else if ((imm & 0xff00ffff) == 0) { - cache_checkinstr(4); - cache_addw( MOV_IMM(dest_reg, imm >> 16) ); // mov dest_reg, #(imm >> 16) - cache_addw( LSL_IMM(dest_reg, dest_reg, 16) ); // lsl dest_reg, dest_reg, #16 - } else if ((imm & 0x00ffffff) == 0) { - cache_checkinstr(4); - cache_addw( MOV_IMM(dest_reg, imm >> 24) ); // mov dest_reg, #(imm >> 24) - cache_addw( LSL_IMM(dest_reg, dest_reg, 24) ); // lsl dest_reg, dest_reg, #24 - } else { - Bit32u diff; - - cache_checkinstr(4); - - diff = imm - ((Bit32u)cache.pos+4); - - if ((diff < 1024) && ((imm & 0x03) == 0)) { - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( ADD_LO_PC_IMM(dest_reg, diff >> 2) ); // add dest_reg, pc, #(diff >> 2) - } else { - cache_addw( NOP ); // nop - cache_addw( ADD_LO_PC_IMM(dest_reg, (diff - 2) >> 2) ); // add dest_reg, pc, #((diff - 2) >> 2) - } - } else { - Bit8u *datapos; - - datapos = cache_reservedata(); - *(Bit32u*)datapos=imm; - - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 4)) ); // ldr dest_reg, [pc, datapos] - } else { - cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 2)) ); // ldr dest_reg, [pc, datapos] - } - } - } -} - -// helper function for gen_mov_word_to_reg -static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)data & 3) { - if ( ((Bit32u)data & 3) == 2 ) { - cache_checkinstr(8); - cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] - cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } else { - cache_checkinstr(16); - cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 - cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] - cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } - } else { - cache_checkinstr(2); - cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] - } - } else { - if ((Bit32u)data & 1) { - cache_checkinstr(8); - cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } else { - cache_checkinstr(2); - cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - } - } -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); - gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); -} - -// helper function for gen_mov_word_from_reg -static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)dest & 3) { - if ( ((Bit32u)dest & 3) == 2 ) { - cache_checkinstr(8); - cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 - cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] - } else { - cache_checkinstr(20); - cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 - cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 - cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 - cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] - } - } else { - cache_checkinstr(2); - cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] - } - } else { - if ((Bit32u)dest & 1) { - cache_checkinstr(8); - cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 - cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] - } else { - cache_checkinstr(2); - cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - } - } -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); - cache_checkinstr(2); - cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - gen_mov_byte_to_reg_low(dest_reg, data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_checkinstr(2); - cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(dest_reg, imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); - cache_checkinstr(2); - cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - cache_checkinstr(4); - cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 - - if (sign) { - cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 - } else { - cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 - } -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - cache_checkinstr(4); - cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 - - if (sign) { - cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 - } else { - cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 - } -} - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - gen_mov_word_to_reg(templo3, op, 1); - cache_checkinstr(2); - cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo1, imm); - cache_checkinstr(2); - cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - if(imm == 0xffffffff) return; - gen_mov_dword_to_reg_imm(templo1, imm); - cache_checkinstr(2); - cache_addw( AND(reg, templo1) ); // and reg, templo1 -} - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - gen_mov_dword_to_reg_imm(templo3, imm); - gen_mov_word_from_reg(templo3, dest, 1); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - -// add an 8bit constant value to a dword memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); - cache_checkinstr(2); - if (imm >= 0) { - cache_addw( ADD_IMM8(templo3, (Bit32s)imm) ); // add templo3, #(imm) - } else { - cache_addw( SUB_IMM8(templo3, -((Bit32s)imm)) ); // sub templo3, #(-imm) - } - gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); - if (dword) { - gen_mov_dword_to_reg_imm(templo1, imm); - } else { - gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); - } - cache_checkinstr(2); - cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 - gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); -} - -// subtract an 8bit constant value from a dword memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); - cache_checkinstr(2); - if (imm >= 0) { - cache_addw( SUB_IMM8(templo3, (Bit32s)imm) ); // sub templo3, #(imm) - } else { - cache_addw( ADD_IMM8(templo3, -((Bit32s)imm)) ); // add templo3, #(-imm) - } - gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); - if (dword) { - gen_mov_dword_to_reg_imm(templo1, imm); - } else { - gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); - } - cache_checkinstr(2); - cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 - gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); -} - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - if (scale) { - cache_checkinstr(4); - cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) - cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 - } else { - cache_checkinstr(2); - cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg - } - gen_add_imm(dest_reg, imm); -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - if (scale) { - cache_checkinstr(2); - cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) - } - gen_add_imm(dest_reg, imm); -} - -// helper function for gen_call_function_raw and gen_call_function_setup -static void gen_call_function_helper(void * func) { - Bit8u *datapos; - - datapos = cache_reservedata(); - *(Bit32u*)datapos=(Bit32u)func; - - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] - cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) - cache_addw( ADD_IMM8(templo2, 1) ); // add templo2, #1 - cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 - cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state - cache_addw( NOP ); // nop - } else { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] - cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4) - cache_addw( ADD_IMM8(templo2, 1) ); // add templo2, #1 - cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 - cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state - } - // after_call: - - // thumb state from now on -} - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - cache_checkinstr(12); - gen_call_function_helper(func); -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - cache_checkinstr(12); - Bit32u proc_addr = (Bit32u)cache.pos; - gen_call_function_helper(func); - return proc_addr; - // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) - // then length of generated code is 12 bytes - // otherwise length of generated code is 10 bytes -} - -#if (1) -// max of 4 parameters in a1-a4 - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - gen_mov_dword_to_reg_imm(param, imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - gen_mov_dword_to_reg_imm(param, addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - gen_mov_regs(param, reg); -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - gen_mov_word_to_reg(param, (void *)mem, 1); -} -#else - other arm abis -#endif - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - gen_mov_word_to_reg(templo3, ptr, 1); - - if (imm) { - gen_mov_dword_to_reg_imm(templo2, imm); - cache_checkinstr(2); - cache_addw( ADD_REG(templo3, templo3, templo2) ); // add templo3, templo3, templo2 - } - -#if (1) -// (*ptr) should be word aligned - if ((imm & 0x03) == 0) { - cache_checkinstr(6); - cache_addw( LDR_IMM(templo2, templo3, 0) ); // ldr templo2, [templo3] - } else -#endif - { - cache_checkinstr(24); - cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] - cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] - cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] - cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - } - - // increase jmp address to keep thumb state - cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 - - cache_addw( BX(templo2) ); // bx templo2 -} - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { - cache_checkinstr(4); - if (dword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 - } - cache_addw( BEQ_FWD(0) ); // beq j - return ((Bit32u)cache.pos-2); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - cache_checkinstr(4); - if (dword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 - } - cache_addw( BNE_FWD(0) ); // bne j - return ((Bit32u)cache.pos-2); -} - -// calculate relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-(data+4); - if (len<0) len=-len; - if (len>252) LOG_MSG("Big jump %d",len); -#endif - *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); -} - - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - Bit8u *datapos; - - cache_checkinstr(8); - datapos = cache_reservedata(); - - if (isdword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 - } - cache_addw( BEQ_FWD(2) ); // beq nobranch (pc+2) - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] - } else { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] - } - cache_addw( BX(templo1) ); // bx templo1 - // nobranch: - return ((Bit32u)datapos); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u gen_create_branch_long_leqzero(HostReg reg) { - Bit8u *datapos; - - cache_checkinstr(8); - datapos = cache_reservedata(); - - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - cache_addw( BGT_FWD(2) ); // bgt nobranch (pc+2) - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] - } else { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] - } - cache_addw( BX(templo1) ); // bx templo1 - // nobranch: - return ((Bit32u)datapos); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - // this is an absolute branch - *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state -} - -static void gen_run_code(void) { - // switch from arm to thumb state - cache_addd(0xe2800000 + (HOST_r3 << 12) + (HOST_pc << 16) + (1)); // add r3, pc, #1 - cache_addd(0xe12fff10 + (HOST_r3)); // bx r3 - - // thumb state from now on - cache_addw(0xb500); // push {lr} - cache_addw( MOV_LO_HI(HOST_r3, FC_SEGS_ADDR) ); // mov r3, FC_SEGS_ADDR - cache_addw( MOV_LO_HI(HOST_r2, FC_REGS_ADDR) ); // mov r2, FC_REGS_ADDR - cache_addw(0xb4fc); // push {r2,r3,v1-v4} - - // adr: 16 - cache_addw( LDR_PC_IMM(HOST_r3, 64 - (16 + 4)) ); // ldr r3, [pc, #(&Segs)] - // adr: 18 - cache_addw( LDR_PC_IMM(HOST_r2, 68 - (18 + 2)) ); // ldr r2, [pc, #(&cpu_regs)] - cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 - cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 - - // align 4 - cache_addw( ADD_LO_PC_IMM(HOST_r3, 8) ); // add r3, pc, #8 - cache_addw( ADD_IMM8(HOST_r0, 1) ); // add r0, #1 - cache_addw( ADD_IMM8(HOST_r3, 1) ); // add r3, #1 - cache_addw(0xb408); // push {r3} - cache_addw( BX(HOST_r0) ); // bx r0 - cache_addw( NOP ); // nop - - // align 4 - cache_addw(0xbcfc); // pop {r2,r3,v1-v4} - cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 - cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 - - cache_addw(0xbc08); // pop {r3} - cache_addw( BX(HOST_r3) ); // bx r3 - - // fill up to 64 bytes - cache_addw( NOP ); // nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - - // adr: 64 - cache_addd((Bit32u)&Segs); // address of "Segs" - // adr: 68 - cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" -} - -// return from a function -static void gen_return_function(void) { - cache_checkinstr(4); - cache_addw(0xbc08); // pop {r3} - cache_addw( BX(HOST_r3) ); // bx r3 -} - - -// short unconditional jump (over data pool) -// must emit at most CACHE_DATA_JUMP bytes -static void INLINE gen_create_branch_short(void * func) { - cache_addw( B_FWD((Bit32u)func - ((Bit32u)cache.pos + 4)) ); // b func -} - - -#ifdef DRC_FLAGS_INVALIDATION - -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { - if ((*(Bit16u*)pos & 0xf000) == 0xe000) { - if ((*(Bit16u*)pos & 0x0fff) >= ((CACHE_DATA_ALIGN / 2) - 1) && - (*(Bit16u*)pos & 0x0fff) < 0x0800) - { - pos = (Bit8u *) ( ( ( (Bit32u)(*(Bit16u*)pos & 0x0fff) ) << 1 ) + ((Bit32u)pos + 4) ); - } - } - -#ifdef DRC_FLAGS_INVALIDATION_DCODE - if (((Bit32u)pos & 0x03) == 0) - { - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit16u*)pos=B_FWD(8); // b after_call (pc+8) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_SHRb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+10)=NOP; // nop - break; - case t_SHRw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+10)=NOP; // nop - break; - case t_SHRd: - *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_SARb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+10)=NOP; // nop - break; - case t_SARw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+10)=NOP; // nop - break; - case t_SARd: - *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_RORb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_RORw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+4)=NOP; // nop - *(Bit16u*)(pos+6)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+8)=NOP; // nop - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_RORd: - *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - case t_ROLw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_ROLd: - *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+10)=NOP; // nop - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 - *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) - break; - default: - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func - break; - } - } - else - { - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit16u*)pos=B_FWD(6); // b after_call (pc+6) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_SHRb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - break; - case t_SHRw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - break; - case t_SHRd: - *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_SARb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - break; - case t_SARw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - break; - case t_SARd: - *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_RORw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+4)=NOP; // nop - *(Bit16u*)(pos+6)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_RORd: - *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - case t_ROLd: - *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+2)=NOP; // nop - *(Bit16u*)(pos+4)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 - *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) - break; - default: - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func - break; - } - - } -#else - if (((Bit32u)pos & 0x03) == 0) - { - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func - } - else - { - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func - } -#endif -} -#endif - -#ifdef DRC_USE_SEGS_ADDR - -// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] -} - -// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] -} - -// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { - cache_checkinstr(6); - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] - cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 -} - -#endif - -#ifdef DRC_USE_REGS_ADDR - -// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] -} - -// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - if (dword) { - cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] - } else { - cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] - } -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] -} - - -// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { - cache_checkinstr(6); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] - cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 -} - - -// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) -static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] -} - -// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - if (dword) { - cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] - } else { - cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] - } -} - -// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR -static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] -} - -#endif +/* + * Copyright (C) 2002-2010 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: risc_armv4le-thumb-iw.h,v 1.5 2009-06-27 12:51:10 c2woody Exp $ */ + + +/* ARMv4 (little endian) backend by M-HT (thumb version with data pool, requires -mthumb-interwork switch when compiling dosbox) */ + + +// temporary "lo" registers +#define templo1 HOST_v3 +#define templo2 HOST_v4 +#define templo3 HOST_v2 + +// register that holds function return values +#define FC_RETOP HOST_a1 + +// register used for address calculations, +#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG + +// register that holds the first parameter +#define FC_OP1 HOST_a1 + +// register that holds the second parameter +#define FC_OP2 HOST_a2 + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_a4 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_a1 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_a2 + +// temporary register for LEA +#define TEMP_REG_DRC HOST_a4 + +#ifdef DRC_USE_REGS_ADDR +// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code +#define FC_REGS_ADDR HOST_v7 +#endif + +#ifdef DRC_USE_SEGS_ADDR +// used to hold the address of "Segs" - preferably filled in function gen_run_code +#define FC_SEGS_ADDR HOST_v8 +#endif + + +// instruction encodings + +// move +// mov dst, #imm @ 0 <= imm <= 255 +#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) +// mov dst, src +#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) +// mov dst, src +#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) +// mov dst, src +#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) + +// arithmetic +// add dst, src, #imm @ 0 <= imm <= 7 +#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) +// add dst, #imm @ 0 <= imm <= 255 +#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) +// add dst, src1, src2 +#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) +// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 +#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) +// sub dst, src1, src2 +#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) +// sub dst, src, #imm @ 0 <= imm <= 7 +#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) +// sub dst, #imm @ 0 <= imm <= 255 +#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) +// neg dst, src +#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) +// cmp dst, #imm @ 0 <= imm <= 255 +#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) +// nop +#define NOP (0x46c0) + +// logical +// and dst, src +#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) +// eor dst, src +#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) +// orr dst, src +#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) + +// shift/rotate +// lsl dst, src, #imm +#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) +// lsl dst, reg +#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) +// lsr dst, src, #imm +#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) +// lsr dst, reg +#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) +// asr dst, src, #imm +#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) +// asr dst, reg +#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) +// ror dst, reg +#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) + +// load +// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 +#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) +// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 +#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) +// ldrb reg, [addr, #imm] @ 0 <= imm < 32 +#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) +// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 +#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) + +// store +// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 +#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) +// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 +#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) +// strb reg, [addr, #imm] @ 0 <= imm < 32 +#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) + +// branch +// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) +// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) +// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) +// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 +#define B_FWD(imm) (0xe000 + ((imm) >> 1) ) +// bx reg +#define BX(reg) (0x4700 + ((reg) << 3) ) + + +// data pool defines +#define CACHE_DATA_JUMP (2) +#define CACHE_DATA_ALIGN (32) +#define CACHE_DATA_MIN (32) +#define CACHE_DATA_MAX (288) + +// data pool variables +static Bit8u * cache_datapos = NULL; // position of data pool in the cache block +static Bit32u cache_datasize = 0; // total size of data pool +static Bit32u cache_dataindex = 0; // used size of data pool = index of free data item (in bytes) in data pool + + +// forwarded function +static void INLINE gen_create_branch_short(void * func); + +// function to check distance to data pool +// if too close, then generate jump after data pool +static void cache_checkinstr(Bit32u size) { + if (cache_datasize == 0) { + if (cache_datapos != NULL) { + if (cache.pos + size + CACHE_DATA_JUMP >= cache_datapos) { + cache_datapos = NULL; + } + } + return; + } + + if (cache.pos + size + CACHE_DATA_JUMP <= cache_datapos) return; + + { + register Bit8u * newcachepos; + + newcachepos = cache_datapos + cache_datasize; + gen_create_branch_short(newcachepos); + cache.pos = newcachepos; + } + + if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && + cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) + { + cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); + } else { + register Bit32u cachemodsize; + + cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); + + if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || + cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) + { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); + } else { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); + } + } + + cache_datasize = 0; + cache_dataindex = 0; +} + +// function to reserve item in data pool +// returns address of item +static Bit8u * cache_reservedata(void) { + // if data pool not yet initialized, then initialize data pool + if (GCC_UNLIKELY(cache_datapos == NULL)) { + if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN < cache.block.active->cache.start + CACHE_DATA_MAX) { + cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); + } + } + + // if data pool not yet used, then set data pool + if (cache_datasize == 0) { + // set data pool address is too close (or behind) cache.pos then set new data pool size + if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_JUMP /*+ CACHE_DATA_ALIGN*/ > cache_datapos) { + if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && + cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) + { + cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); + } else { + register Bit32u cachemodsize; + + cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); + + if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || + cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) + { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); + } else { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); + } + } + } + // set initial data pool size + cache_datasize = CACHE_DATA_ALIGN; + } + + // if data pool is full, then enlarge data pool + if (cache_dataindex == cache_datasize) { + cache_datasize += CACHE_DATA_ALIGN; + } + + cache_dataindex += 4; + return (cache_datapos + (cache_dataindex - 4)); +} + +static void cache_block_before_close(void) { + // if data pool in use, then resize cache block to include the data pool + if (cache_datasize != 0) + { + cache.pos = cache_datapos + cache_dataindex; + } + + // clear the values before next use + cache_datapos = NULL; + cache_datasize = 0; + cache_dataindex = 0; +} + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + if(reg_src == reg_dst) return; + cache_checkinstr(2); + cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + if ((imm & 0xffffff00) == 0) { + cache_checkinstr(2); + cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) + } else if ((imm & 0xffff00ff) == 0) { + cache_checkinstr(4); + cache_addw( MOV_IMM(dest_reg, imm >> 8) ); // mov dest_reg, #(imm >> 8) + cache_addw( LSL_IMM(dest_reg, dest_reg, 8) ); // lsl dest_reg, dest_reg, #8 + } else if ((imm & 0xff00ffff) == 0) { + cache_checkinstr(4); + cache_addw( MOV_IMM(dest_reg, imm >> 16) ); // mov dest_reg, #(imm >> 16) + cache_addw( LSL_IMM(dest_reg, dest_reg, 16) ); // lsl dest_reg, dest_reg, #16 + } else if ((imm & 0x00ffffff) == 0) { + cache_checkinstr(4); + cache_addw( MOV_IMM(dest_reg, imm >> 24) ); // mov dest_reg, #(imm >> 24) + cache_addw( LSL_IMM(dest_reg, dest_reg, 24) ); // lsl dest_reg, dest_reg, #24 + } else { + Bit32u diff; + + cache_checkinstr(4); + + diff = imm - ((Bit32u)cache.pos+4); + + if ((diff < 1024) && ((imm & 0x03) == 0)) { + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( ADD_LO_PC_IMM(dest_reg, diff >> 2) ); // add dest_reg, pc, #(diff >> 2) + } else { + cache_addw( NOP ); // nop + cache_addw( ADD_LO_PC_IMM(dest_reg, (diff - 2) >> 2) ); // add dest_reg, pc, #((diff - 2) >> 2) + } + } else { + Bit8u *datapos; + + datapos = cache_reservedata(); + *(Bit32u*)datapos=imm; + + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 4)) ); // ldr dest_reg, [pc, datapos] + } else { + cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 2)) ); // ldr dest_reg, [pc, datapos] + } + } + } +} + +// helper function for gen_mov_word_to_reg +static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)data & 3) { + if ( ((Bit32u)data & 3) == 2 ) { + cache_checkinstr(8); + cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] + cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } else { + cache_checkinstr(16); + cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 + cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] + cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } + } else { + cache_checkinstr(2); + cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] + } + } else { + if ((Bit32u)data & 1) { + cache_checkinstr(8); + cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } else { + cache_checkinstr(2); + cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + } + } +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); + gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); +} + +// helper function for gen_mov_word_from_reg +static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)dest & 3) { + if ( ((Bit32u)dest & 3) == 2 ) { + cache_checkinstr(8); + cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 + cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] + } else { + cache_checkinstr(20); + cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 + cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 + cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 + cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] + } + } else { + cache_checkinstr(2); + cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] + } + } else { + if ((Bit32u)dest & 1) { + cache_checkinstr(8); + cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 + cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] + } else { + cache_checkinstr(2); + cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + } + } +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); + cache_checkinstr(2); + cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + gen_mov_byte_to_reg_low(dest_reg, data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_checkinstr(2); + cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(dest_reg, imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); + cache_checkinstr(2); + cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + cache_checkinstr(4); + cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 + + if (sign) { + cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 + } else { + cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 + } +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + cache_checkinstr(4); + cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 + + if (sign) { + cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 + } else { + cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 + } +} + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + gen_mov_word_to_reg(templo3, op, 1); + cache_checkinstr(2); + cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo1, imm); + cache_checkinstr(2); + cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + if(imm == 0xffffffff) return; + gen_mov_dword_to_reg_imm(templo1, imm); + cache_checkinstr(2); + cache_addw( AND(reg, templo1) ); // and reg, templo1 +} + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + gen_mov_dword_to_reg_imm(templo3, imm); + gen_mov_word_from_reg(templo3, dest, 1); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + +// add an 8bit constant value to a dword memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); + cache_checkinstr(2); + if (imm >= 0) { + cache_addw( ADD_IMM8(templo3, (Bit32s)imm) ); // add templo3, #(imm) + } else { + cache_addw( SUB_IMM8(templo3, -((Bit32s)imm)) ); // sub templo3, #(-imm) + } + gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); + if (dword) { + gen_mov_dword_to_reg_imm(templo1, imm); + } else { + gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); + } + cache_checkinstr(2); + cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 + gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); +} + +// subtract an 8bit constant value from a dword memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); + cache_checkinstr(2); + if (imm >= 0) { + cache_addw( SUB_IMM8(templo3, (Bit32s)imm) ); // sub templo3, #(imm) + } else { + cache_addw( ADD_IMM8(templo3, -((Bit32s)imm)) ); // add templo3, #(-imm) + } + gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); + if (dword) { + gen_mov_dword_to_reg_imm(templo1, imm); + } else { + gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); + } + cache_checkinstr(2); + cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 + gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); +} + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + if (scale) { + cache_checkinstr(4); + cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) + cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 + } else { + cache_checkinstr(2); + cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg + } + gen_add_imm(dest_reg, imm); +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + if (scale) { + cache_checkinstr(2); + cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) + } + gen_add_imm(dest_reg, imm); +} + +// helper function for gen_call_function_raw and gen_call_function_setup +static void gen_call_function_helper(void * func) { + Bit8u *datapos; + + datapos = cache_reservedata(); + *(Bit32u*)datapos=(Bit32u)func; + + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] + cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) + cache_addw( ADD_IMM8(templo2, 1) ); // add templo2, #1 + cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 + cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state + cache_addw( NOP ); // nop + } else { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] + cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4) + cache_addw( ADD_IMM8(templo2, 1) ); // add templo2, #1 + cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 + cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state + } + // after_call: + + // thumb state from now on +} + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + cache_checkinstr(12); + gen_call_function_helper(func); +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + cache_checkinstr(12); + Bit32u proc_addr = (Bit32u)cache.pos; + gen_call_function_helper(func); + return proc_addr; + // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) + // then length of generated code is 12 bytes + // otherwise length of generated code is 10 bytes +} + +#if (1) +// max of 4 parameters in a1-a4 + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + gen_mov_dword_to_reg_imm(param, imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + gen_mov_dword_to_reg_imm(param, addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + gen_mov_regs(param, reg); +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + gen_mov_word_to_reg(param, (void *)mem, 1); +} +#else + other arm abis +#endif + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + gen_mov_word_to_reg(templo3, ptr, 1); + + if (imm) { + gen_mov_dword_to_reg_imm(templo2, imm); + cache_checkinstr(2); + cache_addw( ADD_REG(templo3, templo3, templo2) ); // add templo3, templo3, templo2 + } + +#if (1) +// (*ptr) should be word aligned + if ((imm & 0x03) == 0) { + cache_checkinstr(6); + cache_addw( LDR_IMM(templo2, templo3, 0) ); // ldr templo2, [templo3] + } else +#endif + { + cache_checkinstr(24); + cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] + cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] + cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] + cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + } + + // increase jmp address to keep thumb state + cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 + + cache_addw( BX(templo2) ); // bx templo2 +} + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { + cache_checkinstr(4); + if (dword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 + } + cache_addw( BEQ_FWD(0) ); // beq j + return ((Bit32u)cache.pos-2); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + cache_checkinstr(4); + if (dword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 + } + cache_addw( BNE_FWD(0) ); // bne j + return ((Bit32u)cache.pos-2); +} + +// calculate relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-(data+4); + if (len<0) len=-len; + if (len>252) LOG_MSG("Big jump %d",len); +#endif + *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); +} + + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + Bit8u *datapos; + + cache_checkinstr(8); + datapos = cache_reservedata(); + + if (isdword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 + } + cache_addw( BEQ_FWD(2) ); // beq nobranch (pc+2) + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] + } else { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] + } + cache_addw( BX(templo1) ); // bx templo1 + // nobranch: + return ((Bit32u)datapos); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u gen_create_branch_long_leqzero(HostReg reg) { + Bit8u *datapos; + + cache_checkinstr(8); + datapos = cache_reservedata(); + + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + cache_addw( BGT_FWD(2) ); // bgt nobranch (pc+2) + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] + } else { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] + } + cache_addw( BX(templo1) ); // bx templo1 + // nobranch: + return ((Bit32u)datapos); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + // this is an absolute branch + *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state +} + +static void gen_run_code(void) { + // switch from arm to thumb state + cache_addd(0xe2800000 + (HOST_r3 << 12) + (HOST_pc << 16) + (1)); // add r3, pc, #1 + cache_addd(0xe12fff10 + (HOST_r3)); // bx r3 + + // thumb state from now on + cache_addw(0xb500); // push {lr} + cache_addw( MOV_LO_HI(HOST_r3, FC_SEGS_ADDR) ); // mov r3, FC_SEGS_ADDR + cache_addw( MOV_LO_HI(HOST_r2, FC_REGS_ADDR) ); // mov r2, FC_REGS_ADDR + cache_addw(0xb4fc); // push {r2,r3,v1-v4} + + // adr: 16 + cache_addw( LDR_PC_IMM(HOST_r3, 64 - (16 + 4)) ); // ldr r3, [pc, #(&Segs)] + // adr: 18 + cache_addw( LDR_PC_IMM(HOST_r2, 68 - (18 + 2)) ); // ldr r2, [pc, #(&cpu_regs)] + cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 + cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 + + // align 4 + cache_addw( ADD_LO_PC_IMM(HOST_r3, 8) ); // add r3, pc, #8 + cache_addw( ADD_IMM8(HOST_r0, 1) ); // add r0, #1 + cache_addw( ADD_IMM8(HOST_r3, 1) ); // add r3, #1 + cache_addw(0xb408); // push {r3} + cache_addw( BX(HOST_r0) ); // bx r0 + cache_addw( NOP ); // nop + + // align 4 + cache_addw(0xbcfc); // pop {r2,r3,v1-v4} + cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 + cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 + + cache_addw(0xbc08); // pop {r3} + cache_addw( BX(HOST_r3) ); // bx r3 + + // fill up to 64 bytes + cache_addw( NOP ); // nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + + // adr: 64 + cache_addd((Bit32u)&Segs); // address of "Segs" + // adr: 68 + cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" +} + +// return from a function +static void gen_return_function(void) { + cache_checkinstr(4); + cache_addw(0xbc08); // pop {r3} + cache_addw( BX(HOST_r3) ); // bx r3 +} + + +// short unconditional jump (over data pool) +// must emit at most CACHE_DATA_JUMP bytes +static void INLINE gen_create_branch_short(void * func) { + cache_addw( B_FWD((Bit32u)func - ((Bit32u)cache.pos + 4)) ); // b func +} + + +#ifdef DRC_FLAGS_INVALIDATION + +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { + if ((*(Bit16u*)pos & 0xf000) == 0xe000) { + if ((*(Bit16u*)pos & 0x0fff) >= ((CACHE_DATA_ALIGN / 2) - 1) && + (*(Bit16u*)pos & 0x0fff) < 0x0800) + { + pos = (Bit8u *) ( ( ( (Bit32u)(*(Bit16u*)pos & 0x0fff) ) << 1 ) + ((Bit32u)pos + 4) ); + } + } + +#ifdef DRC_FLAGS_INVALIDATION_DCODE + if (((Bit32u)pos & 0x03) == 0) + { + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit16u*)pos=B_FWD(8); // b after_call (pc+8) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_SHRb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+10)=NOP; // nop + break; + case t_SHRw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+10)=NOP; // nop + break; + case t_SHRd: + *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_SARb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+10)=NOP; // nop + break; + case t_SARw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+10)=NOP; // nop + break; + case t_SARd: + *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_RORb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_RORw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+4)=NOP; // nop + *(Bit16u*)(pos+6)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+8)=NOP; // nop + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_RORd: + *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + case t_ROLw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_ROLd: + *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+10)=NOP; // nop + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 + *(Bit16u*)(pos+2)=B_FWD(6); // b after_call (pc+6) + break; + default: + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func + break; + } + } + else + { + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit16u*)pos=B_FWD(6); // b after_call (pc+6) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_SHRb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + break; + case t_SHRw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + break; + case t_SHRd: + *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_SARb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + break; + case t_SARw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + break; + case t_SARd: + *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_RORw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+4)=NOP; // nop + *(Bit16u*)(pos+6)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_RORd: + *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + case t_ROLd: + *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+2)=NOP; // nop + *(Bit16u*)(pos+4)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 + *(Bit16u*)(pos+2)=B_FWD(4); // b after_call (pc+4) + break; + default: + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func + break; + } + + } +#else + if (((Bit32u)pos & 0x03) == 0) + { + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func + } + else + { + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func + } +#endif +} +#endif + +#ifdef DRC_USE_SEGS_ADDR + +// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] +} + +// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] +} + +// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { + cache_checkinstr(6); + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] + cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 +} + +#endif + +#ifdef DRC_USE_REGS_ADDR + +// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] +} + +// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + if (dword) { + cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] + } else { + cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] + } +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] +} + + +// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { + cache_checkinstr(6); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] + cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 +} + + +// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) +static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] +} + +// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + if (dword) { + cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] + } else { + cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] + } +} + +// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR +static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] +} + +#endif diff --git a/src/cpu/core_dynrec/risc_armv4le-thumb-niw.h b/src/cpu/core_dynrec/risc_armv4le-thumb-niw.h index ead84ef..3ca6147 100644 --- a/src/cpu/core_dynrec/risc_armv4le-thumb-niw.h +++ b/src/cpu/core_dynrec/risc_armv4le-thumb-niw.h @@ -1,1331 +1,1331 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le-thumb-niw.h,v 1.5 2009/06/27 12:51:10 c2woody Exp $ */ - - -/* ARMv4 (little endian) backend by M-HT (thumb version with data pool) */ - - -// temporary "lo" registers -#define templo1 HOST_v3 -#define templo2 HOST_v4 -#define templo3 HOST_v2 - -// register that holds function return values -#define FC_RETOP HOST_a1 - -// register used for address calculations, -#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG - -// register that holds the first parameter -#define FC_OP1 HOST_a1 - -// register that holds the second parameter -#define FC_OP2 HOST_a2 - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_a4 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_a1 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_a2 - -// temporary register for LEA -#define TEMP_REG_DRC HOST_a4 - -#ifdef DRC_USE_REGS_ADDR -// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code -#define FC_REGS_ADDR HOST_v7 -#endif - -#ifdef DRC_USE_SEGS_ADDR -// used to hold the address of "Segs" - preferably filled in function gen_run_code -#define FC_SEGS_ADDR HOST_v8 -#endif - - -// instruction encodings - -// move -// mov dst, #imm @ 0 <= imm <= 255 -#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) -// mov dst, src -#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) -// mov dst, src -#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) -// mov dst, src -#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) - -// arithmetic -// add dst, src, #imm @ 0 <= imm <= 7 -#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) -// add dst, #imm @ 0 <= imm <= 255 -#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) -// add dst, src1, src2 -#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) -// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 -#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) -// sub dst, src1, src2 -#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) -// sub dst, src, #imm @ 0 <= imm <= 7 -#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) -// sub dst, #imm @ 0 <= imm <= 255 -#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) -// neg dst, src -#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) -// cmp dst, #imm @ 0 <= imm <= 255 -#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) -// nop -#define NOP (0x46c0) - -// logical -// and dst, src -#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) -// eor dst, src -#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) -// orr dst, src -#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) - -// shift/rotate -// lsl dst, src, #imm -#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) -// lsl dst, reg -#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) -// lsr dst, src, #imm -#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) -// lsr dst, reg -#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) -// asr dst, src, #imm -#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) -// asr dst, reg -#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) -// ror dst, reg -#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) - -// load -// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 -#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) -// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 -#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) -// ldrb reg, [addr, #imm] @ 0 <= imm < 32 -#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) -// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 -#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) - -// store -// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 -#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) -// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 -#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) -// strb reg, [addr, #imm] @ 0 <= imm < 32 -#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) - -// branch -// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) -// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) -// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) -// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 -#define B_FWD(imm) (0xe000 + ((imm) >> 1) ) -// bx reg -#define BX(reg) (0x4700 + ((reg) << 3) ) - - -// data pool defines -#define CACHE_DATA_JUMP (2) -#define CACHE_DATA_ALIGN (32) -#define CACHE_DATA_MIN (32) -#define CACHE_DATA_MAX (288) - -// data pool variables -static Bit8u * cache_datapos = NULL; // position of data pool in the cache block -static Bit32u cache_datasize = 0; // total size of data pool -static Bit32u cache_dataindex = 0; // used size of data pool = index of free data item (in bytes) in data pool - - -// forwarded function -static void INLINE gen_create_branch_short(void * func); - -// function to check distance to data pool -// if too close, then generate jump after data pool -static void cache_checkinstr(Bit32u size) { - if (cache_datasize == 0) { - if (cache_datapos != NULL) { - if (cache.pos + size + CACHE_DATA_JUMP >= cache_datapos) { - cache_datapos = NULL; - } - } - return; - } - - if (cache.pos + size + CACHE_DATA_JUMP <= cache_datapos) return; - - { - register Bit8u * newcachepos; - - newcachepos = cache_datapos + cache_datasize; - gen_create_branch_short(newcachepos); - cache.pos = newcachepos; - } - - if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && - cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) - { - cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); - } else { - register Bit32u cachemodsize; - - cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); - - if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || - cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) - { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); - } else { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); - } - } - - cache_datasize = 0; - cache_dataindex = 0; -} - -// function to reserve item in data pool -// returns address of item -static Bit8u * cache_reservedata(void) { - // if data pool not yet initialized, then initialize data pool - if (GCC_UNLIKELY(cache_datapos == NULL)) { - if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN < cache.block.active->cache.start + CACHE_DATA_MAX) { - cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); - } - } - - // if data pool not yet used, then set data pool - if (cache_datasize == 0) { - // set data pool address is too close (or behind) cache.pos then set new data pool size - if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_JUMP /*+ CACHE_DATA_ALIGN*/ > cache_datapos) { - if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && - cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) - { - cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); - } else { - register Bit32u cachemodsize; - - cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); - - if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || - cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) - { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); - } else { - cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); - } - } - } - // set initial data pool size - cache_datasize = CACHE_DATA_ALIGN; - } - - // if data pool is full, then enlarge data pool - if (cache_dataindex == cache_datasize) { - cache_datasize += CACHE_DATA_ALIGN; - } - - cache_dataindex += 4; - return (cache_datapos + (cache_dataindex - 4)); -} - -static void cache_block_before_close(void) { - // if data pool in use, then resize cache block to include the data pool - if (cache_datasize != 0) - { - cache.pos = cache_datapos + cache_dataindex; - } - - // clear the values before next use - cache_datapos = NULL; - cache_datasize = 0; - cache_dataindex = 0; -} - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - if(reg_src == reg_dst) return; - cache_checkinstr(2); - cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - if ((imm & 0xffffff00) == 0) { - cache_checkinstr(2); - cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) - } else if ((imm & 0xffff00ff) == 0) { - cache_checkinstr(4); - cache_addw( MOV_IMM(dest_reg, imm >> 8) ); // mov dest_reg, #(imm >> 8) - cache_addw( LSL_IMM(dest_reg, dest_reg, 8) ); // lsl dest_reg, dest_reg, #8 - } else if ((imm & 0xff00ffff) == 0) { - cache_checkinstr(4); - cache_addw( MOV_IMM(dest_reg, imm >> 16) ); // mov dest_reg, #(imm >> 16) - cache_addw( LSL_IMM(dest_reg, dest_reg, 16) ); // lsl dest_reg, dest_reg, #16 - } else if ((imm & 0x00ffffff) == 0) { - cache_checkinstr(4); - cache_addw( MOV_IMM(dest_reg, imm >> 24) ); // mov dest_reg, #(imm >> 24) - cache_addw( LSL_IMM(dest_reg, dest_reg, 24) ); // lsl dest_reg, dest_reg, #24 - } else { - Bit32u diff; - - cache_checkinstr(4); - - diff = imm - ((Bit32u)cache.pos+4); - - if ((diff < 1024) && ((imm & 0x03) == 0)) { - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( ADD_LO_PC_IMM(dest_reg, diff >> 2) ); // add dest_reg, pc, #(diff >> 2) - } else { - cache_addw( NOP ); // nop - cache_addw( ADD_LO_PC_IMM(dest_reg, (diff - 2) >> 2) ); // add dest_reg, pc, #((diff - 2) >> 2) - } - } else { - Bit8u *datapos; - - datapos = cache_reservedata(); - *(Bit32u*)datapos=imm; - - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 4)) ); // ldr dest_reg, [pc, datapos] - } else { - cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 2)) ); // ldr dest_reg, [pc, datapos] - } - } - } -} - -// helper function for gen_mov_word_to_reg -static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)data & 3) { - if ( ((Bit32u)data & 3) == 2 ) { - cache_checkinstr(8); - cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] - cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } else { - cache_checkinstr(16); - cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 - cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] - cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } - } else { - cache_checkinstr(2); - cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] - } - } else { - if ((Bit32u)data & 1) { - cache_checkinstr(8); - cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } else { - cache_checkinstr(2); - cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - } - } -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); - gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); -} - -// helper function for gen_mov_word_from_reg -static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)dest & 3) { - if ( ((Bit32u)dest & 3) == 2 ) { - cache_checkinstr(8); - cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 - cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] - } else { - cache_checkinstr(20); - cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 - cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 - cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 - cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] - } - } else { - cache_checkinstr(2); - cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] - } - } else { - if ((Bit32u)dest & 1) { - cache_checkinstr(8); - cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 - cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] - } else { - cache_checkinstr(2); - cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - } - } -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); - cache_checkinstr(2); - cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - gen_mov_byte_to_reg_low(dest_reg, data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_checkinstr(2); - cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(dest_reg, imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); - cache_checkinstr(2); - cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - cache_checkinstr(4); - cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 - - if (sign) { - cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 - } else { - cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 - } -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - cache_checkinstr(4); - cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 - - if (sign) { - cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 - } else { - cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 - } -} - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - gen_mov_word_to_reg(templo3, op, 1); - cache_checkinstr(2); - cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo1, imm); - cache_checkinstr(2); - cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - if(imm == 0xffffffff) return; - gen_mov_dword_to_reg_imm(templo1, imm); - cache_checkinstr(2); - cache_addw( AND(reg, templo1) ); // and reg, templo1 -} - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - gen_mov_dword_to_reg_imm(templo3, imm); - gen_mov_word_from_reg(templo3, dest, 1); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - -// add an 8bit constant value to a dword memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); - cache_checkinstr(2); - if (imm >= 0) { - cache_addw( ADD_IMM8(templo3, (Bit32s)imm) ); // add templo3, #(imm) - } else { - cache_addw( SUB_IMM8(templo3, -((Bit32s)imm)) ); // sub templo3, #(-imm) - } - gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); - if (dword) { - gen_mov_dword_to_reg_imm(templo1, imm); - } else { - gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); - } - cache_checkinstr(2); - cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 - gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); -} - -// subtract an 8bit constant value from a dword memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); - cache_checkinstr(2); - if (imm >= 0) { - cache_addw( SUB_IMM8(templo3, (Bit32s)imm) ); // sub templo3, #(imm) - } else { - cache_addw( ADD_IMM8(templo3, -((Bit32s)imm)) ); // add templo3, #(-imm) - } - gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); - if (dword) { - gen_mov_dword_to_reg_imm(templo1, imm); - } else { - gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); - } - cache_checkinstr(2); - cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 - gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); -} - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - if (scale) { - cache_checkinstr(4); - cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) - cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 - } else { - cache_checkinstr(2); - cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg - } - gen_add_imm(dest_reg, imm); -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - if (scale) { - cache_checkinstr(2); - cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) - } - gen_add_imm(dest_reg, imm); -} - -// helper function for gen_call_function_raw and gen_call_function_setup -static void gen_call_function_helper(void * func) { - Bit8u *datapos; - - datapos = cache_reservedata(); - *(Bit32u*)datapos=(Bit32u)func; - - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] - cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4) - cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 - cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state - } else { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] - cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4) - cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 - cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state - cache_addw( NOP ); // nop - } - // after_call: - - // switch from arm to thumb state - cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1 - cache_addd(0xe12fff10 + (templo1)); // bx templo1 - - // thumb state from now on -} - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - cache_checkinstr(18); - gen_call_function_helper(func); -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - cache_checkinstr(18); - Bit32u proc_addr = (Bit32u)cache.pos; - gen_call_function_helper(func); - return proc_addr; - // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) - // then length of generated code is 16 bytes - // otherwise length of generated code is 18 bytes -} - -#if (1) -// max of 4 parameters in a1-a4 - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - gen_mov_dword_to_reg_imm(param, imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - gen_mov_dword_to_reg_imm(param, addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - gen_mov_regs(param, reg); -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - gen_mov_word_to_reg(param, (void *)mem, 1); -} -#else - other arm abis -#endif - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - gen_mov_word_to_reg(templo3, ptr, 1); - - if (imm) { - gen_mov_dword_to_reg_imm(templo2, imm); - cache_checkinstr(2); - cache_addw( ADD_REG(templo3, templo3, templo2) ); // add templo3, templo3, templo2 - } - -#if (1) -// (*ptr) should be word aligned - if ((imm & 0x03) == 0) { - cache_checkinstr(6); - cache_addw( LDR_IMM(templo2, templo3, 0) ); // ldr templo2, [templo3] - } else -#endif - { - cache_checkinstr(24); - cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] - cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] - cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] - cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - } - - // increase jmp address to keep thumb state - cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 - - cache_addw( BX(templo2) ); // bx templo2 -} - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { - cache_checkinstr(4); - if (dword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 - } - cache_addw( BEQ_FWD(0) ); // beq j - return ((Bit32u)cache.pos-2); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - cache_checkinstr(4); - if (dword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 - } - cache_addw( BNE_FWD(0) ); // bne j - return ((Bit32u)cache.pos-2); -} - -// calculate relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-(data+4); - if (len<0) len=-len; - if (len>252) LOG_MSG("Big jump %d",len); -#endif - *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); -} - - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - Bit8u *datapos; - - cache_checkinstr(8); - datapos = cache_reservedata(); - - if (isdword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 - } - cache_addw( BEQ_FWD(2) ); // beq nobranch (pc+2) - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] - } else { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] - } - cache_addw( BX(templo1) ); // bx templo1 - // nobranch: - return ((Bit32u)datapos); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u gen_create_branch_long_leqzero(HostReg reg) { - Bit8u *datapos; - - cache_checkinstr(8); - datapos = cache_reservedata(); - - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - cache_addw( BGT_FWD(2) ); // bgt nobranch (pc+2) - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] - } else { - cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] - } - cache_addw( BX(templo1) ); // bx templo1 - // nobranch: - return ((Bit32u)datapos); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - // this is an absolute branch - *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state -} - -static void gen_run_code(void) { - // switch from arm to thumb state - cache_addd(0xe2800000 + (HOST_r3 << 12) + (HOST_pc << 16) + (1)); // add r3, pc, #1 - cache_addd(0xe12fff10 + (HOST_r3)); // bx r3 - - // thumb state from now on - cache_addw(0xb500); // push {lr} - cache_addw( MOV_LO_HI(HOST_r3, FC_SEGS_ADDR) ); // mov r3, FC_SEGS_ADDR - cache_addw( MOV_LO_HI(HOST_r2, FC_REGS_ADDR) ); // mov r2, FC_REGS_ADDR - cache_addw(0xb4fc); // push {r2,r3,v1-v4} - - // adr: 16 - cache_addw( LDR_PC_IMM(HOST_r3, 64 - (16 + 4)) ); // ldr r3, [pc, #(&Segs)] - // adr: 18 - cache_addw( LDR_PC_IMM(HOST_r2, 68 - (18 + 2)) ); // ldr r2, [pc, #(&cpu_regs)] - cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 - cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 - - // align 4 - cache_addw( ADD_LO_PC_IMM(HOST_r3, 8) ); // add r3, pc, #8 - cache_addw( ADD_IMM8(HOST_r0, 1) ); // add r0, #1 - cache_addw( ADD_IMM8(HOST_r3, 1) ); // add r3, #1 - cache_addw(0xb408); // push {r3} - cache_addw( BX(HOST_r0) ); // bx r0 - cache_addw( NOP ); // nop - - // align 4 - cache_addw(0xbcfc); // pop {r2,r3,v1-v4} - cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 - cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 - - cache_addw(0xbc08); // pop {r3} - cache_addw( BX(HOST_r3) ); // bx r3 - - // fill up to 64 bytes - cache_addw( NOP ); // nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - - // adr: 64 - cache_addd((Bit32u)&Segs); // address of "Segs" - // adr: 68 - cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" -} - -// return from a function -static void gen_return_function(void) { - cache_checkinstr(4); - cache_addw(0xbc08); // pop {r3} - cache_addw( BX(HOST_r3) ); // bx r3 -} - - -// short unconditional jump (over data pool) -// must emit at most CACHE_DATA_JUMP bytes -static void INLINE gen_create_branch_short(void * func) { - cache_addw( B_FWD((Bit32u)func - ((Bit32u)cache.pos + 4)) ); // b func -} - - -#ifdef DRC_FLAGS_INVALIDATION - -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { - if ((*(Bit16u*)pos & 0xf000) == 0xe000) { - if ((*(Bit16u*)pos & 0x0fff) >= ((CACHE_DATA_ALIGN / 2) - 1) && - (*(Bit16u*)pos & 0x0fff) < 0x0800) - { - pos = (Bit8u *) ( ( ( (Bit32u)(*(Bit16u*)pos & 0x0fff) ) << 1 ) + ((Bit32u)pos + 4) ); - } - } - -#ifdef DRC_FLAGS_INVALIDATION_DCODE - if (((Bit32u)pos & 0x03) == 0) - { - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit16u*)pos=B_FWD(12); // b after_call (pc+12) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_SHRb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) - break; - case t_SHRw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) - break; - case t_SHRd: - *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_SARb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) - break; - case t_SARw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) - break; - case t_SARd: - *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_RORb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+10)=NOP; // nop - *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+14)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_RORw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+8)=B_FWD(4); // b after_call (pc+4) - break; - case t_RORd: - *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - case t_ROLb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+14)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_ROLw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=NOP; // nop - *(Bit16u*)(pos+12)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+14)=NOP; // nop - break; - case t_ROLd: - *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 - *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) - break; - default: - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func - break; - } - } - else - { - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit16u*)pos=B_FWD(14); // b after_call (pc+14) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_SHRb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) - break; - case t_SHRw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) - break; - case t_SHRd: - *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_SARb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) - break; - case t_SARw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) - break; - case t_SARd: - *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_RORb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=NOP; // nop - *(Bit16u*)(pos+8)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+10)=NOP; // nop - *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+14)=NOP; // nop - *(Bit16u*)(pos+16)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_RORw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+8)=B_FWD(6); // b after_call (pc+6) - break; - case t_RORd: - *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - case t_ROLb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+14)=NOP; // nop - *(Bit16u*)(pos+16)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_ROLw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=NOP; // nop - *(Bit16u*)(pos+12)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+14)=NOP; // nop - *(Bit16u*)(pos+16)=NOP; // nop - break; - case t_ROLd: - *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 - *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) - break; - default: - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func - break; - } - - } -#else - if (((Bit32u)pos & 0x03) == 0) - { - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func - } - else - { - *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func - } -#endif -} -#endif - -#ifdef DRC_USE_SEGS_ADDR - -// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] -} - -// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] -} - -// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { - cache_checkinstr(6); - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] - cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 -} - -#endif - -#ifdef DRC_USE_REGS_ADDR - -// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] -} - -// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - if (dword) { - cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] - } else { - cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] - } -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] -} - - -// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { - cache_checkinstr(6); - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] - cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 -} - - -// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) -static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] -} - -// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - if (dword) { - cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] - } else { - cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] - } -} - -// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR -static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { - cache_checkinstr(4); - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] -} - -#endif +/* + * Copyright (C) 2002-2010 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: risc_armv4le-thumb-niw.h,v 1.5 2009-06-27 12:51:10 c2woody Exp $ */ + + +/* ARMv4 (little endian) backend by M-HT (thumb version with data pool) */ + + +// temporary "lo" registers +#define templo1 HOST_v3 +#define templo2 HOST_v4 +#define templo3 HOST_v2 + +// register that holds function return values +#define FC_RETOP HOST_a1 + +// register used for address calculations, +#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG + +// register that holds the first parameter +#define FC_OP1 HOST_a1 + +// register that holds the second parameter +#define FC_OP2 HOST_a2 + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_a4 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_a1 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_a2 + +// temporary register for LEA +#define TEMP_REG_DRC HOST_a4 + +#ifdef DRC_USE_REGS_ADDR +// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code +#define FC_REGS_ADDR HOST_v7 +#endif + +#ifdef DRC_USE_SEGS_ADDR +// used to hold the address of "Segs" - preferably filled in function gen_run_code +#define FC_SEGS_ADDR HOST_v8 +#endif + + +// instruction encodings + +// move +// mov dst, #imm @ 0 <= imm <= 255 +#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) +// mov dst, src +#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) +// mov dst, src +#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) +// mov dst, src +#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) + +// arithmetic +// add dst, src, #imm @ 0 <= imm <= 7 +#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) +// add dst, #imm @ 0 <= imm <= 255 +#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) +// add dst, src1, src2 +#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) +// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 +#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) +// sub dst, src1, src2 +#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) +// sub dst, src, #imm @ 0 <= imm <= 7 +#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) +// sub dst, #imm @ 0 <= imm <= 255 +#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) +// neg dst, src +#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) +// cmp dst, #imm @ 0 <= imm <= 255 +#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) +// nop +#define NOP (0x46c0) + +// logical +// and dst, src +#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) +// eor dst, src +#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) +// orr dst, src +#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) + +// shift/rotate +// lsl dst, src, #imm +#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) +// lsl dst, reg +#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) +// lsr dst, src, #imm +#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) +// lsr dst, reg +#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) +// asr dst, src, #imm +#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) +// asr dst, reg +#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) +// ror dst, reg +#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) + +// load +// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 +#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) +// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 +#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) +// ldrb reg, [addr, #imm] @ 0 <= imm < 32 +#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) +// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 +#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) + +// store +// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 +#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) +// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 +#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) +// strb reg, [addr, #imm] @ 0 <= imm < 32 +#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) + +// branch +// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) +// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) +// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) +// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 +#define B_FWD(imm) (0xe000 + ((imm) >> 1) ) +// bx reg +#define BX(reg) (0x4700 + ((reg) << 3) ) + + +// data pool defines +#define CACHE_DATA_JUMP (2) +#define CACHE_DATA_ALIGN (32) +#define CACHE_DATA_MIN (32) +#define CACHE_DATA_MAX (288) + +// data pool variables +static Bit8u * cache_datapos = NULL; // position of data pool in the cache block +static Bit32u cache_datasize = 0; // total size of data pool +static Bit32u cache_dataindex = 0; // used size of data pool = index of free data item (in bytes) in data pool + + +// forwarded function +static void INLINE gen_create_branch_short(void * func); + +// function to check distance to data pool +// if too close, then generate jump after data pool +static void cache_checkinstr(Bit32u size) { + if (cache_datasize == 0) { + if (cache_datapos != NULL) { + if (cache.pos + size + CACHE_DATA_JUMP >= cache_datapos) { + cache_datapos = NULL; + } + } + return; + } + + if (cache.pos + size + CACHE_DATA_JUMP <= cache_datapos) return; + + { + register Bit8u * newcachepos; + + newcachepos = cache_datapos + cache_datasize; + gen_create_branch_short(newcachepos); + cache.pos = newcachepos; + } + + if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && + cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) + { + cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); + } else { + register Bit32u cachemodsize; + + cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); + + if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || + cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) + { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); + } else { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); + } + } + + cache_datasize = 0; + cache_dataindex = 0; +} + +// function to reserve item in data pool +// returns address of item +static Bit8u * cache_reservedata(void) { + // if data pool not yet initialized, then initialize data pool + if (GCC_UNLIKELY(cache_datapos == NULL)) { + if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN < cache.block.active->cache.start + CACHE_DATA_MAX) { + cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); + } + } + + // if data pool not yet used, then set data pool + if (cache_datasize == 0) { + // set data pool address is too close (or behind) cache.pos then set new data pool size + if (cache.pos + CACHE_DATA_MIN + CACHE_DATA_JUMP /*+ CACHE_DATA_ALIGN*/ > cache_datapos) { + if (cache.pos + CACHE_DATA_MAX + CACHE_DATA_ALIGN >= cache.block.active->cache.start + cache.block.active->cache.size && + cache.pos + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) < cache.block.active->cache.start + cache.block.active->cache.size) + { + cache_datapos = (Bit8u *) (((Bitu)cache.block.active->cache.start + cache.block.active->cache.size - CACHE_DATA_ALIGN) & ~(CACHE_DATA_ALIGN - 1)); + } else { + register Bit32u cachemodsize; + + cachemodsize = (cache.pos - cache.block.active->cache.start) & (CACHE_MAXSIZE - 1); + + if (cachemodsize + CACHE_DATA_MAX + CACHE_DATA_ALIGN <= CACHE_MAXSIZE || + cachemodsize + CACHE_DATA_MIN + CACHE_DATA_ALIGN + (CACHE_DATA_ALIGN - CACHE_ALIGN) > CACHE_MAXSIZE) + { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + CACHE_DATA_MAX) & ~(CACHE_DATA_ALIGN - 1)); + } else { + cache_datapos = (Bit8u *) (((Bitu)cache.pos + (CACHE_MAXSIZE - CACHE_DATA_ALIGN) - cachemodsize) & ~(CACHE_DATA_ALIGN - 1)); + } + } + } + // set initial data pool size + cache_datasize = CACHE_DATA_ALIGN; + } + + // if data pool is full, then enlarge data pool + if (cache_dataindex == cache_datasize) { + cache_datasize += CACHE_DATA_ALIGN; + } + + cache_dataindex += 4; + return (cache_datapos + (cache_dataindex - 4)); +} + +static void cache_block_before_close(void) { + // if data pool in use, then resize cache block to include the data pool + if (cache_datasize != 0) + { + cache.pos = cache_datapos + cache_dataindex; + } + + // clear the values before next use + cache_datapos = NULL; + cache_datasize = 0; + cache_dataindex = 0; +} + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + if(reg_src == reg_dst) return; + cache_checkinstr(2); + cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + if ((imm & 0xffffff00) == 0) { + cache_checkinstr(2); + cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) + } else if ((imm & 0xffff00ff) == 0) { + cache_checkinstr(4); + cache_addw( MOV_IMM(dest_reg, imm >> 8) ); // mov dest_reg, #(imm >> 8) + cache_addw( LSL_IMM(dest_reg, dest_reg, 8) ); // lsl dest_reg, dest_reg, #8 + } else if ((imm & 0xff00ffff) == 0) { + cache_checkinstr(4); + cache_addw( MOV_IMM(dest_reg, imm >> 16) ); // mov dest_reg, #(imm >> 16) + cache_addw( LSL_IMM(dest_reg, dest_reg, 16) ); // lsl dest_reg, dest_reg, #16 + } else if ((imm & 0x00ffffff) == 0) { + cache_checkinstr(4); + cache_addw( MOV_IMM(dest_reg, imm >> 24) ); // mov dest_reg, #(imm >> 24) + cache_addw( LSL_IMM(dest_reg, dest_reg, 24) ); // lsl dest_reg, dest_reg, #24 + } else { + Bit32u diff; + + cache_checkinstr(4); + + diff = imm - ((Bit32u)cache.pos+4); + + if ((diff < 1024) && ((imm & 0x03) == 0)) { + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( ADD_LO_PC_IMM(dest_reg, diff >> 2) ); // add dest_reg, pc, #(diff >> 2) + } else { + cache_addw( NOP ); // nop + cache_addw( ADD_LO_PC_IMM(dest_reg, (diff - 2) >> 2) ); // add dest_reg, pc, #((diff - 2) >> 2) + } + } else { + Bit8u *datapos; + + datapos = cache_reservedata(); + *(Bit32u*)datapos=imm; + + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 4)) ); // ldr dest_reg, [pc, datapos] + } else { + cache_addw( LDR_PC_IMM(dest_reg, datapos - (cache.pos + 2)) ); // ldr dest_reg, [pc, datapos] + } + } + } +} + +// helper function for gen_mov_word_to_reg +static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)data & 3) { + if ( ((Bit32u)data & 3) == 2 ) { + cache_checkinstr(8); + cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] + cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } else { + cache_checkinstr(16); + cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 + cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] + cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } + } else { + cache_checkinstr(2); + cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] + } + } else { + if ((Bit32u)data & 1) { + cache_checkinstr(8); + cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } else { + cache_checkinstr(2); + cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + } + } +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); + gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); +} + +// helper function for gen_mov_word_from_reg +static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)dest & 3) { + if ( ((Bit32u)dest & 3) == 2 ) { + cache_checkinstr(8); + cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 + cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] + } else { + cache_checkinstr(20); + cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 + cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 + cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 + cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] + } + } else { + cache_checkinstr(2); + cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] + } + } else { + if ((Bit32u)dest & 1) { + cache_checkinstr(8); + cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 + cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] + } else { + cache_checkinstr(2); + cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + } + } +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); + cache_checkinstr(2); + cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + gen_mov_byte_to_reg_low(dest_reg, data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_checkinstr(2); + cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(dest_reg, imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); + cache_checkinstr(2); + cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + cache_checkinstr(4); + cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 + + if (sign) { + cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 + } else { + cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 + } +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + cache_checkinstr(4); + cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 + + if (sign) { + cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 + } else { + cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 + } +} + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + gen_mov_word_to_reg(templo3, op, 1); + cache_checkinstr(2); + cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo1, imm); + cache_checkinstr(2); + cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + if(imm == 0xffffffff) return; + gen_mov_dword_to_reg_imm(templo1, imm); + cache_checkinstr(2); + cache_addw( AND(reg, templo1) ); // and reg, templo1 +} + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + gen_mov_dword_to_reg_imm(templo3, imm); + gen_mov_word_from_reg(templo3, dest, 1); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + +// add an 8bit constant value to a dword memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); + cache_checkinstr(2); + if (imm >= 0) { + cache_addw( ADD_IMM8(templo3, (Bit32s)imm) ); // add templo3, #(imm) + } else { + cache_addw( SUB_IMM8(templo3, -((Bit32s)imm)) ); // sub templo3, #(-imm) + } + gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); + if (dword) { + gen_mov_dword_to_reg_imm(templo1, imm); + } else { + gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); + } + cache_checkinstr(2); + cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 + gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); +} + +// subtract an 8bit constant value from a dword memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); + cache_checkinstr(2); + if (imm >= 0) { + cache_addw( SUB_IMM8(templo3, (Bit32s)imm) ); // sub templo3, #(imm) + } else { + cache_addw( ADD_IMM8(templo3, -((Bit32s)imm)) ); // add templo3, #(-imm) + } + gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); + if (dword) { + gen_mov_dword_to_reg_imm(templo1, imm); + } else { + gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); + } + cache_checkinstr(2); + cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 + gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); +} + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + if (scale) { + cache_checkinstr(4); + cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) + cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 + } else { + cache_checkinstr(2); + cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg + } + gen_add_imm(dest_reg, imm); +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + if (scale) { + cache_checkinstr(2); + cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) + } + gen_add_imm(dest_reg, imm); +} + +// helper function for gen_call_function_raw and gen_call_function_setup +static void gen_call_function_helper(void * func) { + Bit8u *datapos; + + datapos = cache_reservedata(); + *(Bit32u*)datapos=(Bit32u)func; + + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] + cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4) + cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 + cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state + } else { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] + cache_addw( ADD_LO_PC_IMM(templo2, 4) ); // adr templo2, after_call (add templo2, pc, #4) + cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 + cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state + cache_addw( NOP ); // nop + } + // after_call: + + // switch from arm to thumb state + cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1 + cache_addd(0xe12fff10 + (templo1)); // bx templo1 + + // thumb state from now on +} + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + cache_checkinstr(18); + gen_call_function_helper(func); +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + cache_checkinstr(18); + Bit32u proc_addr = (Bit32u)cache.pos; + gen_call_function_helper(func); + return proc_addr; + // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) + // then length of generated code is 16 bytes + // otherwise length of generated code is 18 bytes +} + +#if (1) +// max of 4 parameters in a1-a4 + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + gen_mov_dword_to_reg_imm(param, imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + gen_mov_dword_to_reg_imm(param, addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + gen_mov_regs(param, reg); +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + gen_mov_word_to_reg(param, (void *)mem, 1); +} +#else + other arm abis +#endif + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + gen_mov_word_to_reg(templo3, ptr, 1); + + if (imm) { + gen_mov_dword_to_reg_imm(templo2, imm); + cache_checkinstr(2); + cache_addw( ADD_REG(templo3, templo3, templo2) ); // add templo3, templo3, templo2 + } + +#if (1) +// (*ptr) should be word aligned + if ((imm & 0x03) == 0) { + cache_checkinstr(6); + cache_addw( LDR_IMM(templo2, templo3, 0) ); // ldr templo2, [templo3] + } else +#endif + { + cache_checkinstr(24); + cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] + cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] + cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] + cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + } + + // increase jmp address to keep thumb state + cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 + + cache_addw( BX(templo2) ); // bx templo2 +} + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { + cache_checkinstr(4); + if (dword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 + } + cache_addw( BEQ_FWD(0) ); // beq j + return ((Bit32u)cache.pos-2); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + cache_checkinstr(4); + if (dword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 + } + cache_addw( BNE_FWD(0) ); // bne j + return ((Bit32u)cache.pos-2); +} + +// calculate relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-(data+4); + if (len<0) len=-len; + if (len>252) LOG_MSG("Big jump %d",len); +#endif + *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); +} + + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + Bit8u *datapos; + + cache_checkinstr(8); + datapos = cache_reservedata(); + + if (isdword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 + } + cache_addw( BEQ_FWD(2) ); // beq nobranch (pc+2) + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] + } else { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] + } + cache_addw( BX(templo1) ); // bx templo1 + // nobranch: + return ((Bit32u)datapos); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u gen_create_branch_long_leqzero(HostReg reg) { + Bit8u *datapos; + + cache_checkinstr(8); + datapos = cache_reservedata(); + + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + cache_addw( BGT_FWD(2) ); // bgt nobranch (pc+2) + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 4)) ); // ldr templo1, [pc, datapos] + } else { + cache_addw( LDR_PC_IMM(templo1, datapos - (cache.pos + 2)) ); // ldr templo1, [pc, datapos] + } + cache_addw( BX(templo1) ); // bx templo1 + // nobranch: + return ((Bit32u)datapos); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + // this is an absolute branch + *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state +} + +static void gen_run_code(void) { + // switch from arm to thumb state + cache_addd(0xe2800000 + (HOST_r3 << 12) + (HOST_pc << 16) + (1)); // add r3, pc, #1 + cache_addd(0xe12fff10 + (HOST_r3)); // bx r3 + + // thumb state from now on + cache_addw(0xb500); // push {lr} + cache_addw( MOV_LO_HI(HOST_r3, FC_SEGS_ADDR) ); // mov r3, FC_SEGS_ADDR + cache_addw( MOV_LO_HI(HOST_r2, FC_REGS_ADDR) ); // mov r2, FC_REGS_ADDR + cache_addw(0xb4fc); // push {r2,r3,v1-v4} + + // adr: 16 + cache_addw( LDR_PC_IMM(HOST_r3, 64 - (16 + 4)) ); // ldr r3, [pc, #(&Segs)] + // adr: 18 + cache_addw( LDR_PC_IMM(HOST_r2, 68 - (18 + 2)) ); // ldr r2, [pc, #(&cpu_regs)] + cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 + cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 + + // align 4 + cache_addw( ADD_LO_PC_IMM(HOST_r3, 8) ); // add r3, pc, #8 + cache_addw( ADD_IMM8(HOST_r0, 1) ); // add r0, #1 + cache_addw( ADD_IMM8(HOST_r3, 1) ); // add r3, #1 + cache_addw(0xb408); // push {r3} + cache_addw( BX(HOST_r0) ); // bx r0 + cache_addw( NOP ); // nop + + // align 4 + cache_addw(0xbcfc); // pop {r2,r3,v1-v4} + cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 + cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 + + cache_addw(0xbc08); // pop {r3} + cache_addw( BX(HOST_r3) ); // bx r3 + + // fill up to 64 bytes + cache_addw( NOP ); // nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + + // adr: 64 + cache_addd((Bit32u)&Segs); // address of "Segs" + // adr: 68 + cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" +} + +// return from a function +static void gen_return_function(void) { + cache_checkinstr(4); + cache_addw(0xbc08); // pop {r3} + cache_addw( BX(HOST_r3) ); // bx r3 +} + + +// short unconditional jump (over data pool) +// must emit at most CACHE_DATA_JUMP bytes +static void INLINE gen_create_branch_short(void * func) { + cache_addw( B_FWD((Bit32u)func - ((Bit32u)cache.pos + 4)) ); // b func +} + + +#ifdef DRC_FLAGS_INVALIDATION + +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { + if ((*(Bit16u*)pos & 0xf000) == 0xe000) { + if ((*(Bit16u*)pos & 0x0fff) >= ((CACHE_DATA_ALIGN / 2) - 1) && + (*(Bit16u*)pos & 0x0fff) < 0x0800) + { + pos = (Bit8u *) ( ( ( (Bit32u)(*(Bit16u*)pos & 0x0fff) ) << 1 ) + ((Bit32u)pos + 4) ); + } + } + +#ifdef DRC_FLAGS_INVALIDATION_DCODE + if (((Bit32u)pos & 0x03) == 0) + { + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit16u*)pos=B_FWD(12); // b after_call (pc+12) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_SHRb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) + break; + case t_SHRw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) + break; + case t_SHRd: + *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_SARb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) + break; + case t_SARw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) + break; + case t_SARd: + *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_RORb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+10)=NOP; // nop + *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+14)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_RORw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+8)=B_FWD(4); // b after_call (pc+4) + break; + case t_RORd: + *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + case t_ROLb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+14)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_ROLw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=NOP; // nop + *(Bit16u*)(pos+12)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+14)=NOP; // nop + break; + case t_ROLd: + *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+6)=B_FWD(6); // b after_call (pc+6) + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 + *(Bit16u*)(pos+2)=B_FWD(10); // b after_call (pc+10) + break; + default: + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func + break; + } + } + else + { + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit16u*)pos=B_FWD(14); // b after_call (pc+14) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_SHRb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) + break; + case t_SHRw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) + break; + case t_SHRd: + *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_SARb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) + break; + case t_SARw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) + break; + case t_SARd: + *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_RORb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=NOP; // nop + *(Bit16u*)(pos+8)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+10)=NOP; // nop + *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+14)=NOP; // nop + *(Bit16u*)(pos+16)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_RORw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+8)=B_FWD(6); // b after_call (pc+6) + break; + case t_RORd: + *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + case t_ROLb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+12)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+14)=NOP; // nop + *(Bit16u*)(pos+16)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_ROLw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=NOP; // nop + *(Bit16u*)(pos+12)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+14)=NOP; // nop + *(Bit16u*)(pos+16)=NOP; // nop + break; + case t_ROLd: + *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+6)=B_FWD(8); // b after_call (pc+8) + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 + *(Bit16u*)(pos+2)=B_FWD(12); // b after_call (pc+12) + break; + default: + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func + break; + } + + } +#else + if (((Bit32u)pos & 0x03) == 0) + { + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 4) ) = (Bit32u)fct_ptr; // simple_func + } + else + { + *(Bit32u*)( ( ((Bit32u) (*pos)) << 2 ) + ((Bit32u)pos + 2) ) = (Bit32u)fct_ptr; // simple_func + } +#endif +} +#endif + +#ifdef DRC_USE_SEGS_ADDR + +// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] +} + +// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] +} + +// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { + cache_checkinstr(6); + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] + cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 +} + +#endif + +#ifdef DRC_USE_REGS_ADDR + +// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] +} + +// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + if (dword) { + cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] + } else { + cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] + } +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] +} + + +// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { + cache_checkinstr(6); + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] + cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 +} + + +// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) +static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] +} + +// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + if (dword) { + cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] + } else { + cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] + } +} + +// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR +static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { + cache_checkinstr(4); + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] +} + +#endif diff --git a/src/cpu/core_dynrec/risc_armv4le-thumb.h b/src/cpu/core_dynrec/risc_armv4le-thumb.h index 708cdbb..9a0bc6c 100644 --- a/src/cpu/core_dynrec/risc_armv4le-thumb.h +++ b/src/cpu/core_dynrec/risc_armv4le-thumb.h @@ -1,1134 +1,1134 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le-thumb.h,v 1.6 2009/06/27 12:51:10 c2woody Exp $ */ - - -/* ARMv4 (little endian) backend by M-HT (thumb version) */ - - -// temporary "lo" registers -#define templo1 HOST_v3 -#define templo2 HOST_v4 -#define templo3 HOST_v2 - -// register that holds function return values -#define FC_RETOP HOST_a1 - -// register used for address calculations, -#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG - -// register that holds the first parameter -#define FC_OP1 HOST_a1 - -// register that holds the second parameter -#define FC_OP2 HOST_a2 - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_a4 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_a1 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_a2 - -// temporary register for LEA -#define TEMP_REG_DRC HOST_a4 - -#ifdef DRC_USE_REGS_ADDR -// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code -#define FC_REGS_ADDR HOST_v7 -#endif - -#ifdef DRC_USE_SEGS_ADDR -// used to hold the address of "Segs" - preferably filled in function gen_run_code -#define FC_SEGS_ADDR HOST_v8 -#endif - - -// instruction encodings - -// move -// mov dst, #imm @ 0 <= imm <= 255 -#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) -// mov dst, src -#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) -// mov dst, src -#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) -// mov dst, src -#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) - -// arithmetic -// add dst, src, #imm @ 0 <= imm <= 7 -#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) -// add dst, #imm @ 0 <= imm <= 255 -#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) -// add dst, src1, src2 -#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) -// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 -#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) -// sub dst, src1, src2 -#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) -// sub dst, src, #imm @ 0 <= imm <= 7 -#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) -// sub dst, #imm @ 0 <= imm <= 255 -#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) -// neg dst, src -#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) -// cmp dst, #imm @ 0 <= imm <= 255 -#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) -// nop -#define NOP (0x46c0) - -// logical -// and dst, src -#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) -// eor dst, src -#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) -// orr dst, src -#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) - -// shift/rotate -// lsl dst, src, #imm -#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) -// lsl dst, reg -#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) -// lsr dst, src, #imm -#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) -// lsr dst, reg -#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) -// asr dst, src, #imm -#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) -// asr dst, reg -#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) -// ror dst, reg -#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) - -// load -// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 -#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) -// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 -#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) -// ldrb reg, [addr, #imm] @ 0 <= imm < 32 -#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) -// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 -#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) - -// store -// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 -#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) -// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 -#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) -// strb reg, [addr, #imm] @ 0 <= imm < 32 -#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) - -// branch -// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) -// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) -// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 -#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) -// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 -#define B_FWD(imm) (0xe000 + ((imm) >> 1) ) -// bx reg -#define BX(reg) (0x4700 + ((reg) << 3) ) - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - if(reg_src == reg_dst) return; - cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - if ((imm & 0xffffff00) == 0) { - cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) - } else if ((imm & 0xffff00ff) == 0) { - cache_addw( MOV_IMM(dest_reg, imm >> 8) ); // mov dest_reg, #(imm >> 8) - cache_addw( LSL_IMM(dest_reg, dest_reg, 8) ); // lsl dest_reg, dest_reg, #8 - } else if ((imm & 0xff00ffff) == 0) { - cache_addw( MOV_IMM(dest_reg, imm >> 16) ); // mov dest_reg, #(imm >> 16) - cache_addw( LSL_IMM(dest_reg, dest_reg, 16) ); // lsl dest_reg, dest_reg, #16 - } else if ((imm & 0x00ffffff) == 0) { - cache_addw( MOV_IMM(dest_reg, imm >> 24) ); // mov dest_reg, #(imm >> 24) - cache_addw( LSL_IMM(dest_reg, dest_reg, 24) ); // lsl dest_reg, dest_reg, #24 - } else { - Bit32u diff; - - diff = imm - ((Bit32u)cache.pos+4); - - if ((diff < 1024) && ((imm & 0x03) == 0)) { - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( ADD_LO_PC_IMM(dest_reg, diff) ); // add dest_reg, pc, #(diff >> 2) - } else { - cache_addw( NOP ); // nop - cache_addw( ADD_LO_PC_IMM(dest_reg, diff - 2) ); // add dest_reg, pc, #((diff - 2) >> 2) - } - } else { - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(dest_reg, 0) ); // ldr dest_reg, [pc, #0] - cache_addw( B_FWD(2) ); // b next_code (pc+2) - cache_addd(imm); // .int imm - // next_code: - } else { - cache_addw( LDR_PC_IMM(dest_reg, 4) ); // ldr dest_reg, [pc, #4] - cache_addw( B_FWD(4) ); // b next_code (pc+4) - cache_addw( NOP ); // nop - cache_addd(imm); // .int imm - // next_code: - } - } - } -} - -// helper function for gen_mov_word_to_reg -static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)data & 3) { - if ( ((Bit32u)data & 3) == 2 ) { - cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] - cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } else { - cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 - cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] - cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } - } else { - cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] - } - } else { - if ((Bit32u)data & 1) { - cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] - cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 - } else { - cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] - } - } -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); - gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); -} - -// helper function for gen_mov_word_from_reg -static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { - // alignment.... - if (dword) { - if ((Bit32u)dest & 3) { - if ( ((Bit32u)dest & 3) == 2 ) { - cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 - cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] - } else { - cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 - cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 - cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 - cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] - } - } else { - cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] - } - } else { - if ((Bit32u)dest & 1) { - cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] - cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg - cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 - cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] - } else { - cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] - } - } -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); - cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - gen_mov_byte_to_reg_low(dest_reg, data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(dest_reg, imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); - cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 - - if (sign) { - cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 - } else { - cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 - } -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 - - if (sign) { - cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 - } else { - cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 - } -} - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - gen_mov_word_to_reg(templo3, op, 1); - cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo1, imm); - cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - if(imm == 0xffffffff) return; - gen_mov_dword_to_reg_imm(templo1, imm); - cache_addw( AND(reg, templo1) ); // and reg, templo1 -} - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - gen_mov_dword_to_reg_imm(templo3, imm); - gen_mov_word_from_reg(templo3, dest, 1); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - -// add an 8bit constant value to a dword memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); - if (imm >= 0) { - cache_addw( ADD_IMM8(templo3, (Bit32s)imm) ); // add templo3, #(imm) - } else { - cache_addw( SUB_IMM8(templo3, -((Bit32s)imm)) ); // sub templo3, #(-imm) - } - gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); - if (dword) { - gen_mov_dword_to_reg_imm(templo1, imm); - } else { - gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); - } - cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 - gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); -} - -// subtract an 8bit constant value from a dword memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - if(!imm) return; - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); - if (imm >= 0) { - cache_addw( SUB_IMM8(templo3, (Bit32s)imm) ); // sub templo3, #(imm) - } else { - cache_addw( ADD_IMM8(templo3, -((Bit32s)imm)) ); // add templo3, #(-imm) - } - gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); - gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); - if (dword) { - gen_mov_dword_to_reg_imm(templo1, imm); - } else { - gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); - } - cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 - gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); -} - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - if (scale) { - cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) - cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 - } else { - cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg - } - gen_add_imm(dest_reg, imm); -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - if (scale) { - cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) - } - gen_add_imm(dest_reg, imm); -} - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] - cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) - cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 - cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state - } else { - cache_addw( LDR_PC_IMM(templo1, 8) ); // ldr templo1, [pc, #8] - cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) - cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 - cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state - cache_addw( NOP ); // nop - } - cache_addd((Bit32u)func); // .int func - // after_call: - - // switch from arm to thumb state - cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1 - cache_addd(0xe12fff10 + (templo1)); // bx templo1 - - // thumb state from now on -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - Bit32u proc_addr = (Bit32u)cache.pos; - gen_call_function_raw(func); - return proc_addr; - // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) - // then length of generated code is 20 bytes - // otherwise length of generated code is 22 bytes -} - -#if (1) -// max of 4 parameters in a1-a4 - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - gen_mov_dword_to_reg_imm(param, imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - gen_mov_dword_to_reg_imm(param, addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - gen_mov_regs(param, reg); -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - gen_mov_word_to_reg(param, (void *)mem, 1); -} -#else - other arm abis -#endif - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - gen_mov_word_to_reg(templo3, ptr, 1); - - if (imm) { - gen_mov_dword_to_reg_imm(templo2, imm); - cache_addw( ADD_REG(templo3, templo3, templo2) ); // add templo3, templo3, templo2 - } - -#if (1) -// (*ptr) should be word aligned - if ((imm & 0x03) == 0) { - cache_addw( LDR_IMM(templo2, templo3, 0) ); // ldr templo2, [templo3] - } else -#endif - { - cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] - cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] - cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] - cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] - cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 - cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 - } - - // increase jmp address to keep thumb state - cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 - - cache_addw( BX(templo2) ); // bx templo2 -} - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { - if (dword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 - } - cache_addw( BEQ_FWD(0) ); // beq j - return ((Bit32u)cache.pos-2); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - if (dword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 - } - cache_addw( BNE_FWD(0) ); // bne j - return ((Bit32u)cache.pos-2); -} - -// calculate relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-(data+4); - if (len<0) len=-len; - if (len>252) LOG_MSG("Big jump %d",len); -#endif - *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); -} - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - if (isdword) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - } else { - cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 - } - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( BEQ_FWD(8) ); // beq nobranch (pc+8) - cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] - cache_addw( BX(templo1) ); // bx templo1 - cache_addw( NOP ); // nop - } else { - cache_addw( BEQ_FWD(6) ); // beq nobranch (pc+6) - cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0] - cache_addw( BX(templo1) ); // bx templo1 - } - cache_addd(0); // fill j - // nobranch: - return ((Bit32u)cache.pos-4); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u gen_create_branch_long_leqzero(HostReg reg) { - cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 - if (((Bit32u)cache.pos & 0x03) == 0) { - cache_addw( BGT_FWD(8) ); // bgt nobranch (pc+8) - cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] - cache_addw( BX(templo1) ); // bx templo1 - cache_addw( NOP ); // nop - } else { - cache_addw( BGT_FWD(6) ); // bgt nobranch (pc+6) - cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0] - cache_addw( BX(templo1) ); // bx templo1 - } - cache_addd(0); // fill j - // nobranch: - return ((Bit32u)cache.pos-4); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - // this is an absolute branch - *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state -} - -static void gen_run_code(void) { - // switch from arm to thumb state - cache_addd(0xe2800000 + (HOST_r3 << 12) + (HOST_pc << 16) + (1)); // add r3, pc, #1 - cache_addd(0xe12fff10 + (HOST_r3)); // bx r3 - - // thumb state from now on - cache_addw(0xb500); // push {lr} - cache_addw( MOV_LO_HI(HOST_r3, FC_SEGS_ADDR) ); // mov r3, FC_SEGS_ADDR - cache_addw( MOV_LO_HI(HOST_r2, FC_REGS_ADDR) ); // mov r2, FC_REGS_ADDR - cache_addw(0xb4fc); // push {r2,r3,v1-v4} - - // adr: 16 - cache_addw( LDR_PC_IMM(HOST_r3, 64 - (16 + 4)) ); // ldr r3, [pc, #(&Segs)] - // adr: 18 - cache_addw( LDR_PC_IMM(HOST_r2, 68 - (18 + 2)) ); // ldr r2, [pc, #(&cpu_regs)] - cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 - cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 - - // align 4 - cache_addw( ADD_LO_PC_IMM(HOST_r3, 8) ); // add r3, pc, #8 - cache_addw( ADD_IMM8(HOST_r0, 1) ); // add r0, #1 - cache_addw( ADD_IMM8(HOST_r3, 1) ); // add r3, #1 - cache_addw(0xb408); // push {r3} - cache_addw( BX(HOST_r0) ); // bx r0 - cache_addw( NOP ); // nop - - // align 4 - cache_addw(0xbcfc); // pop {r2,r3,v1-v4} - cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 - cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 - - cache_addw(0xbc08); // pop {r3} - cache_addw( BX(HOST_r3) ); // bx r3 - - // fill up to 64 bytes - cache_addw( NOP ); // nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - cache_addd( NOP | (NOP << 16) ); // nop, nop - - // adr: 64 - cache_addd((Bit32u)&Segs); // address of "Segs" - // adr: 68 - cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" -} - -// return from a function -static void gen_return_function(void) { - cache_addw(0xbc08); // pop {r3} - cache_addw( BX(HOST_r3) ); // bx r3 -} - -#ifdef DRC_FLAGS_INVALIDATION - -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { -#ifdef DRC_FLAGS_INVALIDATION_DCODE - if (((Bit32u)pos & 0x03) == 0) - { - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit16u*)pos=B_FWD(16); // b after_call (pc+16) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_SHRb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) - break; - case t_SHRw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) - break; - case t_SHRd: - *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_SARb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) - break; - case t_SARw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) - break; - case t_SARd: - *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_RORb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4) - break; - case t_RORw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+8)=B_FWD(8); // b after_call (pc+8) - break; - case t_RORd: - *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - case t_ROLb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=NOP; // nop - *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+14)=NOP; // nop - *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+18)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_ROLw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4) - break; - case t_ROLd: - *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 - *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) - break; - default: - *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func - break; - } - } - else - { - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit16u*)pos=B_FWD(18); // b after_call (pc+18) - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_SHRb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) - break; - case t_SHRw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 - *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) - break; - case t_SHRd: - *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_SARb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) - break; - case t_SARw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 - *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) - break; - case t_SARd: - *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_RORb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6) - break; - case t_RORw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+8)=B_FWD(10); // b after_call (pc+10) - break; - case t_RORd: - *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - case t_ROLb: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=NOP; // nop - *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+14)=NOP; // nop - *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+18)=NOP; // nop - *(Bit16u*)(pos+20)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - break; - case t_ROLw: - *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 - *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 - *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 - *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6) - break; - case t_ROLd: - *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 - *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 - *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 - *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 - *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) - break; - default: - *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func - break; - } - - } -#else - if (((Bit32u)pos & 0x03) == 0) - { - *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func - } - else - { - *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func - } -#endif -} -#endif - -static void cache_block_before_close(void) { } - -#ifdef DRC_USE_SEGS_ADDR - -// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] -} - -// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] -} - -// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { - cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR - cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] - cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 -} - -#endif - -#ifdef DRC_USE_REGS_ADDR - -// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] -} - -// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - if (dword) { - cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] - } else { - cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] - } -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] -} - - -// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { - cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR - cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] - cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 -} - - -// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) -static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] -} - -// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - if (dword) { - cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] - } else { - cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] - } -} - -// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR -static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { - cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR - cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] -} - -#endif +/* + * Copyright (C) 2002-2010 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: risc_armv4le-thumb.h,v 1.6 2009-06-27 12:51:10 c2woody Exp $ */ + + +/* ARMv4 (little endian) backend by M-HT (thumb version) */ + + +// temporary "lo" registers +#define templo1 HOST_v3 +#define templo2 HOST_v4 +#define templo3 HOST_v2 + +// register that holds function return values +#define FC_RETOP HOST_a1 + +// register used for address calculations, +#define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG + +// register that holds the first parameter +#define FC_OP1 HOST_a1 + +// register that holds the second parameter +#define FC_OP2 HOST_a2 + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_a4 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_a1 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_a2 + +// temporary register for LEA +#define TEMP_REG_DRC HOST_a4 + +#ifdef DRC_USE_REGS_ADDR +// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code +#define FC_REGS_ADDR HOST_v7 +#endif + +#ifdef DRC_USE_SEGS_ADDR +// used to hold the address of "Segs" - preferably filled in function gen_run_code +#define FC_SEGS_ADDR HOST_v8 +#endif + + +// instruction encodings + +// move +// mov dst, #imm @ 0 <= imm <= 255 +#define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) +// mov dst, src +#define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) +// mov dst, src +#define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) +// mov dst, src +#define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) + +// arithmetic +// add dst, src, #imm @ 0 <= imm <= 7 +#define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) +// add dst, #imm @ 0 <= imm <= 255 +#define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) +// add dst, src1, src2 +#define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) +// add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 +#define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) +// sub dst, src1, src2 +#define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) +// sub dst, src, #imm @ 0 <= imm <= 7 +#define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) +// sub dst, #imm @ 0 <= imm <= 255 +#define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) +// neg dst, src +#define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) +// cmp dst, #imm @ 0 <= imm <= 255 +#define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) +// nop +#define NOP (0x46c0) + +// logical +// and dst, src +#define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) +// eor dst, src +#define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) +// orr dst, src +#define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) + +// shift/rotate +// lsl dst, src, #imm +#define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) +// lsl dst, reg +#define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) +// lsr dst, src, #imm +#define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) +// lsr dst, reg +#define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) +// asr dst, src, #imm +#define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) +// asr dst, reg +#define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) +// ror dst, reg +#define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) + +// load +// ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 +#define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) +// ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 +#define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) +// ldrb reg, [addr, #imm] @ 0 <= imm < 32 +#define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) +// ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 +#define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) + +// store +// str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 +#define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) +// strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 +#define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) +// strb reg, [addr, #imm] @ 0 <= imm < 32 +#define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) + +// branch +// beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) +// bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) +// bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 +#define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) +// b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 +#define B_FWD(imm) (0xe000 + ((imm) >> 1) ) +// bx reg +#define BX(reg) (0x4700 + ((reg) << 3) ) + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + if(reg_src == reg_dst) return; + cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + if ((imm & 0xffffff00) == 0) { + cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) + } else if ((imm & 0xffff00ff) == 0) { + cache_addw( MOV_IMM(dest_reg, imm >> 8) ); // mov dest_reg, #(imm >> 8) + cache_addw( LSL_IMM(dest_reg, dest_reg, 8) ); // lsl dest_reg, dest_reg, #8 + } else if ((imm & 0xff00ffff) == 0) { + cache_addw( MOV_IMM(dest_reg, imm >> 16) ); // mov dest_reg, #(imm >> 16) + cache_addw( LSL_IMM(dest_reg, dest_reg, 16) ); // lsl dest_reg, dest_reg, #16 + } else if ((imm & 0x00ffffff) == 0) { + cache_addw( MOV_IMM(dest_reg, imm >> 24) ); // mov dest_reg, #(imm >> 24) + cache_addw( LSL_IMM(dest_reg, dest_reg, 24) ); // lsl dest_reg, dest_reg, #24 + } else { + Bit32u diff; + + diff = imm - ((Bit32u)cache.pos+4); + + if ((diff < 1024) && ((imm & 0x03) == 0)) { + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( ADD_LO_PC_IMM(dest_reg, diff) ); // add dest_reg, pc, #(diff >> 2) + } else { + cache_addw( NOP ); // nop + cache_addw( ADD_LO_PC_IMM(dest_reg, diff - 2) ); // add dest_reg, pc, #((diff - 2) >> 2) + } + } else { + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(dest_reg, 0) ); // ldr dest_reg, [pc, #0] + cache_addw( B_FWD(2) ); // b next_code (pc+2) + cache_addd(imm); // .int imm + // next_code: + } else { + cache_addw( LDR_PC_IMM(dest_reg, 4) ); // ldr dest_reg, [pc, #4] + cache_addw( B_FWD(4) ); // b next_code (pc+4) + cache_addw( NOP ); // nop + cache_addd(imm); // .int imm + // next_code: + } + } + } +} + +// helper function for gen_mov_word_to_reg +static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)data & 3) { + if ( ((Bit32u)data & 3) == 2 ) { + cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] + cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } else { + cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 + cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] + cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } + } else { + cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] + } + } else { + if ((Bit32u)data & 1) { + cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] + cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 + } else { + cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] + } + } +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); + gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); +} + +// helper function for gen_mov_word_from_reg +static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { + // alignment.... + if (dword) { + if ((Bit32u)dest & 3) { + if ( ((Bit32u)dest & 3) == 2 ) { + cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 + cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] + } else { + cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 + cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 + cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 + cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] + } + } else { + cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] + } + } else { + if ((Bit32u)dest & 1) { + cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] + cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg + cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 + cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] + } else { + cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] + } + } +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); + cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + gen_mov_byte_to_reg_low(dest_reg, data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(dest_reg, imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); + cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 + + if (sign) { + cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 + } else { + cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 + } +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 + + if (sign) { + cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 + } else { + cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 + } +} + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + gen_mov_word_to_reg(templo3, op, 1); + cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo1, imm); + cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + if(imm == 0xffffffff) return; + gen_mov_dword_to_reg_imm(templo1, imm); + cache_addw( AND(reg, templo1) ); // and reg, templo1 +} + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + gen_mov_dword_to_reg_imm(templo3, imm); + gen_mov_word_from_reg(templo3, dest, 1); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + +// add an 8bit constant value to a dword memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); + if (imm >= 0) { + cache_addw( ADD_IMM8(templo3, (Bit32s)imm) ); // add templo3, #(imm) + } else { + cache_addw( SUB_IMM8(templo3, -((Bit32s)imm)) ); // sub templo3, #(-imm) + } + gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); + if (dword) { + gen_mov_dword_to_reg_imm(templo1, imm); + } else { + gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); + } + cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 + gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); +} + +// subtract an 8bit constant value from a dword memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + if(!imm) return; + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, 1, templo2); + if (imm >= 0) { + cache_addw( SUB_IMM8(templo3, (Bit32s)imm) ); // sub templo3, #(imm) + } else { + cache_addw( ADD_IMM8(templo3, -((Bit32s)imm)) ); // add templo3, #(-imm) + } + gen_mov_word_from_reg_helper(templo3, dest, 1, templo2); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + if (dword && ( (imm<128) || (imm>=0xffffff80) ) ) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); + gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); + if (dword) { + gen_mov_dword_to_reg_imm(templo1, imm); + } else { + gen_mov_word_to_reg_imm(templo1, (Bit16u)imm); + } + cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 + gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); +} + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + if (scale) { + cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) + cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 + } else { + cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg + } + gen_add_imm(dest_reg, imm); +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + if (scale) { + cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) + } + gen_add_imm(dest_reg, imm); +} + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] + cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) + cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 + cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state + } else { + cache_addw( LDR_PC_IMM(templo1, 8) ); // ldr templo1, [pc, #8] + cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) + cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 + cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state + cache_addw( NOP ); // nop + } + cache_addd((Bit32u)func); // .int func + // after_call: + + // switch from arm to thumb state + cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1 + cache_addd(0xe12fff10 + (templo1)); // bx templo1 + + // thumb state from now on +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + Bit32u proc_addr = (Bit32u)cache.pos; + gen_call_function_raw(func); + return proc_addr; + // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) + // then length of generated code is 20 bytes + // otherwise length of generated code is 22 bytes +} + +#if (1) +// max of 4 parameters in a1-a4 + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + gen_mov_dword_to_reg_imm(param, imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + gen_mov_dword_to_reg_imm(param, addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + gen_mov_regs(param, reg); +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + gen_mov_word_to_reg(param, (void *)mem, 1); +} +#else + other arm abis +#endif + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + gen_mov_word_to_reg(templo3, ptr, 1); + + if (imm) { + gen_mov_dword_to_reg_imm(templo2, imm); + cache_addw( ADD_REG(templo3, templo3, templo2) ); // add templo3, templo3, templo2 + } + +#if (1) +// (*ptr) should be word aligned + if ((imm & 0x03) == 0) { + cache_addw( LDR_IMM(templo2, templo3, 0) ); // ldr templo2, [templo3] + } else +#endif + { + cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] + cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] + cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] + cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] + cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 + cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 + } + + // increase jmp address to keep thumb state + cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 + + cache_addw( BX(templo2) ); // bx templo2 +} + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { + if (dword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 + } + cache_addw( BEQ_FWD(0) ); // beq j + return ((Bit32u)cache.pos-2); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + if (dword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 + } + cache_addw( BNE_FWD(0) ); // bne j + return ((Bit32u)cache.pos-2); +} + +// calculate relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-(data+4); + if (len<0) len=-len; + if (len>252) LOG_MSG("Big jump %d",len); +#endif + *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); +} + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + if (isdword) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + } else { + cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 + } + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( BEQ_FWD(8) ); // beq nobranch (pc+8) + cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] + cache_addw( BX(templo1) ); // bx templo1 + cache_addw( NOP ); // nop + } else { + cache_addw( BEQ_FWD(6) ); // beq nobranch (pc+6) + cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0] + cache_addw( BX(templo1) ); // bx templo1 + } + cache_addd(0); // fill j + // nobranch: + return ((Bit32u)cache.pos-4); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u gen_create_branch_long_leqzero(HostReg reg) { + cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 + if (((Bit32u)cache.pos & 0x03) == 0) { + cache_addw( BGT_FWD(8) ); // bgt nobranch (pc+8) + cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] + cache_addw( BX(templo1) ); // bx templo1 + cache_addw( NOP ); // nop + } else { + cache_addw( BGT_FWD(6) ); // bgt nobranch (pc+6) + cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0] + cache_addw( BX(templo1) ); // bx templo1 + } + cache_addd(0); // fill j + // nobranch: + return ((Bit32u)cache.pos-4); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + // this is an absolute branch + *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state +} + +static void gen_run_code(void) { + // switch from arm to thumb state + cache_addd(0xe2800000 + (HOST_r3 << 12) + (HOST_pc << 16) + (1)); // add r3, pc, #1 + cache_addd(0xe12fff10 + (HOST_r3)); // bx r3 + + // thumb state from now on + cache_addw(0xb500); // push {lr} + cache_addw( MOV_LO_HI(HOST_r3, FC_SEGS_ADDR) ); // mov r3, FC_SEGS_ADDR + cache_addw( MOV_LO_HI(HOST_r2, FC_REGS_ADDR) ); // mov r2, FC_REGS_ADDR + cache_addw(0xb4fc); // push {r2,r3,v1-v4} + + // adr: 16 + cache_addw( LDR_PC_IMM(HOST_r3, 64 - (16 + 4)) ); // ldr r3, [pc, #(&Segs)] + // adr: 18 + cache_addw( LDR_PC_IMM(HOST_r2, 68 - (18 + 2)) ); // ldr r2, [pc, #(&cpu_regs)] + cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 + cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 + + // align 4 + cache_addw( ADD_LO_PC_IMM(HOST_r3, 8) ); // add r3, pc, #8 + cache_addw( ADD_IMM8(HOST_r0, 1) ); // add r0, #1 + cache_addw( ADD_IMM8(HOST_r3, 1) ); // add r3, #1 + cache_addw(0xb408); // push {r3} + cache_addw( BX(HOST_r0) ); // bx r0 + cache_addw( NOP ); // nop + + // align 4 + cache_addw(0xbcfc); // pop {r2,r3,v1-v4} + cache_addw( MOV_HI_LO(FC_SEGS_ADDR, HOST_r3) ); // mov FC_SEGS_ADDR, r3 + cache_addw( MOV_HI_LO(FC_REGS_ADDR, HOST_r2) ); // mov FC_REGS_ADDR, r2 + + cache_addw(0xbc08); // pop {r3} + cache_addw( BX(HOST_r3) ); // bx r3 + + // fill up to 64 bytes + cache_addw( NOP ); // nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + cache_addd( NOP | (NOP << 16) ); // nop, nop + + // adr: 64 + cache_addd((Bit32u)&Segs); // address of "Segs" + // adr: 68 + cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" +} + +// return from a function +static void gen_return_function(void) { + cache_addw(0xbc08); // pop {r3} + cache_addw( BX(HOST_r3) ); // bx r3 +} + +#ifdef DRC_FLAGS_INVALIDATION + +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { +#ifdef DRC_FLAGS_INVALIDATION_DCODE + if (((Bit32u)pos & 0x03) == 0) + { + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit16u*)pos=B_FWD(16); // b after_call (pc+16) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_SHRb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) + break; + case t_SHRw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) + break; + case t_SHRd: + *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_SARb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) + break; + case t_SARw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) + break; + case t_SARd: + *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_RORb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4) + break; + case t_RORw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+8)=B_FWD(8); // b after_call (pc+8) + break; + case t_RORd: + *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + case t_ROLb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=NOP; // nop + *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+14)=NOP; // nop + *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+18)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_ROLw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4) + break; + case t_ROLd: + *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 + *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) + break; + default: + *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func + break; + } + } + else + { + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit16u*)pos=B_FWD(18); // b after_call (pc+18) + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_SHRb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) + break; + case t_SHRw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 + *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) + break; + case t_SHRd: + *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_SARb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) + break; + case t_SARw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 + *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) + break; + case t_SARd: + *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_RORb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6) + break; + case t_RORw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+8)=B_FWD(10); // b after_call (pc+10) + break; + case t_RORd: + *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + case t_ROLb: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=NOP; // nop + *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+14)=NOP; // nop + *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+18)=NOP; // nop + *(Bit16u*)(pos+20)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + break; + case t_ROLw: + *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 + *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 + *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 + *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6) + break; + case t_ROLd: + *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 + *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 + *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 + *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 + *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) + break; + default: + *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func + break; + } + + } +#else + if (((Bit32u)pos & 0x03) == 0) + { + *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func + } + else + { + *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func + } +#endif +} +#endif + +static void cache_block_before_close(void) { } + +#ifdef DRC_USE_SEGS_ADDR + +// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] +} + +// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] +} + +// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { + cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR + cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] + cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 +} + +#endif + +#ifdef DRC_USE_REGS_ADDR + +// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] +} + +// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + if (dword) { + cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] + } else { + cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] + } +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] +} + + +// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { + cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR + cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] + cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 +} + + +// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) +static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] +} + +// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + if (dword) { + cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] + } else { + cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] + } +} + +// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR +static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { + cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR + cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] +} + +#endif diff --git a/src/cpu/core_dynrec/risc_armv4le.h b/src/cpu/core_dynrec/risc_armv4le.h index 77496d3..e8cc2f2 100644 --- a/src/cpu/core_dynrec/risc_armv4le.h +++ b/src/cpu/core_dynrec/risc_armv4le.h @@ -1,31 +1,31 @@ -/* - * Copyright (C) 2002-2009 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: risc_armv4le.h,v 1.3 2009/05/27 09:15:41 qbix79 Exp $ */ - - -/* ARMv4 (little endian) backend (switcher) by M-HT */ - -#include "risc_armv4le-common.h" - -// choose your destiny: -#include "risc_armv4le-thumb-niw.h" -//#include "risc_armv4le-thumb-iw.h" -//#include "risc_armv4le-thumb.h" -//#include "risc_armv4le-s3.h" -//#include "risc_armv4le-o3.h" +/* + * Copyright (C) 2002-2010 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: risc_armv4le.h,v 1.3 2009-05-27 09:15:41 qbix79 Exp $ */ + + +/* ARMv4 (little endian) backend (switcher) by M-HT */ + +#include "risc_armv4le-common.h" + +// choose your destiny: +#include "risc_armv4le-thumb-niw.h" +//#include "risc_armv4le-thumb-iw.h" +//#include "risc_armv4le-thumb.h" +//#include "risc_armv4le-s3.h" +//#include "risc_armv4le-o3.h" diff --git a/src/cpu/core_dynrec/risc_mipsel32.h b/src/cpu/core_dynrec/risc_mipsel32.h index 0636539..cdc7541 100644 --- a/src/cpu/core_dynrec/risc_mipsel32.h +++ b/src/cpu/core_dynrec/risc_mipsel32.h @@ -1,751 +1,751 @@ -/* - * Copyright (C) 2002-2009 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: risc_mipsel32.h,v 1.6 2009/06/25 19:31:43 c2woody Exp $ */ - - -/* MIPS32 (little endian) backend by crazyc */ - - -// some configuring defines that specify the capabilities of this architecture -// or aspects of the recompiling - -// protect FC_ADDR over function calls if necessaray -// #define DRC_PROTECT_ADDR_REG - -// try to use non-flags generating functions if possible -#define DRC_FLAGS_INVALIDATION -// try to replace _simple functions by code -#define DRC_FLAGS_INVALIDATION_DCODE - -// type with the same size as a pointer -#define DRC_PTR_SIZE_IM Bit32u - -// calling convention modifier -#define DRC_CALL_CONV /* nothing */ -#define DRC_FC /* nothing */ - -// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR -//#define DRC_USE_REGS_ADDR -// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR -//#define DRC_USE_SEGS_ADDR - -// register mapping -typedef Bit8u HostReg; - -#define HOST_v0 2 -#define HOST_v1 3 -#define HOST_a0 4 -#define HOST_a1 5 -#define HOST_t4 12 -#define HOST_t5 13 -#define HOST_t6 14 -#define HOST_t7 15 -#define HOST_s0 16 -#define HOST_t8 24 -#define HOST_t9 25 -#define temp1 HOST_v1 -#define temp2 HOST_t9 - -// register that holds function return values -#define FC_RETOP HOST_v0 - -// register used for address calculations, -#define FC_ADDR HOST_s0 // has to be saved across calls, see DRC_PROTECT_ADDR_REG - -// register that holds the first parameter -#define FC_OP1 HOST_a0 - -// register that holds the second parameter -#define FC_OP2 HOST_a1 - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_??? - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_t5 - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_t6 - -// temporary register for LEA -#define TEMP_REG_DRC HOST_t7 - -#ifdef DRC_USE_REGS_ADDR -// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code -#define FC_REGS_ADDR HOST_??? -#endif - -#ifdef DRC_USE_SEGS_ADDR -// used to hold the address of "Segs" - preferably filled in function gen_run_code -#define FC_SEGS_ADDR HOST_??? -#endif - -// save some state to improve code gen -static bool temp1_valid = false; -static Bit32u temp1_value; - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - if(reg_src == reg_dst) return; - cache_addw((reg_dst<<11)+0x21); // addu reg_dst, $0, reg_src - cache_addw(reg_src); -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - if(imm < 65536) { - cache_addw((Bit16u)imm); // ori dest_reg, $0, imm - cache_addw(0x3400+dest_reg); - } else if(((Bit32s)imm < 0) && ((Bit32s)imm >= -32768)) { - cache_addw((Bit16u)imm); // addiu dest_reg, $0, imm - cache_addw(0x2400+dest_reg); - } else if(!(imm & 0xffff)) { - cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm) - cache_addw(0x3c00+dest_reg); - } else { - cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm) - cache_addw(0x3c00+dest_reg); - cache_addw((Bit16u)imm); // ori dest_reg, dest_reg, %lo(imm) - cache_addw(0x3400+(dest_reg<<5)+dest_reg); - } -} - -// this is the only place temp1 should be modified -static void INLINE mov_imm_to_temp1(Bit32u imm) { - if (temp1_valid && (temp1_value == imm)) return; - gen_mov_dword_to_reg_imm(temp1, imm); - temp1_valid = true; - temp1_value = imm; -} - -static Bit16s gen_addr_temp1(Bit32u addr) { - Bit32u hihalf = addr & 0xffff0000; - Bit16s lohalf = addr & 0xffff; - if (lohalf > 32764) { // [l,s]wl will overflow - hihalf = addr; - lohalf = 0; - } else if(lohalf < 0) hihalf += 0x10000; - mov_imm_to_temp1(hihalf); - return lohalf; -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - Bit16s lohalf = gen_addr_temp1((Bit32u)data); - // alignment.... - if (dword) { - if ((Bit32u)data & 3) { - cache_addw(lohalf+3); // lwl dest_reg, 3(temp1) - cache_addw(0x8800+(temp1<<5)+dest_reg); - cache_addw(lohalf); // lwr dest_reg, 0(temp1) - cache_addw(0x9800+(temp1<<5)+dest_reg); - } else { - cache_addw(lohalf); // lw dest_reg, 0(temp1) - cache_addw(0x8C00+(temp1<<5)+dest_reg); - } - } else { - if ((Bit32u)data & 1) { - cache_addw(lohalf); // lbu dest_reg, 0(temp1) - cache_addw(0x9000+(temp1<<5)+dest_reg); - cache_addw(lohalf+1); // lbu temp2, 1(temp1) - cache_addw(0x9000+(temp1<<5)+temp2); -#if (_MIPS_ISA==MIPS32R2) || defined(PSP) - cache_addw(0x7a04); // ins dest_reg, temp2, 8, 8 - cache_addw(0x7c00+(temp2<<5)+dest_reg); -#else - cache_addw((temp2<<11)+0x200); // sll temp2, temp2, 8 - cache_addw(temp2); - cache_addw((dest_reg<<11)+0x25); // or dest_reg, temp2, dest_reg - cache_addw((temp2<<5)+dest_reg); -#endif - } else { - cache_addw(lohalf); // lhu dest_reg, 0(temp1); - cache_addw(0x9400+(temp1<<5)+dest_reg); - } - } -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - cache_addw(imm); // ori dest_reg, $0, imm - cache_addw(0x3400+dest_reg); -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - Bit16s lohalf = gen_addr_temp1((Bit32u)dest); - // alignment.... - if (dword) { - if ((Bit32u)dest & 3) { - cache_addw(lohalf+3); // swl src_reg, 3(temp1) - cache_addw(0xA800+(temp1<<5)+src_reg); - cache_addw(lohalf); // swr src_reg, 0(temp1) - cache_addw(0xB800+(temp1<<5)+src_reg); - } else { - cache_addw(lohalf); // sw src_reg, 0(temp1) - cache_addw(0xAC00+(temp1<<5)+src_reg); - } - } else { - if((Bit32u)dest & 1) { - cache_addw(lohalf); // sb src_reg, 0(temp1) - cache_addw(0xA000+(temp1<<5)+src_reg); - cache_addw((temp2<<11)+0x202); // srl temp2, src_reg, 8 - cache_addw(src_reg); - cache_addw(lohalf+1); // sb temp2, 1(temp1) - cache_addw(0xA000+(temp1<<5)+temp2); - } else { - cache_addw(lohalf); // sh src_reg, 0(temp1); - cache_addw(0xA400+(temp1<<5)+src_reg); - } - } -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - Bit16s lohalf = gen_addr_temp1((Bit32u)data); - cache_addw(lohalf); // lbu dest_reg, 0(temp1) - cache_addw(0x9000+(temp1<<5)+dest_reg); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - gen_mov_byte_to_reg_low(dest_reg, data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - gen_mov_word_to_reg_imm(dest_reg, imm); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - gen_mov_byte_to_reg_low_imm(dest_reg, imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - Bit16s lohalf = gen_addr_temp1((Bit32u)dest); - cache_addw(lohalf); // sb src_reg, 0(temp1) - cache_addw(0xA000+(temp1<<5)+src_reg); -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - if (sign) { -#if (_MIPS_ISA==MIPS32R2) || defined(PSP) - cache_addw((reg<<11)+0x420); // seb reg, reg - cache_addw(0x7c00+reg); -#else - arch that lacks seb -#endif - } else { - cache_addw(0xff); // andi reg, reg, 0xff - cache_addw(0x3000+(reg<<5)+reg); - } -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - if (sign) { -#if (_MIPS_ISA==MIPS32R2) || defined(PSP) - cache_addw((reg<<11)+0x620); // seh reg, reg - cache_addw(0x7c00+reg); -#else - arch that lacks seh -#endif - } else { - cache_addw(0xffff); // andi reg, reg, 0xffff - cache_addw(0x3000+(reg<<5)+reg); - } -} - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - gen_mov_word_to_reg(temp2, op, 1); - cache_addw((reg<<11)+0x21); // addu reg, reg, temp2 - cache_addw((reg<<5)+temp2); -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - if(!imm) return; - if(((Bit32s)imm >= -32768) && ((Bit32s)imm < 32768)) { - cache_addw((Bit16u)imm); // addiu reg, reg, imm - cache_addw(0x2400+(reg<<5)+reg); - } else { - mov_imm_to_temp1(imm); - cache_addw((reg<<11)+0x21); // addu reg, reg, temp1 - cache_addw((reg<<5)+temp1); - } -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - if(imm < 65536) { - cache_addw((Bit16u)imm); // andi reg, reg, imm - cache_addw(0x3000+(reg<<5)+reg); - } else { - mov_imm_to_temp1((Bit32u)imm); - cache_addw((reg<<11)+0x24); // and reg, temp1, reg - cache_addw((temp1<<5)+reg); - } -} - - -// move a 32bit constant value into memory -static void INLINE gen_mov_direct_dword(void* dest,Bit32u imm) { - gen_mov_dword_to_reg_imm(temp2, imm); - gen_mov_word_from_reg(temp2, dest, 1); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void INLINE gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if(!imm) return; - gen_mov_word_to_reg(temp2, dest, dword); - gen_add_imm(temp2, imm); - gen_mov_word_from_reg(temp2, dest, dword); -} - -// add an 8bit constant value to a dword memory value -static void INLINE gen_add_direct_byte(void* dest,Bit8s imm) { - gen_add_direct_word(dest, (Bit32s)imm, 1); -} - -// subtract an 8bit constant value from a dword memory value -static void INLINE gen_sub_direct_byte(void* dest,Bit8s imm) { - gen_add_direct_word(dest, -((Bit32s)imm), 1); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void INLINE gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - gen_add_direct_word(dest, -(Bit32s)imm, dword); -} - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - if (scale) { - cache_addw((scale_reg<<11)+(scale<<6)); // sll scale_reg, scale_reg, scale - cache_addw(scale_reg); - } - cache_addw((dest_reg<<11)+0x21); // addu dest_reg, dest_reg, scale_reg - cache_addw((dest_reg<<5)+scale_reg); - gen_add_imm(dest_reg, imm); -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - if (scale) { - cache_addw((dest_reg<<11)+(scale<<6)); // sll dest_reg, dest_reg, scale - cache_addw(dest_reg); - } - gen_add_imm(dest_reg, imm); -} - -#define DELAY cache_addd(0) // nop - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { -#if C_DEBUG - if ((cache.pos ^ func) & 0xf0000000) LOG_MSG("jump overflow\n"); -#endif - temp1_valid = false; - cache_addd(0x0c000000+(((Bit32u)func>>2)&0x3ffffff)); // jal func - DELAY; -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - Bit32u proc_addr = (Bit32u)cache.pos; - gen_call_function_raw(func); - return proc_addr; -} - -#ifdef __mips_eabi -// max of 8 parameters in $a0-$a3 and $t0-$t3 - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - gen_mov_dword_to_reg_imm(param+4, imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - gen_mov_dword_to_reg_imm(param+4, addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - gen_mov_regs(param+4, reg); -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - gen_mov_word_to_reg(param+4, (void *)mem, 1); -} -#else - other mips abis -#endif - -// jump to an address pointed at by ptr, offset is in imm -static void INLINE gen_jmp_ptr(void * ptr,Bits imm=0) { - gen_mov_word_to_reg(temp2, ptr, 1); - if((imm < -32768) || (imm >= 32768)) { - gen_add_imm(temp2, imm); - imm = 0; - } - temp1_valid = false; - cache_addw((Bit16u)imm); // lw temp2, imm(temp2) - cache_addw(0x8C00+(temp2<<5)+temp2); - cache_addd((temp2<<21)+8); // jr temp2 - DELAY; -} - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u INLINE gen_create_branch_on_zero(HostReg reg,bool dword) { - temp1_valid = false; - if(!dword) { - cache_addw(0xffff); // andi temp1, reg, 0xffff - cache_addw(0x3000+(reg<<5)+temp1); - } - cache_addw(0); // beq $0, reg, 0 - cache_addw(0x1000+(dword?reg:temp1)); - DELAY; - return ((Bit32u)cache.pos-8); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u INLINE gen_create_branch_on_nonzero(HostReg reg,bool dword) { - temp1_valid = false; - if(!dword) { - cache_addw(0xffff); // andi temp1, reg, 0xffff - cache_addw(0x3000+(reg<<5)+temp1); - } - cache_addw(0); // bne $0, reg, 0 - cache_addw(0x1400+(dword?reg:temp1)); - DELAY; - return ((Bit32u)cache.pos-8); -} - -// calculate relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-data; - if (len<0) len=-len; - if (len>126) LOG_MSG("Big jump %d",len); -#endif - temp1_valid = false; // this is a branch target - *(Bit16u*)data=((Bit16u)((Bit32u)cache.pos-data-4)>>2); -} - -#if 0 // assume for the moment no branch will go farther then +/- 128KB - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - temp1_valid = false; - if (!isdword) { - cache_addw(0xff); // andi temp1, reg, 0xff - cache_addw(0x3000+(reg<<5)+temp1); - } - cache_addw(3); // beq $0, reg, +12 - cache_addw(0x1000+(isdword?reg:temp1)); - DELAY; - cache_addd(0x00000000); // fill j - DELAY; - return ((Bit32u)cache.pos-8); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) { - temp1_valid = false; - cache_addw(3); // bgtz reg, +12 - cache_addw(0x1c00+(reg<<5)); - DELAY; - cache_addd(0x00000000); // fill j - DELAY; - return ((Bit32u)cache.pos-8); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - temp1_valid = false; - // this is an absolute branch - *(Bit32u*)data=0x08000000+(((Bit32u)cache.pos>>2)&0x3ffffff); -} -#else -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - temp1_valid = false; - if (!isdword) { - cache_addw(0xff); // andi temp1, reg, 0xff - cache_addw(0x3000+(reg<<5)+temp1); - } - cache_addw(0); // bne $0, reg, 0 - cache_addw(0x1400+(isdword?reg:temp1)); - DELAY; - return ((Bit32u)cache.pos-8); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) { - temp1_valid = false; - cache_addw(0); // blez reg, 0 - cache_addw(0x1800+(reg<<5)); - DELAY; - return ((Bit32u)cache.pos-8); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void INLINE gen_fill_branch_long(Bit32u data) { - gen_fill_branch(data); -} -#endif - -static void gen_run_code(void) { - temp1_valid = false; - cache_addd(0x27bdfff0); // addiu $sp, $sp, -16 - cache_addd(0xafb00004); // sw $s0, 4($sp) - cache_addd(0x00800008); // jr $a0 - cache_addd(0xafbf0000); // sw $ra, 0($sp) -} - -// return from a function -static void gen_return_function(void) { - temp1_valid = false; - cache_addd(0x8fbf0000); // lw $ra, 0($sp) - cache_addd(0x8fb00004); // lw $s0, 4($sp) - cache_addd(0x03e00008); // jr $ra - cache_addd(0x27bd0010); // addiu $sp, $sp, 16 -} - -#ifdef DRC_FLAGS_INVALIDATION -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { -#ifdef DRC_FLAGS_INVALIDATION_DCODE - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit32u*)pos=0x00851021; // addu $v0, $a0, $a1 - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit32u*)pos=0x00851025; // or $v0, $a0, $a1 - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit32u*)pos=0x00851024; // and $v0, $a0, $a1 - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit32u*)pos=0x00851023; // subu $v0, $a0, $a1 - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit32u*)pos=0x00851026; // xor $v0, $a0, $a1 - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit32u*)pos=0; // nop - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit32u*)pos=0x24820001; // addiu $v0, $a0, 1 - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit32u*)pos=0x2482ffff; // addiu $v0, $a0, -1 - break; - case t_SHLb: - case t_SHLw: - case t_SHLd: - *(Bit32u*)pos=0x00a41004; // sllv $v0, $a0, $a1 - break; - case t_SHRb: - case t_SHRw: - case t_SHRd: - *(Bit32u*)pos=0x00a41006; // srlv $v0, $a0, $a1 - break; - case t_SARd: - *(Bit32u*)pos=0x00a41007; // srav $v0, $a0, $a1 - break; -#if (_MIPS_ISA==MIPS32R2) || defined(PSP) - case t_RORd: - *(Bit32u*)pos=0x00a41046; // rotr $v0, $a0, $a1 - break; -#endif - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit32u*)pos=0x00041023; // subu $v0, $0, $a0 - break; - default: - *(Bit32u*)pos=0x0c000000+((((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func - break; - } -#else - *(Bit32u*)pos=0x0c000000+(((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func -#endif -} -#endif - -static void cache_block_closing(Bit8u* block_start,Bitu block_size) { -#ifdef PSP -// writeback dcache and invalidate icache - Bit32u inval_start = ((Bit32u)block_start) & ~63; - Bit32u inval_end = (((Bit32u)block_start) + block_size + 64) & ~63; - for (;inval_start < inval_end; inval_start+=64) { - __builtin_allegrex_cache(0x1a, inval_start); - __builtin_allegrex_cache(0x08, inval_start); - } -#endif -} - -static void cache_block_before_close(void) { } - - -#ifdef DRC_USE_SEGS_ADDR - -// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { -// stub -} - -// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { -// stub -} - -// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) -static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { -// stub -} - -#endif - -#ifdef DRC_USE_REGS_ADDR - -// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { -// stub -} - -// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { -// stub -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { -// stub -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { -// stub -} - -// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { -// stub -} - - -// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { -// stub -} - - -// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) -static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { -// stub -} - -// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) -static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { -// stub -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) -static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { -// stub -} - -// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR -static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { -// stub -} - -#endif +/* + * Copyright (C) 2002-2010 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: risc_mipsel32.h,v 1.6 2009-06-25 19:31:43 c2woody Exp $ */ + + +/* MIPS32 (little endian) backend by crazyc */ + + +// some configuring defines that specify the capabilities of this architecture +// or aspects of the recompiling + +// protect FC_ADDR over function calls if necessaray +// #define DRC_PROTECT_ADDR_REG + +// try to use non-flags generating functions if possible +#define DRC_FLAGS_INVALIDATION +// try to replace _simple functions by code +#define DRC_FLAGS_INVALIDATION_DCODE + +// type with the same size as a pointer +#define DRC_PTR_SIZE_IM Bit32u + +// calling convention modifier +#define DRC_CALL_CONV /* nothing */ +#define DRC_FC /* nothing */ + +// use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR +//#define DRC_USE_REGS_ADDR +// use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR +//#define DRC_USE_SEGS_ADDR + +// register mapping +typedef Bit8u HostReg; + +#define HOST_v0 2 +#define HOST_v1 3 +#define HOST_a0 4 +#define HOST_a1 5 +#define HOST_t4 12 +#define HOST_t5 13 +#define HOST_t6 14 +#define HOST_t7 15 +#define HOST_s0 16 +#define HOST_t8 24 +#define HOST_t9 25 +#define temp1 HOST_v1 +#define temp2 HOST_t9 + +// register that holds function return values +#define FC_RETOP HOST_v0 + +// register used for address calculations, +#define FC_ADDR HOST_s0 // has to be saved across calls, see DRC_PROTECT_ADDR_REG + +// register that holds the first parameter +#define FC_OP1 HOST_a0 + +// register that holds the second parameter +#define FC_OP2 HOST_a1 + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_??? + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_t5 + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_t6 + +// temporary register for LEA +#define TEMP_REG_DRC HOST_t7 + +#ifdef DRC_USE_REGS_ADDR +// used to hold the address of "cpu_regs" - preferably filled in function gen_run_code +#define FC_REGS_ADDR HOST_??? +#endif + +#ifdef DRC_USE_SEGS_ADDR +// used to hold the address of "Segs" - preferably filled in function gen_run_code +#define FC_SEGS_ADDR HOST_??? +#endif + +// save some state to improve code gen +static bool temp1_valid = false; +static Bit32u temp1_value; + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + if(reg_src == reg_dst) return; + cache_addw((reg_dst<<11)+0x21); // addu reg_dst, $0, reg_src + cache_addw(reg_src); +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + if(imm < 65536) { + cache_addw((Bit16u)imm); // ori dest_reg, $0, imm + cache_addw(0x3400+dest_reg); + } else if(((Bit32s)imm < 0) && ((Bit32s)imm >= -32768)) { + cache_addw((Bit16u)imm); // addiu dest_reg, $0, imm + cache_addw(0x2400+dest_reg); + } else if(!(imm & 0xffff)) { + cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm) + cache_addw(0x3c00+dest_reg); + } else { + cache_addw((Bit16u)(imm >> 16)); // lui dest_reg, %hi(imm) + cache_addw(0x3c00+dest_reg); + cache_addw((Bit16u)imm); // ori dest_reg, dest_reg, %lo(imm) + cache_addw(0x3400+(dest_reg<<5)+dest_reg); + } +} + +// this is the only place temp1 should be modified +static void INLINE mov_imm_to_temp1(Bit32u imm) { + if (temp1_valid && (temp1_value == imm)) return; + gen_mov_dword_to_reg_imm(temp1, imm); + temp1_valid = true; + temp1_value = imm; +} + +static Bit16s gen_addr_temp1(Bit32u addr) { + Bit32u hihalf = addr & 0xffff0000; + Bit16s lohalf = addr & 0xffff; + if (lohalf > 32764) { // [l,s]wl will overflow + hihalf = addr; + lohalf = 0; + } else if(lohalf < 0) hihalf += 0x10000; + mov_imm_to_temp1(hihalf); + return lohalf; +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + Bit16s lohalf = gen_addr_temp1((Bit32u)data); + // alignment.... + if (dword) { + if ((Bit32u)data & 3) { + cache_addw(lohalf+3); // lwl dest_reg, 3(temp1) + cache_addw(0x8800+(temp1<<5)+dest_reg); + cache_addw(lohalf); // lwr dest_reg, 0(temp1) + cache_addw(0x9800+(temp1<<5)+dest_reg); + } else { + cache_addw(lohalf); // lw dest_reg, 0(temp1) + cache_addw(0x8C00+(temp1<<5)+dest_reg); + } + } else { + if ((Bit32u)data & 1) { + cache_addw(lohalf); // lbu dest_reg, 0(temp1) + cache_addw(0x9000+(temp1<<5)+dest_reg); + cache_addw(lohalf+1); // lbu temp2, 1(temp1) + cache_addw(0x9000+(temp1<<5)+temp2); +#if (_MIPS_ISA==MIPS32R2) || defined(PSP) + cache_addw(0x7a04); // ins dest_reg, temp2, 8, 8 + cache_addw(0x7c00+(temp2<<5)+dest_reg); +#else + cache_addw((temp2<<11)+0x200); // sll temp2, temp2, 8 + cache_addw(temp2); + cache_addw((dest_reg<<11)+0x25); // or dest_reg, temp2, dest_reg + cache_addw((temp2<<5)+dest_reg); +#endif + } else { + cache_addw(lohalf); // lhu dest_reg, 0(temp1); + cache_addw(0x9400+(temp1<<5)+dest_reg); + } + } +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + cache_addw(imm); // ori dest_reg, $0, imm + cache_addw(0x3400+dest_reg); +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + Bit16s lohalf = gen_addr_temp1((Bit32u)dest); + // alignment.... + if (dword) { + if ((Bit32u)dest & 3) { + cache_addw(lohalf+3); // swl src_reg, 3(temp1) + cache_addw(0xA800+(temp1<<5)+src_reg); + cache_addw(lohalf); // swr src_reg, 0(temp1) + cache_addw(0xB800+(temp1<<5)+src_reg); + } else { + cache_addw(lohalf); // sw src_reg, 0(temp1) + cache_addw(0xAC00+(temp1<<5)+src_reg); + } + } else { + if((Bit32u)dest & 1) { + cache_addw(lohalf); // sb src_reg, 0(temp1) + cache_addw(0xA000+(temp1<<5)+src_reg); + cache_addw((temp2<<11)+0x202); // srl temp2, src_reg, 8 + cache_addw(src_reg); + cache_addw(lohalf+1); // sb temp2, 1(temp1) + cache_addw(0xA000+(temp1<<5)+temp2); + } else { + cache_addw(lohalf); // sh src_reg, 0(temp1); + cache_addw(0xA400+(temp1<<5)+src_reg); + } + } +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + Bit16s lohalf = gen_addr_temp1((Bit32u)data); + cache_addw(lohalf); // lbu dest_reg, 0(temp1) + cache_addw(0x9000+(temp1<<5)+dest_reg); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + gen_mov_byte_to_reg_low(dest_reg, data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + gen_mov_word_to_reg_imm(dest_reg, imm); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + gen_mov_byte_to_reg_low_imm(dest_reg, imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + Bit16s lohalf = gen_addr_temp1((Bit32u)dest); + cache_addw(lohalf); // sb src_reg, 0(temp1) + cache_addw(0xA000+(temp1<<5)+src_reg); +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + if (sign) { +#if (_MIPS_ISA==MIPS32R2) || defined(PSP) + cache_addw((reg<<11)+0x420); // seb reg, reg + cache_addw(0x7c00+reg); +#else + arch that lacks seb +#endif + } else { + cache_addw(0xff); // andi reg, reg, 0xff + cache_addw(0x3000+(reg<<5)+reg); + } +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + if (sign) { +#if (_MIPS_ISA==MIPS32R2) || defined(PSP) + cache_addw((reg<<11)+0x620); // seh reg, reg + cache_addw(0x7c00+reg); +#else + arch that lacks seh +#endif + } else { + cache_addw(0xffff); // andi reg, reg, 0xffff + cache_addw(0x3000+(reg<<5)+reg); + } +} + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + gen_mov_word_to_reg(temp2, op, 1); + cache_addw((reg<<11)+0x21); // addu reg, reg, temp2 + cache_addw((reg<<5)+temp2); +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + if(!imm) return; + if(((Bit32s)imm >= -32768) && ((Bit32s)imm < 32768)) { + cache_addw((Bit16u)imm); // addiu reg, reg, imm + cache_addw(0x2400+(reg<<5)+reg); + } else { + mov_imm_to_temp1(imm); + cache_addw((reg<<11)+0x21); // addu reg, reg, temp1 + cache_addw((reg<<5)+temp1); + } +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + if(imm < 65536) { + cache_addw((Bit16u)imm); // andi reg, reg, imm + cache_addw(0x3000+(reg<<5)+reg); + } else { + mov_imm_to_temp1((Bit32u)imm); + cache_addw((reg<<11)+0x24); // and reg, temp1, reg + cache_addw((temp1<<5)+reg); + } +} + + +// move a 32bit constant value into memory +static void INLINE gen_mov_direct_dword(void* dest,Bit32u imm) { + gen_mov_dword_to_reg_imm(temp2, imm); + gen_mov_word_from_reg(temp2, dest, 1); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void INLINE gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if(!imm) return; + gen_mov_word_to_reg(temp2, dest, dword); + gen_add_imm(temp2, imm); + gen_mov_word_from_reg(temp2, dest, dword); +} + +// add an 8bit constant value to a dword memory value +static void INLINE gen_add_direct_byte(void* dest,Bit8s imm) { + gen_add_direct_word(dest, (Bit32s)imm, 1); +} + +// subtract an 8bit constant value from a dword memory value +static void INLINE gen_sub_direct_byte(void* dest,Bit8s imm) { + gen_add_direct_word(dest, -((Bit32s)imm), 1); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void INLINE gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + gen_add_direct_word(dest, -(Bit32s)imm, dword); +} + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + if (scale) { + cache_addw((scale_reg<<11)+(scale<<6)); // sll scale_reg, scale_reg, scale + cache_addw(scale_reg); + } + cache_addw((dest_reg<<11)+0x21); // addu dest_reg, dest_reg, scale_reg + cache_addw((dest_reg<<5)+scale_reg); + gen_add_imm(dest_reg, imm); +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + if (scale) { + cache_addw((dest_reg<<11)+(scale<<6)); // sll dest_reg, dest_reg, scale + cache_addw(dest_reg); + } + gen_add_imm(dest_reg, imm); +} + +#define DELAY cache_addd(0) // nop + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { +#if C_DEBUG + if ((cache.pos ^ func) & 0xf0000000) LOG_MSG("jump overflow\n"); +#endif + temp1_valid = false; + cache_addd(0x0c000000+(((Bit32u)func>>2)&0x3ffffff)); // jal func + DELAY; +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + Bit32u proc_addr = (Bit32u)cache.pos; + gen_call_function_raw(func); + return proc_addr; +} + +#ifdef __mips_eabi +// max of 8 parameters in $a0-$a3 and $t0-$t3 + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + gen_mov_dword_to_reg_imm(param+4, imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + gen_mov_dword_to_reg_imm(param+4, addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + gen_mov_regs(param+4, reg); +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + gen_mov_word_to_reg(param+4, (void *)mem, 1); +} +#else + other mips abis +#endif + +// jump to an address pointed at by ptr, offset is in imm +static void INLINE gen_jmp_ptr(void * ptr,Bits imm=0) { + gen_mov_word_to_reg(temp2, ptr, 1); + if((imm < -32768) || (imm >= 32768)) { + gen_add_imm(temp2, imm); + imm = 0; + } + temp1_valid = false; + cache_addw((Bit16u)imm); // lw temp2, imm(temp2) + cache_addw(0x8C00+(temp2<<5)+temp2); + cache_addd((temp2<<21)+8); // jr temp2 + DELAY; +} + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u INLINE gen_create_branch_on_zero(HostReg reg,bool dword) { + temp1_valid = false; + if(!dword) { + cache_addw(0xffff); // andi temp1, reg, 0xffff + cache_addw(0x3000+(reg<<5)+temp1); + } + cache_addw(0); // beq $0, reg, 0 + cache_addw(0x1000+(dword?reg:temp1)); + DELAY; + return ((Bit32u)cache.pos-8); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u INLINE gen_create_branch_on_nonzero(HostReg reg,bool dword) { + temp1_valid = false; + if(!dword) { + cache_addw(0xffff); // andi temp1, reg, 0xffff + cache_addw(0x3000+(reg<<5)+temp1); + } + cache_addw(0); // bne $0, reg, 0 + cache_addw(0x1400+(dword?reg:temp1)); + DELAY; + return ((Bit32u)cache.pos-8); +} + +// calculate relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-data; + if (len<0) len=-len; + if (len>126) LOG_MSG("Big jump %d",len); +#endif + temp1_valid = false; // this is a branch target + *(Bit16u*)data=((Bit16u)((Bit32u)cache.pos-data-4)>>2); +} + +#if 0 // assume for the moment no branch will go farther then +/- 128KB + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + temp1_valid = false; + if (!isdword) { + cache_addw(0xff); // andi temp1, reg, 0xff + cache_addw(0x3000+(reg<<5)+temp1); + } + cache_addw(3); // beq $0, reg, +12 + cache_addw(0x1000+(isdword?reg:temp1)); + DELAY; + cache_addd(0x00000000); // fill j + DELAY; + return ((Bit32u)cache.pos-8); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) { + temp1_valid = false; + cache_addw(3); // bgtz reg, +12 + cache_addw(0x1c00+(reg<<5)); + DELAY; + cache_addd(0x00000000); // fill j + DELAY; + return ((Bit32u)cache.pos-8); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + temp1_valid = false; + // this is an absolute branch + *(Bit32u*)data=0x08000000+(((Bit32u)cache.pos>>2)&0x3ffffff); +} +#else +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + temp1_valid = false; + if (!isdword) { + cache_addw(0xff); // andi temp1, reg, 0xff + cache_addw(0x3000+(reg<<5)+temp1); + } + cache_addw(0); // bne $0, reg, 0 + cache_addw(0x1400+(isdword?reg:temp1)); + DELAY; + return ((Bit32u)cache.pos-8); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u INLINE gen_create_branch_long_leqzero(HostReg reg) { + temp1_valid = false; + cache_addw(0); // blez reg, 0 + cache_addw(0x1800+(reg<<5)); + DELAY; + return ((Bit32u)cache.pos-8); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void INLINE gen_fill_branch_long(Bit32u data) { + gen_fill_branch(data); +} +#endif + +static void gen_run_code(void) { + temp1_valid = false; + cache_addd(0x27bdfff0); // addiu $sp, $sp, -16 + cache_addd(0xafb00004); // sw $s0, 4($sp) + cache_addd(0x00800008); // jr $a0 + cache_addd(0xafbf0000); // sw $ra, 0($sp) +} + +// return from a function +static void gen_return_function(void) { + temp1_valid = false; + cache_addd(0x8fbf0000); // lw $ra, 0($sp) + cache_addd(0x8fb00004); // lw $s0, 4($sp) + cache_addd(0x03e00008); // jr $ra + cache_addd(0x27bd0010); // addiu $sp, $sp, 16 +} + +#ifdef DRC_FLAGS_INVALIDATION +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { +#ifdef DRC_FLAGS_INVALIDATION_DCODE + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit32u*)pos=0x00851021; // addu $v0, $a0, $a1 + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit32u*)pos=0x00851025; // or $v0, $a0, $a1 + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit32u*)pos=0x00851024; // and $v0, $a0, $a1 + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit32u*)pos=0x00851023; // subu $v0, $a0, $a1 + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit32u*)pos=0x00851026; // xor $v0, $a0, $a1 + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit32u*)pos=0; // nop + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit32u*)pos=0x24820001; // addiu $v0, $a0, 1 + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit32u*)pos=0x2482ffff; // addiu $v0, $a0, -1 + break; + case t_SHLb: + case t_SHLw: + case t_SHLd: + *(Bit32u*)pos=0x00a41004; // sllv $v0, $a0, $a1 + break; + case t_SHRb: + case t_SHRw: + case t_SHRd: + *(Bit32u*)pos=0x00a41006; // srlv $v0, $a0, $a1 + break; + case t_SARd: + *(Bit32u*)pos=0x00a41007; // srav $v0, $a0, $a1 + break; +#if (_MIPS_ISA==MIPS32R2) || defined(PSP) + case t_RORd: + *(Bit32u*)pos=0x00a41046; // rotr $v0, $a0, $a1 + break; +#endif + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit32u*)pos=0x00041023; // subu $v0, $0, $a0 + break; + default: + *(Bit32u*)pos=0x0c000000+((((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func + break; + } +#else + *(Bit32u*)pos=0x0c000000+(((Bit32u)fct_ptr)>>2)&0x3ffffff); // jal simple_func +#endif +} +#endif + +static void cache_block_closing(Bit8u* block_start,Bitu block_size) { +#ifdef PSP +// writeback dcache and invalidate icache + Bit32u inval_start = ((Bit32u)block_start) & ~63; + Bit32u inval_end = (((Bit32u)block_start) + block_size + 64) & ~63; + for (;inval_start < inval_end; inval_start+=64) { + __builtin_allegrex_cache(0x1a, inval_start); + __builtin_allegrex_cache(0x08, inval_start); + } +#endif +} + +static void cache_block_before_close(void) { } + + +#ifdef DRC_USE_SEGS_ADDR + +// mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { +// stub +} + +// mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { +// stub +} + +// add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) +static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { +// stub +} + +#endif + +#ifdef DRC_USE_REGS_ADDR + +// mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { +// stub +} + +// mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { +// stub +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { +// stub +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { +// stub +} + +// move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { +// stub +} + + +// add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { +// stub +} + + +// move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) +static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { +// stub +} + +// move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) +static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { +// stub +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero) +static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { +// stub +} + +// move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR +static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { +// stub +} + +#endif diff --git a/src/cpu/core_dynrec/risc_x64.h b/src/cpu/core_dynrec/risc_x64.h index 5c1e84a..8013785 100644 --- a/src/cpu/core_dynrec/risc_x64.h +++ b/src/cpu/core_dynrec/risc_x64.h @@ -1,681 +1,681 @@ -/* - * Copyright (C) 2002-2009 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: risc_x64.h,v 1.13 2009/06/25 19:31:43 c2woody Exp $ */ - - -// some configuring defines that specify the capabilities of this architecture -// or aspects of the recompiling - -// protect FC_ADDR over function calls if necessaray -// #define DRC_PROTECT_ADDR_REG - -// try to use non-flags generating functions if possible -#define DRC_FLAGS_INVALIDATION -// try to replace _simple functions by code -#define DRC_FLAGS_INVALIDATION_DCODE - -// type with the same size as a pointer -#define DRC_PTR_SIZE_IM Bit64u - -// calling convention modifier -#define DRC_CALL_CONV /* nothing */ -#define DRC_FC /* nothing */ - - -// register mapping -typedef Bit8u HostReg; - -#define HOST_EAX 0 -#define HOST_ECX 1 -#define HOST_EDX 2 -#define HOST_EBX 3 -#define HOST_ESI 6 -#define HOST_EDI 7 - - -// register that holds function return values -#define FC_RETOP HOST_EAX - -// register used for address calculations, if the ABI does not -// state that this register is preserved across function calls -// then define DRC_PROTECT_ADDR_REG above -#define FC_ADDR HOST_EBX - -// register that holds the first parameter -#define FC_OP1 HOST_EDI - -// register that holds the second parameter -#define FC_OP2 HOST_ESI - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_EAX - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_ECX - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_EDX - - -// temporary register for LEA -#define TEMP_REG_DRC HOST_ESI - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - cache_addb(0x8b); // mov reg_dst,reg_src - cache_addb(0xc0+(reg_dst<<3)+reg_src); -} - - -static INLINE void gen_memaddr(HostReg reg,void* data) { - Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+5); - if ((diff<0x80000000LL) && (diff>-0x80000000LL)) { - cache_addb(0x05+(reg<<3)); - // RIP-relative addressing is offset after the instruction - cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL)); - } else if ((Bit64u)data<0x100000000LL) { - cache_addw(0x2504+(reg<<3)); - cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL)); - } else { - E_Exit("DRC64:Unhandled memory reference"); - } -} - - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - if (!dword) cache_addb(0x66); - cache_addb(0x8b); // mov reg,[data] - gen_memaddr(dest_reg,data); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - cache_addb(0x66); - cache_addb(0xb8+dest_reg); // mov reg,imm - cache_addw(imm); -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - cache_addb(0xb8+dest_reg); // mov reg,imm - cache_addd(imm); -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - if (!dword) cache_addb(0x66); - cache_addb(0x89); // mov [data],reg - gen_memaddr(src_reg,dest); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - cache_addb(0x8a); // mov reg,[data] - gen_memaddr(dest_reg,data); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - cache_addb(0x66); - cache_addb(0x8b); // mov reg,[data] - gen_memaddr(dest_reg,data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_addb(0xb0+dest_reg); // mov reg,imm - cache_addb(imm); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - cache_addb(0x66); - cache_addb(0xb8+dest_reg); // mov reg,imm - cache_addw(imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - cache_addb(0x88); // mov [data],reg - gen_memaddr(src_reg,dest); -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - cache_addw(0xb60f+(sign?0x800:0)); // movsx/movzx - cache_addb(0xc0+(reg<<3)+reg); -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - cache_addw(0xb70f+(sign?0x800:0)); // movsx/movzx - cache_addb(0xc0+(reg<<3)+reg); -} - - - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - cache_addb(0x03); // add reg,[data] - gen_memaddr(reg,op); -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - cache_addw(0xc081+(reg<<8)); // add reg,imm - cache_addd(imm); -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - cache_addw(0xe081+(reg<<8)); // and reg,imm - cache_addd(imm); -} - - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - cache_addw(0x04c7); // mov [data],imm - cache_addb(0x25); - cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); - cache_addd(imm); -} - -// move a 64bit constant value into a full register -static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm) { - cache_addb(0x48); - cache_addb(0xb8+dest_reg); // mov dest_reg,imm - cache_addq(imm); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_reg_qword(HOST_EAX,imm); - cache_addb(0x48); - gen_mov_word_from_reg(HOST_EAX,dest,true); -} - - -// add an 8bit constant value to a memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - cache_addw(0x0483); // add [data],imm - cache_addb(0x25); - cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); - cache_addb(imm); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if ((imm<128) && dword) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - if (!dword) cache_addb(0x66); - cache_addw(0x0481); // add [data],imm - cache_addb(0x25); - cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); - if (dword) cache_addd((Bit32u)imm); - else cache_addw((Bit16u)imm); -} - -// subtract an 8bit constant value from a memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - cache_addw(0x2c83); // sub [data],imm - cache_addb(0x25); - cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); - cache_addb(imm); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if ((imm<128) && dword) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - if (!dword) cache_addb(0x66); - cache_addw(0x2c81); // sub [data],imm - cache_addb(0x25); - cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); - if (dword) cache_addd((Bit32u)imm); - else cache_addw((Bit16u)imm); -} - - - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - Bit8u rm_base; - Bitu imm_size; - if (!imm) { - imm_size=0; rm_base=0x0; //no imm - } else if ((imm>=-128 && imm<=127)) { - imm_size=1; rm_base=0x40; //Signed byte imm - } else { - imm_size=4; rm_base=0x80; //Signed dword imm - } - - // ea_reg := ea_reg+scale_reg*(2^scale)+imm - cache_addb(0x48); - cache_addb(0x8d); //LEA - cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator - cache_addb(dest_reg+(scale_reg<<3)+(scale<<6)); - - switch (imm_size) { - case 0: break; - case 1:cache_addb(imm);break; - case 4:cache_addd(imm);break; - } -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - // ea_reg := ea_reg*(2^scale)+imm - // ea_reg := op2 *(2^scale)+imm - cache_addb(0x48); - cache_addb(0x8d); //LEA - cache_addb(0x04+(dest_reg<<3)); - cache_addb(0x05+(dest_reg<<3)+(scale<<6)); - - cache_addd(imm); // always add dword immediate -} - - - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - cache_addb(0x48); - cache_addb(0xb8); // mov reg,imm64 - cache_addq((Bit64u)func); - cache_addw(0xd0ff); -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit64u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - // align the stack - cache_addb(0x48); - cache_addw(0xc48b); // mov rax,rsp - - cache_addb(0x48); - cache_addw(0xec83); // sub rsp,0x08 - cache_addb(0x08); // 0x08==return address pushed onto stack by call - - cache_addb(0x48); - cache_addw(0xe483); // and esp,0xfffffffffffffff0 - cache_addb(0xf0); - - cache_addb(0x48); - cache_addw(0xc483); // add rsp,0x08 - cache_addb(0x08); - - cache_addb(0x50); // push rax (==old rsp) - - Bit64u proc_addr=(Bit64u)cache.pos; - - // Do the actual call to the procedure - cache_addb(0x48); - cache_addb(0xb8); // mov reg,imm64 - cache_addq((Bit64u)func); - - cache_addw(0xd0ff); - - // restore stack - cache_addb(0x5c); // pop rsp - - return proc_addr; -} - - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - // move an immediate 32bit value into a 64bit param reg - switch (param) { - case 0: // mov param1,imm32 - gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm); - break; - case 1: // mov param2,imm32 - gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm); - break; -#if defined (_MSC_VER) - case 2: // mov r8,imm32 - cache_addw(0xb849); - cache_addq((Bit32u)imm); - break; - case 3: // mov r9,imm32 - cache_addw(0xb949); - cache_addq((Bit32u)imm); - break; -#else - case 2: // mov rdx,imm32 - gen_mov_dword_to_reg_imm(HOST_EDX,(Bit32u)imm); - break; - case 3: // mov rcx,imm32 - gen_mov_dword_to_reg_imm(HOST_ECX,(Bit32u)imm); - break; -#endif - default: - E_Exit("I(mm) >4 params unsupported"); - break; - } -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(DRC_PTR_SIZE_IM addr,Bitu param) { - // move an immediate 64bit value into a 64bit param reg - switch (param) { - case 0: // mov param1,addr64 - gen_mov_reg_qword(FC_OP1,addr); - break; - case 1: // mov param2,addr64 - gen_mov_reg_qword(FC_OP2,addr); - break; -#if defined (_MSC_VER) - case 2: // mov r8,addr64 - cache_addw(0xb849); - cache_addq(addr); - break; - case 3: // mov r9,addr64 - cache_addw(0xb949); - cache_addq(addr); - break; -#else - case 2: // mov rdx,addr64 - gen_mov_reg_qword(HOST_EDX,addr); - break; - case 3: // mov rcx,addr64 - gen_mov_reg_qword(HOST_ECX,addr); - break; -#endif - default: - E_Exit("A(ddr) >4 params unsupported"); - break; - } -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - // move a register into a 64bit param reg, {inputregs}!={outputregs} - switch (param) { - case 0: // mov param1,reg&7 - gen_mov_regs(FC_OP1,reg&7); - break; - case 1: // mov param2,reg&7 - gen_mov_regs(FC_OP2,reg&7); - break; -#if defined (_MSC_VER) - case 2: // mov r8,reg&7 - cache_addb(0x49); - gen_mov_regs(0,reg&7); - break; - case 3: // mov r9,reg&7 - cache_addb(0x49); - gen_mov_regs(1,reg&7); - break; -#else - case 2: // mov rdx,reg&7 - gen_mov_regs(HOST_EDX,reg&7); - break; - case 3: // mov rcx,reg&7 - gen_mov_regs(HOST_ECX,reg&7); - break; -#endif - default: - E_Exit("R(eg) >4 params unsupported"); - break; - } -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - // move memory content into a 64bit param reg - switch (param) { - case 0: // mov param1,[mem] - gen_mov_word_to_reg(FC_OP1,(void*)mem,true); - break; - case 1: // mov param2,[mem] - gen_mov_word_to_reg(FC_OP2,(void*)mem,true); - break; -#if defined (_MSC_VER) - case 2: // mov r8,[mem] - cache_addb(0x49); - gen_mov_word_to_reg(0,(void*)mem,true); - break; - case 3: // mov r9,[mem] - cache_addb(0x49); - gen_mov_word_to_reg(1,(void*)mem,true); - break; -#else - case 2: // mov rdx,[mem] - gen_mov_word_to_reg(HOST_EDX,(void*)mem,true); - break; - case 3: // mov rcx,[mem] - gen_mov_word_to_reg(HOST_ECX,(void*)mem,true); - break; -#endif - default: - E_Exit("R(eg) >4 params unsupported"); - break; - } -} - - - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - cache_addw(0xa148); // mov rax,[data] - cache_addq((Bit64u)ptr); - - cache_addb(0xff); // jmp [rax+imm] - if (!imm) { - cache_addb(0x20); - } else if ((imm>=-128 && imm<=127)) { - cache_addb(0x60); - cache_addb(imm); - } else { - cache_addb(0xa0); - cache_addd(imm); - } -} - - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit64u gen_create_branch_on_zero(HostReg reg,bool dword) { - if (!dword) cache_addb(0x66); - cache_addb(0x0b); // or reg,reg - cache_addb(0xc0+reg+(reg<<3)); - - cache_addw(0x0074); // jz addr - return ((Bit64u)cache.pos-1); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit64u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - if (!dword) cache_addb(0x66); - cache_addb(0x0b); // or reg,reg - cache_addb(0xc0+reg+(reg<<3)); - - cache_addw(0x0075); // jnz addr - return ((Bit64u)cache.pos-1); -} - -// calculate relative offset and fill it into the location pointed to by data -static void gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bit64s len=(Bit64u)cache.pos-data; - if (len<0) len=-len; - if (len>126) LOG_MSG("Big jump %d",len); -#endif - *(Bit8u*)data=(Bit8u)((Bit64u)cache.pos-data-1); -} - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit64u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - // isdword: cmp reg32,0 - // not isdword: cmp reg8,0 - cache_addb(0x0a+(isdword?1:0)); // or reg,reg - cache_addb(0xc0+reg+(reg<<3)); - - cache_addw(0x850f); // jnz - cache_addd(0); - return ((Bit64u)cache.pos-4); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit64u gen_create_branch_long_leqzero(HostReg reg) { - cache_addw(0xf883+(reg<<8)); - cache_addb(0x00); // cmp reg,0 - - cache_addw(0x8e0f); // jle - cache_addd(0); - return ((Bit64u)cache.pos-4); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void gen_fill_branch_long(Bit64u data) { - *(Bit32u*)data=(Bit32u)((Bit64u)cache.pos-data-4); -} - - -static void gen_run_code(void) { - cache_addb(0x53); // push rbx - cache_addw(0xd0ff+(FC_OP1<<8)); // call rdi - cache_addb(0x5b); // pop rbx -} - -// return from a function -static void gen_return_function(void) { - cache_addb(0xc3); // ret -} - -#ifdef DRC_FLAGS_INVALIDATION -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { -#ifdef DRC_FLAGS_INVALIDATION_DCODE - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit32u*)(pos+0)=0xf001f889; // mov eax,edi; add eax,esi - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit32u*)(pos+0)=0xf009f889; // mov eax,edi; or eax,esi - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit32u*)(pos+0)=0xf021f889; // mov eax,edi; and eax,esi - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit32u*)(pos+0)=0xf029f889; // mov eax,edi; sub eax,esi - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit32u*)(pos+0)=0xf031f889; // mov eax,edi; xor eax,esi - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit32u*)(pos+0)=0x90900aeb; // skip - *(Bit32u*)(pos+4)=0x90909090; - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit32u*)(pos+0)=0xc0fff889; // mov eax,edi; inc eax - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit32u*)(pos+0)=0xc8fff889; // mov eax,edi; dec eax - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit32u*)(pos+0)=0xd8f7f889; // mov eax,edi; neg eax - *(Bit32u*)(pos+4)=0x909006eb; // skip - *(Bit32u*)(pos+8)=0x90909090; - break; - default: - *(Bit64u*)(pos+2)=(Bit64u)fct_ptr; // fill function pointer - break; - } -#else - *(Bit64u*)(pos+2)=(Bit64u)fct_ptr; -#endif -} -#endif - -static void cache_block_closing(Bit8u* block_start,Bitu block_size) { } - -static void cache_block_before_close(void) { } +/* + * Copyright (C) 2002-2010 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: risc_x64.h,v 1.13 2009-06-25 19:31:43 c2woody Exp $ */ + + +// some configuring defines that specify the capabilities of this architecture +// or aspects of the recompiling + +// protect FC_ADDR over function calls if necessaray +// #define DRC_PROTECT_ADDR_REG + +// try to use non-flags generating functions if possible +#define DRC_FLAGS_INVALIDATION +// try to replace _simple functions by code +#define DRC_FLAGS_INVALIDATION_DCODE + +// type with the same size as a pointer +#define DRC_PTR_SIZE_IM Bit64u + +// calling convention modifier +#define DRC_CALL_CONV /* nothing */ +#define DRC_FC /* nothing */ + + +// register mapping +typedef Bit8u HostReg; + +#define HOST_EAX 0 +#define HOST_ECX 1 +#define HOST_EDX 2 +#define HOST_EBX 3 +#define HOST_ESI 6 +#define HOST_EDI 7 + + +// register that holds function return values +#define FC_RETOP HOST_EAX + +// register used for address calculations, if the ABI does not +// state that this register is preserved across function calls +// then define DRC_PROTECT_ADDR_REG above +#define FC_ADDR HOST_EBX + +// register that holds the first parameter +#define FC_OP1 HOST_EDI + +// register that holds the second parameter +#define FC_OP2 HOST_ESI + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_EAX + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_ECX + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_EDX + + +// temporary register for LEA +#define TEMP_REG_DRC HOST_ESI + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + cache_addb(0x8b); // mov reg_dst,reg_src + cache_addb(0xc0+(reg_dst<<3)+reg_src); +} + + +static INLINE void gen_memaddr(HostReg reg,void* data) { + Bit64s diff = (Bit64s)data-((Bit64s)cache.pos+5); + if ((diff<0x80000000LL) && (diff>-0x80000000LL)) { + cache_addb(0x05+(reg<<3)); + // RIP-relative addressing is offset after the instruction + cache_addd((Bit32u)(((Bit64u)diff)&0xffffffffLL)); + } else if ((Bit64u)data<0x100000000LL) { + cache_addw(0x2504+(reg<<3)); + cache_addd((Bit32u)(((Bit64u)data)&0xffffffffLL)); + } else { + E_Exit("DRC64:Unhandled memory reference"); + } +} + + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + if (!dword) cache_addb(0x66); + cache_addb(0x8b); // mov reg,[data] + gen_memaddr(dest_reg,data); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + cache_addb(0x66); + cache_addb(0xb8+dest_reg); // mov reg,imm + cache_addw(imm); +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + cache_addb(0xb8+dest_reg); // mov reg,imm + cache_addd(imm); +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + if (!dword) cache_addb(0x66); + cache_addb(0x89); // mov [data],reg + gen_memaddr(src_reg,dest); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + cache_addb(0x8a); // mov reg,[data] + gen_memaddr(dest_reg,data); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + cache_addb(0x66); + cache_addb(0x8b); // mov reg,[data] + gen_memaddr(dest_reg,data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_addb(0xb0+dest_reg); // mov reg,imm + cache_addb(imm); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + cache_addb(0x66); + cache_addb(0xb8+dest_reg); // mov reg,imm + cache_addw(imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + cache_addb(0x88); // mov [data],reg + gen_memaddr(src_reg,dest); +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + cache_addw(0xb60f+(sign?0x800:0)); // movsx/movzx + cache_addb(0xc0+(reg<<3)+reg); +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + cache_addw(0xb70f+(sign?0x800:0)); // movsx/movzx + cache_addb(0xc0+(reg<<3)+reg); +} + + + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + cache_addb(0x03); // add reg,[data] + gen_memaddr(reg,op); +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + cache_addw(0xc081+(reg<<8)); // add reg,imm + cache_addd(imm); +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + cache_addw(0xe081+(reg<<8)); // and reg,imm + cache_addd(imm); +} + + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + cache_addw(0x04c7); // mov [data],imm + cache_addb(0x25); + cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); + cache_addd(imm); +} + +// move a 64bit constant value into a full register +static void gen_mov_reg_qword(HostReg dest_reg,Bit64u imm) { + cache_addb(0x48); + cache_addb(0xb8+dest_reg); // mov dest_reg,imm + cache_addq(imm); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_reg_qword(HOST_EAX,imm); + cache_addb(0x48); + gen_mov_word_from_reg(HOST_EAX,dest,true); +} + + +// add an 8bit constant value to a memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + cache_addw(0x0483); // add [data],imm + cache_addb(0x25); + cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); + cache_addb(imm); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if ((imm<128) && dword) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + if (!dword) cache_addb(0x66); + cache_addw(0x0481); // add [data],imm + cache_addb(0x25); + cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); + if (dword) cache_addd((Bit32u)imm); + else cache_addw((Bit16u)imm); +} + +// subtract an 8bit constant value from a memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + cache_addw(0x2c83); // sub [data],imm + cache_addb(0x25); + cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); + cache_addb(imm); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if ((imm<128) && dword) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + if (!dword) cache_addb(0x66); + cache_addw(0x2c81); // sub [data],imm + cache_addb(0x25); + cache_addd((Bit32u)(((Bit64u)dest)&0xffffffffLL)); + if (dword) cache_addd((Bit32u)imm); + else cache_addw((Bit16u)imm); +} + + + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + Bit8u rm_base; + Bitu imm_size; + if (!imm) { + imm_size=0; rm_base=0x0; //no imm + } else if ((imm>=-128 && imm<=127)) { + imm_size=1; rm_base=0x40; //Signed byte imm + } else { + imm_size=4; rm_base=0x80; //Signed dword imm + } + + // ea_reg := ea_reg+scale_reg*(2^scale)+imm + cache_addb(0x48); + cache_addb(0x8d); //LEA + cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator + cache_addb(dest_reg+(scale_reg<<3)+(scale<<6)); + + switch (imm_size) { + case 0: break; + case 1:cache_addb(imm);break; + case 4:cache_addd(imm);break; + } +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + // ea_reg := ea_reg*(2^scale)+imm + // ea_reg := op2 *(2^scale)+imm + cache_addb(0x48); + cache_addb(0x8d); //LEA + cache_addb(0x04+(dest_reg<<3)); + cache_addb(0x05+(dest_reg<<3)+(scale<<6)); + + cache_addd(imm); // always add dword immediate +} + + + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + cache_addb(0x48); + cache_addb(0xb8); // mov reg,imm64 + cache_addq((Bit64u)func); + cache_addw(0xd0ff); +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit64u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + // align the stack + cache_addb(0x48); + cache_addw(0xc48b); // mov rax,rsp + + cache_addb(0x48); + cache_addw(0xec83); // sub rsp,0x08 + cache_addb(0x08); // 0x08==return address pushed onto stack by call + + cache_addb(0x48); + cache_addw(0xe483); // and esp,0xfffffffffffffff0 + cache_addb(0xf0); + + cache_addb(0x48); + cache_addw(0xc483); // add rsp,0x08 + cache_addb(0x08); + + cache_addb(0x50); // push rax (==old rsp) + + Bit64u proc_addr=(Bit64u)cache.pos; + + // Do the actual call to the procedure + cache_addb(0x48); + cache_addb(0xb8); // mov reg,imm64 + cache_addq((Bit64u)func); + + cache_addw(0xd0ff); + + // restore stack + cache_addb(0x5c); // pop rsp + + return proc_addr; +} + + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + // move an immediate 32bit value into a 64bit param reg + switch (param) { + case 0: // mov param1,imm32 + gen_mov_dword_to_reg_imm(FC_OP1,(Bit32u)imm); + break; + case 1: // mov param2,imm32 + gen_mov_dword_to_reg_imm(FC_OP2,(Bit32u)imm); + break; +#if defined (_MSC_VER) + case 2: // mov r8,imm32 + cache_addw(0xb849); + cache_addq((Bit32u)imm); + break; + case 3: // mov r9,imm32 + cache_addw(0xb949); + cache_addq((Bit32u)imm); + break; +#else + case 2: // mov rdx,imm32 + gen_mov_dword_to_reg_imm(HOST_EDX,(Bit32u)imm); + break; + case 3: // mov rcx,imm32 + gen_mov_dword_to_reg_imm(HOST_ECX,(Bit32u)imm); + break; +#endif + default: + E_Exit("I(mm) >4 params unsupported"); + break; + } +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(DRC_PTR_SIZE_IM addr,Bitu param) { + // move an immediate 64bit value into a 64bit param reg + switch (param) { + case 0: // mov param1,addr64 + gen_mov_reg_qword(FC_OP1,addr); + break; + case 1: // mov param2,addr64 + gen_mov_reg_qword(FC_OP2,addr); + break; +#if defined (_MSC_VER) + case 2: // mov r8,addr64 + cache_addw(0xb849); + cache_addq(addr); + break; + case 3: // mov r9,addr64 + cache_addw(0xb949); + cache_addq(addr); + break; +#else + case 2: // mov rdx,addr64 + gen_mov_reg_qword(HOST_EDX,addr); + break; + case 3: // mov rcx,addr64 + gen_mov_reg_qword(HOST_ECX,addr); + break; +#endif + default: + E_Exit("A(ddr) >4 params unsupported"); + break; + } +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + // move a register into a 64bit param reg, {inputregs}!={outputregs} + switch (param) { + case 0: // mov param1,reg&7 + gen_mov_regs(FC_OP1,reg&7); + break; + case 1: // mov param2,reg&7 + gen_mov_regs(FC_OP2,reg&7); + break; +#if defined (_MSC_VER) + case 2: // mov r8,reg&7 + cache_addb(0x49); + gen_mov_regs(0,reg&7); + break; + case 3: // mov r9,reg&7 + cache_addb(0x49); + gen_mov_regs(1,reg&7); + break; +#else + case 2: // mov rdx,reg&7 + gen_mov_regs(HOST_EDX,reg&7); + break; + case 3: // mov rcx,reg&7 + gen_mov_regs(HOST_ECX,reg&7); + break; +#endif + default: + E_Exit("R(eg) >4 params unsupported"); + break; + } +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + // move memory content into a 64bit param reg + switch (param) { + case 0: // mov param1,[mem] + gen_mov_word_to_reg(FC_OP1,(void*)mem,true); + break; + case 1: // mov param2,[mem] + gen_mov_word_to_reg(FC_OP2,(void*)mem,true); + break; +#if defined (_MSC_VER) + case 2: // mov r8,[mem] + cache_addb(0x49); + gen_mov_word_to_reg(0,(void*)mem,true); + break; + case 3: // mov r9,[mem] + cache_addb(0x49); + gen_mov_word_to_reg(1,(void*)mem,true); + break; +#else + case 2: // mov rdx,[mem] + gen_mov_word_to_reg(HOST_EDX,(void*)mem,true); + break; + case 3: // mov rcx,[mem] + gen_mov_word_to_reg(HOST_ECX,(void*)mem,true); + break; +#endif + default: + E_Exit("R(eg) >4 params unsupported"); + break; + } +} + + + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + cache_addw(0xa148); // mov rax,[data] + cache_addq((Bit64u)ptr); + + cache_addb(0xff); // jmp [rax+imm] + if (!imm) { + cache_addb(0x20); + } else if ((imm>=-128 && imm<=127)) { + cache_addb(0x60); + cache_addb(imm); + } else { + cache_addb(0xa0); + cache_addd(imm); + } +} + + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit64u gen_create_branch_on_zero(HostReg reg,bool dword) { + if (!dword) cache_addb(0x66); + cache_addb(0x0b); // or reg,reg + cache_addb(0xc0+reg+(reg<<3)); + + cache_addw(0x0074); // jz addr + return ((Bit64u)cache.pos-1); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit64u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + if (!dword) cache_addb(0x66); + cache_addb(0x0b); // or reg,reg + cache_addb(0xc0+reg+(reg<<3)); + + cache_addw(0x0075); // jnz addr + return ((Bit64u)cache.pos-1); +} + +// calculate relative offset and fill it into the location pointed to by data +static void gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bit64s len=(Bit64u)cache.pos-data; + if (len<0) len=-len; + if (len>126) LOG_MSG("Big jump %d",len); +#endif + *(Bit8u*)data=(Bit8u)((Bit64u)cache.pos-data-1); +} + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit64u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + // isdword: cmp reg32,0 + // not isdword: cmp reg8,0 + cache_addb(0x0a+(isdword?1:0)); // or reg,reg + cache_addb(0xc0+reg+(reg<<3)); + + cache_addw(0x850f); // jnz + cache_addd(0); + return ((Bit64u)cache.pos-4); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit64u gen_create_branch_long_leqzero(HostReg reg) { + cache_addw(0xf883+(reg<<8)); + cache_addb(0x00); // cmp reg,0 + + cache_addw(0x8e0f); // jle + cache_addd(0); + return ((Bit64u)cache.pos-4); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void gen_fill_branch_long(Bit64u data) { + *(Bit32u*)data=(Bit32u)((Bit64u)cache.pos-data-4); +} + + +static void gen_run_code(void) { + cache_addb(0x53); // push rbx + cache_addw(0xd0ff+(FC_OP1<<8)); // call rdi + cache_addb(0x5b); // pop rbx +} + +// return from a function +static void gen_return_function(void) { + cache_addb(0xc3); // ret +} + +#ifdef DRC_FLAGS_INVALIDATION +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { +#ifdef DRC_FLAGS_INVALIDATION_DCODE + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit32u*)(pos+0)=0xf001f889; // mov eax,edi; add eax,esi + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit32u*)(pos+0)=0xf009f889; // mov eax,edi; or eax,esi + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit32u*)(pos+0)=0xf021f889; // mov eax,edi; and eax,esi + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit32u*)(pos+0)=0xf029f889; // mov eax,edi; sub eax,esi + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit32u*)(pos+0)=0xf031f889; // mov eax,edi; xor eax,esi + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit32u*)(pos+0)=0x90900aeb; // skip + *(Bit32u*)(pos+4)=0x90909090; + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit32u*)(pos+0)=0xc0fff889; // mov eax,edi; inc eax + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit32u*)(pos+0)=0xc8fff889; // mov eax,edi; dec eax + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit32u*)(pos+0)=0xd8f7f889; // mov eax,edi; neg eax + *(Bit32u*)(pos+4)=0x909006eb; // skip + *(Bit32u*)(pos+8)=0x90909090; + break; + default: + *(Bit64u*)(pos+2)=(Bit64u)fct_ptr; // fill function pointer + break; + } +#else + *(Bit64u*)(pos+2)=(Bit64u)fct_ptr; +#endif +} +#endif + +static void cache_block_closing(Bit8u* block_start,Bitu block_size) { } + +static void cache_block_before_close(void) { } diff --git a/src/cpu/core_dynrec/risc_x86.h b/src/cpu/core_dynrec/risc_x86.h index 126cdf9..4ebe906 100644 --- a/src/cpu/core_dynrec/risc_x86.h +++ b/src/cpu/core_dynrec/risc_x86.h @@ -1,517 +1,517 @@ -/* - * Copyright (C) 2002-2009 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: risc_x86.h,v 1.10 2009/06/25 19:31:43 c2woody Exp $ */ - - -// some configuring defines that specify the capabilities of this architecture -// or aspects of the recompiling - -// protect FC_ADDR over function calls if necessaray -// #define DRC_PROTECT_ADDR_REG - -// try to use non-flags generating functions if possible -#define DRC_FLAGS_INVALIDATION -// try to replace _simple functions by code -#define DRC_FLAGS_INVALIDATION_DCODE - -// type with the same size as a pointer -#define DRC_PTR_SIZE_IM Bit32u - -// calling convention modifier -#if defined (WIN32) -#define DRC_CALL_CONV _fastcall -#define DRC_FC /* nothing */ -#else -#define DRC_CALL_CONV /* nothing */ -#define DRC_FC GCC_ATTRIBUTE(fastcall) -#endif - - -// register mapping -enum HostReg { - HOST_EAX=0, - HOST_ECX, - HOST_EDX, - HOST_EBX, - HOST_ESP, - HOST_EBP, - HOST_ESI, - HOST_EDI -}; - - -// register that holds function return values -#define FC_RETOP HOST_EAX - -// register used for address calculations, if the ABI does not -// state that this register is preserved across function calls -// then define DRC_PROTECT_ADDR_REG above -#define FC_ADDR HOST_EBX - -// register that holds the first parameter -#define FC_OP1 HOST_ECX - -// register that holds the second parameter -#define FC_OP2 HOST_EDX - -// special register that holds the third parameter for _R3 calls (byte accessible) -#define FC_OP3 HOST_EAX - -// register that holds byte-accessible temporary values -#define FC_TMP_BA1 HOST_ECX - -// register that holds byte-accessible temporary values -#define FC_TMP_BA2 HOST_EDX - - -// temporary register for LEA -#define TEMP_REG_DRC HOST_ESI - - -// move a full register from reg_src to reg_dst -static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { - cache_addb(0x8b); // mov reg_dst,reg_src - cache_addb(0xc0+(reg_dst<<3)+reg_src); -} - -// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg -// 16bit moves may destroy the upper 16bit of the destination register -static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { - if (!dword) cache_addb(0x66); - cache_addw(0x058b+(dest_reg<<11)); // mov reg,[data] - cache_addd((Bit32u)data); -} - -// move a 16bit constant value into dest_reg -// the upper 16bit of the destination register may be destroyed -static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { - cache_addb(0x66); - cache_addb(0xb8+dest_reg); // mov reg,imm - cache_addw(imm); -} - -// move a 32bit constant value into dest_reg -static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { - cache_addb(0xb8+dest_reg); // mov reg,imm - cache_addd(imm); -} - -// move 32bit (dword==true) or 16bit (dword==false) of a register into memory -static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { - if (!dword) cache_addb(0x66); - cache_addw(0x0589+(src_reg<<11)); // mov [data],reg - cache_addd((Bit32u)dest); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { - cache_addw(0x058a+(dest_reg<<11)); // mov reg,[data] - cache_addd((Bit32u)data); -} - -// move an 8bit value from memory into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { - cache_addb(0x66); - cache_addw(0x058b+(dest_reg<<11)); // mov reg,[data] - cache_addd((Bit32u)data); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function does not use FC_OP1/FC_OP2 as dest_reg as these -// registers might not be directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { - cache_addb(0xb0+dest_reg); // mov reg,imm - cache_addb(imm); -} - -// move an 8bit constant value into dest_reg -// the upper 24bit of the destination register can be destroyed -// this function can use FC_OP1/FC_OP2 as dest_reg which are -// not directly byte-accessible on some architectures -static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { - cache_addb(0x66); - cache_addb(0xb8+dest_reg); // mov reg,imm - cache_addw(imm); -} - -// move the lowest 8bit of a register into memory -static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { - cache_addw(0x0588+(src_reg<<11)); // mov [data],reg - cache_addd((Bit32u)dest); -} - - - -// convert an 8bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_byte(bool sign,HostReg reg) { - cache_addw(0xb60f+(sign?0x800:0)); // movsx/movzx - cache_addb(0xc0+(reg<<3)+reg); -} - -// convert a 16bit word to a 32bit dword -// the register is zero-extended (sign==false) or sign-extended (sign==true) -static void gen_extend_word(bool sign,HostReg reg) { - cache_addw(0xb70f+(sign?0x800:0)); // movsx/movzx - cache_addb(0xc0+(reg<<3)+reg); -} - - - -// add a 32bit value from memory to a full register -static void gen_add(HostReg reg,void* op) { - cache_addw(0x0503+(reg<<11)); // add reg,[data] - cache_addd((Bit32u)op); -} - -// add a 32bit constant value to a full register -static void gen_add_imm(HostReg reg,Bit32u imm) { - cache_addw(0xc081+(reg<<8)); // add reg,imm - cache_addd(imm); -} - -// and a 32bit constant value with a full register -static void gen_and_imm(HostReg reg,Bit32u imm) { - cache_addw(0xe081+(reg<<8)); // and reg,imm - cache_addd(imm); -} - - - -// move a 32bit constant value into memory -static void gen_mov_direct_dword(void* dest,Bit32u imm) { - cache_addw(0x05c7); // mov [data],imm - cache_addd((Bit32u)dest); - cache_addd(imm); -} - -// move an address into memory -static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { - gen_mov_direct_dword(dest,(Bit32u)imm); -} - - -// add an 8bit constant value to a memory value -static void gen_add_direct_byte(void* dest,Bit8s imm) { - cache_addw(0x0583); // add [data],imm - cache_addd((Bit32u)dest); - cache_addb(imm); -} - -// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value -static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { - if ((imm<128) && dword) { - gen_add_direct_byte(dest,(Bit8s)imm); - return; - } - if (!dword) cache_addb(0x66); - cache_addw(0x0581); // add [data],imm - cache_addd((Bit32u)dest); - if (dword) cache_addd((Bit32u)imm); - else cache_addw((Bit16u)imm); -} - -// subtract an 8bit constant value from a memory value -static void gen_sub_direct_byte(void* dest,Bit8s imm) { - cache_addw(0x2d83); // sub [data],imm - cache_addd((Bit32u)dest); - cache_addb(imm); -} - -// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value -static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { - if ((imm<128) && dword) { - gen_sub_direct_byte(dest,(Bit8s)imm); - return; - } - if (!dword) cache_addb(0x66); - cache_addw(0x2d81); // sub [data],imm - cache_addd((Bit32u)dest); - if (dword) cache_addd((Bit32u)imm); - else cache_addw((Bit16u)imm); -} - - - -// effective address calculation, destination is dest_reg -// scale_reg is scaled by scale (scale_reg*(2^scale)) and -// added to dest_reg, then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { - Bit8u rm_base; - Bitu imm_size; - if (!imm) { - imm_size=0; rm_base=0x0; //no imm - } else if ((imm>=-128 && imm<=127)) { - imm_size=1; rm_base=0x40; //Signed byte imm - } else { - imm_size=4; rm_base=0x80; //Signed dword imm - } - - // ea_reg := ea_reg+scale_reg*(2^scale)+imm - cache_addb(0x8d); //LEA - cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator - cache_addb(dest_reg+(scale_reg<<3)+(scale<<6)); - - switch (imm_size) { - case 0: break; - case 1:cache_addb(imm);break; - case 4:cache_addd(imm);break; - } -} - -// effective address calculation, destination is dest_reg -// dest_reg is scaled by scale (dest_reg*(2^scale)), -// then the immediate value is added -static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { - // ea_reg := ea_reg*(2^scale)+imm - // ea_reg := op2 *(2^scale)+imm - cache_addb(0x8d); //LEA - cache_addb(0x04+(dest_reg<<3)); - cache_addb(0x05+(dest_reg<<3)+(scale<<6)); - - cache_addd(imm); // always add dword immediate -} - - - -// generate a call to a parameterless function -static void INLINE gen_call_function_raw(void * func) { - cache_addb(0xe8); - cache_addd((Bit32u)func - (Bit32u)cache.pos-4); -} - -// generate a call to a function with paramcount parameters -// note: the parameters are loaded in the architecture specific way -// using the gen_load_param_ functions below -static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { - Bit32u proc_addr=(Bit32u)cache.pos; - // Do the actual call to the procedure - cache_addb(0xe8); - cache_addd((Bit32u)func - (Bit32u)cache.pos-4); - - // Restore the params of the stack - if (paramcount) { - cache_addw(0xc483); //add ESP,imm byte - cache_addb((!fastcall)?paramcount*4:0); - } - return proc_addr; -} - - -// load an immediate value as param'th function parameter -static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { - cache_addb(0x68); // push immediate - cache_addd(imm); -} - -// load an address as param'th function parameter -static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { - cache_addb(0x68); // push immediate (address) - cache_addd(addr); -} - -// load a host-register as param'th function parameter -static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { - cache_addb(0x50+(reg&7)); // push reg -} - -// load a value from memory as param'th function parameter -static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { - cache_addw(0x35ff); // push [] - cache_addd(mem); -} - - - -// jump to an address pointed at by ptr, offset is in imm -static void gen_jmp_ptr(void * ptr,Bits imm=0) { - gen_mov_word_to_reg(HOST_EAX,ptr,true); - cache_addb(0xff); // jmp [eax+imm] - if (!imm) { - cache_addb(0x20); - } else if ((imm>=-128 && imm<=127)) { - cache_addb(0x60); - cache_addb(imm); - } else { - cache_addb(0xa0); - cache_addd(imm); - } -} - - -// short conditional jump (+-127 bytes) if register is zero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { - if (!dword) cache_addb(0x66); - cache_addb(0x0b); // or reg,reg - cache_addb(0xc0+reg+(reg<<3)); - - cache_addw(0x0074); // jz addr - return ((Bit32u)cache.pos-1); -} - -// short conditional jump (+-127 bytes) if register is nonzero -// the destination is set by gen_fill_branch() later -static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { - if (!dword) cache_addb(0x66); - cache_addb(0x0b); // or reg,reg - cache_addb(0xc0+reg+(reg<<3)); - - cache_addw(0x0075); // jnz addr - return ((Bit32u)cache.pos-1); -} - -// calculate relative offset and fill it into the location pointed to by data -static void gen_fill_branch(DRC_PTR_SIZE_IM data) { -#if C_DEBUG - Bits len=(Bit32u)cache.pos-data; - if (len<0) len=-len; - if (len>126) LOG_MSG("Big jump %d",len); -#endif - *(Bit8u*)data=(Bit8u)((Bit32u)cache.pos-data-1); -} - -// conditional jump if register is nonzero -// for isdword==true the 32bit of the register are tested -// for isdword==false the lowest 8bit of the register are tested -static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { - // isdword: cmp reg32,0 - // not isdword: cmp reg8,0 - cache_addb(0x0a+(isdword?1:0)); // or reg,reg - cache_addb(0xc0+reg+(reg<<3)); - - cache_addw(0x850f); // jnz - cache_addd(0); - return ((Bit32u)cache.pos-4); -} - -// compare 32bit-register against zero and jump if value less/equal than zero -static Bit32u gen_create_branch_long_leqzero(HostReg reg) { - cache_addw(0xf883+(reg<<8)); - cache_addb(0x00); // cmp reg,0 - - cache_addw(0x8e0f); // jle - cache_addd(0); - return ((Bit32u)cache.pos-4); -} - -// calculate long relative offset and fill it into the location pointed to by data -static void gen_fill_branch_long(Bit32u data) { - *(Bit32u*)data=((Bit32u)cache.pos-data-4); -} - - -static void gen_run_code(void) { - cache_addd(0x0424448b); // mov eax,[esp+4] - cache_addb(0x53); // push ebx - cache_addb(0x56); // push esi - cache_addw(0xd0ff); // call eax - cache_addb(0x5e); // pop esi - cache_addb(0x5b); // pop ebx -} - -// return from a function -static void gen_return_function(void) { - cache_addb(0xc3); // ret -} - -#ifdef DRC_FLAGS_INVALIDATION -// called when a call to a function can be replaced by a -// call to a simpler function -static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { -#ifdef DRC_FLAGS_INVALIDATION_DCODE - // try to avoid function calls but rather directly fill in code - switch (flags_type) { - case t_ADDb: - case t_ADDw: - case t_ADDd: - *(Bit32u*)pos=0xc203c18b; // mov eax,ecx; add eax,edx - *(pos+4)=0x90; - break; - case t_ORb: - case t_ORw: - case t_ORd: - *(Bit32u*)pos=0xc20bc18b; // mov eax,ecx; or eax,edx - *(pos+4)=0x90; - break; - case t_ANDb: - case t_ANDw: - case t_ANDd: - *(Bit32u*)pos=0xc223c18b; // mov eax,ecx; and eax,edx - *(pos+4)=0x90; - break; - case t_SUBb: - case t_SUBw: - case t_SUBd: - *(Bit32u*)pos=0xc22bc18b; // mov eax,ecx; sub eax,edx - *(pos+4)=0x90; - break; - case t_XORb: - case t_XORw: - case t_XORd: - *(Bit32u*)pos=0xc233c18b; // mov eax,ecx; xor eax,edx - *(pos+4)=0x90; - break; - case t_CMPb: - case t_CMPw: - case t_CMPd: - case t_TESTb: - case t_TESTw: - case t_TESTd: - *(Bit32u*)pos=0x909003eb; // skip - *(pos+4)=0x90; - break; - case t_INCb: - case t_INCw: - case t_INCd: - *(Bit32u*)pos=0x9040c18b; // mov eax,ecx; inc eax - *(pos+4)=0x90; - break; - case t_DECb: - case t_DECw: - case t_DECd: - *(Bit32u*)pos=0x9048c18b; // mov eax,ecx; dec eax - *(pos+4)=0x90; - break; - case t_NEGb: - case t_NEGw: - case t_NEGd: - *(Bit32u*)pos=0xd8f7c18b; // mov eax,ecx; neg eax - *(pos+4)=0x90; - break; - default: - *(Bit32u*)(pos+1)=(Bit32u)((Bit8u*)fct_ptr - (pos+1+4)); // fill function pointer - break; - } -#else - *(Bit32u*)(pos+1)=(Bit32u)((Bit8u*)fct_ptr - (pos+1+4)); // fill function pointer -#endif -} -#endif - -static void cache_block_closing(Bit8u* block_start,Bitu block_size) { } - -static void cache_block_before_close(void) { } +/* + * Copyright (C) 2002-2010 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: risc_x86.h,v 1.10 2009-06-25 19:31:43 c2woody Exp $ */ + + +// some configuring defines that specify the capabilities of this architecture +// or aspects of the recompiling + +// protect FC_ADDR over function calls if necessaray +// #define DRC_PROTECT_ADDR_REG + +// try to use non-flags generating functions if possible +#define DRC_FLAGS_INVALIDATION +// try to replace _simple functions by code +#define DRC_FLAGS_INVALIDATION_DCODE + +// type with the same size as a pointer +#define DRC_PTR_SIZE_IM Bit32u + +// calling convention modifier +#if defined (WIN32) +#define DRC_CALL_CONV _fastcall +#define DRC_FC /* nothing */ +#else +#define DRC_CALL_CONV /* nothing */ +#define DRC_FC GCC_ATTRIBUTE(fastcall) +#endif + + +// register mapping +enum HostReg { + HOST_EAX=0, + HOST_ECX, + HOST_EDX, + HOST_EBX, + HOST_ESP, + HOST_EBP, + HOST_ESI, + HOST_EDI +}; + + +// register that holds function return values +#define FC_RETOP HOST_EAX + +// register used for address calculations, if the ABI does not +// state that this register is preserved across function calls +// then define DRC_PROTECT_ADDR_REG above +#define FC_ADDR HOST_EBX + +// register that holds the first parameter +#define FC_OP1 HOST_ECX + +// register that holds the second parameter +#define FC_OP2 HOST_EDX + +// special register that holds the third parameter for _R3 calls (byte accessible) +#define FC_OP3 HOST_EAX + +// register that holds byte-accessible temporary values +#define FC_TMP_BA1 HOST_ECX + +// register that holds byte-accessible temporary values +#define FC_TMP_BA2 HOST_EDX + + +// temporary register for LEA +#define TEMP_REG_DRC HOST_ESI + + +// move a full register from reg_src to reg_dst +static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { + cache_addb(0x8b); // mov reg_dst,reg_src + cache_addb(0xc0+(reg_dst<<3)+reg_src); +} + +// move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg +// 16bit moves may destroy the upper 16bit of the destination register +static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { + if (!dword) cache_addb(0x66); + cache_addw(0x058b+(dest_reg<<11)); // mov reg,[data] + cache_addd((Bit32u)data); +} + +// move a 16bit constant value into dest_reg +// the upper 16bit of the destination register may be destroyed +static void gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { + cache_addb(0x66); + cache_addb(0xb8+dest_reg); // mov reg,imm + cache_addw(imm); +} + +// move a 32bit constant value into dest_reg +static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { + cache_addb(0xb8+dest_reg); // mov reg,imm + cache_addd(imm); +} + +// move 32bit (dword==true) or 16bit (dword==false) of a register into memory +static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { + if (!dword) cache_addb(0x66); + cache_addw(0x0589+(src_reg<<11)); // mov [data],reg + cache_addd((Bit32u)dest); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { + cache_addw(0x058a+(dest_reg<<11)); // mov reg,[data] + cache_addd((Bit32u)data); +} + +// move an 8bit value from memory into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { + cache_addb(0x66); + cache_addw(0x058b+(dest_reg<<11)); // mov reg,[data] + cache_addd((Bit32u)data); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function does not use FC_OP1/FC_OP2 as dest_reg as these +// registers might not be directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { + cache_addb(0xb0+dest_reg); // mov reg,imm + cache_addb(imm); +} + +// move an 8bit constant value into dest_reg +// the upper 24bit of the destination register can be destroyed +// this function can use FC_OP1/FC_OP2 as dest_reg which are +// not directly byte-accessible on some architectures +static void gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { + cache_addb(0x66); + cache_addb(0xb8+dest_reg); // mov reg,imm + cache_addw(imm); +} + +// move the lowest 8bit of a register into memory +static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { + cache_addw(0x0588+(src_reg<<11)); // mov [data],reg + cache_addd((Bit32u)dest); +} + + + +// convert an 8bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_byte(bool sign,HostReg reg) { + cache_addw(0xb60f+(sign?0x800:0)); // movsx/movzx + cache_addb(0xc0+(reg<<3)+reg); +} + +// convert a 16bit word to a 32bit dword +// the register is zero-extended (sign==false) or sign-extended (sign==true) +static void gen_extend_word(bool sign,HostReg reg) { + cache_addw(0xb70f+(sign?0x800:0)); // movsx/movzx + cache_addb(0xc0+(reg<<3)+reg); +} + + + +// add a 32bit value from memory to a full register +static void gen_add(HostReg reg,void* op) { + cache_addw(0x0503+(reg<<11)); // add reg,[data] + cache_addd((Bit32u)op); +} + +// add a 32bit constant value to a full register +static void gen_add_imm(HostReg reg,Bit32u imm) { + cache_addw(0xc081+(reg<<8)); // add reg,imm + cache_addd(imm); +} + +// and a 32bit constant value with a full register +static void gen_and_imm(HostReg reg,Bit32u imm) { + cache_addw(0xe081+(reg<<8)); // and reg,imm + cache_addd(imm); +} + + + +// move a 32bit constant value into memory +static void gen_mov_direct_dword(void* dest,Bit32u imm) { + cache_addw(0x05c7); // mov [data],imm + cache_addd((Bit32u)dest); + cache_addd(imm); +} + +// move an address into memory +static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { + gen_mov_direct_dword(dest,(Bit32u)imm); +} + + +// add an 8bit constant value to a memory value +static void gen_add_direct_byte(void* dest,Bit8s imm) { + cache_addw(0x0583); // add [data],imm + cache_addd((Bit32u)dest); + cache_addb(imm); +} + +// add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value +static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { + if ((imm<128) && dword) { + gen_add_direct_byte(dest,(Bit8s)imm); + return; + } + if (!dword) cache_addb(0x66); + cache_addw(0x0581); // add [data],imm + cache_addd((Bit32u)dest); + if (dword) cache_addd((Bit32u)imm); + else cache_addw((Bit16u)imm); +} + +// subtract an 8bit constant value from a memory value +static void gen_sub_direct_byte(void* dest,Bit8s imm) { + cache_addw(0x2d83); // sub [data],imm + cache_addd((Bit32u)dest); + cache_addb(imm); +} + +// subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value +static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { + if ((imm<128) && dword) { + gen_sub_direct_byte(dest,(Bit8s)imm); + return; + } + if (!dword) cache_addb(0x66); + cache_addw(0x2d81); // sub [data],imm + cache_addd((Bit32u)dest); + if (dword) cache_addd((Bit32u)imm); + else cache_addw((Bit16u)imm); +} + + + +// effective address calculation, destination is dest_reg +// scale_reg is scaled by scale (scale_reg*(2^scale)) and +// added to dest_reg, then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { + Bit8u rm_base; + Bitu imm_size; + if (!imm) { + imm_size=0; rm_base=0x0; //no imm + } else if ((imm>=-128 && imm<=127)) { + imm_size=1; rm_base=0x40; //Signed byte imm + } else { + imm_size=4; rm_base=0x80; //Signed dword imm + } + + // ea_reg := ea_reg+scale_reg*(2^scale)+imm + cache_addb(0x8d); //LEA + cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator + cache_addb(dest_reg+(scale_reg<<3)+(scale<<6)); + + switch (imm_size) { + case 0: break; + case 1:cache_addb(imm);break; + case 4:cache_addd(imm);break; + } +} + +// effective address calculation, destination is dest_reg +// dest_reg is scaled by scale (dest_reg*(2^scale)), +// then the immediate value is added +static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { + // ea_reg := ea_reg*(2^scale)+imm + // ea_reg := op2 *(2^scale)+imm + cache_addb(0x8d); //LEA + cache_addb(0x04+(dest_reg<<3)); + cache_addb(0x05+(dest_reg<<3)+(scale<<6)); + + cache_addd(imm); // always add dword immediate +} + + + +// generate a call to a parameterless function +static void INLINE gen_call_function_raw(void * func) { + cache_addb(0xe8); + cache_addd((Bit32u)func - (Bit32u)cache.pos-4); +} + +// generate a call to a function with paramcount parameters +// note: the parameters are loaded in the architecture specific way +// using the gen_load_param_ functions below +static Bit32u INLINE gen_call_function_setup(void * func,Bitu paramcount,bool fastcall=false) { + Bit32u proc_addr=(Bit32u)cache.pos; + // Do the actual call to the procedure + cache_addb(0xe8); + cache_addd((Bit32u)func - (Bit32u)cache.pos-4); + + // Restore the params of the stack + if (paramcount) { + cache_addw(0xc483); //add ESP,imm byte + cache_addb((!fastcall)?paramcount*4:0); + } + return proc_addr; +} + + +// load an immediate value as param'th function parameter +static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { + cache_addb(0x68); // push immediate + cache_addd(imm); +} + +// load an address as param'th function parameter +static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { + cache_addb(0x68); // push immediate (address) + cache_addd(addr); +} + +// load a host-register as param'th function parameter +static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { + cache_addb(0x50+(reg&7)); // push reg +} + +// load a value from memory as param'th function parameter +static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { + cache_addw(0x35ff); // push [] + cache_addd(mem); +} + + + +// jump to an address pointed at by ptr, offset is in imm +static void gen_jmp_ptr(void * ptr,Bits imm=0) { + gen_mov_word_to_reg(HOST_EAX,ptr,true); + cache_addb(0xff); // jmp [eax+imm] + if (!imm) { + cache_addb(0x20); + } else if ((imm>=-128 && imm<=127)) { + cache_addb(0x60); + cache_addb(imm); + } else { + cache_addb(0xa0); + cache_addd(imm); + } +} + + +// short conditional jump (+-127 bytes) if register is zero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { + if (!dword) cache_addb(0x66); + cache_addb(0x0b); // or reg,reg + cache_addb(0xc0+reg+(reg<<3)); + + cache_addw(0x0074); // jz addr + return ((Bit32u)cache.pos-1); +} + +// short conditional jump (+-127 bytes) if register is nonzero +// the destination is set by gen_fill_branch() later +static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { + if (!dword) cache_addb(0x66); + cache_addb(0x0b); // or reg,reg + cache_addb(0xc0+reg+(reg<<3)); + + cache_addw(0x0075); // jnz addr + return ((Bit32u)cache.pos-1); +} + +// calculate relative offset and fill it into the location pointed to by data +static void gen_fill_branch(DRC_PTR_SIZE_IM data) { +#if C_DEBUG + Bits len=(Bit32u)cache.pos-data; + if (len<0) len=-len; + if (len>126) LOG_MSG("Big jump %d",len); +#endif + *(Bit8u*)data=(Bit8u)((Bit32u)cache.pos-data-1); +} + +// conditional jump if register is nonzero +// for isdword==true the 32bit of the register are tested +// for isdword==false the lowest 8bit of the register are tested +static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { + // isdword: cmp reg32,0 + // not isdword: cmp reg8,0 + cache_addb(0x0a+(isdword?1:0)); // or reg,reg + cache_addb(0xc0+reg+(reg<<3)); + + cache_addw(0x850f); // jnz + cache_addd(0); + return ((Bit32u)cache.pos-4); +} + +// compare 32bit-register against zero and jump if value less/equal than zero +static Bit32u gen_create_branch_long_leqzero(HostReg reg) { + cache_addw(0xf883+(reg<<8)); + cache_addb(0x00); // cmp reg,0 + + cache_addw(0x8e0f); // jle + cache_addd(0); + return ((Bit32u)cache.pos-4); +} + +// calculate long relative offset and fill it into the location pointed to by data +static void gen_fill_branch_long(Bit32u data) { + *(Bit32u*)data=((Bit32u)cache.pos-data-4); +} + + +static void gen_run_code(void) { + cache_addd(0x0424448b); // mov eax,[esp+4] + cache_addb(0x53); // push ebx + cache_addb(0x56); // push esi + cache_addw(0xd0ff); // call eax + cache_addb(0x5e); // pop esi + cache_addb(0x5b); // pop ebx +} + +// return from a function +static void gen_return_function(void) { + cache_addb(0xc3); // ret +} + +#ifdef DRC_FLAGS_INVALIDATION +// called when a call to a function can be replaced by a +// call to a simpler function +static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { +#ifdef DRC_FLAGS_INVALIDATION_DCODE + // try to avoid function calls but rather directly fill in code + switch (flags_type) { + case t_ADDb: + case t_ADDw: + case t_ADDd: + *(Bit32u*)pos=0xc203c18b; // mov eax,ecx; add eax,edx + *(pos+4)=0x90; + break; + case t_ORb: + case t_ORw: + case t_ORd: + *(Bit32u*)pos=0xc20bc18b; // mov eax,ecx; or eax,edx + *(pos+4)=0x90; + break; + case t_ANDb: + case t_ANDw: + case t_ANDd: + *(Bit32u*)pos=0xc223c18b; // mov eax,ecx; and eax,edx + *(pos+4)=0x90; + break; + case t_SUBb: + case t_SUBw: + case t_SUBd: + *(Bit32u*)pos=0xc22bc18b; // mov eax,ecx; sub eax,edx + *(pos+4)=0x90; + break; + case t_XORb: + case t_XORw: + case t_XORd: + *(Bit32u*)pos=0xc233c18b; // mov eax,ecx; xor eax,edx + *(pos+4)=0x90; + break; + case t_CMPb: + case t_CMPw: + case t_CMPd: + case t_TESTb: + case t_TESTw: + case t_TESTd: + *(Bit32u*)pos=0x909003eb; // skip + *(pos+4)=0x90; + break; + case t_INCb: + case t_INCw: + case t_INCd: + *(Bit32u*)pos=0x9040c18b; // mov eax,ecx; inc eax + *(pos+4)=0x90; + break; + case t_DECb: + case t_DECw: + case t_DECd: + *(Bit32u*)pos=0x9048c18b; // mov eax,ecx; dec eax + *(pos+4)=0x90; + break; + case t_NEGb: + case t_NEGw: + case t_NEGd: + *(Bit32u*)pos=0xd8f7c18b; // mov eax,ecx; neg eax + *(pos+4)=0x90; + break; + default: + *(Bit32u*)(pos+1)=(Bit32u)((Bit8u*)fct_ptr - (pos+1+4)); // fill function pointer + break; + } +#else + *(Bit32u*)(pos+1)=(Bit32u)((Bit8u*)fct_ptr - (pos+1+4)); // fill function pointer +#endif +} +#endif + +static void cache_block_closing(Bit8u* block_start,Bitu block_size) { } + +static void cache_block_before_close(void) { } diff --git a/src/cpu/core_full.cpp b/src/cpu/core_full.cpp index b827357..4299dc7 100644 --- a/src/cpu/core_full.cpp +++ b/src/cpu/core_full.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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.cpp b/src/cpu/core_normal.cpp index 4fd1a78..7f3b25b 100644 --- a/src/cpu/core_normal.cpp +++ b/src/cpu/core_normal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/helpers.h b/src/cpu/core_normal/helpers.h index 06fc3fb..f0fb75c 100644 --- a/src/cpu/core_normal/helpers.h +++ b/src/cpu/core_normal/helpers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 b234023..1c191b5 100644 --- a/src/cpu/core_normal/prefix_0f.h +++ b/src/cpu/core_normal/prefix_0f.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_66.h b/src/cpu/core_normal/prefix_66.h index 39769ce..b9adacc 100644 --- a/src/cpu/core_normal/prefix_66.h +++ b/src/cpu/core_normal/prefix_66.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_66_0f.h b/src/cpu/core_normal/prefix_66_0f.h index b8aee89..eed5bac 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-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_none.h b/src/cpu/core_normal/prefix_none.h index 043cabd..5e12ba5 100644 --- a/src/cpu/core_normal/prefix_none.h +++ b/src/cpu/core_normal/prefix_none.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/support.h b/src/cpu/core_normal/support.h index 2a84945..9b23081 100644 --- a/src/cpu/core_normal/support.h +++ b/src/cpu/core_normal/support.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 3f9329b..08d4613 100644 --- a/src/cpu/core_normal/table_ea.h +++ b/src/cpu/core_normal/table_ea.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_prefetch.cpp b/src/cpu/core_prefetch.cpp index 0ea91f0..d9ec489 100644 --- a/src/cpu/core_prefetch.cpp +++ b/src/cpu/core_prefetch.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 1930c3b..2d026b9 100644 --- a/src/cpu/core_simple.cpp +++ b/src/cpu/core_simple.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cpu.cpp b/src/cpu/cpu.cpp index bdc400a..98b1b1a 100644 --- a/src/cpu/cpu.cpp +++ b/src/cpu/cpu.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/flags.cpp b/src/cpu/flags.cpp index 889f6a4..2e9532f 100644 --- a/src/cpu/flags.cpp +++ b/src/cpu/flags.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 cb1df6b..1696997 100644 --- a/src/cpu/instructions.h +++ b/src/cpu/instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/lazyflags.h b/src/cpu/lazyflags.h index 96974ec..a2a031d 100644 --- a/src/cpu/lazyflags.h +++ b/src/cpu/lazyflags.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 cd62c62..bbac41e 100644 --- a/src/cpu/modrm.cpp +++ b/src/cpu/modrm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 d06aec6..60482bf 100644 --- a/src/cpu/modrm.h +++ b/src/cpu/modrm.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 589c489..3978083 100644 --- a/src/cpu/paging.cpp +++ b/src/cpu/paging.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/debug/debug.cpp b/src/debug/debug.cpp index ed9b2c6..356ccea 100644 --- a/src/debug/debug.cpp +++ b/src/debug/debug.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/debug/debug_gui.cpp b/src/debug/debug_gui.cpp index 53d1936..fc9f1ca 100644 --- a/src/debug/debug_gui.cpp +++ b/src/debug/debug_gui.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/debug/debug_inc.h b/src/debug/debug_inc.h index f17fa31..1900e94 100644 --- a/src/debug/debug_inc.h +++ b/src/debug/debug_inc.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/debug/debug_win32.cpp b/src/debug/debug_win32.cpp index b33c900..91147f6 100644 --- a/src/debug/debug_win32.cpp +++ b/src/debug/debug_win32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/debug/disasm_tables.h b/src/debug/disasm_tables.h index e86e1f8..96531ef 100644 --- a/src/debug/disasm_tables.h +++ b/src/debug/disasm_tables.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cdrom.cpp b/src/dos/cdrom.cpp index 8e3ec41..2a4b711 100644 --- a/src/dos/cdrom.cpp +++ b/src/dos/cdrom.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cdrom_aspi_win32.cpp b/src/dos/cdrom_aspi_win32.cpp index d333ef7..4c60454 100644 --- a/src/dos/cdrom_aspi_win32.cpp +++ b/src/dos/cdrom_aspi_win32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cdrom_image.cpp b/src/dos/cdrom_image.cpp index f1dd979..d7bcfa6 100644 --- a/src/dos/cdrom_image.cpp +++ b/src/dos/cdrom_image.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cdrom_ioctl_linux.cpp b/src/dos/cdrom_ioctl_linux.cpp index a4a968b..448fa02 100644 --- a/src/dos/cdrom_ioctl_linux.cpp +++ b/src/dos/cdrom_ioctl_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cdrom_ioctl_os2.cpp b/src/dos/cdrom_ioctl_os2.cpp index 30c6272..ec1a7c8 100644 --- a/src/dos/cdrom_ioctl_os2.cpp +++ b/src/dos/cdrom_ioctl_os2.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cdrom_ioctl_win32.cpp b/src/dos/cdrom_ioctl_win32.cpp index 60d9d3c..9044e54 100644 --- a/src/dos/cdrom_ioctl_win32.cpp +++ b/src/dos/cdrom_ioctl_win32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dev_con.h b/src/dos/dev_con.h index 4a3527e..dfd267a 100644 --- a/src/dos/dev_con.h +++ b/src/dos/dev_con.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dos.cpp b/src/dos/dos.cpp index 0ff8f43..2073a55 100644 --- a/src/dos/dos.cpp +++ b/src/dos/dos.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dos_classes.cpp b/src/dos/dos_classes.cpp index 6057e02..840f204 100644 --- a/src/dos/dos_classes.cpp +++ b/src/dos/dos_classes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dos_devices.cpp b/src/dos/dos_devices.cpp index 47811f6..4e9beb1 100644 --- a/src/dos/dos_devices.cpp +++ b/src/dos/dos_devices.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dos_execute.cpp b/src/dos/dos_execute.cpp index bf81479..8db998c 100644 --- a/src/dos/dos_execute.cpp +++ b/src/dos/dos_execute.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -57,11 +57,6 @@ struct EXE_Header { #define MAGIC2 0x4d5a #define MAXENV 32768u #define ENV_KEEPFREE 83 /* keep unallocated by environment variables */ - /* The '65' added to nEnvSize does not cover the additional stuff: - + 2 bytes: number of strings - + 80 bytes: maximum absolute filename - + 1 byte: '\0' - -- 1999/04/21 ska */ #define LOADNGO 0 #define LOAD 1 #define OVERLAY 3 @@ -107,7 +102,7 @@ void DOS_UpdatePSPName(void) { void DOS_Terminate(Bit16u pspseg,bool tsr,Bit8u exitcode) { dos.return_code=exitcode; - dos.return_mode=(tsr)?RETURN_TSR:RETURN_EXIT; + dos.return_mode=(tsr)?(Bit8u)RETURN_TSR:(Bit8u)RETURN_EXIT; DOS_PSP curpsp(pspseg); if (pspseg==curpsp.GetParent()) return; @@ -336,6 +331,7 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { if (dataread<0xf800) minsize=((dataread+0x10)>>4)+0x20; } if (maxfree0xfffe) || (reg_sp<18)) E_Exit("stack underflow/wrap at EXEC"); /* Get Caller's program CS:IP of the stack and set termination address to that */ RealSetVec(0x22,RealMake(mem_readw(SegPhys(ss)+reg_sp+2),mem_readw(SegPhys(ss)+reg_sp))); SaveRegisters(); @@ -455,12 +453,10 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { /* Set the stack for new program */ SegSet16(ss,RealSeg(sssp));reg_sp=RealOff(sssp); /* Add some flags and CS:IP on the stack for the IRET */ - reg_sp-=4; - mem_writew(SegPhys(ss)+reg_sp+0,RealOff(csip)); - mem_writew(SegPhys(ss)+reg_sp+2,RealSeg(csip)); - /* Old info, we now jump to a RETF: - * DOS starts programs with a RETF, so our IRET - * should not modify critical flags (IOPL in v86 mode); + CPU_Push16(RealSeg(csip)); + CPU_Push16(RealOff(csip)); + /* DOS starts programs with a RETF, so critical flags + * should not be modified (IOPL in v86 mode); * interrupt flag is set explicitly, test flags cleared */ reg_flags=(reg_flags&(~FMASK_TEST))|FLAG_IF; //Jump to retf so that we only need to store cs:ip on the stack @@ -481,7 +477,7 @@ bool DOS_Execute(char * name,PhysPt block_pt,Bit8u flags) { while (char chr=*name++) { switch (chr) { case ':':case '\\':case '/':index=0;break; - default:if (index<8) stripname[index++]=toupper(chr); + default:if (index<8) stripname[index++]=(char)toupper(chr); } } index=0; diff --git a/src/dos/dos_files.cpp b/src/dos/dos_files.cpp index 875a189..c720fd9 100644 --- a/src/dos/dos_files.cpp +++ b/src/dos/dos_files.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -93,7 +93,7 @@ bool DOS_MakeName(char const * const name,char * const fullname,Bit8u * drive) { case '!': case '%': case '{': case '}': case '`': case '~': case '_': case '-': case '.': case '*': case '?': case '&': case '\'': case '+': case '^': case 246: case 255: case 0xa0: - case 0xe5: + case 0xe5: case 0xbd: upname[w++]=c; break; default: @@ -175,6 +175,11 @@ bool DOS_MakeName(char const * const name,char * const fullname,Bit8u * drive) { ext[4] = 0; if((strlen(tempdir) - strlen(ext)) > 8) memmove(tempdir + 8, ext, 5); } else tempdir[8]=0; + + if (strlen(fullname)+strlen(tempdir)>=DOS_PATHLENGTH) { + DOS_SetError(DOSERR_PATH_NOT_FOUND);return false; + } + strcat(fullname,tempdir); tempdir[0]=0; w=0;r++; diff --git a/src/dos/dos_ioctl.cpp b/src/dos/dos_ioctl.cpp index 57c5377..af2e625 100644 --- a/src/dos/dos_ioctl.cpp +++ b/src/dos/dos_ioctl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dos_keyboard_layout.cpp b/src/dos/dos_keyboard_layout.cpp index 661ca88..d6886be 100644 --- a/src/dos/dos_keyboard_layout.cpp +++ b/src/dos/dos_keyboard_layout.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -80,7 +80,7 @@ public: // call layout_key to apply the current language layout bool layout_key(Bitu key, Bit8u flags1, Bit8u flags2, Bit8u flags3); - Bitu switch_keyboard_layout(const char* new_layout, keyboard_layout* &created_layout); + Bitu switch_keyboard_layout(const char* new_layout, keyboard_layout* &created_layout, Bit32s& tried_cp); void switch_foreign_layout(); const char* get_layout_name(); const char* main_language_code(); @@ -951,7 +951,7 @@ Bitu keyboard_layout::read_codepage_file(const char* codepage_file_name, Bit32s return KEYB_INVALIDCPFILE; } -Bitu keyboard_layout::switch_keyboard_layout(const char* new_layout, keyboard_layout*& created_layout) { +Bitu keyboard_layout::switch_keyboard_layout(const char* new_layout, keyboard_layout*& created_layout, Bit32s& tried_cp) { if (strncasecmp(new_layout,"US",2)) { // switch to a foreign layout char tbuf[256]; @@ -977,6 +977,7 @@ Bitu keyboard_layout::switch_keyboard_layout(const char* new_layout, keyboard_la } else { keyboard_layout * temp_layout=new keyboard_layout(); Bitu req_codepage=temp_layout->extract_codepage(new_layout); + tried_cp = req_codepage; Bitu kerrcode=temp_layout->read_keyboard_file(new_layout, req_codepage); if (kerrcode) { delete temp_layout; @@ -1059,10 +1060,10 @@ Bitu DOS_LoadKeyboardLayout(const char * layoutname, Bit32s codepage, const char return KEYB_NOERROR; } -Bitu DOS_SwitchKeyboardLayout(const char* new_layout) { +Bitu DOS_SwitchKeyboardLayout(const char* new_layout, Bit32s& tried_cp) { if (loaded_layout) { keyboard_layout* changed_layout=NULL; - Bitu ret_code=loaded_layout->switch_keyboard_layout(new_layout, changed_layout); + Bitu ret_code=loaded_layout->switch_keyboard_layout(new_layout, changed_layout, tried_cp); if (changed_layout) { // Remove old layout, activate new layout delete loaded_layout; diff --git a/src/dos/dos_memory.cpp b/src/dos/dos_memory.cpp index 6753371..7bdd514 100644 --- a/src/dos/dos_memory.cpp +++ b/src/dos/dos_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dos_misc.cpp b/src/dos/dos_misc.cpp index c448ac4..923e5da 100644 --- a/src/dos/dos_misc.cpp +++ b/src/dos/dos_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -192,7 +192,7 @@ static bool DOS_MultiplexFunctions(void) { case 0x4a01: /* Query free hma space */ case 0x4a02: /* ALLOCATE HMA SPACE */ LOG(LOG_DOSMISC,LOG_WARN)("INT 2f:4a HMA. DOSBox reports none available."); - reg_bx=0; //number of bytes available in HMA or amount succesfully allocated + reg_bx=0; //number of bytes available in HMA or amount successfully allocated //ESDI=ffff:ffff Location of HMA/Allocated memory SegSet16(es,0xffff); reg_di=0xffff; diff --git a/src/dos/dos_mscdex.cpp b/src/dos/dos_mscdex.cpp index e8908b1..65ab123 100644 --- a/src/dos/dos_mscdex.cpp +++ b/src/dos/dos_mscdex.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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,6 +39,7 @@ #define MSCDEX_MAX_DRIVES 8 // Error Codes +#define MSCDEX_ERROR_INVALID_FUNCTION 1 #define MSCDEX_ERROR_BAD_FORMAT 11 #define MSCDEX_ERROR_UNKNOWN_DRIVE 15 #define MSCDEX_ERROR_DRIVE_NOT_READY 21 @@ -339,7 +340,7 @@ int CMscdex::AddDrive(Bit16u _drive, char* physicalPath, Bit8u& subUnit) // Create Callback Strategy Bit16u off = sizeof(DOS_DeviceHeader::sDeviceHeader); - Bitu call_strategy=CALLBACK_Allocate(); + Bit16u call_strategy=(Bit16u)CALLBACK_Allocate(); CallBack_Handlers[call_strategy]=MSCDEX_Strategy_Handler; real_writeb(seg,off+0,(Bit8u)0xFE); //GRP 4 real_writeb(seg,off+1,(Bit8u)0x38); //Extra Callback instruction @@ -349,7 +350,7 @@ int CMscdex::AddDrive(Bit16u _drive, char* physicalPath, Bit8u& subUnit) // Create Callback Interrupt off += 5; - Bitu call_interrupt=CALLBACK_Allocate(); + Bit16u call_interrupt=(Bit16u)CALLBACK_Allocate(); CallBack_Handlers[call_interrupt]=MSCDEX_Interrupt_Handler; real_writeb(seg,off+0,(Bit8u)0xFE); //GRP 4 real_writeb(seg,off+1,(Bit8u)0x38); //Extra Callback instruction @@ -380,10 +381,10 @@ int CMscdex::AddDrive(Bit16u _drive, char* physicalPath, Bit8u& subUnit) } cdrom[0] = _cdrom; dinfo[0].drive = (Bit8u)_drive; - dinfo[0].physDrive = toupper(physicalPath[0]); + dinfo[0].physDrive = (Bit8u)toupper(physicalPath[0]); } else { dinfo[numDrives].drive = (Bit8u)_drive; - dinfo[numDrives].physDrive = toupper(physicalPath[0]); + dinfo[numDrives].physDrive = (Bit8u)toupper(physicalPath[0]); } numDrives++; // stop audio @@ -541,14 +542,12 @@ bool CMscdex::StopAudio(Bit8u subUnit) return dinfo[subUnit].lastResult; } -bool CMscdex::ResumeAudio(Bit8u subUnit) -{ +bool CMscdex::ResumeAudio(Bit8u subUnit) { if (subUnit>=numDrives) return false; return dinfo[subUnit].lastResult = PlayAudioSector(subUnit,dinfo[subUnit].audioStart,dinfo[subUnit].audioEnd); } -Bit32u CMscdex::GetVolumeSize(Bit8u subUnit) -{ +Bit32u CMscdex::GetVolumeSize(Bit8u subUnit) { if (subUnit>=numDrives) return false; Bit8u tr1,tr2; TMSF leadOut; @@ -557,21 +556,25 @@ Bit32u CMscdex::GetVolumeSize(Bit8u subUnit) return 0; } -bool CMscdex::ReadVTOC(Bit16u drive, Bit16u volume, PhysPt data, Bit16u& error) -{ - if (!ReadSectors(GetSubUnit(drive),false,16+volume,1,data)) { - error=MSCDEX_ERROR_DRIVE_NOT_READY; - return false; - } - char id[5]; - MEM_BlockRead(data + 1, id, 5); - if (strncmp("CD001",id, 5)!=0) { - error = MSCDEX_ERROR_BAD_FORMAT; - return false; - } - Bit8u type = mem_readb(data); - error = (type == 1) ? 1 : (type == 0xFF) ? 0xFF : 0; - return true; +bool CMscdex::ReadVTOC(Bit16u drive, Bit16u volume, PhysPt data, Bit16u& error) { + Bit8u subunit = GetSubUnit(drive); +/* if (subunit>=numDrives) { + error=MSCDEX_ERROR_UNKNOWN_DRIVE; + return false; + } */ + if (!ReadSectors(subunit,false,16+volume,1,data)) { + error=MSCDEX_ERROR_DRIVE_NOT_READY; + return false; + } + char id[5]; + MEM_BlockRead(data + 1, id, 5); + if (strncmp("CD001",id, 5)!=0) { + error = MSCDEX_ERROR_BAD_FORMAT; + return false; + } + Bit8u type = mem_readb(data); + error = (type == 1) ? 1 : (type == 0xFF) ? 0xFF : 0; + return true; } bool CMscdex::GetVolumeName(Bit8u subUnit, char* data) { @@ -1104,7 +1107,7 @@ static bool MSCDEX_Handler(void) { if (mscdex->GetCopyrightName(reg_cx,data)) { CALLBACK_SCF(false); } else { - reg_al = MSCDEX_ERROR_UNKNOWN_DRIVE; + reg_ax = MSCDEX_ERROR_UNKNOWN_DRIVE; CALLBACK_SCF(true); }; return true; @@ -1112,7 +1115,7 @@ static bool MSCDEX_Handler(void) { if (mscdex->GetAbstractName(reg_cx,data)) { CALLBACK_SCF(false); } else { - reg_al = MSCDEX_ERROR_UNKNOWN_DRIVE; + reg_ax = MSCDEX_ERROR_UNKNOWN_DRIVE; CALLBACK_SCF(true); }; return true; @@ -1120,13 +1123,14 @@ static bool MSCDEX_Handler(void) { if (mscdex->GetDocumentationName(reg_cx,data)) { CALLBACK_SCF(false); } else { - reg_al = MSCDEX_ERROR_UNKNOWN_DRIVE; + reg_ax = MSCDEX_ERROR_UNKNOWN_DRIVE; CALLBACK_SCF(true); }; return true; case 0x1505: { // read vtoc Bit16u error = 0; if (mscdex->ReadVTOC(reg_cx,reg_dx,data,error)) { +// reg_ax = error; // return code CALLBACK_SCF(false); } else { reg_ax = error; @@ -1137,19 +1141,21 @@ static bool MSCDEX_Handler(void) { case 0x1508: { // read sectors Bit32u sector = (reg_si<<16)+reg_di; if (mscdex->ReadSectors(reg_cx,sector,reg_dx,data)) { + reg_ax = 0; CALLBACK_SCF(false); } else { - reg_al = MSCDEX_ERROR_UNKNOWN_DRIVE; + // possibly: MSCDEX_ERROR_DRIVE_NOT_READY if sector is beyond total length + reg_ax = MSCDEX_ERROR_UNKNOWN_DRIVE; CALLBACK_SCF(true); }; return true; }; case 0x1509: // write sectors - not supported - reg_al = MSCDEX_ERROR_DRIVE_NOT_READY; + reg_ax = MSCDEX_ERROR_INVALID_FUNCTION; CALLBACK_SCF(true); return true; case 0x150B: /* Valid CDROM drive ? */ - reg_ax = mscdex->IsValidDrive(reg_cx); + reg_ax = (mscdex->IsValidDrive(reg_cx) ? 0x5ad8 : 0x0000); reg_bx = 0xADAD; return true; case 0x150C: /* Get MSCDEX Version */ @@ -1158,6 +1164,30 @@ static bool MSCDEX_Handler(void) { case 0x150D: /* Get drives */ mscdex->GetDrives(data); return true; + case 0x150E: /* Get/Set Volume Descriptor Preference */ + if (mscdex->IsValidDrive(reg_cx)) { + if (reg_bx == 0) { + // get preference + reg_dx = 0x100; // preference? + CALLBACK_SCF(false); + } else if (reg_bx == 1) { + // set preference + if (reg_dh == 1) { + // valid + CALLBACK_SCF(false); + } else { + reg_ax = MSCDEX_ERROR_INVALID_FUNCTION; + CALLBACK_SCF(true); + } + } else { + reg_ax = MSCDEX_ERROR_INVALID_FUNCTION; + CALLBACK_SCF(true); + } + } else { + reg_ax = MSCDEX_ERROR_UNKNOWN_DRIVE; + CALLBACK_SCF(true); + } + return true; case 0x150F: { // Get directory entry Bit16u error; bool success = mscdex->GetDirectoryEntry(reg_cl,reg_ch&1,data,PhysMake(reg_si,reg_di),error); @@ -1168,7 +1198,7 @@ static bool MSCDEX_Handler(void) { if (mscdex->SendDriverRequest(reg_cx,data)) { CALLBACK_SCF(false); } else { - reg_ax = 0x0f; // invalid drive + reg_ax = MSCDEX_ERROR_UNKNOWN_DRIVE; CALLBACK_SCF(true); } return true; @@ -1261,21 +1291,18 @@ bool MSCDEX_HasMediaChanged(Bit8u subUnit) return true; } -void MSCDEX_SetCDInterface(int intNr, int numCD) -{ +void MSCDEX_SetCDInterface(int intNr, int numCD) { useCdromInterface = intNr; forceCD = numCD; } -void MSCDEX_ShutDown(Section* sec) -{ +void MSCDEX_ShutDown(Section* /*sec*/) { delete mscdex; mscdex = 0; curReqheaderPtr = 0; } -void MSCDEX_Init(Section* sec) -{ +void MSCDEX_Init(Section* sec) { // AddDestroy func sec->AddDestroyFunction(&MSCDEX_ShutDown); /* Register the mscdex device */ diff --git a/src/dos/dos_programs.cpp b/src/dos/dos_programs.cpp index 1ada622..d01c7de 100644 --- a/src/dos/dos_programs.cpp +++ b/src/dos/dos_programs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -120,7 +120,6 @@ int MountDOSBoxDir(char DriveLetter, const char *path) { } - class MOUNT : public Program { public: void Run(void) @@ -160,7 +159,7 @@ public: Drives[i_drive] = 0; if(i_drive == DOS_GetDefaultDrive()) DOS_SetDrive(toupper('Z') - 'A'); - WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_SUCCES"),umount[0]); + WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_SUCCESS"),umount[0]); break; case 1: WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_NO_VIRTUAL")); @@ -391,7 +390,11 @@ public: } return; showusage: - WriteOut(MSG_Get("PROGRAM_MOUNT_USAGE")); +#if defined (WIN32) || defined(OS2) + WriteOut(MSG_Get("PROGRAM_MOUNT_USAGE"),"d:\\dosprogs","d:\\dosprogs"); +#else + WriteOut(MSG_Get("PROGRAM_MOUNT_USAGE"),"~/dosprogs","~/dosprogs"); +#endif return; } }; @@ -1062,7 +1065,7 @@ public: Drives[i_drive] = 0; if (i_drive == DOS_GetDefaultDrive()) DOS_SetDrive(toupper('Z') - 'A'); - WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_SUCCES"),umount[0]); + WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_SUCCESS"),umount[0]); break; case 1: WriteOut(MSG_Get("PROGRAM_MOUNT_UMOUNT_NO_VIRTUAL")); @@ -1177,13 +1180,12 @@ public: WriteOut(MSG_Get("PROGRAM_IMGMOUNT_FILE_NOT_FOUND")); return; } - - if ((test.st_mode & S_IFDIR)) { - WriteOut(MSG_Get("PROGRAM_IMGMOUNT_MOUNT")); - return; - } } } + if ((test.st_mode & S_IFDIR)) { + WriteOut(MSG_Get("PROGRAM_IMGMOUNT_MOUNT")); + return; + } paths.push_back(temp_line); } if (paths.size() == 0) { @@ -1228,7 +1230,7 @@ public: } newdrive=new fatDrive(temp_line.c_str(),sizes[0],sizes[1],sizes[2],sizes[3],0); - if(!(dynamic_cast(newdrive))->created_succesfully) { + if(!(dynamic_cast(newdrive))->created_successfully) { delete newdrive; newdrive = 0; } @@ -1339,7 +1341,7 @@ void IMGMOUNT_ProgramStart(Program * * make) { } -Bitu DOS_SwitchKeyboardLayout(const char* new_layout); +Bitu DOS_SwitchKeyboardLayout(const char* new_layout, Bit32s& tried_cp); Bitu DOS_LoadKeyboardLayout(const char * layoutname, Bit32s codepage, const char * codepagefile); const char* DOS_GetLoadedLayout(void); @@ -1356,9 +1358,10 @@ void KEYB::Run(void) { /* first parameter is layout ID */ Bitu keyb_error=0; std::string cp_string; + Bit32s tried_cp = -1; if (cmd->FindCommand(2,cp_string)) { /* second parameter is codepage number */ - Bit32s par_cp=atoi(cp_string.c_str()); + tried_cp=atoi(cp_string.c_str()); char cp_file_name[256]; if (cmd->FindCommand(3,cp_string)) { /* third parameter is codepage file */ @@ -1368,8 +1371,10 @@ void KEYB::Run(void) { strcpy(cp_file_name, "auto"); } - keyb_error=DOS_LoadKeyboardLayout(temp_line.c_str(), par_cp, cp_file_name); - } else keyb_error=DOS_SwitchKeyboardLayout(temp_line.c_str()); + keyb_error=DOS_LoadKeyboardLayout(temp_line.c_str(), tried_cp, cp_file_name); + } else { + keyb_error=DOS_SwitchKeyboardLayout(temp_line.c_str(), tried_cp); + } switch (keyb_error) { case KEYB_NOERROR: WriteOut(MSG_Get("PROGRAM_KEYB_NOERROR"),temp_line.c_str(),dos.loaded_codepage); @@ -1382,7 +1387,7 @@ void KEYB::Run(void) { WriteOut(MSG_Get("PROGRAM_KEYB_INVALIDFILE"),temp_line.c_str()); break; case KEYB_LAYOUTNOTFOUND: - WriteOut(MSG_Get("PROGRAM_KEYB_LAYOUTNOTFOUND"),temp_line.c_str(),dos.loaded_codepage); + WriteOut(MSG_Get("PROGRAM_KEYB_LAYOUTNOTFOUND"),temp_line.c_str(),tried_cp); break; case KEYB_INVALIDCPFILE: WriteOut(MSG_Get("PROGRAM_KEYB_INVCPFILE"),temp_line.c_str()); @@ -1422,10 +1427,14 @@ void DOS_SetupPrograms(void) { #ifdef HW_RVL MSG_Add("PROGRAM_MOUNT_USAGE","Usage \033[34;1mMOUNT Drive-Letter Local-Directory\033[0m\nSo a MOUNT d usb:/windows mounts windows directory on USB as the d: drive\n"); #else - MSG_Add("PROGRAM_MOUNT_USAGE","Usage \033[34;1mMOUNT Drive-Letter Local-Directory\033[0m\nSo a MOUNT c c:\\windows mounts windows directory as the c: drive in DOSBox\n"); + MSG_Add("PROGRAM_MOUNT_USAGE", + "Usage \033[34;1mMOUNT Drive-Letter Local-Directory\033[0m\n" + "For example: MOUNT c %s\n" + "This makes the directory %s act as the C: drive inside DOSBox.\n" + "The directory has to exist.\n"); #endif 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_SUCCESS","Drive %c has successfully 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"); @@ -1458,7 +1467,7 @@ void DOS_SetupPrograms(void) { "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" + "For more information about DOSBox, go to \033[34;1mhttp://www.dosbox.com/wiki\033[0m\n" "\n" "\033[31;1mDOSBox will stop/exit without a warning if an error occured!\033[0m\n" "\n" @@ -1473,38 +1482,27 @@ void DOS_SetupPrograms(void) { 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" + "\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:\\dosprogs\\\033[37m will create a C drive with c:\\dosprogs as contents.\xBA\n" + "\xBA \xBA\n" + "\xBA \033[32mc:\\dosprogs\\\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\xCD\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_WII", - "\033[44;1m===========================" - "============================" - "=======================\n" - "| \033[32mmount c usb:/dosprog/\033[37m will create a C drive with usb:/dosprog as contents. |\n" - "| |\n" - "| \033[32musb:/dosprog/\033[37m is an example. Possible drives are sd: usb: carda: cardb: \033[37m |\n" - "===========================" - "============================" - "=======================\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" + "\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\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" + "\xBA \033[32mmount c ~/dosprogs\033[37m will create a C drive with ~/dosprogs as contents.\xBA\n" + "\xBA \xBA\n" + "\xBA \033[32m~/dosprogs\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\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" + "When the mount has successfully 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[33;1m[]\033[0m in a directory listing).\n" diff --git a/src/dos/dos_tables.cpp b/src/dos/dos_tables.cpp index 7b9152d..704daef 100644 --- a/src/dos/dos_tables.cpp +++ b/src/dos/dos_tables.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/drive_cache.cpp b/src/dos/drive_cache.cpp index d7b4ccc..37f3098 100644 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -707,16 +707,24 @@ bool DOS_Drive_Cache::SetResult(CFileInfo* dir, char* &result, Bitu entryNr) } // FindFirst / FindNext -bool DOS_Drive_Cache::FindFirst(char* path, Bitu& id) { +bool DOS_Drive_Cache::FindFirst(char* path, Bit16u& id) { Bit16u dirID; - Bitu dirFindFirstID = this->nextFreeFindFirst; - // Cache directory in if (!OpenDir(path,dirID)) return false; - this->nextFreeFindFirst++; //increase it for the next search + //Find a free slot. + //If the next one isn't free, move on to the next, if none is free => reset and assume the worst + Bit16u local_findcounter = 0; + while ( local_findcounter < MAX_OPENDIRS ) { + if (dirFindFirst[this->nextFreeFindFirst] == 0) break; + if (++this->nextFreeFindFirst >= MAX_OPENDIRS) this->nextFreeFindFirst = 0; //Wrap around + local_findcounter++; + } - if (dirFindFirstID == MAX_OPENDIRS) { + Bit16u dirFindFirstID = this->nextFreeFindFirst++; + if (this->nextFreeFindFirst >= MAX_OPENDIRS) this->nextFreeFindFirst = 0; //Increase and wrap around for the next search. + + if (local_findcounter == MAX_OPENDIRS) { //Here is the reset from above. // no free slot found... LOG(LOG_MISC,LOG_ERROR)("DIRCACHE: FindFirst/Next: All slots full. Resetting"); // Clear the internal list then. @@ -751,7 +759,7 @@ bool DOS_Drive_Cache::FindFirst(char* path, Bitu& id) { return true; } -bool DOS_Drive_Cache::FindNext(Bitu id, char* &result) { +bool DOS_Drive_Cache::FindNext(Bit16u id, char* &result) { // out of range ? if ((id>=MAX_OPENDIRS) || !dirFindFirst[id]) { LOG(LOG_MISC,LOG_ERROR)("DIRCACHE: FindFirst/Next failure : ID out of range: %04X",id); diff --git a/src/dos/drive_fat.cpp b/src/dos/drive_fat.cpp index 76cf973..3fbe33b 100644 --- a/src/dos/drive_fat.cpp +++ b/src/dos/drive_fat.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -628,7 +628,7 @@ bool fatDrive::allocateCluster(Bit32u useCluster, Bit32u prevCluster) { } fatDrive::fatDrive(const char *sysFilename, Bit32u bytesector, Bit32u cylsector, Bit32u headscyl, Bit32u cylinders, Bit32u startSector) { - created_succesfully = true; + created_successfully = true; FILE *diskfile; Bit32u filesize; struct partTable mbrData; @@ -640,14 +640,14 @@ fatDrive::fatDrive(const char *sysFilename, Bit32u bytesector, Bit32u cylsector, } diskfile = fopen(sysFilename, "rb+"); - if(!diskfile) {created_succesfully = false;return;} + if(!diskfile) {created_successfully = false;return;} fseek(diskfile, 0L, SEEK_END); filesize = (Bit32u)ftell(diskfile) / 1024L; /* Load disk image */ loadedDisk = new imageDisk(diskfile, (Bit8u *)sysFilename, filesize, (filesize > 2880)); if(!loadedDisk) { - created_succesfully = false; + created_successfully = false; return; } @@ -686,7 +686,7 @@ fatDrive::fatDrive(const char *sysFilename, Bit32u bytesector, Bit32u cylsector, if(!bootbuffer.sectorsperfat) { /* FAT32 not implemented yet */ - created_succesfully = false; + created_successfully = false; return; } diff --git a/src/dos/drive_iso.cpp b/src/dos/drive_iso.cpp index 4135d73..5150850 100644 --- a/src/dos/drive_iso.cpp +++ b/src/dos/drive_iso.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -246,7 +246,10 @@ bool isoDrive::FindFirst(char *dir, DOS_DTA &dta, bool fcb_findfirst) { } // get a directory iterator and save its id in the dta - dta.SetDirID((Bit16u)GetDirIterator(&de)); + int dirIterator = GetDirIterator(&de); + bool isRoot = (*dir == 0); + dirIterators[dirIterator].root = isRoot; + dta.SetDirID((Bit16u)dirIterator); Bit8u attr; char pattern[ISO_MAXPATHNAME]; @@ -260,7 +263,7 @@ bool isoDrive::FindFirst(char *dir, DOS_DTA &dta, bool fcb_findfirst) { DOS_SetError(DOSERR_NO_MORE_FILES); return false; } - } else if ((attr & DOS_ATTR_VOLUME) && (*dir == 0) && !fcb_findfirst) { + } else if ((attr & DOS_ATTR_VOLUME) && isRoot && !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); @@ -277,6 +280,7 @@ bool isoDrive::FindNext(DOS_DTA &dta) { dta.GetSearchParams(attr, pattern); int dirIterator = dta.GetDirID(); + bool isRoot = dirIterators[dirIterator].root; isoDirEntry de; while (GetNextDirEntry(dirIterator, &de)) { @@ -285,7 +289,7 @@ bool isoDrive::FindNext(DOS_DTA &dta) { else findAttr |= DOS_ATTR_ARCHIVE; if (IS_HIDDEN(de.fileFlags)) findAttr |= DOS_ATTR_HIDDEN; - if (WildFileCmp((char*)de.ident, pattern) + if (!(isRoot && de.ident[0]=='.') && 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 */ diff --git a/src/dos/drive_local.cpp b/src/dos/drive_local.cpp index 15dee47..f92e666 100644 --- a/src/dos/drive_local.cpp +++ b/src/dos/drive_local.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -188,7 +188,7 @@ bool localDrive::FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst) { char end[2]={CROSS_FILESPLIT,0}; if (tempDir[strlen(tempDir)-1]!=CROSS_FILESPLIT) strcat(tempDir,end); - Bitu id; + Bit16u id; if (!dirCache.FindFirst(tempDir,id)) { DOS_SetError(DOSERR_PATH_NOT_FOUND); return false; @@ -239,7 +239,7 @@ bool localDrive::FindNext(DOS_DTA & dta) { Bit8u find_attr; dta.GetSearchParams(srch_attr,srch_pattern); - Bitu id = dta.GetDirID(); + Bit16u id = dta.GetDirID(); again: if (!dirCache.FindNext(id,dir_ent)) { diff --git a/src/dos/drive_virtual.cpp b/src/dos/drive_virtual.cpp index c2089a8..95bdf18 100644 --- a/src/dos/drive_virtual.cpp +++ b/src/dos/drive_virtual.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/drives.cpp b/src/dos/drives.cpp index 018dd52..c5b502d 100644 --- a/src/dos/drives.cpp +++ b/src/dos/drives.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/drives.h b/src/dos/drives.h index 86ce3de..aa629fc 100644 --- a/src/dos/drives.h +++ b/src/dos/drives.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -175,7 +175,7 @@ public: bool directoryBrowse(Bit32u dirClustNumber, direntry *useEntry, Bit32s entNum); bool directoryChange(Bit32u dirClustNumber, direntry *useEntry, Bit32s entNum); imageDisk *loadedDisk; - bool created_succesfully; + bool created_successfully; private: Bit32u getClusterValue(Bit32u clustNum); void setClusterValue(Bit32u clustNum, Bit32u clustValue); @@ -345,6 +345,7 @@ private: struct DirIterator { bool valid; + bool root; Bit32u currentSector; Bit32u endSector; Bit32u pos; diff --git a/src/dosbox.cpp b/src/dosbox.cpp index b008333..b55a8d4 100644 --- a/src/dosbox.cpp +++ b/src/dosbox.cpp @@ -1,687 +1,687 @@ -/* - * Copyright (C) 2002-2009 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.cpp,v 1.149 2009/05/20 18:07:06 qbix79 Exp $ */ - -#include -#include -#include -#include -#include -#include "dosbox.h" -#include "debug.h" -#include "cpu.h" -#include "video.h" -#include "pic.h" -#include "cpu.h" -#include "callback.h" -#include "inout.h" -#include "mixer.h" -#include "timer.h" -#include "dos_inc.h" -#include "setup.h" -#include "control.h" -#include "cross.h" -#include "programs.h" -#include "support.h" -#include "mapper.h" -#include "ints/int10.h" -#include "render.h" - -Config * control; -MachineType machine; -SVGACards svgaCard; - -/* The whole load of startups for all the subfunctions */ -void MSG_Init(Section_prop *); -void LOG_StartUp(void); -void MEM_Init(Section *); -void PAGING_Init(Section *); -void IO_Init(Section * ); -void CALLBACK_Init(Section*); -void PROGRAMS_Init(Section*); -//void CREDITS_Init(Section*); -void RENDER_Init(Section*); -void VGA_Init(Section*); - -void DOS_Init(Section*); - - -void CPU_Init(Section*); - -#if C_FPU -void FPU_Init(Section*); -#endif - -void DMA_Init(Section*); - -void MIXER_Init(Section*); -void MIDI_Init(Section*); -void HARDWARE_Init(Section*); - - -void KEYBOARD_Init(Section*); //TODO This should setup INT 16 too but ok ;) -void JOYSTICK_Init(Section*); -void MOUSE_Init(Section*); -void SBLASTER_Init(Section*); -void GUS_Init(Section*); -void MPU401_Init(Section*); -void PCSPEAKER_Init(Section*); -void TANDYSOUND_Init(Section*); -void DISNEY_Init(Section*); -void SERIAL_Init(Section*); - - -#if C_IPX -void IPX_Init(Section*); -#endif - -void SID_Init(Section* sec); - -void PIC_Init(Section*); -void TIMER_Init(Section*); -void BIOS_Init(Section*); -void DEBUG_Init(Section*); -void CMOS_Init(Section*); - -void MSCDEX_Init(Section*); -void DRIVES_Init(Section*); -void CDROM_Image_Init(Section*); - -/* Dos Internal mostly */ -void EMS_Init(Section*); -void XMS_Init(Section*); - -void DOS_KeyboardLayout_Init(Section*); - -void AUTOEXEC_Init(Section*); -void SHELL_Init(void); - -void INT10_Init(Section*); - -static LoopHandler * loop; - -bool SDLNetInited; - -static Bit32u ticksRemain; -static Bit32u ticksLast; -static Bit32u ticksAdded; -Bit32s ticksDone; -Bit32u ticksScheduled; -bool ticksLocked; - -static Bitu Normal_Loop(void) { - Bits ret; - while (1) { - if (PIC_RunQueue()) { - ret=(*cpudecoder)(); - if (ret<0) return 1; - if (ret>0) { - Bitu blah=(*CallBack_Handlers[ret])(); - if (blah) return blah; - } -#if C_DEBUG - if (DEBUG_ExitLoop()) return 0; -#endif - } else { - GFX_Events(); - if (ticksRemain>0) { - TIMER_AddTick(); - ticksRemain--; - } else goto increaseticks; - } - } -increaseticks: - 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_CycleAutoAdjust && !CPU_SkipCycleAutoAdjust) { - if (ticksScheduled >= 250 || ticksDone >= 250 || (ticksAdded > 15 && ticksScheduled >= 5) ) { - if(ticksDone < 1) ticksDone = 1; // Protect against div by zero - /* ratio we are aiming for is around 90% usage*/ - Bit32s ratio = (ticksScheduled * (CPU_CyclePercUsed*90*1024/100/100)) / ticksDone; - Bit32s new_cmax = CPU_CycleMax; - Bit64s cproc = (Bit64s)CPU_CycleMax * (Bit64s)ticksScheduled; - if (cproc > 0) { - /* ignore the cycles added due to the io delay code in order - to have smoother auto cycle adjustments */ - double ratioremoved = (double) CPU_IODelayRemoved / (double) cproc; - if (ratioremoved < 1.0) { - ratio = (Bit32s)((double)ratio * (1 - ratioremoved)); - /* Don't allow very high ratio which can cause us to lock as we don't scale down - * for very low ratios. High ratio might result because of timing resolution */ - if (ticksScheduled >= 250 && ticksDone < 10 && ratio > 20480) - ratio = 20480; - Bit64s cmax_scaled = (Bit64s)CPU_CycleMax * (Bit64s)ratio; - if (ratio <= 1024) - new_cmax = (Bit32s)(cmax_scaled / (Bit64s)1024); - else - new_cmax = (Bit32s)(1 + (CPU_CycleMax >> 1) + cmax_scaled / (Bit64s)2048); - } - } - - if (new_cmax10) { - /* ratios below 12% along with a large time since the last update - has taken place are most likely caused by heavy load through a - different application, the cycles adjusting is skipped as well */ - if ((ratio>120) || (ticksDone<700)) { - CPU_CycleMax = new_cmax; - if (CPU_CycleLimit > 0) { - if (CPU_CycleMax>CPU_CycleLimit) CPU_CycleMax = CPU_CycleLimit; - } - } - } - CPU_IODelayRemoved = 0; - ticksDone = 0; - ticksScheduled = 0; - } else if (ticksAdded > 15) { - /* ticksAdded > 15 but ticksScheduled < 5, lower the cycles - but do not reset the scheduled/done ticks to take them into - account during the next auto cycle adjustment */ - CPU_CycleMax /= 3; - if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT) - CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT; - } - } - } else { - ticksAdded = 0; - SDL_Delay(1); - ticksDone -= GetTicks() - ticksNew; - if (ticksDone < 0) - ticksDone = 0; - } - } - return 0; -} - -void DOSBOX_SetLoop(LoopHandler * handler) { - loop=handler; -} - -void DOSBOX_SetNormalLoop() { - loop=Normal_Loop; -} - -void DOSBOX_RunMachine(void){ - Bitu ret; - do { - ret=(*loop)(); - } while (!ret); -} - -static void DOSBOX_UnlockSpeed( bool pressed ) { - static bool autoadjust = false; - if (pressed) { - ticksLocked = true; - if (CPU_CycleAutoAdjust) { - autoadjust = true; - CPU_CycleAutoAdjust = false; - CPU_CycleMax /= 3; - if (CPU_CycleMax<1000) CPU_CycleMax=1000; - } - } else { - ticksLocked = false; - if (autoadjust) { - autoadjust = false; - CPU_CycleAutoAdjust = true; - } - } -} - -static void DOSBOX_RealInit(Section * sec) { - Section_prop * section=static_cast(sec); - /* Initialize some dosbox internals */ - - ticksRemain=0; - ticksLast=GetTicks(); - ticksLocked = false; - DOSBOX_SetLoop(&Normal_Loop); - MSG_Init(section); - - MAPPER_AddHandler(DOSBOX_UnlockSpeed, MK_f12, MMOD2,"speedlock","Speedlock"); - std::string cmd_machine; - if (control->cmdline->FindString("-machine",cmd_machine,true)){ - //update value in config (else no matching against suggested values - section->HandleInputline(std::string("machine=") + cmd_machine); - } - - std::string mtype(section->Get_string("machine")); - svgaCard = SVGA_None; - machine = MCH_VGA; - int10.vesa_nolfb = false; - int10.vesa_oldvbe = false; - if (mtype == "cga") { machine = MCH_CGA; } - else if (mtype == "tandy") { machine = MCH_TANDY; } - else if (mtype == "pcjr") { machine = MCH_PCJR; } - else if (mtype == "hercules") { machine = MCH_HERC; } - else if (mtype == "ega") { machine = MCH_EGA; } -// else if (mtype == "vga") { svgaCard = SVGA_S3Trio; } - else if (mtype == "svga_s3") { svgaCard = SVGA_S3Trio; } - else if (mtype == "vesa_nolfb") { svgaCard = SVGA_S3Trio; int10.vesa_nolfb = true;} - else if (mtype == "vesa_oldvbe") { svgaCard = SVGA_S3Trio; int10.vesa_oldvbe = true;} - else if (mtype == "svga_et4000") { svgaCard = SVGA_TsengET4K; } - else if (mtype == "svga_et3000") { svgaCard = SVGA_TsengET3K; } -// else if (mtype == "vga_pvga1a") { svgaCard = SVGA_ParadisePVGA1A; } - else if (mtype == "svga_paradise") { svgaCard = SVGA_ParadisePVGA1A; } - else if (mtype == "vgaonly") { svgaCard = SVGA_None; } - else E_Exit("DOSBOX:Unknown machine type %s",mtype.c_str()); -} - - -void DOSBOX_Init(void) { - Section_prop * secprop; - Section_line * secline; - Prop_int* Pint; - Prop_hex* Phex; - Prop_string* Pstring; - Prop_bool* Pbool; - Prop_multival* Pmulti; - Prop_multival_remain* Pmulti_remain; - - SDLNetInited = false; - - // Some frequently used option sets - const char *rates[] = { "22050", "44100", "48000", "32000", "16000", "11025", "8000", "49716", 0 }; - const char *oplrates[] = { "22050", "49716", "44100", "48000", "32000", "16000", "11025", "8000", 0 }; - const char *ios[] = { "220", "240", "260", "280", "2a0", "2c0", "2e0", "300", 0 }; - const char *irqssb[] = { "7", "5", "3", "9", "10", "11", "12", 0 }; - const char *dmassb[] = { "1", "5", "0", "3", "6", "7", 0 }; - const char *iosgus[] = { "240", "220", "260", "280", "2a0", "2c0", "2e0", "300", 0 }; - const char *irqsgus[] = { "5", "3", "7", "9", "10", "11", "12", 0 }; - const char *dmasgus[] = { "3", "0", "1", "5", "6", "7", 0 }; - - - /* Setup all the different modules making up DOSBox */ - const char* machines[] = { - "hercules", "cga", "tandy", "pcjr", "ega", - "vgaonly", "svga_s3", "svga_et3000", "svga_et4000", - "svga_paradise", "vesa_nolfb", "vesa_oldvbe", 0 }; - secprop=control->AddSection_prop("dosbox",&DOSBOX_RealInit); - Pstring = secprop->Add_path("language",Property::Changeable::Always,""); - Pstring->Set_help("Select another language file."); - - Pstring = secprop->Add_string("machine",Property::Changeable::OnlyAtStart,"svga_s3"); - Pstring->Set_values(machines); - Pstring->Set_help("The type of machine tries to emulate."); - - Pstring = secprop->Add_path("captures",Property::Changeable::Always,"capture"); - Pstring->Set_help("Directory where things like wave, midi, screenshot get captured."); - -#if C_DEBUG - LOG_StartUp(); -#endif - - secprop->AddInitFunction(&IO_Init);//done - secprop->AddInitFunction(&PAGING_Init);//done - secprop->AddInitFunction(&MEM_Init);//done - secprop->AddInitFunction(&HARDWARE_Init);//done - Pint = secprop->Add_int("memsize", Property::Changeable::WhenIdle,16); - Pint->SetMinMax(1,63); - Pint->Set_help( - "Amount of memory DOSBox has in megabytes.\n" - " This value is best left at its default to avoid problems with some games,\n" - " though few games might require a higher value.\n" - " There is generally no speed advantage when raising this value."); - secprop->AddInitFunction(&CALLBACK_Init); - secprop->AddInitFunction(&PIC_Init);//done - secprop->AddInitFunction(&PROGRAMS_Init); - secprop->AddInitFunction(&TIMER_Init);//done - secprop->AddInitFunction(&CMOS_Init);//done - - secprop=control->AddSection_prop("render",&RENDER_Init,true); - Pint = secprop->Add_int("frameskip",Property::Changeable::Always,0); - Pint->SetMinMax(0,10); - Pint->Set_help("How many frames DOSBox skips before drawing one."); - - Pbool = secprop->Add_bool("aspect",Property::Changeable::Always,false); - Pbool->Set_help("Do aspect correction, if your output method doesn't support scaling this can slow things down!."); - - Pmulti = secprop->Add_multi("scaler",Property::Changeable::Always," "); - Pmulti->SetValue("normal2x"); - Pmulti->Set_help("Scaler used to enlarge/enhance low resolution modes. If 'forced' is appended,the scaler will be used even if the result might not be desired."); - Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"normal2x"); - - const char *scalers[] = { - "none", "normal2x", "normal3x", -#if RENDER_USE_ADVANCED_SCALERS>2 - "advmame2x", "advmame3x", "advinterp2x", "advinterp3x", "hq2x", "hq3x", "2xsai", "super2xsai", "supereagle", -#endif -#if RENDER_USE_ADVANCED_SCALERS>0 - "tv2x", "tv3x", "rgb2x", "rgb3x", "scan2x", "scan3x", -#endif - 0 }; - Pstring->Set_values(scalers); - - const char* force[] = { "", "forced", 0 }; - Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,""); - Pstring->Set_values(force); - - secprop=control->AddSection_prop("cpu",&CPU_Init,true);//done - const char* cores[] = { "auto", -#if (C_DYNAMIC_X86) || (C_DYNREC) - "dynamic", -#endif - "normal", "simple",0 }; - Pstring = secprop->Add_string("core",Property::Changeable::WhenIdle,"auto"); - Pstring->Set_values(cores); - Pstring->Set_help("CPU Core used in emulation. auto will switch to dynamic if available and appropriate."); - - const char* cputype_values[] = { "auto", "386", "386_slow", "486_slow", "pentium_slow", "386_prefetch", 0}; - Pstring = secprop->Add_string("cputype",Property::Changeable::Always,"auto"); - Pstring->Set_values(cputype_values); - Pstring->Set_help("CPU Type used in emulation. auto is the fastest choice."); - - - Pmulti_remain = secprop->Add_multiremain("cycles",Property::Changeable::Always," "); - Pmulti_remain->Set_help( - "Amount of instructions DOSBox tries to emulate each millisecond. Setting this value too high results in sound dropouts and lags. Cycles can be set in 3 ways:\n" - " 'auto' tries to guess what a game needs.\n" - " It usually works, but can fail for certain games.\n" - " 'fixed #number' will set a fixed amount of cycles. This is what you usually need if 'auto' fails.\n" - " (Example: fixed 4000)\n" - " 'max' will allocate as much cycles as your computer is able to handle\n"); - - const char* cyclest[] = { "auto","fixed","max","%u",0 }; - Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::Always,"auto"); - Pmulti_remain->SetValue("auto"); - Pstring->Set_values(cyclest); - - Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::Always,""); - - Pint = secprop->Add_int("cycleup",Property::Changeable::Always,500); - Pint->SetMinMax(1,1000000); - Pint->Set_help("Amount of cycles to increase/decrease with keycombo."); - - Pint = secprop->Add_int("cycledown",Property::Changeable::Always,20); - Pint->SetMinMax(1,1000000); - Pint->Set_help("Setting it lower than 100 will be a percentage."); - -#if C_FPU - secprop->AddInitFunction(&FPU_Init); -#endif - secprop->AddInitFunction(&DMA_Init);//done - secprop->AddInitFunction(&VGA_Init); - secprop->AddInitFunction(&KEYBOARD_Init); - - secprop=control->AddSection_prop("mixer",&MIXER_Init); - Pbool = secprop->Add_bool("nosound",Property::Changeable::OnlyAtStart,false); - Pbool->Set_help("Enable silent mode, sound is still emulated though."); - - Pint = secprop->Add_int("rate",Property::Changeable::OnlyAtStart,22050); - Pint->Set_values(rates); - Pint->Set_help("Mixer sample rate, setting any device's rate higher than this will probably lower their sound quality."); - - const char *blocksizes[] = { - "2048", "4096", "8192", "1024", "512", "256", 0}; -#ifdef HW_RVL - Pint = secprop->Add_int("blocksize",Property::Changeable::OnlyAtStart,512); -#else - Pint = secprop->Add_int("blocksize",Property::Changeable::OnlyAtStart,2048); -#endif - Pint->Set_values(blocksizes); - Pint->Set_help("Mixer block size, larger blocks might help sound stuttering but sound will also be more lagged."); - - Pint = secprop->Add_int("prebuffer",Property::Changeable::OnlyAtStart,10); - Pint->SetMinMax(0,100); - Pint->Set_help("How many milliseconds of data to keep on top of the blocksize."); - - secprop=control->AddSection_prop("midi",&MIDI_Init,true);//done - secprop->AddInitFunction(&MPU401_Init,true);//done - - const char* mputypes[] = { "intelligent", "uart", "none",0}; - // FIXME: add some way to offer the actually available choices. - const char *devices[] = { "default", "win32", "alsa", "oss", "coreaudio", "coremidi","none", 0}; - Pstring = secprop->Add_string("mpu401",Property::Changeable::WhenIdle,"intelligent"); - Pstring->Set_values(mputypes); - Pstring->Set_help("Type of MPU-401 to emulate."); - - Pstring = secprop->Add_string("mididevice",Property::Changeable::WhenIdle,"default"); - Pstring->Set_values(devices); - Pstring->Set_help("Device that will receive the MIDI data from MPU-401."); - - Pstring = secprop->Add_string("midiconfig",Property::Changeable::WhenIdle,""); - Pstring->Set_help("Special configuration options for the device driver. This is usually the id of the device you want to use. See README for details."); - -#if C_DEBUG - secprop=control->AddSection_prop("debug",&DEBUG_Init); -#endif - - secprop=control->AddSection_prop("sblaster",&SBLASTER_Init,true);//done - - const char* sbtypes[] = { "sb1", "sb2", "sbpro1", "sbpro2", "sb16", "none", 0 }; - Pstring = secprop->Add_string("sbtype",Property::Changeable::WhenIdle,"sb16"); - Pstring->Set_values(sbtypes); - Pstring->Set_help("Type of sblaster to emulate."); - - Phex = secprop->Add_hex("sbbase",Property::Changeable::WhenIdle,0x220); - Phex->Set_values(ios); - Phex->Set_help("The IO address of the soundblaster."); - - Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,7); - Pint->Set_values(irqssb); - Pint->Set_help("The IRQ number of the soundblaster."); - - Pint = secprop->Add_int("dma",Property::Changeable::WhenIdle,1); - Pint->Set_values(dmassb); - Pint->Set_help("The DMA number of the soundblaster."); - - Pint = secprop->Add_int("hdma",Property::Changeable::WhenIdle,5); - Pint->Set_values(dmassb); - Pint->Set_help("The High DMA number of the soundblaster."); - - Pbool = secprop->Add_bool("sbmixer",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Allow the soundblaster mixer to modify the DOSBox mixer."); - - const char* oplmodes[]={ "auto", "cms", "opl2", "dualopl2", "opl3", "none", 0}; - Pstring = secprop->Add_string("oplmode",Property::Changeable::WhenIdle,"auto"); - Pstring->Set_values(oplmodes); - Pstring->Set_help("Type of OPL emulation. On 'auto' the mode is determined by sblaster type. All OPL modes are Adlib-compatible, except for 'cms'."); - - const char* oplemus[]={ "default", "compat", "fast", "old", 0}; - Pstring = secprop->Add_string("oplemu",Property::Changeable::WhenIdle,"default"); - Pstring->Set_values(oplemus); - Pstring->Set_help("Provider for the OPL emulation. compat or old might provide better quality (see oplrate as well)."); - - Pint = secprop->Add_int("oplrate",Property::Changeable::WhenIdle,22050); - Pint->Set_values(oplrates); - Pint->Set_help("Sample rate of OPL music emulation. Use 49716 for highest quality (set the mixer rate accordingly)."); - - - secprop=control->AddSection_prop("gus",&GUS_Init,true); //done - Pbool = secprop->Add_bool("gus",Property::Changeable::WhenIdle,false); - Pbool->Set_help("Enable the Gravis Ultrasound emulation."); - - Pint = secprop->Add_int("gusrate",Property::Changeable::WhenIdle,22050); - Pint->Set_values(rates); - Pint->Set_help("Sample rate of Ultrasound emulation."); - - Phex = secprop->Add_hex("gusbase",Property::Changeable::WhenIdle,0x240); - Phex->Set_values(iosgus); - Phex->Set_help("The IO base address of the Gravis Ultrasound."); - - Pint = secprop->Add_int("gusirq",Property::Changeable::WhenIdle,5); - Pint->Set_values(irqsgus); - Pint->Set_help("The IRQ number of the Gravis Ultrasound."); - - Pint = secprop->Add_int("gusdma",Property::Changeable::WhenIdle,3); - Pint->Set_values(dmasgus); - Pint->Set_help("The DMA channel of the Gravis Ultrasound."); - - Pstring = secprop->Add_string("ultradir",Property::Changeable::WhenIdle,"C:\\ULTRASND"); - Pstring->Set_help( - "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."); - - secprop = control->AddSection_prop("speaker",&PCSPEAKER_Init,true);//done - Pbool = secprop->Add_bool("pcspeaker",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable PC-Speaker emulation."); - - Pint = secprop->Add_int("pcrate",Property::Changeable::WhenIdle,22050); - Pint->Set_values(rates); - Pint->Set_help("Sample rate of the PC-Speaker sound generation."); - - secprop->AddInitFunction(&TANDYSOUND_Init,true);//done - const char* tandys[] = { "auto", "on", "off", 0}; - Pstring = secprop->Add_string("tandy",Property::Changeable::WhenIdle,"auto"); - Pstring->Set_values(tandys); - Pstring->Set_help("Enable Tandy Sound System emulation. For 'auto', emulation is present only if machine is set to 'tandy'."); - - Pint = secprop->Add_int("tandyrate",Property::Changeable::WhenIdle,22050); - Pint->Set_values(rates); - Pint->Set_help("Sample rate of the Tandy 3-Voice generation."); - - secprop->AddInitFunction(&DISNEY_Init,true);//done - - Pbool = secprop->Add_bool("disney",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable Disney Sound Source emulation. (Covox Voice Master and Speech Thing compatible)."); - - secprop=control->AddSection_prop("joystick",&BIOS_Init,false);//done - secprop->AddInitFunction(&INT10_Init); - secprop->AddInitFunction(&MOUSE_Init); //Must be after int10 as it uses CurMode - secprop->AddInitFunction(&JOYSTICK_Init); - const char* joytypes[] = { "auto", "2axis", "4axis", "4axis_2", "fcs", "ch", "none",0}; - Pstring = secprop->Add_string("joysticktype",Property::Changeable::WhenIdle,"auto"); - Pstring->Set_values(joytypes); - Pstring->Set_help( - "Type of joystick to emulate: auto (default), none,\n" - "2axis (supports two joysticks),\n" - "4axis (supports one joystick, first joystick used),\n" - "4axis_2 (supports one joystick, second joystick used),\n" - "fcs (Thrustmaster), ch (CH Flightstick).\n" - "none disables joystick emulation.\n" - "auto chooses emulation depending on real joystick(s)."); - - Pbool = secprop->Add_bool("timed",Property::Changeable::WhenIdle,true); - Pbool->Set_help("enable timed intervals for axis. (false is old style behaviour)."); - - Pbool = secprop->Add_bool("autofire",Property::Changeable::WhenIdle,false); - Pbool->Set_help("continuously fires as long as you keep the button pressed."); - - Pbool = secprop->Add_bool("swap34",Property::Changeable::WhenIdle,false); - Pbool->Set_help("swap the 3rd and the 4th axis. can be useful for certain joysticks."); - - Pbool = secprop->Add_bool("buttonwrap",Property::Changeable::WhenIdle,true); - Pbool->Set_help("enable button wrapping at the number of emulated buttons."); - - secprop=control->AddSection_prop("serial",&SERIAL_Init,true); - const char* serials[] = { "dummy", "disabled", "modem", "nullmodem", - "directserial",0 }; - - Pmulti_remain = secprop->Add_multiremain("serial1",Property::Changeable::WhenIdle," "); - Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy"); - Pmulti_remain->SetValue("dummy"); - Pstring->Set_values(serials); - Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); - Pmulti_remain->Set_help( - "set type of device connected to com port.\n" - "Can be disabled, dummy, modem, nullmodem, directserial.\n" - "Additional parameters must be in the same line in the form of\n" - "parameter:value. Parameter for all types is irq.\n" - "for directserial: realport (required), rxdelay (optional).\n" - " (realport:COM1 realport:ttyS0).\n" - "for modem: listenport (optional).\n" - "for nullmodem: server, rxdelay, txdelay, telnet, usedtr,\n" - " transparent, port, inhsocket (all optional).\n" - "Example: serial1=modem listenport:5000"); - - Pmulti_remain = secprop->Add_multiremain("serial2",Property::Changeable::WhenIdle," "); - Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy"); - Pmulti_remain->SetValue("dummy"); - Pstring->Set_values(serials); - Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); - Pmulti_remain->Set_help("see serial1"); - - Pmulti_remain = secprop->Add_multiremain("serial3",Property::Changeable::WhenIdle," "); - Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled"); - Pmulti_remain->SetValue("disabled"); - Pstring->Set_values(serials); - Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); - Pmulti_remain->Set_help("see serial1"); - - Pmulti_remain = secprop->Add_multiremain("serial4",Property::Changeable::WhenIdle," "); - Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled"); - Pmulti_remain->SetValue("disabled"); - Pstring->Set_values(serials); - Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); - Pmulti_remain->Set_help("see serial1"); - - - /* All the DOS Related stuff, which will eventually start up in the shell */ - secprop=control->AddSection_prop("dos",&DOS_Init,false);//done - secprop->AddInitFunction(&XMS_Init,true);//done - Pbool = secprop->Add_bool("xms",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable XMS support."); - - secprop->AddInitFunction(&EMS_Init,true);//done - Pbool = secprop->Add_bool("ems",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable EMS support."); - - Pbool = secprop->Add_bool("umb",Property::Changeable::WhenIdle,true); - Pbool->Set_help("Enable UMB support."); - - secprop->AddInitFunction(&DOS_KeyboardLayout_Init,true); - Pstring = secprop->Add_string("keyboardlayout",Property::Changeable::WhenIdle, "auto"); - Pstring->Set_help("Language code of the keyboard layout (or none)."); - - // Mscdex - secprop->AddInitFunction(&MSCDEX_Init); - secprop->AddInitFunction(&DRIVES_Init); - secprop->AddInitFunction(&CDROM_Image_Init); -#if C_IPX - secprop=control->AddSection_prop("ipx",&IPX_Init,true); - Pbool = secprop->Add_bool("ipx",Property::Changeable::WhenIdle, false); - Pbool->Set_help("Enable ipx over UDP/IP emulation."); -#endif -// secprop->AddInitFunction(&CREDITS_Init); - - //TODO ? - secline=control->AddSection_line("autoexec",&AUTOEXEC_Init); - MSG_Add("AUTOEXEC_CONFIGFILE_HELP", - "Lines in this section will be run at startup.\n" - ); - MSG_Add("CONFIGFILE_INTRO", - "# This is the configurationfile for DOSBox %s.\n" - "# Lines starting with a # are commentlines.\n" - "# They are used to (briefly) document the effect of each option.\n"); - MSG_Add("CONFIG_SUGGESTED_VALUES", "Possible values"); - - control->SetStartUp(&SHELL_Init); -} +/* + * Copyright (C) 2002-2010 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.cpp,v 1.150 2009-11-03 20:17:42 qbix79 Exp $ */ + +#include +#include +#include +#include +#include +#include "dosbox.h" +#include "debug.h" +#include "cpu.h" +#include "video.h" +#include "pic.h" +#include "cpu.h" +#include "callback.h" +#include "inout.h" +#include "mixer.h" +#include "timer.h" +#include "dos_inc.h" +#include "setup.h" +#include "control.h" +#include "cross.h" +#include "programs.h" +#include "support.h" +#include "mapper.h" +#include "ints/int10.h" +#include "render.h" + +Config * control; +MachineType machine; +SVGACards svgaCard; + +/* The whole load of startups for all the subfunctions */ +void MSG_Init(Section_prop *); +void LOG_StartUp(void); +void MEM_Init(Section *); +void PAGING_Init(Section *); +void IO_Init(Section * ); +void CALLBACK_Init(Section*); +void PROGRAMS_Init(Section*); +//void CREDITS_Init(Section*); +void RENDER_Init(Section*); +void VGA_Init(Section*); + +void DOS_Init(Section*); + + +void CPU_Init(Section*); + +#if C_FPU +void FPU_Init(Section*); +#endif + +void DMA_Init(Section*); + +void MIXER_Init(Section*); +void MIDI_Init(Section*); +void HARDWARE_Init(Section*); + + +void KEYBOARD_Init(Section*); //TODO This should setup INT 16 too but ok ;) +void JOYSTICK_Init(Section*); +void MOUSE_Init(Section*); +void SBLASTER_Init(Section*); +void GUS_Init(Section*); +void MPU401_Init(Section*); +void PCSPEAKER_Init(Section*); +void TANDYSOUND_Init(Section*); +void DISNEY_Init(Section*); +void SERIAL_Init(Section*); + + +#if C_IPX +void IPX_Init(Section*); +#endif + +void SID_Init(Section* sec); + +void PIC_Init(Section*); +void TIMER_Init(Section*); +void BIOS_Init(Section*); +void DEBUG_Init(Section*); +void CMOS_Init(Section*); + +void MSCDEX_Init(Section*); +void DRIVES_Init(Section*); +void CDROM_Image_Init(Section*); + +/* Dos Internal mostly */ +void EMS_Init(Section*); +void XMS_Init(Section*); + +void DOS_KeyboardLayout_Init(Section*); + +void AUTOEXEC_Init(Section*); +void SHELL_Init(void); + +void INT10_Init(Section*); + +static LoopHandler * loop; + +bool SDLNetInited; + +static Bit32u ticksRemain; +static Bit32u ticksLast; +static Bit32u ticksAdded; +Bit32s ticksDone; +Bit32u ticksScheduled; +bool ticksLocked; + +static Bitu Normal_Loop(void) { + Bits ret; + while (1) { + if (PIC_RunQueue()) { + ret=(*cpudecoder)(); + if (GCC_UNLIKELY(ret<0)) return 1; + if (ret>0) { + Bitu blah=(*CallBack_Handlers[ret])(); + if (GCC_UNLIKELY(blah)) return blah; + } +#if C_DEBUG + if (DEBUG_ExitLoop()) return 0; +#endif + } else { + GFX_Events(); + if (ticksRemain>0) { + TIMER_AddTick(); + ticksRemain--; + } else goto increaseticks; + } + } +increaseticks: + 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_CycleAutoAdjust && !CPU_SkipCycleAutoAdjust) { + if (ticksScheduled >= 250 || ticksDone >= 250 || (ticksAdded > 15 && ticksScheduled >= 5) ) { + if(ticksDone < 1) ticksDone = 1; // Protect against div by zero + /* ratio we are aiming for is around 90% usage*/ + Bit32s ratio = (ticksScheduled * (CPU_CyclePercUsed*90*1024/100/100)) / ticksDone; + Bit32s new_cmax = CPU_CycleMax; + Bit64s cproc = (Bit64s)CPU_CycleMax * (Bit64s)ticksScheduled; + if (cproc > 0) { + /* ignore the cycles added due to the io delay code in order + to have smoother auto cycle adjustments */ + double ratioremoved = (double) CPU_IODelayRemoved / (double) cproc; + if (ratioremoved < 1.0) { + ratio = (Bit32s)((double)ratio * (1 - ratioremoved)); + /* Don't allow very high ratio which can cause us to lock as we don't scale down + * for very low ratios. High ratio might result because of timing resolution */ + if (ticksScheduled >= 250 && ticksDone < 10 && ratio > 20480) + ratio = 20480; + Bit64s cmax_scaled = (Bit64s)CPU_CycleMax * (Bit64s)ratio; + if (ratio <= 1024) + new_cmax = (Bit32s)(cmax_scaled / (Bit64s)1024); + else + new_cmax = (Bit32s)(1 + (CPU_CycleMax >> 1) + cmax_scaled / (Bit64s)2048); + } + } + + if (new_cmax10) { + /* ratios below 12% along with a large time since the last update + has taken place are most likely caused by heavy load through a + different application, the cycles adjusting is skipped as well */ + if ((ratio>120) || (ticksDone<700)) { + CPU_CycleMax = new_cmax; + if (CPU_CycleLimit > 0) { + if (CPU_CycleMax>CPU_CycleLimit) CPU_CycleMax = CPU_CycleLimit; + } + } + } + CPU_IODelayRemoved = 0; + ticksDone = 0; + ticksScheduled = 0; + } else if (ticksAdded > 15) { + /* ticksAdded > 15 but ticksScheduled < 5, lower the cycles + but do not reset the scheduled/done ticks to take them into + account during the next auto cycle adjustment */ + CPU_CycleMax /= 3; + if (CPU_CycleMax < CPU_CYCLES_LOWER_LIMIT) + CPU_CycleMax = CPU_CYCLES_LOWER_LIMIT; + } + } + } else { + ticksAdded = 0; + SDL_Delay(1); + ticksDone -= GetTicks() - ticksNew; + if (ticksDone < 0) + ticksDone = 0; + } + } + return 0; +} + +void DOSBOX_SetLoop(LoopHandler * handler) { + loop=handler; +} + +void DOSBOX_SetNormalLoop() { + loop=Normal_Loop; +} + +void DOSBOX_RunMachine(void){ + Bitu ret; + do { + ret=(*loop)(); + } while (!ret); +} + +static void DOSBOX_UnlockSpeed( bool pressed ) { + static bool autoadjust = false; + if (pressed) { + ticksLocked = true; + if (CPU_CycleAutoAdjust) { + autoadjust = true; + CPU_CycleAutoAdjust = false; + CPU_CycleMax /= 3; + if (CPU_CycleMax<1000) CPU_CycleMax=1000; + } + } else { + ticksLocked = false; + if (autoadjust) { + autoadjust = false; + CPU_CycleAutoAdjust = true; + } + } +} + +static void DOSBOX_RealInit(Section * sec) { + Section_prop * section=static_cast(sec); + /* Initialize some dosbox internals */ + + ticksRemain=0; + ticksLast=GetTicks(); + ticksLocked = false; + DOSBOX_SetLoop(&Normal_Loop); + MSG_Init(section); + + MAPPER_AddHandler(DOSBOX_UnlockSpeed, MK_f12, MMOD2,"speedlock","Speedlock"); + std::string cmd_machine; + if (control->cmdline->FindString("-machine",cmd_machine,true)){ + //update value in config (else no matching against suggested values + section->HandleInputline(std::string("machine=") + cmd_machine); + } + + std::string mtype(section->Get_string("machine")); + svgaCard = SVGA_None; + machine = MCH_VGA; + int10.vesa_nolfb = false; + int10.vesa_oldvbe = false; + if (mtype == "cga") { machine = MCH_CGA; } + else if (mtype == "tandy") { machine = MCH_TANDY; } + else if (mtype == "pcjr") { machine = MCH_PCJR; } + else if (mtype == "hercules") { machine = MCH_HERC; } + else if (mtype == "ega") { machine = MCH_EGA; } +// else if (mtype == "vga") { svgaCard = SVGA_S3Trio; } + else if (mtype == "svga_s3") { svgaCard = SVGA_S3Trio; } + else if (mtype == "vesa_nolfb") { svgaCard = SVGA_S3Trio; int10.vesa_nolfb = true;} + else if (mtype == "vesa_oldvbe") { svgaCard = SVGA_S3Trio; int10.vesa_oldvbe = true;} + else if (mtype == "svga_et4000") { svgaCard = SVGA_TsengET4K; } + else if (mtype == "svga_et3000") { svgaCard = SVGA_TsengET3K; } +// else if (mtype == "vga_pvga1a") { svgaCard = SVGA_ParadisePVGA1A; } + else if (mtype == "svga_paradise") { svgaCard = SVGA_ParadisePVGA1A; } + else if (mtype == "vgaonly") { svgaCard = SVGA_None; } + else E_Exit("DOSBOX:Unknown machine type %s",mtype.c_str()); +} + + +void DOSBOX_Init(void) { + Section_prop * secprop; + Section_line * secline; + Prop_int* Pint; + Prop_hex* Phex; + Prop_string* Pstring; + Prop_bool* Pbool; + Prop_multival* Pmulti; + Prop_multival_remain* Pmulti_remain; + + SDLNetInited = false; + + // Some frequently used option sets + const char *rates[] = { "22050", "44100", "48000", "32000", "16000", "11025", "8000", "49716", 0 }; + const char *oplrates[] = { "22050", "49716", "44100", "48000", "32000", "16000", "11025", "8000", 0 }; + const char *ios[] = { "220", "240", "260", "280", "2a0", "2c0", "2e0", "300", 0 }; + const char *irqssb[] = { "7", "5", "3", "9", "10", "11", "12", 0 }; + const char *dmassb[] = { "1", "5", "0", "3", "6", "7", 0 }; + const char *iosgus[] = { "240", "220", "260", "280", "2a0", "2c0", "2e0", "300", 0 }; + const char *irqsgus[] = { "5", "3", "7", "9", "10", "11", "12", 0 }; + const char *dmasgus[] = { "3", "0", "1", "5", "6", "7", 0 }; + + + /* Setup all the different modules making up DOSBox */ + const char* machines[] = { + "hercules", "cga", "tandy", "pcjr", "ega", + "vgaonly", "svga_s3", "svga_et3000", "svga_et4000", + "svga_paradise", "vesa_nolfb", "vesa_oldvbe", 0 }; + secprop=control->AddSection_prop("dosbox",&DOSBOX_RealInit); + Pstring = secprop->Add_path("language",Property::Changeable::Always,""); + Pstring->Set_help("Select another language file."); + + Pstring = secprop->Add_string("machine",Property::Changeable::OnlyAtStart,"svga_s3"); + Pstring->Set_values(machines); + Pstring->Set_help("The type of machine tries to emulate."); + + Pstring = secprop->Add_path("captures",Property::Changeable::Always,"capture"); + Pstring->Set_help("Directory where things like wave, midi, screenshot get captured."); + +#if C_DEBUG + LOG_StartUp(); +#endif + + secprop->AddInitFunction(&IO_Init);//done + secprop->AddInitFunction(&PAGING_Init);//done + secprop->AddInitFunction(&MEM_Init);//done + secprop->AddInitFunction(&HARDWARE_Init);//done + Pint = secprop->Add_int("memsize", Property::Changeable::WhenIdle,16); + Pint->SetMinMax(1,63); + Pint->Set_help( + "Amount of memory DOSBox has in megabytes.\n" + " This value is best left at its default to avoid problems with some games,\n" + " though few games might require a higher value.\n" + " There is generally no speed advantage when raising this value."); + secprop->AddInitFunction(&CALLBACK_Init); + secprop->AddInitFunction(&PIC_Init);//done + secprop->AddInitFunction(&PROGRAMS_Init); + secprop->AddInitFunction(&TIMER_Init);//done + secprop->AddInitFunction(&CMOS_Init);//done + + secprop=control->AddSection_prop("render",&RENDER_Init,true); + Pint = secprop->Add_int("frameskip",Property::Changeable::Always,0); + Pint->SetMinMax(0,10); + Pint->Set_help("How many frames DOSBox skips before drawing one."); + + Pbool = secprop->Add_bool("aspect",Property::Changeable::Always,false); + Pbool->Set_help("Do aspect correction, if your output method doesn't support scaling this can slow things down!."); + + Pmulti = secprop->Add_multi("scaler",Property::Changeable::Always," "); + Pmulti->SetValue("normal2x"); + Pmulti->Set_help("Scaler used to enlarge/enhance low resolution modes. If 'forced' is appended,the scaler will be used even if the result might not be desired."); + Pstring = Pmulti->GetSection()->Add_string("type",Property::Changeable::Always,"normal2x"); + + const char *scalers[] = { + "none", "normal2x", "normal3x", +#if RENDER_USE_ADVANCED_SCALERS>2 + "advmame2x", "advmame3x", "advinterp2x", "advinterp3x", "hq2x", "hq3x", "2xsai", "super2xsai", "supereagle", +#endif +#if RENDER_USE_ADVANCED_SCALERS>0 + "tv2x", "tv3x", "rgb2x", "rgb3x", "scan2x", "scan3x", +#endif + 0 }; + Pstring->Set_values(scalers); + + const char* force[] = { "", "forced", 0 }; + Pstring = Pmulti->GetSection()->Add_string("force",Property::Changeable::Always,""); + Pstring->Set_values(force); + + secprop=control->AddSection_prop("cpu",&CPU_Init,true);//done + const char* cores[] = { "auto", +#if (C_DYNAMIC_X86) || (C_DYNREC) + "dynamic", +#endif + "normal", "simple",0 }; + Pstring = secprop->Add_string("core",Property::Changeable::WhenIdle,"auto"); + Pstring->Set_values(cores); + Pstring->Set_help("CPU Core used in emulation. auto will switch to dynamic if available and appropriate."); + + const char* cputype_values[] = { "auto", "386", "386_slow", "486_slow", "pentium_slow", "386_prefetch", 0}; + Pstring = secprop->Add_string("cputype",Property::Changeable::Always,"auto"); + Pstring->Set_values(cputype_values); + Pstring->Set_help("CPU Type used in emulation. auto is the fastest choice."); + + + Pmulti_remain = secprop->Add_multiremain("cycles",Property::Changeable::Always," "); + Pmulti_remain->Set_help( + "Amount of instructions DOSBox tries to emulate each millisecond. Setting this value too high results in sound dropouts and lags. Cycles can be set in 3 ways:\n" + " 'auto' tries to guess what a game needs.\n" + " It usually works, but can fail for certain games.\n" + " 'fixed #number' will set a fixed amount of cycles. This is what you usually need if 'auto' fails.\n" + " (Example: fixed 4000)\n" + " 'max' will allocate as much cycles as your computer is able to handle.\n"); + + const char* cyclest[] = { "auto","fixed","max","%u",0 }; + Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::Always,"auto"); + Pmulti_remain->SetValue("auto"); + Pstring->Set_values(cyclest); + + Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::Always,""); + + Pint = secprop->Add_int("cycleup",Property::Changeable::Always,500); + Pint->SetMinMax(1,1000000); + Pint->Set_help("Amount of cycles to increase/decrease with keycombo."); + + Pint = secprop->Add_int("cycledown",Property::Changeable::Always,20); + Pint->SetMinMax(1,1000000); + Pint->Set_help("Setting it lower than 100 will be a percentage."); + +#if C_FPU + secprop->AddInitFunction(&FPU_Init); +#endif + secprop->AddInitFunction(&DMA_Init);//done + secprop->AddInitFunction(&VGA_Init); + secprop->AddInitFunction(&KEYBOARD_Init); + + secprop=control->AddSection_prop("mixer",&MIXER_Init); + Pbool = secprop->Add_bool("nosound",Property::Changeable::OnlyAtStart,false); + Pbool->Set_help("Enable silent mode, sound is still emulated though."); + + Pint = secprop->Add_int("rate",Property::Changeable::OnlyAtStart,22050); + Pint->Set_values(rates); + Pint->Set_help("Mixer sample rate, setting any device's rate higher than this will probably lower their sound quality."); + + const char *blocksizes[] = { + "2048", "4096", "8192", "1024", "512", "256", 0}; +#ifdef HW_RVL + Pint = secprop->Add_int("blocksize",Property::Changeable::OnlyAtStart,512); +#else + Pint = secprop->Add_int("blocksize",Property::Changeable::OnlyAtStart,2048); +#endif + Pint->Set_values(blocksizes); + Pint->Set_help("Mixer block size, larger blocks might help sound stuttering but sound will also be more lagged."); + + Pint = secprop->Add_int("prebuffer",Property::Changeable::OnlyAtStart,10); + Pint->SetMinMax(0,100); + Pint->Set_help("How many milliseconds of data to keep on top of the blocksize."); + + secprop=control->AddSection_prop("midi",&MIDI_Init,true);//done + secprop->AddInitFunction(&MPU401_Init,true);//done + + const char* mputypes[] = { "intelligent", "uart", "none",0}; + // FIXME: add some way to offer the actually available choices. + const char *devices[] = { "default", "win32", "alsa", "oss", "coreaudio", "coremidi","none", 0}; + Pstring = secprop->Add_string("mpu401",Property::Changeable::WhenIdle,"intelligent"); + Pstring->Set_values(mputypes); + Pstring->Set_help("Type of MPU-401 to emulate."); + + Pstring = secprop->Add_string("mididevice",Property::Changeable::WhenIdle,"default"); + Pstring->Set_values(devices); + Pstring->Set_help("Device that will receive the MIDI data from MPU-401."); + + Pstring = secprop->Add_string("midiconfig",Property::Changeable::WhenIdle,""); + Pstring->Set_help("Special configuration options for the device driver. This is usually the id of the device you want to use. See README for details."); + +#if C_DEBUG + secprop=control->AddSection_prop("debug",&DEBUG_Init); +#endif + + secprop=control->AddSection_prop("sblaster",&SBLASTER_Init,true);//done + + const char* sbtypes[] = { "sb1", "sb2", "sbpro1", "sbpro2", "sb16", "gb", "none", 0 }; + Pstring = secprop->Add_string("sbtype",Property::Changeable::WhenIdle,"sb16"); + Pstring->Set_values(sbtypes); + Pstring->Set_help("Type of Soundblaster to emulate. gb is Gameblaster."); + + Phex = secprop->Add_hex("sbbase",Property::Changeable::WhenIdle,0x220); + Phex->Set_values(ios); + Phex->Set_help("The IO address of the soundblaster."); + + Pint = secprop->Add_int("irq",Property::Changeable::WhenIdle,7); + Pint->Set_values(irqssb); + Pint->Set_help("The IRQ number of the soundblaster."); + + Pint = secprop->Add_int("dma",Property::Changeable::WhenIdle,1); + Pint->Set_values(dmassb); + Pint->Set_help("The DMA number of the soundblaster."); + + Pint = secprop->Add_int("hdma",Property::Changeable::WhenIdle,5); + Pint->Set_values(dmassb); + Pint->Set_help("The High DMA number of the soundblaster."); + + Pbool = secprop->Add_bool("sbmixer",Property::Changeable::WhenIdle,true); + Pbool->Set_help("Allow the soundblaster mixer to modify the DOSBox mixer."); + + const char* oplmodes[]={ "auto", "cms", "opl2", "dualopl2", "opl3", "none", 0}; + Pstring = secprop->Add_string("oplmode",Property::Changeable::WhenIdle,"auto"); + Pstring->Set_values(oplmodes); + Pstring->Set_help("Type of OPL emulation. On 'auto' the mode is determined by sblaster type. All OPL modes are Adlib-compatible, except for 'cms'."); + + const char* oplemus[]={ "default", "compat", "fast", 0}; + Pstring = secprop->Add_string("oplemu",Property::Changeable::WhenIdle,"default"); + Pstring->Set_values(oplemus); + Pstring->Set_help("Provider for the OPL emulation. compat might provide better quality (see oplrate as well)."); + + Pint = secprop->Add_int("oplrate",Property::Changeable::WhenIdle,22050); + Pint->Set_values(oplrates); + Pint->Set_help("Sample rate of OPL music emulation. Use 49716 for highest quality (set the mixer rate accordingly)."); + + + secprop=control->AddSection_prop("gus",&GUS_Init,true); //done + Pbool = secprop->Add_bool("gus",Property::Changeable::WhenIdle,false); + Pbool->Set_help("Enable the Gravis Ultrasound emulation."); + + Pint = secprop->Add_int("gusrate",Property::Changeable::WhenIdle,22050); + Pint->Set_values(rates); + Pint->Set_help("Sample rate of Ultrasound emulation."); + + Phex = secprop->Add_hex("gusbase",Property::Changeable::WhenIdle,0x240); + Phex->Set_values(iosgus); + Phex->Set_help("The IO base address of the Gravis Ultrasound."); + + Pint = secprop->Add_int("gusirq",Property::Changeable::WhenIdle,5); + Pint->Set_values(irqsgus); + Pint->Set_help("The IRQ number of the Gravis Ultrasound."); + + Pint = secprop->Add_int("gusdma",Property::Changeable::WhenIdle,3); + Pint->Set_values(dmasgus); + Pint->Set_help("The DMA channel of the Gravis Ultrasound."); + + Pstring = secprop->Add_string("ultradir",Property::Changeable::WhenIdle,"C:\\ULTRASND"); + Pstring->Set_help( + "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."); + + secprop = control->AddSection_prop("speaker",&PCSPEAKER_Init,true);//done + Pbool = secprop->Add_bool("pcspeaker",Property::Changeable::WhenIdle,true); + Pbool->Set_help("Enable PC-Speaker emulation."); + + Pint = secprop->Add_int("pcrate",Property::Changeable::WhenIdle,22050); + Pint->Set_values(rates); + Pint->Set_help("Sample rate of the PC-Speaker sound generation."); + + secprop->AddInitFunction(&TANDYSOUND_Init,true);//done + const char* tandys[] = { "auto", "on", "off", 0}; + Pstring = secprop->Add_string("tandy",Property::Changeable::WhenIdle,"auto"); + Pstring->Set_values(tandys); + Pstring->Set_help("Enable Tandy Sound System emulation. For 'auto', emulation is present only if machine is set to 'tandy'."); + + Pint = secprop->Add_int("tandyrate",Property::Changeable::WhenIdle,22050); + Pint->Set_values(rates); + Pint->Set_help("Sample rate of the Tandy 3-Voice generation."); + + secprop->AddInitFunction(&DISNEY_Init,true);//done + + Pbool = secprop->Add_bool("disney",Property::Changeable::WhenIdle,true); + Pbool->Set_help("Enable Disney Sound Source emulation. (Covox Voice Master and Speech Thing compatible)."); + + secprop=control->AddSection_prop("joystick",&BIOS_Init,false);//done + secprop->AddInitFunction(&INT10_Init); + secprop->AddInitFunction(&MOUSE_Init); //Must be after int10 as it uses CurMode + secprop->AddInitFunction(&JOYSTICK_Init); + const char* joytypes[] = { "auto", "2axis", "4axis", "4axis_2", "fcs", "ch", "none",0}; + Pstring = secprop->Add_string("joysticktype",Property::Changeable::WhenIdle,"auto"); + Pstring->Set_values(joytypes); + Pstring->Set_help( + "Type of joystick to emulate: auto (default), none,\n" + "2axis (supports two joysticks),\n" + "4axis (supports one joystick, first joystick used),\n" + "4axis_2 (supports one joystick, second joystick used),\n" + "fcs (Thrustmaster), ch (CH Flightstick).\n" + "none disables joystick emulation.\n" + "auto chooses emulation depending on real joystick(s)."); + + Pbool = secprop->Add_bool("timed",Property::Changeable::WhenIdle,true); + Pbool->Set_help("enable timed intervals for axis. (false is old style behaviour)."); + + Pbool = secprop->Add_bool("autofire",Property::Changeable::WhenIdle,false); + Pbool->Set_help("continuously fires as long as you keep the button pressed."); + + Pbool = secprop->Add_bool("swap34",Property::Changeable::WhenIdle,false); + Pbool->Set_help("swap the 3rd and the 4th axis. can be useful for certain joysticks."); + + Pbool = secprop->Add_bool("buttonwrap",Property::Changeable::WhenIdle,false); + Pbool->Set_help("enable button wrapping at the number of emulated buttons."); + + secprop=control->AddSection_prop("serial",&SERIAL_Init,true); + const char* serials[] = { "dummy", "disabled", "modem", "nullmodem", + "directserial",0 }; + + Pmulti_remain = secprop->Add_multiremain("serial1",Property::Changeable::WhenIdle," "); + Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy"); + Pmulti_remain->SetValue("dummy"); + Pstring->Set_values(serials); + Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); + Pmulti_remain->Set_help( + "set type of device connected to com port.\n" + "Can be disabled, dummy, modem, nullmodem, directserial.\n" + "Additional parameters must be in the same line in the form of\n" + "parameter:value. Parameter for all types is irq (optional).\n" + "for directserial: realport (required), rxdelay (optional).\n" + " (realport:COM1 realport:ttyS0).\n" + "for modem: listenport (optional).\n" + "for nullmodem: server, rxdelay, txdelay, telnet, usedtr,\n" + " transparent, port, inhsocket (all optional).\n" + "Example: serial1=modem listenport:5000"); + + Pmulti_remain = secprop->Add_multiremain("serial2",Property::Changeable::WhenIdle," "); + Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"dummy"); + Pmulti_remain->SetValue("dummy"); + Pstring->Set_values(serials); + Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); + Pmulti_remain->Set_help("see serial1"); + + Pmulti_remain = secprop->Add_multiremain("serial3",Property::Changeable::WhenIdle," "); + Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled"); + Pmulti_remain->SetValue("disabled"); + Pstring->Set_values(serials); + Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); + Pmulti_remain->Set_help("see serial1"); + + Pmulti_remain = secprop->Add_multiremain("serial4",Property::Changeable::WhenIdle," "); + Pstring = Pmulti_remain->GetSection()->Add_string("type",Property::Changeable::WhenIdle,"disabled"); + Pmulti_remain->SetValue("disabled"); + Pstring->Set_values(serials); + Pstring = Pmulti_remain->GetSection()->Add_string("parameters",Property::Changeable::WhenIdle,""); + Pmulti_remain->Set_help("see serial1"); + + + /* All the DOS Related stuff, which will eventually start up in the shell */ + secprop=control->AddSection_prop("dos",&DOS_Init,false);//done + secprop->AddInitFunction(&XMS_Init,true);//done + Pbool = secprop->Add_bool("xms",Property::Changeable::WhenIdle,true); + Pbool->Set_help("Enable XMS support."); + + secprop->AddInitFunction(&EMS_Init,true);//done + Pbool = secprop->Add_bool("ems",Property::Changeable::WhenIdle,true); + Pbool->Set_help("Enable EMS support."); + + Pbool = secprop->Add_bool("umb",Property::Changeable::WhenIdle,true); + Pbool->Set_help("Enable UMB support."); + + secprop->AddInitFunction(&DOS_KeyboardLayout_Init,true); + Pstring = secprop->Add_string("keyboardlayout",Property::Changeable::WhenIdle, "auto"); + Pstring->Set_help("Language code of the keyboard layout (or none)."); + + // Mscdex + secprop->AddInitFunction(&MSCDEX_Init); + secprop->AddInitFunction(&DRIVES_Init); + secprop->AddInitFunction(&CDROM_Image_Init); +#if C_IPX + secprop=control->AddSection_prop("ipx",&IPX_Init,true); + Pbool = secprop->Add_bool("ipx",Property::Changeable::WhenIdle, false); + Pbool->Set_help("Enable ipx over UDP/IP emulation."); +#endif +// secprop->AddInitFunction(&CREDITS_Init); + + //TODO ? + secline=control->AddSection_line("autoexec",&AUTOEXEC_Init); + MSG_Add("AUTOEXEC_CONFIGFILE_HELP", + "Lines in this section will be run at startup.\n" + ); + MSG_Add("CONFIGFILE_INTRO", + "# This is the configurationfile for DOSBox %s.\n" + "# Lines starting with a # are commentlines.\n" + "# They are used to (briefly) document the effect of each option.\n"); + MSG_Add("CONFIG_SUGGESTED_VALUES", "Possible values"); + + control->SetStartUp(&SHELL_Init); +} diff --git a/src/fpu/fpu.cpp b/src/fpu/fpu.cpp index fade5f1..48c5b96 100644 --- a/src/fpu/fpu.cpp +++ b/src/fpu/fpu.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/fpu/fpu_instructions.h b/src/fpu/fpu_instructions.h index ec2f810..9a505a2 100644 --- a/src/fpu/fpu_instructions.h +++ b/src/fpu/fpu_instructions.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -106,7 +106,7 @@ static Real64 FPU_FLD80(PhysPt addr) { Bit64s sign = (test.begin&0x8000)?1:0; FPU_Reg result; result.ll = (sign <<63)|(exp64final << 52)| mant64; - return result.d; + return result.d; //mant64= test.mant80/2***64 * 2 **53 } @@ -118,12 +118,16 @@ static void FPU_ST80(PhysPt addr,Bitu reg) { } 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 exp80final = (exp80>>52); 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); + if(fpu.regs[reg].d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= LONGTYPE(0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + 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); @@ -239,7 +243,7 @@ static void FPU_FST_I64(PhysPt addr) { static void FPU_FBST(PhysPt addr) { FPU_Reg val = fpu.regs[TOP]; bool sign = false; - if(val.d<0.0){ //sign + if(fpu.regs[TOP].ll & LONGTYPE(0x8000000000000000)) { //sign sign=true; val.d=-val.d; } @@ -519,7 +523,7 @@ static void FPU_FXTRACT(void) { Bit64s exp80final = (exp80>>52) - BIAS64; Real64 mant = test.d / (pow(2.0,static_cast(exp80final))); fpu.regs[TOP].d = static_cast(exp80final); - FPU_PUSH(mant); + FPU_PUSH(mant); } static void FPU_FCHS(void){ diff --git a/src/fpu/fpu_instructions_x86.h b/src/fpu/fpu_instructions_x86.h index 8d5ad72..16d96d6 100644 --- a/src/fpu/fpu_instructions_x86.h +++ b/src/fpu/fpu_instructions_x86.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dosbox_logo.h b/src/gui/dosbox_logo.h index 25f2c15..4895d7d 100644 --- a/src/gui/dosbox_logo.h +++ b/src/gui/dosbox_logo.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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.cpp b/src/gui/midi.cpp index 1ddbd37..61d15e5 100644 --- a/src/gui/midi.cpp +++ b/src/gui/midi.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_alsa.h b/src/gui/midi_alsa.h index 36f7e96..4c57ffa 100644 --- a/src/gui/midi_alsa.h +++ b/src/gui/midi_alsa.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_coreaudio.h b/src/gui/midi_coreaudio.h index 4dc5048..82f4c13 100644 --- a/src/gui/midi_coreaudio.h +++ b/src/gui/midi_coreaudio.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 0010d8a..e1d8d97 100644 --- a/src/gui/midi_oss.h +++ b/src/gui/midi_oss.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_win32.h b/src/gui/midi_win32.h index 7efb756..a71904b 100644 --- a/src/gui/midi_win32.h +++ b/src/gui/midi_win32.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render.cpp b/src/gui/render.cpp index c25e6ca..c76047c 100644 --- a/src/gui/render.cpp +++ b/src/gui/render.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_loops.h b/src/gui/render_loops.h index 4986779..4d74249 100644 --- a/src/gui/render_loops.h +++ b/src/gui/render_loops.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_scalers.cpp b/src/gui/render_scalers.cpp index 784ff49..35da160 100644 --- a/src/gui/render_scalers.cpp +++ b/src/gui/render_scalers.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_scalers.h b/src/gui/render_scalers.h index 1287b8b..938b790 100644 --- a/src/gui/render_scalers.h +++ b/src/gui/render_scalers.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_simple.h b/src/gui/render_simple.h index b873acc..23f40af 100644 --- a/src/gui/render_simple.h +++ b/src/gui/render_simple.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_templates.h b/src/gui/render_templates.h index 4959d45..39ab2ef 100644 --- a/src/gui/render_templates.h +++ b/src/gui/render_templates.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_templates_hq.h b/src/gui/render_templates_hq.h index 661604e..3114dc7 100644 --- a/src/gui/render_templates_hq.h +++ b/src/gui/render_templates_hq.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_templates_hq2x.h b/src/gui/render_templates_hq2x.h index 764d278..5e4072e 100644 --- a/src/gui/render_templates_hq2x.h +++ b/src/gui/render_templates_hq2x.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_templates_hq3x.h b/src/gui/render_templates_hq3x.h index 6f72393..13b6873 100644 --- a/src/gui/render_templates_hq3x.h +++ b/src/gui/render_templates_hq3x.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/render_templates_sai.h b/src/gui/render_templates_sai.h index 62da940..022d3b3 100644 --- a/src/gui/render_templates_sai.h +++ b/src/gui/render_templates_sai.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/sdl_gui.cpp b/src/gui/sdl_gui.cpp index fa653e8..6ddae4a 100644 --- a/src/gui/sdl_gui.cpp +++ b/src/gui/sdl_gui.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -575,7 +575,7 @@ public: Section_prop *section = static_cast(sec); new SectionEditor(getScreen(), 50, 30, section); } else if (arg == "About") { - new GUI::MessageBox(getScreen(), 200, 150, 280, "About DOSBox", "\nDOSBox 0.73\nAn emulator for old DOS Games\n\nCopyright 2002-2009\nThe DOSBox Team"); + new GUI::MessageBox(getScreen(), 200, 150, 280, "About DOSBox", "\nDOSBox 0.73\nAn emulator for old DOS Games\n\nCopyright 2002-2010\nThe DOSBox Team"); } else if (arg == "Introduction") { new GUI::MessageBox(getScreen(), 20, 50, 600, "Introduction", MSG_Get("PROGRAM_INTRO")); } else if (arg == "Getting Started") { diff --git a/src/gui/sdl_mapper.cpp b/src/gui/sdl_mapper.cpp index 480f0e4..60393cf 100644 --- a/src/gui/sdl_mapper.cpp +++ b/src/gui/sdl_mapper.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/sdlmain.cpp b/src/gui/sdlmain.cpp index a748431..66c6ed6 100644 --- a/src/gui/sdlmain.cpp +++ b/src/gui/sdlmain.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -1474,7 +1474,6 @@ static BOOL WINAPI ConsoleEventHandler(DWORD event) { /* 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 const* format,...) { char buf[512]; va_list msg; @@ -1549,7 +1548,7 @@ void Config_Add_SDL() { Pstring = Pmulti->GetSection()->Add_string("inactive",Property::Changeable::Always,"normal"); Pstring->Set_values(inactt); - Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,"mapper.txt"); + Pstring = sdl_sec->Add_path("mapperfile",Property::Changeable::Always,"mapper.conf"); Pstring->Set_help("File used to load/save the key/event mappings from."); Pbool = sdl_sec->Add_bool("usescancodes",Property::Changeable::Always,true); @@ -1726,7 +1725,7 @@ int main(int argc, char* argv[]) { #endif //defined(WIN32) && !(C_DEBUG) if (control->cmdline->FindExist("-version") || control->cmdline->FindExist("--version") ) { - printf("\nDOSBox version %s, copyright 2002-2009 DOSBox Team.\n\n",VERSION); + printf("\nDOSBox version %s, copyright 2002-2010 DOSBox Team.\n\n",VERSION); printf("DOSBox is written by the DOSBox Team (See AUTHORS file))\n"); printf("DOSBox comes with ABSOLUTELY NO WARRANTY. This is free software,\n"); printf("and you are welcome to redistribute it under certain conditions;\n"); @@ -1754,11 +1753,13 @@ int main(int argc, char* argv[]) { /* Display Welcometext in the console */ LOG_MSG("DOSBox version %s",VERSION); - LOG_MSG("Copyright 2002-2009 DOSBox Team, published under GNU GPL."); + LOG_MSG("Copyright 2002-2010 DOSBox Team, published under GNU GPL."); LOG_MSG("---"); /* Init SDL */ - putenv(const_cast("SDL_DISABLE_LOCK_KEYS=1")); //Workaround debian/ubuntu fixes for SDL. +#if SDL_VERSION_ATLEAST(1, 2, 14) + putenv(const_cast("SDL_DISABLE_LOCK_KEYS=1")); +#endif if ( SDL_Init( SDL_INIT_AUDIO|SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_CDROM |SDL_INIT_NOPARACHUTE ) < 0 ) E_Exit("Can't init SDL %s",SDL_GetError()); diff --git a/src/hardware/adlib.cpp b/src/hardware/adlib.cpp index 2331177..7a0a5e6 100644 --- a/src/hardware/adlib.cpp +++ b/src/hardware/adlib.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/adlib.h b/src/hardware/adlib.h index f82953d..5070d66 100644 --- a/src/hardware/adlib.h +++ b/src/hardware/adlib.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/cmos.cpp b/src/hardware/cmos.cpp index 35f3df8..e6adad5 100644 --- a/src/hardware/cmos.cpp +++ b/src/hardware/cmos.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dbopl.cpp b/src/hardware/dbopl.cpp index b5ff85e..df1c754 100644 --- a/src/hardware/dbopl.cpp +++ b/src/hardware/dbopl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dbopl.h b/src/hardware/dbopl.h index c0e5367..c6334e0 100644 --- a/src/hardware/dbopl.h +++ b/src/hardware/dbopl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/disney.cpp b/src/hardware/disney.cpp index 89b3ce5..867d32f 100644 --- a/src/hardware/disney.cpp +++ b/src/hardware/disney.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/dma.cpp b/src/hardware/dma.cpp index c58dc03..542f596 100644 --- a/src/hardware/dma.cpp +++ b/src/hardware/dma.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/gameblaster.cpp b/src/hardware/gameblaster.cpp index 628d368..210817c 100644 --- a/src/hardware/gameblaster.cpp +++ b/src/hardware/gameblaster.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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,6 +22,7 @@ #include "mem.h" #include "hardware.h" #include "setup.h" +#include "support.h" #include "pic.h" #include #include @@ -139,6 +140,7 @@ static Bit16s * cms_buf_point[4] = { cms_buffer[0][0],cms_buffer[0][1],cms_buffer[1][0],cms_buffer[1][1] }; static Bitu last_command; +static Bitu base_port; static void saa1099_envelope(int chip, int ch) @@ -286,6 +288,16 @@ static void saa1099_update(int chip, INT16 **buffer, int length) static void saa1099_write_port_w( int chip, int offset, int data ) { struct SAA1099 *saa = &saa1099[chip]; + if(offset == 1) { + // address port + saa->selected_reg = data & 0x1f; + if (saa->selected_reg == 0x18 || saa->selected_reg == 0x19) { + /* clock the envelope channels */ + if (saa->env_clock[0]) saa1099_envelope(chip,0); + if (saa->env_clock[1]) saa1099_envelope(chip,1); + } + return; + } int reg = saa->selected_reg; int ch; @@ -364,37 +376,26 @@ static void saa1099_write_port_w( int chip, int offset, int data ) } } - -static void write_cms(Bitu port,Bitu val,Bitu iolen) { - if (last_command + 1000 < PIC_Ticks) if(cms_chan) cms_chan->Enable(true); +static void write_cms(Bitu port, Bitu val, Bitu /* iolen */) { + if(cms_chan && (!cms_chan->enabled)) cms_chan->Enable(true); last_command = PIC_Ticks; - switch (port) { - case 0x0220: + switch (port-base_port) { + case 0: + saa1099_write_port_w(0,0,val); + break; + case 1: saa1099_write_port_w(0,1,val); break; - case 0x221: - saa1099[0].selected_reg = val & 0x1f; - if (saa1099[0].selected_reg == 0x18 || saa1099[0].selected_reg == 0x19) { - /* clock the envelope channels */ - if (saa1099[0].env_clock[0]) saa1099_envelope(0,0); - if (saa1099[0].env_clock[1]) saa1099_envelope(0,1); - } + case 2: + saa1099_write_port_w(1,0,val); break; - case 0x0222: + case 3: saa1099_write_port_w(1,1,val); break; - case 0x223: - saa1099[1].selected_reg = val & 0x1f; - if (saa1099[1].selected_reg == 0x18 || saa1099[1].selected_reg == 0x19) { - /* clock the envelope channels */ - if (saa1099[1].env_clock[0]) saa1099_envelope(1,0); - if (saa1099[1].env_clock[1]) saa1099_envelope(1,1); - } - break; } } - static void CMS_CallBack(Bitu len) { +static void CMS_CallBack(Bitu len) { if (len > CMS_BUFFER_SIZE) return; saa1099_update(0, &cms_buf_point[0], (int)len); @@ -421,10 +422,38 @@ static void write_cms(Bitu port,Bitu val,Bitu iolen) { if (last_command + 10000 < PIC_Ticks) if(cms_chan) cms_chan->Enable(false); } +// The Gameblaster detection +static Bit8u cms_detect_register = 0xff; + +static void write_cms_detect(Bitu port, Bitu val, Bitu /* iolen */) { + switch(port-base_port) { + case 0x6: + case 0x7: + cms_detect_register = val; + break; + } +} + +static Bitu read_cms_detect(Bitu port, Bitu /* iolen */) { + Bit8u retval = 0xff; + switch(port-base_port) { + case 0x4: + retval = 0x7f; + break; + case 0xa: + case 0xb: + retval = cms_detect_register; + break; + } + return retval; +} + class CMS:public Module_base { private: IO_WriteHandleObject WriteHandler; + IO_WriteHandleObject DetWriteHandler; + IO_ReadHandleObject DetReadHandler; MixerObject MixerChan; public: @@ -432,8 +461,16 @@ public: 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); + base_port = section->Get_hex("sbbase"); + WriteHandler.Install(base_port, write_cms, IO_MB,4); + + // A standalone Gameblaster has a magic chip on it which is + // sometimes used for detection. + const char * sbtype=section->Get_string("sbtype"); + if (!strcasecmp(sbtype,"gb")) { + DetWriteHandler.Install(base_port+4,write_cms_detect,IO_MB,12); + DetReadHandler.Install(base_port,read_cms_detect,IO_MB,16); + } /* Register the Mixer CallBack */ cms_chan = MixerChan.Install(CMS_CallBack,sample_rate_temp,"CMS"); diff --git a/src/hardware/gus.cpp b/src/hardware/gus.cpp index 727ad07..aa230dc 100644 --- a/src/hardware/gus.cpp +++ b/src/hardware/gus.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/hardware.cpp b/src/hardware/hardware.cpp index 378f718..42570b2 100644 --- a/src/hardware/hardware.cpp +++ b/src/hardware/hardware.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/iohandler.cpp b/src/hardware/iohandler.cpp index 328c780..d53ad70 100644 --- a/src/hardware/iohandler.cpp +++ b/src/hardware/iohandler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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,6 +26,8 @@ #include "../src/cpu/lazyflags.h" #include "callback.h" +//#define ENABLE_PORTLOG + IO_WriteHandler * io_writehandlers[3][IO_MAX]; IO_ReadHandler * io_readhandlers[3][IO_MAX]; @@ -209,8 +211,74 @@ inline void IO_USEC_write_delay() { CPU_IODelayRemoved += delaycyc; } +#ifdef ENABLE_PORTLOG +static Bit8u crtc_index = 0; +const char* const len_type[] = {" 8","16","32"}; +void log_io(Bitu width, bool write, Bitu port, Bitu val) { + switch(width) { + case 0: + val&=0xff; + break; + case 1: + val&=0xffff; + break; + } + if (write) { + // skip the video cursor position spam + if (port==0x3d4) { + if (width==0) crtc_index = (Bit8u)val; + else if(width==1) crtc_index = (Bit8u)(val>>8); + } + if (crtc_index==0xe || crtc_index==0xf) { + if((width==0 && (port==0x3d4 || port==0x3d5))||(width==1 && port==0x3d4)) + return; + } + + switch(port) { + //case 0x020: // interrupt command + //case 0x040: // timer 0 + //case 0x042: // timer 2 + //case 0x043: // timer control + //case 0x061: // speaker control + case 0x3c8: // VGA palette + case 0x3c9: // VGA palette + // case 0x3d4: // VGA crtc + // case 0x3d5: // VGA crtc + // case 0x3c4: // VGA seq + // case 0x3c5: // VGA seq + break; + default: + LOG_MSG("iow%s % 4x % 4x, cs:ip %04x:%04x", len_type[width], + port, val, SegValue(cs),reg_eip); + break; + } + } else { + switch(port) { + //case 0x021: // interrupt status + //case 0x040: // timer 0 + //case 0x042: // timer 2 + //case 0x061: // speaker control + case 0x201: // joystick status + case 0x3c9: // VGA palette + // case 0x3d4: // VGA crtc index + // case 0x3d5: // VGA crtc + case 0x3da: // display status - a real spammer + // don't log for the above cases + break; + default: + LOG_MSG("ior%s % 4x % 4x,\t\tcs:ip %04x:%04x", len_type[width], + port, val, SegValue(cs),reg_eip); + break; + } + } +} +#else +#define log_io(W, X, Y, Z) +#endif + void IO_WriteB(Bitu port,Bitu val) { + log_io(0, true, port, val); if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,1)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -246,6 +314,7 @@ void IO_WriteB(Bitu port,Bitu val) { } void IO_WriteW(Bitu port,Bitu val) { + log_io(1, true, port, val); if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,2)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -281,6 +350,7 @@ void IO_WriteW(Bitu port,Bitu val) { } void IO_WriteD(Bitu port,Bitu val) { + log_io(2, true, port, val); if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,4)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -313,6 +383,7 @@ void IO_WriteD(Bitu port,Bitu val) { } Bitu IO_ReadB(Bitu port) { + Bitu retval; if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,1)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -334,8 +405,7 @@ Bitu IO_ReadB(Bitu port) { DOSBOX_RunMachine(); iof_queue.used--; - Bitu retval = reg_al; - + retval = reg_al; reg_dx = old_dx; memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); cpudecoder=old_cpudecoder; @@ -343,11 +413,14 @@ Bitu IO_ReadB(Bitu port) { } else { IO_USEC_read_delay(); - return io_readhandlers[0][port](port,1); + retval = io_readhandlers[0][port](port,1); } + log_io(0, false, port, retval); + return retval; } Bitu IO_ReadW(Bitu port) { + Bitu retval; if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,2)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -369,20 +442,21 @@ Bitu IO_ReadW(Bitu port) { DOSBOX_RunMachine(); iof_queue.used--; - Bitu retval = reg_ax; - + retval = reg_ax; reg_dx = old_dx; memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); cpudecoder=old_cpudecoder; - return retval; } else { IO_USEC_read_delay(); - return io_readhandlers[1][port](port,2); + retval = io_readhandlers[1][port](port,2); } + log_io(1, false, port, retval); + return retval; } Bitu IO_ReadD(Bitu port) { + Bitu retval; if (GCC_UNLIKELY(GETFLAG(VM) && (CPU_IO_Exception(port,4)))) { LazyFlags old_lflags; memcpy(&old_lflags,&lflags,sizeof(LazyFlags)); @@ -404,14 +478,15 @@ Bitu IO_ReadD(Bitu port) { DOSBOX_RunMachine(); iof_queue.used--; - Bitu retval = reg_eax; - + retval = reg_eax; reg_dx = old_dx; memcpy(&lflags,&old_lflags,sizeof(LazyFlags)); cpudecoder=old_cpudecoder; - return retval; + } else { + retval = io_readhandlers[2][port](port,4); } - else return io_readhandlers[2][port](port,4); + log_io(2, false, port, retval); + return retval; } class IO :public Module_base { diff --git a/src/hardware/ipx.cpp b/src/hardware/ipx.cpp index e4129d0..7b45c80 100644 --- a/src/hardware/ipx.cpp +++ b/src/hardware/ipx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ipxserver.cpp b/src/hardware/ipxserver.cpp index 9c1d3d2..937b4e3 100644 --- a/src/hardware/ipxserver.cpp +++ b/src/hardware/ipxserver.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/joystick.cpp b/src/hardware/joystick.cpp index b963cfe..6aff4c4 100644 --- a/src/hardware/joystick.cpp +++ b/src/hardware/joystick.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/keyboard.cpp b/src/hardware/keyboard.cpp index 4b48ef1..4d25a7b 100644 --- a/src/hardware/keyboard.cpp +++ b/src/hardware/keyboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/memory.cpp b/src/hardware/memory.cpp index 20b2a92..ba76a8d 100644 --- a/src/hardware/memory.cpp +++ b/src/hardware/memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/mixer.cpp b/src/hardware/mixer.cpp index d5a29ce..202f101 100644 --- a/src/hardware/mixer.cpp +++ b/src/hardware/mixer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/mpu401.cpp b/src/hardware/mpu401.cpp index a0a8214..333e106 100644 --- a/src/hardware/mpu401.cpp +++ b/src/hardware/mpu401.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/opl.cpp b/src/hardware/opl.cpp index 5a84ff7..333f796 100644 --- a/src/hardware/opl.cpp +++ b/src/hardware/opl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 The DOSBox Team * OPL2/OPL3 emulation library * * This library is free software; you can redistribute it and/or diff --git a/src/hardware/opl.h b/src/hardware/opl.h index eafb527..c7f38e0 100644 --- a/src/hardware/opl.h +++ b/src/hardware/opl.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 The DOSBox Team * OPL2/OPL3 emulation library * * This library is free software; you can redistribute it and/or diff --git a/src/hardware/pcspeaker.cpp b/src/hardware/pcspeaker.cpp index 9449671..008523b 100644 --- a/src/hardware/pcspeaker.cpp +++ b/src/hardware/pcspeaker.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/pic.cpp b/src/hardware/pic.cpp index 5a1df36..fde8502 100644 --- a/src/hardware/pic.cpp +++ b/src/hardware/pic.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -123,7 +123,7 @@ static void write_command(Bitu port,Bitu val,Bitu iolen) { irqs[PIC_IRQActive].inservice=false; PIC_IRQActive=PIC_NOIRQ; for (i=0; i<=15; i++){ - if(irqs[IRQ_priority_table[i]].inservice) { + if(GCC_UNLIKELY(irqs[IRQ_priority_table[i]].inservice)) { PIC_IRQActive=IRQ_priority_table[i]; break; } @@ -276,7 +276,7 @@ static inline bool PIC_startIRQ(Bitu i) { 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) { + } else if (GCC_UNLIKELY(pics[pic].rotate_on_auto_eoi)) { E_Exit("rotate on auto EOI not handled"); } return true; @@ -284,8 +284,8 @@ static inline bool PIC_startIRQ(Bitu i) { void PIC_runIRQs(void) { if (!GETFLAG(IF)) return; - if (!PIC_IRQCheck) return; - if (cpudecoder==CPU_Core_Normal_Trap_Run) return; + if (GCC_UNLIKELY(!PIC_IRQCheck)) return; + if (GCC_UNLIKELY(cpudecoder==CPU_Core_Normal_Trap_Run)) return; static Bitu IRQ_priority_order[16] = { 0,1,2,8,9,10,11,12,13,14,15,3,4,5,6,7 }; @@ -305,7 +305,7 @@ void PIC_runIRQs(void) { for (j = 0; j < Priority_Active_IRQ; j++) { i = IRQ_priority_order[j]; if (!irqs[i].masked && irqs[i].active) { - if(PIC_startIRQ(i)) return; + if(GCC_LIKELY(PIC_startIRQ(i))) return; } } } else { /* Special mode variant */ @@ -315,7 +315,7 @@ void PIC_runIRQs(void) { 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 started successfully return, else go for the next */ if(PIC_startIRQ(i)) return; } } @@ -355,7 +355,7 @@ void PIC_SetIRQMask(Bitu irq, bool masked) { static void AddEntry(PICEntry * entry) { PICEntry * find_entry=pic_queue.next_entry; - if (!find_entry) { + if (GCC_UNLIKELY(find_entry ==0)) { entry->next=0; pic_queue.next_entry=entry; } else if (find_entry->index>entry->index) { @@ -383,14 +383,18 @@ static void AddEntry(PICEntry * entry) { CPU_Cycles=0; } } +static bool InEventService = false; +static float srv_lag = 0; void PIC_AddEvent(PIC_EventHandler handler,float delay,Bitu val) { - if (!pic_queue.free_entry) { + if (GCC_UNLIKELY(!pic_queue.free_entry)) { LOG(LOG_PIC,LOG_ERROR)("Event queue full"); return; } PICEntry * entry=pic_queue.free_entry; - entry->index=delay+PIC_TickIndex(); + if(InEventService) entry->index = delay + srv_lag; + else entry->index = delay + PIC_TickIndex(); + entry->pic_event=handler; entry->value=val; pic_queue.free_entry=pic_queue.free_entry->next; @@ -402,7 +406,7 @@ void PIC_RemoveSpecificEvents(PIC_EventHandler handler, Bitu val) { PICEntry * prev_entry; prev_entry = 0; while (entry) { - if ((entry->pic_event == handler) && (entry->value == val)) { + if (GCC_UNLIKELY((entry->pic_event == handler)) && (entry->value == val)) { if (prev_entry) { prev_entry->next=entry->next; entry->next=pic_queue.free_entry; @@ -427,7 +431,7 @@ void PIC_RemoveEvents(PIC_EventHandler handler) { PICEntry * prev_entry; prev_entry=0; while (entry) { - if (entry->pic_event==handler) { + if (GCC_UNLIKELY(entry->pic_event==handler)) { if (prev_entry) { prev_entry->next=entry->next; entry->next=pic_queue.free_entry; @@ -457,18 +461,24 @@ bool PIC_RunQueue(void) { } /* Check the queue for an entry */ Bits index_nd=PIC_TickIndexND(); + InEventService = true; while (pic_queue.next_entry && (pic_queue.next_entry->index*CPU_CycleMax<=index_nd)) { PICEntry * entry=pic_queue.next_entry; pic_queue.next_entry=entry->next; - (entry->pic_event)(entry->value); + + srv_lag = entry->index; + (entry->pic_event)(entry->value); // call the event handler + /* Put the entry in the free list */ entry->next=pic_queue.free_entry; pic_queue.free_entry=entry; } + InEventService = false; + /* Check when to set the new cycle end */ if (pic_queue.next_entry) { Bits cycles=(Bits)(pic_queue.next_entry->index*CPU_CycleMax-index_nd); - if (!cycles) cycles=1; + if (GCC_UNLIKELY(!cycles)) cycles=1; if (cyclesindex>=1) entry->index-=1; - else entry->index=0; + entry->index -= 1.0; entry=entry->next; } /* Call our list of ticker handlers */ diff --git a/src/hardware/sblaster.cpp b/src/hardware/sblaster.cpp index a832902..0ad028f 100644 --- a/src/hardware/sblaster.cpp +++ b/src/hardware/sblaster.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -63,7 +63,7 @@ bool MIDI_Available(void); #define SB_SH_MASK ((1 << SB_SH)-1) enum {DSP_S_RESET,DSP_S_RESET_WAIT,DSP_S_NORMAL,DSP_S_HIGHSPEED}; -enum SB_TYPES {SBT_NONE=0,SBT_1=1,SBT_PRO1=2,SBT_2=3,SBT_PRO2=4,SBT_16=6}; +enum SB_TYPES {SBT_NONE=0,SBT_1=1,SBT_PRO1=2,SBT_2=3,SBT_PRO2=4,SBT_16=6,SBT_GB=7}; enum SB_IRQS {SB_IRQ_8,SB_IRQ_16,SB_IRQ_MPU}; enum DSP_MODES { @@ -995,6 +995,8 @@ static void DSP_DoCommand(void) { LOG(LOG_SB,LOG_ERROR)("DSP:Unimplemented auto-init DMA ADPCM command %2X",sb.dsp.cmd); break; case 0x20: + DSP_AddData(0x7f); // fake silent input for Creative parrot + break; 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 */ @@ -1366,7 +1368,10 @@ static Bitu read_sb(Bitu port,Bitu /*iolen*/) { return DSP_ReadData(); case DSP_READ_STATUS: //TODO See for high speed dma :) - sb.irq.pending_8bit=false; + if (sb.irq.pending_8bit) { + sb.irq.pending_8bit=false; + PIC_DeActivateIRQ(sb.hw.irq); + } if (sb.dsp.out.used) return 0xff; else return 0x7f; case DSP_ACK_16BIT: @@ -1473,6 +1478,7 @@ private: 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,"gb")) type=SBT_GB; else if (!strcasecmp(sbtype,"none")) type=SBT_NONE; else type=SBT_16; @@ -1490,7 +1496,9 @@ private: /* Else assume auto */ else { switch (type) { - case SBT_NONE:opl_mode=OPL_none;break; + case SBT_NONE: + case SBT_GB: + 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; @@ -1519,23 +1527,25 @@ public: OPL_Mode opl_mode = OPL_none; Find_Type_And_Opl(section,sb.type,opl_mode); + bool do_cms = (sb.type==SBT_GB)? true:false; + 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); + do_cms = true; break; case OPL_opl2: - CMS_Init(section); + do_cms = true; case OPL_dualopl2: case OPL_opl3: OPL_Init(section,opl_mode); break; } - - if (sb.type==SBT_NONE) return; + if (do_cms) CMS_Init(section); + if (sb.type==SBT_NONE || sb.type==SBT_GB) return; sb.chan=MixerChan.Install(&SBLASTER_CallBack,22050,"SB"); sb.dsp.state=DSP_S_NORMAL; @@ -1598,7 +1608,7 @@ public: break; } - if (sb.type==SBT_NONE) return; + if (sb.type==SBT_NONE || sb.type==SBT_GB) return; DSP_Reset();//Stop everything } }; //End of SBLASTER class diff --git a/src/hardware/serialport/directserial.cpp b/src/hardware/serialport/directserial.cpp index 8d8db43..529c11b 100644 --- a/src/hardware/serialport/directserial.cpp +++ b/src/hardware/serialport/directserial.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/directserial.h b/src/hardware/serialport/directserial.h index d8285ea..e7121e2 100644 --- a/src/hardware/serialport/directserial.h +++ b/src/hardware/serialport/directserial.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/libserial.cpp b/src/hardware/serialport/libserial.cpp index 0c7ad2a..5d66851 100644 --- a/src/hardware/serialport/libserial.cpp +++ b/src/hardware/serialport/libserial.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/libserial.h b/src/hardware/serialport/libserial.h index f3420c8..fad6d20 100644 --- a/src/hardware/serialport/libserial.h +++ b/src/hardware/serialport/libserial.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/misc_util.cpp b/src/hardware/serialport/misc_util.cpp index 6f01d9c..0243c35 100644 --- a/src/hardware/serialport/misc_util.cpp +++ b/src/hardware/serialport/misc_util.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/misc_util.h b/src/hardware/serialport/misc_util.h index e426042..83f3dfa 100644 --- a/src/hardware/serialport/misc_util.h +++ b/src/hardware/serialport/misc_util.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/nullmodem.cpp b/src/hardware/serialport/nullmodem.cpp index 605d382..668ebc4 100644 --- a/src/hardware/serialport/nullmodem.cpp +++ b/src/hardware/serialport/nullmodem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/nullmodem.h b/src/hardware/serialport/nullmodem.h index 395af64..012ddaf 100644 --- a/src/hardware/serialport/nullmodem.h +++ b/src/hardware/serialport/nullmodem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/serialdummy.cpp b/src/hardware/serialport/serialdummy.cpp index c8aa949..f4dd904 100644 --- a/src/hardware/serialport/serialdummy.cpp +++ b/src/hardware/serialport/serialdummy.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/serialdummy.h b/src/hardware/serialport/serialdummy.h index 52087b5..2da38af 100644 --- a/src/hardware/serialport/serialdummy.h +++ b/src/hardware/serialport/serialdummy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/serialport.cpp b/src/hardware/serialport/serialport.cpp index b6a310a..1fd1f2d 100644 --- a/src/hardware/serialport/serialport.cpp +++ b/src/hardware/serialport/serialport.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/softmodem.cpp b/src/hardware/serialport/softmodem.cpp index 0dd33c2..78029a9 100644 --- a/src/hardware/serialport/softmodem.cpp +++ b/src/hardware/serialport/softmodem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/serialport/softmodem.h b/src/hardware/serialport/softmodem.h index 42406c3..f884dde 100644 --- a/src/hardware/serialport/softmodem.h +++ b/src/hardware/serialport/softmodem.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/tandy_sound.cpp b/src/hardware/tandy_sound.cpp index 120ed13..7ee942f 100644 --- a/src/hardware/tandy_sound.cpp +++ b/src/hardware/tandy_sound.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/timer.cpp b/src/hardware/timer.cpp index f94e43c..a4a7c50 100644 --- a/src/hardware/timer.cpp +++ b/src/hardware/timer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -75,9 +75,7 @@ static void PIT0_Event(Bitu /*val*/) { pit[0].delay=(1000.0f/((float)PIT_TICK_RATE/(float)pit[0].cntr)); pit[0].update_count=false; } - - double error = pit[0].start - PIC_FullIndex(); - PIC_AddEvent(PIT0_Event,(float)(pit[0].delay + error)); + PIC_AddEvent(PIT0_Event,pit[0].delay); } } @@ -271,9 +269,7 @@ static Bitu read_latch(Bitu port,Bitu /*iolen*/) { break; case 3: /* read LSB followed by MSB */ ret = pit[counter].read_latch & 0xff; - - if (pit[counter].mode & 0x80) pit[counter].mode &= 7; - else pit[counter].read_state = 0; + pit[counter].read_state = 0; break; case 1: /* read LSB */ ret = pit[counter].read_latch & 0xff; diff --git a/src/hardware/vga.cpp b/src/hardware/vga.cpp index 0f1377b..74edb83 100644 --- a/src/hardware/vga.cpp +++ b/src/hardware/vga.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_attr.cpp b/src/hardware/vga_attr.cpp index 94e320f..1f1371b 100644 --- a/src/hardware/vga_attr.cpp +++ b/src/hardware/vga_attr.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_crtc.cpp b/src/hardware/vga_crtc.cpp index 561185d..aab7b88 100644 --- a/src/hardware/vga_crtc.cpp +++ b/src/hardware/vga_crtc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_dac.cpp b/src/hardware/vga_dac.cpp index 74f4476..c217937 100644 --- a/src/hardware/vga_dac.cpp +++ b/src/hardware/vga_dac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_draw.cpp b/src/hardware/vga_draw.cpp index 6e94013..3edf56c 100644 --- a/src/hardware/vga_draw.cpp +++ b/src/hardware/vga_draw.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_gfx.cpp b/src/hardware/vga_gfx.cpp index 9ce72a7..a79e9c3 100644 --- a/src/hardware/vga_gfx.cpp +++ b/src/hardware/vga_gfx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 c972d51..74f9752 100644 --- a/src/hardware/vga_memory.cpp +++ b/src/hardware/vga_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_misc.cpp b/src/hardware/vga_misc.cpp index 4773f93..517166f 100644 --- a/src/hardware/vga_misc.cpp +++ b/src/hardware/vga_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_other.cpp b/src/hardware/vga_other.cpp index bbf059a..80143d4 100644 --- a/src/hardware/vga_other.cpp +++ b/src/hardware/vga_other.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_paradise.cpp b/src/hardware/vga_paradise.cpp index 596b267..f05c862 100644 --- a/src/hardware/vga_paradise.cpp +++ b/src/hardware/vga_paradise.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_s3.cpp b/src/hardware/vga_s3.cpp index 0be0982..c656a4d 100644 --- a/src/hardware/vga_s3.cpp +++ b/src/hardware/vga_s3.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_seq.cpp b/src/hardware/vga_seq.cpp index 409b2ca..33a6604 100644 --- a/src/hardware/vga_seq.cpp +++ b/src/hardware/vga_seq.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_tseng.cpp b/src/hardware/vga_tseng.cpp index c3cded9..1673557 100644 --- a/src/hardware/vga_tseng.cpp +++ b/src/hardware/vga_tseng.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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_xga.cpp b/src/hardware/vga_xga.cpp index 363b959..b7f927c 100644 --- a/src/hardware/vga_xga.cpp +++ b/src/hardware/vga_xga.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/bios.cpp b/src/ints/bios.cpp index 50debee..4190b8a 100644 --- a/src/ints/bios.cpp +++ b/src/ints/bios.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/bios_disk.cpp b/src/ints/bios_disk.cpp index 9b0289e..f4ae47d 100644 --- a/src/ints/bios_disk.cpp +++ b/src/ints/bios_disk.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/bios_keyboard.cpp b/src/ints/bios_keyboard.cpp index e26c11a..8ad3655 100644 --- a/src/ints/bios_keyboard.cpp +++ b/src/ints/bios_keyboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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,11 +26,14 @@ #include "regs.h" #include "inout.h" #include "dos_inc.h" +#include "SDL.h" /* SDL by default treats numlock and scrolllock different from all other keys. - * Some linux distros disable this bad behaviour. (for example debian) + * In recent versions this can disabled by a environment variable which we set in sdlmain.cpp * Define the following if this is the case */ -//#define CAN_USE_LOCK 1 +#if SDL_VERSION_ATLEAST(1, 2, 14) +#define CAN_USE_LOCK 1 +#endif static Bitu call_int16,call_irq1,call_irq6; @@ -243,6 +246,7 @@ static Bitu IRQ1_Handler(void) { flags2&=~(0x40+0x20);//remove numlock/capslock pressed (hack for sdl only reporting states) #endif if (DOS_LayoutKey(scancode,flags1,flags2,flags3)) return CBRET_NONE; +LOG_MSG("key input %d %d %d %d",scancode,flags1,flags2,flags3); switch (scancode) { /* First the hard ones */ case 0xfa: /* ack. Do nothing for now */ @@ -588,8 +592,9 @@ static void InitBiosSegment(void) { mem_writew(BIOS_KEYBOARD_BUFFER_TAIL,0x1e); Bit8u flag1 = 0; Bit8u leds = 16; /* Ack recieved */ - if(startup_state_capslock) { flag1|=0x40; leds|=0x04;} - if(startup_state_numlock){ flag1|=0x20; leds|=0x02;} +//MAPPER_Init takes care of this now ? +// if(startup_state_capslock) { flag1|=0x40; leds|=0x04;} +// if(startup_state_numlock){ flag1|=0x20; leds|=0x02;} mem_writeb(BIOS_KEYBOARD_FLAGS1,flag1); mem_writeb(BIOS_KEYBOARD_FLAGS2,0); mem_writeb(BIOS_KEYBOARD_FLAGS3,16); /* Enhanced keyboard installed */ diff --git a/src/ints/ems.cpp b/src/ints/ems.cpp index 64d2593..a24a4a4 100644 --- a/src/ints/ems.cpp +++ b/src/ints/ems.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10.cpp b/src/ints/int10.cpp index 62b638b..018e994 100644 --- a/src/ints/int10.cpp +++ b/src/ints/int10.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10.h b/src/ints/int10.h index 4e0fd1c..8bc7fbc 100644 --- a/src/ints/int10.h +++ b/src/ints/int10.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_char.cpp b/src/ints/int10_char.cpp index b51e785..a3f7764 100644 --- a/src/ints/int10_char.cpp +++ b/src/ints/int10_char.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_memory.cpp b/src/ints/int10_memory.cpp index 1c0ee0a..789d52a 100644 --- a/src/ints/int10_memory.cpp +++ b/src/ints/int10_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_misc.cpp b/src/ints/int10_misc.cpp index 4c91dbe..b9867d5 100644 --- a/src/ints/int10_misc.cpp +++ b/src/ints/int10_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_modes.cpp b/src/ints/int10_modes.cpp index 1b2666c..b8eec1b 100644 --- a/src/ints/int10_modes.cpp +++ b/src/ints/int10_modes.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -57,6 +57,8 @@ VideoModeBlock ModeList_VGA[]={ { 0x054 ,M_TEXT ,1056,688, 132,43, 8, 16, 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 }, +/* Alias of mode 101 */ +{ 0x069 ,M_LIN8 ,640 ,480 ,80 ,30 ,8 ,16 ,1 ,0xA0000 ,0x10000,100 ,525 ,80 ,480 ,0 }, /* Alias of mode 102 */ { 0x06A ,M_LIN4 ,800 ,600 ,100,37 ,8 ,16 ,1 ,0xA0000 ,0x10000,128 ,663 ,100,600 ,0 }, @@ -439,6 +441,7 @@ bool INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem) { if (mode>6) return false; case TANDY_ARCH_CASE: if (mode>0xa) return false; + if (mode==7) mode=0; // PCJR defaults to 0 on illegal mode 7 if (!SetCurMode(ModeList_OTHER,mode)) { LOG(LOG_INT10,LOG_ERROR)("Trying to set illegal mode %X",mode); return false; @@ -448,6 +451,7 @@ bool INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem) { // Only init the adapter if the equipment word is set to monochrome (Testdrive) if ((real_readw(BIOSMEM_SEG,BIOSMEM_INITIAL_MODE)&0x30)!=0x30) return false; CurMode=&Hercules_Mode; + mode=7; // in case the video parameter table is modified break; } LOG(LOG_INT10,LOG_NORMAL)("Set Video Mode %X",mode); @@ -594,31 +598,15 @@ bool INT10_SetVideoMode_OTHER(Bit16u mode,bool clearmem) { if (mode < 2) crtc_block_index = 0; else if (mode < 4) crtc_block_index = 1; else if (mode < 7) crtc_block_index = 2; - else { - if (machine==MCH_PCJR) { - if (mode < 9) crtc_block_index = 2; - else crtc_block_index = 3; - } else { - if (mode == 7) crtc_block_index = 3; - } - } + else if (mode == 7) crtc_block_index = 3; // MDA mono mode; invalid for others + else if (mode < 9) crtc_block_index = 2; + else crtc_block_index = 3; // Tandy/PCjr modes // init CRTC registers for (Bit16u i = 0; i < 16; i++) IO_WriteW(crtc_base, i | (real_readb(RealSeg(vparams), RealOff(vparams) + i + crtc_block_index*16) << 8)); - if (machine==MCH_CGA) { - // mode register - Bit8u mode_control = real_readb(RealSeg(vparams), RealOff(vparams) + 80 + mode); - IO_WriteB(crtc_base + 4, mode_control); - real_writeb(BIOSMEM_SEG,BIOSMEM_CURRENT_MSR, mode_control); - } - - if (machine==MCH_TANDY) { - E_Exit("INT10 modeset: video parameter table changed"); - } } - FinishSetMode(clearmem); return true; } diff --git a/src/ints/int10_pal.cpp b/src/ints/int10_pal.cpp index 49e4826..e9ff967 100644 --- a/src/ints/int10_pal.cpp +++ b/src/ints/int10_pal.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_put_pixel.cpp b/src/ints/int10_put_pixel.cpp index 585260c..63e0868 100644 --- a/src/ints/int10_put_pixel.cpp +++ b/src/ints/int10_put_pixel.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_vesa.cpp b/src/ints/int10_vesa.cpp index 82fc350..627703f 100644 --- a/src/ints/int10_vesa.cpp +++ b/src/ints/int10_vesa.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_video_state.cpp b/src/ints/int10_video_state.cpp index 4c697f6..59bfc61 100644 --- a/src/ints/int10_video_state.cpp +++ b/src/ints/int10_video_state.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/int10_vptable.cpp b/src/ints/int10_vptable.cpp index 7b80fb3..4e507be 100644 --- a/src/ints/int10_vptable.cpp +++ b/src/ints/int10_vptable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/mouse.cpp b/src/ints/mouse.cpp index 0635772..e0aa8b6 100644 --- a/src/ints/mouse.cpp +++ b/src/ints/mouse.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ struct button_event { #define QUEUE_SIZE 32 #define MOUSE_BUTTONS 3 #define MOUSE_IRQ 12 -#define POS_X (Bit16s)(mouse.x) +#define POS_X ((Bit16s)(mouse.x) & mouse.granMask) #define POS_Y (Bit16s)(mouse.y) #define CURSORX 16 @@ -126,6 +126,7 @@ static struct { bool timer_in_progress; bool in_UIR; Bit8u mode; + Bit16s granMask; } mouse; bool Mouse_SetPS2State(bool use) { @@ -496,18 +497,26 @@ void Mouse_CursorSet(float x,float y) { void Mouse_ButtonPressed(Bit8u button) { switch (button) { +#if (MOUSE_BUTTONS >= 1) case 0: mouse.buttons|=1; Mouse_AddEvent(MOUSE_LEFT_PRESSED); break; +#endif +#if (MOUSE_BUTTONS >= 2) case 1: mouse.buttons|=2; Mouse_AddEvent(MOUSE_RIGHT_PRESSED); break; +#endif +#if (MOUSE_BUTTONS >= 3) case 2: mouse.buttons|=4; Mouse_AddEvent(MOUSE_MIDDLE_PRESSED); break; +#endif + default: + return; } mouse.times_pressed[button]++; mouse.last_pressed_x[button]=POS_X; @@ -516,18 +525,26 @@ void Mouse_ButtonPressed(Bit8u button) { void Mouse_ButtonReleased(Bit8u button) { switch (button) { +#if (MOUSE_BUTTONS >= 1) case 0: mouse.buttons&=~1; Mouse_AddEvent(MOUSE_LEFT_RELEASED); break; +#endif +#if (MOUSE_BUTTONS >= 2) case 1: mouse.buttons&=~2; Mouse_AddEvent(MOUSE_RIGHT_RELEASED); break; +#endif +#if (MOUSE_BUTTONS >= 3) case 2: mouse.buttons&=~4; Mouse_AddEvent(MOUSE_MIDDLE_RELEASED); break; +#endif + default: + return; } mouse.times_released[button]++; mouse.last_released_x[button]=POS_X; @@ -610,6 +627,7 @@ void Mouse_NewVideoMode(void) { mouse.max_x = 639; mouse.min_x = 0; mouse.min_y = 0; + mouse.granMask = (mode == 0x0d || mode == 0x13) ? 0xfffe : 0xffff; mouse.events = 0; mouse.timer_in_progress = false; diff --git a/src/ints/xms.cpp b/src/ints/xms.cpp index a5d9f66..456fab1 100644 --- a/src/ints/xms.cpp +++ b/src/ints/xms.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/ints/xms.h b/src/ints/xms.h index f41151d..d96d49c 100644 --- a/src/ints/xms.h +++ b/src/ints/xms.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/gui_tk/Doxyfile b/src/libs/gui_tk/Doxyfile index fc7686f..598d6fe 100644 --- a/src/libs/gui_tk/Doxyfile +++ b/src/libs/gui_tk/Doxyfile @@ -1,238 +1,238 @@ -# Doxyfile 1.5.2 - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = gui::tk -PROJECT_NUMBER = "Version 1.0" -OUTPUT_DIRECTORY = -CREATE_SUBDIRS = NO -OUTPUT_LANGUAGE = English -BRIEF_MEMBER_DESC = YES -REPEAT_BRIEF = YES -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the -ALWAYS_DETAILED_SEC = NO -INLINE_INHERITED_MEMB = NO -FULL_PATH_NAMES = YES -STRIP_FROM_PATH = . -STRIP_FROM_INC_PATH = -SHORT_NAMES = NO -JAVADOC_AUTOBRIEF = NO -MULTILINE_CPP_IS_BRIEF = NO -DETAILS_AT_TOP = YES -INHERIT_DOCS = YES -SEPARATE_MEMBER_PAGES = NO -TAB_SIZE = 8 -ALIASES = -OPTIMIZE_OUTPUT_FOR_C = NO -OPTIMIZE_OUTPUT_JAVA = NO -BUILTIN_STL_SUPPORT = YES -CPP_CLI_SUPPORT = NO -DISTRIBUTE_GROUP_DOC = NO -SUBGROUPING = YES -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- -EXTRACT_ALL = NO -EXTRACT_PRIVATE = NO -EXTRACT_STATIC = NO -EXTRACT_LOCAL_CLASSES = YES -EXTRACT_LOCAL_METHODS = NO -HIDE_UNDOC_MEMBERS = NO -HIDE_UNDOC_CLASSES = NO -HIDE_FRIEND_COMPOUNDS = NO -HIDE_IN_BODY_DOCS = NO -INTERNAL_DOCS = NO -CASE_SENSE_NAMES = YES -HIDE_SCOPE_NAMES = NO -SHOW_INCLUDE_FILES = YES -INLINE_INFO = YES -SORT_MEMBER_DOCS = YES -SORT_BRIEF_DOCS = NO -SORT_BY_SCOPE_NAME = NO -GENERATE_TODOLIST = YES -GENERATE_TESTLIST = YES -GENERATE_BUGLIST = YES -GENERATE_DEPRECATEDLIST= YES -ENABLED_SECTIONS = -MAX_INITIALIZER_LINES = 30 -SHOW_USED_FILES = YES -SHOW_DIRECTORIES = YES -FILE_VERSION_FILTER = -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- -QUIET = NO -WARNINGS = YES -WARN_IF_UNDOCUMENTED = NO -WARN_IF_DOC_ERROR = YES -WARN_NO_PARAMDOC = NO -WARN_FORMAT = "$file:$line: $text" -WARN_LOGFILE = -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- -INPUT = . -INPUT_ENCODING = UTF-8 -FILE_PATTERNS = gui_tk.h \ - gui_tk.cpp -RECURSIVE = NO -EXCLUDE = -EXCLUDE_SYMLINKS = NO -EXCLUDE_PATTERNS = -EXCLUDE_SYMBOLS = -EXAMPLE_PATH = -EXAMPLE_PATTERNS = * -EXAMPLE_RECURSIVE = NO -IMAGE_PATH = -INPUT_FILTER = -FILTER_PATTERNS = -FILTER_SOURCE_FILES = NO -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- -SOURCE_BROWSER = YES -INLINE_SOURCES = NO -STRIP_CODE_COMMENTS = YES -REFERENCED_BY_RELATION = YES -REFERENCES_RELATION = YES -REFERENCES_LINK_SOURCE = YES -USE_HTAGS = NO -VERBATIM_HEADERS = YES -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- -ALPHABETICAL_INDEX = NO -COLS_IN_ALPHA_INDEX = 5 -IGNORE_PREFIX = -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- -GENERATE_HTML = YES -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = -HTML_STYLESHEET = -HTML_ALIGN_MEMBERS = YES -GENERATE_HTMLHELP = NO -CHM_FILE = -HHC_LOCATION = -GENERATE_CHI = NO -BINARY_TOC = NO -TOC_EXPAND = NO -DISABLE_INDEX = NO -ENUM_VALUES_PER_LINE = 4 -GENERATE_TREEVIEW = NO -TREEVIEW_WIDTH = 250 -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- -GENERATE_LATEX = NO -LATEX_OUTPUT = latex -LATEX_CMD_NAME = latex -MAKEINDEX_CMD_NAME = makeindex -COMPACT_LATEX = NO -PAPER_TYPE = a4wide -EXTRA_PACKAGES = -LATEX_HEADER = -PDF_HYPERLINKS = NO -USE_PDFLATEX = NO -LATEX_BATCHMODE = NO -LATEX_HIDE_INDICES = NO -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- -GENERATE_RTF = NO -RTF_OUTPUT = rtf -COMPACT_RTF = NO -RTF_HYPERLINKS = NO -RTF_STYLESHEET_FILE = -RTF_EXTENSIONS_FILE = -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- -GENERATE_MAN = NO -MAN_OUTPUT = man -MAN_EXTENSION = .3 -MAN_LINKS = NO -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- -GENERATE_XML = NO -XML_OUTPUT = xml -XML_SCHEMA = -XML_DTD = -XML_PROGRAMLISTING = YES -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- -GENERATE_AUTOGEN_DEF = NO -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- -GENERATE_PERLMOD = NO -PERLMOD_LATEX = NO -PERLMOD_PRETTY = YES -PERLMOD_MAKEVAR_PREFIX = -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- -ENABLE_PREPROCESSING = YES -MACRO_EXPANSION = NO -EXPAND_ONLY_PREDEF = NO -SEARCH_INCLUDES = YES -INCLUDE_PATH = -INCLUDE_FILE_PATTERNS = -PREDEFINED = TESTING SDL_MAJOR_VERSION -EXPAND_AS_DEFINED = -SKIP_FUNCTION_MACROS = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- -TAGFILES = -GENERATE_TAGFILE = DOSBox.tag -ALLEXTERNALS = NO -EXTERNAL_GROUPS = YES -PERL_PATH = /usr/bin/perl -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- -CLASS_DIAGRAMS = YES -MSCGEN_PATH = -HIDE_UNDOC_RELATIONS = YES -HAVE_DOT = YES -CLASS_GRAPH = YES -COLLABORATION_GRAPH = YES -GROUP_GRAPHS = YES -UML_LOOK = YES -TEMPLATE_RELATIONS = YES -INCLUDE_GRAPH = YES -INCLUDED_BY_GRAPH = YES -CALL_GRAPH = YES -CALLER_GRAPH = YES -GRAPHICAL_HIERARCHY = YES -DIRECTORY_GRAPH = YES -DOT_IMAGE_FORMAT = png -DOT_PATH = -DOTFILE_DIRS = -DOT_GRAPH_MAX_NODES = 50 -DOT_TRANSPARENT = YES -DOT_MULTI_TARGETS = YES -GENERATE_LEGEND = YES -DOT_CLEANUP = YES -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- -SEARCHENGINE = NO +# Doxyfile 1.5.2 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = gui::tk +PROJECT_NUMBER = "Version 1.0" +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = . +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = YES +CPP_CLI_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = YES +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = NO +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = gui_tk.h \ + gui_tk.cpp +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = TESTING SDL_MAJOR_VERSION +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = DOSBox.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/src/libs/gui_tk/gui_tk.cpp b/src/libs/gui_tk/gui_tk.cpp index 2a75074..0ba88eb 100644 --- a/src/libs/gui_tk/gui_tk.cpp +++ b/src/libs/gui_tk/gui_tk.cpp @@ -1,1707 +1,1707 @@ -#if 0 -/* - * gui_tk - framework-agnostic GUI toolkit - * Copyright (C) 2005-2007 Jörg Walter - * - * gui_tk 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 3 of the License, or - * (at your option) any later version. - * - * gui_tk 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, see - */ - -/* TODO: - - make menu a bufferedwindow with shadow -*/ -/* $Id: gui_tk.cpp,v 1.5 2009/02/01 16:06:26 qbix79 Exp $ */ - -/** \file - * \brief Implementation file for gui_tk. - * - * It contains implementations for all non-inlined class methods. - * - * Also contained is a small test program that demonstrates all features of - * gui_tk. It is enabled by defining the preprocessor macro TESTING. - */ - -#include -#include "gui_tk.h" - -namespace GUI { - -namespace Color { - -RGB Background3D = 0xffc0c0c0; - -RGB Light3D = 0xfffcfcfc; - -RGB Shadow3D = 0xff808080; - -RGB Border = 0xff000000; - -RGB Text = 0xff000000; - -RGB Background = 0xffc0c0c0; - -RGB SelectionBackground = 0xff000080; - -RGB SelectionForeground = 0xffffffff; - -RGB EditableBackground = 0xffffffff; - -RGB Titlebar = 0xff000080; - -RGB TitlebarText = 0xffffffff; - -} - -void Drawable::drawText(const String& text, bool interpret, Size start, Size len) { - if (interpret) { - if (len > text.size()-start) len = (Size)(text.size()-start); - len += start; - - Size wordstart = start; - int width = 0; - - while (start < len) { - switch (font->toSpecial(text[start])) { - case Font::CR: - if (wordstart != start) { - drawText(text,false,wordstart,start-wordstart); - wordstart = start; - width = 0; - } - wordstart++; - gotoXY(0,y); - break; - case Font::LF: - if (wordstart != start) { - drawText(text,false,wordstart,start-wordstart); - wordstart = start; - width = 0; - } - wordstart++; - gotoXY(0,y+font->getHeight()); - break; - case Font::BS: - if (wordstart != start) { - drawText(text,false,wordstart,start-wordstart); - wordstart = start; - width = 0; - } - wordstart++; - gotoXY(imax(0,x-font->getWidth()),y); - break; - case Font::Tab: - if (wordstart != start) { - drawText(text,false,wordstart,start-wordstart); - wordstart = start; - width = 0; - } - wordstart++; - gotoXY((((int)(x/font->getWidth()/8))+1)*8*font->getWidth(),y); - break; - case Font::Space: - if (wordstart != start) { - drawText(text,false,wordstart,start-wordstart); - wordstart = start; - width = 0; - } - wordstart++; - font->drawString(this,text,start,1); - break; - case Font::ESC: // ignore ANSI sequences except for colors - if (wordstart != start) { - drawText(text,false,wordstart,start-wordstart); - wordstart = start; - width = 0; - } - wordstart++; - do { - int seqstart = start+1; - Char c; - do { - start++; - wordstart++; - c = font->toSpecial(text[start]); - } while (start < len && ((c >= '0' && c <= '9') || c == ';' || c == '[')); - if (c == 'm' && start < len) { - if (font->toSpecial(text[seqstart++]) != '[') break; - c = font->toSpecial(text[seqstart++]); - while (c != 'm') { - int param = 0; - if (c == ';') c = '0'; - while (c != 'm' && c != ';') { - param = param * 10 + c-'0'; - c = font->toSpecial(text[seqstart++]); - } - const RGB bright = 0x00808080; - const RGB intensity = (color&bright?~0:~bright); - switch (param) { - case 0: setColor(Color::Black); break; - case 1: setColor(color | 0x00808080); break; - case 30: setColor((Color::Black|bright) & intensity); break; - case 31: setColor(Color::Red & intensity); break; - case 32: setColor(Color::Green & intensity); break; - case 33: setColor(Color::Yellow & intensity); break; - case 34: setColor(Color::Blue & intensity); break; - case 35: setColor(Color::Magenta & intensity); break; - case 36: setColor(Color::Cyan & intensity); break; - case 37: setColor(Color::White & intensity); break; - default: break; - } - } - } - } while (0); - default: - width += font->getWidth(text[start]); - if (x > 0 && x+width > cw) gotoXY(0,y+font->getHeight()); - } - start++; - } - if (wordstart != start) drawText(text,false,wordstart,start-wordstart); - return; - } - - font->drawString(this,text,start,len); -} - -bool ToplevelWindow::mouseDown(int x, int y, MouseButton button) { - if (button == Left && x > 32 && x < width-6 && y > 4 && y < 31) { - dragx = x; - dragy = y; - mouseChild = NULL; - systemMenu->setVisible(false); - return true; - } else if (button == Left && x < 32 && x > 6 && y > 4 && y < 31) { - mouseChild = NULL; - raise(); - systemMenu->setVisible(!systemMenu->isVisible()); - return true; - } - systemMenu->setVisible(false); - BorderedWindow::mouseDown(x,y,button); - return true; -} - -Drawable::Drawable(int w, int h, RGB clear) : - buffer(new RGB[w*h]), - width(w), height(h), - owner(true), - color(Color::Black), - font(NULL), - lineWidth(1), - tx(0), ty(0), - cx(0), cy(0), - cw(w), ch(h), - x(0), y(0) -{ - this->clear(clear); -} - -Drawable::Drawable(Drawable &src, RGB clear) : - buffer(new RGB[src.cw*src.ch]), - width(src.cw), height(src.ch), - owner(true), - color(src.color), - font(src.font), - lineWidth(src.lineWidth), - tx(0), ty(0), - cx(0), cy(0), - cw(src.cw), ch(src.ch), - x(src.x), y(src.y) -{ - if (clear != 0) { - this->clear(clear); - } else { - for (int h = 0; h < src.ch; h++) { - memcpy(buffer+src.cw*h,src.buffer+src.width*(h+src.ty)+src.tx,4*src.cw); - } - } -} - -Drawable::Drawable(Drawable &src, int x, int y, int w, int h) : - buffer(src.buffer), - width(src.width), height(src.height), - owner(false), - color(src.color), - font(src.font), - lineWidth(src.lineWidth), - tx(src.tx+x), ty(src.ty+y), - cx(imax(imax(-x,src.cx-x),0)), cy(imax(imax(-y,src.cy-y),0)), - cw(imax(0,imin(src.cw-x,w))), ch(imax(0,imin(src.ch-y,h))), - x(imax(0,imin(src.tx-tx,cw))), y(imax(0,imin(src.ty-ty,cw))) -{ -} - -Drawable::~Drawable() -{ - if (owner) delete[] buffer; -} - -void Drawable::clear(RGB clear) -{ - for (int y = cy; y < ch; y++) { - for (int x = cx; x < cw; x++) { - buffer[(y+ty)*width+x+tx] = clear; - } - } -} - -void Drawable::drawLine(int x2, int y2) -{ - int x0 = x2, x1 = x, y0 = y2, y1 = y; - int dx = x2-x1, dy = y2-y1; - drawPixel(); - - if (abs(dx) > abs(dy)) { - if (x1 > x2) { - x = x2; x2 = x1; x1 = x; - y = y2; y2 = y1; y1 = y; - } - for (x = x1; x <= x2; x++) { - y = y1+(x-x1)*dy/dx-lineWidth/2; - for (int i = 0; i < lineWidth; i++, y++) { - drawPixel(); - } - } - } else if (y1 != y2) { - if (y1 > y2) { - x = x2; x2 = x1; x1 = x; - y = y2; y2 = y1; y1 = y; - } - for (y = y1; y <= y2; y ++) { - x = x1+(y-y1)*dx/dy-lineWidth/2; - for (int i = 0; i < lineWidth; i++, x++) { - drawPixel(); - } - } - } - - drawPixel(x0,y0); -} - -void Drawable::drawCircle(int d) { - int xo = 0, yo = d/2, rest = (d+1)/2-yo, x0 = x, y0 = y, rsq = d*d/4, lwo = lineWidth/2; - - while (xo <= yo) { - while (xo*xo+(2*yo-1)*(2*yo-1)/4 > rsq) yo--; - for (int i = 0, yow = yo+lwo; i < lineWidth; i++, yow--) { - drawPixel(x0+xo,y0-yow-rest); - drawPixel(x0+yow,y0-xo-rest); - drawPixel(x0+yow,y0+xo); - drawPixel(x0+xo,y0+yow); - - drawPixel(x0-xo-rest,y0-yow-rest); - drawPixel(x0-yow-rest,y0-xo-rest); - drawPixel(x0-yow-rest,y0+xo); - drawPixel(x0-xo-rest,y0+yow); - } - - xo++; - } - gotoXY(x0,y0); -} - -void Drawable::drawRect(int w, int h) -{ - gotoXY(x-lineWidth/2,y); - drawLine(x+w+lineWidth-1,y); - gotoXY(x-(lineWidth-1)/2,y); - drawLine(x,y+h); - gotoXY(x+(lineWidth-1)/2,y); - drawLine(x-w-lineWidth+1,y); - gotoXY(x+lineWidth/2,y); - drawLine(x,y-h); -} - -void Drawable::fill() -{ - int x0 = x, xmin; - RGB color = getPixel(); - - if (color == this->color) return; - - for (x--; x >= 0 && getPixel() == color; x--) drawPixel(); - xmin = ++x; - for (x = x0; x < cw && getPixel() == color; x++) drawPixel(); - y++; - for (x--; x >= xmin; x--) { - if (getPixel() == color) fill(); - y -= 2; - if (getPixel() == color) fill(); - y += 2; - } - y--; - x = x0; -} - -void Drawable::fillCircle(int d) -{ - int xo = 0, yo = d/2, rest = (d+1)/2-yo, x0 = x, y0 = y, rsq = d*d/4; - - while (xo <= yo) { - while (xo*xo+(2*yo-1)*(2*yo-1)/4 > rsq) yo--; - x = x0+xo; - for (y = y0-yo-rest; y <= y0+yo; y++) drawPixel(); - x = x0-xo-rest; - for (y = y0-yo-rest; y <= y0+yo; y++) drawPixel(); - - y = y0-xo-rest; - for (x = x0-yo-rest; x <= x0+yo; x++) drawPixel(); - y = y0+xo; - for (x = x0-yo-rest; x <= x0+yo; x++) drawPixel(); - - xo++; - } - gotoXY(x0,y0); -} - -void Drawable::fillRect(int w, int h) -{ - int x0 = x, y0 = y, w0 = w; - for (; h > 0; h--, y++) { - for (x = x0, w = w0; w > 0; w--, x++) { - drawPixel(); - } - } - gotoXY(x0,y0); -} - -void Drawable::drawDrawable(Drawable &d, unsigned char alpha) -{ - int scw = d.cw, sch = d.ch, w, h; - RGB *src, *dest; - - for (h = imax(d.cy,-ty-y); h < sch && y+h < ch; h++) { - src = d.buffer+d.width*(h+d.ty)+d.tx; - dest = buffer+width*(y+ty+h)+tx+x; - for (w = imax(d.cx,-tx-x); w < scw && x+w < cw; w++) { - RGB srcb = src[w], destb = dest[w]; - unsigned int sop = Color::A(srcb)*((unsigned int)alpha)/255; - unsigned int rop = Color::A(destb) + sop - Color::A(destb)*sop/255; - if (rop == 0) { - dest[w] = Color::Transparent; - } else { - unsigned int dop = Color::A(destb)*(255-sop)/255; - unsigned int magval = ((destb&Color::MagentaMask)*dop+(srcb&Color::MagentaMask)*sop); - dest[w] = (((magval&0xffff)/rop)&Color::BlueMask) | - (((magval&0xffff0000)/rop)&Color::RedMask) | - ((((destb&Color::GreenMask)*dop+(srcb&Color::GreenMask)*sop)/rop)&Color::GreenMask) | - (rop<toSpecial(c)) { - case Font::CR: gotoXY(0,y); return; - case Font::LF: gotoXY(0,y+font->getHeight()); return; - case Font::BS: gotoXY(imax(0,x-font->getWidth()),y); return; - case Font::Tab: gotoXY((((int)(x/font->getWidth()/8))+1)*8*font->getWidth(),y); return; - default: break; - } - if (font->getWidth(c)+x > cw) gotoXY(0,y+font->getHeight()); - } - font->drawChar(this,c); -} - -#define move(x) (ptr += ((x)+bit)/8-(((x)+bit)<0), bit = ((x)+bit+(((x)+bit)<0?8:0))%8) -void BitmapFont::drawChar(Drawable *d, const Char c) const { - const unsigned char *ptr = bitmap; - int bit = 0; - - if (c > last) return; - - if (char_position != NULL) { - ptr = char_position[c]; - bit = 0; - } else { - move(character_step*((int)c)); - } - - int rs = row_step; - int w = (widths != NULL?widths[c]:width); - int h = (ascents != NULL?ascents[c]:height); - Drawable out(*d,d->getX(),d->getY()-ascent,w,h); - - if (rs == 0) rs = isign(col_step)*w; - if (rs < 0) move(-rs*(h-1)); - if (col_step < 0) move(abs(rs)-1); - - for (int row = height-h; row < height; row++, move(rs-w*col_step)) { - for (int col = 0; col < w; col++, move(col_step)) { - if (!background_set ^ !(*ptr&(1<gotoXY(d->getX()+w,d->getY()); -} -#undef move - -std::map Font::registry; - -void Timer::check(unsigned int ticks) -{ - if (timers.empty()) return; - - if (Timer::ticks > (Timer::ticks+ticks)) { - ticks -= -1-Timer::ticks; - check(-1-Timer::ticks); - } - - std::multimap::iterator old, i = timers.lower_bound(Timer::ticks+1); - Timer::ticks += ticks; - - while (i != timers.end() && (*i).first <= Timer::ticks) { - Timer_Callback *c = (*i).second; - unsigned int time = (*i).first; - old = i; - ++i; - timers.erase(old); - unsigned int next = c->timerExpired(time); - if (next) add(c, time+next-Timer::ticks); - } -} - -void Timer::remove(const Timer_Callback *const timer) -{ - if (timers.empty()) return; - - std::multimap::iterator old, i = timers.begin(); - - while (i != timers.end()) { - old = i; - ++i; - if ((*old).second == timer) timers.erase(old); - } -} - -unsigned int Timer::next() -{ - if (timers.empty()) return 0; - - std::multimap::iterator i = timers.upper_bound(ticks); - - if (i == timers.end()) return 0; - return (*i).first-Timer::ticks; -} - -std::multimap Timer::timers; -unsigned int Timer::ticks = 0; - -BitmapFont::BitmapFont(const unsigned char *data, int height, int ascent, bool owner, - int width, bool background_set, - int col_step, int row_step, int character_step, Char last, - const int *widths, const int *ascents, const unsigned char *const* char_position, - const Font::SpecialChar *special) : - bitmap(data), - width(width), height(height), ascent(ascent), widths(widths), ascents(ascents), - background_set(background_set), col_step(col_step), row_step(row_step), - character_step(character_step?character_step:abs((row_step?row_step:width*col_step)*height)), - char_position(char_position), special(special), owner(owner), last(last) -{ -} - -BitmapFont::~BitmapFont() { - if (owner) { - if (bitmap != NULL) delete bitmap; - if (ascents != NULL) delete ascents; - if (widths != NULL) delete widths; - if (special != NULL) delete special; - } -} - -Window::Window(Window *parent, int x, int y, int w, int h) : - width(w), height(h), - x(x), y(y), - dirty(true), - visible(true), - parent(parent), - mouseChild(NULL) -{ - parent->addChild(this); -} - -Window::Window() : - width(0), height(0), - x(0), y(0), - dirty(false), - visible(true), - parent(NULL), - mouseChild(NULL) -{ -} - - -Window::~Window() -{ - while (!children.empty()) delete children.front(); - if (parent) parent->removeChild(this); - if (parent && parent->mouseChild == this) parent->mouseChild = NULL; -} - -void Window::addChild(Window *child) -{ - children.push_back(child); - setDirty(); -} - -void Window::removeChild(Window *child) -{ - children.remove(child); - setDirty(); -} - -void Window::move(int x, int y) -{ - this->x = x; - this->y = y; - std::list::iterator i = movehandlers.begin(); - bool end = (i == movehandlers.end()); - while (!end) { - Window_Callback *c = *i; - ++i; - end = (i == movehandlers.end()); - c->windowMoved(this,x,y); - } - parent->setDirty(); -} - -void Window::resize(int w, int h) -{ - this->width = w; - this->height = h; - setDirty(); -} - -void Window::paintAll(Drawable &d) const -{ - paint(d); - std::list::const_iterator i = children.begin(); - while (i != children.end()) { - Window *child = *i; - ++i; - if (child->visible) { - Drawable *cd = new Drawable(d,child->x,child->y,child->width,child->height); - child->paintAll(*cd); - delete cd; - } - } -} - -bool Window::keyDown(const Key &key) -{ - if (children.empty()) return false; - if ((*children.rbegin())->keyDown(key)) return true; - if (key.ctrl || key.alt || key.windows || key.special != Key::Tab) return false; - - if (key.shift) { - std::list::reverse_iterator i = children.rbegin(), e = children.rend(); - ++i; - while (i != e && !(*i)->raise()) ++i; - return i != e; - } else { - std::list::iterator i = children.begin(), e = children.end(); - while (i != e && !(*i)->raise()) ++i; - return (i != e); - } -} - -bool Window::keyUp(const Key &key) -{ - if (children.empty()) return false; - return (*children.rbegin())->keyUp(key); -} - -bool Window::mouseMoved(int x, int y) -{ - std::list::reverse_iterator i = children.rbegin(); - bool end = (i == children.rend()); - while (!end) { - Window *w = *i; - i++; - end = (i == children.rend()); - if (w->visible && x >= w->x && x <= w->x+w->width - && y >= w->y && y <= w->y+w->height - && w->mouseMoved(x-w->x, y-w->y)) return true; - } - return false; -} - -bool Window::mouseDragged(int x, int y, MouseButton button) -{ - if (mouseChild == NULL) return false; - return mouseChild->mouseDragged(x-mouseChild->x, y-mouseChild->y, button); -} - -bool Window::mouseDown(int x, int y, MouseButton button) -{ - Window *last = NULL; - std::list::reverse_iterator i = children.rbegin(); - bool end = (i == children.rend()); - while (!end) { - Window *w = *i; - i++; - end = (i == children.rend()); - if (w->visible && x >= w->x && x <= w->x+w->width - && y >= w->y && y <= w->y+w->height - && (mouseChild = last = w) - && w->mouseDown(x-w->x, y-w->y, button) - && w->raise()) { - return true; - } - } - mouseChild = NULL; - if (last != NULL) last->raise(); - return false; -} - -bool Window::mouseUp(int x, int y, MouseButton button) -{ - if (mouseChild == NULL) return false; - return mouseChild->mouseUp(x-mouseChild->x, y-mouseChild->y, button); -} - -bool Window::mouseClicked(int x, int y, MouseButton button) -{ - if (mouseChild == NULL) return false; - return mouseChild->mouseClicked(x-mouseChild->x, y-mouseChild->y, button); -} - -bool Window::mouseDoubleClicked(int x, int y, MouseButton button) -{ - if (mouseChild == NULL) return false; - return mouseChild->mouseDoubleClicked(x-mouseChild->x, y-mouseChild->y, button); -} - -bool BorderedWindow::mouseDown(int x, int y, MouseButton button) -{ - mouseChild = NULL; - if (x > width-border_right || y > width-border_bottom) return false; - x -= border_left; y -= border_top; - if (x < 0 || y < 0) return false; - return Window::mouseDown(x,y,button); -} - -bool BorderedWindow::mouseMoved(int x, int y) -{ - if (x > width-border_right || y > width-border_bottom) return false; - x -= border_left; y -= border_top; - if (x < 0 || y < 0) return false; - return Window::mouseMoved(x,y); -} - -bool BorderedWindow::mouseDragged(int x, int y, MouseButton button) -{ - if (x > width-border_right || y > width-border_bottom) return false; - x -= border_left; y -= border_top; - if (x < 0 || y < 0) return false; - return Window::mouseDragged(x,y,button); -} - -void ToplevelWindow::paint(Drawable &d) const -{ - int mask = (systemMenu->isVisible()?Color::RedMask|Color::GreenMask|Color::BlueMask:0); - d.clear(Color::Background); - - d.setColor(Color::Border); - d.drawLine(0,height-1,width-1,height-1); - d.drawLine(width-1,0,width-1,height-1); - - d.setColor(Color::Shadow3D); - d.drawLine(0,0,width-2,0); - d.drawLine(0,0,0,height-2); - d.drawLine(0,height-2,width-2,height-2); - d.drawLine(width-2,0,width-2,height-2); - - d.drawLine(5,4,width-7,4); - d.drawLine(5,4,5,30); - - d.setColor(Color::Light3D); - d.drawLine(1,1,width-3,1); - d.drawLine(1,1,1,height-3); - - d.drawLine(5,31,width-6,31); - d.drawLine(width-6,5,width-6,31); - - d.setColor(Color::Background3D^mask); - d.fillRect(6,5,26,26); - d.setColor(Color::Grey50^mask); - d.fillRect(9,17,20,4); - d.setColor(Color::Black^mask); - d.fillRect(8,16,20,4); - d.setColor(Color::White^mask); - d.fillRect(9,17,18,2); - - d.setColor(Color::Border); - d.drawLine(32,5,32,30); - - d.setColor(Color::Titlebar); - d.fillRect(33,5,width-39,26); - - const Font *font = Font::getFont("title"); - d.setColor(Color::TitlebarText); - d.setFont(font); - d.drawText(31+(width-39-font->getWidth(title))/2,5+(26-font->getHeight())/2+font->getAscent(),title,false,0); -} - -void Input::paint(Drawable &d) const -{ - d.clear(Color::EditableBackground); - - d.setColor(Color::Shadow3D); - d.drawLine(0,0,width-2,0); - d.drawLine(0,0,0,height-2); - - d.setColor(Color::Background3D); - d.drawLine(1,height-2,width-2,height-2); - d.drawLine(width-2,1,width-2,height-2); - - d.setColor(Color::Text); - d.drawLine(1,1,width-3,1); - d.drawLine(1,1,1,height-3); - - const Font *f = Font::getFont("input"); - d.setFont(f); - - Drawable d1(d,3,4,width-6,height-8); - Drawable dr(d1,(multi?0:-offset),(multi?-offset:0),width-6+(multi?0:offset),height-8+(multi?offset:0)); - - const Size start = imin(start_sel, end_sel), end = imax(start_sel, end_sel); - dr.drawText(0,f->getAscent()+1,text,multi,0,start); - - int sx = dr.getX(), sy = dr.getY(); - dr.drawText(text, multi, start, end-start); - int ex = dr.getX(), ey = dr.getY(); - - if (sx != ex || sy != ey) { - dr.setColor(Color::SelectionBackground); - if (sy == ey) dr.fillRect(sx,sy-f->getAscent(),ex-sx,f->getHeight()+1); - else { - dr.fillRect(sx, sy-f->getAscent(), width-sx+offset, f->getHeight() ); - dr.fillRect(0, sy-f->getAscent()+f->getHeight(), width+offset, ey-sy-f->getHeight()); - dr.fillRect(0, ey-f->getAscent(), ex, f->getHeight() ); - } - dr.setColor(Color::SelectionForeground); - dr.drawText(sx, sy, text, multi, start, end-start); - } - - dr.setColor(Color::Text); - - dr.drawText(text, multi, end); - - if (blink && hasFocus()) { - if (insert) dr.drawLine(posx,posy,posx,posy+f->getHeight()+1); - else dr.fillRect(posx,posy,f->getWidth(text[pos]),f->getHeight()+1); - } -} - -Size Input::findPos(int x, int y) { - const Font *f = Font::getFont("input"); - if (multi) y += offset; - else x += offset; - y = (y-4) / f->getHeight(); - int line = 0; - Size pos = 0; - while (line < y && pos < text.size()) if (f->toSpecial(text[pos++]) == Font::LF) line++; - Drawable d(width-6,1); - d.setFont(f); - while (pos <= text.size() && d.getY() == 0 && x > d.getX()) { - d.drawText(String(text), multi, pos, 1); - pos++; - } - if (pos > 0) pos--; - return pos; -} - -bool Input::mouseDown(int x, int y, MouseButton button) -{ - if (button == Left || (button == Middle && start_sel == end_sel)) { - end_sel = start_sel = pos = findPos(x,y); - blink = true; - checkOffset(); - } - if (button == Middle) keyDown(Key(0,Key::Insert,true,false,false,false)); - return true; -} - -bool Input::mouseDragged(int x, int y, MouseButton button) -{ - if (button == Left) { - end_sel = pos = findPos(x,y); - blink = true; - checkOffset(); - } - return true; -} - -bool Input::keyDown(const Key &key) -{ - const Font *f = Font::getFont("input"); - switch (key.special) { - case Key::None: - if (key.ctrl) { - switch (key.character) { - case 1: - case 'a': - case 'A': - if (key.shift) { - start_sel = end_sel = pos; - } else { - start_sel = 0; - pos = end_sel = (Size)text.size(); - } - break; - case 24: - case 'x': - case 'X': - cutSelection(); - break; - case 3: - case 'c': - case 'C': - copySelection(); - break; - case 22: - case 'v': - case 'V': - pasteSelection(); - break; - default: printf("Ctrl-0x%x\n",key.character); break; - } - break; - } - if (start_sel != end_sel) clearSelection(); - if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,key.character); - else text[pos++] = key.character; - break; - case Key::Left: - if (pos > 0) pos--; - break; - case Key::Right: - if (pos < text.size()) pos++; - break; - case Key::Down: - if (multi) pos = findPos(posx+3, posy-offset+f->getHeight()+4); - break; - case Key::Up: - if (multi) pos = findPos(posx+3, posy-offset-f->getHeight()+4); - break; - case Key::Home: - if (multi) { - while (pos > 0 && f->toSpecial(text[pos-1]) != Font::LF) pos--; - } else pos = 0; - break; - case Key::End: - if (multi) { - while (pos < text.size() && f->toSpecial(text[pos]) != Font::LF) pos++; - } else pos = (Size)text.size(); - break; - case Key::Backspace: - if (!key.shift && start_sel != end_sel) clearSelection(); - else if (pos > 0) text.erase(text.begin()+ --pos); - break; - case Key::Delete: - if (key.shift) cutSelection(); - else if (start_sel != end_sel) clearSelection(); - else if (pos < text.size()) text.erase(text.begin()+pos); - break; - case Key::Insert: - if (key.ctrl) copySelection(); - else if (key.shift) pasteSelection(); - else insert = !insert; - break; - case Key::Enter: - if (multi) { - if (start_sel != end_sel) clearSelection(); - if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,f->fromSpecial(Font::LF)); - else text[pos++] = f->fromSpecial(Font::LF); - } else executeAction(text); - break; - case Key::Tab: - if (multi) { - if (start_sel != end_sel) clearSelection(); - if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,f->fromSpecial(Font::Tab)); - else text[pos++] = f->fromSpecial(Font::Tab); - } else return false; - break; - default: - return false; - } - if (!key.ctrl) { - if (!key.shift || key.special == Key::None) start_sel = end_sel = pos; - else end_sel = pos; - } - checkOffset(); - blink = true; - return true; -} - -void BorderedWindow::paintAll(Drawable &d) const -{ - this->paint(d); - Drawable dchild(d,border_left,border_top,width-border_left-border_right,height-border_top-border_bottom); - for (std::list::const_iterator i = children.begin(); i != children.end(); ++i) { - Window *child = *i; - if (child->isVisible()) { - Drawable cd(dchild,child->getX(),child->getY(),child->getWidth(),child->getHeight()); - child->paintAll(cd); - } - } -} - -void Button::paint(Drawable &d) const -{ - int offset = -1; - - if (hasFocus()) { - offset = 0; - d.setColor(Color::Border); - d.drawLine(0,0,width,0); - d.drawLine(0,0,0,height); - - d.drawLine(0,height-1,width,height-1); - d.drawLine(width-1,0,width-1,height); - } - - d.setColor(Color::Background3D); - d.fillRect(2,2,width-4,height-4); - - if (pressed) { - d.setColor(Color::Shadow3D); - - d.drawLine(1+offset,1+offset,width-2-offset,1+offset); - d.drawLine(1+offset,1+offset,1+offset,height-2-offset); - } else { - d.setColor(Color::Background3D); - - d.drawLine(1+offset,1+offset,width-3-offset,1+offset); - d.drawLine(1+offset,1+offset,1+offset,height-3-offset); - - d.setColor(Color::Light3D); - - d.drawLine(2+offset,2+offset,width-4-offset,2+offset); - d.drawLine(2+offset,2+offset,2+offset,height-4-offset); - - d.setColor(Color::Shadow3D); - - d.drawLine(2+offset,height-3-offset,width-2-offset,height-3-offset); - d.drawLine(width-3-offset,2+offset,width-3-offset,height-2-offset); - - d.setColor(Color::Border); - - d.drawLine(width-2-offset,1+offset,width-2-offset,height-2-offset); - d.drawLine(1+offset,height-2-offset,width-2-offset,height-2-offset); - } -} - -bool Checkbox::keyDown(const Key &key) -{ - switch (key.special) { - case Key::None: - if (key.character != ' ') return false; - case Key::Enter: - break; - default: return false; - } - mouseDown(0,0,Left); - return true; -} - -bool Checkbox::keyUp(const Key &key) -{ - if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false; - mouseUp(0,0,Left); - mouseClicked(0,0,Left); - return true; -} - -void Checkbox::paint(Drawable &d) const -{ - d.setColor(Color::Background3D); - d.fillRect(2,(height/2)-7,14,14); - - d.setColor(Color::Shadow3D); - d.drawLine(2,(height/2)-7,13,(height/2)-7); - d.drawLine(2,(height/2)-7,2,(height/2)+5); - - d.setColor(Color::Light3D); - d.drawLine(2,(height/2)+5,14,(height/2)+5); - d.drawLine(14,(height/2)-7,14,(height/2)+5); - - d.setColor(Color::EditableBackground); - d.fillRect(4,(height/2)-5,9,9); - - d.setColor(Color::Border); - d.drawLine(3,(height/2)-6,12,(height/2)-6); - d.drawLine(3,(height/2)-6,3,(height/2)+4); - - if (checked) { - d.setColor(Color::Text); - d.drawLine(5,(height/2)-2,7,(height/2) ); - d.drawLine(11,(height/2)-4); - d.drawLine(5,(height/2)-1,7,(height/2)+1); - d.drawLine(11,(height/2)-3); - d.drawLine(5,(height/2) ,7,(height/2)+2); - d.drawLine(11,(height/2)-2); - } -} - -Radiobox::Radiobox(Frame *parent, int x, int y, int w, int h) : BorderedWindow(static_cast(parent),x,y,w,h,16,0,0,0), ActionEventSource("GUI::Radiobox"), checked(0) -{ - addActionHandler(parent); -} - -bool Radiobox::keyDown(const Key &key) -{ - switch (key.special) { - case Key::None: - if (key.character != ' ') return false; - case Key::Enter: - break; - default: return false; - } - mouseDown(0,0,Left); - return true; -} - -bool Radiobox::keyUp(const Key &key) -{ - if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false; - mouseUp(0,0,Left); - mouseClicked(0,0,Left); - return true; -} - -void Radiobox::paint(Drawable &d) const -{ - d.setColor(Color::Light3D); - d.drawLine(6,(height/2)+6,9,(height/2)+6); - d.drawLine(4,(height/2)+5,11,(height/2)+5); - d.drawLine(13,(height/2)-1,13,(height/2)+2); - d.drawLine(12,(height/2)-2,12,(height/2)+4); - - d.setColor(Color::Background3D); - d.drawLine(6,(height/2)+5,9,(height/2)+5); - d.drawLine(4,(height/2)+4,11,(height/2)+4); - d.drawLine(12,(height/2)-1,12,(height/2)+2); - d.drawLine(11,(height/2)-2,11,(height/2)+4); - - d.setColor(Color::Shadow3D); - d.drawLine(6,(height/2)-5,9,(height/2)-5); - d.drawLine(4,(height/2)-4,11,(height/2)-4); - d.drawLine(2,(height/2)-1,2,(height/2)+2); - d.drawLine(3,(height/2)-3,3,(height/2)+4); - - d.setColor(Color::Border); - d.drawLine(6,(height/2)-4,9,(height/2)-4); - d.drawLine(4,(height/2)-3,11,(height/2)-3); - d.drawLine(3,(height/2)-1,3,(height/2)+2); - d.drawLine(4,(height/2)-3,4,(height/2)+3); - - d.setColor(Color::EditableBackground); - d.fillRect(5,(height/2)-2,6,6); - d.fillRect(4,(height/2)-1,8,4); - d.fillRect(6,(height/2)-3,4,8); - - if (checked) { - d.setColor(Color::Text); - d.fillRect(6,(height/2),4,2); - d.fillRect(7,(height/2)-1,2,4); - } -} - -void Menu::paint(Drawable &d) const -{ - d.clear(Color::Background3D); - - d.setColor(Color::Border); - d.drawLine(0,height-1,width-1,height-1); - d.drawLine(width-1,0,width-1,height-1); - - d.setColor(Color::Shadow3D); - d.drawLine(0,0,width-2,0); - d.drawLine(0,0,0,height-2); - d.drawLine(0,height-2,width-2,height-2); - d.drawLine(width-2,0,width-2,height-2); - - d.setColor(Color::Light3D); - d.drawLine(1,1,width-3,1); - d.drawLine(1,1,1,height-3); - - d.setFont(Font::getFont("menu")); - const int asc = Font::getFont("menu")->getAscent()+1; - const int height = Font::getFont("menu")->getHeight()+2; - int y = asc+3; - int index = 0; - for (std::vector::const_iterator i = items.begin(); i != items.end(); ++i) { - if ((*i).empty()) { - d.setColor(Color::Shadow3D); - d.drawLine(4,y-asc+6,width-5,y-asc+6); - d.setColor(Color::Light3D); - d.drawLine(4,y-asc+7,width-5,y-asc+7); - y += 12; - } else { - if (index == selected && hasFocus()) { - d.setColor(Color::SelectionBackground); - d.fillRect(3,y-asc,width-6,height); - d.setColor(Color::SelectionForeground); - } else { - d.setColor(Color::Text); - } - d.drawText(20,y,(*i),false,0); - y += height; - } - index++; - } -} - -void Menubar::paint(Drawable &d) const -{ - const Font *f = Font::getFont("menu"); - - d.setColor(Color::Light3D); - d.drawLine(0,height-1,width-1,height-1); - d.setColor(Color::Shadow3D); - d.drawLine(0,height-2,width-1,height-2); - - d.gotoXY(7,f->getAscent()+2); - - int index = 0; - for (std::vector::const_iterator i = menus.begin(); i != menus.end(); ++i, ++index) { - if (index == selected && (*i)->isVisible()) { - int w = f->getWidth((*i)->getName()); - d.setColor(Color::SelectionBackground); - d.fillRect(d.getX()-7,0,w+14,height-2); - d.setColor(Color::SelectionForeground); - d.gotoXY(d.getX()+7,f->getAscent()+2); - } else { - d.setColor(Color::Text); - } - d.drawText((*i)->getName(),false); - d.gotoXY(d.getX()+14,f->getAscent()+2); - } -} - -bool Button::keyDown(const Key &key) -{ - switch (key.special) { - case Key::None: - if (key.character != ' ') return false; - case Key::Enter: - break; - default: return false; - } - mouseDown(0,0,Left); - return true; -} - -bool Button::keyUp(const Key &key) -{ - if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false; - mouseUp(0,0,Left); - mouseClicked(0,0,Left); - return true; -} - -void Frame::paint(Drawable &d) const { - const Font *f = Font::getFont("default"); - const int top = (label.empty()?1:f->getAscent()/2+1); - - d.setColor(Color::Shadow3D); - d.drawLine(1,height-2,1,top); - d.drawLine(8,top); - d.drawLine((label.empty()?8:f->getWidth(label)+14),top,width-2,top); - d.drawLine(2,height-3,width-3,height-3); - d.drawLine(width-3,top+1); - - d.setColor(Color::Light3D); - d.drawLine(2,height-3,2,top+1); - d.drawLine(8,top+1); - d.drawLine((label.empty()?8:f->getWidth(label)+14),top+1,width-3,top+1); - d.drawLine(2,height-2,width-2,height-2); - d.drawLine(width-2,top+1); - - d.setColor(Color::Text); - d.drawText(11,f->getAscent()+1,label,false,0); -} - -Screen *Window::getScreen() { return (parent == NULL?dynamic_cast(this):parent->getScreen()); } - -Screen::Screen(unsigned int width, unsigned int height) : - Window(), - buffer(new Drawable(width, height)) -{ - this->width = width; - this->height = height; -} - -Screen::Screen(Drawable *d) : - Window(), - buffer(d) -{ - this->width = d->getClipWidth(); - this->height = d->getClipHeight(); -} - -Screen::~Screen() -{ -} - -void Screen::paint(Drawable &d) const -{ - d.clear(Color::Transparent); -} - -unsigned int Screen::update(void *surface, unsigned int ticks) -{ - Timer::check(ticks); - - paintAll(*buffer); - RGB *buf = buffer->buffer; - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++, buf++) { - RGB sval = surfaceToRGB(surface); - RGB bval = *buf; - int a = Color::A(bval); - bval = ((((sval&Color::MagentaMask)*a+(bval&Color::MagentaMask)*(256-a))>>8)&Color::MagentaMask) - | ((((sval&Color::GreenMask)*a+(bval&Color::GreenMask)*(256-a))>>8)&Color::GreenMask); - rgbToSurface(bval, &surface); - } - } - - return Timer::next(); -} - -void Screen::move(int x, int y) -{ -} - -void Screen::resize(int w, int h) -{ -} - -#ifdef TESTING -static void test(Drawable &d) { - const int width = d.getClipWidth(); - const int height = d.getClipHeight(); - - d.clear(Color::rgba(0,0,255,128)); - - d.setColor(Color::Black); - for (int x = 0; x < width; x += 10) d.drawLine(x,0,x,height); - for (int y = 0; y < height; y += 10) d.drawLine(0,y,width,y); - - d.setColor(Color::Red); - for (int x = 10; x <= 130 ; x += 10) { - d.drawLine(x,10,70,70); - d.drawLine(x,130); - } - for (int y = 10; y <= 130 ; y += 10) { - d.drawLine(10,y,70,70); - d.drawLine(130,y); - } - - d.setColor(Color::Yellow); - d.fillRect(150,10,30,30); - d.setColor(Color::Blue); - d.drawRect(30,30); - - d.drawRect(150,60,30,30); - d.setColor(Color::Yellow); - d.fillRect(30,30); - - for (int x = 0; x <= 100 ; x += 10) { - d.setColor(Color::rgba(0xff,0x00,0xff,(255*x/100)&255)); - d.fillRect(200+2*x,0,20,20); - } - - d.setColor(Color::Yellow); - d.fillCircle(210,60,40); - d.setColor(Color::Blue); - d.drawCircle(40); - - d.drawCircle(210,110,40); - d.setColor(Color::Yellow); - d.fillCircle(40); - - d.setColor(Color::rgba(0,0,255,128)); - d.fillRect(251,41,9,59); - d.fillRect(251,41,59,9); - d.fillRect(301,41,9,59); - d.fillRect(291,91,19,9); - d.fillRect(291,51,9,49); - d.fillRect(261,51,39,9); - d.fillRect(261,51,9,49); - d.fillRect(261,91,29,9); - d.fillRect(281,61,9,39); - d.fillRect(271,61,19,9); - d.fillRect(271,61,9,29); - d.fillRect(241,41,9,59); - d.fillRect(241,41,19,9); - d.fillRect(241,91,19,9); - d.setColor(Color::rgba(255,0,0,128)); - d.fill(255,64); - - d.setColor(Color::Green); - Drawable(d,500,355,30,30).fillCircle(65); - - for (int i = 0; i <= 100; i += 10) { - Drawable(d,25,155+i*3,420,30).drawDrawable(0,0,d,255*i/100); - } - - d.setColor(Color::White); - d.setFont(Font::getFont("VGA14")); - d.drawText(270,110,"GUI:: Test Program\n"); - d.drawText("Still testing\tTable\n"); - d.drawText("More of...\tTable\n"); - d.drawText("Overwrite\rXXXXXXXXX\n"); - d.drawText("Fake int'l chars: O\b/e\b\"\n"); - d.drawText("Real ones: \211\222\234\345\246\321"); -} -#else -static void test(Drawable &d) { (void)d; } -#endif - - -void ScreenRGB32le::paint(Drawable &d) const -{ - parent->paint(d); - test(d); -} - -static MouseButton SDL_to_GUI(const int button) -{ - switch (button) { - case SDL_BUTTON_LEFT: return GUI::Left; - case SDL_BUTTON_RIGHT: return GUI::Right; - case SDL_BUTTON_MIDDLE: return GUI::Middle; - case SDL_BUTTON_WHEELUP: return GUI::WheelUp; - case SDL_BUTTON_WHEELDOWN: return GUI::WheelDown; - default: return GUI::NoButton; - } -} - -static const Key SDL_to_GUI(const SDL_keysym &key) -{ - GUI::Key::Special ksym = GUI::Key::None; - switch (key.sym) { - case SDLK_ESCAPE: ksym = GUI::Key::Escape; break; - case SDLK_BACKSPACE: ksym = GUI::Key::Backspace; break; - case SDLK_TAB: ksym = GUI::Key::Tab; break; - case SDLK_LEFT: ksym = GUI::Key::Left; break; - case SDLK_RIGHT: ksym = GUI::Key::Right; break; - case SDLK_UP: ksym = GUI::Key::Up; break; - case SDLK_DOWN: ksym = GUI::Key::Down; break; - case SDLK_HOME: ksym = GUI::Key::Home; break; - case SDLK_END: ksym = GUI::Key::End; break; - case SDLK_DELETE: ksym = GUI::Key::Delete; break; - case SDLK_INSERT: ksym = GUI::Key::Insert; break; - case SDLK_RETURN: ksym = GUI::Key::Enter; break; - case SDLK_MENU: ksym = GUI::Key::Menu; break; - case SDLK_PAGEUP: ksym = GUI::Key::PageUp; break; - case SDLK_PAGEDOWN: ksym = GUI::Key::PageDown; break; - case SDLK_PRINT: ksym = GUI::Key::Print; break; - case SDLK_PAUSE: ksym = GUI::Key::Pause; break; - case SDLK_BREAK: ksym = GUI::Key::Break; break; - case SDLK_CAPSLOCK: ksym = GUI::Key::CapsLock; break; - case SDLK_NUMLOCK: ksym = GUI::Key::NumLock; break; - case SDLK_SCROLLOCK: ksym = GUI::Key::ScrollLock; break; - case SDLK_F1:case SDLK_F2:case SDLK_F3:case SDLK_F4:case SDLK_F5:case SDLK_F6: - case SDLK_F7:case SDLK_F8:case SDLK_F9:case SDLK_F10:case SDLK_F11:case SDLK_F12: - ksym = (GUI::Key::Special)(GUI::Key::F1 + key.sym-SDLK_F1); - default: break; - } - return Key(key.unicode, ksym, - (key.mod&KMOD_SHIFT)>0, - (key.mod&KMOD_CTRL)>0, - (key.mod&KMOD_ALT)>0, - (key.mod&KMOD_META)>0); -} - -/** \brief Internal class that handles different screen bit depths and layouts the SDL way */ -class SDL_Drawable : public Drawable { -protected: - SDL_Surface *const surface; - -public: - SDL_Drawable(int width, int height, RGB clear = Color::Transparent) : Drawable(width, height, clear), surface(SDL_CreateRGBSurfaceFrom(buffer, width, height, 32, width*4, Color::RedMask, Color::GreenMask, Color::BlueMask, Color::AlphaMask)) { - surface->flags |= SDL_SRCALPHA; - } - - ~SDL_Drawable() { - SDL_FreeSurface(surface); - } - - void update(SDL_Surface *dest) const { - SDL_BlitSurface(surface, NULL, dest, NULL); - } -}; - -ScreenSDL::ScreenSDL(SDL_Surface *surface) : Screen(new SDL_Drawable(surface->w, surface->h)), surface(surface), downx(0), downy(0), lastclick(0) {} - -Ticks ScreenSDL::update(Ticks ticks) -{ - Timer::check(ticks); - - paintAll(*buffer); - static_cast(buffer)->update(surface); - - return Timer::next(); -} - -void ScreenSDL::paint(Drawable &d) const { - d.clear(Color::Transparent); - test(d); -} - -bool ScreenSDL::event(const SDL_Event &event) { - bool rc; - - switch (event.type) { - case SDL_KEYUP: { - const Key &key = SDL_to_GUI(event.key.keysym); - if (key.special == GUI::Key::None && key.character == 0) break; - if (key.special == GUI::Key::CapsLock || key.special == GUI::Key::NumLock) keyDown(key); - return keyUp(key); - } - case SDL_KEYDOWN: { - const Key &key = SDL_to_GUI(event.key.keysym); - if (key.special == GUI::Key::None && key.character == 0) break; - rc = keyDown(key); - if (key.special == GUI::Key::CapsLock || key.special == GUI::Key::NumLock) keyUp(key); - return rc; - } - case SDL_MOUSEMOTION: - if (event.motion.state) { - if (abs(event.motion.x-downx) <= 10 && abs(event.motion.y-downy) <= 10) - break; - downx = -11; downy = -11; - if (event.motion.state&SDL_BUTTON(1)) - return mouseDragged(event.motion.x, event.motion.y, GUI::Left); - else if (event.motion.state&SDL_BUTTON(2)) - return mouseDragged(event.motion.x, event.motion.y, GUI::Middle); - else if (event.motion.state&SDL_BUTTON(3)) - return mouseDragged(event.motion.x, event.motion.y, GUI::Right); - break; - } - - return mouseMoved(event.motion.x, event.motion.y); - - case SDL_MOUSEBUTTONDOWN: - rc = mouseDown(event.button.x, event.button.y, SDL_to_GUI(event.button.button)); - if (abs(event.button.x-downx) > 10 || abs(event.button.y-downy) > 10) lastclick = 0; - downx = event.button.x; downy = event.button.y; - return rc; - - case SDL_MOUSEBUTTONUP: - rc = mouseUp(event.button.x, event.button.y, SDL_to_GUI(event.button.button)); - if (abs(event.button.x-downx) < 10 && abs(event.button.y-downy) < 10) { - if (lastclick == 0 || (GUI::Timer::now()-lastclick) > 20) { - lastclick = GUI::Timer::now(); - rc |= mouseClicked(downx, downy, SDL_to_GUI(event.button.button)); - } else if (lastclick != 0) { - rc |= mouseDoubleClicked(downx, downy, SDL_to_GUI(event.button.button)); - lastclick = 0; - } else { - lastclick = 0; - } - } else { - lastclick = 0; - } - return rc; - } - - return false; -} - -} - - - -#ifdef TESTING -#include - -/** \brief A test program that serves as an example for all GUI elements. - * - * Note that you need SDL installed and a file "testfont.h" for this - * to compile, which must contain a bitmap font declared as - * - * \code - * static const unsigned char testfont[256 * 14] = { ... }; - * \endcode - * - * (256 chars, 8x14 fixed-width font, for example the IBM PC VGA 14-line font, - * you can get it from DOSBox) - * - * To compile it, use a command line like this: - * - * \code - * g++ -DTESTING `sdl-config --cflags` `sdl-config --libs` gui_tk.cpp -o testgui_tk - * \endcode - * - */ - -int main(int argc, char *argv[]) -{ - printf("GUI:: test program\n"); - - SDL_Surface *screen; - - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); - exit(1); - } - - atexit(SDL_Quit); - - screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE); - if (screen == NULL) { - fprintf(stderr, "Couldn't set 640x480x32 video mode: %s\n", SDL_GetError()); - exit(1); - } - printf("GUI:: color depth %i\n",screen->format->BitsPerPixel); - - SDL_EnableUNICODE(true); - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); - - #include "testfont.h" - GUI::Font::addFont("default",new GUI::BitmapFont(testfont,14,10)); - - GUI::ScreenSDL guiscreen(screen); - GUI::ToplevelWindow *frame = new GUI::ToplevelWindow(&guiscreen,205,100,380,250,"GUI::Frame"); - static struct delwin : public GUI::ActionEventSource_Callback { - void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { - dynamic_cast(dynamic_cast(b)->getParent())->close(); - } - } dw; - struct newwin : public GUI::ActionEventSource_Callback { - GUI::Screen *screen; - int n; - void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { - char title[256]; - sprintf(title,"Window %i",++n); - GUI::ToplevelWindow *w = new GUI::ToplevelWindow(screen,405,100,120,150,title); - GUI::Button *close = new GUI::Button(w,5,5,"Close"); - close->addActionHandler(&dw); - } - } nw; - nw.screen = &guiscreen; - nw.n = 0; - struct quit : public GUI::ActionEventSource_Callback { - GUI::ToplevelWindow *frame; - void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { - if (arg == "Quit" && b->getName() != "GUI::Input") exit(0); - frame->setTitle(arg); - } - } ex; - ex.frame = frame; - - GUI::Button *b = new GUI::Button(frame,8,20,"Open a new Window"); - b->addActionHandler(&nw); - (new GUI::Button(frame,200,20,"1"))->addActionHandler(&ex); - (new GUI::Button(frame,235,20,"2"))->addActionHandler(&ex); - b = new GUI::Button(frame,270,20,"Quit"); - b->addActionHandler(&ex); - (new GUI::Input(frame,16,55,150))->addActionHandler(&ex); - - printf("Title: %s\n",(const char*)frame->getTitle()); - - struct movewin : public GUI::Timer_Callback, public GUI::ToplevelWindow_Callback { - public: - GUI::ToplevelWindow *frame; - GUI::Checkbox *cb1, *cb2; - int x, y; - virtual unsigned int timerExpired(unsigned int t) { - if (cb2->isChecked()) frame->move(frame->getX()+x,frame->getY()+y); - if (frame->getX() <= -frame->getWidth()) x = 1; - if (frame->getX() >= 640) x = -1; - if (frame->getY() <= -frame->getHeight()) y = 1; - if (frame->getY() >= 480) y = -1; - return 10; - } - virtual bool windowClosing(GUI::ToplevelWindow *win) { - if (!cb1->isChecked()) return false; - return true; - } - virtual void windowClosed(GUI::ToplevelWindow *win) { - GUI::Timer::remove(this); - } - } mw; - mw.frame = frame; - mw.x = -1; - mw.y = 1; - GUI::Frame *box = new GUI::Frame(frame,16,80,300,50); - mw.cb1 = new GUI::Checkbox(box,0,0,"Allow to close this window"); - mw.cb2 = new GUI::Checkbox(box,0,20,"Move this window"); - box = new GUI::Frame(frame,16,130,300,80,"Radio Buttons"); - (new GUI::Radiobox(box,0,0,"Normal"))->setChecked(true); - new GUI::Radiobox(box,0,20,"Dynamic"); - new GUI::Radiobox(box,0,40,"Simple"); - box->addActionHandler(&ex); - GUI::Timer::add(&mw,10); - frame->addWindowHandler(&mw); - GUI::Menubar *bar = new GUI::Menubar(frame,0,0,frame->getWidth()); - bar->addMenu("File"); - bar->addItem(0,"New..."); - bar->addItem(0,"Open..."); - bar->addItem(0,""); - bar->addItem(0,"Save"); - bar->addItem(0,"Save as..."); - bar->addItem(0,""); - bar->addItem(0,"Close"); - bar->addItem(0,"Quit"); - bar->addMenu("Edit"); - bar->addItem(1,"Undo"); - bar->addItem(1,"Redo"); - bar->addItem(1,""); - bar->addItem(1,"Cut"); - bar->addItem(1,"Copy"); - bar->addItem(1,"Paste"); - bar->addItem(1,""); - bar->addItem(1,"Select all"); - bar->addItem(1,"Select none"); - bar->addMenu("View"); - bar->addItem(2,"Zoom..."); - bar->addItem(2,"Zoom in"); - bar->addItem(2,"Zoom out"); - bar->addMenu("?"); - bar->addItem(3,"Manual"); - bar->addItem(3,"Search..."); - bar->addItem(3,""); - bar->addItem(3,"About"); - bar->addActionHandler(&ex); - - SDL_Event event; - while (1) { - while (SDL_PollEvent(&event)) { - if (!guiscreen.event(event)) { - if (event.type == SDL_QUIT) exit(0); - } - } - - if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); - memset(screen->pixels,0xff,4*640*15); - memset(((char *)screen->pixels)+4*640*15,0x00,4*640*450); - memset(((char *)screen->pixels)+4*640*465,0xff,4*640*15); - if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); - guiscreen.update(4); - SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); - - SDL_Delay(40); - } -} -#endif - +#if 0 +/* + * gui_tk - framework-agnostic GUI toolkit + * Copyright (C) 2005-2007 Jörg Walter + * + * gui_tk 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 3 of the License, or + * (at your option) any later version. + * + * gui_tk 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, see + */ + +/* TODO: + - make menu a bufferedwindow with shadow +*/ +/* $Id: gui_tk.cpp,v 1.5 2009-02-01 16:06:26 qbix79 Exp $ */ + +/** \file + * \brief Implementation file for gui_tk. + * + * It contains implementations for all non-inlined class methods. + * + * Also contained is a small test program that demonstrates all features of + * gui_tk. It is enabled by defining the preprocessor macro TESTING. + */ + +#include +#include "gui_tk.h" + +namespace GUI { + +namespace Color { + +RGB Background3D = 0xffc0c0c0; + +RGB Light3D = 0xfffcfcfc; + +RGB Shadow3D = 0xff808080; + +RGB Border = 0xff000000; + +RGB Text = 0xff000000; + +RGB Background = 0xffc0c0c0; + +RGB SelectionBackground = 0xff000080; + +RGB SelectionForeground = 0xffffffff; + +RGB EditableBackground = 0xffffffff; + +RGB Titlebar = 0xff000080; + +RGB TitlebarText = 0xffffffff; + +} + +void Drawable::drawText(const String& text, bool interpret, Size start, Size len) { + if (interpret) { + if (len > text.size()-start) len = (Size)(text.size()-start); + len += start; + + Size wordstart = start; + int width = 0; + + while (start < len) { + switch (font->toSpecial(text[start])) { + case Font::CR: + if (wordstart != start) { + drawText(text,false,wordstart,start-wordstart); + wordstart = start; + width = 0; + } + wordstart++; + gotoXY(0,y); + break; + case Font::LF: + if (wordstart != start) { + drawText(text,false,wordstart,start-wordstart); + wordstart = start; + width = 0; + } + wordstart++; + gotoXY(0,y+font->getHeight()); + break; + case Font::BS: + if (wordstart != start) { + drawText(text,false,wordstart,start-wordstart); + wordstart = start; + width = 0; + } + wordstart++; + gotoXY(imax(0,x-font->getWidth()),y); + break; + case Font::Tab: + if (wordstart != start) { + drawText(text,false,wordstart,start-wordstart); + wordstart = start; + width = 0; + } + wordstart++; + gotoXY((((int)(x/font->getWidth()/8))+1)*8*font->getWidth(),y); + break; + case Font::Space: + if (wordstart != start) { + drawText(text,false,wordstart,start-wordstart); + wordstart = start; + width = 0; + } + wordstart++; + font->drawString(this,text,start,1); + break; + case Font::ESC: // ignore ANSI sequences except for colors + if (wordstart != start) { + drawText(text,false,wordstart,start-wordstart); + wordstart = start; + width = 0; + } + wordstart++; + do { + int seqstart = start+1; + Char c; + do { + start++; + wordstart++; + c = font->toSpecial(text[start]); + } while (start < len && ((c >= '0' && c <= '9') || c == ';' || c == '[')); + if (c == 'm' && start < len) { + if (font->toSpecial(text[seqstart++]) != '[') break; + c = font->toSpecial(text[seqstart++]); + while (c != 'm') { + int param = 0; + if (c == ';') c = '0'; + while (c != 'm' && c != ';') { + param = param * 10 + c-'0'; + c = font->toSpecial(text[seqstart++]); + } + const RGB bright = 0x00808080; + const RGB intensity = (color&bright?~0:~bright); + switch (param) { + case 0: setColor(Color::Black); break; + case 1: setColor(color | 0x00808080); break; + case 30: setColor((Color::Black|bright) & intensity); break; + case 31: setColor(Color::Red & intensity); break; + case 32: setColor(Color::Green & intensity); break; + case 33: setColor(Color::Yellow & intensity); break; + case 34: setColor(Color::Blue & intensity); break; + case 35: setColor(Color::Magenta & intensity); break; + case 36: setColor(Color::Cyan & intensity); break; + case 37: setColor(Color::White & intensity); break; + default: break; + } + } + } + } while (0); + default: + width += font->getWidth(text[start]); + if (x > 0 && x+width > cw) gotoXY(0,y+font->getHeight()); + } + start++; + } + if (wordstart != start) drawText(text,false,wordstart,start-wordstart); + return; + } + + font->drawString(this,text,start,len); +} + +bool ToplevelWindow::mouseDown(int x, int y, MouseButton button) { + if (button == Left && x > 32 && x < width-6 && y > 4 && y < 31) { + dragx = x; + dragy = y; + mouseChild = NULL; + systemMenu->setVisible(false); + return true; + } else if (button == Left && x < 32 && x > 6 && y > 4 && y < 31) { + mouseChild = NULL; + raise(); + systemMenu->setVisible(!systemMenu->isVisible()); + return true; + } + systemMenu->setVisible(false); + BorderedWindow::mouseDown(x,y,button); + return true; +} + +Drawable::Drawable(int w, int h, RGB clear) : + buffer(new RGB[w*h]), + width(w), height(h), + owner(true), + color(Color::Black), + font(NULL), + lineWidth(1), + tx(0), ty(0), + cx(0), cy(0), + cw(w), ch(h), + x(0), y(0) +{ + this->clear(clear); +} + +Drawable::Drawable(Drawable &src, RGB clear) : + buffer(new RGB[src.cw*src.ch]), + width(src.cw), height(src.ch), + owner(true), + color(src.color), + font(src.font), + lineWidth(src.lineWidth), + tx(0), ty(0), + cx(0), cy(0), + cw(src.cw), ch(src.ch), + x(src.x), y(src.y) +{ + if (clear != 0) { + this->clear(clear); + } else { + for (int h = 0; h < src.ch; h++) { + memcpy(buffer+src.cw*h,src.buffer+src.width*(h+src.ty)+src.tx,4*src.cw); + } + } +} + +Drawable::Drawable(Drawable &src, int x, int y, int w, int h) : + buffer(src.buffer), + width(src.width), height(src.height), + owner(false), + color(src.color), + font(src.font), + lineWidth(src.lineWidth), + tx(src.tx+x), ty(src.ty+y), + cx(imax(imax(-x,src.cx-x),0)), cy(imax(imax(-y,src.cy-y),0)), + cw(imax(0,imin(src.cw-x,w))), ch(imax(0,imin(src.ch-y,h))), + x(imax(0,imin(src.tx-tx,cw))), y(imax(0,imin(src.ty-ty,cw))) +{ +} + +Drawable::~Drawable() +{ + if (owner) delete[] buffer; +} + +void Drawable::clear(RGB clear) +{ + for (int y = cy; y < ch; y++) { + for (int x = cx; x < cw; x++) { + buffer[(y+ty)*width+x+tx] = clear; + } + } +} + +void Drawable::drawLine(int x2, int y2) +{ + int x0 = x2, x1 = x, y0 = y2, y1 = y; + int dx = x2-x1, dy = y2-y1; + drawPixel(); + + if (abs(dx) > abs(dy)) { + if (x1 > x2) { + x = x2; x2 = x1; x1 = x; + y = y2; y2 = y1; y1 = y; + } + for (x = x1; x <= x2; x++) { + y = y1+(x-x1)*dy/dx-lineWidth/2; + for (int i = 0; i < lineWidth; i++, y++) { + drawPixel(); + } + } + } else if (y1 != y2) { + if (y1 > y2) { + x = x2; x2 = x1; x1 = x; + y = y2; y2 = y1; y1 = y; + } + for (y = y1; y <= y2; y ++) { + x = x1+(y-y1)*dx/dy-lineWidth/2; + for (int i = 0; i < lineWidth; i++, x++) { + drawPixel(); + } + } + } + + drawPixel(x0,y0); +} + +void Drawable::drawCircle(int d) { + int xo = 0, yo = d/2, rest = (d+1)/2-yo, x0 = x, y0 = y, rsq = d*d/4, lwo = lineWidth/2; + + while (xo <= yo) { + while (xo*xo+(2*yo-1)*(2*yo-1)/4 > rsq) yo--; + for (int i = 0, yow = yo+lwo; i < lineWidth; i++, yow--) { + drawPixel(x0+xo,y0-yow-rest); + drawPixel(x0+yow,y0-xo-rest); + drawPixel(x0+yow,y0+xo); + drawPixel(x0+xo,y0+yow); + + drawPixel(x0-xo-rest,y0-yow-rest); + drawPixel(x0-yow-rest,y0-xo-rest); + drawPixel(x0-yow-rest,y0+xo); + drawPixel(x0-xo-rest,y0+yow); + } + + xo++; + } + gotoXY(x0,y0); +} + +void Drawable::drawRect(int w, int h) +{ + gotoXY(x-lineWidth/2,y); + drawLine(x+w+lineWidth-1,y); + gotoXY(x-(lineWidth-1)/2,y); + drawLine(x,y+h); + gotoXY(x+(lineWidth-1)/2,y); + drawLine(x-w-lineWidth+1,y); + gotoXY(x+lineWidth/2,y); + drawLine(x,y-h); +} + +void Drawable::fill() +{ + int x0 = x, xmin; + RGB color = getPixel(); + + if (color == this->color) return; + + for (x--; x >= 0 && getPixel() == color; x--) drawPixel(); + xmin = ++x; + for (x = x0; x < cw && getPixel() == color; x++) drawPixel(); + y++; + for (x--; x >= xmin; x--) { + if (getPixel() == color) fill(); + y -= 2; + if (getPixel() == color) fill(); + y += 2; + } + y--; + x = x0; +} + +void Drawable::fillCircle(int d) +{ + int xo = 0, yo = d/2, rest = (d+1)/2-yo, x0 = x, y0 = y, rsq = d*d/4; + + while (xo <= yo) { + while (xo*xo+(2*yo-1)*(2*yo-1)/4 > rsq) yo--; + x = x0+xo; + for (y = y0-yo-rest; y <= y0+yo; y++) drawPixel(); + x = x0-xo-rest; + for (y = y0-yo-rest; y <= y0+yo; y++) drawPixel(); + + y = y0-xo-rest; + for (x = x0-yo-rest; x <= x0+yo; x++) drawPixel(); + y = y0+xo; + for (x = x0-yo-rest; x <= x0+yo; x++) drawPixel(); + + xo++; + } + gotoXY(x0,y0); +} + +void Drawable::fillRect(int w, int h) +{ + int x0 = x, y0 = y, w0 = w; + for (; h > 0; h--, y++) { + for (x = x0, w = w0; w > 0; w--, x++) { + drawPixel(); + } + } + gotoXY(x0,y0); +} + +void Drawable::drawDrawable(Drawable &d, unsigned char alpha) +{ + int scw = d.cw, sch = d.ch, w, h; + RGB *src, *dest; + + for (h = imax(d.cy,-ty-y); h < sch && y+h < ch; h++) { + src = d.buffer+d.width*(h+d.ty)+d.tx; + dest = buffer+width*(y+ty+h)+tx+x; + for (w = imax(d.cx,-tx-x); w < scw && x+w < cw; w++) { + RGB srcb = src[w], destb = dest[w]; + unsigned int sop = Color::A(srcb)*((unsigned int)alpha)/255; + unsigned int rop = Color::A(destb) + sop - Color::A(destb)*sop/255; + if (rop == 0) { + dest[w] = Color::Transparent; + } else { + unsigned int dop = Color::A(destb)*(255-sop)/255; + unsigned int magval = ((destb&Color::MagentaMask)*dop+(srcb&Color::MagentaMask)*sop); + dest[w] = (((magval&0xffff)/rop)&Color::BlueMask) | + (((magval&0xffff0000)/rop)&Color::RedMask) | + ((((destb&Color::GreenMask)*dop+(srcb&Color::GreenMask)*sop)/rop)&Color::GreenMask) | + (rop<toSpecial(c)) { + case Font::CR: gotoXY(0,y); return; + case Font::LF: gotoXY(0,y+font->getHeight()); return; + case Font::BS: gotoXY(imax(0,x-font->getWidth()),y); return; + case Font::Tab: gotoXY((((int)(x/font->getWidth()/8))+1)*8*font->getWidth(),y); return; + default: break; + } + if (font->getWidth(c)+x > cw) gotoXY(0,y+font->getHeight()); + } + font->drawChar(this,c); +} + +#define move(x) (ptr += ((x)+bit)/8-(((x)+bit)<0), bit = ((x)+bit+(((x)+bit)<0?8:0))%8) +void BitmapFont::drawChar(Drawable *d, const Char c) const { + const unsigned char *ptr = bitmap; + int bit = 0; + + if (c > last) return; + + if (char_position != NULL) { + ptr = char_position[c]; + bit = 0; + } else { + move(character_step*((int)c)); + } + + int rs = row_step; + int w = (widths != NULL?widths[c]:width); + int h = (ascents != NULL?ascents[c]:height); + Drawable out(*d,d->getX(),d->getY()-ascent,w,h); + + if (rs == 0) rs = isign(col_step)*w; + if (rs < 0) move(-rs*(h-1)); + if (col_step < 0) move(abs(rs)-1); + + for (int row = height-h; row < height; row++, move(rs-w*col_step)) { + for (int col = 0; col < w; col++, move(col_step)) { + if (!background_set ^ !(*ptr&(1<gotoXY(d->getX()+w,d->getY()); +} +#undef move + +std::map Font::registry; + +void Timer::check(unsigned int ticks) +{ + if (timers.empty()) return; + + if (Timer::ticks > (Timer::ticks+ticks)) { + ticks -= -1-Timer::ticks; + check(-1-Timer::ticks); + } + + std::multimap::iterator old, i = timers.lower_bound(Timer::ticks+1); + Timer::ticks += ticks; + + while (i != timers.end() && (*i).first <= Timer::ticks) { + Timer_Callback *c = (*i).second; + unsigned int time = (*i).first; + old = i; + ++i; + timers.erase(old); + unsigned int next = c->timerExpired(time); + if (next) add(c, time+next-Timer::ticks); + } +} + +void Timer::remove(const Timer_Callback *const timer) +{ + if (timers.empty()) return; + + std::multimap::iterator old, i = timers.begin(); + + while (i != timers.end()) { + old = i; + ++i; + if ((*old).second == timer) timers.erase(old); + } +} + +unsigned int Timer::next() +{ + if (timers.empty()) return 0; + + std::multimap::iterator i = timers.upper_bound(ticks); + + if (i == timers.end()) return 0; + return (*i).first-Timer::ticks; +} + +std::multimap Timer::timers; +unsigned int Timer::ticks = 0; + +BitmapFont::BitmapFont(const unsigned char *data, int height, int ascent, bool owner, + int width, bool background_set, + int col_step, int row_step, int character_step, Char last, + const int *widths, const int *ascents, const unsigned char *const* char_position, + const Font::SpecialChar *special) : + bitmap(data), + width(width), height(height), ascent(ascent), widths(widths), ascents(ascents), + background_set(background_set), col_step(col_step), row_step(row_step), + character_step(character_step?character_step:abs((row_step?row_step:width*col_step)*height)), + char_position(char_position), special(special), owner(owner), last(last) +{ +} + +BitmapFont::~BitmapFont() { + if (owner) { + if (bitmap != NULL) delete bitmap; + if (ascents != NULL) delete ascents; + if (widths != NULL) delete widths; + if (special != NULL) delete special; + } +} + +Window::Window(Window *parent, int x, int y, int w, int h) : + width(w), height(h), + x(x), y(y), + dirty(true), + visible(true), + parent(parent), + mouseChild(NULL) +{ + parent->addChild(this); +} + +Window::Window() : + width(0), height(0), + x(0), y(0), + dirty(false), + visible(true), + parent(NULL), + mouseChild(NULL) +{ +} + + +Window::~Window() +{ + while (!children.empty()) delete children.front(); + if (parent) parent->removeChild(this); + if (parent && parent->mouseChild == this) parent->mouseChild = NULL; +} + +void Window::addChild(Window *child) +{ + children.push_back(child); + setDirty(); +} + +void Window::removeChild(Window *child) +{ + children.remove(child); + setDirty(); +} + +void Window::move(int x, int y) +{ + this->x = x; + this->y = y; + std::list::iterator i = movehandlers.begin(); + bool end = (i == movehandlers.end()); + while (!end) { + Window_Callback *c = *i; + ++i; + end = (i == movehandlers.end()); + c->windowMoved(this,x,y); + } + parent->setDirty(); +} + +void Window::resize(int w, int h) +{ + this->width = w; + this->height = h; + setDirty(); +} + +void Window::paintAll(Drawable &d) const +{ + paint(d); + std::list::const_iterator i = children.begin(); + while (i != children.end()) { + Window *child = *i; + ++i; + if (child->visible) { + Drawable *cd = new Drawable(d,child->x,child->y,child->width,child->height); + child->paintAll(*cd); + delete cd; + } + } +} + +bool Window::keyDown(const Key &key) +{ + if (children.empty()) return false; + if ((*children.rbegin())->keyDown(key)) return true; + if (key.ctrl || key.alt || key.windows || key.special != Key::Tab) return false; + + if (key.shift) { + std::list::reverse_iterator i = children.rbegin(), e = children.rend(); + ++i; + while (i != e && !(*i)->raise()) ++i; + return i != e; + } else { + std::list::iterator i = children.begin(), e = children.end(); + while (i != e && !(*i)->raise()) ++i; + return (i != e); + } +} + +bool Window::keyUp(const Key &key) +{ + if (children.empty()) return false; + return (*children.rbegin())->keyUp(key); +} + +bool Window::mouseMoved(int x, int y) +{ + std::list::reverse_iterator i = children.rbegin(); + bool end = (i == children.rend()); + while (!end) { + Window *w = *i; + i++; + end = (i == children.rend()); + if (w->visible && x >= w->x && x <= w->x+w->width + && y >= w->y && y <= w->y+w->height + && w->mouseMoved(x-w->x, y-w->y)) return true; + } + return false; +} + +bool Window::mouseDragged(int x, int y, MouseButton button) +{ + if (mouseChild == NULL) return false; + return mouseChild->mouseDragged(x-mouseChild->x, y-mouseChild->y, button); +} + +bool Window::mouseDown(int x, int y, MouseButton button) +{ + Window *last = NULL; + std::list::reverse_iterator i = children.rbegin(); + bool end = (i == children.rend()); + while (!end) { + Window *w = *i; + i++; + end = (i == children.rend()); + if (w->visible && x >= w->x && x <= w->x+w->width + && y >= w->y && y <= w->y+w->height + && (mouseChild = last = w) + && w->mouseDown(x-w->x, y-w->y, button) + && w->raise()) { + return true; + } + } + mouseChild = NULL; + if (last != NULL) last->raise(); + return false; +} + +bool Window::mouseUp(int x, int y, MouseButton button) +{ + if (mouseChild == NULL) return false; + return mouseChild->mouseUp(x-mouseChild->x, y-mouseChild->y, button); +} + +bool Window::mouseClicked(int x, int y, MouseButton button) +{ + if (mouseChild == NULL) return false; + return mouseChild->mouseClicked(x-mouseChild->x, y-mouseChild->y, button); +} + +bool Window::mouseDoubleClicked(int x, int y, MouseButton button) +{ + if (mouseChild == NULL) return false; + return mouseChild->mouseDoubleClicked(x-mouseChild->x, y-mouseChild->y, button); +} + +bool BorderedWindow::mouseDown(int x, int y, MouseButton button) +{ + mouseChild = NULL; + if (x > width-border_right || y > width-border_bottom) return false; + x -= border_left; y -= border_top; + if (x < 0 || y < 0) return false; + return Window::mouseDown(x,y,button); +} + +bool BorderedWindow::mouseMoved(int x, int y) +{ + if (x > width-border_right || y > width-border_bottom) return false; + x -= border_left; y -= border_top; + if (x < 0 || y < 0) return false; + return Window::mouseMoved(x,y); +} + +bool BorderedWindow::mouseDragged(int x, int y, MouseButton button) +{ + if (x > width-border_right || y > width-border_bottom) return false; + x -= border_left; y -= border_top; + if (x < 0 || y < 0) return false; + return Window::mouseDragged(x,y,button); +} + +void ToplevelWindow::paint(Drawable &d) const +{ + int mask = (systemMenu->isVisible()?Color::RedMask|Color::GreenMask|Color::BlueMask:0); + d.clear(Color::Background); + + d.setColor(Color::Border); + d.drawLine(0,height-1,width-1,height-1); + d.drawLine(width-1,0,width-1,height-1); + + d.setColor(Color::Shadow3D); + d.drawLine(0,0,width-2,0); + d.drawLine(0,0,0,height-2); + d.drawLine(0,height-2,width-2,height-2); + d.drawLine(width-2,0,width-2,height-2); + + d.drawLine(5,4,width-7,4); + d.drawLine(5,4,5,30); + + d.setColor(Color::Light3D); + d.drawLine(1,1,width-3,1); + d.drawLine(1,1,1,height-3); + + d.drawLine(5,31,width-6,31); + d.drawLine(width-6,5,width-6,31); + + d.setColor(Color::Background3D^mask); + d.fillRect(6,5,26,26); + d.setColor(Color::Grey50^mask); + d.fillRect(9,17,20,4); + d.setColor(Color::Black^mask); + d.fillRect(8,16,20,4); + d.setColor(Color::White^mask); + d.fillRect(9,17,18,2); + + d.setColor(Color::Border); + d.drawLine(32,5,32,30); + + d.setColor(Color::Titlebar); + d.fillRect(33,5,width-39,26); + + const Font *font = Font::getFont("title"); + d.setColor(Color::TitlebarText); + d.setFont(font); + d.drawText(31+(width-39-font->getWidth(title))/2,5+(26-font->getHeight())/2+font->getAscent(),title,false,0); +} + +void Input::paint(Drawable &d) const +{ + d.clear(Color::EditableBackground); + + d.setColor(Color::Shadow3D); + d.drawLine(0,0,width-2,0); + d.drawLine(0,0,0,height-2); + + d.setColor(Color::Background3D); + d.drawLine(1,height-2,width-2,height-2); + d.drawLine(width-2,1,width-2,height-2); + + d.setColor(Color::Text); + d.drawLine(1,1,width-3,1); + d.drawLine(1,1,1,height-3); + + const Font *f = Font::getFont("input"); + d.setFont(f); + + Drawable d1(d,3,4,width-6,height-8); + Drawable dr(d1,(multi?0:-offset),(multi?-offset:0),width-6+(multi?0:offset),height-8+(multi?offset:0)); + + const Size start = imin(start_sel, end_sel), end = imax(start_sel, end_sel); + dr.drawText(0,f->getAscent()+1,text,multi,0,start); + + int sx = dr.getX(), sy = dr.getY(); + dr.drawText(text, multi, start, end-start); + int ex = dr.getX(), ey = dr.getY(); + + if (sx != ex || sy != ey) { + dr.setColor(Color::SelectionBackground); + if (sy == ey) dr.fillRect(sx,sy-f->getAscent(),ex-sx,f->getHeight()+1); + else { + dr.fillRect(sx, sy-f->getAscent(), width-sx+offset, f->getHeight() ); + dr.fillRect(0, sy-f->getAscent()+f->getHeight(), width+offset, ey-sy-f->getHeight()); + dr.fillRect(0, ey-f->getAscent(), ex, f->getHeight() ); + } + dr.setColor(Color::SelectionForeground); + dr.drawText(sx, sy, text, multi, start, end-start); + } + + dr.setColor(Color::Text); + + dr.drawText(text, multi, end); + + if (blink && hasFocus()) { + if (insert) dr.drawLine(posx,posy,posx,posy+f->getHeight()+1); + else dr.fillRect(posx,posy,f->getWidth(text[pos]),f->getHeight()+1); + } +} + +Size Input::findPos(int x, int y) { + const Font *f = Font::getFont("input"); + if (multi) y += offset; + else x += offset; + y = (y-4) / f->getHeight(); + int line = 0; + Size pos = 0; + while (line < y && pos < text.size()) if (f->toSpecial(text[pos++]) == Font::LF) line++; + Drawable d(width-6,1); + d.setFont(f); + while (pos <= text.size() && d.getY() == 0 && x > d.getX()) { + d.drawText(String(text), multi, pos, 1); + pos++; + } + if (pos > 0) pos--; + return pos; +} + +bool Input::mouseDown(int x, int y, MouseButton button) +{ + if (button == Left || (button == Middle && start_sel == end_sel)) { + end_sel = start_sel = pos = findPos(x,y); + blink = true; + checkOffset(); + } + if (button == Middle) keyDown(Key(0,Key::Insert,true,false,false,false)); + return true; +} + +bool Input::mouseDragged(int x, int y, MouseButton button) +{ + if (button == Left) { + end_sel = pos = findPos(x,y); + blink = true; + checkOffset(); + } + return true; +} + +bool Input::keyDown(const Key &key) +{ + const Font *f = Font::getFont("input"); + switch (key.special) { + case Key::None: + if (key.ctrl) { + switch (key.character) { + case 1: + case 'a': + case 'A': + if (key.shift) { + start_sel = end_sel = pos; + } else { + start_sel = 0; + pos = end_sel = (Size)text.size(); + } + break; + case 24: + case 'x': + case 'X': + cutSelection(); + break; + case 3: + case 'c': + case 'C': + copySelection(); + break; + case 22: + case 'v': + case 'V': + pasteSelection(); + break; + default: printf("Ctrl-0x%x\n",key.character); break; + } + break; + } + if (start_sel != end_sel) clearSelection(); + if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,key.character); + else text[pos++] = key.character; + break; + case Key::Left: + if (pos > 0) pos--; + break; + case Key::Right: + if (pos < text.size()) pos++; + break; + case Key::Down: + if (multi) pos = findPos(posx+3, posy-offset+f->getHeight()+4); + break; + case Key::Up: + if (multi) pos = findPos(posx+3, posy-offset-f->getHeight()+4); + break; + case Key::Home: + if (multi) { + while (pos > 0 && f->toSpecial(text[pos-1]) != Font::LF) pos--; + } else pos = 0; + break; + case Key::End: + if (multi) { + while (pos < text.size() && f->toSpecial(text[pos]) != Font::LF) pos++; + } else pos = (Size)text.size(); + break; + case Key::Backspace: + if (!key.shift && start_sel != end_sel) clearSelection(); + else if (pos > 0) text.erase(text.begin()+ --pos); + break; + case Key::Delete: + if (key.shift) cutSelection(); + else if (start_sel != end_sel) clearSelection(); + else if (pos < text.size()) text.erase(text.begin()+pos); + break; + case Key::Insert: + if (key.ctrl) copySelection(); + else if (key.shift) pasteSelection(); + else insert = !insert; + break; + case Key::Enter: + if (multi) { + if (start_sel != end_sel) clearSelection(); + if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,f->fromSpecial(Font::LF)); + else text[pos++] = f->fromSpecial(Font::LF); + } else executeAction(text); + break; + case Key::Tab: + if (multi) { + if (start_sel != end_sel) clearSelection(); + if (insert || pos >= text.size() ) text.insert(text.begin()+pos++,f->fromSpecial(Font::Tab)); + else text[pos++] = f->fromSpecial(Font::Tab); + } else return false; + break; + default: + return false; + } + if (!key.ctrl) { + if (!key.shift || key.special == Key::None) start_sel = end_sel = pos; + else end_sel = pos; + } + checkOffset(); + blink = true; + return true; +} + +void BorderedWindow::paintAll(Drawable &d) const +{ + this->paint(d); + Drawable dchild(d,border_left,border_top,width-border_left-border_right,height-border_top-border_bottom); + for (std::list::const_iterator i = children.begin(); i != children.end(); ++i) { + Window *child = *i; + if (child->isVisible()) { + Drawable cd(dchild,child->getX(),child->getY(),child->getWidth(),child->getHeight()); + child->paintAll(cd); + } + } +} + +void Button::paint(Drawable &d) const +{ + int offset = -1; + + if (hasFocus()) { + offset = 0; + d.setColor(Color::Border); + d.drawLine(0,0,width,0); + d.drawLine(0,0,0,height); + + d.drawLine(0,height-1,width,height-1); + d.drawLine(width-1,0,width-1,height); + } + + d.setColor(Color::Background3D); + d.fillRect(2,2,width-4,height-4); + + if (pressed) { + d.setColor(Color::Shadow3D); + + d.drawLine(1+offset,1+offset,width-2-offset,1+offset); + d.drawLine(1+offset,1+offset,1+offset,height-2-offset); + } else { + d.setColor(Color::Background3D); + + d.drawLine(1+offset,1+offset,width-3-offset,1+offset); + d.drawLine(1+offset,1+offset,1+offset,height-3-offset); + + d.setColor(Color::Light3D); + + d.drawLine(2+offset,2+offset,width-4-offset,2+offset); + d.drawLine(2+offset,2+offset,2+offset,height-4-offset); + + d.setColor(Color::Shadow3D); + + d.drawLine(2+offset,height-3-offset,width-2-offset,height-3-offset); + d.drawLine(width-3-offset,2+offset,width-3-offset,height-2-offset); + + d.setColor(Color::Border); + + d.drawLine(width-2-offset,1+offset,width-2-offset,height-2-offset); + d.drawLine(1+offset,height-2-offset,width-2-offset,height-2-offset); + } +} + +bool Checkbox::keyDown(const Key &key) +{ + switch (key.special) { + case Key::None: + if (key.character != ' ') return false; + case Key::Enter: + break; + default: return false; + } + mouseDown(0,0,Left); + return true; +} + +bool Checkbox::keyUp(const Key &key) +{ + if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false; + mouseUp(0,0,Left); + mouseClicked(0,0,Left); + return true; +} + +void Checkbox::paint(Drawable &d) const +{ + d.setColor(Color::Background3D); + d.fillRect(2,(height/2)-7,14,14); + + d.setColor(Color::Shadow3D); + d.drawLine(2,(height/2)-7,13,(height/2)-7); + d.drawLine(2,(height/2)-7,2,(height/2)+5); + + d.setColor(Color::Light3D); + d.drawLine(2,(height/2)+5,14,(height/2)+5); + d.drawLine(14,(height/2)-7,14,(height/2)+5); + + d.setColor(Color::EditableBackground); + d.fillRect(4,(height/2)-5,9,9); + + d.setColor(Color::Border); + d.drawLine(3,(height/2)-6,12,(height/2)-6); + d.drawLine(3,(height/2)-6,3,(height/2)+4); + + if (checked) { + d.setColor(Color::Text); + d.drawLine(5,(height/2)-2,7,(height/2) ); + d.drawLine(11,(height/2)-4); + d.drawLine(5,(height/2)-1,7,(height/2)+1); + d.drawLine(11,(height/2)-3); + d.drawLine(5,(height/2) ,7,(height/2)+2); + d.drawLine(11,(height/2)-2); + } +} + +Radiobox::Radiobox(Frame *parent, int x, int y, int w, int h) : BorderedWindow(static_cast(parent),x,y,w,h,16,0,0,0), ActionEventSource("GUI::Radiobox"), checked(0) +{ + addActionHandler(parent); +} + +bool Radiobox::keyDown(const Key &key) +{ + switch (key.special) { + case Key::None: + if (key.character != ' ') return false; + case Key::Enter: + break; + default: return false; + } + mouseDown(0,0,Left); + return true; +} + +bool Radiobox::keyUp(const Key &key) +{ + if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false; + mouseUp(0,0,Left); + mouseClicked(0,0,Left); + return true; +} + +void Radiobox::paint(Drawable &d) const +{ + d.setColor(Color::Light3D); + d.drawLine(6,(height/2)+6,9,(height/2)+6); + d.drawLine(4,(height/2)+5,11,(height/2)+5); + d.drawLine(13,(height/2)-1,13,(height/2)+2); + d.drawLine(12,(height/2)-2,12,(height/2)+4); + + d.setColor(Color::Background3D); + d.drawLine(6,(height/2)+5,9,(height/2)+5); + d.drawLine(4,(height/2)+4,11,(height/2)+4); + d.drawLine(12,(height/2)-1,12,(height/2)+2); + d.drawLine(11,(height/2)-2,11,(height/2)+4); + + d.setColor(Color::Shadow3D); + d.drawLine(6,(height/2)-5,9,(height/2)-5); + d.drawLine(4,(height/2)-4,11,(height/2)-4); + d.drawLine(2,(height/2)-1,2,(height/2)+2); + d.drawLine(3,(height/2)-3,3,(height/2)+4); + + d.setColor(Color::Border); + d.drawLine(6,(height/2)-4,9,(height/2)-4); + d.drawLine(4,(height/2)-3,11,(height/2)-3); + d.drawLine(3,(height/2)-1,3,(height/2)+2); + d.drawLine(4,(height/2)-3,4,(height/2)+3); + + d.setColor(Color::EditableBackground); + d.fillRect(5,(height/2)-2,6,6); + d.fillRect(4,(height/2)-1,8,4); + d.fillRect(6,(height/2)-3,4,8); + + if (checked) { + d.setColor(Color::Text); + d.fillRect(6,(height/2),4,2); + d.fillRect(7,(height/2)-1,2,4); + } +} + +void Menu::paint(Drawable &d) const +{ + d.clear(Color::Background3D); + + d.setColor(Color::Border); + d.drawLine(0,height-1,width-1,height-1); + d.drawLine(width-1,0,width-1,height-1); + + d.setColor(Color::Shadow3D); + d.drawLine(0,0,width-2,0); + d.drawLine(0,0,0,height-2); + d.drawLine(0,height-2,width-2,height-2); + d.drawLine(width-2,0,width-2,height-2); + + d.setColor(Color::Light3D); + d.drawLine(1,1,width-3,1); + d.drawLine(1,1,1,height-3); + + d.setFont(Font::getFont("menu")); + const int asc = Font::getFont("menu")->getAscent()+1; + const int height = Font::getFont("menu")->getHeight()+2; + int y = asc+3; + int index = 0; + for (std::vector::const_iterator i = items.begin(); i != items.end(); ++i) { + if ((*i).empty()) { + d.setColor(Color::Shadow3D); + d.drawLine(4,y-asc+6,width-5,y-asc+6); + d.setColor(Color::Light3D); + d.drawLine(4,y-asc+7,width-5,y-asc+7); + y += 12; + } else { + if (index == selected && hasFocus()) { + d.setColor(Color::SelectionBackground); + d.fillRect(3,y-asc,width-6,height); + d.setColor(Color::SelectionForeground); + } else { + d.setColor(Color::Text); + } + d.drawText(20,y,(*i),false,0); + y += height; + } + index++; + } +} + +void Menubar::paint(Drawable &d) const +{ + const Font *f = Font::getFont("menu"); + + d.setColor(Color::Light3D); + d.drawLine(0,height-1,width-1,height-1); + d.setColor(Color::Shadow3D); + d.drawLine(0,height-2,width-1,height-2); + + d.gotoXY(7,f->getAscent()+2); + + int index = 0; + for (std::vector::const_iterator i = menus.begin(); i != menus.end(); ++i, ++index) { + if (index == selected && (*i)->isVisible()) { + int w = f->getWidth((*i)->getName()); + d.setColor(Color::SelectionBackground); + d.fillRect(d.getX()-7,0,w+14,height-2); + d.setColor(Color::SelectionForeground); + d.gotoXY(d.getX()+7,f->getAscent()+2); + } else { + d.setColor(Color::Text); + } + d.drawText((*i)->getName(),false); + d.gotoXY(d.getX()+14,f->getAscent()+2); + } +} + +bool Button::keyDown(const Key &key) +{ + switch (key.special) { + case Key::None: + if (key.character != ' ') return false; + case Key::Enter: + break; + default: return false; + } + mouseDown(0,0,Left); + return true; +} + +bool Button::keyUp(const Key &key) +{ + if (key.ctrl || key.alt || key.windows || (key.character != ' ' && key.special != Key::Enter)) return false; + mouseUp(0,0,Left); + mouseClicked(0,0,Left); + return true; +} + +void Frame::paint(Drawable &d) const { + const Font *f = Font::getFont("default"); + const int top = (label.empty()?1:f->getAscent()/2+1); + + d.setColor(Color::Shadow3D); + d.drawLine(1,height-2,1,top); + d.drawLine(8,top); + d.drawLine((label.empty()?8:f->getWidth(label)+14),top,width-2,top); + d.drawLine(2,height-3,width-3,height-3); + d.drawLine(width-3,top+1); + + d.setColor(Color::Light3D); + d.drawLine(2,height-3,2,top+1); + d.drawLine(8,top+1); + d.drawLine((label.empty()?8:f->getWidth(label)+14),top+1,width-3,top+1); + d.drawLine(2,height-2,width-2,height-2); + d.drawLine(width-2,top+1); + + d.setColor(Color::Text); + d.drawText(11,f->getAscent()+1,label,false,0); +} + +Screen *Window::getScreen() { return (parent == NULL?dynamic_cast(this):parent->getScreen()); } + +Screen::Screen(unsigned int width, unsigned int height) : + Window(), + buffer(new Drawable(width, height)) +{ + this->width = width; + this->height = height; +} + +Screen::Screen(Drawable *d) : + Window(), + buffer(d) +{ + this->width = d->getClipWidth(); + this->height = d->getClipHeight(); +} + +Screen::~Screen() +{ +} + +void Screen::paint(Drawable &d) const +{ + d.clear(Color::Transparent); +} + +unsigned int Screen::update(void *surface, unsigned int ticks) +{ + Timer::check(ticks); + + paintAll(*buffer); + RGB *buf = buffer->buffer; + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++, buf++) { + RGB sval = surfaceToRGB(surface); + RGB bval = *buf; + int a = Color::A(bval); + bval = ((((sval&Color::MagentaMask)*a+(bval&Color::MagentaMask)*(256-a))>>8)&Color::MagentaMask) + | ((((sval&Color::GreenMask)*a+(bval&Color::GreenMask)*(256-a))>>8)&Color::GreenMask); + rgbToSurface(bval, &surface); + } + } + + return Timer::next(); +} + +void Screen::move(int x, int y) +{ +} + +void Screen::resize(int w, int h) +{ +} + +#ifdef TESTING +static void test(Drawable &d) { + const int width = d.getClipWidth(); + const int height = d.getClipHeight(); + + d.clear(Color::rgba(0,0,255,128)); + + d.setColor(Color::Black); + for (int x = 0; x < width; x += 10) d.drawLine(x,0,x,height); + for (int y = 0; y < height; y += 10) d.drawLine(0,y,width,y); + + d.setColor(Color::Red); + for (int x = 10; x <= 130 ; x += 10) { + d.drawLine(x,10,70,70); + d.drawLine(x,130); + } + for (int y = 10; y <= 130 ; y += 10) { + d.drawLine(10,y,70,70); + d.drawLine(130,y); + } + + d.setColor(Color::Yellow); + d.fillRect(150,10,30,30); + d.setColor(Color::Blue); + d.drawRect(30,30); + + d.drawRect(150,60,30,30); + d.setColor(Color::Yellow); + d.fillRect(30,30); + + for (int x = 0; x <= 100 ; x += 10) { + d.setColor(Color::rgba(0xff,0x00,0xff,(255*x/100)&255)); + d.fillRect(200+2*x,0,20,20); + } + + d.setColor(Color::Yellow); + d.fillCircle(210,60,40); + d.setColor(Color::Blue); + d.drawCircle(40); + + d.drawCircle(210,110,40); + d.setColor(Color::Yellow); + d.fillCircle(40); + + d.setColor(Color::rgba(0,0,255,128)); + d.fillRect(251,41,9,59); + d.fillRect(251,41,59,9); + d.fillRect(301,41,9,59); + d.fillRect(291,91,19,9); + d.fillRect(291,51,9,49); + d.fillRect(261,51,39,9); + d.fillRect(261,51,9,49); + d.fillRect(261,91,29,9); + d.fillRect(281,61,9,39); + d.fillRect(271,61,19,9); + d.fillRect(271,61,9,29); + d.fillRect(241,41,9,59); + d.fillRect(241,41,19,9); + d.fillRect(241,91,19,9); + d.setColor(Color::rgba(255,0,0,128)); + d.fill(255,64); + + d.setColor(Color::Green); + Drawable(d,500,355,30,30).fillCircle(65); + + for (int i = 0; i <= 100; i += 10) { + Drawable(d,25,155+i*3,420,30).drawDrawable(0,0,d,255*i/100); + } + + d.setColor(Color::White); + d.setFont(Font::getFont("VGA14")); + d.drawText(270,110,"GUI:: Test Program\n"); + d.drawText("Still testing\tTable\n"); + d.drawText("More of...\tTable\n"); + d.drawText("Overwrite\rXXXXXXXXX\n"); + d.drawText("Fake int'l chars: O\b/e\b\"\n"); + d.drawText("Real ones: \211\222\234\345\246\321"); +} +#else +static void test(Drawable &d) { (void)d; } +#endif + + +void ScreenRGB32le::paint(Drawable &d) const +{ + parent->paint(d); + test(d); +} + +static MouseButton SDL_to_GUI(const int button) +{ + switch (button) { + case SDL_BUTTON_LEFT: return GUI::Left; + case SDL_BUTTON_RIGHT: return GUI::Right; + case SDL_BUTTON_MIDDLE: return GUI::Middle; + case SDL_BUTTON_WHEELUP: return GUI::WheelUp; + case SDL_BUTTON_WHEELDOWN: return GUI::WheelDown; + default: return GUI::NoButton; + } +} + +static const Key SDL_to_GUI(const SDL_keysym &key) +{ + GUI::Key::Special ksym = GUI::Key::None; + switch (key.sym) { + case SDLK_ESCAPE: ksym = GUI::Key::Escape; break; + case SDLK_BACKSPACE: ksym = GUI::Key::Backspace; break; + case SDLK_TAB: ksym = GUI::Key::Tab; break; + case SDLK_LEFT: ksym = GUI::Key::Left; break; + case SDLK_RIGHT: ksym = GUI::Key::Right; break; + case SDLK_UP: ksym = GUI::Key::Up; break; + case SDLK_DOWN: ksym = GUI::Key::Down; break; + case SDLK_HOME: ksym = GUI::Key::Home; break; + case SDLK_END: ksym = GUI::Key::End; break; + case SDLK_DELETE: ksym = GUI::Key::Delete; break; + case SDLK_INSERT: ksym = GUI::Key::Insert; break; + case SDLK_RETURN: ksym = GUI::Key::Enter; break; + case SDLK_MENU: ksym = GUI::Key::Menu; break; + case SDLK_PAGEUP: ksym = GUI::Key::PageUp; break; + case SDLK_PAGEDOWN: ksym = GUI::Key::PageDown; break; + case SDLK_PRINT: ksym = GUI::Key::Print; break; + case SDLK_PAUSE: ksym = GUI::Key::Pause; break; + case SDLK_BREAK: ksym = GUI::Key::Break; break; + case SDLK_CAPSLOCK: ksym = GUI::Key::CapsLock; break; + case SDLK_NUMLOCK: ksym = GUI::Key::NumLock; break; + case SDLK_SCROLLOCK: ksym = GUI::Key::ScrollLock; break; + case SDLK_F1:case SDLK_F2:case SDLK_F3:case SDLK_F4:case SDLK_F5:case SDLK_F6: + case SDLK_F7:case SDLK_F8:case SDLK_F9:case SDLK_F10:case SDLK_F11:case SDLK_F12: + ksym = (GUI::Key::Special)(GUI::Key::F1 + key.sym-SDLK_F1); + default: break; + } + return Key(key.unicode, ksym, + (key.mod&KMOD_SHIFT)>0, + (key.mod&KMOD_CTRL)>0, + (key.mod&KMOD_ALT)>0, + (key.mod&KMOD_META)>0); +} + +/** \brief Internal class that handles different screen bit depths and layouts the SDL way */ +class SDL_Drawable : public Drawable { +protected: + SDL_Surface *const surface; + +public: + SDL_Drawable(int width, int height, RGB clear = Color::Transparent) : Drawable(width, height, clear), surface(SDL_CreateRGBSurfaceFrom(buffer, width, height, 32, width*4, Color::RedMask, Color::GreenMask, Color::BlueMask, Color::AlphaMask)) { + surface->flags |= SDL_SRCALPHA; + } + + ~SDL_Drawable() { + SDL_FreeSurface(surface); + } + + void update(SDL_Surface *dest) const { + SDL_BlitSurface(surface, NULL, dest, NULL); + } +}; + +ScreenSDL::ScreenSDL(SDL_Surface *surface) : Screen(new SDL_Drawable(surface->w, surface->h)), surface(surface), downx(0), downy(0), lastclick(0) {} + +Ticks ScreenSDL::update(Ticks ticks) +{ + Timer::check(ticks); + + paintAll(*buffer); + static_cast(buffer)->update(surface); + + return Timer::next(); +} + +void ScreenSDL::paint(Drawable &d) const { + d.clear(Color::Transparent); + test(d); +} + +bool ScreenSDL::event(const SDL_Event &event) { + bool rc; + + switch (event.type) { + case SDL_KEYUP: { + const Key &key = SDL_to_GUI(event.key.keysym); + if (key.special == GUI::Key::None && key.character == 0) break; + if (key.special == GUI::Key::CapsLock || key.special == GUI::Key::NumLock) keyDown(key); + return keyUp(key); + } + case SDL_KEYDOWN: { + const Key &key = SDL_to_GUI(event.key.keysym); + if (key.special == GUI::Key::None && key.character == 0) break; + rc = keyDown(key); + if (key.special == GUI::Key::CapsLock || key.special == GUI::Key::NumLock) keyUp(key); + return rc; + } + case SDL_MOUSEMOTION: + if (event.motion.state) { + if (abs(event.motion.x-downx) <= 10 && abs(event.motion.y-downy) <= 10) + break; + downx = -11; downy = -11; + if (event.motion.state&SDL_BUTTON(1)) + return mouseDragged(event.motion.x, event.motion.y, GUI::Left); + else if (event.motion.state&SDL_BUTTON(2)) + return mouseDragged(event.motion.x, event.motion.y, GUI::Middle); + else if (event.motion.state&SDL_BUTTON(3)) + return mouseDragged(event.motion.x, event.motion.y, GUI::Right); + break; + } + + return mouseMoved(event.motion.x, event.motion.y); + + case SDL_MOUSEBUTTONDOWN: + rc = mouseDown(event.button.x, event.button.y, SDL_to_GUI(event.button.button)); + if (abs(event.button.x-downx) > 10 || abs(event.button.y-downy) > 10) lastclick = 0; + downx = event.button.x; downy = event.button.y; + return rc; + + case SDL_MOUSEBUTTONUP: + rc = mouseUp(event.button.x, event.button.y, SDL_to_GUI(event.button.button)); + if (abs(event.button.x-downx) < 10 && abs(event.button.y-downy) < 10) { + if (lastclick == 0 || (GUI::Timer::now()-lastclick) > 20) { + lastclick = GUI::Timer::now(); + rc |= mouseClicked(downx, downy, SDL_to_GUI(event.button.button)); + } else if (lastclick != 0) { + rc |= mouseDoubleClicked(downx, downy, SDL_to_GUI(event.button.button)); + lastclick = 0; + } else { + lastclick = 0; + } + } else { + lastclick = 0; + } + return rc; + } + + return false; +} + +} + + + +#ifdef TESTING +#include + +/** \brief A test program that serves as an example for all GUI elements. + * + * Note that you need SDL installed and a file "testfont.h" for this + * to compile, which must contain a bitmap font declared as + * + * \code + * static const unsigned char testfont[256 * 14] = { ... }; + * \endcode + * + * (256 chars, 8x14 fixed-width font, for example the IBM PC VGA 14-line font, + * you can get it from DOSBox) + * + * To compile it, use a command line like this: + * + * \code + * g++ -DTESTING `sdl-config --cflags` `sdl-config --libs` gui_tk.cpp -o testgui_tk + * \endcode + * + */ + +int main(int argc, char *argv[]) +{ + printf("GUI:: test program\n"); + + SDL_Surface *screen; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError()); + exit(1); + } + + atexit(SDL_Quit); + + screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE); + if (screen == NULL) { + fprintf(stderr, "Couldn't set 640x480x32 video mode: %s\n", SDL_GetError()); + exit(1); + } + printf("GUI:: color depth %i\n",screen->format->BitsPerPixel); + + SDL_EnableUNICODE(true); + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL); + + #include "testfont.h" + GUI::Font::addFont("default",new GUI::BitmapFont(testfont,14,10)); + + GUI::ScreenSDL guiscreen(screen); + GUI::ToplevelWindow *frame = new GUI::ToplevelWindow(&guiscreen,205,100,380,250,"GUI::Frame"); + static struct delwin : public GUI::ActionEventSource_Callback { + void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { + dynamic_cast(dynamic_cast(b)->getParent())->close(); + } + } dw; + struct newwin : public GUI::ActionEventSource_Callback { + GUI::Screen *screen; + int n; + void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { + char title[256]; + sprintf(title,"Window %i",++n); + GUI::ToplevelWindow *w = new GUI::ToplevelWindow(screen,405,100,120,150,title); + GUI::Button *close = new GUI::Button(w,5,5,"Close"); + close->addActionHandler(&dw); + } + } nw; + nw.screen = &guiscreen; + nw.n = 0; + struct quit : public GUI::ActionEventSource_Callback { + GUI::ToplevelWindow *frame; + void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { + if (arg == "Quit" && b->getName() != "GUI::Input") exit(0); + frame->setTitle(arg); + } + } ex; + ex.frame = frame; + + GUI::Button *b = new GUI::Button(frame,8,20,"Open a new Window"); + b->addActionHandler(&nw); + (new GUI::Button(frame,200,20,"1"))->addActionHandler(&ex); + (new GUI::Button(frame,235,20,"2"))->addActionHandler(&ex); + b = new GUI::Button(frame,270,20,"Quit"); + b->addActionHandler(&ex); + (new GUI::Input(frame,16,55,150))->addActionHandler(&ex); + + printf("Title: %s\n",(const char*)frame->getTitle()); + + struct movewin : public GUI::Timer_Callback, public GUI::ToplevelWindow_Callback { + public: + GUI::ToplevelWindow *frame; + GUI::Checkbox *cb1, *cb2; + int x, y; + virtual unsigned int timerExpired(unsigned int t) { + if (cb2->isChecked()) frame->move(frame->getX()+x,frame->getY()+y); + if (frame->getX() <= -frame->getWidth()) x = 1; + if (frame->getX() >= 640) x = -1; + if (frame->getY() <= -frame->getHeight()) y = 1; + if (frame->getY() >= 480) y = -1; + return 10; + } + virtual bool windowClosing(GUI::ToplevelWindow *win) { + if (!cb1->isChecked()) return false; + return true; + } + virtual void windowClosed(GUI::ToplevelWindow *win) { + GUI::Timer::remove(this); + } + } mw; + mw.frame = frame; + mw.x = -1; + mw.y = 1; + GUI::Frame *box = new GUI::Frame(frame,16,80,300,50); + mw.cb1 = new GUI::Checkbox(box,0,0,"Allow to close this window"); + mw.cb2 = new GUI::Checkbox(box,0,20,"Move this window"); + box = new GUI::Frame(frame,16,130,300,80,"Radio Buttons"); + (new GUI::Radiobox(box,0,0,"Normal"))->setChecked(true); + new GUI::Radiobox(box,0,20,"Dynamic"); + new GUI::Radiobox(box,0,40,"Simple"); + box->addActionHandler(&ex); + GUI::Timer::add(&mw,10); + frame->addWindowHandler(&mw); + GUI::Menubar *bar = new GUI::Menubar(frame,0,0,frame->getWidth()); + bar->addMenu("File"); + bar->addItem(0,"New..."); + bar->addItem(0,"Open..."); + bar->addItem(0,""); + bar->addItem(0,"Save"); + bar->addItem(0,"Save as..."); + bar->addItem(0,""); + bar->addItem(0,"Close"); + bar->addItem(0,"Quit"); + bar->addMenu("Edit"); + bar->addItem(1,"Undo"); + bar->addItem(1,"Redo"); + bar->addItem(1,""); + bar->addItem(1,"Cut"); + bar->addItem(1,"Copy"); + bar->addItem(1,"Paste"); + bar->addItem(1,""); + bar->addItem(1,"Select all"); + bar->addItem(1,"Select none"); + bar->addMenu("View"); + bar->addItem(2,"Zoom..."); + bar->addItem(2,"Zoom in"); + bar->addItem(2,"Zoom out"); + bar->addMenu("?"); + bar->addItem(3,"Manual"); + bar->addItem(3,"Search..."); + bar->addItem(3,""); + bar->addItem(3,"About"); + bar->addActionHandler(&ex); + + SDL_Event event; + while (1) { + while (SDL_PollEvent(&event)) { + if (!guiscreen.event(event)) { + if (event.type == SDL_QUIT) exit(0); + } + } + + if (SDL_MUSTLOCK(screen)) SDL_LockSurface(screen); + memset(screen->pixels,0xff,4*640*15); + memset(((char *)screen->pixels)+4*640*15,0x00,4*640*450); + memset(((char *)screen->pixels)+4*640*465,0xff,4*640*15); + if (SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen); + guiscreen.update(4); + SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); + + SDL_Delay(40); + } +} +#endif + #endif \ No newline at end of file diff --git a/src/libs/gui_tk/gui_tk.h b/src/libs/gui_tk/gui_tk.h index 696c89f..ebc90c5 100644 --- a/src/libs/gui_tk/gui_tk.h +++ b/src/libs/gui_tk/gui_tk.h @@ -1,2225 +1,2225 @@ -/** \mainpage gui::tk - framework-agnostic C++ GUI toolkit - * - * \section i Introduction - * - * gui::tk is a simple one-file C++ GUI toolkit for use with arbitrary - * memory framebuffers. - * - * \section f Features - * - * \li small source and binary code size - * \li reasonable performance and memory usage - * \li comfortable usage - * \li suitable for embedded usage: integer math only - * \li extensibility via OO - * \li non-intrusive: can be integrated with any event mechanism of your liking - * \li no dependencies apart from standards-conformant ANSI C++ (including a little STL) - * \li support for different encodings, single- and multibyte - * \li flexible font support - * - * \section o Overview - * - * The toolkit draws on a surface you provide, using any size or pixel format. - * Create a GUI::Screen with the buffer to draw on, then pass that object - * (or a GUI::Window created from it) to all other widgets' constructors. - * - * It doesn't provide an own event loop. Instead, it relies on you passing events - * and updating the screen regularly. This way, it can easily be integrated with - * any event loop available (SDL, Qt, glib, X11, Win32, selfmade, ...) - * - * Many functions and concepts were taken from other well-known toolkits, so if you - * know Qt, Java or wxWindows, you may encounter (intentional) similarities. However, - * simplicity of code has been given priority over maximum optimization and pixel-exact - * replication of their appearance. - * - * A note about font support and encodings: All text-related functions use templates to - * support any encoding. Fonts define the charset. - * - * \section g Getting Started - * - * gui::tk contains an SDL adapter, so if your program is already using SDL, - * things are really easy. The rough sequence to get up and running is: - * - * \code - * // setup a suitable video mode with SDL - * SDL_surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE); - * - * // add a default font, you will most probably need it - * GUI::Font::addFont("default",new GUI::BitmapFont(testfont,14,10)); - * - * // create the root-level screen object, the parent of all top-level windows - * GUI::ScreenSDL guiscreen(screen); - * - * // create any amount of toplevel windows you like - * GUI::ToplevelWindow *frame = new GUI::ToplevelWindow(&guiscreen, 205, 100, 380, 250, "gui::tk example"); - * - * // add some GUI elements to the toplevel window - * GUI::Button *b = new GUI::Button(frame,8,20,"Quit"); - * - * // Define and add an event handler - * struct quit : public GUI::ActionEventSource_Callback { - * void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { - * exit(0); - * } - * } ex; - * b->addActionHandler(&ex); - * - * // Enter an event loop, calling update() regularly. - * SDL_Event event; - * while (1) { - * while (SDL_PollEvent(&event)) { - * if (!guiscreen.event(event)) { // gui::tk didn't handle that event - * if (event.type == SDL_QUIT) exit(0); - * } - * } - * - * guiscreen.update(4); // 4 ticks = 40ms - * SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); - * - * SDL_Delay(40); // wait 40ms - * } - * \endcode - * - * Look at gui_tk.h for more detailed documentation and reference of all classes. - * - * A test program that shows off the capabilities of gui::tk is available as part of gui_tk.cpp. - * - * \section l License - * - * Copyright (C) 2005-2007 Jörg Walter - * - * gui::tk 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 3 of the License, or - * (at your option) any later version. - * - * gui::tk 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, see - */ - -/* $Id: gui_tk.h,v 1.6 2009/05/17 15:28:05 c2woody Exp $ */ - -#ifndef GUI__TOOLKIT_H -#define GUI__TOOLKIT_H - -#define imin(x,y) ((x)<(y)?(x):(y)) -#define imax(x,y) ((x)>(y)?(x):(y)) -#define isign(x) (((x)<0?-1:1)) - -/** \file - * \brief Header file for gui::tk. - * - * All you need to do is to include "gui_tk.h". If you want SDL support, then include \c SDL.h first. - */ - -#ifdef _MSC_VER -typedef signed __int8 int8_t; -typedef signed __int16 int16_t; -typedef signed __int32 int32_t; -typedef unsigned __int8 uint8_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int32 uint32_t; -#else -#include -#endif - -#include -#include -#include -#include -#include -#include - -/// This namespace contains all GUI toolkit classes, types and functions. -namespace GUI { - -/// ARGB 24-bit color value: (a<<24)|(r<<16)|(g<<8)|(b) -typedef uint32_t RGB; - -/// Collection of all color-related constants and functions. -namespace Color { -/// A fully transparent pixel. -const RGB Transparent = 0x00ffffff; - -/// A fully opaque black pixel. -const RGB Black = 0xff000000; - -/// A fully opaque white pixel. -const RGB White = 0xffffffff; - -/// Alpha mask. -const RGB AlphaMask = 0xff000000; - -/// Offset of alpha value. -const int AlphaShift = 24; - -/// Red mask. -const RGB RedMask = 0x00ff0000; - -/// Full-intensity red. -const RGB Red = Black|RedMask; - -/// Offset of red value. -const int RedShift = 16; - -/// Green mask. -const RGB GreenMask = 0x0000ff00; - -/// Full-intensity green. -const RGB Green = Black|GreenMask; - -/// Offset of green value. -const int GreenShift = 8; - -/// Blue mask. -const RGB BlueMask = 0x000000ff; - -/// Full-intensity blue. -const RGB Blue = Black|BlueMask; - -/// Offset of blue value. -const int BlueShift = 0; - -/// Full-intensity Magenta. -const RGB Magenta = Red|Blue; - -/// Magenta mask. -const RGB MagentaMask = RedMask|BlueMask; - -/// Full-intensity Cyan. -const RGB Cyan = Green|Blue; - -/// Cyan mask. -const RGB CyanMask = GreenMask|BlueMask; - -/// Full-intensity Yellow. -const RGB Yellow = Red|Green; - -/// Yellow mask. -const RGB YellowMask = RedMask|GreenMask; - -/// 50% grey -const RGB Grey50 = 0xff808080; - -/// Background color for 3D effects. May be customized. -extern RGB Background3D; - -/// Light highlight color for 3D effects. May be customized. -extern RGB Light3D; - -/// Dark highlight color (shadow) for 3D effects. May be customized. -extern RGB Shadow3D; - -/// Generic border color for highlights or similar. May be customized. -extern RGB Border; - -/// Foreground color for regular content (mainly text). May be customized. -extern RGB Text; - -/// Background color for inactive areas. May be customized. -extern RGB Background; - -/// Background color for selected areas. May be customized. -extern RGB SelectionBackground; - -/// Foreground color for selected areas. May be customized. -extern RGB SelectionForeground; - -/// Background color for inputs / application area. May be customized. -extern RGB EditableBackground; - -/// Title bar color for windows. May be customized. -extern RGB Titlebar; - -/// Title bar text color for windows. May be customized. -extern RGB TitlebarText; - -/// Convert separate r, g, b and a values (each 0-255) to an RGB value. -static inline RGB rgba(int r, int g, int b, int a=0) { - return (((r&255)<>Color::RedShift); } -/// Get green value (0-255) from an RGB value. -static inline int G(RGB val) { return ((val&Color::GreenMask)>>Color::GreenShift); } -/// Get blue value (0-255) from an RGB value. -static inline int B(RGB val) { return ((val&Color::BlueMask)>>Color::BlueShift); } -/// Get alpha value (0-255) from an RGB value. -static inline int A(RGB val) { return ((val&Color::AlphaMask)>>Color::AlphaShift); } - -} - -/// Identifies a mouse button. -enum MouseButton { NoButton, Left, Right, Middle, WheelUp, WheelDown, WheelLeft, WheelRight }; - -/// A type which holds size values that can be very large. -typedef unsigned int Size; - -/// A type which holds a single character. Large enough for Unicode. -typedef uint32_t Char; - -/// A type which holds a number of timer ticks. -typedef unsigned int Ticks; - -/// Identifies a keyboard key. -class Key { -public: - /// Translated character value. - /** No encoding is implied. The Font that is used to display this character - * determines the appearance. */ - Char character; - /// Special keyboard keys. - /** It is modeled after PC keyboards. When you feed keyboard events to a GUI::Screen, - * try to map native keys to this set. Some special keys have a character value. Set - * to \c None if the key has no special meaning. */ - enum Special { - None, - F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, - Up, Down, Left, Right, Backspace, Tab, Backtab, Enter, Escape, - Home, End, PageUp, PageDown, Insert, Delete, Menu, - Print, Pause, Break, CapsLock, NumLock, ScrollLock, - Alt, Ctrl, Shift, Windows - } special; - /// Set if the Shift key is currently down. - bool shift; - /// Set if the Ctrl key is currently down. - bool ctrl; - /// Set if the Alt (PC) or Meta (classic Unix) key is currently down. - bool alt; - /// Set if the "Windows"/Meta (PC) or Super (classic Unix) key is currently down. - /** Do not depend too heavily on this, as many keyboards and systems do not have such a key. */ - bool windows; - - /// Constructor. - Key(int character, Special special, bool shift, bool ctrl, bool alt, bool windows) : - character(character), special(special), - shift(shift), ctrl(ctrl), alt(alt), windows(windows) {} -}; - -class Drawable; -class String; - -/** \brief Converts between strings of various types and String objects. - * - * It is used to deal with string encoding. It is intended to be used with template - * specializations. Having such a specialization means you can feed the corresponding type to - * all functions that expect a string -- without any conversion. You can add specializations - * yourself in your program's code to deal with unsupported types. - * - * As an example, see the std::string version. - * - * Encodings, as opposed to character sets, define how bytes map to character values. - * ASCII, for example, has an \em encoding where each byte is one character, while the - * ASCII \em character \em set says that values 0-127 are valid and 65 is the upper case - * letter 'A'. UTF-8 has 1-6 bytes per character, and the character set is unicode. - * - * GUI::Font deals with the character set, and this class encapsulates encodings. - * - */ -template class NativeString { -protected: - friend class String; - - /// Converts a native string into a String object - static void getString(String &dest, const STR &src) { STR::_this_string_type_is_not_supported_(); } - - /** \brief Converts a string object to native representation. - * - * If some characters cannot be converted, they should silently be skipped. Apart from that, - * \c nativeString(stringNative(String(),X)) should be value-equal to \c X. - */ - static STR& getNative(const String &src) { STR::_this_string_type_is_not_supported_();return*new STR(); } -}; - -template class NativeString { -protected: - friend class String; - static void getString(String &dest, const STR *src); - static STR* getNative(const String &src); -}; - -template class NativeString : public NativeString {}; -template class NativeString : public NativeString {}; -template class NativeString : public NativeString {}; - -/// 'less-than' comparison between pointer addresses -struct ltvoid { bool operator()(const void* s1, const void* s2) const { return s1 < s2; } }; - -/** \brief Simple STL-based string class. - * - * This is intended as internal helper class to allow gui::tk to work with any kind of - * string objects. While you can use this in normal application code, you should better - * use the string class of your application framework (like Qt). If you don't have any, - * use std::string. - * - * It supports arbitrary characters, no character set is implied. Conversion from/to usual - * string types like \c char* is automatic but not thread-safe for non-class types. - */ -class String : public std::vector { -protected: - template friend class NativeString; - /// Simple pointer encapsulation class for memory management. - class Native { public: virtual ~Native() {}; }; - /// Simple pointer encapsulation class for memory management. - template class NativeArray: public Native { - STR *data; - public: - NativeArray(STR *data) : data(data) {} - virtual ~NativeArray() { delete[] data; } - }; - template class NativeObject: public Native { - STR *data; - public: - NativeObject(STR *data) : data(data) {} - virtual ~NativeObject() { delete data; } - }; - -private: - /// Semi-static memory management for pointer string types. - mutable std::map strings; - -protected: - /// Manage a native string's memory. - void addNative(Native *dest) const { - const class std::type_info &type = typeid(dest); - if (strings[&type] != NULL) delete strings[&type]; - strings[&type] = dest; - } - -public: - /// Allocate a new String initialized from native string. - template String(const STR& src) { NativeString::getString(*this, src); } - - /// Taken from STL. - template String(InputIterator a, InputIterator b) : std::vector(a,b) {} - - /// Copy-constructor - String(const String &src) : std::vector(src), strings() {}; - - /// Allocate a new String. - String() { } - - /// Deallocate a String. - ~String() { - for (std::map::iterator i = strings.begin(); i != strings.end(); ++i) - delete (*i).second; - }; - - /// Convert to native representation. - /** For pointer types like \c char*, the returned pointer is usually only valid as long as - * this object exists, or until it is modified and cast to the same type again. */ - template operator T() const { return NativeString::getNative(*this); } - - /// Compare with native representation. - template bool operator==(const T &src) const { return *this == String(src); } - /// Compare with other Strings. - bool operator==(const String &src) const { return *(std::vector*)this == src; } - - /// Compare with native representation. - template bool operator!=(const T &src) const { return *this != String(src); } - /// Compare with other Strings. - bool operator!=(const String &src) const { return *(std::vector*)this != src; } -}; - -template void NativeString::getString(String &dest, const STR* src) { - Size strlen = 0; - while (src[strlen]) strlen++; - dest.resize(strlen); - for (strlen = 0; src[strlen]; strlen++) dest[strlen] = (sizeof(STR)==1?(unsigned char)src[strlen]:sizeof(STR)==2?(unsigned short)src[strlen]:src[strlen]); -} - -template STR* NativeString::getNative(const String &src) { - Size strlen = (Size)src.size(); - STR* dest = new STR[strlen+1]; - dest[strlen] = 0; - for (; strlen > 0; strlen--) dest[strlen-1] = src[strlen-1]; - src.addNative(new String::NativeArray(dest)); - return dest; -} - -template <> class NativeString { -protected: - friend class String; - static void getString(String &dest, const std::string *src) { - Size strlen = (Size)src->length(); - dest.resize(strlen); - for (Size i = 0; i< strlen; i++) dest[i] = (*src)[i]; - } - static std::string* getNative(const String &src) { - Size strlen = (Size)src.size(); - std::string* dest = new std::string(); - for (Size i = 0; i < strlen; i++) dest->append(1,src[i]); - src.addNative(new String::NativeObject(dest)); - return dest; - } -}; - -template <> class NativeString : public NativeString {}; - -template <> class NativeString { -protected: - friend class String; - static void getString(String &dest, const std::string &src) { - Size strlen = (Size)src.length(); - dest.resize(strlen); - for (Size i = 0; i< strlen; i++) dest[i] = src[i]; - } - static std::string& getNative(const String &src) { - Size strlen = (Size)src.size(); - std::string* dest = new std::string(); - for (Size i = 0; i < strlen; i++) dest->append(1,src[i]); - src.addNative(new String::NativeObject(dest)); - return *dest; - } -}; - -template <> class NativeString : public NativeString {}; - -class ToplevelWindow; -class Menu; -class TransientWindow; -class Screen; -class Window; - -/// Callback for window events. -struct Window_Callback { -public: - /// Called whenever this window changes position. - virtual void windowMoved(Window *win, int x, int y) = 0; - virtual ~Window_Callback() {} -}; - - -/** \brief A Window is a rectangular sub-area of another window. - * - * Windows are arranged hierarchically. A Window cannot leave its parent's - * area. They may contain their own buffer or share it with their parent. - * - * Usually, every GUI element is a subclass of Window. Note that this is - * \em not a GUI window with decorations like border and title bar. See ToplevelWindow - * for that. - */ -class Window { -protected: - friend class ToplevelWindow; - friend class TransientWindow; - friend class Menu; - - /// Width of the window. - int width; - /// Height of the window. - int height; - /// X position relative to parent. - int x; - /// Y position relative to parent. - int y; - - /// \c true if anything changed in this window or one of it's children - bool dirty; - - /// \c true if this window should be visible on screen. - bool visible; - - /// Parent window. - Window *const parent; - - /// Child window of last button-down event - /** It receives all drag/up/click/doubleclick events until an up event is received */ - Window *mouseChild; - - /// Child windows. - /** Z ordering is done in list order. The first element is the lowermost - * window. This window's content is below all children. */ - std::list children; - - /// List of registered event handlers. - std::list movehandlers; - - /// Register child window. - virtual void addChild(Window *child); - - /// Remove child window. - virtual void removeChild(Window *child); - - /// Mark this window and all parents as dirty. - void setDirty() { if (dirty) return; dirty = true; if (parent != NULL) parent->setDirty(); }; - - /// Replace clipboard content. - virtual void setClipboard(const String &s) { parent->setClipboard(s); }; - - /// Get clipboard content. - virtual const String& getClipboard() { return parent->getClipboard(); }; - - /// Default constructor. Only used in class Screen. Do not use. - Window(); - - /// Called whenever the focus changes. - virtual void focusChanged(bool gained) { - if (children.size() > 0) children.back()->focusChanged(gained); - } - -public: - - /// Add an event handler. - void addWindowHandler(Window_Callback *handler) { movehandlers.push_back(handler); } - - /// Remove an event handler. - void removeWindowHandler(Window_Callback *handler) { movehandlers.remove(handler); } - - /// Create a subwindow of the given parent window. - Window(Window *parent, int x, int y, int w, int h); - - /// Destructor. - virtual ~Window(); - - /// Resize this window to the given dimensions. - /** If that would move part of the window outside of this window's area, - * the outside area will silently be clipped while drawing. */ - virtual void resize(int w, int h); - /// Return this window's width - virtual int getWidth() const { return width; } - /// Return this window's height - virtual int getHeight() const { return height; } - - /// Move this window to the given position relative to the parent window's origin. - /** If that would move part of the window outside of this window's area, - * the outside area will silently be clipped while drawing. */ - virtual void move(int x, int y); - /// Return this window's X position relative to the parent's top left corner - virtual int getX() const { return x; } - /// Return this window's Y position relative to the parent's top left corner - virtual int getY() const { return y; } - /// Return this window's contents' X position relative to the screen's top left corner - virtual int getScreenX() const { return (parent == NULL?0:parent->getScreenX()+x); } - /// Return this window's contents' Y position relative to the screen's top left corner - virtual int getScreenY() const { return (parent == NULL?0:parent->getScreenY()+y); } - - /// Draw this window's content including all children. - virtual void paintAll(Drawable &d) const; - - /// Draw this window's content. - virtual void paint(Drawable &d) const {}; - - /// Show or hide this window. - /** By default, most windows are shown when created. Hidden windows do not receive any events. */ - virtual void setVisible(bool v) { visible = !!v; parent->setDirty(); } - - /// Returns \c true if this window is visible. - virtual bool isVisible() const { return (!parent || parent->isVisible()) && visible; } - - /// Return parent window. - /** May return NULL if this is the topmost window (the Screen). */ - Window *getParent() const { return parent; } - - /// Get the topmost window (the Screen) - Screen *getScreen(); - - /// Returns \c true if this window has currently the keyboard focus. - virtual bool hasFocus() const { return parent->hasFocus() && *parent->children.rbegin() == this; } - - /// Mouse was moved. Returns true if event was handled. - virtual bool mouseMoved(int x, int y); - /// Mouse was moved while a button was pressed. Returns true if event was handled. - virtual bool mouseDragged(int x, int y, MouseButton button); - /// Mouse was pressed. Returns true if event was handled. - virtual bool mouseDown(int x, int y, MouseButton button); - /// Mouse was released. Returns true if event was handled. - virtual bool mouseUp(int x, int y, MouseButton button); - /// Mouse was clicked. Returns true if event was handled. - /** Clicking means pressing and releasing the mouse button while not moving it. */ - virtual bool mouseClicked(int x, int y, MouseButton button); - /// Mouse was double-clicked. Returns true if event was handled. - virtual bool mouseDoubleClicked(int x, int y, MouseButton button); - - /// Key was pressed. Returns true if event was handled. - virtual bool keyDown(const Key &key); - /// Key was released. Returns true if event was handled. - virtual bool keyUp(const Key &key); - - /// Put this window on top of all it's siblings. Preserves relative order. - /** Returns true if the window accepts the raise request. */ - virtual bool raise() { - Window *last = parent->children.back(); - for (Window *cur = parent->children.back(); cur != this; cur = parent->children.back()) { - parent->children.remove(cur); - parent->children.push_front(cur); - } - if (last != this) { - focusChanged(true); - last->focusChanged(false); - } - parent->setDirty(); - return true; - } - - /// Put this window below all of it's siblings. Does not preserve relative order. - virtual void lower() { - parent->children.remove(this); - parent->children.push_front(this); - if (this != parent->children.back()) { - parent->children.back()->focusChanged(true); - focusChanged(false); - } - parent->setDirty(); - } - - /// Return the \p n th child - Window *getChild(int n) { - for (std::list::const_iterator i = children.begin(); i != children.end(); ++i) { - if (n--) return *i; - } - return NULL; - } - -}; - -/** \brief A Screen represents the framebuffer that is the final destination of the GUI. - * - * It's main purpose is to manage the current contents of the surface and to combine - * it with all GUI elements. You can't resize and move the screen. Requests to do so - * will be ignored. - * - * This is an abstract base class. You need to use a subclass which implements rgbToSurface - * and surfaceToRGB. - * - * To make things work, Screen needs events. Call the mouse and key event functions (see Window) - * whenever such an event occurs. Call update(void *surface, int ticks) regularly, if possible about - * every 40msec (25 fps). If nothing has changed, screen updates are quite fast. - */ -class Screen : public Window { -protected: - /// Screen buffer. - Drawable *const buffer; - - /// Clipboard. - String clipboard; - - /// Currently pressed mouse button. - MouseButton button; - - /// Store a single RGB triple (8 bit each) as a native pixel value and advance pointer. - virtual void rgbToSurface(RGB color, void **pixel) = 0; - - /// Map a single framebuffer pixel to an RGB value. - virtual RGB surfaceToRGB(void *pixel) = 0; - - /// Create a new screen with the given characteristics. - Screen(Size width, Size height); - - /// Create a new screen from the given GUI::Drawable. - Screen(Drawable *d); - -public: - /// Destructor. - virtual ~Screen(); - - /// Set clipboard content. - template void setClipboard(const STR s) { this->setClipboard(String(s)); } - - /// Set clipboard content. - virtual void setClipboard(const String &s) { clipboard = s; } - - /// Get clipboard content. - virtual const String& getClipboard() { return clipboard; } - - /// Do nothing. - virtual void resize(int w, int h); - - /// Do nothing. - virtual void move(int x, int y); - - /// Screen has always focus. - virtual bool hasFocus() const { return true; } - - /// Update the given surface with this screen's content, fully honouring the alpha channel. - /** \p ticks can be set to a different value depending on how much time has passed. Timing - * doesn't need to be perfect, but try to call this at least every 40 msec. Each tick - * amounts to about 10 msec. Returns the number of ticks until the next event is scheduled, or - * 0 if none. */ - Ticks update(void *surface, Ticks ticks = 1); - - /// Default: clear screen. - virtual void paint(Drawable &d) const; -}; - -class Timer; - -/// Timer callback type -struct Timer_Callback { -public: - /// The timer has expired. - /** Callbacks for timers take one parameter, the number of ticks since - * application start. Note that this value may wrap after a little less - * than 500 days. If you want callbacks to be called again, return the - * delay in ticks relative to the scheduled time of this - * callback (which may be earlier than now() ). Otherwise return 0. */ - virtual Ticks timerExpired(Ticks time) = 0; - virtual ~Timer_Callback() {} -}; - -/** \brief Timing service. - * Time is measured in ticks. A tick is about 10 msec. - * - * Note that this is not suitable as a high-accuracy timing service. Timer - * events can be off by many ticks, and a tick may be slightly more or - * slightly less than 10 msec. Because of that, Timers are only intended for - * simple animation effects, input timeouts and similar things. - * - */ -class Timer { -protected: - /// Number of ticks since application start. - static Ticks ticks; - - /// Compare two integers for 'less-than'. - struct ltuint { bool operator()(Ticks i1, Ticks i2) const { - return (i1 < i2); - } }; - - /// Active timers. - static std::multimap timers; - -public: - /// Advance time and check for expired timers. - static void check(Ticks ticks); - - /// Add a timed callback. \p ticks is a value relative to now(). - /** \p cb is not copied. */ - static void add(Timer_Callback *cb, const Ticks ticks) { timers.insert(std::pair(ticks+Timer::ticks,cb)); } - - static void remove(const Timer_Callback *const cb); - - /// Return current time (ticks since application start) - static Ticks now() { return ticks; } - - /// Return number of ticks until next scheduled timer or 0 if no timers - static Ticks next(); -}; - - -/** \brief A 24 bit per pixel RGB framebuffer aligned to 32 bit per pixel. - * - * Warning: This framebuffer type varies with CPU endiannes. It is meant as - * a testing/debugging tool. - */ -class ScreenRGB32le : public Screen { -protected: - /// Map a single RGB triple (8 bit each) to a native pixel value. - virtual void rgbToSurface(RGB color, void **pixel) { RGB **p = (RGB **)pixel; **p = color; (*p)++; }; - - /// Map a single surface pixel to an RGB value. - virtual RGB surfaceToRGB(void *pixel) { return *(RGB*)pixel; }; -public: - ScreenRGB32le(Size width, Size height) : Screen(width,height) {}; - - virtual void paint(Drawable &d) const; -}; - - -#ifdef SDL_MAJOR_VERSION -/** \brief An SDL surface adapter. - * - * This screen type will draw on an SDL surface (honouring transparency if the - * surface is already filled) and react on SDL events. It does not provide an - * application event loop, you have to call update() and event() regularly until - * you decide to quit the application. - * - * The implementation of this class could as well have been integrated into - * GUI::Screen. That might have been a little more efficient, but this way - * this class serves as an example for custom screen classes. - * - * Note that you have to include \c SDL.h \em before \c gui_tk.h for this class - * to become available. - */ -class ScreenSDL : public Screen { -protected: - /// not used. - virtual void rgbToSurface(RGB color, void **pixel) {}; - - /// not used. - virtual RGB surfaceToRGB(void *pixel) { return 0; }; - - /// The SDL surface being drawn to. - SDL_Surface *surface; - - /// Position of last mouse down. - int downx, downy; - - /// time of last click for double-click detection. - Ticks lastclick; - -public: - - /** Initialize SDL screen with a surface - * - * The dimensions of this surface will define the screen dimensions. Changing the surface - * later on will not change the available area. - */ - ScreenSDL(SDL_Surface *surface); - - /** Change current surface - * - * The new surface may have different dimensions than the current one, but - * the screen size will not change. This means that either the screen will - * not be displayed fully, or there will be borders around the screen. - */ - void setSurface(SDL_Surface *surface) { this->surface = surface; } - - /// Retrieve current surface. - SDL_Surface *getSurface() { return surface; } - - /// Overridden: makes background transparent by default. - virtual void paint(Drawable &d) const; - - /// Use this to update the SDL surface. The screen must not be locked. - Ticks update(Ticks ticks); - - /// Process an SDL event. Returns \c true if event was handled. - bool event(const SDL_Event *ev) { return event(*ev); } - - - /// Process an SDL event. Returns \c true if event was handled. - bool event(const SDL_Event& ev); -}; -#endif - -class Font; - -/** \brief A drawable represents a rectangular off-screen drawing area. - * - * It is an off-screen buffer which can be copied to other drawables or - * to a Screen's framebuffer. The drawable's origin is at the top left. All - * operations are silently clipped to the available area. The alpha channel - * is honoured while copying one drawable to another, but not during other - * drawing operations. - * - * Drawables have a current font, color and (x,y) position. Drawing takes place - * at the given point using the given font and color. The current position is - * then moved to the final point of the drawing primitive unless otherwise - * noted. Pixel width of all lines is selectable, but be aware that visual - * appearance of lines with width > 1 is not as sophisticated as in well-known - * toolkits like Java or Qt. - * - * Some drawing primitives are overloaded to take full coordinates. These ignore - * the current position, but update it just like their regular brethren. - */ -class Drawable { -protected: - friend Ticks Screen::update(void *, Ticks); - /// The actual pixel buffer. - RGB *const buffer; - /// Total width of buffer. - const int width; - /// Total height of buffer. - const int height; - /// \c true if \a buffer must be freed by this instance. - const bool owner; - - /// Current color. - RGB color; - /// Current font. - const Font *font; - /// Current line width. - int lineWidth; - - /// X translation. - const int tx; - /// Y translation. - const int ty; - /// clip x. - const int cx; - /// clip y. - const int cy; - /// clip width. - const int cw; - /// clip height. - const int ch; - - /// Current position x coordinate. - int x; - /// Current position y coordinate. - int y; - -public: - /// Create an empty drawable object with given dimensions. - /** Optionally, the area is cleared with a given color (default: fully transparent). */ - Drawable(int w, int h, RGB clear = Color::Transparent); - - /// Deep-copying copy constructor. - /** It honours clip and translate so that the resulting drawable, if drawn - * to the source drawable at (0,0), yields the same result as drawing - * directly to the source surface. If \p fill is not explicitly set, will - * copy the original surface's contents */ - Drawable(Drawable &src, RGB clear = 0); - - /// Shallow-copying copy constructor with clip & translate. See setClipTranslate(int x, int y, int w, int h). - Drawable(Drawable &src, int x, int y, int w, int h); - - /// Destructor. - virtual ~Drawable(); - - /// Clears the surface. - void clear(RGB clear = Color::Transparent); - - /// Change current drawing color. - /** The alpha part is honoured in all drawing primitives like this: - All drawing operations in this window will unconditionally overwrite - earlier content of this window. Only when combining this window with - it's parent, the alpha channel is fully honoured. */ - void setColor(RGB c) { color = c; }; - /// Return the currently selected drawing color. - RGB getColor() { return color; }; - - /// Change current drawing font. - void setFont(const Font *f) { font = f; }; - /// Return the currently selected drawing font. - const Font *getFont() { return font; }; - - /// Change current line width. - void setLineWidth(int w) { lineWidth = w; }; - /// Return the current line width. - int getLineWidth() { return lineWidth; }; - - /// Move the current position to the given coordinates. - void gotoXY(int x, int y) { this->x = x; this->y = y; }; - /// Return current position X. - int getX() { return x; } - /// Return current position Y. - int getY() { return y; } - - /// Return clip width - int getClipX() { return cx; } - /// Return clip height - int getClipY() { return cy; } - /// Return clip width - int getClipWidth() { return cw; } - /// Return clip height - int getClipHeight() { return ch; } - - /// Paint a single pixel at the current position. - void drawPixel() { if (x >= cx && x < cw && y >= cy && y < ch) buffer[x+tx+(y+ty)*width] = color; }; - /// Paint a single pixel at the given coordinates. - void drawPixel(int x, int y) { gotoXY(x,y); drawPixel(); }; - - /// Return the pixel color at the current position. - RGB getPixel() { if (x >= cx && x < cw && y >= cy && y < ch) return buffer[x+tx+(y+ty)*width]; return Color::Transparent; }; - /// Return the pixel color at the given coordinates. - RGB getPixel(int x, int y) { gotoXY(x,y); return getPixel(); }; - - /// Draw a straight line from the current position to the given coordinates. - void drawLine(int x2, int y2); - /// Draw a straight line from (\p x1,\p y1) to (\p x2,\p y2). - void drawLine(int x1, int y1, int x2, int y2) { gotoXY(x1,y1); drawLine(x2,y2); }; - - /// Draw a circle centered at the current position with diameter \p d. - /** The current position is not changed. */ - void drawCircle(int d); - /// Draw a circle centered at the given coordinates with diameter \p d. - /** The current position is set to the center. */ - void drawCircle(int x, int y, int d) { gotoXY(x, y); drawCircle(d); }; - - /// Draw a rectangle with top left at the current position and size \p w, \p h. - /** The current position is not changed. */ - void drawRect(int w, int h); - /// Draw a rectangle with top left at the given coordinates and size \p w, \p h. - /** The current position is set to the top left corner. */ - void drawRect(int x, int y, int w, int h) { gotoXY(x, y); drawRect(w, h); }; - - /// Flood-fill an area at the current position. - /** A continuous area with the same RGB value as the selected pixel is - changed to the current color. The current position is not changed. */ - void fill(); - /// Flood-fill an area at a given position. - /** see fill(), but moves current position to the given coordinates */ - void fill(int x, int y) { gotoXY(x,y); fill(); }; - - /// Draw a filled circle centered at the current position with diameter \p d. - /** The current position is not changed. */ - void fillCircle(int d); - /// Draw a filled circle centered at the given coordinates with diameter \p d. - /** The current position is set to the center. */ - void fillCircle(int x, int y, int d) { gotoXY(x, y); fillCircle(d); }; - - /// Draw a filled rectangle with top left at the current position and size \p w, \p h. - /** The current position is not changed. */ - void fillRect(int w, int h); - /// Draw a filled rectangle with top left at the given coordinates and size \p w, \p h. - /** The current position is set to the top left corner. */ - void fillRect(int x, int y, int w, int h) { gotoXY(x, y); fillRect(w, h); }; - - /// Draw a text string. - /** Current position is the leftmost pixel on the baseline of the character. - The current position is moved to the next character. Background is not - cleared. If \p interpret is \c true, some ASCII control characters like - backspace, line-feed, tab and ANSI colors are interpreted, and text is word-wrapped at - the window borders. You can optionally pass start and length of a substring - to print */ - void drawText(const String& text, bool interpret = true, Size start = 0, Size len = (Size)-1); - - /// Draw a text string at a fixed position. - /** see drawText(const String& text, bool interpret, Size start, Size len) */ - template void drawText(int x, int y, const STR text, bool interpret, Size start, Size len = (Size)-1) { gotoXY(x,y); drawText(String(text), interpret, start, len); }; - /// Draw a single character. - /** see drawText(const STR text, bool interpret), except wrapping is - performed on this character only */ - void drawText(const Char c, bool interpret = false); - /// Draw a single character at a fixed position. - /** see drawText(const Char c, bool interpret). */ - void drawText(int x, int y, const Char c, bool interpret = false) { gotoXY(x,y); drawText(c, interpret); }; - - /// Copy the contents of another Drawable to this one. - /** The top left corner of the source Drawable is put at the current - position. The alpha channel is fully honoured. Additionally, an extra - \p alpha value may be given which is multiplied with the source - alpha channel. The current position remains unchanged. */ - void drawDrawable(Drawable &d, unsigned char alpha = 1); - /// Copy the contents of another Drawable to this one at a given position. - /** see drawDrawable(Drawable &d, unsigned char alpha). The current position - is moved to the given coordinates. */ - void drawDrawable(int x, int y, Drawable &d, unsigned char alpha = 1) { gotoXY(x,y); drawDrawable(d, alpha); }; - -}; - -/** \brief A variable- or fixed-width fixed-size Font. - * - * These Fonts can't be scaled once instantiated, but it is possible - * to subclass this abstract font class to encapsulate scalable - * fonts. Fonts can be anti-aliasing and multi-coloured, depending on - * subclass. There is no encoding enforced. The font object implicitly - * knows about it's encoding. Because of that, there is a utility - * function for string examination as well. - * - * You can't instantiate objects of this class directly, use one of the - * subclasses like BitmapFont. - * - * This class provides a font registry which allows you to register - * and retrieve font objects using a name of your choice. It is recommended - * to use a naming scheme like "FontName-variant-pixelsize-encoding" where - * variant is "normal", "bold", "italic" or "bolditalic". No one enforces - * this, however. - * - * The GUI uses some special font names. You must add them before creating - * the relevant GUI item. - * \li \c default - used if a requested font was not found - * \li \c title - GUI::ToplevelWindow title - * \li \c input - GUI::Input - * - */ -class Font { -protected: - friend void Drawable::drawText(const Char c, bool interpret); - friend void Drawable::drawText(const String& s, bool interpret, Size start, Size len); - - /// Compare two strings for 'less-than'. - struct ltstr { bool operator()(const char* s1, const char* s2) const { - return strcmp(s1, s2) < 0; - } }; - /// Font registry. Contains all known font objects indexed by name. - static std::map registry; - - /// Default constructor. - Font() {}; - - /// Draw character to a drawable at the current position. - /** \p d's current position is advanced to the position of the next character. - * The y coordinate is located at the baseline before and after the call. */ - virtual void drawChar(Drawable *d, const Char c) const = 0; - - /// Draw \p len characters to a drawable at the current position, starting at string position \p start. - /** This can be used to provide kerning. */ - virtual void drawString(Drawable *d, const String &s, Size start, Size len) const { - if (len > s.size()-start) len = (Size)(s.size()-start); - len += start; - while (start < len) drawChar(d,s[start++]); - } - -public: - /// Return a font with the given name (case-sensitive). - /** If no font was registered with that name, returns NULL. */ - static const Font *getFont(const char *name) { - std::map::iterator i = registry.find(name); - if (i == registry.end()) return(strcmp(name,"default")?getFont("default"):NULL); - return (*i).second; - } - - /// Add a font with a given name. - /** Don't delete this font once added. This class will do that for you. - * If a font with that name already exists, it will be replaced. */ - static void addFont(const char *name, Font *font) { - std::map::iterator i = registry.find(name); - if (i != registry.end()) delete (*i).second; - registry[name] = font; - } - - virtual ~Font() {}; - - /// Retrieve total height of font in pixels. - virtual int getHeight() const = 0; - - /// Retrieve the ascent, i.e. the number of pixels above the base line. - virtual int getAscent() const = 0; - - /// Return width of a string. - template int getWidth(const STR s, Size start = 0, Size len = (Size)-1) const { - return this->getWidth(String(s), start, len); - } - - /// Retrieve width of a character. - virtual int getWidth(Char c = 'M') const = 0; - - /// Retrieve width of a string of characters. - /** Can be used to provide kerning. */ - virtual int getWidth(const String &s, Size start = 0, Size len = (Size)-1) const { - int width = 0; - if (start+len > s.size()) len = (Size)(s.size()-start); - while (len--) width += getWidth(s[start++]); - return width; - } - - /// Characters with special appearance or meaning. - enum SpecialChar { CR = '\r', LF = '\n', BS = '\b', Tab = '\t', Space = ' ', ESC = 27 }; - - /// Convert a character to an equivalent SpecialChar. May return values not in SpecialChar. - virtual SpecialChar toSpecial(Char c) const { return (SpecialChar)(c<255?c:255); } - - /// Convert a SpecialChar to an equivalent character. - virtual Char fromSpecial(SpecialChar c) const { return c; } -}; - -/** \brief A bitmap font. - * This is a font which is defined by a binary bit map. Each bit in the bitmap - * defines one pixel. Bits may be arranged in various common patterns. - * - * Encoding free, character size depends on number of characters in the font. - */ -class BitmapFont : public Font { -protected: - /// The actual font data. - const unsigned char *const bitmap; - - /// Width of a character cell. - const int width; - - /// Height of all characters. - const int height; - - /// Ascent of all characters. - const int ascent; - - /// Array of character widths. If font is fixed-width, this is NULL and \a width is used. - const int *const widths; - - /// Array of character ascents. If this is NULL, \a ascent is used for all characters. - /** This allows character data to be flush to the top or bottom of it's bitmap area. */ - const int *const ascents; - - /// True if set bits are background, false otherwise. - const bool background_set; - - /// Number of bits added to get from a column to the next column. - const int col_step; - - /// Distance between 2 rows of a character, or 0 for variable-width rows. - const int row_step; - - /// Distance of two characters in the bitmap in bits. - /** This is calculated as abs(row_step*height) unless explicitly specified. */ - const int character_step; - - /// Array of pointers to font data. If set, neither \a bitmap nor \a character_step are used. - const unsigned char *const*const char_position; - - /// Array of SpecialChar equivalents. - /** If unset, encoding is assumed ASCII-like for the first 32 characters */ - const SpecialChar *const special; - - /// If \c true, then all arrays are freed on destruction. - const bool owner; - - /// Last defined character. Characters above this will be ignored. - const Char last; - - /// Draw character to a drawable at the current position. - /** \p d's current position is advanced to the position of the next character. - * The y coordinate is located at the baseline before and after the call. */ - virtual void drawChar(Drawable *d, const Char c) const; - -public: - /// Constructor. - /** The default values provide an 8 bit wide fixed-width pixel layout with each byte a row, - * arranged top-to-bottom just like a PC's VGA font. See the individual member documentation - * for details on the parameters. */ - BitmapFont(const unsigned char *data, int height, int ascent, bool owner = false, - int width = 8, bool background_set = false, - int col_step = -1, int row_step = 8, int character_step = 0, Char last = 256, - const int *widths = NULL, const int *ascents = NULL, - const unsigned char *const* char_position = NULL, - const SpecialChar *special = NULL); - - virtual ~BitmapFont(); - - /// Retrieve total height of font in pixels. - virtual int getHeight() const { return height; }; - - /// Retrieve the ascent, i.e. the number of pixels above the base line. - virtual int getAscent() const { return ascent; }; - - /// Retrieve width of a character. - virtual int getWidth(Char c = 'M') const { return (widths != NULL?widths[c]:width); }; - - /// Convert a character to an equivalent SpecialChar. See Font::toSpecial(Char c) - virtual SpecialChar toSpecial(Char c) const { return (special != NULL?special[c]:Font::toSpecial(c)); } - - /// Convert a character to an equivalent character. See Font::fromSpecial(SpecialChar c). - virtual Char fromSpecial(SpecialChar c) const { if (special == NULL) return Font::fromSpecial(c); Char i = 0; while(special[i] != c) i++; return i; } - -}; - -class ActionEventSource; -/// Callback for action events. -struct ActionEventSource_Callback { -public: - /// Handler with optional String argument. - /** If the event source doesn't provide an additional argument, the name will be used. */ - virtual void actionExecuted(ActionEventSource *source, const String &arg) = 0; - virtual ~ActionEventSource_Callback() {} -}; - -/// Event class for action events. -/** Action events are events generated by GUI elements like Buttons, Menus and by pressing Enter in - * an Input. All of these are handled similarly: The source of such an event has a name, and the - * Event may also be connected with a String describing what was executed, like the name of the - * Menu entry or the contents of the Input. - */ -class ActionEventSource { -protected: - /// List of registered action handlers. - std::list actionHandlers; - - /// This event source's name. - /** The name is primarily meant for your own purposes, for example identification of the activated - * element. One exception are Menubars, which display the name of their Menus. */ - String name; - -public: - /// Create a named event source. - template ActionEventSource(const STR name) : name(String(name)) { } - - /// Dummy destructor. - virtual ~ActionEventSource() {} - - /// Add a button press event handler. - void addActionHandler(ActionEventSource_Callback *handler) { actionHandlers.push_back(handler); } - - /// Remove a button press event handler. - void removeActionHandler(ActionEventSource_Callback *handler) { actionHandlers.remove(handler); } - - /// Set the name of this event source. - template void setName(const STR name) { this->name = String(name); } - - /// Get the name of this event source. - const String &getName() const { return name; } - - /// Execute handlers. - void executeAction(const String &arg) { - std::list::iterator i = actionHandlers.begin(); - bool end = (i == actionHandlers.end()); - while (!end) { - ActionEventSource_Callback *c = *i; - ++i; - end = (i == actionHandlers.end()); - c->actionExecuted(this,arg); - } - } - - /// Execute handlers. - void executeAction() { executeAction(name); } -}; - -/// Internal class for windows whose child content should not span the entire area. -class BorderedWindow : public Window { -protected: - /// Borders. - int border_left, border_top, border_right, border_bottom; - - /// Create a bordered window. - BorderedWindow(Window *parent, int x, int y, int w, int h, int bl, int bt, int br, int bb) : - Window(parent,x,y,w,h), border_left(bl), border_top(bt), border_right(br), border_bottom(bb) {} - -public: - virtual void paintAll(Drawable &d) const; - virtual bool mouseMoved(int x, int y); - virtual bool mouseDown(int x, int y, MouseButton button); - virtual bool mouseDragged(int x, int y, MouseButton button); - virtual int getScreenX() const { return Window::getScreenX()+border_left; } - virtual int getScreenY() const { return Window::getScreenY()+border_top; } -}; - -/// A text label -/** Text labels are positioned relative to the top left corner of their bounding box. - * They size themselves automatically and display their text in non-interpreted mode. - */ - -class Label : public Window { - /// The Font used - const Font *font; - - /// Text color - RGB color; - - /// Text - String text; - - /// multiline text? - bool interpret; - -public: - /// Create a text label with given position, \p text, \p font and \p color. - /** If \p width is given, the resulting label is a word-wrapped multiline label */ - template Label(Window *parent, int x, int y, const STR text, int width = 0, const Font *font = Font::getFont("default"), RGB color = Color::Text) : - Window(parent, x, y, (width?width:1), 1), font(font), color(color), text(text), interpret(width != 0) - { resize(); } - - /// Set a new text. Size of the label is adjusted accordingly. - template void setText(const STR text) { this->text = text; resize(); } - /// Retrieve current text - const String& getText() { return text; } - - /// Set a new font. Size of the label is adjusted accordingly. - void setFont(const Font *font) { this->font = font; resize(); } - /// Retrieve current font - const Font *getFont() { return font; } - - /// Set a new text color. - void setColor(const RGB color) { this->color = color; resize(); } - /// Retrieve current color - RGB getColor() { return color; } - - /// Calculate label size. Parameters are ignored. - virtual void resize(int w = -1, int h = -1) { - if (w == -1) w = (interpret?getWidth():0); - else interpret = (w != 0); - Drawable d((w?w:1), 1); - d.setFont(font); - d.drawText(0, font->getAscent(), text, interpret, 0); - if (interpret) Window::resize(w, d.getY()-font->getAscent()+font->getHeight()); - else Window::resize(d.getX(), font->getHeight()); - } - - /// Paint label - virtual void paint(Drawable &d) const { d.setColor(color); d.drawText(0, font->getAscent(), text, interpret, 0); } - - virtual bool raise() { return false; } -}; - - -/// A single-line text input -/** It uses Font::getFont("input") to display content. - * It supports selection, the clipboard and all well-known key bindings (except undo). - */ -class Input : public Window, public Timer_Callback, public ActionEventSource { -protected: - /// The text entered. - String text; - - /// Current position in \a text. - Size pos; - - /// Last updated position in \a text. - Size lastpos; - - /// Coordinates according to pos. - int posx, posy; - - /// Selection in \a text. - Size start_sel, end_sel; - - /// Is cursor visible at the moment? - bool blink; - - /// Insert mode? - bool insert; - - /// Multiline? - bool multi; - - /// Horizontal scrolling offset. - int offset; - - /// Ensure that pos is visible. - void checkOffset() { - if (lastpos == pos) return; - const Font *f = Font::getFont("input"); - if (multi) { - Drawable d(width-6,1); - d.setFont(f); - d.drawText(0, 0, text, multi, 0, pos); - posy = d.getY(); - posx = d.getX(); - if (posy-offset > height-8-f->getHeight()) offset = posy-height+8+f->getHeight(); - if (posy-offset < 0) offset = posy; - } else { - posy = 0; - posx = f->getWidth(text,0,pos); - if (f->getWidth(text,0,pos+1)-offset > width-10) offset = f->getWidth(text,0,pos+1)-width+10; - if (f->getWidth(text,0,(pos>0?pos-1:0))-offset < 0) offset = f->getWidth(text,0,(pos>0?pos-1:0)); - } - lastpos = pos; - setDirty(); - } - -public: - /// Create an input with given position and width. If not set, height is calculated from the font and input is single-line. - Input(Window *parent, int x, int y, int w, int h = 0) : - Window(parent,x,y,w,(h?h:Font::getFont("input")->getHeight()+10)), ActionEventSource("GUI::Input"), - text(""), pos(0), lastpos(0), posx(0), posy(0), start_sel(0), end_sel(0), blink(true), insert(true), multi(h != 0), offset(0) - { Timer::add(this,30); } - - ~Input() { - Timer::remove(this); - } - - /// Paint input. - virtual void paint(Drawable &d) const; - - /// Clear selected area. - void clearSelection() { - text.erase(text.begin()+(pos = imin(start_sel,end_sel)),text.begin()+imax(start_sel,end_sel)); - start_sel = end_sel = pos; - } - - /// Copy selection to clipboard. - void copySelection() { - setClipboard(String(text.begin()+imin(start_sel,end_sel),text.begin()+imax(start_sel,end_sel))); - } - - /// Cut selection to clipboard. - void cutSelection() { - setClipboard(String(text.begin()+imin(start_sel,end_sel),text.begin()+imax(start_sel,end_sel))); - clearSelection(); - } - - /// Paste from clipboard. - void pasteSelection() { - String c = getClipboard(); - clearSelection(); - text.insert(text.begin()+pos,c.begin(),c.end()); - start_sel = end_sel = pos += (Size)c.size(); - } - - /// get character position corresponding to coordinates - Size findPos(int x, int y); - - /// Set text to be edited. - template void setText(const STR text) { this->text = text; setDirty(); }; - /// Get the entered text. If you need it longer, copy it immediately. - const String& getText() { return text; }; - - /// Handle text input. - virtual bool keyDown(const Key &key); - - /// Handle mouse input. - virtual bool mouseDown(int x, int y, MouseButton button); - - /// Handle mouse input. - virtual bool mouseDragged(int x, int y, MouseButton button); - - /// Timer callback function - virtual Ticks timerExpired(Ticks time) - { blink = !blink; setDirty(); return 30; } - -}; - -class ToplevelWindow; -/// Callbacks for window events. -struct ToplevelWindow_Callback { -public: - /// The window has been asked to be closed. - /** Return \c false in order to block the requested action. Do not do any - * deallocation here, as other callbacks may abort the close process. - */ - virtual bool windowClosing(ToplevelWindow *win) = 0; - - /// The window will been closed. - /** Now it is safe to deallocate all external resources that applications - * may have associated with this window, like registering this window - * with external callbacks. - */ - virtual void windowClosed(ToplevelWindow *win) = 0; - virtual ~ToplevelWindow_Callback() {} -}; - -/// An actual decorated window. -class ToplevelWindow : public BorderedWindow, public ActionEventSource_Callback { -protected: - /// Title text - String title; - - /// Drag base - int dragx, dragy; - - /// List of registered event handlers. - std::list closehandlers; - - /// System menu (top left) - Menu *systemMenu; - -public: - /// Create a new GUI Frame with title bar, border and close button - template ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title); - - /// Call cleanup handlers - ~ToplevelWindow() { - std::list::iterator i = closehandlers.begin(); - bool end = (i == closehandlers.end()); - while (!end) { - ToplevelWindow_Callback *c = *i; - ++i; - end = (i == closehandlers.end()); - c->windowClosed(this); - } - } - - /// Menu callback function - virtual void actionExecuted(ActionEventSource *src, const String &item) { - if (item == String("Close")) close(); - } - - /// Add a window event handler. - void addCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.push_back(handler); } - - /// Remove a window event handler. - void removeCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.remove(handler); } - - virtual void paint(Drawable &d) const; - virtual bool mouseDown(int x, int y, MouseButton button); - virtual bool mouseDoubleClicked(int x, int y, MouseButton button) { - if (button == Left && x < 32 && x > 6 && y > 4 && y < 31) { - close(); - return true; - } - BorderedWindow::mouseClicked(x,y,button); - return true; - } - virtual bool mouseUp(int x, int y, MouseButton button) { - if (button == Left && dragx >= 0 && dragy >= 0) { - dragx = dragy = -1; - return true; - } - BorderedWindow::mouseUp(x,y,button); - return true; - } - virtual bool mouseDragged(int x, int y, MouseButton button) { - if (button == Left && dragx >= 0 && dragy >= 0) { - move(x-dragx+this->x,y-dragy+this->y); - return true; - } - BorderedWindow::mouseDragged(x,y,button); - return true; - } - virtual bool mouseMoved(int x, int y) { - BorderedWindow::mouseMoved(x,y); - return true; - } - - /// Put window on top of all other windows without changing their relative order - virtual bool raise() { - Window *last = parent->children.back(); - parent->children.remove(this); - parent->children.push_back(this); - if (last != this) { - focusChanged(true); - last->focusChanged(false); - } - return true; - } - - /// Set a new title. - template void setTitle(const STR title) { this->title = title; setDirty(); } - /// Retrieve current title. - const String& getTitle() { return title; } - - /// Close window. - void close() { - bool doit = true; - std::list::iterator i = closehandlers.begin(); - bool end = (i == closehandlers.end()); - while (!end) { - ToplevelWindow_Callback *c = *i; - ++i; - end = (i == closehandlers.end()); - doit = doit && c->windowClosing(this); - } - if (doit) delete this; - } -}; - -/// A floating temporary window that is not restricted by it's parent's area. -/** They have a parent which displays them, - * but that parent is not their real parent in the window hierarchy: They are always top-level elements, thus - * they are not clipped to their logical parent's area, they can freely overlay any part of the screen. - * As another consequence, they are not automatically deleted when their logical parent is deleted. - * - * You should observe the following points: - * \li TransientWindows behave mostly as if their logical parent was their true parent, but are not - * restricted to it's area - * \li TransientWindows are deleted automatically when the ToplevelWindow is deleted in which their logical - * parent resides; do NOT delete them in your destructor or bad things will happen - * \li only the logical parent object can show/hide a TransientWindow at will - * \li it will close automatically upon clicking other GUI elements, \em except for the - * logical parent and it's children - */ -class TransientWindow : public Window, Window_Callback, ToplevelWindow_Callback { -protected: - /// The true parent window. - Window *realparent; - - /// User selected position relative to logical parent. - int relx, rely; - -public: - /// Handle automatic hiding - virtual void focusChanged(bool gained) { - Window::focusChanged(gained); - if (isVisible() && !gained) { - if (realparent->hasFocus()) raise(); - else setVisible(false); - } - } - - /// Handle automatic delete - void windowClosed(ToplevelWindow *win) { - delete this; - } - - /// No-op - bool windowClosing(ToplevelWindow *win) { return true; } - - /// Create a transient window with given position and size - /** \a parent is the logical parent. The true parent object is - * always the screen the logical parent resides on. */ - TransientWindow(Window *parent, int x, int y, int w, int h) : - Window(parent->getScreen(),x+parent->getScreenX(),y+parent->getScreenY(),w,h), - realparent(parent), relx(x), rely(y) { - Window *p = realparent, *last = NULL, *last2 = NULL; - while (p != NULL) { - p->addWindowHandler(this); - last2 = last; - last = p; - p = p->getParent(); - } - dynamic_cast(last2)->addCloseHandler(this); - } - - ~TransientWindow() { - Window *p = realparent, *last = NULL, *last2 = NULL; - while (p != NULL) { - p->removeWindowHandler(this); - last2 = last; - last = p; - p = p->getParent(); - } - dynamic_cast(last2)->removeCloseHandler(this); - } - - virtual void move(int x, int y) { relx = x; rely = y; - Window::move(x+realparent->getScreenX(),y+realparent->getScreenY()); } - virtual int getX() const { return x-realparent->getScreenX(); } - virtual int getY() const { return y-realparent->getScreenY(); } - virtual void setVisible(bool v) { if (v) raise(); Window::setVisible(v); } - virtual void windowMoved(Window *src, int x, int y) { move(relx,rely); } - - /// Put window on top of all other windows without changing their relative order - virtual bool raise() { - Window *last = parent->children.back(); - parent->children.remove(this); - parent->children.push_back(this); - if (last != this) { - focusChanged(true); - last->focusChanged(false); - } - return true; - } - -}; - -/// A popup menu. -/** Popup menus are used as context menus or as part of a menu bar. Menus are not visible when created. - * Menus have a name which can be used in event handlers to identify it, and it is used in Menubars as well. - * - * Currently, menu entries are not interpreted in any way. This may change in the future. To ensure upwards - * compatibility, avoid the \c '&' character in menu entries, since it may have a special meaning in future - * versions. Menus use the Font named "menu". - * - * Please note the general remarks in GUI::TransientWindow - */ -class Menu : public TransientWindow, public ActionEventSource { -protected: - /// List of menu items (displayed text) - std::vector items; - - /// Currently selected menu item. - /** Can be -1 if no item is currently active. */ - int selected; - - /// Flag to skip the first mouseUp-event - bool firstMouseUp; - - /// Where we grabbed the mouse from. - Window *mouseTakenFrom; - - /// Selects menu item at position (x,y). - /** \a selected is set to -1 if there is no active item at that location. */ - virtual void selectItem(int x, int y) { - y -= 2; - selected = -1; - const int height = Font::getFont("menu")->getHeight()+2; - std::vector::iterator i; - for (i = items.begin(); i != items.end() && y > 0; ++i) { - selected++; - if ((*i).size() > 0) y -= height; - else y -= 12; - } - if (y > 0 || (selected >= 0 && items[selected].size() == 0)) selected = -1; - } - - virtual Size getPreferredWidth() { - Size width = 0; - const Font *f = Font::getFont("menu"); - std::vector::iterator i; - for (i = items.begin(); i != items.end() && y > 0; ++i) { - Size newwidth = f->getWidth(*i); - if (newwidth > width) width = newwidth; - } - return width+39; - } - - virtual Size getPreferredHeight() { - Size height = 0; - const Size h = Font::getFont("menu")->getHeight()+2; - std::vector::iterator i; - for (i = items.begin(); i != items.end() && y > 0; ++i) { - height += ((*i).size() > 0?h:12); - } - return height+6; - } - -public: - /// Create a menu with given position - /** Size is determined dynamically. \a parent is the logical parent. The true parent object is - * always the screen the logical parent resides on. */ - template Menu(Window *parent, int x, int y, const STR name) : - TransientWindow(parent,x,y,4,4), ActionEventSource(name), selected(-1) - { setVisible(false); } - - ~Menu() { - setVisible(false); - } - - /// Paint button. - virtual void paint(Drawable &d) const; - - /// Highlight current item. - virtual bool mouseMoved(int x, int y) { - selectItem(x,y); - return true; - } - - /// Highlight current item. - virtual bool mouseDragged(int x, int y, MouseButton b) { - selectItem(x,y); - return true; - } - - virtual bool mouseDown(int x, int y, MouseButton button) { return true; } - - /// Possibly select item. - virtual bool mouseUp(int x, int y, MouseButton button) { - selectItem(x,y); - if (firstMouseUp) firstMouseUp = false; - else setVisible(false); - execute(); - return true; - } - - /// Handle keyboard input. - virtual bool keyDown(const Key &key) { - if (key.special == Key::Up) selected--; - else if (key.special == Key::Down) selected++; - else if (key.special == Key::Enter) { execute(); return true; } - else if (key.special == Key::Escape) { setVisible(false); return true; } - else return true; - if (items[selected].size() == 0 && items.size() > 1) return keyDown(key); - if (selected < 0) selected = (int)(items.size()-1); - if (selected >= (int)items.size()) selected = 0; - return true; - } - - - /// Add a menu item at end. An empty string denotes a separator. - template void addItem(const T item) { - items.push_back(String(item)); - resize(getPreferredWidth(),getPreferredHeight()); - } - - /// Remove an existing menu item. - template void removeItem(const T item) { - const String s(item); - std::vector::iterator i = items.begin(); - while (i != items.end() && s != (*i)) ++i; - if (i != items.end()) items.erase(i); - resize(getPreferredWidth(),getPreferredHeight()); - } - - virtual void setVisible(bool v) { - TransientWindow::setVisible(v); - if (v) { - parent->mouseChild = this; - raise(); - firstMouseUp = true; - } - } - - /// Execute menu item. - void execute() { - if (selected >= 0) { - setVisible(false); - executeAction(items[selected]); - } - } -}; - -/// A push button -/** Buttons have 3D appearance and can have any child widget as content. - * There are convenience constructors for common forms of buttons. - */ -class Button : public BorderedWindow, public ActionEventSource { -protected: - /// \c true, if button is currently pressed down. - bool pressed; - -public: - /// Create a button with given position and size - Button(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource("GUI::Button"), pressed(0) {} - - /// Create a text button. - /** If a size is specified, text is centered. Otherwise, button size is adjusted for the text. */ - template Button(Window *parent, int x, int y, const T text, int w = -1, int h = -1); - - /// Paint button. - virtual void paint(Drawable &d) const; - - /// Press button. - virtual bool mouseDown(int x, int y, MouseButton button) { - border_left = 7; border_right = 5; border_top = 7; border_bottom = 3; - pressed = true; - return true; - } - - /// Release button. - virtual bool mouseUp(int x, int y, MouseButton button) { - border_left = 6; border_right = 6; border_top = 5; border_bottom = 5; - pressed = false; - return true; - } - - /// Handle mouse activation. - virtual bool mouseClicked(int x, int y, MouseButton button) { - if (button == Left) { - executeAction(); - return true; - } - return false; - } - - /// Handle keyboard input. - virtual bool keyDown(const Key &key); - - /// Handle keyboard input. - virtual bool keyUp(const Key &key); - -}; - -/// A menu bar at the top of a ToplevelWindow -/** Menu bars aggregate several Menus. They have a simple border at the bottom. If your application - * has a work area with 3D sunken look, place it so that it overlaps the menu by one row. - * - * As with Menus, avoid the character \c '&' in Menu names as it may - * have a special meaning in future versions. Menubars use the Font named "menu". - */ -class Menubar : public Window, public ActionEventSource, ActionEventSource_Callback { -protected: - /// Currently activated menu index. - int selected; - - /// Horizontal position of next menu. - int lastx; - - /// List of Menus. - std::vector menus; - -public: - /// Create a menubar with given position and size - /** Height is autocalculated from font size */ - Menubar(Window *parent, int x, int y, int w) : Window(parent,x,y,w,Font::getFont("menu")->getHeight()+5), ActionEventSource("GUI::Menubar"), selected(-1), lastx(0) {} - - /// Add a Menu. - template void addMenu(const STR name) { - const String n(name); - menus.push_back(new Menu(this,lastx,height-2,n)); - menus.back()->addActionHandler(this); - lastx += Font::getFont("menu")->getWidth(n)+14; - } - - /// Add a Menuitem. - template void addItem(int index, const STR name) { menus[index]->addItem(name); } - - /// Remove a Menuitem. - template void removeItem(int index, const STR name) { menus[index]->removeItem(name); } - - /// Paint menubar. - virtual void paint(Drawable &d) const; - - /// Open menu. - virtual bool mouseDown(int x, int y, MouseButton button) { - int oldselected = selected; - if (selected >= 0 && !menus[selected]->isVisible()) oldselected = -1; - if (selected >= 0) menus[selected]->setVisible(false); - if (x < 0 || x >= lastx) return true; - for (selected = (int)(menus.size()-1); menus[selected]->getX() > x; selected--) {}; - if (oldselected == selected) selected = -1; - else menus[selected]->setVisible(true); - return true; - } - - /// Handle keyboard input. - virtual bool keyDown(const Key &key) { return true; }; - - /// Handle keyboard input. - virtual bool keyUp(const Key &key) { return true; }; - - virtual void actionExecuted(ActionEventSource *src, const String &arg) { - std::list::iterator i = actionHandlers.begin(); - bool end = (i == actionHandlers.end()); - while (!end) { - ActionEventSource_Callback *c = *i; - ++i; - end = (i == actionHandlers.end()); - c->actionExecuted(src,arg); - } - } -}; - -/// A checkbox -/** Checkboxes can have any child widget as content. - * There are convenience constructors for common forms of checkboxes. - */ -class Checkbox : public BorderedWindow, public ActionEventSource { -protected: - /// \c true, if checkbox is currently selected. - bool checked; - -public: - /// Create a checkbox with given position and size - Checkbox(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource("GUI::Checkbox"), checked(0) {} - - /// Create a checkbox with text label. - /** If a size is specified, text is centered. Otherwise, checkbox size is adjusted for the text. */ - template Checkbox(Window *parent, int x, int y, const T text, int w = -1, int h = -1); - - /// Paint checkbox. - virtual void paint(Drawable &d) const; - - /// Change checkbox state. - virtual void setChecked(bool checked) { this->checked = checked; } - - /// Get checkbox state. - virtual bool isChecked() { return checked; } - - /// Press checkbox. - virtual bool mouseDown(int x, int y, MouseButton button) { - checked = !checked; - return true; - } - - /// Release checkbox. - virtual bool mouseUp(int x, int y, MouseButton button) { - execute(); - return true; - } - - /// Handle keyboard input. - virtual bool keyDown(const Key &key); - - /// Handle keyboard input. - virtual bool keyUp(const Key &key); - - /// Execute handlers. - virtual void execute() { - String arg(name); - if (!checked) arg.insert(arg.begin(),'!'); - executeAction(arg); - } -}; - -class Frame; - -/// A radio box. -/** Radio boxes can have any child widget as content. - * There are convenience constructors for common forms of radio boxes. - */ -class Radiobox : public BorderedWindow, public ActionEventSource { -protected: - /// \c true, if radio box is currently selected. - bool checked; - -public: - /// Create a radio box with given position and size - Radiobox(Frame *parent, int x, int y, int w, int h); - - /// Create a radio box with text label. - /** If a size is specified, text is centered. Otherwise, checkbox size is adjusted for the text. */ - template Radiobox(Frame *parent, int x, int y, const T text, int w = -1, int h = -1); - - /// Paint radio box. - virtual void paint(Drawable &d) const; - - /// Change radio box state. - virtual void setChecked(bool checked) { this->checked = checked; } - - /// Get radio box state. - virtual bool isChecked() { return checked; } - - /// Press radio box. - virtual bool mouseDown(int x, int y, MouseButton button) { - checked = true; - return true; - } - - /// Release checkbox. - virtual bool mouseUp(int x, int y, MouseButton button) { - executeAction(); - return true; - } - - /// Handle keyboard input. - virtual bool keyDown(const Key &key); - - /// Handle keyboard input. - virtual bool keyUp(const Key &key); -}; - -/// A rectangular 3D sunken frame -/** These can be used as generic grouping elements and also serve as aggregators for RadioBoxes. - */ -class Frame : public BorderedWindow, public ActionEventSource, protected ActionEventSource_Callback { -protected: - friend class Radiobox; - - /// Currently selected radio box. - int selected; - - /// Label of frame. - String label; - - /// Execute handlers. - virtual void actionExecuted(ActionEventSource *src, const String &arg) { - for (std::list::iterator i = children.begin(); i != children.end(); ++i) { - Radiobox *r = dynamic_cast(*i); - if (r != NULL && src != dynamic_cast(r)) r->setChecked(false); - } - executeAction(src->getName()); - } - -public: - /// Create a non-labeled frame with given position and size - Frame(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,5,5,5,5), ActionEventSource("GUI::Frame"), selected(0) {} - - /// Create a frame with text label. - template Frame(Window *parent, int x, int y, int w, int h, const T text) : - BorderedWindow(parent,x,y,w,h,5,Font::getFont("default")->getHeight()+2,5,5), - ActionEventSource(text), selected(0), label(text) { } - - /// Paint frame. - virtual void paint(Drawable &d) const; - -}; - -/// A message box with a single "Close" button. -class MessageBox : public GUI::ToplevelWindow { -protected: - Label *message; - Button *close; -public: - /// Create a new message box - template MessageBox(Screen *parent, int x, int y, int width, const STR title, const STR text) : - ToplevelWindow(parent, x, y, width, 1, title) { - message = new Label(this, 5, 5, text, width-10); - close = new GUI::Button(this, width/2-40, 10, "Close", 70); - close->addActionHandler(this); - setText(text); - } - - /// Set a new text. Size of the box is adjusted accordingly. - template void setText(const STR text) { - message->setText(text); - close->move(width/2-40, 20+message->getHeight()); - resize(width, message->getHeight()+100); - } -}; - -template ToplevelWindow::ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title) : - BorderedWindow(parent, x, y, w, h, 6, 33, 6, 3), title(title), - dragx(-1), dragy(-1), closehandlers(), systemMenu(new Menu(this,-1,-2,"System Menu")) { - systemMenu->addItem("Move"); - systemMenu->addItem("Resize"); - systemMenu->addItem(""); - systemMenu->addItem("Minimize"); - systemMenu->addItem("Maximize"); - systemMenu->addItem("Restore"); - systemMenu->addItem(""); - systemMenu->addItem("Close"); - systemMenu->addActionHandler(this); -} - -template Button::Button(Window *parent, int x, int y, const STR text, int w, int h) : - BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource(text), pressed(0) -{ - - Label *l = new Label(this,0,0,text); - if (width < 0) resize(l->getWidth()+border_left+border_right+10,height); - if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+6); - l->move((width-border_left-border_right-l->getWidth())/2, - (height-border_top-border_bottom-l->getHeight())/2); -} - -template Checkbox::Checkbox(Window *parent, int x, int y, const STR text, int w, int h) : - BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0) -{ - Label *l = new Label(this,0,0,text); - if (width < 0) resize(l->getWidth()+border_left+border_right+4,height); - if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4); - l->move((width-border_left-border_right-l->getWidth())/2, - (height-border_top-border_bottom-l->getHeight())/2); -} - -template Radiobox::Radiobox(Frame *parent, int x, int y, const STR text, int w, int h) : - BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0) -{ - Label *l = new Label(this,0,0,text); - if (width < 0) resize(l->getWidth()+border_left+border_right+4,height); - if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4); - l->move((width-border_left-border_right-l->getWidth())/2, - (height-border_top-border_bottom-l->getHeight())/2); - addActionHandler(parent); -} - -}; - -#endif +/** \mainpage gui::tk - framework-agnostic C++ GUI toolkit + * + * \section i Introduction + * + * gui::tk is a simple one-file C++ GUI toolkit for use with arbitrary + * memory framebuffers. + * + * \section f Features + * + * \li small source and binary code size + * \li reasonable performance and memory usage + * \li comfortable usage + * \li suitable for embedded usage: integer math only + * \li extensibility via OO + * \li non-intrusive: can be integrated with any event mechanism of your liking + * \li no dependencies apart from standards-conformant ANSI C++ (including a little STL) + * \li support for different encodings, single- and multibyte + * \li flexible font support + * + * \section o Overview + * + * The toolkit draws on a surface you provide, using any size or pixel format. + * Create a GUI::Screen with the buffer to draw on, then pass that object + * (or a GUI::Window created from it) to all other widgets' constructors. + * + * It doesn't provide an own event loop. Instead, it relies on you passing events + * and updating the screen regularly. This way, it can easily be integrated with + * any event loop available (SDL, Qt, glib, X11, Win32, selfmade, ...) + * + * Many functions and concepts were taken from other well-known toolkits, so if you + * know Qt, Java or wxWindows, you may encounter (intentional) similarities. However, + * simplicity of code has been given priority over maximum optimization and pixel-exact + * replication of their appearance. + * + * A note about font support and encodings: All text-related functions use templates to + * support any encoding. Fonts define the charset. + * + * \section g Getting Started + * + * gui::tk contains an SDL adapter, so if your program is already using SDL, + * things are really easy. The rough sequence to get up and running is: + * + * \code + * // setup a suitable video mode with SDL + * SDL_surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE); + * + * // add a default font, you will most probably need it + * GUI::Font::addFont("default",new GUI::BitmapFont(testfont,14,10)); + * + * // create the root-level screen object, the parent of all top-level windows + * GUI::ScreenSDL guiscreen(screen); + * + * // create any amount of toplevel windows you like + * GUI::ToplevelWindow *frame = new GUI::ToplevelWindow(&guiscreen, 205, 100, 380, 250, "gui::tk example"); + * + * // add some GUI elements to the toplevel window + * GUI::Button *b = new GUI::Button(frame,8,20,"Quit"); + * + * // Define and add an event handler + * struct quit : public GUI::ActionEventSource_Callback { + * void actionExecuted(GUI::ActionEventSource *b, const GUI::String &arg) { + * exit(0); + * } + * } ex; + * b->addActionHandler(&ex); + * + * // Enter an event loop, calling update() regularly. + * SDL_Event event; + * while (1) { + * while (SDL_PollEvent(&event)) { + * if (!guiscreen.event(event)) { // gui::tk didn't handle that event + * if (event.type == SDL_QUIT) exit(0); + * } + * } + * + * guiscreen.update(4); // 4 ticks = 40ms + * SDL_UpdateRect(screen, 0, 0, screen->w, screen->h); + * + * SDL_Delay(40); // wait 40ms + * } + * \endcode + * + * Look at gui_tk.h for more detailed documentation and reference of all classes. + * + * A test program that shows off the capabilities of gui::tk is available as part of gui_tk.cpp. + * + * \section l License + * + * Copyright (C) 2005-2007 Jörg Walter + * + * gui::tk 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 3 of the License, or + * (at your option) any later version. + * + * gui::tk 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, see + */ + +/* $Id: gui_tk.h,v 1.6 2009-05-17 15:28:05 c2woody Exp $ */ + +#ifndef GUI__TOOLKIT_H +#define GUI__TOOLKIT_H + +#define imin(x,y) ((x)<(y)?(x):(y)) +#define imax(x,y) ((x)>(y)?(x):(y)) +#define isign(x) (((x)<0?-1:1)) + +/** \file + * \brief Header file for gui::tk. + * + * All you need to do is to include "gui_tk.h". If you want SDL support, then include \c SDL.h first. + */ + +#ifdef _MSC_VER +typedef signed __int8 int8_t; +typedef signed __int16 int16_t; +typedef signed __int32 int32_t; +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int32 uint32_t; +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +/// This namespace contains all GUI toolkit classes, types and functions. +namespace GUI { + +/// ARGB 24-bit color value: (a<<24)|(r<<16)|(g<<8)|(b) +typedef uint32_t RGB; + +/// Collection of all color-related constants and functions. +namespace Color { +/// A fully transparent pixel. +const RGB Transparent = 0x00ffffff; + +/// A fully opaque black pixel. +const RGB Black = 0xff000000; + +/// A fully opaque white pixel. +const RGB White = 0xffffffff; + +/// Alpha mask. +const RGB AlphaMask = 0xff000000; + +/// Offset of alpha value. +const int AlphaShift = 24; + +/// Red mask. +const RGB RedMask = 0x00ff0000; + +/// Full-intensity red. +const RGB Red = Black|RedMask; + +/// Offset of red value. +const int RedShift = 16; + +/// Green mask. +const RGB GreenMask = 0x0000ff00; + +/// Full-intensity green. +const RGB Green = Black|GreenMask; + +/// Offset of green value. +const int GreenShift = 8; + +/// Blue mask. +const RGB BlueMask = 0x000000ff; + +/// Full-intensity blue. +const RGB Blue = Black|BlueMask; + +/// Offset of blue value. +const int BlueShift = 0; + +/// Full-intensity Magenta. +const RGB Magenta = Red|Blue; + +/// Magenta mask. +const RGB MagentaMask = RedMask|BlueMask; + +/// Full-intensity Cyan. +const RGB Cyan = Green|Blue; + +/// Cyan mask. +const RGB CyanMask = GreenMask|BlueMask; + +/// Full-intensity Yellow. +const RGB Yellow = Red|Green; + +/// Yellow mask. +const RGB YellowMask = RedMask|GreenMask; + +/// 50% grey +const RGB Grey50 = 0xff808080; + +/// Background color for 3D effects. May be customized. +extern RGB Background3D; + +/// Light highlight color for 3D effects. May be customized. +extern RGB Light3D; + +/// Dark highlight color (shadow) for 3D effects. May be customized. +extern RGB Shadow3D; + +/// Generic border color for highlights or similar. May be customized. +extern RGB Border; + +/// Foreground color for regular content (mainly text). May be customized. +extern RGB Text; + +/// Background color for inactive areas. May be customized. +extern RGB Background; + +/// Background color for selected areas. May be customized. +extern RGB SelectionBackground; + +/// Foreground color for selected areas. May be customized. +extern RGB SelectionForeground; + +/// Background color for inputs / application area. May be customized. +extern RGB EditableBackground; + +/// Title bar color for windows. May be customized. +extern RGB Titlebar; + +/// Title bar text color for windows. May be customized. +extern RGB TitlebarText; + +/// Convert separate r, g, b and a values (each 0-255) to an RGB value. +static inline RGB rgba(int r, int g, int b, int a=0) { + return (((r&255)<>Color::RedShift); } +/// Get green value (0-255) from an RGB value. +static inline int G(RGB val) { return ((val&Color::GreenMask)>>Color::GreenShift); } +/// Get blue value (0-255) from an RGB value. +static inline int B(RGB val) { return ((val&Color::BlueMask)>>Color::BlueShift); } +/// Get alpha value (0-255) from an RGB value. +static inline int A(RGB val) { return ((val&Color::AlphaMask)>>Color::AlphaShift); } + +} + +/// Identifies a mouse button. +enum MouseButton { NoButton, Left, Right, Middle, WheelUp, WheelDown, WheelLeft, WheelRight }; + +/// A type which holds size values that can be very large. +typedef unsigned int Size; + +/// A type which holds a single character. Large enough for Unicode. +typedef uint32_t Char; + +/// A type which holds a number of timer ticks. +typedef unsigned int Ticks; + +/// Identifies a keyboard key. +class Key { +public: + /// Translated character value. + /** No encoding is implied. The Font that is used to display this character + * determines the appearance. */ + Char character; + /// Special keyboard keys. + /** It is modeled after PC keyboards. When you feed keyboard events to a GUI::Screen, + * try to map native keys to this set. Some special keys have a character value. Set + * to \c None if the key has no special meaning. */ + enum Special { + None, + F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, + Up, Down, Left, Right, Backspace, Tab, Backtab, Enter, Escape, + Home, End, PageUp, PageDown, Insert, Delete, Menu, + Print, Pause, Break, CapsLock, NumLock, ScrollLock, + Alt, Ctrl, Shift, Windows + } special; + /// Set if the Shift key is currently down. + bool shift; + /// Set if the Ctrl key is currently down. + bool ctrl; + /// Set if the Alt (PC) or Meta (classic Unix) key is currently down. + bool alt; + /// Set if the "Windows"/Meta (PC) or Super (classic Unix) key is currently down. + /** Do not depend too heavily on this, as many keyboards and systems do not have such a key. */ + bool windows; + + /// Constructor. + Key(int character, Special special, bool shift, bool ctrl, bool alt, bool windows) : + character(character), special(special), + shift(shift), ctrl(ctrl), alt(alt), windows(windows) {} +}; + +class Drawable; +class String; + +/** \brief Converts between strings of various types and String objects. + * + * It is used to deal with string encoding. It is intended to be used with template + * specializations. Having such a specialization means you can feed the corresponding type to + * all functions that expect a string -- without any conversion. You can add specializations + * yourself in your program's code to deal with unsupported types. + * + * As an example, see the std::string version. + * + * Encodings, as opposed to character sets, define how bytes map to character values. + * ASCII, for example, has an \em encoding where each byte is one character, while the + * ASCII \em character \em set says that values 0-127 are valid and 65 is the upper case + * letter 'A'. UTF-8 has 1-6 bytes per character, and the character set is unicode. + * + * GUI::Font deals with the character set, and this class encapsulates encodings. + * + */ +template class NativeString { +protected: + friend class String; + + /// Converts a native string into a String object + static void getString(String &dest, const STR &src) { STR::_this_string_type_is_not_supported_(); } + + /** \brief Converts a string object to native representation. + * + * If some characters cannot be converted, they should silently be skipped. Apart from that, + * \c nativeString(stringNative(String(),X)) should be value-equal to \c X. + */ + static STR& getNative(const String &src) { STR::_this_string_type_is_not_supported_();return*new STR(); } +}; + +template class NativeString { +protected: + friend class String; + static void getString(String &dest, const STR *src); + static STR* getNative(const String &src); +}; + +template class NativeString : public NativeString {}; +template class NativeString : public NativeString {}; +template class NativeString : public NativeString {}; + +/// 'less-than' comparison between pointer addresses +struct ltvoid { bool operator()(const void* s1, const void* s2) const { return s1 < s2; } }; + +/** \brief Simple STL-based string class. + * + * This is intended as internal helper class to allow gui::tk to work with any kind of + * string objects. While you can use this in normal application code, you should better + * use the string class of your application framework (like Qt). If you don't have any, + * use std::string. + * + * It supports arbitrary characters, no character set is implied. Conversion from/to usual + * string types like \c char* is automatic but not thread-safe for non-class types. + */ +class String : public std::vector { +protected: + template friend class NativeString; + /// Simple pointer encapsulation class for memory management. + class Native { public: virtual ~Native() {}; }; + /// Simple pointer encapsulation class for memory management. + template class NativeArray: public Native { + STR *data; + public: + NativeArray(STR *data) : data(data) {} + virtual ~NativeArray() { delete[] data; } + }; + template class NativeObject: public Native { + STR *data; + public: + NativeObject(STR *data) : data(data) {} + virtual ~NativeObject() { delete data; } + }; + +private: + /// Semi-static memory management for pointer string types. + mutable std::map strings; + +protected: + /// Manage a native string's memory. + void addNative(Native *dest) const { + const class std::type_info &type = typeid(dest); + if (strings[&type] != NULL) delete strings[&type]; + strings[&type] = dest; + } + +public: + /// Allocate a new String initialized from native string. + template String(const STR& src) { NativeString::getString(*this, src); } + + /// Taken from STL. + template String(InputIterator a, InputIterator b) : std::vector(a,b) {} + + /// Copy-constructor + String(const String &src) : std::vector(src), strings() {}; + + /// Allocate a new String. + String() { } + + /// Deallocate a String. + ~String() { + for (std::map::iterator i = strings.begin(); i != strings.end(); ++i) + delete (*i).second; + }; + + /// Convert to native representation. + /** For pointer types like \c char*, the returned pointer is usually only valid as long as + * this object exists, or until it is modified and cast to the same type again. */ + template operator T() const { return NativeString::getNative(*this); } + + /// Compare with native representation. + template bool operator==(const T &src) const { return *this == String(src); } + /// Compare with other Strings. + bool operator==(const String &src) const { return *(std::vector*)this == src; } + + /// Compare with native representation. + template bool operator!=(const T &src) const { return *this != String(src); } + /// Compare with other Strings. + bool operator!=(const String &src) const { return *(std::vector*)this != src; } +}; + +template void NativeString::getString(String &dest, const STR* src) { + Size strlen = 0; + while (src[strlen]) strlen++; + dest.resize(strlen); + for (strlen = 0; src[strlen]; strlen++) dest[strlen] = (sizeof(STR)==1?(unsigned char)src[strlen]:sizeof(STR)==2?(unsigned short)src[strlen]:src[strlen]); +} + +template STR* NativeString::getNative(const String &src) { + Size strlen = (Size)src.size(); + STR* dest = new STR[strlen+1]; + dest[strlen] = 0; + for (; strlen > 0; strlen--) dest[strlen-1] = src[strlen-1]; + src.addNative(new String::NativeArray(dest)); + return dest; +} + +template <> class NativeString { +protected: + friend class String; + static void getString(String &dest, const std::string *src) { + Size strlen = (Size)src->length(); + dest.resize(strlen); + for (Size i = 0; i< strlen; i++) dest[i] = (*src)[i]; + } + static std::string* getNative(const String &src) { + Size strlen = (Size)src.size(); + std::string* dest = new std::string(); + for (Size i = 0; i < strlen; i++) dest->append(1,src[i]); + src.addNative(new String::NativeObject(dest)); + return dest; + } +}; + +template <> class NativeString : public NativeString {}; + +template <> class NativeString { +protected: + friend class String; + static void getString(String &dest, const std::string &src) { + Size strlen = (Size)src.length(); + dest.resize(strlen); + for (Size i = 0; i< strlen; i++) dest[i] = src[i]; + } + static std::string& getNative(const String &src) { + Size strlen = (Size)src.size(); + std::string* dest = new std::string(); + for (Size i = 0; i < strlen; i++) dest->append(1,src[i]); + src.addNative(new String::NativeObject(dest)); + return *dest; + } +}; + +template <> class NativeString : public NativeString {}; + +class ToplevelWindow; +class Menu; +class TransientWindow; +class Screen; +class Window; + +/// Callback for window events. +struct Window_Callback { +public: + /// Called whenever this window changes position. + virtual void windowMoved(Window *win, int x, int y) = 0; + virtual ~Window_Callback() {} +}; + + +/** \brief A Window is a rectangular sub-area of another window. + * + * Windows are arranged hierarchically. A Window cannot leave its parent's + * area. They may contain their own buffer or share it with their parent. + * + * Usually, every GUI element is a subclass of Window. Note that this is + * \em not a GUI window with decorations like border and title bar. See ToplevelWindow + * for that. + */ +class Window { +protected: + friend class ToplevelWindow; + friend class TransientWindow; + friend class Menu; + + /// Width of the window. + int width; + /// Height of the window. + int height; + /// X position relative to parent. + int x; + /// Y position relative to parent. + int y; + + /// \c true if anything changed in this window or one of it's children + bool dirty; + + /// \c true if this window should be visible on screen. + bool visible; + + /// Parent window. + Window *const parent; + + /// Child window of last button-down event + /** It receives all drag/up/click/doubleclick events until an up event is received */ + Window *mouseChild; + + /// Child windows. + /** Z ordering is done in list order. The first element is the lowermost + * window. This window's content is below all children. */ + std::list children; + + /// List of registered event handlers. + std::list movehandlers; + + /// Register child window. + virtual void addChild(Window *child); + + /// Remove child window. + virtual void removeChild(Window *child); + + /// Mark this window and all parents as dirty. + void setDirty() { if (dirty) return; dirty = true; if (parent != NULL) parent->setDirty(); }; + + /// Replace clipboard content. + virtual void setClipboard(const String &s) { parent->setClipboard(s); }; + + /// Get clipboard content. + virtual const String& getClipboard() { return parent->getClipboard(); }; + + /// Default constructor. Only used in class Screen. Do not use. + Window(); + + /// Called whenever the focus changes. + virtual void focusChanged(bool gained) { + if (children.size() > 0) children.back()->focusChanged(gained); + } + +public: + + /// Add an event handler. + void addWindowHandler(Window_Callback *handler) { movehandlers.push_back(handler); } + + /// Remove an event handler. + void removeWindowHandler(Window_Callback *handler) { movehandlers.remove(handler); } + + /// Create a subwindow of the given parent window. + Window(Window *parent, int x, int y, int w, int h); + + /// Destructor. + virtual ~Window(); + + /// Resize this window to the given dimensions. + /** If that would move part of the window outside of this window's area, + * the outside area will silently be clipped while drawing. */ + virtual void resize(int w, int h); + /// Return this window's width + virtual int getWidth() const { return width; } + /// Return this window's height + virtual int getHeight() const { return height; } + + /// Move this window to the given position relative to the parent window's origin. + /** If that would move part of the window outside of this window's area, + * the outside area will silently be clipped while drawing. */ + virtual void move(int x, int y); + /// Return this window's X position relative to the parent's top left corner + virtual int getX() const { return x; } + /// Return this window's Y position relative to the parent's top left corner + virtual int getY() const { return y; } + /// Return this window's contents' X position relative to the screen's top left corner + virtual int getScreenX() const { return (parent == NULL?0:parent->getScreenX()+x); } + /// Return this window's contents' Y position relative to the screen's top left corner + virtual int getScreenY() const { return (parent == NULL?0:parent->getScreenY()+y); } + + /// Draw this window's content including all children. + virtual void paintAll(Drawable &d) const; + + /// Draw this window's content. + virtual void paint(Drawable &d) const {}; + + /// Show or hide this window. + /** By default, most windows are shown when created. Hidden windows do not receive any events. */ + virtual void setVisible(bool v) { visible = !!v; parent->setDirty(); } + + /// Returns \c true if this window is visible. + virtual bool isVisible() const { return (!parent || parent->isVisible()) && visible; } + + /// Return parent window. + /** May return NULL if this is the topmost window (the Screen). */ + Window *getParent() const { return parent; } + + /// Get the topmost window (the Screen) + Screen *getScreen(); + + /// Returns \c true if this window has currently the keyboard focus. + virtual bool hasFocus() const { return parent->hasFocus() && *parent->children.rbegin() == this; } + + /// Mouse was moved. Returns true if event was handled. + virtual bool mouseMoved(int x, int y); + /// Mouse was moved while a button was pressed. Returns true if event was handled. + virtual bool mouseDragged(int x, int y, MouseButton button); + /// Mouse was pressed. Returns true if event was handled. + virtual bool mouseDown(int x, int y, MouseButton button); + /// Mouse was released. Returns true if event was handled. + virtual bool mouseUp(int x, int y, MouseButton button); + /// Mouse was clicked. Returns true if event was handled. + /** Clicking means pressing and releasing the mouse button while not moving it. */ + virtual bool mouseClicked(int x, int y, MouseButton button); + /// Mouse was double-clicked. Returns true if event was handled. + virtual bool mouseDoubleClicked(int x, int y, MouseButton button); + + /// Key was pressed. Returns true if event was handled. + virtual bool keyDown(const Key &key); + /// Key was released. Returns true if event was handled. + virtual bool keyUp(const Key &key); + + /// Put this window on top of all it's siblings. Preserves relative order. + /** Returns true if the window accepts the raise request. */ + virtual bool raise() { + Window *last = parent->children.back(); + for (Window *cur = parent->children.back(); cur != this; cur = parent->children.back()) { + parent->children.remove(cur); + parent->children.push_front(cur); + } + if (last != this) { + focusChanged(true); + last->focusChanged(false); + } + parent->setDirty(); + return true; + } + + /// Put this window below all of it's siblings. Does not preserve relative order. + virtual void lower() { + parent->children.remove(this); + parent->children.push_front(this); + if (this != parent->children.back()) { + parent->children.back()->focusChanged(true); + focusChanged(false); + } + parent->setDirty(); + } + + /// Return the \p n th child + Window *getChild(int n) { + for (std::list::const_iterator i = children.begin(); i != children.end(); ++i) { + if (n--) return *i; + } + return NULL; + } + +}; + +/** \brief A Screen represents the framebuffer that is the final destination of the GUI. + * + * It's main purpose is to manage the current contents of the surface and to combine + * it with all GUI elements. You can't resize and move the screen. Requests to do so + * will be ignored. + * + * This is an abstract base class. You need to use a subclass which implements rgbToSurface + * and surfaceToRGB. + * + * To make things work, Screen needs events. Call the mouse and key event functions (see Window) + * whenever such an event occurs. Call update(void *surface, int ticks) regularly, if possible about + * every 40msec (25 fps). If nothing has changed, screen updates are quite fast. + */ +class Screen : public Window { +protected: + /// Screen buffer. + Drawable *const buffer; + + /// Clipboard. + String clipboard; + + /// Currently pressed mouse button. + MouseButton button; + + /// Store a single RGB triple (8 bit each) as a native pixel value and advance pointer. + virtual void rgbToSurface(RGB color, void **pixel) = 0; + + /// Map a single framebuffer pixel to an RGB value. + virtual RGB surfaceToRGB(void *pixel) = 0; + + /// Create a new screen with the given characteristics. + Screen(Size width, Size height); + + /// Create a new screen from the given GUI::Drawable. + Screen(Drawable *d); + +public: + /// Destructor. + virtual ~Screen(); + + /// Set clipboard content. + template void setClipboard(const STR s) { this->setClipboard(String(s)); } + + /// Set clipboard content. + virtual void setClipboard(const String &s) { clipboard = s; } + + /// Get clipboard content. + virtual const String& getClipboard() { return clipboard; } + + /// Do nothing. + virtual void resize(int w, int h); + + /// Do nothing. + virtual void move(int x, int y); + + /// Screen has always focus. + virtual bool hasFocus() const { return true; } + + /// Update the given surface with this screen's content, fully honouring the alpha channel. + /** \p ticks can be set to a different value depending on how much time has passed. Timing + * doesn't need to be perfect, but try to call this at least every 40 msec. Each tick + * amounts to about 10 msec. Returns the number of ticks until the next event is scheduled, or + * 0 if none. */ + Ticks update(void *surface, Ticks ticks = 1); + + /// Default: clear screen. + virtual void paint(Drawable &d) const; +}; + +class Timer; + +/// Timer callback type +struct Timer_Callback { +public: + /// The timer has expired. + /** Callbacks for timers take one parameter, the number of ticks since + * application start. Note that this value may wrap after a little less + * than 500 days. If you want callbacks to be called again, return the + * delay in ticks relative to the scheduled time of this + * callback (which may be earlier than now() ). Otherwise return 0. */ + virtual Ticks timerExpired(Ticks time) = 0; + virtual ~Timer_Callback() {} +}; + +/** \brief Timing service. + * Time is measured in ticks. A tick is about 10 msec. + * + * Note that this is not suitable as a high-accuracy timing service. Timer + * events can be off by many ticks, and a tick may be slightly more or + * slightly less than 10 msec. Because of that, Timers are only intended for + * simple animation effects, input timeouts and similar things. + * + */ +class Timer { +protected: + /// Number of ticks since application start. + static Ticks ticks; + + /// Compare two integers for 'less-than'. + struct ltuint { bool operator()(Ticks i1, Ticks i2) const { + return (i1 < i2); + } }; + + /// Active timers. + static std::multimap timers; + +public: + /// Advance time and check for expired timers. + static void check(Ticks ticks); + + /// Add a timed callback. \p ticks is a value relative to now(). + /** \p cb is not copied. */ + static void add(Timer_Callback *cb, const Ticks ticks) { timers.insert(std::pair(ticks+Timer::ticks,cb)); } + + static void remove(const Timer_Callback *const cb); + + /// Return current time (ticks since application start) + static Ticks now() { return ticks; } + + /// Return number of ticks until next scheduled timer or 0 if no timers + static Ticks next(); +}; + + +/** \brief A 24 bit per pixel RGB framebuffer aligned to 32 bit per pixel. + * + * Warning: This framebuffer type varies with CPU endiannes. It is meant as + * a testing/debugging tool. + */ +class ScreenRGB32le : public Screen { +protected: + /// Map a single RGB triple (8 bit each) to a native pixel value. + virtual void rgbToSurface(RGB color, void **pixel) { RGB **p = (RGB **)pixel; **p = color; (*p)++; }; + + /// Map a single surface pixel to an RGB value. + virtual RGB surfaceToRGB(void *pixel) { return *(RGB*)pixel; }; +public: + ScreenRGB32le(Size width, Size height) : Screen(width,height) {}; + + virtual void paint(Drawable &d) const; +}; + + +#ifdef SDL_MAJOR_VERSION +/** \brief An SDL surface adapter. + * + * This screen type will draw on an SDL surface (honouring transparency if the + * surface is already filled) and react on SDL events. It does not provide an + * application event loop, you have to call update() and event() regularly until + * you decide to quit the application. + * + * The implementation of this class could as well have been integrated into + * GUI::Screen. That might have been a little more efficient, but this way + * this class serves as an example for custom screen classes. + * + * Note that you have to include \c SDL.h \em before \c gui_tk.h for this class + * to become available. + */ +class ScreenSDL : public Screen { +protected: + /// not used. + virtual void rgbToSurface(RGB color, void **pixel) {}; + + /// not used. + virtual RGB surfaceToRGB(void *pixel) { return 0; }; + + /// The SDL surface being drawn to. + SDL_Surface *surface; + + /// Position of last mouse down. + int downx, downy; + + /// time of last click for double-click detection. + Ticks lastclick; + +public: + + /** Initialize SDL screen with a surface + * + * The dimensions of this surface will define the screen dimensions. Changing the surface + * later on will not change the available area. + */ + ScreenSDL(SDL_Surface *surface); + + /** Change current surface + * + * The new surface may have different dimensions than the current one, but + * the screen size will not change. This means that either the screen will + * not be displayed fully, or there will be borders around the screen. + */ + void setSurface(SDL_Surface *surface) { this->surface = surface; } + + /// Retrieve current surface. + SDL_Surface *getSurface() { return surface; } + + /// Overridden: makes background transparent by default. + virtual void paint(Drawable &d) const; + + /// Use this to update the SDL surface. The screen must not be locked. + Ticks update(Ticks ticks); + + /// Process an SDL event. Returns \c true if event was handled. + bool event(const SDL_Event *ev) { return event(*ev); } + + + /// Process an SDL event. Returns \c true if event was handled. + bool event(const SDL_Event& ev); +}; +#endif + +class Font; + +/** \brief A drawable represents a rectangular off-screen drawing area. + * + * It is an off-screen buffer which can be copied to other drawables or + * to a Screen's framebuffer. The drawable's origin is at the top left. All + * operations are silently clipped to the available area. The alpha channel + * is honoured while copying one drawable to another, but not during other + * drawing operations. + * + * Drawables have a current font, color and (x,y) position. Drawing takes place + * at the given point using the given font and color. The current position is + * then moved to the final point of the drawing primitive unless otherwise + * noted. Pixel width of all lines is selectable, but be aware that visual + * appearance of lines with width > 1 is not as sophisticated as in well-known + * toolkits like Java or Qt. + * + * Some drawing primitives are overloaded to take full coordinates. These ignore + * the current position, but update it just like their regular brethren. + */ +class Drawable { +protected: + friend Ticks Screen::update(void *, Ticks); + /// The actual pixel buffer. + RGB *const buffer; + /// Total width of buffer. + const int width; + /// Total height of buffer. + const int height; + /// \c true if \a buffer must be freed by this instance. + const bool owner; + + /// Current color. + RGB color; + /// Current font. + const Font *font; + /// Current line width. + int lineWidth; + + /// X translation. + const int tx; + /// Y translation. + const int ty; + /// clip x. + const int cx; + /// clip y. + const int cy; + /// clip width. + const int cw; + /// clip height. + const int ch; + + /// Current position x coordinate. + int x; + /// Current position y coordinate. + int y; + +public: + /// Create an empty drawable object with given dimensions. + /** Optionally, the area is cleared with a given color (default: fully transparent). */ + Drawable(int w, int h, RGB clear = Color::Transparent); + + /// Deep-copying copy constructor. + /** It honours clip and translate so that the resulting drawable, if drawn + * to the source drawable at (0,0), yields the same result as drawing + * directly to the source surface. If \p fill is not explicitly set, will + * copy the original surface's contents */ + Drawable(Drawable &src, RGB clear = 0); + + /// Shallow-copying copy constructor with clip & translate. See setClipTranslate(int x, int y, int w, int h). + Drawable(Drawable &src, int x, int y, int w, int h); + + /// Destructor. + virtual ~Drawable(); + + /// Clears the surface. + void clear(RGB clear = Color::Transparent); + + /// Change current drawing color. + /** The alpha part is honoured in all drawing primitives like this: + All drawing operations in this window will unconditionally overwrite + earlier content of this window. Only when combining this window with + it's parent, the alpha channel is fully honoured. */ + void setColor(RGB c) { color = c; }; + /// Return the currently selected drawing color. + RGB getColor() { return color; }; + + /// Change current drawing font. + void setFont(const Font *f) { font = f; }; + /// Return the currently selected drawing font. + const Font *getFont() { return font; }; + + /// Change current line width. + void setLineWidth(int w) { lineWidth = w; }; + /// Return the current line width. + int getLineWidth() { return lineWidth; }; + + /// Move the current position to the given coordinates. + void gotoXY(int x, int y) { this->x = x; this->y = y; }; + /// Return current position X. + int getX() { return x; } + /// Return current position Y. + int getY() { return y; } + + /// Return clip width + int getClipX() { return cx; } + /// Return clip height + int getClipY() { return cy; } + /// Return clip width + int getClipWidth() { return cw; } + /// Return clip height + int getClipHeight() { return ch; } + + /// Paint a single pixel at the current position. + void drawPixel() { if (x >= cx && x < cw && y >= cy && y < ch) buffer[x+tx+(y+ty)*width] = color; }; + /// Paint a single pixel at the given coordinates. + void drawPixel(int x, int y) { gotoXY(x,y); drawPixel(); }; + + /// Return the pixel color at the current position. + RGB getPixel() { if (x >= cx && x < cw && y >= cy && y < ch) return buffer[x+tx+(y+ty)*width]; return Color::Transparent; }; + /// Return the pixel color at the given coordinates. + RGB getPixel(int x, int y) { gotoXY(x,y); return getPixel(); }; + + /// Draw a straight line from the current position to the given coordinates. + void drawLine(int x2, int y2); + /// Draw a straight line from (\p x1,\p y1) to (\p x2,\p y2). + void drawLine(int x1, int y1, int x2, int y2) { gotoXY(x1,y1); drawLine(x2,y2); }; + + /// Draw a circle centered at the current position with diameter \p d. + /** The current position is not changed. */ + void drawCircle(int d); + /// Draw a circle centered at the given coordinates with diameter \p d. + /** The current position is set to the center. */ + void drawCircle(int x, int y, int d) { gotoXY(x, y); drawCircle(d); }; + + /// Draw a rectangle with top left at the current position and size \p w, \p h. + /** The current position is not changed. */ + void drawRect(int w, int h); + /// Draw a rectangle with top left at the given coordinates and size \p w, \p h. + /** The current position is set to the top left corner. */ + void drawRect(int x, int y, int w, int h) { gotoXY(x, y); drawRect(w, h); }; + + /// Flood-fill an area at the current position. + /** A continuous area with the same RGB value as the selected pixel is + changed to the current color. The current position is not changed. */ + void fill(); + /// Flood-fill an area at a given position. + /** see fill(), but moves current position to the given coordinates */ + void fill(int x, int y) { gotoXY(x,y); fill(); }; + + /// Draw a filled circle centered at the current position with diameter \p d. + /** The current position is not changed. */ + void fillCircle(int d); + /// Draw a filled circle centered at the given coordinates with diameter \p d. + /** The current position is set to the center. */ + void fillCircle(int x, int y, int d) { gotoXY(x, y); fillCircle(d); }; + + /// Draw a filled rectangle with top left at the current position and size \p w, \p h. + /** The current position is not changed. */ + void fillRect(int w, int h); + /// Draw a filled rectangle with top left at the given coordinates and size \p w, \p h. + /** The current position is set to the top left corner. */ + void fillRect(int x, int y, int w, int h) { gotoXY(x, y); fillRect(w, h); }; + + /// Draw a text string. + /** Current position is the leftmost pixel on the baseline of the character. + The current position is moved to the next character. Background is not + cleared. If \p interpret is \c true, some ASCII control characters like + backspace, line-feed, tab and ANSI colors are interpreted, and text is word-wrapped at + the window borders. You can optionally pass start and length of a substring + to print */ + void drawText(const String& text, bool interpret = true, Size start = 0, Size len = (Size)-1); + + /// Draw a text string at a fixed position. + /** see drawText(const String& text, bool interpret, Size start, Size len) */ + template void drawText(int x, int y, const STR text, bool interpret, Size start, Size len = (Size)-1) { gotoXY(x,y); drawText(String(text), interpret, start, len); }; + /// Draw a single character. + /** see drawText(const STR text, bool interpret), except wrapping is + performed on this character only */ + void drawText(const Char c, bool interpret = false); + /// Draw a single character at a fixed position. + /** see drawText(const Char c, bool interpret). */ + void drawText(int x, int y, const Char c, bool interpret = false) { gotoXY(x,y); drawText(c, interpret); }; + + /// Copy the contents of another Drawable to this one. + /** The top left corner of the source Drawable is put at the current + position. The alpha channel is fully honoured. Additionally, an extra + \p alpha value may be given which is multiplied with the source + alpha channel. The current position remains unchanged. */ + void drawDrawable(Drawable &d, unsigned char alpha = 1); + /// Copy the contents of another Drawable to this one at a given position. + /** see drawDrawable(Drawable &d, unsigned char alpha). The current position + is moved to the given coordinates. */ + void drawDrawable(int x, int y, Drawable &d, unsigned char alpha = 1) { gotoXY(x,y); drawDrawable(d, alpha); }; + +}; + +/** \brief A variable- or fixed-width fixed-size Font. + * + * These Fonts can't be scaled once instantiated, but it is possible + * to subclass this abstract font class to encapsulate scalable + * fonts. Fonts can be anti-aliasing and multi-coloured, depending on + * subclass. There is no encoding enforced. The font object implicitly + * knows about it's encoding. Because of that, there is a utility + * function for string examination as well. + * + * You can't instantiate objects of this class directly, use one of the + * subclasses like BitmapFont. + * + * This class provides a font registry which allows you to register + * and retrieve font objects using a name of your choice. It is recommended + * to use a naming scheme like "FontName-variant-pixelsize-encoding" where + * variant is "normal", "bold", "italic" or "bolditalic". No one enforces + * this, however. + * + * The GUI uses some special font names. You must add them before creating + * the relevant GUI item. + * \li \c default - used if a requested font was not found + * \li \c title - GUI::ToplevelWindow title + * \li \c input - GUI::Input + * + */ +class Font { +protected: + friend void Drawable::drawText(const Char c, bool interpret); + friend void Drawable::drawText(const String& s, bool interpret, Size start, Size len); + + /// Compare two strings for 'less-than'. + struct ltstr { bool operator()(const char* s1, const char* s2) const { + return strcmp(s1, s2) < 0; + } }; + /// Font registry. Contains all known font objects indexed by name. + static std::map registry; + + /// Default constructor. + Font() {}; + + /// Draw character to a drawable at the current position. + /** \p d's current position is advanced to the position of the next character. + * The y coordinate is located at the baseline before and after the call. */ + virtual void drawChar(Drawable *d, const Char c) const = 0; + + /// Draw \p len characters to a drawable at the current position, starting at string position \p start. + /** This can be used to provide kerning. */ + virtual void drawString(Drawable *d, const String &s, Size start, Size len) const { + if (len > s.size()-start) len = (Size)(s.size()-start); + len += start; + while (start < len) drawChar(d,s[start++]); + } + +public: + /// Return a font with the given name (case-sensitive). + /** If no font was registered with that name, returns NULL. */ + static const Font *getFont(const char *name) { + std::map::iterator i = registry.find(name); + if (i == registry.end()) return(strcmp(name,"default")?getFont("default"):NULL); + return (*i).second; + } + + /// Add a font with a given name. + /** Don't delete this font once added. This class will do that for you. + * If a font with that name already exists, it will be replaced. */ + static void addFont(const char *name, Font *font) { + std::map::iterator i = registry.find(name); + if (i != registry.end()) delete (*i).second; + registry[name] = font; + } + + virtual ~Font() {}; + + /// Retrieve total height of font in pixels. + virtual int getHeight() const = 0; + + /// Retrieve the ascent, i.e. the number of pixels above the base line. + virtual int getAscent() const = 0; + + /// Return width of a string. + template int getWidth(const STR s, Size start = 0, Size len = (Size)-1) const { + return this->getWidth(String(s), start, len); + } + + /// Retrieve width of a character. + virtual int getWidth(Char c = 'M') const = 0; + + /// Retrieve width of a string of characters. + /** Can be used to provide kerning. */ + virtual int getWidth(const String &s, Size start = 0, Size len = (Size)-1) const { + int width = 0; + if (start+len > s.size()) len = (Size)(s.size()-start); + while (len--) width += getWidth(s[start++]); + return width; + } + + /// Characters with special appearance or meaning. + enum SpecialChar { CR = '\r', LF = '\n', BS = '\b', Tab = '\t', Space = ' ', ESC = 27 }; + + /// Convert a character to an equivalent SpecialChar. May return values not in SpecialChar. + virtual SpecialChar toSpecial(Char c) const { return (SpecialChar)(c<255?c:255); } + + /// Convert a SpecialChar to an equivalent character. + virtual Char fromSpecial(SpecialChar c) const { return c; } +}; + +/** \brief A bitmap font. + * This is a font which is defined by a binary bit map. Each bit in the bitmap + * defines one pixel. Bits may be arranged in various common patterns. + * + * Encoding free, character size depends on number of characters in the font. + */ +class BitmapFont : public Font { +protected: + /// The actual font data. + const unsigned char *const bitmap; + + /// Width of a character cell. + const int width; + + /// Height of all characters. + const int height; + + /// Ascent of all characters. + const int ascent; + + /// Array of character widths. If font is fixed-width, this is NULL and \a width is used. + const int *const widths; + + /// Array of character ascents. If this is NULL, \a ascent is used for all characters. + /** This allows character data to be flush to the top or bottom of it's bitmap area. */ + const int *const ascents; + + /// True if set bits are background, false otherwise. + const bool background_set; + + /// Number of bits added to get from a column to the next column. + const int col_step; + + /// Distance between 2 rows of a character, or 0 for variable-width rows. + const int row_step; + + /// Distance of two characters in the bitmap in bits. + /** This is calculated as abs(row_step*height) unless explicitly specified. */ + const int character_step; + + /// Array of pointers to font data. If set, neither \a bitmap nor \a character_step are used. + const unsigned char *const*const char_position; + + /// Array of SpecialChar equivalents. + /** If unset, encoding is assumed ASCII-like for the first 32 characters */ + const SpecialChar *const special; + + /// If \c true, then all arrays are freed on destruction. + const bool owner; + + /// Last defined character. Characters above this will be ignored. + const Char last; + + /// Draw character to a drawable at the current position. + /** \p d's current position is advanced to the position of the next character. + * The y coordinate is located at the baseline before and after the call. */ + virtual void drawChar(Drawable *d, const Char c) const; + +public: + /// Constructor. + /** The default values provide an 8 bit wide fixed-width pixel layout with each byte a row, + * arranged top-to-bottom just like a PC's VGA font. See the individual member documentation + * for details on the parameters. */ + BitmapFont(const unsigned char *data, int height, int ascent, bool owner = false, + int width = 8, bool background_set = false, + int col_step = -1, int row_step = 8, int character_step = 0, Char last = 256, + const int *widths = NULL, const int *ascents = NULL, + const unsigned char *const* char_position = NULL, + const SpecialChar *special = NULL); + + virtual ~BitmapFont(); + + /// Retrieve total height of font in pixels. + virtual int getHeight() const { return height; }; + + /// Retrieve the ascent, i.e. the number of pixels above the base line. + virtual int getAscent() const { return ascent; }; + + /// Retrieve width of a character. + virtual int getWidth(Char c = 'M') const { return (widths != NULL?widths[c]:width); }; + + /// Convert a character to an equivalent SpecialChar. See Font::toSpecial(Char c) + virtual SpecialChar toSpecial(Char c) const { return (special != NULL?special[c]:Font::toSpecial(c)); } + + /// Convert a character to an equivalent character. See Font::fromSpecial(SpecialChar c). + virtual Char fromSpecial(SpecialChar c) const { if (special == NULL) return Font::fromSpecial(c); Char i = 0; while(special[i] != c) i++; return i; } + +}; + +class ActionEventSource; +/// Callback for action events. +struct ActionEventSource_Callback { +public: + /// Handler with optional String argument. + /** If the event source doesn't provide an additional argument, the name will be used. */ + virtual void actionExecuted(ActionEventSource *source, const String &arg) = 0; + virtual ~ActionEventSource_Callback() {} +}; + +/// Event class for action events. +/** Action events are events generated by GUI elements like Buttons, Menus and by pressing Enter in + * an Input. All of these are handled similarly: The source of such an event has a name, and the + * Event may also be connected with a String describing what was executed, like the name of the + * Menu entry or the contents of the Input. + */ +class ActionEventSource { +protected: + /// List of registered action handlers. + std::list actionHandlers; + + /// This event source's name. + /** The name is primarily meant for your own purposes, for example identification of the activated + * element. One exception are Menubars, which display the name of their Menus. */ + String name; + +public: + /// Create a named event source. + template ActionEventSource(const STR name) : name(String(name)) { } + + /// Dummy destructor. + virtual ~ActionEventSource() {} + + /// Add a button press event handler. + void addActionHandler(ActionEventSource_Callback *handler) { actionHandlers.push_back(handler); } + + /// Remove a button press event handler. + void removeActionHandler(ActionEventSource_Callback *handler) { actionHandlers.remove(handler); } + + /// Set the name of this event source. + template void setName(const STR name) { this->name = String(name); } + + /// Get the name of this event source. + const String &getName() const { return name; } + + /// Execute handlers. + void executeAction(const String &arg) { + std::list::iterator i = actionHandlers.begin(); + bool end = (i == actionHandlers.end()); + while (!end) { + ActionEventSource_Callback *c = *i; + ++i; + end = (i == actionHandlers.end()); + c->actionExecuted(this,arg); + } + } + + /// Execute handlers. + void executeAction() { executeAction(name); } +}; + +/// Internal class for windows whose child content should not span the entire area. +class BorderedWindow : public Window { +protected: + /// Borders. + int border_left, border_top, border_right, border_bottom; + + /// Create a bordered window. + BorderedWindow(Window *parent, int x, int y, int w, int h, int bl, int bt, int br, int bb) : + Window(parent,x,y,w,h), border_left(bl), border_top(bt), border_right(br), border_bottom(bb) {} + +public: + virtual void paintAll(Drawable &d) const; + virtual bool mouseMoved(int x, int y); + virtual bool mouseDown(int x, int y, MouseButton button); + virtual bool mouseDragged(int x, int y, MouseButton button); + virtual int getScreenX() const { return Window::getScreenX()+border_left; } + virtual int getScreenY() const { return Window::getScreenY()+border_top; } +}; + +/// A text label +/** Text labels are positioned relative to the top left corner of their bounding box. + * They size themselves automatically and display their text in non-interpreted mode. + */ + +class Label : public Window { + /// The Font used + const Font *font; + + /// Text color + RGB color; + + /// Text + String text; + + /// multiline text? + bool interpret; + +public: + /// Create a text label with given position, \p text, \p font and \p color. + /** If \p width is given, the resulting label is a word-wrapped multiline label */ + template Label(Window *parent, int x, int y, const STR text, int width = 0, const Font *font = Font::getFont("default"), RGB color = Color::Text) : + Window(parent, x, y, (width?width:1), 1), font(font), color(color), text(text), interpret(width != 0) + { resize(); } + + /// Set a new text. Size of the label is adjusted accordingly. + template void setText(const STR text) { this->text = text; resize(); } + /// Retrieve current text + const String& getText() { return text; } + + /// Set a new font. Size of the label is adjusted accordingly. + void setFont(const Font *font) { this->font = font; resize(); } + /// Retrieve current font + const Font *getFont() { return font; } + + /// Set a new text color. + void setColor(const RGB color) { this->color = color; resize(); } + /// Retrieve current color + RGB getColor() { return color; } + + /// Calculate label size. Parameters are ignored. + virtual void resize(int w = -1, int h = -1) { + if (w == -1) w = (interpret?getWidth():0); + else interpret = (w != 0); + Drawable d((w?w:1), 1); + d.setFont(font); + d.drawText(0, font->getAscent(), text, interpret, 0); + if (interpret) Window::resize(w, d.getY()-font->getAscent()+font->getHeight()); + else Window::resize(d.getX(), font->getHeight()); + } + + /// Paint label + virtual void paint(Drawable &d) const { d.setColor(color); d.drawText(0, font->getAscent(), text, interpret, 0); } + + virtual bool raise() { return false; } +}; + + +/// A single-line text input +/** It uses Font::getFont("input") to display content. + * It supports selection, the clipboard and all well-known key bindings (except undo). + */ +class Input : public Window, public Timer_Callback, public ActionEventSource { +protected: + /// The text entered. + String text; + + /// Current position in \a text. + Size pos; + + /// Last updated position in \a text. + Size lastpos; + + /// Coordinates according to pos. + int posx, posy; + + /// Selection in \a text. + Size start_sel, end_sel; + + /// Is cursor visible at the moment? + bool blink; + + /// Insert mode? + bool insert; + + /// Multiline? + bool multi; + + /// Horizontal scrolling offset. + int offset; + + /// Ensure that pos is visible. + void checkOffset() { + if (lastpos == pos) return; + const Font *f = Font::getFont("input"); + if (multi) { + Drawable d(width-6,1); + d.setFont(f); + d.drawText(0, 0, text, multi, 0, pos); + posy = d.getY(); + posx = d.getX(); + if (posy-offset > height-8-f->getHeight()) offset = posy-height+8+f->getHeight(); + if (posy-offset < 0) offset = posy; + } else { + posy = 0; + posx = f->getWidth(text,0,pos); + if (f->getWidth(text,0,pos+1)-offset > width-10) offset = f->getWidth(text,0,pos+1)-width+10; + if (f->getWidth(text,0,(pos>0?pos-1:0))-offset < 0) offset = f->getWidth(text,0,(pos>0?pos-1:0)); + } + lastpos = pos; + setDirty(); + } + +public: + /// Create an input with given position and width. If not set, height is calculated from the font and input is single-line. + Input(Window *parent, int x, int y, int w, int h = 0) : + Window(parent,x,y,w,(h?h:Font::getFont("input")->getHeight()+10)), ActionEventSource("GUI::Input"), + text(""), pos(0), lastpos(0), posx(0), posy(0), start_sel(0), end_sel(0), blink(true), insert(true), multi(h != 0), offset(0) + { Timer::add(this,30); } + + ~Input() { + Timer::remove(this); + } + + /// Paint input. + virtual void paint(Drawable &d) const; + + /// Clear selected area. + void clearSelection() { + text.erase(text.begin()+(pos = imin(start_sel,end_sel)),text.begin()+imax(start_sel,end_sel)); + start_sel = end_sel = pos; + } + + /// Copy selection to clipboard. + void copySelection() { + setClipboard(String(text.begin()+imin(start_sel,end_sel),text.begin()+imax(start_sel,end_sel))); + } + + /// Cut selection to clipboard. + void cutSelection() { + setClipboard(String(text.begin()+imin(start_sel,end_sel),text.begin()+imax(start_sel,end_sel))); + clearSelection(); + } + + /// Paste from clipboard. + void pasteSelection() { + String c = getClipboard(); + clearSelection(); + text.insert(text.begin()+pos,c.begin(),c.end()); + start_sel = end_sel = pos += (Size)c.size(); + } + + /// get character position corresponding to coordinates + Size findPos(int x, int y); + + /// Set text to be edited. + template void setText(const STR text) { this->text = text; setDirty(); }; + /// Get the entered text. If you need it longer, copy it immediately. + const String& getText() { return text; }; + + /// Handle text input. + virtual bool keyDown(const Key &key); + + /// Handle mouse input. + virtual bool mouseDown(int x, int y, MouseButton button); + + /// Handle mouse input. + virtual bool mouseDragged(int x, int y, MouseButton button); + + /// Timer callback function + virtual Ticks timerExpired(Ticks time) + { blink = !blink; setDirty(); return 30; } + +}; + +class ToplevelWindow; +/// Callbacks for window events. +struct ToplevelWindow_Callback { +public: + /// The window has been asked to be closed. + /** Return \c false in order to block the requested action. Do not do any + * deallocation here, as other callbacks may abort the close process. + */ + virtual bool windowClosing(ToplevelWindow *win) = 0; + + /// The window will been closed. + /** Now it is safe to deallocate all external resources that applications + * may have associated with this window, like registering this window + * with external callbacks. + */ + virtual void windowClosed(ToplevelWindow *win) = 0; + virtual ~ToplevelWindow_Callback() {} +}; + +/// An actual decorated window. +class ToplevelWindow : public BorderedWindow, public ActionEventSource_Callback { +protected: + /// Title text + String title; + + /// Drag base + int dragx, dragy; + + /// List of registered event handlers. + std::list closehandlers; + + /// System menu (top left) + Menu *systemMenu; + +public: + /// Create a new GUI Frame with title bar, border and close button + template ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title); + + /// Call cleanup handlers + ~ToplevelWindow() { + std::list::iterator i = closehandlers.begin(); + bool end = (i == closehandlers.end()); + while (!end) { + ToplevelWindow_Callback *c = *i; + ++i; + end = (i == closehandlers.end()); + c->windowClosed(this); + } + } + + /// Menu callback function + virtual void actionExecuted(ActionEventSource *src, const String &item) { + if (item == String("Close")) close(); + } + + /// Add a window event handler. + void addCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.push_back(handler); } + + /// Remove a window event handler. + void removeCloseHandler(ToplevelWindow_Callback *handler) { closehandlers.remove(handler); } + + virtual void paint(Drawable &d) const; + virtual bool mouseDown(int x, int y, MouseButton button); + virtual bool mouseDoubleClicked(int x, int y, MouseButton button) { + if (button == Left && x < 32 && x > 6 && y > 4 && y < 31) { + close(); + return true; + } + BorderedWindow::mouseClicked(x,y,button); + return true; + } + virtual bool mouseUp(int x, int y, MouseButton button) { + if (button == Left && dragx >= 0 && dragy >= 0) { + dragx = dragy = -1; + return true; + } + BorderedWindow::mouseUp(x,y,button); + return true; + } + virtual bool mouseDragged(int x, int y, MouseButton button) { + if (button == Left && dragx >= 0 && dragy >= 0) { + move(x-dragx+this->x,y-dragy+this->y); + return true; + } + BorderedWindow::mouseDragged(x,y,button); + return true; + } + virtual bool mouseMoved(int x, int y) { + BorderedWindow::mouseMoved(x,y); + return true; + } + + /// Put window on top of all other windows without changing their relative order + virtual bool raise() { + Window *last = parent->children.back(); + parent->children.remove(this); + parent->children.push_back(this); + if (last != this) { + focusChanged(true); + last->focusChanged(false); + } + return true; + } + + /// Set a new title. + template void setTitle(const STR title) { this->title = title; setDirty(); } + /// Retrieve current title. + const String& getTitle() { return title; } + + /// Close window. + void close() { + bool doit = true; + std::list::iterator i = closehandlers.begin(); + bool end = (i == closehandlers.end()); + while (!end) { + ToplevelWindow_Callback *c = *i; + ++i; + end = (i == closehandlers.end()); + doit = doit && c->windowClosing(this); + } + if (doit) delete this; + } +}; + +/// A floating temporary window that is not restricted by it's parent's area. +/** They have a parent which displays them, + * but that parent is not their real parent in the window hierarchy: They are always top-level elements, thus + * they are not clipped to their logical parent's area, they can freely overlay any part of the screen. + * As another consequence, they are not automatically deleted when their logical parent is deleted. + * + * You should observe the following points: + * \li TransientWindows behave mostly as if their logical parent was their true parent, but are not + * restricted to it's area + * \li TransientWindows are deleted automatically when the ToplevelWindow is deleted in which their logical + * parent resides; do NOT delete them in your destructor or bad things will happen + * \li only the logical parent object can show/hide a TransientWindow at will + * \li it will close automatically upon clicking other GUI elements, \em except for the + * logical parent and it's children + */ +class TransientWindow : public Window, Window_Callback, ToplevelWindow_Callback { +protected: + /// The true parent window. + Window *realparent; + + /// User selected position relative to logical parent. + int relx, rely; + +public: + /// Handle automatic hiding + virtual void focusChanged(bool gained) { + Window::focusChanged(gained); + if (isVisible() && !gained) { + if (realparent->hasFocus()) raise(); + else setVisible(false); + } + } + + /// Handle automatic delete + void windowClosed(ToplevelWindow *win) { + delete this; + } + + /// No-op + bool windowClosing(ToplevelWindow *win) { return true; } + + /// Create a transient window with given position and size + /** \a parent is the logical parent. The true parent object is + * always the screen the logical parent resides on. */ + TransientWindow(Window *parent, int x, int y, int w, int h) : + Window(parent->getScreen(),x+parent->getScreenX(),y+parent->getScreenY(),w,h), + realparent(parent), relx(x), rely(y) { + Window *p = realparent, *last = NULL, *last2 = NULL; + while (p != NULL) { + p->addWindowHandler(this); + last2 = last; + last = p; + p = p->getParent(); + } + dynamic_cast(last2)->addCloseHandler(this); + } + + ~TransientWindow() { + Window *p = realparent, *last = NULL, *last2 = NULL; + while (p != NULL) { + p->removeWindowHandler(this); + last2 = last; + last = p; + p = p->getParent(); + } + dynamic_cast(last2)->removeCloseHandler(this); + } + + virtual void move(int x, int y) { relx = x; rely = y; + Window::move(x+realparent->getScreenX(),y+realparent->getScreenY()); } + virtual int getX() const { return x-realparent->getScreenX(); } + virtual int getY() const { return y-realparent->getScreenY(); } + virtual void setVisible(bool v) { if (v) raise(); Window::setVisible(v); } + virtual void windowMoved(Window *src, int x, int y) { move(relx,rely); } + + /// Put window on top of all other windows without changing their relative order + virtual bool raise() { + Window *last = parent->children.back(); + parent->children.remove(this); + parent->children.push_back(this); + if (last != this) { + focusChanged(true); + last->focusChanged(false); + } + return true; + } + +}; + +/// A popup menu. +/** Popup menus are used as context menus or as part of a menu bar. Menus are not visible when created. + * Menus have a name which can be used in event handlers to identify it, and it is used in Menubars as well. + * + * Currently, menu entries are not interpreted in any way. This may change in the future. To ensure upwards + * compatibility, avoid the \c '&' character in menu entries, since it may have a special meaning in future + * versions. Menus use the Font named "menu". + * + * Please note the general remarks in GUI::TransientWindow + */ +class Menu : public TransientWindow, public ActionEventSource { +protected: + /// List of menu items (displayed text) + std::vector items; + + /// Currently selected menu item. + /** Can be -1 if no item is currently active. */ + int selected; + + /// Flag to skip the first mouseUp-event + bool firstMouseUp; + + /// Where we grabbed the mouse from. + Window *mouseTakenFrom; + + /// Selects menu item at position (x,y). + /** \a selected is set to -1 if there is no active item at that location. */ + virtual void selectItem(int x, int y) { + y -= 2; + selected = -1; + const int height = Font::getFont("menu")->getHeight()+2; + std::vector::iterator i; + for (i = items.begin(); i != items.end() && y > 0; ++i) { + selected++; + if ((*i).size() > 0) y -= height; + else y -= 12; + } + if (y > 0 || (selected >= 0 && items[selected].size() == 0)) selected = -1; + } + + virtual Size getPreferredWidth() { + Size width = 0; + const Font *f = Font::getFont("menu"); + std::vector::iterator i; + for (i = items.begin(); i != items.end() && y > 0; ++i) { + Size newwidth = f->getWidth(*i); + if (newwidth > width) width = newwidth; + } + return width+39; + } + + virtual Size getPreferredHeight() { + Size height = 0; + const Size h = Font::getFont("menu")->getHeight()+2; + std::vector::iterator i; + for (i = items.begin(); i != items.end() && y > 0; ++i) { + height += ((*i).size() > 0?h:12); + } + return height+6; + } + +public: + /// Create a menu with given position + /** Size is determined dynamically. \a parent is the logical parent. The true parent object is + * always the screen the logical parent resides on. */ + template Menu(Window *parent, int x, int y, const STR name) : + TransientWindow(parent,x,y,4,4), ActionEventSource(name), selected(-1) + { setVisible(false); } + + ~Menu() { + setVisible(false); + } + + /// Paint button. + virtual void paint(Drawable &d) const; + + /// Highlight current item. + virtual bool mouseMoved(int x, int y) { + selectItem(x,y); + return true; + } + + /// Highlight current item. + virtual bool mouseDragged(int x, int y, MouseButton b) { + selectItem(x,y); + return true; + } + + virtual bool mouseDown(int x, int y, MouseButton button) { return true; } + + /// Possibly select item. + virtual bool mouseUp(int x, int y, MouseButton button) { + selectItem(x,y); + if (firstMouseUp) firstMouseUp = false; + else setVisible(false); + execute(); + return true; + } + + /// Handle keyboard input. + virtual bool keyDown(const Key &key) { + if (key.special == Key::Up) selected--; + else if (key.special == Key::Down) selected++; + else if (key.special == Key::Enter) { execute(); return true; } + else if (key.special == Key::Escape) { setVisible(false); return true; } + else return true; + if (items[selected].size() == 0 && items.size() > 1) return keyDown(key); + if (selected < 0) selected = (int)(items.size()-1); + if (selected >= (int)items.size()) selected = 0; + return true; + } + + + /// Add a menu item at end. An empty string denotes a separator. + template void addItem(const T item) { + items.push_back(String(item)); + resize(getPreferredWidth(),getPreferredHeight()); + } + + /// Remove an existing menu item. + template void removeItem(const T item) { + const String s(item); + std::vector::iterator i = items.begin(); + while (i != items.end() && s != (*i)) ++i; + if (i != items.end()) items.erase(i); + resize(getPreferredWidth(),getPreferredHeight()); + } + + virtual void setVisible(bool v) { + TransientWindow::setVisible(v); + if (v) { + parent->mouseChild = this; + raise(); + firstMouseUp = true; + } + } + + /// Execute menu item. + void execute() { + if (selected >= 0) { + setVisible(false); + executeAction(items[selected]); + } + } +}; + +/// A push button +/** Buttons have 3D appearance and can have any child widget as content. + * There are convenience constructors for common forms of buttons. + */ +class Button : public BorderedWindow, public ActionEventSource { +protected: + /// \c true, if button is currently pressed down. + bool pressed; + +public: + /// Create a button with given position and size + Button(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource("GUI::Button"), pressed(0) {} + + /// Create a text button. + /** If a size is specified, text is centered. Otherwise, button size is adjusted for the text. */ + template Button(Window *parent, int x, int y, const T text, int w = -1, int h = -1); + + /// Paint button. + virtual void paint(Drawable &d) const; + + /// Press button. + virtual bool mouseDown(int x, int y, MouseButton button) { + border_left = 7; border_right = 5; border_top = 7; border_bottom = 3; + pressed = true; + return true; + } + + /// Release button. + virtual bool mouseUp(int x, int y, MouseButton button) { + border_left = 6; border_right = 6; border_top = 5; border_bottom = 5; + pressed = false; + return true; + } + + /// Handle mouse activation. + virtual bool mouseClicked(int x, int y, MouseButton button) { + if (button == Left) { + executeAction(); + return true; + } + return false; + } + + /// Handle keyboard input. + virtual bool keyDown(const Key &key); + + /// Handle keyboard input. + virtual bool keyUp(const Key &key); + +}; + +/// A menu bar at the top of a ToplevelWindow +/** Menu bars aggregate several Menus. They have a simple border at the bottom. If your application + * has a work area with 3D sunken look, place it so that it overlaps the menu by one row. + * + * As with Menus, avoid the character \c '&' in Menu names as it may + * have a special meaning in future versions. Menubars use the Font named "menu". + */ +class Menubar : public Window, public ActionEventSource, ActionEventSource_Callback { +protected: + /// Currently activated menu index. + int selected; + + /// Horizontal position of next menu. + int lastx; + + /// List of Menus. + std::vector menus; + +public: + /// Create a menubar with given position and size + /** Height is autocalculated from font size */ + Menubar(Window *parent, int x, int y, int w) : Window(parent,x,y,w,Font::getFont("menu")->getHeight()+5), ActionEventSource("GUI::Menubar"), selected(-1), lastx(0) {} + + /// Add a Menu. + template void addMenu(const STR name) { + const String n(name); + menus.push_back(new Menu(this,lastx,height-2,n)); + menus.back()->addActionHandler(this); + lastx += Font::getFont("menu")->getWidth(n)+14; + } + + /// Add a Menuitem. + template void addItem(int index, const STR name) { menus[index]->addItem(name); } + + /// Remove a Menuitem. + template void removeItem(int index, const STR name) { menus[index]->removeItem(name); } + + /// Paint menubar. + virtual void paint(Drawable &d) const; + + /// Open menu. + virtual bool mouseDown(int x, int y, MouseButton button) { + int oldselected = selected; + if (selected >= 0 && !menus[selected]->isVisible()) oldselected = -1; + if (selected >= 0) menus[selected]->setVisible(false); + if (x < 0 || x >= lastx) return true; + for (selected = (int)(menus.size()-1); menus[selected]->getX() > x; selected--) {}; + if (oldselected == selected) selected = -1; + else menus[selected]->setVisible(true); + return true; + } + + /// Handle keyboard input. + virtual bool keyDown(const Key &key) { return true; }; + + /// Handle keyboard input. + virtual bool keyUp(const Key &key) { return true; }; + + virtual void actionExecuted(ActionEventSource *src, const String &arg) { + std::list::iterator i = actionHandlers.begin(); + bool end = (i == actionHandlers.end()); + while (!end) { + ActionEventSource_Callback *c = *i; + ++i; + end = (i == actionHandlers.end()); + c->actionExecuted(src,arg); + } + } +}; + +/// A checkbox +/** Checkboxes can have any child widget as content. + * There are convenience constructors for common forms of checkboxes. + */ +class Checkbox : public BorderedWindow, public ActionEventSource { +protected: + /// \c true, if checkbox is currently selected. + bool checked; + +public: + /// Create a checkbox with given position and size + Checkbox(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource("GUI::Checkbox"), checked(0) {} + + /// Create a checkbox with text label. + /** If a size is specified, text is centered. Otherwise, checkbox size is adjusted for the text. */ + template Checkbox(Window *parent, int x, int y, const T text, int w = -1, int h = -1); + + /// Paint checkbox. + virtual void paint(Drawable &d) const; + + /// Change checkbox state. + virtual void setChecked(bool checked) { this->checked = checked; } + + /// Get checkbox state. + virtual bool isChecked() { return checked; } + + /// Press checkbox. + virtual bool mouseDown(int x, int y, MouseButton button) { + checked = !checked; + return true; + } + + /// Release checkbox. + virtual bool mouseUp(int x, int y, MouseButton button) { + execute(); + return true; + } + + /// Handle keyboard input. + virtual bool keyDown(const Key &key); + + /// Handle keyboard input. + virtual bool keyUp(const Key &key); + + /// Execute handlers. + virtual void execute() { + String arg(name); + if (!checked) arg.insert(arg.begin(),'!'); + executeAction(arg); + } +}; + +class Frame; + +/// A radio box. +/** Radio boxes can have any child widget as content. + * There are convenience constructors for common forms of radio boxes. + */ +class Radiobox : public BorderedWindow, public ActionEventSource { +protected: + /// \c true, if radio box is currently selected. + bool checked; + +public: + /// Create a radio box with given position and size + Radiobox(Frame *parent, int x, int y, int w, int h); + + /// Create a radio box with text label. + /** If a size is specified, text is centered. Otherwise, checkbox size is adjusted for the text. */ + template Radiobox(Frame *parent, int x, int y, const T text, int w = -1, int h = -1); + + /// Paint radio box. + virtual void paint(Drawable &d) const; + + /// Change radio box state. + virtual void setChecked(bool checked) { this->checked = checked; } + + /// Get radio box state. + virtual bool isChecked() { return checked; } + + /// Press radio box. + virtual bool mouseDown(int x, int y, MouseButton button) { + checked = true; + return true; + } + + /// Release checkbox. + virtual bool mouseUp(int x, int y, MouseButton button) { + executeAction(); + return true; + } + + /// Handle keyboard input. + virtual bool keyDown(const Key &key); + + /// Handle keyboard input. + virtual bool keyUp(const Key &key); +}; + +/// A rectangular 3D sunken frame +/** These can be used as generic grouping elements and also serve as aggregators for RadioBoxes. + */ +class Frame : public BorderedWindow, public ActionEventSource, protected ActionEventSource_Callback { +protected: + friend class Radiobox; + + /// Currently selected radio box. + int selected; + + /// Label of frame. + String label; + + /// Execute handlers. + virtual void actionExecuted(ActionEventSource *src, const String &arg) { + for (std::list::iterator i = children.begin(); i != children.end(); ++i) { + Radiobox *r = dynamic_cast(*i); + if (r != NULL && src != dynamic_cast(r)) r->setChecked(false); + } + executeAction(src->getName()); + } + +public: + /// Create a non-labeled frame with given position and size + Frame(Window *parent, int x, int y, int w, int h) : BorderedWindow(parent,x,y,w,h,5,5,5,5), ActionEventSource("GUI::Frame"), selected(0) {} + + /// Create a frame with text label. + template Frame(Window *parent, int x, int y, int w, int h, const T text) : + BorderedWindow(parent,x,y,w,h,5,Font::getFont("default")->getHeight()+2,5,5), + ActionEventSource(text), selected(0), label(text) { } + + /// Paint frame. + virtual void paint(Drawable &d) const; + +}; + +/// A message box with a single "Close" button. +class MessageBox : public GUI::ToplevelWindow { +protected: + Label *message; + Button *close; +public: + /// Create a new message box + template MessageBox(Screen *parent, int x, int y, int width, const STR title, const STR text) : + ToplevelWindow(parent, x, y, width, 1, title) { + message = new Label(this, 5, 5, text, width-10); + close = new GUI::Button(this, width/2-40, 10, "Close", 70); + close->addActionHandler(this); + setText(text); + } + + /// Set a new text. Size of the box is adjusted accordingly. + template void setText(const STR text) { + message->setText(text); + close->move(width/2-40, 20+message->getHeight()); + resize(width, message->getHeight()+100); + } +}; + +template ToplevelWindow::ToplevelWindow(Screen *parent, int x, int y, int w, int h, const STR title) : + BorderedWindow(parent, x, y, w, h, 6, 33, 6, 3), title(title), + dragx(-1), dragy(-1), closehandlers(), systemMenu(new Menu(this,-1,-2,"System Menu")) { + systemMenu->addItem("Move"); + systemMenu->addItem("Resize"); + systemMenu->addItem(""); + systemMenu->addItem("Minimize"); + systemMenu->addItem("Maximize"); + systemMenu->addItem("Restore"); + systemMenu->addItem(""); + systemMenu->addItem("Close"); + systemMenu->addActionHandler(this); +} + +template Button::Button(Window *parent, int x, int y, const STR text, int w, int h) : + BorderedWindow(parent,x,y,w,h,6,5,6,5), ActionEventSource(text), pressed(0) +{ + + Label *l = new Label(this,0,0,text); + if (width < 0) resize(l->getWidth()+border_left+border_right+10,height); + if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+6); + l->move((width-border_left-border_right-l->getWidth())/2, + (height-border_top-border_bottom-l->getHeight())/2); +} + +template Checkbox::Checkbox(Window *parent, int x, int y, const STR text, int w, int h) : + BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0) +{ + Label *l = new Label(this,0,0,text); + if (width < 0) resize(l->getWidth()+border_left+border_right+4,height); + if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4); + l->move((width-border_left-border_right-l->getWidth())/2, + (height-border_top-border_bottom-l->getHeight())/2); +} + +template Radiobox::Radiobox(Frame *parent, int x, int y, const STR text, int w, int h) : + BorderedWindow(parent,x,y,w,h,16,0,0,0), ActionEventSource(text), checked(0) +{ + Label *l = new Label(this,0,0,text); + if (width < 0) resize(l->getWidth()+border_left+border_right+4,height); + if (height < 0) resize(width,l->getHeight()+border_top+border_bottom+4); + l->move((width-border_left-border_right-l->getWidth())/2, + (height-border_top-border_bottom-l->getHeight())/2); + addActionHandler(parent); +} + +}; + +#endif diff --git a/src/libs/zmbv/drvproc.cpp b/src/libs/zmbv/drvproc.cpp index c97bb5c..3f5bc95 100644 --- a/src/libs/zmbv/drvproc.cpp +++ b/src/libs/zmbv/drvproc.cpp @@ -1,212 +1,212 @@ -/* - * Copyright (C) 2002-2009 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. - */ -// -// Zipped Motion Block Video -// -// Based on Huffyuv by Ben Rudiak-Gould. -// which was based on MSYUV sample code, which is: -// Copyright (c) 1993 Microsoft Corporation. -// All Rights Reserved. -// - -#include "zmbv_vfw.h" - -/*************************************************************************** - * DriverProc - The entry point for an installable driver. - * - * PARAMETERS - * dwDriverId: For most messages, is the DWORD - * value that the driver returns in response to a message. - * Each time that the driver is opened, through the API, - * the driver receives a message and can return an - * arbitrary, non-zero value. The installable driver interface - * saves this value and returns a unique driver handle to the - * application. Whenever the application sends a message to the - * driver using the driver handle, the interface routes the message - * to this entry point and passes the corresponding . - * This mechanism allows the driver to use the same or different - * identifiers for multiple opens but ensures that driver handles - * are unique at the application interface layer. - * - * The following messages are not related to a particular open - * instance of the driver. For these messages, the dwDriverId - * will always be zero. - * - * DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN - * - * hDriver: This is the handle returned to the application by the - * driver interface. - * - * uiMessage: The requested action to be performed. Message - * values below are used for globally defined messages. - * Message values from to are used for - * defined driver protocols. Messages above are used - * for driver specific messages. - * - * lParam1: Data for this message. Defined separately for - * each message - * - * lParam2: Data for this message. Defined separately for - * each message - * - * RETURNS - * Defined separately for each message. - * - ***************************************************************************/ -LRESULT PASCAL DriverProc(DWORD dwDriverID, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2) { - CodecInst* pi = (CodecInst*)dwDriverID; - - switch (uiMessage) { - case DRV_LOAD: - return (LRESULT)1L; - - case DRV_FREE: - return (LRESULT)1L; - - case DRV_OPEN: - // GAAH! This used to return a pointer to 0xFFFF0000 when lParam==0! - return (LRESULT)(DWORD)(UINT) Open((ICOPEN*) lParam2); - - case DRV_CLOSE: - if (pi) Close(pi); - return (LRESULT)1L; - - /********************************************************************* - - state messages - - *********************************************************************/ - - // cwk - case DRV_QUERYCONFIGURE: // configuration from drivers applet - return (LRESULT)1L; - - case DRV_CONFIGURE: - pi->Configure((HWND)lParam1); - return DRV_OK; - - case ICM_CONFIGURE: - // - // return ICERR_OK if you will do a configure box, error otherwise - // - if (lParam1 == -1) - return pi->QueryConfigure() ? ICERR_OK : ICERR_UNSUPPORTED; - else - return pi->Configure((HWND)lParam1); - - case ICM_ABOUT: - // - // return ICERR_OK if you will do a about box, error otherwise - // - if (lParam1 == -1) - return pi->QueryAbout() ? ICERR_OK : ICERR_UNSUPPORTED; - else - return pi->About((HWND)lParam1); - - case ICM_GETSTATE: - return pi->GetState((LPVOID)lParam1, (DWORD)lParam2); - - case ICM_SETSTATE: - return pi->SetState((LPVOID)lParam1, (DWORD)lParam2); - - case ICM_GETINFO: - return pi->GetInfo((ICINFO*)lParam1, (DWORD)lParam2); - - case ICM_GETDEFAULTQUALITY: - if (lParam1) { - *((LPDWORD)lParam1) = 10000; - return ICERR_OK; - } - break; - - /********************************************************************* - - compression messages - - *********************************************************************/ - - case ICM_COMPRESS_QUERY: - return pi->CompressQuery((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_COMPRESS_BEGIN: - return pi->CompressBegin((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_COMPRESS_GET_FORMAT: - return pi->CompressGetFormat((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_COMPRESS_GET_SIZE: - return pi->CompressGetSize((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_COMPRESS: - return pi->Compress((ICCOMPRESS*)lParam1, (DWORD)lParam2); - - case ICM_COMPRESS_END: - return pi->CompressEnd(); - - /********************************************************************* - - decompress messages - - *********************************************************************/ - - case ICM_DECOMPRESS_QUERY: - return pi->DecompressQuery((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_DECOMPRESS_BEGIN: - return pi->DecompressBegin((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_DECOMPRESS_GET_FORMAT: - return pi->DecompressGetFormat((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_DECOMPRESS_GET_PALETTE: - return pi->DecompressGetPalette((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); - - case ICM_DECOMPRESS: - return pi->Decompress((ICDECOMPRESS*)lParam1, (DWORD)lParam2); - - case ICM_DECOMPRESS_END: - return pi->DecompressEnd(); - - /********************************************************************* - - standard driver messages - - *********************************************************************/ - - case DRV_DISABLE: - case DRV_ENABLE: - return (LRESULT)1L; - - case DRV_INSTALL: - case DRV_REMOVE: - return (LRESULT)DRV_OK; - } - - if (uiMessage < DRV_USER) - return DefDriverProc(dwDriverID, hDriver, uiMessage, lParam1, lParam2); - else - return ICERR_UNSUPPORTED; -} - - -HMODULE hmoduleCodec=0; - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD, LPVOID) { - hmoduleCodec = (HMODULE) hinstDLL; - return TRUE; -} +/* + * Copyright (C) 2002-2010 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. + */ +// +// Zipped Motion Block Video +// +// Based on Huffyuv by Ben Rudiak-Gould. +// which was based on MSYUV sample code, which is: +// Copyright (c) 1993 Microsoft Corporation. +// All Rights Reserved. +// + +#include "zmbv_vfw.h" + +/*************************************************************************** + * DriverProc - The entry point for an installable driver. + * + * PARAMETERS + * dwDriverId: For most messages, is the DWORD + * value that the driver returns in response to a message. + * Each time that the driver is opened, through the API, + * the driver receives a message and can return an + * arbitrary, non-zero value. The installable driver interface + * saves this value and returns a unique driver handle to the + * application. Whenever the application sends a message to the + * driver using the driver handle, the interface routes the message + * to this entry point and passes the corresponding . + * This mechanism allows the driver to use the same or different + * identifiers for multiple opens but ensures that driver handles + * are unique at the application interface layer. + * + * The following messages are not related to a particular open + * instance of the driver. For these messages, the dwDriverId + * will always be zero. + * + * DRV_LOAD, DRV_FREE, DRV_ENABLE, DRV_DISABLE, DRV_OPEN + * + * hDriver: This is the handle returned to the application by the + * driver interface. + * + * uiMessage: The requested action to be performed. Message + * values below are used for globally defined messages. + * Message values from to are used for + * defined driver protocols. Messages above are used + * for driver specific messages. + * + * lParam1: Data for this message. Defined separately for + * each message + * + * lParam2: Data for this message. Defined separately for + * each message + * + * RETURNS + * Defined separately for each message. + * + ***************************************************************************/ +LRESULT PASCAL DriverProc(DWORD dwDriverID, HDRVR hDriver, UINT uiMessage, LPARAM lParam1, LPARAM lParam2) { + CodecInst* pi = (CodecInst*)dwDriverID; + + switch (uiMessage) { + case DRV_LOAD: + return (LRESULT)1L; + + case DRV_FREE: + return (LRESULT)1L; + + case DRV_OPEN: + // GAAH! This used to return a pointer to 0xFFFF0000 when lParam==0! + return (LRESULT)(DWORD)(UINT) Open((ICOPEN*) lParam2); + + case DRV_CLOSE: + if (pi) Close(pi); + return (LRESULT)1L; + + /********************************************************************* + + state messages + + *********************************************************************/ + + // cwk + case DRV_QUERYCONFIGURE: // configuration from drivers applet + return (LRESULT)1L; + + case DRV_CONFIGURE: + pi->Configure((HWND)lParam1); + return DRV_OK; + + case ICM_CONFIGURE: + // + // return ICERR_OK if you will do a configure box, error otherwise + // + if (lParam1 == -1) + return pi->QueryConfigure() ? ICERR_OK : ICERR_UNSUPPORTED; + else + return pi->Configure((HWND)lParam1); + + case ICM_ABOUT: + // + // return ICERR_OK if you will do a about box, error otherwise + // + if (lParam1 == -1) + return pi->QueryAbout() ? ICERR_OK : ICERR_UNSUPPORTED; + else + return pi->About((HWND)lParam1); + + case ICM_GETSTATE: + return pi->GetState((LPVOID)lParam1, (DWORD)lParam2); + + case ICM_SETSTATE: + return pi->SetState((LPVOID)lParam1, (DWORD)lParam2); + + case ICM_GETINFO: + return pi->GetInfo((ICINFO*)lParam1, (DWORD)lParam2); + + case ICM_GETDEFAULTQUALITY: + if (lParam1) { + *((LPDWORD)lParam1) = 10000; + return ICERR_OK; + } + break; + + /********************************************************************* + + compression messages + + *********************************************************************/ + + case ICM_COMPRESS_QUERY: + return pi->CompressQuery((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_BEGIN: + return pi->CompressBegin((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_GET_FORMAT: + return pi->CompressGetFormat((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS_GET_SIZE: + return pi->CompressGetSize((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_COMPRESS: + return pi->Compress((ICCOMPRESS*)lParam1, (DWORD)lParam2); + + case ICM_COMPRESS_END: + return pi->CompressEnd(); + + /********************************************************************* + + decompress messages + + *********************************************************************/ + + case ICM_DECOMPRESS_QUERY: + return pi->DecompressQuery((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS_BEGIN: + return pi->DecompressBegin((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS_GET_FORMAT: + return pi->DecompressGetFormat((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS_GET_PALETTE: + return pi->DecompressGetPalette((LPBITMAPINFOHEADER)lParam1, (LPBITMAPINFOHEADER)lParam2); + + case ICM_DECOMPRESS: + return pi->Decompress((ICDECOMPRESS*)lParam1, (DWORD)lParam2); + + case ICM_DECOMPRESS_END: + return pi->DecompressEnd(); + + /********************************************************************* + + standard driver messages + + *********************************************************************/ + + case DRV_DISABLE: + case DRV_ENABLE: + return (LRESULT)1L; + + case DRV_INSTALL: + case DRV_REMOVE: + return (LRESULT)DRV_OK; + } + + if (uiMessage < DRV_USER) + return DefDriverProc(dwDriverID, hDriver, uiMessage, lParam1, lParam2); + else + return ICERR_UNSUPPORTED; +} + + +HMODULE hmoduleCodec=0; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD, LPVOID) { + hmoduleCodec = (HMODULE) hinstDLL; + return TRUE; +} diff --git a/src/libs/zmbv/resource.h b/src/libs/zmbv/resource.h index f3d9a34..f4830af 100644 --- a/src/libs/zmbv/resource.h +++ b/src/libs/zmbv/resource.h @@ -1,21 +1,21 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by zmbv_vfw.rc -// -#define IDD_ABOUT 101 -#define IDD_CONFIGURE 102 -#define IDC_HOMEPAGE 1000 -#define IDC_EMAIL 1001 -#define IDC_SLIDER1 1008 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 103 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1009 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by zmbv_vfw.rc +// +#define IDD_ABOUT 101 +#define IDD_CONFIGURE 102 +#define IDC_HOMEPAGE 1000 +#define IDC_EMAIL 1001 +#define IDC_SLIDER1 1008 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1009 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/src/libs/zmbv/zmbv.cpp b/src/libs/zmbv/zmbv.cpp index 1457d87..d45e56a 100644 --- a/src/libs/zmbv/zmbv.cpp +++ b/src/libs/zmbv/zmbv.cpp @@ -1,549 +1,549 @@ -/* - * Copyright (C) 2002-2009 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 +#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); -}; +/* + * Copyright (C) 2002-2010 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. + */ + +#ifndef DOSBOX_DOSBOX_H +#ifdef _MSC_VER +#define INLINE __forceinline +#else +#define INLINE inline +#endif +#endif + +#define CODEC_4CC "ZMBV" + +typedef enum { + ZMBV_FORMAT_NONE = 0x00, + ZMBV_FORMAT_1BPP = 0x01, + ZMBV_FORMAT_2BPP = 0x02, + ZMBV_FORMAT_4BPP = 0x03, + ZMBV_FORMAT_8BPP = 0x04, + ZMBV_FORMAT_15BPP = 0x05, + ZMBV_FORMAT_16BPP = 0x06, + ZMBV_FORMAT_24BPP = 0x07, + ZMBV_FORMAT_32BPP = 0x08 +} zmbv_format_t; + +void Msg(const char fmt[], ...); +class VideoCodec { +private: + struct FrameBlock { + int start; + int dx,dy; + }; + struct CodecVector { + int x,y; + int slot; + }; + struct KeyframeHeader { + unsigned char high_version; + unsigned char low_version; + unsigned char compression; + unsigned char format; + unsigned char blockwidth,blockheight; + }; + + struct { + int linesDone; + int writeSize; + int writeDone; + unsigned char *writeBuf; + } compress; + + CodecVector VectorTable[512]; + int VectorCount; + + unsigned char *oldframe, *newframe; + unsigned char *buf1, *buf2, *work; + int bufsize; + + int blockcount; + FrameBlock * blocks; + + int workUsed, workPos; + + int palsize; + char palette[256*4]; + int height, width, pitch; + zmbv_format_t format; + int pixelsize; + + z_stream zstream; + + // methods + void FreeBuffers(void); + void CreateVectorTable(void); + bool SetupBuffers(zmbv_format_t format, int blockwidth, int blockheight); + + template + 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/libs/zmbv/zmbv.inf b/src/libs/zmbv/zmbv.inf index 2ab3ea2..a98ea01 100644 --- a/src/libs/zmbv/zmbv.inf +++ b/src/libs/zmbv/zmbv.inf @@ -1,105 +1,105 @@ -[Version] -Signature="$CHICAGO$" -Provider=%ZMBV_PUBLISHER% -Class=MEDIA - - -[DefaultInstall] -CopyFiles=ZMBV.Files.Inf,ZMBV.Files.Dll -AddReg=ZMBV.Reg9x -UpdateInis=ZMBV.INIs - -[DefaultInstall.ntx86] -CopyFiles=ZMBV.Files.Inf,ZMBV.Files.Dll -AddReg=ZMBV.RegNTx86 -UpdateInis=ZMBV.INIs - -[DefaultInstall.ntamd64] -CopyFiles=ZMBV.Files.Inf,ZMBV.Files.Dll.NTamd64 -AddReg=ZMBV.RegNTamd64 -UpdateInis=ZMBV.INIs - -[DefaultUnInstall] -DelFiles=ZMBV.Files.Dll,ZMBV.Files.Inf,ZMBV.Files.Ini -DelReg=ZMBV.Reg9x -UpdateInis=ZMBV.INIs.Del - -[DefaultUnInstall.ntx86] -DelFiles=ZMBV.Files.Dll,ZMBV.Files.Inf,ZMBV.Files.Ini -DelReg=ZMBV.RegNTx86 -UpdateInis=ZMBV.INIs.Del - -[DefaultUnInstall.ntamd64] -DelFiles=ZMBV.Files.Dll.NTamd64,ZMBV.Files.Inf,ZMBV.Files.Ini -DelReg=ZMBV.RegNTamd64 -UpdateInis=ZMBV.INIs.Del - -[SourceDisksNames] -1="Zip Motion Block Video codec","",1 - -[SourceDisksFiles] -ZMBV.INF=1 - -[DestinationDirs] -ZMBV.Files.Inf=17 -ZMBV.Files.Dll=11 -ZMBV.Files.Dll.NTamd64=10,SysWOW64 -ZMBV.Files.Ini=25 - -[ZMBV.Files.Inf] -zmbv.inf - -[ZMBV.Files.Dll] -zmbv.dll - -[ZMBV.Files.Dll.NTamd64] -zmbv.dll - -[ZMBV.Files.Ini] -zmbv.ini - -[ZMBV.Reg9x] -HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.ZMBV,Description,,"%ZMBV_DISPLAY_NAME%" -HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.ZMBV,Driver,,"zmbv.dll" -HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.ZMBV,FriendlyName,,"%ZMBV_DISPLAY_NAME%" - -HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV -HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,DisplayName,,"%ZMBV_UNINST_DISPLAY_NAME%" -HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,UninstallString,,"rundll.exe setupx.dll,InstallHinfSection DefaultUninstall 132 %17%\ZMBV.INF" - -[ZMBV.RegNTx86] -HKLM,SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers.desc,zmbv.dll,,"%ZMBV_DISPLAY_NAME%" -HKLM,SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers32,vidc.zmbv,,zmbv.dll - -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,DisplayName,,"%ZMBV_UNINST_DISPLAY_NAME%" -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,Publisher,,"%ZMBV_PUBLISHER%" -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,URLInfoAbout,,"%ZMBV_URL_HOMEPAGE%" -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoRepair,0x10001,01,00,00,00 -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoModify,0x10001,01,00,00,00 -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,UninstallString,,"rundll32.exe setupapi,InstallHinfSection DefaultUninstall 132 %17%\ZMBV.INF" - -[ZMBV.RegNTamd64] -HKLM,SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\drivers.desc,zmbv.dll,,"%ZMBV_DISPLAY_NAME%" -HKLM,SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\drivers32,vidc.zmbv,,zmbv.dll - -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,DisplayName,,"%ZMBV_UNINST_DISPLAY_NAME%" -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,Publisher,,"%ZMBV_PUBLISHER%" -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,URLInfoAbout,,"%ZMBV_URL_HOMEPAGE%" -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoRepair,0x10001,01,00,00,00 -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoModify,0x10001,01,00,00,00 -HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,UninstallString,,"rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 %17%\ZMBV.INF" - -[ZMBV.INIs] -system.ini, drivers32,, "VIDC.ZMBV=zmbv.dll" - -[ZMBV.INIs.Del] -system.ini, drivers32, "VIDC.ZMBV=zmbv.dll" - -[Strings] -ZMBV_PUBLISHER = "DOSBox Team" -ZMBV_DISPLAY_NAME = "Zip Motion Block Video [ZMBV]" -ZMBV_UNINST_DISPLAY_NAME = "Zip Motion Block Video codec (Remove Only)" -ZMBV_URL_HOMEPAGE = "http://www.dosbox.com/" -CODEC_INSTALLATION_FINISHED = "Zip Motion Block Video codec installation is complete." +[Version] +Signature="$CHICAGO$" +Provider=%ZMBV_PUBLISHER% +Class=MEDIA + + +[DefaultInstall] +CopyFiles=ZMBV.Files.Inf,ZMBV.Files.Dll +AddReg=ZMBV.Reg9x +UpdateInis=ZMBV.INIs + +[DefaultInstall.ntx86] +CopyFiles=ZMBV.Files.Inf,ZMBV.Files.Dll +AddReg=ZMBV.RegNTx86 +UpdateInis=ZMBV.INIs + +[DefaultInstall.ntamd64] +CopyFiles=ZMBV.Files.Inf,ZMBV.Files.Dll.NTamd64 +AddReg=ZMBV.RegNTamd64 +UpdateInis=ZMBV.INIs + +[DefaultUnInstall] +DelFiles=ZMBV.Files.Dll,ZMBV.Files.Inf,ZMBV.Files.Ini +DelReg=ZMBV.Reg9x +UpdateInis=ZMBV.INIs.Del + +[DefaultUnInstall.ntx86] +DelFiles=ZMBV.Files.Dll,ZMBV.Files.Inf,ZMBV.Files.Ini +DelReg=ZMBV.RegNTx86 +UpdateInis=ZMBV.INIs.Del + +[DefaultUnInstall.ntamd64] +DelFiles=ZMBV.Files.Dll.NTamd64,ZMBV.Files.Inf,ZMBV.Files.Ini +DelReg=ZMBV.RegNTamd64 +UpdateInis=ZMBV.INIs.Del + +[SourceDisksNames] +1="Zip Motion Block Video codec","",1 + +[SourceDisksFiles] +ZMBV.INF=1 + +[DestinationDirs] +ZMBV.Files.Inf=17 +ZMBV.Files.Dll=11 +ZMBV.Files.Dll.NTamd64=10,SysWOW64 +ZMBV.Files.Ini=25 + +[ZMBV.Files.Inf] +zmbv.inf + +[ZMBV.Files.Dll] +zmbv.dll + +[ZMBV.Files.Dll.NTamd64] +zmbv.dll + +[ZMBV.Files.Ini] +zmbv.ini + +[ZMBV.Reg9x] +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.ZMBV,Description,,"%ZMBV_DISPLAY_NAME%" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.ZMBV,Driver,,"zmbv.dll" +HKLM,SYSTEM\CurrentControlSet\Control\MediaResources\icm\VIDC.ZMBV,FriendlyName,,"%ZMBV_DISPLAY_NAME%" + +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,DisplayName,,"%ZMBV_UNINST_DISPLAY_NAME%" +HKLM,Software\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,UninstallString,,"rundll.exe setupx.dll,InstallHinfSection DefaultUninstall 132 %17%\ZMBV.INF" + +[ZMBV.RegNTx86] +HKLM,SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers.desc,zmbv.dll,,"%ZMBV_DISPLAY_NAME%" +HKLM,SOFTWARE\Microsoft\Windows NT\CurrentVersion\drivers32,vidc.zmbv,,zmbv.dll + +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,DisplayName,,"%ZMBV_UNINST_DISPLAY_NAME%" +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,Publisher,,"%ZMBV_PUBLISHER%" +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,URLInfoAbout,,"%ZMBV_URL_HOMEPAGE%" +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoRepair,0x10001,01,00,00,00 +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoModify,0x10001,01,00,00,00 +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,UninstallString,,"rundll32.exe setupapi,InstallHinfSection DefaultUninstall 132 %17%\ZMBV.INF" + +[ZMBV.RegNTamd64] +HKLM,SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\drivers.desc,zmbv.dll,,"%ZMBV_DISPLAY_NAME%" +HKLM,SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\drivers32,vidc.zmbv,,zmbv.dll + +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,DisplayName,,"%ZMBV_UNINST_DISPLAY_NAME%" +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,Publisher,,"%ZMBV_PUBLISHER%" +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,URLInfoAbout,,"%ZMBV_URL_HOMEPAGE%" +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoRepair,0x10001,01,00,00,00 +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,NoModify,0x10001,01,00,00,00 +HKLM,SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\ZMBV,UninstallString,,"rundll32.exe setupapi.dll,InstallHinfSection DefaultUninstall 132 %17%\ZMBV.INF" + +[ZMBV.INIs] +system.ini, drivers32,, "VIDC.ZMBV=zmbv.dll" + +[ZMBV.INIs.Del] +system.ini, drivers32, "VIDC.ZMBV=zmbv.dll" + +[Strings] +ZMBV_PUBLISHER = "DOSBox Team" +ZMBV_DISPLAY_NAME = "Zip Motion Block Video [ZMBV]" +ZMBV_UNINST_DISPLAY_NAME = "Zip Motion Block Video codec (Remove Only)" +ZMBV_URL_HOMEPAGE = "http://www.dosbox.com/" +CODEC_INSTALLATION_FINISHED = "Zip Motion Block Video codec installation is complete." diff --git a/src/libs/zmbv/zmbv.sln b/src/libs/zmbv/zmbv.sln index 07c961a..aea19d7 100644 --- a/src/libs/zmbv/zmbv.sln +++ b/src/libs/zmbv/zmbv.sln @@ -1,21 +1,21 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zmbv", "zmbv.vcproj", "{619CF3F9-C373-4BD5-93DA-025F5E16F8FA}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Debug.ActiveCfg = Debug|Win32 - {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Debug.Build.0 = Debug|Win32 - {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Release.ActiveCfg = Release|Win32 - {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zmbv", "zmbv.vcproj", "{619CF3F9-C373-4BD5-93DA-025F5E16F8FA}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Debug.ActiveCfg = Debug|Win32 + {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Debug.Build.0 = Debug|Win32 + {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Release.ActiveCfg = Release|Win32 + {619CF3F9-C373-4BD5-93DA-025F5E16F8FA}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/src/libs/zmbv/zmbv.vcproj b/src/libs/zmbv/zmbv.vcproj index eecc333..ce973b8 100644 --- a/src/libs/zmbv/zmbv.vcproj +++ b/src/libs/zmbv/zmbv.vcproj @@ -1,141 +1,141 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/zmbv/zmbv_vfw.cpp b/src/libs/zmbv/zmbv_vfw.cpp index f282cdf..5fd6351 100644 --- a/src/libs/zmbv/zmbv_vfw.cpp +++ b/src/libs/zmbv/zmbv_vfw.cpp @@ -1,397 +1,397 @@ -/* - * Copyright (C) 2002-2009 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. - */ -// -// Zipped Motion Block Video -// -// Based on Huffyuv by Ben Rudiak-Gould. -// which was based on MSYUV sample code, which is: -// Copyright (c) 1993 Microsoft Corporation. -// All Rights Reserved. -// - -#include "zmbv_vfw.h" -#include "resource.h" - -#include -#include - -TCHAR szDescription[] = TEXT("Zipped Motion Block Video v0.1"); -TCHAR szName[] = TEXT(CODEC_4CC); - -#define VERSION 0x00000001 // 0.1 - -/******************************************************************** -********************************************************************/ - -CodecInst *encode_table_owner, *decode_table_owner; - -/******************************************************************** -********************************************************************/ - -void Msg(const char fmt[], ...) { - DWORD written; - char buf[2000]; - va_list val; - - va_start(val, fmt); - wvsprintf(buf, fmt, val); - - const COORD _80x50 = {80,50}; - static BOOL startup = (AllocConsole(), SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), _80x50)); - WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, lstrlen(buf), &written, 0); -} - - -/******************************************************************** -********************************************************************/ - -CodecInst::CodecInst() { - codec = 0; -} - -CodecInst* Open(ICOPEN* icinfo) { - if (icinfo && icinfo->fccType != ICTYPE_VIDEO) - return NULL; - - CodecInst* pinst = new CodecInst(); - - if (icinfo) icinfo->dwError = pinst ? ICERR_OK : ICERR_MEMORY; - - return pinst; -} - -DWORD Close(CodecInst* pinst) { -// delete pinst; // this caused problems when deleting at app close time - return 1; -} - -/******************************************************************** -********************************************************************/ - - -/******************************************************************** -********************************************************************/ - -BOOL CodecInst::QueryAbout() { return TRUE; } - -static BOOL CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - if (uMsg == WM_COMMAND) { - switch (LOWORD(wParam)) { - case IDOK: - EndDialog(hwndDlg, 0); - break; - case IDC_HOMEPAGE: - ShellExecute(NULL, NULL, "http://www.dosbox.com", NULL, NULL, SW_SHOW); - break; - case IDC_EMAIL: - ShellExecute(NULL, NULL, "mailto:dosbox.crew@gmail.com", NULL, NULL, SW_SHOW); - break; - } - } - return FALSE; -} -DWORD CodecInst::About(HWND hwnd) { - DialogBox(hmoduleCodec, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDialogProc); - return ICERR_OK; -} - -static BOOL CALLBACK ConfigureDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - - if (uMsg == WM_INITDIALOG) { - - } else if (uMsg == WM_COMMAND) { - - switch (LOWORD(wParam)) { - - case IDOK: - - case IDCANCEL: - EndDialog(hwndDlg, 0); - break; - - default: - return AboutDialogProc(hwndDlg, uMsg, wParam, lParam); // handle email and home-page buttons - } - } - return FALSE; -} - -BOOL CodecInst::QueryConfigure() { return TRUE; } - -DWORD CodecInst::Configure(HWND hwnd) { - DialogBox(hmoduleCodec, MAKEINTRESOURCE(IDD_CONFIGURE), hwnd, ConfigureDialogProc); - return ICERR_OK; -} - - -/******************************************************************** -********************************************************************/ - - -// we have no state information which needs to be stored - -DWORD CodecInst::GetState(LPVOID pv, DWORD dwSize) { return 0; } - -DWORD CodecInst::SetState(LPVOID pv, DWORD dwSize) { return 0; } - - -DWORD CodecInst::GetInfo(ICINFO* icinfo, DWORD dwSize) { - if (icinfo == NULL) - return sizeof(ICINFO); - - if (dwSize < sizeof(ICINFO)) - return 0; - - icinfo->dwSize = sizeof(ICINFO); - icinfo->fccType = ICTYPE_VIDEO; - memcpy(&icinfo->fccHandler,CODEC_4CC, 4); - icinfo->dwFlags = VIDCF_FASTTEMPORALC | VIDCF_FASTTEMPORALD | VIDCF_TEMPORAL; - - icinfo->dwVersion = VERSION; - icinfo->dwVersionICM = ICVERSION; - MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR)); - MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR)); - - return sizeof(ICINFO); -} - -/******************************************************************** -****************************************************************/ - -static int GetInputBitDepth(const BITMAPINFOHEADER *lpbiIn) { - if (lpbiIn->biCompression == BI_RGB) { - if (lpbiIn->biPlanes != 1) - return -1; - - switch(lpbiIn->biBitCount) { - case 8: - return 8; - case 16: - return 15; // Standard Windows 16-bit RGB is 1555. - case 32: - return 32; - } - - } else if (lpbiIn->biCompression == BI_BITFIELDS) { - // BI_BITFIELDS RGB masks lie right after the BITMAPINFOHEADER structure, - // at (ptr+40). This is true even for a BITMAPV4HEADER or BITMAPV5HEADER. - const DWORD *masks = (const DWORD *)(lpbiIn + 1); - - if (lpbiIn->biBitCount == 16) { - // Test for 16 (555) - if (masks[0] == 0x7C00 && masks[1] == 0x03E0 && masks[2] == 0x001F) - return 15; - - // Test for 16 (565) - if (masks[0] == 0xF800 && masks[1] == 0x07E0 && masks[2] == 0x001F) - return 16; - } else if (lpbiIn->biBitCount == 32) { - if (masks[0] == 0xFF0000 && masks[1] == 0x00FF00 && masks[2] == 0x0000FF) - return 32; - } - } - - return -1; -} - -static bool CanCompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, bool requireOutput) { - if (lpbiIn) { - if (GetInputBitDepth(lpbiIn) < 0) - return false; - } else return false; - if (lpbiOut) { - if (memcmp(&lpbiOut->biCompression,CODEC_4CC, 4)) - return false; - } else return !requireOutput; - return true; -} - -/******************************************************************** -****************************************************************/ - -DWORD CodecInst::CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - if (CanCompress(lpbiIn,lpbiOut,false)) return ICERR_OK; - return ICERR_BADFORMAT; -} - -DWORD CodecInst::CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - if (!lpbiOut) - return sizeof(BITMAPINFOHEADER); - lpbiOut->biSize = sizeof(BITMAPINFOHEADER); - lpbiOut->biWidth = lpbiIn->biWidth; - lpbiOut->biHeight = lpbiIn->biHeight; - lpbiOut->biPlanes = 1; - lpbiOut->biCompression = *(const DWORD *)CODEC_4CC; - lpbiOut->biBitCount = lpbiIn->biBitCount; - lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * lpbiIn->biBitCount/8 + 1024; - lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter; - lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter; - lpbiOut->biClrUsed = 0; - lpbiOut->biClrImportant = 0; - return ICERR_OK; -} - -DWORD CodecInst::CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - CompressEnd(); // free resources if necessary - if (!CanCompress(lpbiIn, lpbiOut, true)) - return ICERR_BADFORMAT; - codec = new VideoCodec(); - if (!codec) - return ICERR_MEMORY; - if (!codec->SetupCompress( lpbiIn->biWidth, lpbiIn->biHeight)) - return ICERR_MEMORY; - return ICERR_OK; -} - -DWORD CodecInst::CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - if (!CanCompress(lpbiIn, lpbiOut, true)) - return ICERR_BADFORMAT; - return lpbiIn->biWidth * lpbiIn->biHeight * lpbiIn->biBitCount/8 + 1024; -} - -DWORD CodecInst::Compress(ICCOMPRESS* icinfo, DWORD dwSize) { - int i, pitch; - zmbv_format_t format; - LPBITMAPINFOHEADER lpbiIn=icinfo->lpbiInput; - LPBITMAPINFOHEADER lpbiOut=icinfo->lpbiOutput; - if (!CanCompress(lpbiIn, lpbiOut, true)) - return ICERR_BADFORMAT; - if (!icinfo->lpInput || !icinfo->lpOutput) - return ICERR_ABORT; - switch (GetInputBitDepth(lpbiIn)) { - case 8: - format = ZMBV_FORMAT_8BPP; - pitch = lpbiIn->biWidth; - break; - case 15: - format = ZMBV_FORMAT_15BPP; - pitch = lpbiIn->biWidth * 2; - break; - case 16: - format = ZMBV_FORMAT_16BPP; - pitch = lpbiIn->biWidth * 2; - break; - case 32: - format = ZMBV_FORMAT_32BPP; - pitch = lpbiIn->biWidth * 4; - break; - } - - // DIB scanlines for RGB formats are always aligned to DWORD. - pitch = (pitch + 3) & ~3; - - // force a key frame if requested by the client - int flags = 0; - if (icinfo->dwFlags & ICCOMPRESS_KEYFRAME) - flags |= 1; - - codec->PrepareCompressFrame( flags, format, 0, icinfo->lpOutput, 99999999); - char *readPt = (char *)icinfo->lpInput + pitch*(lpbiIn->biHeight - 1); - for(i = 0;ibiHeight;i++) { - codec->CompressLines(1, (void **)&readPt ); - readPt -= pitch; - } - lpbiOut->biSizeImage = codec->FinishCompressFrame(); - - if (flags & 1) - *icinfo->lpdwFlags = AVIIF_KEYFRAME; - else - *icinfo->lpdwFlags = 0; - - return ICERR_OK; -} - - -DWORD CodecInst::CompressEnd() { - if (codec) - delete codec; - codec = 0; - return ICERR_OK; -} - -/******************************************************************** -********************************************************************/ - -static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - if (memcmp(&lpbiIn->biCompression,CODEC_4CC,4)) - return false; - if (lpbiOut) { - if (lpbiOut->biCompression!=0) return false; - if (lpbiOut->biBitCount != 24) return false; - if (lpbiIn->biWidth!=lpbiOut->biWidth || lpbiIn->biHeight!=lpbiOut->biHeight) - return false; - } - return true; -} - -/******************************************************************** -********************************************************************/ - - -DWORD CodecInst::DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - return CanDecompress(lpbiIn, lpbiOut) ? ICERR_OK : ICERR_BADFORMAT; -} - -DWORD CodecInst::DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - if (memcmp(&lpbiIn->biCompression,CODEC_4CC,4)) - return ICERR_BADFORMAT; - if (!lpbiOut) return sizeof(BITMAPINFOHEADER); - *lpbiOut = *lpbiIn; - lpbiOut->biPlanes = 1; - lpbiOut->biSize = sizeof(BITMAPINFOHEADER); - lpbiOut->biBitCount = 24; - lpbiOut->biSizeImage = ((lpbiOut->biWidth*3 + 3) & ~3) * lpbiOut->biHeight; - lpbiOut->biCompression = BI_RGB; - lpbiOut->biClrUsed = 0; - lpbiOut->biClrImportant = 0; - return ICERR_OK; -} - -DWORD CodecInst::DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - DecompressEnd(); // free resources if necessary - if (!CanDecompress(lpbiIn, lpbiOut)) - return ICERR_BADFORMAT; - codec=new VideoCodec(); - if (!codec) - return ICERR_MEMORY; - if (!codec->SetupDecompress( lpbiIn->biWidth, lpbiIn->biHeight)) - return ICERR_MEMORY; - return ICERR_OK; -} - -DWORD CodecInst::Decompress(ICDECOMPRESS* icinfo, DWORD dwSize) { - if (!codec || !icinfo) - return ICERR_ABORT; - if (codec->DecompressFrame( icinfo->lpInput, icinfo->lpbiInput->biSizeImage)) { - codec->Output_UpsideDown_24(icinfo->lpOutput); - } else return ICERR_DONTDRAW; - return ICERR_OK; -} - - -// palette-mapped output only -DWORD CodecInst::DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { - return ICERR_BADFORMAT; -} - -DWORD CodecInst::DecompressEnd() { - if (codec) - delete codec; - codec = 0; - return ICERR_OK; -} +/* + * Copyright (C) 2002-2010 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. + */ +// +// Zipped Motion Block Video +// +// Based on Huffyuv by Ben Rudiak-Gould. +// which was based on MSYUV sample code, which is: +// Copyright (c) 1993 Microsoft Corporation. +// All Rights Reserved. +// + +#include "zmbv_vfw.h" +#include "resource.h" + +#include +#include + +TCHAR szDescription[] = TEXT("Zipped Motion Block Video v0.1"); +TCHAR szName[] = TEXT(CODEC_4CC); + +#define VERSION 0x00000001 // 0.1 + +/******************************************************************** +********************************************************************/ + +CodecInst *encode_table_owner, *decode_table_owner; + +/******************************************************************** +********************************************************************/ + +void Msg(const char fmt[], ...) { + DWORD written; + char buf[2000]; + va_list val; + + va_start(val, fmt); + wvsprintf(buf, fmt, val); + + const COORD _80x50 = {80,50}; + static BOOL startup = (AllocConsole(), SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), _80x50)); + WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), buf, lstrlen(buf), &written, 0); +} + + +/******************************************************************** +********************************************************************/ + +CodecInst::CodecInst() { + codec = 0; +} + +CodecInst* Open(ICOPEN* icinfo) { + if (icinfo && icinfo->fccType != ICTYPE_VIDEO) + return NULL; + + CodecInst* pinst = new CodecInst(); + + if (icinfo) icinfo->dwError = pinst ? ICERR_OK : ICERR_MEMORY; + + return pinst; +} + +DWORD Close(CodecInst* pinst) { +// delete pinst; // this caused problems when deleting at app close time + return 1; +} + +/******************************************************************** +********************************************************************/ + + +/******************************************************************** +********************************************************************/ + +BOOL CodecInst::QueryAbout() { return TRUE; } + +static BOOL CALLBACK AboutDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + if (uMsg == WM_COMMAND) { + switch (LOWORD(wParam)) { + case IDOK: + EndDialog(hwndDlg, 0); + break; + case IDC_HOMEPAGE: + ShellExecute(NULL, NULL, "http://www.dosbox.com", NULL, NULL, SW_SHOW); + break; + case IDC_EMAIL: + ShellExecute(NULL, NULL, "mailto:dosbox.crew@gmail.com", NULL, NULL, SW_SHOW); + break; + } + } + return FALSE; +} +DWORD CodecInst::About(HWND hwnd) { + DialogBox(hmoduleCodec, MAKEINTRESOURCE(IDD_ABOUT), hwnd, AboutDialogProc); + return ICERR_OK; +} + +static BOOL CALLBACK ConfigureDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { + + if (uMsg == WM_INITDIALOG) { + + } else if (uMsg == WM_COMMAND) { + + switch (LOWORD(wParam)) { + + case IDOK: + + case IDCANCEL: + EndDialog(hwndDlg, 0); + break; + + default: + return AboutDialogProc(hwndDlg, uMsg, wParam, lParam); // handle email and home-page buttons + } + } + return FALSE; +} + +BOOL CodecInst::QueryConfigure() { return TRUE; } + +DWORD CodecInst::Configure(HWND hwnd) { + DialogBox(hmoduleCodec, MAKEINTRESOURCE(IDD_CONFIGURE), hwnd, ConfigureDialogProc); + return ICERR_OK; +} + + +/******************************************************************** +********************************************************************/ + + +// we have no state information which needs to be stored + +DWORD CodecInst::GetState(LPVOID pv, DWORD dwSize) { return 0; } + +DWORD CodecInst::SetState(LPVOID pv, DWORD dwSize) { return 0; } + + +DWORD CodecInst::GetInfo(ICINFO* icinfo, DWORD dwSize) { + if (icinfo == NULL) + return sizeof(ICINFO); + + if (dwSize < sizeof(ICINFO)) + return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = ICTYPE_VIDEO; + memcpy(&icinfo->fccHandler,CODEC_4CC, 4); + icinfo->dwFlags = VIDCF_FASTTEMPORALC | VIDCF_FASTTEMPORALD | VIDCF_TEMPORAL; + + icinfo->dwVersion = VERSION; + icinfo->dwVersionICM = ICVERSION; + MultiByteToWideChar(CP_ACP, 0, szDescription, -1, icinfo->szDescription, sizeof(icinfo->szDescription)/sizeof(WCHAR)); + MultiByteToWideChar(CP_ACP, 0, szName, -1, icinfo->szName, sizeof(icinfo->szName)/sizeof(WCHAR)); + + return sizeof(ICINFO); +} + +/******************************************************************** +****************************************************************/ + +static int GetInputBitDepth(const BITMAPINFOHEADER *lpbiIn) { + if (lpbiIn->biCompression == BI_RGB) { + if (lpbiIn->biPlanes != 1) + return -1; + + switch(lpbiIn->biBitCount) { + case 8: + return 8; + case 16: + return 15; // Standard Windows 16-bit RGB is 1555. + case 32: + return 32; + } + + } else if (lpbiIn->biCompression == BI_BITFIELDS) { + // BI_BITFIELDS RGB masks lie right after the BITMAPINFOHEADER structure, + // at (ptr+40). This is true even for a BITMAPV4HEADER or BITMAPV5HEADER. + const DWORD *masks = (const DWORD *)(lpbiIn + 1); + + if (lpbiIn->biBitCount == 16) { + // Test for 16 (555) + if (masks[0] == 0x7C00 && masks[1] == 0x03E0 && masks[2] == 0x001F) + return 15; + + // Test for 16 (565) + if (masks[0] == 0xF800 && masks[1] == 0x07E0 && masks[2] == 0x001F) + return 16; + } else if (lpbiIn->biBitCount == 32) { + if (masks[0] == 0xFF0000 && masks[1] == 0x00FF00 && masks[2] == 0x0000FF) + return 32; + } + } + + return -1; +} + +static bool CanCompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut, bool requireOutput) { + if (lpbiIn) { + if (GetInputBitDepth(lpbiIn) < 0) + return false; + } else return false; + if (lpbiOut) { + if (memcmp(&lpbiOut->biCompression,CODEC_4CC, 4)) + return false; + } else return !requireOutput; + return true; +} + +/******************************************************************** +****************************************************************/ + +DWORD CodecInst::CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + if (CanCompress(lpbiIn,lpbiOut,false)) return ICERR_OK; + return ICERR_BADFORMAT; +} + +DWORD CodecInst::CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + if (!lpbiOut) + return sizeof(BITMAPINFOHEADER); + lpbiOut->biSize = sizeof(BITMAPINFOHEADER); + lpbiOut->biWidth = lpbiIn->biWidth; + lpbiOut->biHeight = lpbiIn->biHeight; + lpbiOut->biPlanes = 1; + lpbiOut->biCompression = *(const DWORD *)CODEC_4CC; + lpbiOut->biBitCount = lpbiIn->biBitCount; + lpbiOut->biSizeImage = lpbiIn->biWidth * lpbiIn->biHeight * lpbiIn->biBitCount/8 + 1024; + lpbiOut->biXPelsPerMeter = lpbiIn->biXPelsPerMeter; + lpbiOut->biYPelsPerMeter = lpbiIn->biYPelsPerMeter; + lpbiOut->biClrUsed = 0; + lpbiOut->biClrImportant = 0; + return ICERR_OK; +} + +DWORD CodecInst::CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + CompressEnd(); // free resources if necessary + if (!CanCompress(lpbiIn, lpbiOut, true)) + return ICERR_BADFORMAT; + codec = new VideoCodec(); + if (!codec) + return ICERR_MEMORY; + if (!codec->SetupCompress( lpbiIn->biWidth, lpbiIn->biHeight)) + return ICERR_MEMORY; + return ICERR_OK; +} + +DWORD CodecInst::CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + if (!CanCompress(lpbiIn, lpbiOut, true)) + return ICERR_BADFORMAT; + return lpbiIn->biWidth * lpbiIn->biHeight * lpbiIn->biBitCount/8 + 1024; +} + +DWORD CodecInst::Compress(ICCOMPRESS* icinfo, DWORD dwSize) { + int i, pitch; + zmbv_format_t format; + LPBITMAPINFOHEADER lpbiIn=icinfo->lpbiInput; + LPBITMAPINFOHEADER lpbiOut=icinfo->lpbiOutput; + if (!CanCompress(lpbiIn, lpbiOut, true)) + return ICERR_BADFORMAT; + if (!icinfo->lpInput || !icinfo->lpOutput) + return ICERR_ABORT; + switch (GetInputBitDepth(lpbiIn)) { + case 8: + format = ZMBV_FORMAT_8BPP; + pitch = lpbiIn->biWidth; + break; + case 15: + format = ZMBV_FORMAT_15BPP; + pitch = lpbiIn->biWidth * 2; + break; + case 16: + format = ZMBV_FORMAT_16BPP; + pitch = lpbiIn->biWidth * 2; + break; + case 32: + format = ZMBV_FORMAT_32BPP; + pitch = lpbiIn->biWidth * 4; + break; + } + + // DIB scanlines for RGB formats are always aligned to DWORD. + pitch = (pitch + 3) & ~3; + + // force a key frame if requested by the client + int flags = 0; + if (icinfo->dwFlags & ICCOMPRESS_KEYFRAME) + flags |= 1; + + codec->PrepareCompressFrame( flags, format, 0, icinfo->lpOutput, 99999999); + char *readPt = (char *)icinfo->lpInput + pitch*(lpbiIn->biHeight - 1); + for(i = 0;ibiHeight;i++) { + codec->CompressLines(1, (void **)&readPt ); + readPt -= pitch; + } + lpbiOut->biSizeImage = codec->FinishCompressFrame(); + + if (flags & 1) + *icinfo->lpdwFlags = AVIIF_KEYFRAME; + else + *icinfo->lpdwFlags = 0; + + return ICERR_OK; +} + + +DWORD CodecInst::CompressEnd() { + if (codec) + delete codec; + codec = 0; + return ICERR_OK; +} + +/******************************************************************** +********************************************************************/ + +static bool CanDecompress(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + if (memcmp(&lpbiIn->biCompression,CODEC_4CC,4)) + return false; + if (lpbiOut) { + if (lpbiOut->biCompression!=0) return false; + if (lpbiOut->biBitCount != 24) return false; + if (lpbiIn->biWidth!=lpbiOut->biWidth || lpbiIn->biHeight!=lpbiOut->biHeight) + return false; + } + return true; +} + +/******************************************************************** +********************************************************************/ + + +DWORD CodecInst::DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + return CanDecompress(lpbiIn, lpbiOut) ? ICERR_OK : ICERR_BADFORMAT; +} + +DWORD CodecInst::DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + if (memcmp(&lpbiIn->biCompression,CODEC_4CC,4)) + return ICERR_BADFORMAT; + if (!lpbiOut) return sizeof(BITMAPINFOHEADER); + *lpbiOut = *lpbiIn; + lpbiOut->biPlanes = 1; + lpbiOut->biSize = sizeof(BITMAPINFOHEADER); + lpbiOut->biBitCount = 24; + lpbiOut->biSizeImage = ((lpbiOut->biWidth*3 + 3) & ~3) * lpbiOut->biHeight; + lpbiOut->biCompression = BI_RGB; + lpbiOut->biClrUsed = 0; + lpbiOut->biClrImportant = 0; + return ICERR_OK; +} + +DWORD CodecInst::DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + DecompressEnd(); // free resources if necessary + if (!CanDecompress(lpbiIn, lpbiOut)) + return ICERR_BADFORMAT; + codec=new VideoCodec(); + if (!codec) + return ICERR_MEMORY; + if (!codec->SetupDecompress( lpbiIn->biWidth, lpbiIn->biHeight)) + return ICERR_MEMORY; + return ICERR_OK; +} + +DWORD CodecInst::Decompress(ICDECOMPRESS* icinfo, DWORD dwSize) { + if (!codec || !icinfo) + return ICERR_ABORT; + if (codec->DecompressFrame( icinfo->lpInput, icinfo->lpbiInput->biSizeImage)) { + codec->Output_UpsideDown_24(icinfo->lpOutput); + } else return ICERR_DONTDRAW; + return ICERR_OK; +} + + +// palette-mapped output only +DWORD CodecInst::DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut) { + return ICERR_BADFORMAT; +} + +DWORD CodecInst::DecompressEnd() { + if (codec) + delete codec; + codec = 0; + return ICERR_OK; +} diff --git a/src/libs/zmbv/zmbv_vfw.h b/src/libs/zmbv/zmbv_vfw.h index 02688b9..9f50656 100644 --- a/src/libs/zmbv/zmbv_vfw.h +++ b/src/libs/zmbv/zmbv_vfw.h @@ -1,61 +1,61 @@ -// -// Huffyuv v2.1.1, by Ben Rudiak-Gould. -// http://www.math.berkeley.edu/~benrg/huffyuv.html -// -// This file is copyright 2000 Ben Rudiak-Gould, and distributed under -// the terms of the GNU General Public License, v2 or later. See -// http://www.gnu.org/copyleft/gpl.html. -// -// I edit these files in 10-point Verdana, a proportionally-spaced font. -// You may notice formatting oddities if you use a monospaced font. -// - - -#include -#include -#include -#include "zmbv.h" -#pragma hdrstop - -extern HMODULE hmoduleCodec; - - -// huffyuv.cpp - -class CodecInst { -private: - VideoCodec * codec; -public: - CodecInst(); - ~CodecInst(); - - BOOL QueryAbout(); - DWORD About(HWND hwnd); - - BOOL QueryConfigure(); - DWORD Configure(HWND hwnd); - - DWORD GetState(LPVOID pv, DWORD dwSize); - DWORD SetState(LPVOID pv, DWORD dwSize); - - DWORD GetInfo(ICINFO* icinfo, DWORD dwSize); - - DWORD CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD Compress(ICCOMPRESS* icinfo, DWORD dwSize); - DWORD CompressEnd(); - - DWORD DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - - DWORD Decompress(ICDECOMPRESS* icinfo, DWORD dwSize); - DWORD DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); - DWORD DecompressEnd(); -}; - -CodecInst* Open(ICOPEN* icinfo); -DWORD Close(CodecInst* pinst); - +// +// Huffyuv v2.1.1, by Ben Rudiak-Gould. +// http://www.math.berkeley.edu/~benrg/huffyuv.html +// +// This file is copyright 2000 Ben Rudiak-Gould, and distributed under +// the terms of the GNU General Public License, v2 or later. See +// http://www.gnu.org/copyleft/gpl.html. +// +// I edit these files in 10-point Verdana, a proportionally-spaced font. +// You may notice formatting oddities if you use a monospaced font. +// + + +#include +#include +#include +#include "zmbv.h" +#pragma hdrstop + +extern HMODULE hmoduleCodec; + + +// huffyuv.cpp + +class CodecInst { +private: + VideoCodec * codec; +public: + CodecInst(); + ~CodecInst(); + + BOOL QueryAbout(); + DWORD About(HWND hwnd); + + BOOL QueryConfigure(); + DWORD Configure(HWND hwnd); + + DWORD GetState(LPVOID pv, DWORD dwSize); + DWORD SetState(LPVOID pv, DWORD dwSize); + + DWORD GetInfo(ICINFO* icinfo, DWORD dwSize); + + DWORD CompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD CompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD CompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD CompressGetSize(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD Compress(ICCOMPRESS* icinfo, DWORD dwSize); + DWORD CompressEnd(); + + DWORD DecompressQuery(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD DecompressGetFormat(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD DecompressBegin(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + + DWORD Decompress(ICDECOMPRESS* icinfo, DWORD dwSize); + DWORD DecompressGetPalette(LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut); + DWORD DecompressEnd(); +}; + +CodecInst* Open(ICOPEN* icinfo); +DWORD Close(CodecInst* pinst); + diff --git a/src/libs/zmbv/zmbv_vfw.rc b/src/libs/zmbv/zmbv_vfw.rc index 4d670d5..41d8229 100644 --- a/src/libs/zmbv/zmbv_vfw.rc +++ b/src/libs/zmbv/zmbv_vfw.rc @@ -1,123 +1,123 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUT DIALOGEX 0, 0, 167, 55 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | - WS_SYSMENU -CAPTION "DOSBox Video Codec v0.1" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - DEFPUSHBUTTON "OK",IDOK,131,34,29,14 - CTEXT "Zipped Motion Block Video v 0.1\nCopyright 2009, DOSBox Team", - IDC_STATIC,7,7,153,25,SS_NOPREFIX - PUSHBUTTON "Email author",IDC_EMAIL,7,34,50,14 - PUSHBUTTON "Visit home page",IDC_HOMEPAGE,59,34,58,14 -END - -IDD_CONFIGURE DIALOGEX 0, 0, 213, 146 -STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | - WS_SYSMENU -CAPTION "ZMBV configuration dialog" -FONT 8, "MS Sans Serif", 0, 0, 0x0 -BEGIN - PUSHBUTTON "Email author",IDC_EMAIL,44,86,50,14 - PUSHBUTTON "Visit home page",IDC_HOMEPAGE,109,87,58,14 - DEFPUSHBUTTON "OK",IDOK,44,125,50,14 - PUSHBUTTON "Cancel",IDCANCEL,117,125,50,14 - CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | - TBS_NOTICKS | WS_TABSTOP,57,30,92,18 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ABOUT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 160 - TOPMARGIN, 7 - BOTTOMMARGIN, 48 - END - - IDD_CONFIGURE, DIALOG - BEGIN - LEFTMARGIN, 44 - RIGHTMARGIN, 167 - TOPMARGIN, 6 - BOTTOMMARGIN, 139 - END -END -#endif // APSTUDIO_INVOKED - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOGEX 0, 0, 167, 55 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "DOSBox Video Codec v0.1" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + DEFPUSHBUTTON "OK",IDOK,131,34,29,14 + CTEXT "Zipped Motion Block Video v 0.1\nCopyright 2009, DOSBox Team", + IDC_STATIC,7,7,153,25,SS_NOPREFIX + PUSHBUTTON "Email author",IDC_EMAIL,7,34,50,14 + PUSHBUTTON "Visit home page",IDC_HOMEPAGE,59,34,58,14 +END + +IDD_CONFIGURE DIALOGEX 0, 0, 213, 146 +STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | + WS_SYSMENU +CAPTION "ZMBV configuration dialog" +FONT 8, "MS Sans Serif", 0, 0, 0x0 +BEGIN + PUSHBUTTON "Email author",IDC_EMAIL,44,86,50,14 + PUSHBUTTON "Visit home page",IDC_HOMEPAGE,109,87,58,14 + DEFPUSHBUTTON "OK",IDOK,44,125,50,14 + PUSHBUTTON "Cancel",IDCANCEL,117,125,50,14 + CONTROL "",IDC_SLIDER1,"msctls_trackbar32",TBS_BOTH | + TBS_NOTICKS | WS_TABSTOP,57,30,92,18 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 160 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_CONFIGURE, DIALOG + BEGIN + LEFTMARGIN, 44 + RIGHTMARGIN, 167 + TOPMARGIN, 6 + BOTTOMMARGIN, 139 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/src/misc/cross.cpp b/src/misc/cross.cpp index 31be629..24d2411 100644 --- a/src/misc/cross.cpp +++ b/src/misc/cross.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/misc/messages.cpp b/src/misc/messages.cpp index b2ce3d9..b253d79 100644 --- a/src/misc/messages.cpp +++ b/src/misc/messages.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/misc/programs.cpp b/src/misc/programs.cpp index b67aee7..f88f06e 100644 --- a/src/misc/programs.cpp +++ b/src/misc/programs.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -137,18 +137,38 @@ void Program::WriteOut(const char * format,...) { va_end(msg); Bit16u size = (Bit16u)strlen(buf); - DOS_WriteFile(STDOUT,(Bit8u *)buf,&size); + for(Bit16u i = 0; i < size;i++) { + Bit8u out;Bit16u s=1; + if(buf[i] == 0xA && i > 0 && buf[i-1] !=0xD) { + out = 0xD;DOS_WriteFile(STDOUT,&out,&s); + } + out = buf[i]; + DOS_WriteFile(STDOUT,&out,&s); + } + +// DOS_WriteFile(STDOUT,(Bit8u *)buf,&size); } void Program::WriteOut_NoParsing(const char * format) { Bit16u size = (Bit16u)strlen(format); - DOS_WriteFile(STDOUT,(Bit8u *)format,&size); + char const* buf = format; + for(Bit16u i = 0; i < size;i++) { + Bit8u out;Bit16u s=1; + if(buf[i] == 0xA && i > 0 && buf[i-1] !=0xD) { + out = 0xD;DOS_WriteFile(STDOUT,&out,&s); + } + out = buf[i]; + DOS_WriteFile(STDOUT,&out,&s); + } + +// DOS_WriteFile(STDOUT,(Bit8u *)format,&size); } bool Program::GetEnvStr(const char * entry,std::string & result) { /* Walk through the internal environment and see for a match */ PhysPt env_read=PhysMake(psp->GetEnvironment(),0); + char env_string[1024+1]; result.erase(); if (!entry[0]) return false; diff --git a/src/misc/setup.cpp b/src/misc/setup.cpp index 27bee4b..f87b874 100644 --- a/src/misc/setup.cpp +++ b/src/misc/setup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/misc/support.cpp b/src/misc/support.cpp index 375923a..19d037c 100644 --- a/src/misc/support.cpp +++ b/src/misc/support.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/platform/sdl-win32.diff b/src/platform/sdl-win32.diff index efb89b7..0b9ae53 100644 --- a/src/platform/sdl-win32.diff +++ b/src/platform/sdl-win32.diff @@ -1,55 +1,55 @@ -diff -ru SDL-1.2.12/src/main/win32/version.rc SDL-1.2.12release/src/main/win32/version.rc ---- SDL-1.2.12/src/main/win32/version.rc 2007-07-20 07:52:05.000000000 +0200 -+++ SDL-1.2.12release/src/main/win32/version.rc 2007-08-17 19:03:42.000000000 +0200 -@@ -13,7 +13,7 @@ - FILEVERSION 1,2,12,0 - PRODUCTVERSION 1,2,12,0 - FILEFLAGSMASK 0x3fL -- FILEFLAGS 0x0L -+ FILEFLAGS 0x4L - FILEOS 0x40004L - FILETYPE 0x2L - FILESUBTYPE 0x0L -diff -ru SDL-1.2.12/src/video/SDL_video.c SDL-1.2.12release/src/video/SDL_video.c ---- SDL-1.2.12/src/video/SDL_video.c 2007-07-20 07:52:25.000000000 +0200 -+++ SDL-1.2.12release/src/video/SDL_video.c 2007-08-17 02:51:52.000000000 +0200 -@@ -75,12 +75,12 @@ - #if SDL_VIDEO_DRIVER_GAPI - &GAPI_bootstrap, - #endif --#if SDL_VIDEO_DRIVER_WINDIB -- &WINDIB_bootstrap, --#endif - #if SDL_VIDEO_DRIVER_DDRAW - &DIRECTX_bootstrap, - #endif -+#if SDL_VIDEO_DRIVER_WINDIB -+ &WINDIB_bootstrap, -+#endif - #if SDL_VIDEO_DRIVER_BWINDOW - &BWINDOW_bootstrap, - #endif -diff -ru SDL-1.2.12/src/video/windx5/SDL_dx5events.c SDL-1.2.12release/src/video/windx5/SDL_dx5events.c ---- SDL-1.2.12/src/video/windx5/SDL_dx5events.c 2007-07-20 07:52:25.000000000 +0200 -+++ SDL-1.2.12release/src/video/windx5/SDL_dx5events.c 2007-08-17 02:51:52.000000000 +0200 -@@ -519,7 +519,7 @@ - case WM_SYSKEYDOWN: { - /* Pass syskey to DefWindwoProc (ALT-F4, etc.) */ - } -- break; -+// break; - case WM_KEYUP: - case WM_KEYDOWN: { - /* Ignore windows keyboard messages */; -diff -ru SDL-1.2.12/src/video/windx5/SDL_dx5video.c SDL-1.2.12release/src/video/windx5/SDL_dx5video.c ---- SDL-1.2.12/src/video/windx5/SDL_dx5video.c 2007-07-20 07:52:25.000000000 +0200 -+++ SDL-1.2.12release/src/video/windx5/SDL_dx5video.c 2007-08-17 02:51:52.000000000 +0200 -@@ -1496,7 +1496,7 @@ - } - } - dd_surface3 = NULL; --#if 0 /* FIXME: enable this when SDL consistently reports lost surfaces */ -+#if 1 /* FIXME: enable this when SDL consistently reports lost surfaces */ - if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { - video->flags |= SDL_HWSURFACE; - } else { +diff -ru SDL-1.2.12/src/main/win32/version.rc SDL-1.2.12release/src/main/win32/version.rc +--- SDL-1.2.12/src/main/win32/version.rc 2007-07-20 07:52:05.000000000 +0200 ++++ SDL-1.2.12release/src/main/win32/version.rc 2007-08-17 19:03:42.000000000 +0200 +@@ -13,7 +13,7 @@ + FILEVERSION 1,2,12,0 + PRODUCTVERSION 1,2,12,0 + FILEFLAGSMASK 0x3fL +- FILEFLAGS 0x0L ++ FILEFLAGS 0x4L + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +diff -ru SDL-1.2.12/src/video/SDL_video.c SDL-1.2.12release/src/video/SDL_video.c +--- SDL-1.2.12/src/video/SDL_video.c 2007-07-20 07:52:25.000000000 +0200 ++++ SDL-1.2.12release/src/video/SDL_video.c 2007-08-17 02:51:52.000000000 +0200 +@@ -75,12 +75,12 @@ + #if SDL_VIDEO_DRIVER_GAPI + &GAPI_bootstrap, + #endif +-#if SDL_VIDEO_DRIVER_WINDIB +- &WINDIB_bootstrap, +-#endif + #if SDL_VIDEO_DRIVER_DDRAW + &DIRECTX_bootstrap, + #endif ++#if SDL_VIDEO_DRIVER_WINDIB ++ &WINDIB_bootstrap, ++#endif + #if SDL_VIDEO_DRIVER_BWINDOW + &BWINDOW_bootstrap, + #endif +diff -ru SDL-1.2.12/src/video/windx5/SDL_dx5events.c SDL-1.2.12release/src/video/windx5/SDL_dx5events.c +--- SDL-1.2.12/src/video/windx5/SDL_dx5events.c 2007-07-20 07:52:25.000000000 +0200 ++++ SDL-1.2.12release/src/video/windx5/SDL_dx5events.c 2007-08-17 02:51:52.000000000 +0200 +@@ -519,7 +519,7 @@ + case WM_SYSKEYDOWN: { + /* Pass syskey to DefWindwoProc (ALT-F4, etc.) */ + } +- break; ++// break; + case WM_KEYUP: + case WM_KEYDOWN: { + /* Ignore windows keyboard messages */; +diff -ru SDL-1.2.12/src/video/windx5/SDL_dx5video.c SDL-1.2.12release/src/video/windx5/SDL_dx5video.c +--- SDL-1.2.12/src/video/windx5/SDL_dx5video.c 2007-07-20 07:52:25.000000000 +0200 ++++ SDL-1.2.12release/src/video/windx5/SDL_dx5video.c 2007-08-17 02:51:52.000000000 +0200 +@@ -1496,7 +1496,7 @@ + } + } + dd_surface3 = NULL; +-#if 0 /* FIXME: enable this when SDL consistently reports lost surfaces */ ++#if 1 /* FIXME: enable this when SDL consistently reports lost surfaces */ + if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) { + video->flags |= SDL_HWSURFACE; + } else { diff --git a/src/platform/visualc/config.h b/src/platform/visualc/config.h index a21c723..d49f10a 100644 --- a/src/platform/visualc/config.h +++ b/src/platform/visualc/config.h @@ -1,77 +1,78 @@ -#define VERSION "0.73" - -/* Define to 1 to enable internal debugger, requires libcurses */ -#define C_DEBUG 0 - -/* Define to 1 to enable screenshots, requires libpng */ -#define C_SSHOT 1 - -/* Define to 1 to use opengl display output support */ -#define C_OPENGL 1 - -/* Define to 1 to enable internal modem support, requires SDL_net */ -#define C_MODEM 1 - -/* Define to 1 to enable IPX networking support, requires SDL_net */ -#define C_IPX 1 - -/* Enable some heavy debugging options */ -#define C_HEAVY_DEBUG 0 - -/* The type of cpu this host has */ -#define C_TARGETCPU X86 -//#define C_TARGETCPU X86_64 - -/* Define to 1 to use x86 dynamic cpu core */ -#define C_DYNAMIC_X86 1 - -/* Define to 1 to use recompiling cpu core. Can not be used together with the dynamic-x86 core */ -#define C_DYNREC 0 - -/* Enable memory function inlining in */ -#define C_CORE_INLINE 0 - -/* 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 - -/* environ can be linked */ -#define ENVIRON_LINKED 1 - -/* Define to 1 if you have the header file. */ -#define HAVE_DDRAW_H 1 - -/* Define to 1 if you want serial passthrough support (Win32 only). */ -#define C_DIRECTSERIAL 1 - -#define GCC_ATTRIBUTE(x) /* attribute not supported */ -#define GCC_UNLIKELY(x) (x) - -#define INLINE __forceinline -#define DB_FASTCALL __fastcall - -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#pragma warning(disable : 4996) -#endif - -typedef double Real64; -/* The internal types */ -typedef unsigned char Bit8u; -typedef signed char Bit8s; -typedef unsigned short Bit16u; -typedef signed short Bit16s; -typedef unsigned long Bit32u; -typedef signed long Bit32s; -typedef unsigned __int64 Bit64u; -typedef signed __int64 Bit64s; -typedef unsigned int Bitu; -typedef signed int Bits; - +#define VERSION "0.73" + +/* Define to 1 to enable internal debugger, requires libcurses */ +#define C_DEBUG 0 + +/* Define to 1 to enable screenshots, requires libpng */ +#define C_SSHOT 1 + +/* Define to 1 to use opengl display output support */ +#define C_OPENGL 1 + +/* Define to 1 to enable internal modem support, requires SDL_net */ +#define C_MODEM 1 + +/* Define to 1 to enable IPX networking support, requires SDL_net */ +#define C_IPX 1 + +/* Enable some heavy debugging options */ +#define C_HEAVY_DEBUG 0 + +/* The type of cpu this host has */ +#define C_TARGETCPU X86 +//#define C_TARGETCPU X86_64 + +/* Define to 1 to use x86 dynamic cpu core */ +#define C_DYNAMIC_X86 1 + +/* Define to 1 to use recompiling cpu core. Can not be used together with the dynamic-x86 core */ +#define C_DYNREC 0 + +/* Enable memory function inlining in */ +#define C_CORE_INLINE 0 + +/* 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 + +/* environ can be linked */ +#define ENVIRON_LINKED 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DDRAW_H 1 + +/* Define to 1 if you want serial passthrough support (Win32 only). */ +#define C_DIRECTSERIAL 1 + +#define GCC_ATTRIBUTE(x) /* attribute not supported */ +#define GCC_UNLIKELY(x) (x) +#define GCC_LIKELY(x) (x) + +#define INLINE __forceinline +#define DB_FASTCALL __fastcall + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#pragma warning(disable : 4996) +#endif + +typedef double Real64; +/* The internal types */ +typedef unsigned char Bit8u; +typedef signed char Bit8s; +typedef unsigned short Bit16u; +typedef signed short Bit16s; +typedef unsigned long Bit32u; +typedef signed long Bit32s; +typedef unsigned __int64 Bit64u; +typedef signed __int64 Bit64s; +typedef unsigned int Bitu; +typedef signed int Bits; + diff --git a/src/platform/visualc/ntddcdrm.h b/src/platform/visualc/ntddcdrm.h index b2e592c..c1ee8c2 100644 --- a/src/platform/visualc/ntddcdrm.h +++ b/src/platform/visualc/ntddcdrm.h @@ -1,320 +1,320 @@ -/* - * ntddcdrm.h - * - * CDROM IOCTL interface. - * - * This file is part of the w32api package. - * - * Contributors: - * Created by Casper S. Hornstrup - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __NTDDCDRM_H -#define __NTDDCDRM_H - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#pragma pack(push,4) - -#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM - -#define IOCTL_CDROM_CHECK_VERIFY \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_FIND_NEW_DEVICES \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_GET_CONTROL \ - CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_GET_DRIVE_GEOMETRY \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_GET_LAST_SESSION \ - CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_GET_VOLUME \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_PAUSE_AUDIO \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_PLAY_AUDIO_MSF \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_RAW_READ \ - CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) - -#define IOCTL_CDROM_READ_Q_CHANNEL \ - CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_READ_TOC \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_READ_TOC_EX \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_RESUME_AUDIO \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_SEEK_AUDIO_MSF \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_SET_VOLUME \ - CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_SIMBAD \ - CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) - -#define IOCTL_CDROM_STOP_AUDIO \ - CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) - - -#define MAXIMUM_NUMBER_TRACKS 100 -#define MAXIMUM_CDROM_SIZE 804 -#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 - -typedef struct _TRACK_DATA { - UCHAR Reserved; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR TrackNumber; - UCHAR Reserved1; - UCHAR Address[4]; -} TRACK_DATA, *PTRACK_DATA; - -/* CDROM_DISK_DATA.DiskData flags */ -#define CDROM_DISK_AUDIO_TRACK 0x00000001 -#define CDROM_DISK_DATA_TRACK 0x00000002 - -typedef struct _CDROM_DISK_DATA { - ULONG DiskData; -} CDROM_DISK_DATA, *PCDROM_DISK_DATA; - -typedef struct _CDROM_PLAY_AUDIO_MSF { - UCHAR StartingM; - UCHAR StartingS; - UCHAR StartingF; - UCHAR EndingM; - UCHAR EndingS; - UCHAR EndingF; -} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; - -/* CDROM_READ_TOC_EX.Format constants */ -#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 -#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 -#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 -#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 -#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 -#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 - -typedef struct _CDROM_READ_TOC_EX { - UCHAR Format : 4; - UCHAR Reserved1 : 3; - UCHAR Msf : 1; - UCHAR SessionTrack; - UCHAR Reserved2; - UCHAR Reserved3; -} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; - -typedef struct _CDROM_SEEK_AUDIO_MSF { - UCHAR M; - UCHAR S; - UCHAR F; -} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; - -/* CDROM_SUB_Q_DATA_FORMAT.Format constants */ -#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 -#define IOCTL_CDROM_CURRENT_POSITION 0x01 -#define IOCTL_CDROM_MEDIA_CATALOG 0x02 -#define IOCTL_CDROM_TRACK_ISRC 0x03 - -typedef struct _CDROM_SUB_Q_DATA_FORMAT { - UCHAR Format; - UCHAR Track; -} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; - -typedef struct _CDROM_TOC { - UCHAR Length[2]; - UCHAR FirstTrack; - UCHAR LastTrack; - TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; -} CDROM_TOC, *PCDROM_TOC; - -#define CDROM_TOC_SIZE sizeof(CDROM_TOC) - -typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { - UCHAR CdrwReferenceSpeed : 3; - UCHAR Reserved3 : 1; - UCHAR WritePower : 3; - UCHAR True1 : 1; - UCHAR Reserved4 : 6; - UCHAR UnrestrictedUse : 1; - UCHAR Reserved5 : 1; - UCHAR A3Valid : 1; - UCHAR A2Valid : 1; - UCHAR A1Valid : 1; - UCHAR Reserved6 : 3; - UCHAR IsCdrw : 1; - UCHAR True2 : 1; - UCHAR Reserved7; - UCHAR LeadInMsf[3]; - UCHAR Reserved8; - UCHAR LeadOutMsf[3]; - UCHAR Reserved9; - UCHAR A1Values[3]; - UCHAR Reserved10; - UCHAR A2Values[3]; - UCHAR Reserved11; - UCHAR A3Values[3]; - UCHAR Reserved12; -} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; - -/* CDROM_TOC_CD_TEXT_DATA_BLOCK.PackType constants */ -#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 -#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 -#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 -#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 -#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 -#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 -#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 -#define CDROM_CD_TEXT_PACK_GENRE 0x87 -#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 -#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 -#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e -#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f - -typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { - UCHAR PackType; - UCHAR TrackNumber : 7; - UCHAR ExtensionFlag : 1; - UCHAR SequenceNumber; - UCHAR CharacterPosition : 4; - UCHAR BlockNumber : 3; - UCHAR Unicode : 1; - union { - UCHAR Text[12]; - WCHAR WText[6]; - }; - UCHAR CRC[2]; -} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; - -/* CDROM_TOC_FULL_TOC_DATA_BLOCK.Adr constants */ -#define ADR_NO_MODE_INFORMATION 0x0 -#define ADR_ENCODES_CURRENT_POSITION 0x1 -#define ADR_ENCODES_MEDIA_CATALOG 0x2 -#define ADR_ENCODES_ISRC 0x3 - -typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { - UCHAR SessionNumber; - UCHAR Control : 4; - UCHAR Adr : 4; - UCHAR Reserved1; - UCHAR Point; - UCHAR MsfExtra[3]; - UCHAR Zero; - UCHAR Msf[3]; -} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; - -/* SUB_Q_HEADER.AudioStatus constants */ -#define AUDIO_STATUS_NOT_SUPPORTED 0x00 -#define AUDIO_STATUS_IN_PROGRESS 0x11 -#define AUDIO_STATUS_PAUSED 0x12 -#define AUDIO_STATUS_PLAY_COMPLETE 0x13 -#define AUDIO_STATUS_PLAY_ERROR 0x14 -#define AUDIO_STATUS_NO_STATUS 0x15 - -typedef struct _SUB_Q_HEADER { - UCHAR Reserved; - UCHAR AudioStatus; - UCHAR DataLength[2]; -} SUB_Q_HEADER, *PSUB_Q_HEADER; - -typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved[3]; - UCHAR Reserved1 : 7; - UCHAR Mcval :1; - UCHAR MediaCatalog[15]; -} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; - -typedef struct _SUB_Q_TRACK_ISRC { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Reserved0; - UCHAR Track; - UCHAR Reserved1; - UCHAR Reserved2 : 7; - UCHAR Tcval : 1; - UCHAR TrackIsrc[15]; -} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; - -typedef struct _SUB_Q_CURRENT_POSITION { - SUB_Q_HEADER Header; - UCHAR FormatCode; - UCHAR Control : 4; - UCHAR ADR : 4; - UCHAR TrackNumber; - UCHAR IndexNumber; - UCHAR AbsoluteAddress[4]; - UCHAR TrackRelativeAddress[4]; -} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; - -typedef union _SUB_Q_CHANNEL_DATA { - SUB_Q_CURRENT_POSITION CurrentPosition; - SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; - SUB_Q_TRACK_ISRC TrackIsrc; -} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; - -/* CDROM_AUDIO_CONTROL.LbaFormat constants */ -#define AUDIO_WITH_PREEMPHASIS 0x1 -#define DIGITAL_COPY_PERMITTED 0x2 -#define AUDIO_DATA_TRACK 0x4 -#define TWO_FOUR_CHANNEL_AUDIO 0x8 - -typedef struct _CDROM_AUDIO_CONTROL { - UCHAR LbaFormat; - USHORT LogicalBlocksPerSecond; -} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; - -typedef struct _VOLUME_CONTROL { - UCHAR PortVolume[4]; -} VOLUME_CONTROL, *PVOLUME_CONTROL; - -typedef enum _TRACK_MODE_TYPE { - YellowMode2, - XAForm2, - CDDA -} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; - -typedef struct __RAW_READ_INFO { - LARGE_INTEGER DiskOffset; - ULONG SectorCount; - TRACK_MODE_TYPE TrackMode; -} RAW_READ_INFO, *PRAW_READ_INFO; - -#pragma pack(pop) - -#ifdef __cplusplus -} -#endif - -#endif /* __NTDDCDRM_H */ +/* + * ntddcdrm.h + * + * CDROM IOCTL interface. + * + * This file is part of the w32api package. + * + * Contributors: + * Created by Casper S. Hornstrup + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __NTDDCDRM_H +#define __NTDDCDRM_H + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push,4) + +#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM + +#define IOCTL_CDROM_CHECK_VERIFY \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0200, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_FIND_NEW_DEVICES \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0206, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_GET_CONTROL \ + CTL_CODE(IOCTL_CDROM_BASE, 0x000D, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_GET_DRIVE_GEOMETRY \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_GET_LAST_SESSION \ + CTL_CODE(IOCTL_CDROM_BASE, 0x000E, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_GET_VOLUME \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0005, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_PAUSE_AUDIO \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0003, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_PLAY_AUDIO_MSF \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0006, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_RAW_READ \ + CTL_CODE(IOCTL_CDROM_BASE, 0x000F, METHOD_OUT_DIRECT, FILE_READ_ACCESS) + +#define IOCTL_CDROM_READ_Q_CHANNEL \ + CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_READ_TOC \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_READ_TOC_EX \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0015, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_RESUME_AUDIO \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0004, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_SEEK_AUDIO_MSF \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0001, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_SET_VOLUME \ + CTL_CODE(IOCTL_CDROM_BASE, 0x000A, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_SIMBAD \ + CTL_CODE(IOCTL_CDROM_BASE, 0x1003, METHOD_BUFFERED, FILE_READ_ACCESS) + +#define IOCTL_CDROM_STOP_AUDIO \ + CTL_CODE(IOCTL_CDROM_BASE, 0x0002, METHOD_BUFFERED, FILE_READ_ACCESS) + + +#define MAXIMUM_NUMBER_TRACKS 100 +#define MAXIMUM_CDROM_SIZE 804 +#define MINIMUM_CDROM_READ_TOC_EX_SIZE 2 + +typedef struct _TRACK_DATA { + UCHAR Reserved; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR TrackNumber; + UCHAR Reserved1; + UCHAR Address[4]; +} TRACK_DATA, *PTRACK_DATA; + +/* CDROM_DISK_DATA.DiskData flags */ +#define CDROM_DISK_AUDIO_TRACK 0x00000001 +#define CDROM_DISK_DATA_TRACK 0x00000002 + +typedef struct _CDROM_DISK_DATA { + ULONG DiskData; +} CDROM_DISK_DATA, *PCDROM_DISK_DATA; + +typedef struct _CDROM_PLAY_AUDIO_MSF { + UCHAR StartingM; + UCHAR StartingS; + UCHAR StartingF; + UCHAR EndingM; + UCHAR EndingS; + UCHAR EndingF; +} CDROM_PLAY_AUDIO_MSF, *PCDROM_PLAY_AUDIO_MSF; + +/* CDROM_READ_TOC_EX.Format constants */ +#define CDROM_READ_TOC_EX_FORMAT_TOC 0x00 +#define CDROM_READ_TOC_EX_FORMAT_SESSION 0x01 +#define CDROM_READ_TOC_EX_FORMAT_FULL_TOC 0x02 +#define CDROM_READ_TOC_EX_FORMAT_PMA 0x03 +#define CDROM_READ_TOC_EX_FORMAT_ATIP 0x04 +#define CDROM_READ_TOC_EX_FORMAT_CDTEXT 0x05 + +typedef struct _CDROM_READ_TOC_EX { + UCHAR Format : 4; + UCHAR Reserved1 : 3; + UCHAR Msf : 1; + UCHAR SessionTrack; + UCHAR Reserved2; + UCHAR Reserved3; +} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX; + +typedef struct _CDROM_SEEK_AUDIO_MSF { + UCHAR M; + UCHAR S; + UCHAR F; +} CDROM_SEEK_AUDIO_MSF, *PCDROM_SEEK_AUDIO_MSF; + +/* CDROM_SUB_Q_DATA_FORMAT.Format constants */ +#define IOCTL_CDROM_SUB_Q_CHANNEL 0x00 +#define IOCTL_CDROM_CURRENT_POSITION 0x01 +#define IOCTL_CDROM_MEDIA_CATALOG 0x02 +#define IOCTL_CDROM_TRACK_ISRC 0x03 + +typedef struct _CDROM_SUB_Q_DATA_FORMAT { + UCHAR Format; + UCHAR Track; +} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT; + +typedef struct _CDROM_TOC { + UCHAR Length[2]; + UCHAR FirstTrack; + UCHAR LastTrack; + TRACK_DATA TrackData[MAXIMUM_NUMBER_TRACKS]; +} CDROM_TOC, *PCDROM_TOC; + +#define CDROM_TOC_SIZE sizeof(CDROM_TOC) + +typedef struct _CDROM_TOC_ATIP_DATA_BLOCK { + UCHAR CdrwReferenceSpeed : 3; + UCHAR Reserved3 : 1; + UCHAR WritePower : 3; + UCHAR True1 : 1; + UCHAR Reserved4 : 6; + UCHAR UnrestrictedUse : 1; + UCHAR Reserved5 : 1; + UCHAR A3Valid : 1; + UCHAR A2Valid : 1; + UCHAR A1Valid : 1; + UCHAR Reserved6 : 3; + UCHAR IsCdrw : 1; + UCHAR True2 : 1; + UCHAR Reserved7; + UCHAR LeadInMsf[3]; + UCHAR Reserved8; + UCHAR LeadOutMsf[3]; + UCHAR Reserved9; + UCHAR A1Values[3]; + UCHAR Reserved10; + UCHAR A2Values[3]; + UCHAR Reserved11; + UCHAR A3Values[3]; + UCHAR Reserved12; +} CDROM_TOC_ATIP_DATA_BLOCK, *PCDROM_TOC_ATIP_DATA_BLOCK; + +/* CDROM_TOC_CD_TEXT_DATA_BLOCK.PackType constants */ +#define CDROM_CD_TEXT_PACK_ALBUM_NAME 0x80 +#define CDROM_CD_TEXT_PACK_PERFORMER 0x81 +#define CDROM_CD_TEXT_PACK_SONGWRITER 0x82 +#define CDROM_CD_TEXT_PACK_COMPOSER 0x83 +#define CDROM_CD_TEXT_PACK_ARRANGER 0x84 +#define CDROM_CD_TEXT_PACK_MESSAGES 0x85 +#define CDROM_CD_TEXT_PACK_DISC_ID 0x86 +#define CDROM_CD_TEXT_PACK_GENRE 0x87 +#define CDROM_CD_TEXT_PACK_TOC_INFO 0x88 +#define CDROM_CD_TEXT_PACK_TOC_INFO2 0x89 +#define CDROM_CD_TEXT_PACK_UPC_EAN 0x8e +#define CDROM_CD_TEXT_PACK_SIZE_INFO 0x8f + +typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK { + UCHAR PackType; + UCHAR TrackNumber : 7; + UCHAR ExtensionFlag : 1; + UCHAR SequenceNumber; + UCHAR CharacterPosition : 4; + UCHAR BlockNumber : 3; + UCHAR Unicode : 1; + union { + UCHAR Text[12]; + WCHAR WText[6]; + }; + UCHAR CRC[2]; +} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK; + +/* CDROM_TOC_FULL_TOC_DATA_BLOCK.Adr constants */ +#define ADR_NO_MODE_INFORMATION 0x0 +#define ADR_ENCODES_CURRENT_POSITION 0x1 +#define ADR_ENCODES_MEDIA_CATALOG 0x2 +#define ADR_ENCODES_ISRC 0x3 + +typedef struct _CDROM_TOC_FULL_TOC_DATA_BLOCK { + UCHAR SessionNumber; + UCHAR Control : 4; + UCHAR Adr : 4; + UCHAR Reserved1; + UCHAR Point; + UCHAR MsfExtra[3]; + UCHAR Zero; + UCHAR Msf[3]; +} CDROM_TOC_FULL_TOC_DATA_BLOCK, *PCDROM_TOC_FULL_TOC_DATA_BLOCK; + +/* SUB_Q_HEADER.AudioStatus constants */ +#define AUDIO_STATUS_NOT_SUPPORTED 0x00 +#define AUDIO_STATUS_IN_PROGRESS 0x11 +#define AUDIO_STATUS_PAUSED 0x12 +#define AUDIO_STATUS_PLAY_COMPLETE 0x13 +#define AUDIO_STATUS_PLAY_ERROR 0x14 +#define AUDIO_STATUS_NO_STATUS 0x15 + +typedef struct _SUB_Q_HEADER { + UCHAR Reserved; + UCHAR AudioStatus; + UCHAR DataLength[2]; +} SUB_Q_HEADER, *PSUB_Q_HEADER; + +typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved[3]; + UCHAR Reserved1 : 7; + UCHAR Mcval :1; + UCHAR MediaCatalog[15]; +} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER; + +typedef struct _SUB_Q_TRACK_ISRC { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Reserved0; + UCHAR Track; + UCHAR Reserved1; + UCHAR Reserved2 : 7; + UCHAR Tcval : 1; + UCHAR TrackIsrc[15]; +} SUB_Q_TRACK_ISRC, *PSUB_Q_TRACK_ISRC; + +typedef struct _SUB_Q_CURRENT_POSITION { + SUB_Q_HEADER Header; + UCHAR FormatCode; + UCHAR Control : 4; + UCHAR ADR : 4; + UCHAR TrackNumber; + UCHAR IndexNumber; + UCHAR AbsoluteAddress[4]; + UCHAR TrackRelativeAddress[4]; +} SUB_Q_CURRENT_POSITION, *PSUB_Q_CURRENT_POSITION; + +typedef union _SUB_Q_CHANNEL_DATA { + SUB_Q_CURRENT_POSITION CurrentPosition; + SUB_Q_MEDIA_CATALOG_NUMBER MediaCatalog; + SUB_Q_TRACK_ISRC TrackIsrc; +} SUB_Q_CHANNEL_DATA, *PSUB_Q_CHANNEL_DATA; + +/* CDROM_AUDIO_CONTROL.LbaFormat constants */ +#define AUDIO_WITH_PREEMPHASIS 0x1 +#define DIGITAL_COPY_PERMITTED 0x2 +#define AUDIO_DATA_TRACK 0x4 +#define TWO_FOUR_CHANNEL_AUDIO 0x8 + +typedef struct _CDROM_AUDIO_CONTROL { + UCHAR LbaFormat; + USHORT LogicalBlocksPerSecond; +} CDROM_AUDIO_CONTROL, *PCDROM_AUDIO_CONTROL; + +typedef struct _VOLUME_CONTROL { + UCHAR PortVolume[4]; +} VOLUME_CONTROL, *PVOLUME_CONTROL; + +typedef enum _TRACK_MODE_TYPE { + YellowMode2, + XAForm2, + CDDA +} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE; + +typedef struct __RAW_READ_INFO { + LARGE_INTEGER DiskOffset; + ULONG SectorCount; + TRACK_MODE_TYPE TrackMode; +} RAW_READ_INFO, *PRAW_READ_INFO; + +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif + +#endif /* __NTDDCDRM_H */ diff --git a/src/platform/visualc/ntddscsi.h b/src/platform/visualc/ntddscsi.h index 387862c..e071324 100644 --- a/src/platform/visualc/ntddscsi.h +++ b/src/platform/visualc/ntddscsi.h @@ -1,174 +1,174 @@ -/* - * ntddscsi.h - * - * SCSI port IOCTL interface. - * - * This file is part of the w32api package. - * - * Contributors: - * Created by Casper S. Hornstrup - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef __NTDDSCSI_H -#define __NTDDSCSI_H - -#if __GNUC__ >=3 -#pragma GCC system_header -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#pragma pack(push,4) - -//#include "ntddk.h" - -#define DD_SCSI_DEVICE_NAME "\\Device\\ScsiPort" -#define DD_SCSI_DEVICE_NAME_U L"\\Device\\ScsiPort" - -#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER - -#define IOCTL_SCSI_GET_INQUIRY_DATA \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_SCSI_GET_CAPABILITIES \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_SCSI_GET_ADDRESS \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) - -#define IOCTL_SCSI_MINIPORT \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_SCSI_PASS_THROUGH \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_SCSI_PASS_THROUGH_DIRECT \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) - -#define IOCTL_SCSI_RESCAN_BUS \ - CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS) - - -DEFINE_GUID(ScsiRawInterfaceGuid, 0x53f56309L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); - -DEFINE_GUID(WmiScsiAddressGuid, 0x53f5630fL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); - -typedef struct _SCSI_PASS_THROUGH { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - ULONG_PTR DataBufferOffset; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; - -typedef struct _SCSI_PASS_THROUGH_DIRECT { - USHORT Length; - UCHAR ScsiStatus; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - UCHAR CdbLength; - UCHAR SenseInfoLength; - UCHAR DataIn; - ULONG DataTransferLength; - ULONG TimeOutValue; - PVOID DataBuffer; - ULONG SenseInfoOffset; - UCHAR Cdb[16]; -} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; - -typedef struct _SRB_IO_CONTROL { - ULONG HeaderLength; - UCHAR Signature[8]; - ULONG Timeout; - ULONG ControlCode; - ULONG ReturnCode; - ULONG Length; -} SRB_IO_CONTROL, *PSRB_IO_CONTROL; - -typedef struct _SCSI_ADDRESS { - ULONG Length; - UCHAR PortNumber; - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; -} SCSI_ADDRESS, *PSCSI_ADDRESS; - -typedef struct _SCSI_BUS_DATA { - UCHAR NumberOfLogicalUnits; - UCHAR InitiatorBusId; - ULONG InquiryDataOffset; -}SCSI_BUS_DATA, *PSCSI_BUS_DATA; - -typedef struct _SCSI_ADAPTER_BUS_INFO { - UCHAR NumberOfBuses; - SCSI_BUS_DATA BusData[1]; -} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; - -typedef struct _IO_SCSI_CAPABILITIES { - ULONG Length; - ULONG MaximumTransferLength; - ULONG MaximumPhysicalPages; - ULONG SupportedAsynchronousEvents; - ULONG AlignmentMask; - BOOLEAN TaggedQueuing; - BOOLEAN AdapterScansDown; - BOOLEAN AdapterUsesPio; -} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES; - -typedef struct _SCSI_INQUIRY_DATA { - UCHAR PathId; - UCHAR TargetId; - UCHAR Lun; - BOOLEAN DeviceClaimed; - ULONG InquiryDataLength; - ULONG NextInquiryDataOffset; - UCHAR InquiryData[1]; -} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; - -#define SCSI_IOCTL_DATA_OUT 0 -#define SCSI_IOCTL_DATA_IN 1 -#define SCSI_IOCTL_DATA_UNSPECIFIED 2 - -/* -typedef struct _DUMP_POINTERS { - PADAPTER_OBJECT AdapterObject; - PVOID MappedRegisterBase; - PVOID DumpData; - PVOID CommonBufferVa; - LARGE_INTEGER CommonBufferPa; - ULONG CommonBufferSize; - BOOLEAN AllocateCommonBuffers; - BOOLEAN UseDiskDump; - UCHAR Spare1[2]; - PVOID DeviceObject; -} DUMP_POINTERS, *PDUMP_POINTERS; -*/ -#pragma pack(pop) - -#ifdef __cplusplus -} -#endif - -#endif /* __NTDDSCSI_H */ +/* + * ntddscsi.h + * + * SCSI port IOCTL interface. + * + * This file is part of the w32api package. + * + * Contributors: + * Created by Casper S. Hornstrup + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef __NTDDSCSI_H +#define __NTDDSCSI_H + +#if __GNUC__ >=3 +#pragma GCC system_header +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#pragma pack(push,4) + +//#include "ntddk.h" + +#define DD_SCSI_DEVICE_NAME "\\Device\\ScsiPort" +#define DD_SCSI_DEVICE_NAME_U L"\\Device\\ScsiPort" + +#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER + +#define IOCTL_SCSI_GET_INQUIRY_DATA \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_SCSI_GET_CAPABILITIES \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_SCSI_GET_ADDRESS \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define IOCTL_SCSI_MINIPORT \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_SCSI_PASS_THROUGH \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_SCSI_PASS_THROUGH_DIRECT \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) + +#define IOCTL_SCSI_RESCAN_BUS \ + CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +DEFINE_GUID(ScsiRawInterfaceGuid, 0x53f56309L, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); + +DEFINE_GUID(WmiScsiAddressGuid, 0x53f5630fL, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); + +typedef struct _SCSI_PASS_THROUGH { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + ULONG_PTR DataBufferOffset; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; + +typedef struct _SCSI_PASS_THROUGH_DIRECT { + USHORT Length; + UCHAR ScsiStatus; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + UCHAR CdbLength; + UCHAR SenseInfoLength; + UCHAR DataIn; + ULONG DataTransferLength; + ULONG TimeOutValue; + PVOID DataBuffer; + ULONG SenseInfoOffset; + UCHAR Cdb[16]; +} SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; + +typedef struct _SRB_IO_CONTROL { + ULONG HeaderLength; + UCHAR Signature[8]; + ULONG Timeout; + ULONG ControlCode; + ULONG ReturnCode; + ULONG Length; +} SRB_IO_CONTROL, *PSRB_IO_CONTROL; + +typedef struct _SCSI_ADDRESS { + ULONG Length; + UCHAR PortNumber; + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; +} SCSI_ADDRESS, *PSCSI_ADDRESS; + +typedef struct _SCSI_BUS_DATA { + UCHAR NumberOfLogicalUnits; + UCHAR InitiatorBusId; + ULONG InquiryDataOffset; +}SCSI_BUS_DATA, *PSCSI_BUS_DATA; + +typedef struct _SCSI_ADAPTER_BUS_INFO { + UCHAR NumberOfBuses; + SCSI_BUS_DATA BusData[1]; +} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; + +typedef struct _IO_SCSI_CAPABILITIES { + ULONG Length; + ULONG MaximumTransferLength; + ULONG MaximumPhysicalPages; + ULONG SupportedAsynchronousEvents; + ULONG AlignmentMask; + BOOLEAN TaggedQueuing; + BOOLEAN AdapterScansDown; + BOOLEAN AdapterUsesPio; +} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES; + +typedef struct _SCSI_INQUIRY_DATA { + UCHAR PathId; + UCHAR TargetId; + UCHAR Lun; + BOOLEAN DeviceClaimed; + ULONG InquiryDataLength; + ULONG NextInquiryDataOffset; + UCHAR InquiryData[1]; +} SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; + +#define SCSI_IOCTL_DATA_OUT 0 +#define SCSI_IOCTL_DATA_IN 1 +#define SCSI_IOCTL_DATA_UNSPECIFIED 2 + +/* +typedef struct _DUMP_POINTERS { + PADAPTER_OBJECT AdapterObject; + PVOID MappedRegisterBase; + PVOID DumpData; + PVOID CommonBufferVa; + LARGE_INTEGER CommonBufferPa; + ULONG CommonBufferSize; + BOOLEAN AllocateCommonBuffers; + BOOLEAN UseDiskDump; + UCHAR Spare1[2]; + PVOID DeviceObject; +} DUMP_POINTERS, *PDUMP_POINTERS; +*/ +#pragma pack(pop) + +#ifdef __cplusplus +} +#endif + +#endif /* __NTDDSCSI_H */ diff --git a/src/platform/visualc/unistd.h b/src/platform/visualc/unistd.h index 65ce389..8f51f76 100644 --- a/src/platform/visualc/unistd.h +++ b/src/platform/visualc/unistd.h @@ -1,10 +1,10 @@ -/* - * This file is part of the Mingw32 package. - * - * unistd.h maps (roughly) to io.h - */ - -#ifndef __STRICT_ANSI__ -#include -#endif - +/* + * This file is part of the Mingw32 package. + * + * unistd.h maps (roughly) to io.h + */ + +#ifndef __STRICT_ANSI__ +#include +#endif + diff --git a/src/platform/wii/config.h b/src/platform/wii/config.h index 2d0ca7a..1c617c5 100644 --- a/src/platform/wii/config.h +++ b/src/platform/wii/config.h @@ -53,6 +53,7 @@ #define GCC_ATTRIBUTE(x) __attribute__ ((x)) #define GCC_UNLIKELY(x) __builtin_expect((x), 0) +#define GCC_LIKELY(x) __builtin_expect((x), 1) #define INLINE inline //#define DB_FASTCALL __fastcall diff --git a/src/shell/shell.cpp b/src/shell/shell.cpp index d0976ca..ec67763 100644 --- a/src/shell/shell.cpp +++ b/src/shell/shell.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -146,6 +146,7 @@ Bitu DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn,bool * append) { char ch; Bitu num=0; bool quote = false; + char* t; while ( (ch=*lr++) ) { if(quote && ch != '"') { /* don't parse redirection within quotes. Not perfect yet. Escaped quotes will mess the count up */ @@ -163,26 +164,30 @@ Bitu DOS_Shell::GetRedirection(char *s, char **ifn, char **ofn,bool * append) { lr=ltrim(lr); if (*ofn) free(*ofn); *ofn=lr; - while (*lr && *lr!=' ') lr++; + while (*lr && *lr!=' ' && *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 - *lr=0; - *ofn=strdup(*ofn); +// if(*lr && *(lr+1)) +// *lr++=0; +// else +// *lr=0; + t = (char*)malloc(lr-*ofn+1); + safe_strncpy(t,*ofn,lr-*ofn+1); + *ofn=t; continue; case '<': if (*ifn) free(*ifn); lr=ltrim(lr); *ifn=lr; - while (*lr && *lr!=' ') lr++; + while (*lr && *lr!=' ' && *lr!='>' && *lr != '|') lr++; if((*ifn != lr) && (lr[-1] == ':')) lr[-1] = 0; - if(*lr && *(lr+1)) - *lr++=0; - else - *lr=0; - *ifn=strdup(*ifn); +// if(*lr && *(lr+1)) +// *lr++=0; +// else +// *lr=0; + t = (char*)malloc(lr-*ifn+1); + safe_strncpy(t,*ifn,lr-*ifn+1); + *ifn=t; continue; case '|': ch=0; @@ -376,6 +381,7 @@ public: /* Check for first command being a directory or file */ char buffer[CROSS_LEN]; + char orig[CROSS_LEN]; char cross_filesplit[2] = {CROSS_FILESPLIT , 0}; /* Combining -securemode and no parameter leaves you with a lovely Z:\. */ if ( !control->cmdline->FindCommand(1,line) ) { @@ -408,21 +414,29 @@ public: if (access(buffer,F_OK)) goto nomount; autoexec[12].Install(std::string("MOUNT C \"") + buffer + "\""); autoexec[13].Install("C:"); + /* Save the non modified filename (so boot and imgmount can use it (long filenames, case sensivitive)*/ + strcpy(orig,name); upcase(name); if(strstr(name,".BAT") != 0) { if(secure) autoexec[14].Install("z:\\config.com -securemode"); /* BATch files are called else exit will not work */ autoexec[15].Install(std::string("CALL ") + name); - } else if((strstr(name,".IMG") != 0) || (strstr(name,".IMA") !=0)) { + if(addexit) autoexec[16].Install("exit"); + } else if((strstr(name,".IMG") != 0) || (strstr(name,".IMA") !=0 )) { //No secure mode here as boot is destructive and enabling securemode disables boot /* Boot image files */ - autoexec[15].Install(std::string("BOOT ") + name); + autoexec[15].Install(std::string("BOOT ") + orig); + } else if((strstr(name,".ISO") != 0) || (strstr(name,".CUE") !=0 )) { + if(secure) autoexec[14].Install("z:\\config.com -securemode"); + /* imgmount CD image files */ + autoexec[15].Install(std::string("IMGMOUNT D \"") + orig + std::string("\" -t iso")); + //autoexec[16].Install("D:"); + /* Makes no sense to exit here */ } else { if(secure) autoexec[14].Install("z:\\config.com -securemode"); autoexec[15].Install(name); + if(addexit) autoexec[16].Install("exit"); } - - if(addexit) autoexec[16].Install("exit"); } } nomount: @@ -451,7 +465,7 @@ void SHELL_Init() { MSG_Add("SHELL_MISSING_PARAMETER","Required parameter missing.\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_CHDIR_HINT_2","directoryname is longer than 8 charachters and/or contains spaces.\nTry \033[31mcd %s\033[0m\n"); + MSG_Add("SHELL_CMD_CHDIR_HINT_2","directoryname is longer than 8 characters and/or contains spaces.\nTry \033[31mcd %s\033[0m\n"); MSG_Add("SHELL_CMD_CHDIR_HINT_3","You are still on drive Z:, change to a mounted drive with \033[31mC:\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"); diff --git a/src/shell/shell_batch.cpp b/src/shell/shell_batch.cpp index 821d188..b259651 100644 --- a/src/shell/shell_batch.cpp +++ b/src/shell/shell_batch.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/shell/shell_cmds.cpp b/src/shell/shell_cmds.cpp index 89989e0..49ff827 100644 --- a/src/shell/shell_cmds.cpp +++ b/src/shell/shell_cmds.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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 @@ -32,37 +32,37 @@ #include static SHELL_Cmd cmd_list[]={ +{ "DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP"}, { "CHDIR", 1, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP"}, +{ "ATTRIB", 1, &DOS_Shell::CMD_ATTRIB, "SHELL_CMD_ATTRIB_HELP"}, +{ "CALL", 1, &DOS_Shell::CMD_CALL, "SHELL_CMD_CALL_HELP"}, { "CD", 0, &DOS_Shell::CMD_CHDIR, "SHELL_CMD_CHDIR_HELP"}, +{ "CHOICE", 1, &DOS_Shell::CMD_CHOICE, "SHELL_CMD_CHOICE_HELP"}, { "CLS", 0, &DOS_Shell::CMD_CLS, "SHELL_CMD_CLS_HELP"}, { "COPY", 0, &DOS_Shell::CMD_COPY, "SHELL_CMD_COPY_HELP"}, -{ "DIR", 0, &DOS_Shell::CMD_DIR, "SHELL_CMD_DIR_HELP"}, { "DEL", 0, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "DELETE", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "ERASE", 1, &DOS_Shell::CMD_DELETE, "SHELL_CMD_DELETE_HELP"}, { "ECHO", 1, &DOS_Shell::CMD_ECHO, "SHELL_CMD_ECHO_HELP"}, { "EXIT", 0, &DOS_Shell::CMD_EXIT, "SHELL_CMD_EXIT_HELP"}, +{ "GOTO", 1, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP"}, { "HELP", 1, &DOS_Shell::CMD_HELP, "SHELL_CMD_HELP_HELP"}, +{ "IF", 1, &DOS_Shell::CMD_IF, "SHELL_CMD_IF_HELP"}, +{ "LOADHIGH", 1, &DOS_Shell::CMD_LOADHIGH, "SHELL_CMD_LOADHIGH_HELP"}, +{ "LH", 1, &DOS_Shell::CMD_LOADHIGH, "SHELL_CMD_LOADHIGH_HELP"}, { "MKDIR", 1, &DOS_Shell::CMD_MKDIR, "SHELL_CMD_MKDIR_HELP"}, { "MD", 0, &DOS_Shell::CMD_MKDIR, "SHELL_CMD_MKDIR_HELP"}, +{ "PATH", 1, &DOS_Shell::CMD_PATH, "SHELL_CMD_PATH_HELP"}, +{ "PAUSE", 1, &DOS_Shell::CMD_PAUSE, "SHELL_CMD_PAUSE_HELP"}, { "RMDIR", 1, &DOS_Shell::CMD_RMDIR, "SHELL_CMD_RMDIR_HELP"}, { "RD", 0, &DOS_Shell::CMD_RMDIR, "SHELL_CMD_RMDIR_HELP"}, -{ "SET", 1, &DOS_Shell::CMD_SET, "SHELL_CMD_SET_HELP"}, -{ "IF", 1, &DOS_Shell::CMD_IF, "SHELL_CMD_IF_HELP"}, -{ "GOTO", 1, &DOS_Shell::CMD_GOTO, "SHELL_CMD_GOTO_HELP"}, -{ "SHIFT", 1, &DOS_Shell::CMD_SHIFT, "SHELL_CMD_SHIFT_HELP"}, -{ "TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP"}, { "REM", 1, &DOS_Shell::CMD_REM, "SHELL_CMD_REM_HELP"}, { "RENAME", 1, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP"}, { "REN", 0, &DOS_Shell::CMD_RENAME, "SHELL_CMD_RENAME_HELP"}, -{ "PAUSE", 1, &DOS_Shell::CMD_PAUSE, "SHELL_CMD_PAUSE_HELP"}, -{ "CALL", 1, &DOS_Shell::CMD_CALL, "SHELL_CMD_CALL_HELP"}, +{ "SET", 1, &DOS_Shell::CMD_SET, "SHELL_CMD_SET_HELP"}, +{ "SHIFT", 1, &DOS_Shell::CMD_SHIFT, "SHELL_CMD_SHIFT_HELP"}, { "SUBST", 1, &DOS_Shell::CMD_SUBST, "SHELL_CMD_SUBST_HELP"}, -{ "LOADHIGH", 0, &DOS_Shell::CMD_LOADHIGH, "SHELL_CMD_LOADHIGH_HELP"}, -{ "LH", 1, &DOS_Shell::CMD_LOADHIGH, "SHELL_CMD_LOADHIGH_HELP"}, -{ "CHOICE", 0, &DOS_Shell::CMD_CHOICE, "SHELL_CMD_CHOICE_HELP"}, -{ "ATTRIB", 1, &DOS_Shell::CMD_ATTRIB, "SHELL_CMD_ATTRIB_HELP"}, -{ "PATH", 1, &DOS_Shell::CMD_PATH, "SHELL_CMD_PATH_HELP"}, +{ "TYPE", 0, &DOS_Shell::CMD_TYPE, "SHELL_CMD_TYPE_HELP"}, { "VER", 0, &DOS_Shell::CMD_VER, "SHELL_CMD_VER_HELP"}, {0,0,0,0} }; @@ -248,8 +248,9 @@ void DOS_Shell::CMD_RENAME(char * args){ if((strlen(dir_source) == 2) && (dir_source[1] == ':')) strcat(dir_source,"\\"); //X: add slash - char dir_current[DOS_PATHLENGTH]; - DOS_GetCurrentDir(0,dir_current); + char dir_current[DOS_PATHLENGTH + 1]; + dir_current[0] = '\\'; //Absolute addressing so we can return properly + DOS_GetCurrentDir(0,dir_current + 1); if(!DOS_ChangeDir(dir_source)) { WriteOut(MSG_Get("SHELL_ILLEGAL_PATH")); return; @@ -262,7 +263,6 @@ void DOS_Shell::CMD_RENAME(char * args){ } void DOS_Shell::CMD_ECHO(char * args){ - HELP("ECHO"); if (!*args) { if (echo) { WriteOut(MSG_Get("SHELL_CMD_ECHO_ON"));} else { WriteOut(MSG_Get("SHELL_CMD_ECHO_OFF"));} @@ -280,6 +280,8 @@ void DOS_Shell::CMD_ECHO(char * args){ echo=true; return; } + if(strcasecmp(pbuffer,"/?")==0) { HELP("ECHO"); } + args++;//skip first character. either a slash or dot or space size_t len = strlen(args); //TODO check input of else ook nodig is. if(len && args[len - 1] == '\r') { diff --git a/src/shell/shell_misc.cpp b/src/shell/shell_misc.cpp index 2b5056a..221ddc4 100644 --- a/src/shell/shell_misc.cpp +++ b/src/shell/shell_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002-2009 The DOSBox Team + * Copyright (C) 2002-2010 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/winres.rc b/src/winres.rc index 1ca3922..4a071af 100644 --- a/src/winres.rc +++ b/src/winres.rc @@ -1,37 +1,37 @@ - -#include "afxres.h" - -// icon resource -dosbox_ico ICON "dosbox.ico" - - -// version resource -VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,73,0,0 - PRODUCTVERSION 0,73,0,0 - FILEFLAGSMASK 0x3fL - FILEFLAGS 0x0L - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "© 2002-2009 DOSBox Team, published under GNU GPL" - VALUE "CompanyName", "DOSBox Team" - VALUE "FileDescription", "DOSBox DOS Emulator" - VALUE "FileVersion", "0, 73, 0, 0" - VALUE "InternalName", "DOSBox" - VALUE "LegalCopyright", "Copyright © 2002-2009 DOSBox Team" - VALUE "OriginalFilename", "dosbox.exe" - VALUE "ProductName", "DOSBox DOS Emulator" - VALUE "ProductVersion", "0, 73, 0, 0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END + +#include "afxres.h" + +// icon resource +dosbox_ico ICON "dosbox.ico" + + +// version resource +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,73,0,0 + PRODUCTVERSION 0,73,0,0 + FILEFLAGSMASK 0x3fL + FILEFLAGS 0x0L + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "© 2002-2009 DOSBox Team, published under GNU GPL" + VALUE "CompanyName", "DOSBox Team" + VALUE "FileDescription", "DOSBox DOS Emulator" + VALUE "FileVersion", "0, 73, 0, 0" + VALUE "InternalName", "DOSBox" + VALUE "LegalCopyright", "Copyright © 2002-2009 DOSBox Team" + VALUE "OriginalFilename", "dosbox.exe" + VALUE "ProductName", "DOSBox DOS Emulator" + VALUE "ProductVersion", "0, 73, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/visualc_net/dosbox.sln b/visualc_net/dosbox.sln index 503642c..5f2be4c 100644 --- a/visualc_net/dosbox.sln +++ b/visualc_net/dosbox.sln @@ -1,21 +1,21 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dosbox", "dosbox.vcproj", "{7FCFFB9B-8629-4D51-849C-8490CECF8AB7}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Debug.ActiveCfg = Debug|Win32 - {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Debug.Build.0 = Debug|Win32 - {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Release.ActiveCfg = Release|Win32 - {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Release.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dosbox", "dosbox.vcproj", "{7FCFFB9B-8629-4D51-849C-8490CECF8AB7}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Debug.ActiveCfg = Debug|Win32 + {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Debug.Build.0 = Debug|Win32 + {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Release.ActiveCfg = Release|Win32 + {7FCFFB9B-8629-4D51-849C-8490CECF8AB7}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/visualc_net/dosbox.vcproj b/visualc_net/dosbox.vcproj index dffb1c9..5a36f2e 100644 --- a/visualc_net/dosbox.vcproj +++ b/visualc_net/dosbox.vcproj @@ -1,874 +1,874 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +