mirror of
https://github.com/retro100/dosbox-wii.git
synced 2025-01-12 18:29:07 +01:00
DOSBox for Windows, as of 3 May 2009, from the DOSBox CVS on SourceForge. Version 0.72 + many CVS changes, probably close to 0.73 release.
This commit is contained in:
commit
113e08c5bd
11
AUTHORS
Normal file
11
AUTHORS
Normal file
@ -0,0 +1,11 @@
|
||||
The DOSBox Team
|
||||
---------------
|
||||
|
||||
Sjoerd v.d. Berg <harekiet>
|
||||
Peter Veenstra <qbix79>
|
||||
Ulf Wohlers <finsterr>
|
||||
Tommy Frössman <fanskapet>
|
||||
Dean Beeler <canadacow>
|
||||
Sebastian Strohhäcker <c2woody>
|
||||
|
||||
nick_without_<> @ users.sourceforge.net
|
340
COPYING
Normal file
340
COPYING
Normal file
@ -0,0 +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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This 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.
|
||||
|
||||
<signature of Ty Coon>, 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.
|
509
ChangeLog
Normal file
509
ChangeLog
Normal file
@ -0,0 +1,509 @@
|
||||
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
|
97
INSTALL
Normal file
97
INSTALL
Normal file
@ -0,0 +1,97 @@
|
||||
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
|
||||
|
||||
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-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
|
4
Makefile.am
Normal file
4
Makefile.am
Normal file
@ -0,0 +1,4 @@
|
||||
# Main Makefile for DOSBox
|
||||
|
||||
EXTRA_DIST = autogen.sh
|
||||
SUBDIRS = src include docs visualc_net
|
530
NEWS
Normal file
530
NEWS
Normal file
@ -0,0 +1,530 @@
|
||||
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.
|
26
THANKS
Normal file
26
THANKS
Normal file
@ -0,0 +1,26 @@
|
||||
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 OPL 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 and gulikoza 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.
|
||||
All the people who submitted a bug.
|
||||
The Beta Testers.
|
||||
|
396
acinclude.m4
Normal file
396
acinclude.m4
Normal file
@ -0,0 +1,396 @@
|
||||
dnl AM_PATH_SDL([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
|
||||
dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS
|
||||
dnl
|
||||
AC_DEFUN([AM_PATH_SDL],
|
||||
[dnl
|
||||
dnl Get the cflags and libraries from the sdl-config script
|
||||
dnl
|
||||
AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)],
|
||||
sdl_prefix="$withval", sdl_prefix="")
|
||||
AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)],
|
||||
sdl_exec_prefix="$withval", sdl_exec_prefix="")
|
||||
AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and run a test SDL program],
|
||||
, enable_sdltest=yes)
|
||||
|
||||
if test x$sdl_exec_prefix != x ; then
|
||||
sdl_args="$sdl_args --exec-prefix=$sdl_exec_prefix"
|
||||
if test x${SDL_CONFIG+set} != xset ; then
|
||||
SDL_CONFIG=$sdl_exec_prefix/bin/sdl-config
|
||||
fi
|
||||
fi
|
||||
if test x$sdl_prefix != x ; then
|
||||
sdl_args="$sdl_args --prefix=$sdl_prefix"
|
||||
if test x${SDL_CONFIG+set} != xset ; then
|
||||
SDL_CONFIG=$sdl_prefix/bin/sdl-config
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(SDL_CONFIG, sdl-config, no)
|
||||
min_sdl_version=ifelse([$1], ,0.11.0,$1)
|
||||
AC_MSG_CHECKING(for SDL - version >= $min_sdl_version)
|
||||
no_sdl=""
|
||||
if test "$SDL_CONFIG" = "no" ; then
|
||||
no_sdl=yes
|
||||
else
|
||||
SDL_CFLAGS=`$SDL_CONFIG $sdlconf_args --cflags`
|
||||
SDL_LIBS=`$SDL_CONFIG $sdlconf_args --libs`
|
||||
|
||||
sdl_major_version=`$SDL_CONFIG $sdl_args --version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
|
||||
sdl_minor_version=`$SDL_CONFIG $sdl_args --version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
|
||||
sdl_micro_version=`$SDL_CONFIG $sdl_config_args --version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
|
||||
if test "x$enable_sdltest" = "xyes" ; then
|
||||
ac_save_CFLAGS="$CFLAGS"
|
||||
ac_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $SDL_CFLAGS"
|
||||
LIBS="$LIBS $SDL_LIBS"
|
||||
dnl
|
||||
dnl Now check if the installed SDL is sufficiently new. (Also sanity
|
||||
dnl checks the results of sdl-config to some extent
|
||||
dnl
|
||||
rm -f conf.sdltest
|
||||
AC_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "SDL.h"
|
||||
|
||||
char*
|
||||
my_strdup (char *str)
|
||||
{
|
||||
char *new_str;
|
||||
|
||||
if (str)
|
||||
{
|
||||
new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char));
|
||||
strcpy (new_str, str);
|
||||
}
|
||||
else
|
||||
new_str = NULL;
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
int major, minor, micro;
|
||||
char *tmp_version;
|
||||
|
||||
/* This hangs on some systems (?)
|
||||
system ("touch conf.sdltest");
|
||||
*/
|
||||
{ FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); }
|
||||
|
||||
/* HP/UX 9 (%@#!) writes to sscanf strings */
|
||||
tmp_version = my_strdup("$min_sdl_version");
|
||||
if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) {
|
||||
printf("%s, bad version string\n", "$min_sdl_version");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (($sdl_major_version > major) ||
|
||||
(($sdl_major_version == major) && ($sdl_minor_version > minor)) ||
|
||||
(($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("\n*** 'sdl-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version);
|
||||
printf("*** of SDL required is %d.%d.%d. If sdl-config is correct, then it is\n", major, minor, micro);
|
||||
printf("*** best to upgrade to the required version.\n");
|
||||
printf("*** If sdl-config was wrong, set the environment variable SDL_CONFIG\n");
|
||||
printf("*** to point to the correct copy of sdl-config, and remove the file\n");
|
||||
printf("*** config.cache before re-running configure\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
fi
|
||||
fi
|
||||
if test "x$no_sdl" = x ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
ifelse([$2], , :, [$2])
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
if test "$SDL_CONFIG" = "no" ; then
|
||||
echo "*** The sdl-config script installed by SDL could not be found"
|
||||
echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in"
|
||||
echo "*** your path, or set the SDL_CONFIG environment variable to the"
|
||||
echo "*** full path to sdl-config."
|
||||
else
|
||||
if test -f conf.sdltest ; then
|
||||
:
|
||||
else
|
||||
echo "*** Could not run SDL test program, checking why..."
|
||||
CFLAGS="$CFLAGS $SDL_CFLAGS"
|
||||
LIBS="$LIBS $SDL_LIBS"
|
||||
AC_TRY_LINK([
|
||||
#include <stdio.h>
|
||||
#include "SDL.h"
|
||||
], [ return 0; ],
|
||||
[ echo "*** The test program compiled, but did not run. This usually means"
|
||||
echo "*** that the run-time linker is not finding SDL or finding the wrong"
|
||||
echo "*** version of SDL. If it is not finding SDL, you'll need to set your"
|
||||
echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
|
||||
echo "*** to the installed location Also, make sure you have run ldconfig if that"
|
||||
echo "*** is required on your system"
|
||||
echo "***"
|
||||
echo "*** If you have an old version installed, it is best to remove it, although"
|
||||
echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH"],
|
||||
[ echo "*** The test program failed to compile or link. See the file config.log for the"
|
||||
echo "*** exact error that occured. This usually means SDL was incorrectly installed"
|
||||
echo "*** or that you have moved SDL since it was installed. In the latter case, you"
|
||||
echo "*** may want to edit the sdl-config script: $SDL_CONFIG" ])
|
||||
CFLAGS="$ac_save_CFLAGS"
|
||||
LIBS="$ac_save_LIBS"
|
||||
fi
|
||||
fi
|
||||
SDL_CFLAGS=""
|
||||
SDL_LIBS=""
|
||||
ifelse([$3], , :, [$3])
|
||||
fi
|
||||
AC_SUBST(SDL_CFLAGS)
|
||||
AC_SUBST(SDL_LIBS)
|
||||
rm -f conf.sdltest
|
||||
])
|
||||
|
||||
dnl Configure Paths for Alsa
|
||||
dnl Some modifications by Richard Boulton <richard-alsa@tartarus.org>
|
||||
dnl Christopher Lansdown <lansdoct@cs.alfred.edu>
|
||||
dnl Jaroslav Kysela <perex@suse.cz>
|
||||
dnl Last modification: alsa.m4,v 1.22 2002/05/27 11:14:20 tiwai Exp
|
||||
dnl AM_PATH_ALSA([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
|
||||
dnl Test for libasound, and define ALSA_CFLAGS and ALSA_LIBS as appropriate.
|
||||
dnl enables arguments --with-alsa-prefix=
|
||||
dnl --with-alsa-enc-prefix=
|
||||
dnl --disable-alsatest (this has no effect, as yet)
|
||||
dnl
|
||||
dnl For backwards compatibility, if ACTION_IF_NOT_FOUND is not specified,
|
||||
dnl and the alsa libraries are not found, a fatal AC_MSG_ERROR() will result.
|
||||
dnl
|
||||
AC_DEFUN([AM_PATH_ALSA],
|
||||
[dnl Save the original CFLAGS, LDFLAGS, and LIBS
|
||||
alsa_save_CFLAGS="$CFLAGS"
|
||||
alsa_save_LDFLAGS="$LDFLAGS"
|
||||
alsa_save_LIBS="$LIBS"
|
||||
alsa_found=yes
|
||||
|
||||
dnl
|
||||
dnl Get the cflags and libraries for alsa
|
||||
dnl
|
||||
AC_ARG_WITH(alsa-prefix,
|
||||
[ --with-alsa-prefix=PFX Prefix where Alsa library is installed(optional)],
|
||||
[alsa_prefix="$withval"], [alsa_prefix=""])
|
||||
|
||||
AC_ARG_WITH(alsa-inc-prefix,
|
||||
[ --with-alsa-inc-prefix=PFX Prefix where include libraries are (optional)],
|
||||
[alsa_inc_prefix="$withval"], [alsa_inc_prefix=""])
|
||||
|
||||
dnl FIXME: this is not yet implemented
|
||||
AC_ARG_ENABLE(alsatest,
|
||||
[ --disable-alsatest Do not try to compile and run a test Alsa program],
|
||||
[enable_alsatest=no],
|
||||
[enable_alsatest=yes])
|
||||
|
||||
dnl Add any special include directories
|
||||
AC_MSG_CHECKING(for ALSA CFLAGS)
|
||||
if test "$alsa_inc_prefix" != "" ; then
|
||||
ALSA_CFLAGS="$ALSA_CFLAGS -I$alsa_inc_prefix"
|
||||
CFLAGS="$CFLAGS -I$alsa_inc_prefix"
|
||||
fi
|
||||
AC_MSG_RESULT($ALSA_CFLAGS)
|
||||
|
||||
dnl add any special lib dirs
|
||||
AC_MSG_CHECKING(for ALSA LDFLAGS)
|
||||
if test "$alsa_prefix" != "" ; then
|
||||
ALSA_LIBS="$ALSA_LIBS -L$alsa_prefix"
|
||||
LDFLAGS="$LDFLAGS $ALSA_LIBS"
|
||||
fi
|
||||
|
||||
dnl add the alsa library
|
||||
ALSA_LIBS="$ALSA_LIBS -lasound -lm -ldl -lpthread"
|
||||
LIBS=`echo $LIBS | sed 's/-lm//'`
|
||||
LIBS=`echo $LIBS | sed 's/-ldl//'`
|
||||
LIBS=`echo $LIBS | sed 's/-lpthread//'`
|
||||
LIBS=`echo $LIBS | sed 's/ //'`
|
||||
LIBS="$ALSA_LIBS $LIBS"
|
||||
AC_MSG_RESULT($ALSA_LIBS)
|
||||
|
||||
dnl Check for a working version of libasound that is of the right version.
|
||||
min_alsa_version=ifelse([$1], ,0.1.1,$1)
|
||||
AC_MSG_CHECKING(for libasound headers version >= $min_alsa_version)
|
||||
no_alsa=""
|
||||
alsa_min_major_version=`echo $min_alsa_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
|
||||
alsa_min_minor_version=`echo $min_alsa_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
|
||||
alsa_min_micro_version=`echo $min_alsa_version | \
|
||||
sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
|
||||
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
AC_TRY_COMPILE([
|
||||
#include <alsa/asoundlib.h>
|
||||
], [
|
||||
/* ensure backward compatibility */
|
||||
#if !defined(SND_LIB_MAJOR) && defined(SOUNDLIB_VERSION_MAJOR)
|
||||
#define SND_LIB_MAJOR SOUNDLIB_VERSION_MAJOR
|
||||
#endif
|
||||
#if !defined(SND_LIB_MINOR) && defined(SOUNDLIB_VERSION_MINOR)
|
||||
#define SND_LIB_MINOR SOUNDLIB_VERSION_MINOR
|
||||
#endif
|
||||
#if !defined(SND_LIB_SUBMINOR) && defined(SOUNDLIB_VERSION_SUBMINOR)
|
||||
#define SND_LIB_SUBMINOR SOUNDLIB_VERSION_SUBMINOR
|
||||
#endif
|
||||
|
||||
# if(SND_LIB_MAJOR > $alsa_min_major_version)
|
||||
exit(0);
|
||||
# else
|
||||
# if(SND_LIB_MAJOR < $alsa_min_major_version)
|
||||
# error not present
|
||||
# endif
|
||||
|
||||
# if(SND_LIB_MINOR > $alsa_min_minor_version)
|
||||
exit(0);
|
||||
# else
|
||||
# if(SND_LIB_MINOR < $alsa_min_minor_version)
|
||||
# error not present
|
||||
# endif
|
||||
|
||||
# if(SND_LIB_SUBMINOR < $alsa_min_micro_version)
|
||||
# error not present
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
exit(0);
|
||||
],
|
||||
[AC_MSG_RESULT(found.)],
|
||||
[AC_MSG_RESULT(not present.)
|
||||
ifelse([$3], , [AC_MSG_ERROR(Sufficiently new version of libasound not found.)])
|
||||
alsa_found=no]
|
||||
)
|
||||
AC_LANG_RESTORE
|
||||
|
||||
dnl Now that we know that we have the right version, let's see if we have the library and not just the headers.
|
||||
AC_CHECK_LIB([asound], [snd_ctl_open],,
|
||||
[ifelse([$3], , [AC_MSG_ERROR(No linkable libasound was found.)])
|
||||
alsa_found=no]
|
||||
)
|
||||
|
||||
if test "x$alsa_found" = "xyes" ; then
|
||||
ifelse([$2], , :, [$2])
|
||||
LIBS=`echo $LIBS | sed 's/-lasound//g'`
|
||||
LIBS=`echo $LIBS | sed 's/ //'`
|
||||
LIBS="-lasound $LIBS"
|
||||
fi
|
||||
if test "x$alsa_found" = "xno" ; then
|
||||
ifelse([$3], , :, [$3])
|
||||
CFLAGS="$alsa_save_CFLAGS"
|
||||
LDFLAGS="$alsa_save_LDFLAGS"
|
||||
LIBS="$alsa_save_LIBS"
|
||||
ALSA_CFLAGS=""
|
||||
ALSA_LIBS=""
|
||||
fi
|
||||
|
||||
dnl That should be it. Now just export out symbols:
|
||||
AC_SUBST(ALSA_CFLAGS)
|
||||
AC_SUBST(ALSA_LIBS)
|
||||
])
|
||||
|
||||
AH_TOP([
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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 Library 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.
|
||||
*/
|
||||
])
|
||||
|
||||
AH_BOTTOM([#if C_ATTRIBUTE_ALWAYS_INLINE
|
||||
#define INLINE inline __attribute__((always_inline))
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif])
|
||||
|
||||
AH_BOTTOM([#if C_ATTRIBUTE_FASTCALL
|
||||
#define DB_FASTCALL __attribute__((fastcall))
|
||||
#else
|
||||
#define DB_FASTCALL
|
||||
#endif])
|
||||
|
||||
|
||||
AH_BOTTOM([#if C_HAS_ATTRIBUTE
|
||||
#define GCC_ATTRIBUTE(x) __attribute__ ((x))
|
||||
#else
|
||||
#define GCC_ATTRIBUTE(x) /* attribute not supported */
|
||||
#endif])
|
||||
|
||||
AH_BOTTOM([#if C_HAS_BUILTIN_EXPECT
|
||||
#define GCC_UNLIKELY(x) __builtin_expect((x),0)
|
||||
#else
|
||||
#define GCC_UNLIKELY(x) (x)
|
||||
#endif])
|
||||
|
||||
AH_BOTTOM([
|
||||
typedef double Real64;
|
||||
|
||||
#if SIZEOF_UNSIGNED_CHAR != 1
|
||||
# error "sizeof (unsigned char) != 1"
|
||||
#else
|
||||
typedef unsigned char Bit8u;
|
||||
typedef signed char Bit8s;
|
||||
#endif
|
||||
|
||||
#if SIZEOF_UNSIGNED_SHORT != 2
|
||||
# error "sizeof (unsigned short) != 2"
|
||||
#else
|
||||
typedef unsigned short Bit16u;
|
||||
typedef signed short Bit16s;
|
||||
#endif
|
||||
|
||||
#if SIZEOF_UNSIGNED_INT == 4
|
||||
typedef unsigned int Bit32u;
|
||||
typedef signed int Bit32s;
|
||||
#elif SIZEOF_UNSIGNED_LONG == 4
|
||||
typedef unsigned long Bit32u;
|
||||
typedef signed long Bit32s;
|
||||
#else
|
||||
# error "can't find sizeof(type) of 4 bytes!"
|
||||
#endif
|
||||
|
||||
#if SIZEOF_UNSIGNED_LONG == 8
|
||||
typedef unsigned long Bit64u;
|
||||
typedef signed long Bit64s;
|
||||
#elif SIZEOF_UNSIGNED_LONG_LONG == 8
|
||||
typedef unsigned long long Bit64u;
|
||||
typedef signed long long Bit64s;
|
||||
#else
|
||||
# error "can't find data type of 8 bytes"
|
||||
#endif
|
||||
|
||||
#if SIZEOF_INT_P == 4
|
||||
typedef Bit32u Bitu;
|
||||
typedef Bit32s Bits;
|
||||
#else
|
||||
typedef Bit64u Bitu;
|
||||
typedef Bit64s Bits;
|
||||
#endif
|
||||
|
||||
])
|
14
autogen.sh
Normal file
14
autogen.sh
Normal file
@ -0,0 +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."
|
519
configure.in
Normal file
519
configure.in
Normal file
@ -0,0 +1,519 @@
|
||||
dnl Init.
|
||||
AC_INIT(dosbox,0.72)
|
||||
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 <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
])
|
||||
|
||||
dnl check for the socklen_t (darwin doesn't always have it)
|
||||
AC_COMPILE_IFELSE([
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#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 <unistd.h>
|
||||
#include <stdlib.h>]],[[*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 <sys/types.h>
|
||||
#include <dirent.h>
|
||||
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
|
||||
if test x$target = xi386-pc-os2-emx ; then
|
||||
AC_MSG_CHECKING(for powf in libm);
|
||||
LIBS_BACKUP=$LIBS;
|
||||
LIBS="$LIBS -lm";
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <math.h>]],[[
|
||||
powf(1.0f, 1.0f);
|
||||
]])], [AC_MSG_RESULT(yes)], [AC_DEFINE([DB_HAVE_NO_POWF],[1],[libm doesn't include powf])])
|
||||
LIBS=$LIBS_BACKUP
|
||||
else
|
||||
AC_CHECK_LIB([m],[powf],,[AC_DEFINE([DB_HAVE_NO_POWF],[1],[libm doesn't include powf])])
|
||||
fi
|
||||
|
||||
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 <SDL_Net.h>]],[[
|
||||
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_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 <sys/resource.h>
|
||||
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
|
8
docs/Makefile.am
Normal file
8
docs/Makefile.am
Normal file
@ -0,0 +1,8 @@
|
||||
# Main Makefile for DOSBox
|
||||
|
||||
man_MANS = dosbox.1
|
||||
EXTRA_DIST = $(man_MANS) README.video PORTING
|
||||
|
||||
|
||||
|
||||
|
44
docs/PORTING
Normal file
44
docs/PORTING
Normal file
@ -0,0 +1,44 @@
|
||||
Some notes about porting DOSBox to systems with certain restrictions,
|
||||
like handheld devices.
|
||||
|
||||
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
|
35
docs/README.video
Normal file
35
docs/README.video
Normal file
@ -0,0 +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
|
337
docs/dosbox.1
Normal file
337
docs/dosbox.1
Normal file
@ -0,0 +1,337 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.TH DOSBOX 1 "Jul 01, 2007"
|
||||
.\" 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
|
||||
.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, pcjr, tandy, vga(default)".
|
||||
The machinetype has influence on both the videocard and the available
|
||||
soundcards.
|
||||
.TP
|
||||
.B \-version
|
||||
Output version information and exit. Useful for frontends.
|
||||
.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.
|
||||
First ~/.dosboxrc (if present) will be loaded. If no
|
||||
configfile is specified at the commandline, a file named
|
||||
.BR dosbox.conf " (if present in the current directory) will be"
|
||||
loaded automatically afterwards. If a configfile is specified at the commandline
|
||||
that one will be used instead.
|
||||
.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 <H.P.Veenstra@student.rug.nl> and James Oakley <jfunk@funktronics.ca>,
|
||||
for the Debian system (but may be used by others).
|
39
include/Makefile.am
Normal file
39
include/Makefile.am
Normal file
@ -0,0 +1,39 @@
|
||||
noinst_HEADERS = \
|
||||
bios.h \
|
||||
bios_disk.h \
|
||||
callback.h \
|
||||
cpu.h \
|
||||
cross.h \
|
||||
control.h \
|
||||
debug.h \
|
||||
dma.h \
|
||||
dos_inc.h \
|
||||
dos_system.h \
|
||||
dosbox.h \
|
||||
fpu.h \
|
||||
hardware.h \
|
||||
inout.h \
|
||||
joystick.h \
|
||||
ipx.h \
|
||||
ipxserver.h \
|
||||
keyboard.h \
|
||||
logging.h \
|
||||
mapper.h \
|
||||
mem.h \
|
||||
mixer.h \
|
||||
modules.h \
|
||||
mouse.h \
|
||||
paging.h \
|
||||
pic.h \
|
||||
programs.h \
|
||||
render.h \
|
||||
regs.h \
|
||||
render.h \
|
||||
serialport.h \
|
||||
setup.h \
|
||||
shell.h \
|
||||
support.h \
|
||||
timer.h \
|
||||
vga.h \
|
||||
video.h
|
||||
|
127
include/bios.h
Normal file
127
include/bios.h
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_BIOS_H
|
||||
#define DOSBOX_BIOS_H
|
||||
|
||||
#define BIOS_BASE_ADDRESS_COM1 0x400
|
||||
#define BIOS_BASE_ADDRESS_COM2 0x402
|
||||
#define BIOS_BASE_ADDRESS_COM3 0x404
|
||||
#define BIOS_BASE_ADDRESS_COM4 0x406
|
||||
#define BIOS_ADDRESS_LPT1 0x408
|
||||
#define BIOS_ADDRESS_LPT2 0x40a
|
||||
#define BIOS_ADDRESS_LPT3 0x40c
|
||||
/* 0x40e is reserved */
|
||||
#define BIOS_CONFIGURATION 0x410
|
||||
/* 0x412 is reserved */
|
||||
#define BIOS_MEMORY_SIZE 0x413
|
||||
#define BIOS_TRUE_MEMORY_SIZE 0x415
|
||||
/* #define bios_expansion_memory_size (*(unsigned int *) 0x415) */
|
||||
#define BIOS_KEYBOARD_STATE 0x417
|
||||
#define BIOS_KEYBOARD_FLAGS1 BIOS_KEYBOARD_STATE
|
||||
#define BIOS_KEYBOARD_FLAGS2 0x418
|
||||
#define BIOS_KEYBOARD_TOKEN 0x419
|
||||
/* used for keyboard input with Alt-Number */
|
||||
#define BIOS_KEYBOARD_BUFFER_HEAD 0x41a
|
||||
#define BIOS_KEYBOARD_BUFFER_TAIL 0x41c
|
||||
#define BIOS_KEYBOARD_BUFFER 0x41e
|
||||
/* #define bios_keyboard_buffer (*(unsigned int *) 0x41e) */
|
||||
#define BIOS_DRIVE_ACTIVE 0x43e
|
||||
#define BIOS_DRIVE_RUNNING 0x43f
|
||||
#define BIOS_DISK_MOTOR_TIMEOUT 0x440
|
||||
#define BIOS_DISK_STATUS 0x441
|
||||
/* #define bios_fdc_result_buffer (*(unsigned short *) 0x442) */
|
||||
#define BIOS_VIDEO_MODE 0x449
|
||||
#define BIOS_SCREEN_COLUMNS 0x44a
|
||||
#define BIOS_VIDEO_MEMORY_USED 0x44c
|
||||
#define BIOS_VIDEO_MEMORY_ADDRESS 0x44e
|
||||
#define BIOS_VIDEO_CURSOR_POS 0x450
|
||||
|
||||
|
||||
#define BIOS_CURSOR_SHAPE 0x460
|
||||
#define BIOS_CURSOR_LAST_LINE 0x460
|
||||
#define BIOS_CURSOR_FIRST_LINE 0x461
|
||||
#define BIOS_CURRENT_SCREEN_PAGE 0x462
|
||||
#define BIOS_VIDEO_PORT 0x463
|
||||
#define BIOS_VDU_CONTROL 0x465
|
||||
#define BIOS_VDU_COLOR_REGISTER 0x466
|
||||
/* 0x467-0x468 is reserved */
|
||||
#define BIOS_TIMER 0x46c
|
||||
#define BIOS_24_HOURS_FLAG 0x470
|
||||
#define BIOS_KEYBOARD_FLAGS 0x471
|
||||
#define BIOS_CTRL_ALT_DEL_FLAG 0x472
|
||||
#define BIOS_HARDDISK_COUNT 0x475
|
||||
/* 0x474, 0x476, 0x477 is reserved */
|
||||
#define BIOS_LPT1_TIMEOUT 0x478
|
||||
#define BIOS_LPT2_TIMEOUT 0x479
|
||||
#define BIOS_LPT3_TIMEOUT 0x47a
|
||||
/* 0x47b is reserved */
|
||||
#define BIOS_COM1_TIMEOUT 0x47c
|
||||
#define BIOS_COM2_TIMEOUT 0x47d
|
||||
#define BIOS_COM3_TIMEOUT 0x47e
|
||||
#define BIOS_COM4_TIMEOUT 0x47f
|
||||
/* 0x47e is reserved */ //<- why that?
|
||||
/* 0x47f-0x4ff is unknow for me */
|
||||
#define BIOS_KEYBOARD_BUFFER_START 0x480
|
||||
#define BIOS_KEYBOARD_BUFFER_END 0x482
|
||||
|
||||
#define BIOS_ROWS_ON_SCREEN_MINUS_1 0x484
|
||||
#define BIOS_FONT_HEIGHT 0x485
|
||||
|
||||
#define BIOS_VIDEO_INFO_0 0x487
|
||||
#define BIOS_VIDEO_INFO_1 0x488
|
||||
#define BIOS_VIDEO_INFO_2 0x489
|
||||
#define BIOS_VIDEO_COMBO 0x48a
|
||||
|
||||
#define BIOS_KEYBOARD_FLAGS3 0x496
|
||||
#define BIOS_KEYBOARD_LEDS 0x497
|
||||
|
||||
#define BIOS_WAIT_FLAG_POINTER 0x498
|
||||
#define BIOS_WAIT_FLAG_COUNT 0x49c
|
||||
#define BIOS_WAIT_FLAG_ACTIVE 0x4a0
|
||||
#define BIOS_WAIT_FLAG_TEMP 0x4a1
|
||||
|
||||
|
||||
#define BIOS_PRINT_SCREEN_FLAG 0x500
|
||||
|
||||
#define BIOS_VIDEO_SAVEPTR 0x4a8
|
||||
|
||||
/* maximum of scancodes handled by keyboard bios routines */
|
||||
#define MAX_SCAN_CODE 0x58
|
||||
|
||||
/* The Section handling Bios Disk Access */
|
||||
//#define BIOS_MAX_DISK 10
|
||||
|
||||
//#define MAX_SWAPPABLE_DISKS 20
|
||||
|
||||
void BIOS_ZeroExtendedSize(bool in);
|
||||
void char_out(Bit8u chr,Bit32u att,Bit8u page);
|
||||
void INT10_StartUp(void);
|
||||
void INT16_StartUp(void);
|
||||
void INT2A_StartUp(void);
|
||||
void INT2F_StartUp(void);
|
||||
void INT33_StartUp(void);
|
||||
void INT13_StartUp(void);
|
||||
|
||||
bool BIOS_AddKeyToBuffer(Bit16u code);
|
||||
|
||||
void INT10_ReloadRomFonts();
|
||||
|
||||
void BIOS_SetComPorts (Bit16u baseaddr[]);
|
||||
|
||||
#endif
|
85
include/bios_disk.h
Normal file
85
include/bios_disk.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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_BIOS_DISK_H
|
||||
#define DOSBOX_BIOS_DISK_H
|
||||
|
||||
#include <stdio.h>
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_DOS_INC_H
|
||||
#include "dos_inc.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_BIOS_H
|
||||
#include "bios.h"
|
||||
#endif
|
||||
|
||||
/* The Section handling Bios Disk Access */
|
||||
#define BIOS_MAX_DISK 10
|
||||
|
||||
#define MAX_SWAPPABLE_DISKS 20
|
||||
struct diskGeo {
|
||||
Bit32u ksize; /* Size in kilobytes */
|
||||
Bit16u secttrack; /* Sectors per track */
|
||||
Bit16u headscyl; /* Heads per cylinder */
|
||||
Bit16u cylcount; /* Cylinders per side */
|
||||
Bit16u biosval; /* Type to return from BIOS */
|
||||
};
|
||||
extern diskGeo DiskGeometryList[];
|
||||
|
||||
class imageDisk {
|
||||
public:
|
||||
Bit8u Read_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data);
|
||||
Bit8u Write_Sector(Bit32u head,Bit32u cylinder,Bit32u sector,void * data);
|
||||
Bit8u Read_AbsoluteSector(Bit32u sectnum, void * data);
|
||||
Bit8u Write_AbsoluteSector(Bit32u sectnum, void * data);
|
||||
|
||||
void Set_Geometry(Bit32u setHeads, Bit32u setCyl, Bit32u setSect, Bit32u setSectSize);
|
||||
void Get_Geometry(Bit32u * getHeads, Bit32u *getCyl, Bit32u *getSect, Bit32u *getSectSize);
|
||||
Bit8u GetBiosType(void);
|
||||
Bit32u getSectSize(void);
|
||||
imageDisk(FILE *imgFile, Bit8u *imgName, Bit32u imgSizeK, bool isHardDisk);
|
||||
~imageDisk() { if(diskimg != NULL) { fclose(diskimg); } };
|
||||
|
||||
bool hardDrive;
|
||||
bool active;
|
||||
FILE *diskimg;
|
||||
Bit8u diskname[512];
|
||||
Bit8u floppytype;
|
||||
|
||||
Bit32u sector_size;
|
||||
Bit32u heads,cylinders,sectors;
|
||||
};
|
||||
|
||||
void updateDPT(void);
|
||||
|
||||
#define MAX_HDD_IMAGES 2
|
||||
|
||||
extern imageDisk *imageDiskList[2 + MAX_HDD_IMAGES];
|
||||
extern imageDisk *diskSwap[20];
|
||||
extern Bits swapPosition;
|
||||
extern Bit16u imgDTASeg; /* Real memory location of temporary DTA pointer for fat image disk access */
|
||||
extern RealPt imgDTAPtr; /* Real memory location of temporary DTA pointer for fat image disk access */
|
||||
extern DOS_DTA *imgDTA;
|
||||
|
||||
void swapInDisks(void);
|
||||
void swapInNextDisk(void);
|
||||
bool getSwapRequest(void);
|
||||
|
||||
#endif
|
99
include/callback.h
Normal file
99
include/callback.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: callback.h,v 1.23 2009/04/25 16:25:03 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_CALLBACK_H
|
||||
#define DOSBOX_CALLBACK_H
|
||||
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
typedef Bitu (*CallBack_Handler)(void);
|
||||
extern CallBack_Handler CallBack_Handlers[];
|
||||
|
||||
enum { CB_RETN,CB_RETF,CB_RETF8,CB_IRET,CB_IRETD,CB_IRET_STI,CB_IRET_EOI_PIC1,
|
||||
CB_IRQ0,CB_IRQ1,CB_IRQ9,CB_IRQ12,CB_IRQ12_RET,CB_IRQ6_PCJR,CB_MOUSE,
|
||||
CB_INT29,CB_INT16,CB_HOOKABLE,CB_TDE_IRET,CB_IPXESR,CB_IPXESR_RET,
|
||||
CB_INT21 };
|
||||
|
||||
#define CB_MAX 128
|
||||
#define CB_SIZE 32
|
||||
#define CB_SEG 0xF100
|
||||
|
||||
enum {
|
||||
CBRET_NONE=0,CBRET_STOP=1
|
||||
};
|
||||
|
||||
extern Bit8u lastint;
|
||||
|
||||
static INLINE RealPt CALLBACK_RealPointer(Bitu callback) {
|
||||
return RealMake(CB_SEG,(Bit16u)(callback*CB_SIZE));
|
||||
}
|
||||
static INLINE PhysPt CALLBACK_PhysPointer(Bitu callback) {
|
||||
return PhysMake(CB_SEG,(Bit16u)(callback*CB_SIZE));
|
||||
}
|
||||
|
||||
static INLINE PhysPt CALLBACK_GetBase(void) {
|
||||
return CB_SEG << 4;
|
||||
}
|
||||
|
||||
Bitu CALLBACK_Allocate();
|
||||
|
||||
void CALLBACK_Idle(void);
|
||||
|
||||
|
||||
void CALLBACK_RunRealInt(Bit8u intnum);
|
||||
void CALLBACK_RunRealFar(Bit16u seg,Bit16u off);
|
||||
|
||||
bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* descr);
|
||||
Bitu CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,PhysPt addr,const char* descr);
|
||||
|
||||
const char* CALLBACK_GetDescription(Bitu callback);
|
||||
bool CALLBACK_Free(Bitu callback);
|
||||
|
||||
void CALLBACK_SCF(bool val);
|
||||
void CALLBACK_SZF(bool val);
|
||||
|
||||
extern Bitu call_priv_io;
|
||||
|
||||
|
||||
class CALLBACK_HandlerObject{
|
||||
private:
|
||||
bool installed;
|
||||
Bit16u m_callback;
|
||||
enum {NONE,SETUP,SETUPAT} m_type;
|
||||
struct {
|
||||
RealPt old_vector;
|
||||
Bit8u interrupt;
|
||||
bool installed;
|
||||
} vectorhandler;
|
||||
public:
|
||||
CALLBACK_HandlerObject():installed(false),m_type(NONE){vectorhandler.installed=false;}
|
||||
~CALLBACK_HandlerObject();
|
||||
//Install and allocate a callback.
|
||||
void Install(CallBack_Handler handler,Bitu type,const char* description);
|
||||
void Install(CallBack_Handler handler,Bitu type,PhysPt addr,const char* description);
|
||||
//Only allocate a callback number
|
||||
void Allocate(CallBack_Handler handler,const char* description=0);
|
||||
Bit16u Get_callback(){return m_callback;}
|
||||
RealPt Get_RealPointer(){ return CALLBACK_RealPointer(m_callback);}
|
||||
void Set_RealVec(Bit8u vec);
|
||||
};
|
||||
#endif
|
87
include/control.h
Normal file
87
include/control.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: control.h,v 1.1 2009/02/01 14:11:45 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_CONTROL_H
|
||||
#define DOSBOX_CONTROL_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning ( disable : 4786 )
|
||||
#pragma warning ( disable : 4290 )
|
||||
#endif
|
||||
|
||||
#ifndef DOSBOX_PROGRAMS_H
|
||||
#include "programs.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_SETUP_H
|
||||
#include "setup.h"
|
||||
#endif
|
||||
|
||||
#ifndef CH_LIST
|
||||
#define CH_LIST
|
||||
#include <list>
|
||||
#endif
|
||||
|
||||
#ifndef CH_VECTOR
|
||||
#define CH_VECTOR
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#ifndef CH_STRING
|
||||
#define CH_STRING
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
class Config{
|
||||
public:
|
||||
CommandLine * cmdline;
|
||||
private:
|
||||
std::list<Section*> sectionlist;
|
||||
typedef std::list<Section*>::iterator it;
|
||||
typedef std::list<Section*>::reverse_iterator reverse_it;
|
||||
typedef std::list<Section*>::const_iterator const_it;
|
||||
typedef std::list<Section*>::const_reverse_iterator const_reverse_it;
|
||||
void (* _start_function)(void);
|
||||
bool secure_mode; //Sandbox mode
|
||||
public:
|
||||
Config(CommandLine * cmd):cmdline(cmd),secure_mode(false){}
|
||||
~Config();
|
||||
|
||||
Section_line * AddSection_line(char const * const _name,void (*_initfunction)(Section*));
|
||||
Section_prop * AddSection_prop(char const * const _name,void (*_initfunction)(Section*),bool canchange=false);
|
||||
|
||||
Section* GetSection(int index);
|
||||
Section* GetSection(std::string const&_sectionname) const;
|
||||
Section* GetSectionFromProperty(char const * const prop) const;
|
||||
|
||||
void SetStartUp(void (*_function)(void));
|
||||
void Init();
|
||||
void ShutDown();
|
||||
void StartUp();
|
||||
bool PrintConfig(char const * const configfilename) const;
|
||||
bool ParseConfigFile(char const * const configfilename);
|
||||
void ParseEnv(char ** envp);
|
||||
bool SecureMode() const { return secure_mode; }
|
||||
void SwitchToSecureMode() { secure_mode = true; }//can't be undone
|
||||
};
|
||||
|
||||
#endif
|
492
include/cpu.h
Normal file
492
include/cpu.h
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: cpu.h,v 1.56 2009/04/25 16:25:03 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_CPU_H
|
||||
#define DOSBOX_CPU_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_REGS_H
|
||||
#include "regs.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
#define CPU_AUTODETERMINE_NONE 0x00
|
||||
#define CPU_AUTODETERMINE_CORE 0x01
|
||||
#define CPU_AUTODETERMINE_CYCLES 0x02
|
||||
|
||||
#define CPU_AUTODETERMINE_SHIFT 0x02
|
||||
#define CPU_AUTODETERMINE_MASK 0x03
|
||||
|
||||
#define CPU_CYCLES_LOWER_LIMIT 100
|
||||
|
||||
|
||||
#define CPU_ARCHTYPE_MIXED 0xff
|
||||
#define CPU_ARCHTYPE_386SLOW 0x30
|
||||
#define CPU_ARCHTYPE_386FAST 0x35
|
||||
#define CPU_ARCHTYPE_486OLDSLOW 0x40
|
||||
#define CPU_ARCHTYPE_486NEWSLOW 0x45
|
||||
#define CPU_ARCHTYPE_PENTIUMSLOW 0x50
|
||||
|
||||
/* CPU Cycle Timing */
|
||||
extern Bit32s CPU_Cycles;
|
||||
extern Bit32s CPU_CycleLeft;
|
||||
extern Bit32s CPU_CycleMax;
|
||||
extern Bit32s CPU_OldCycleMax;
|
||||
extern Bit32s CPU_CyclePercUsed;
|
||||
extern Bit32s CPU_CycleLimit;
|
||||
extern Bit64s CPU_IODelayRemoved;
|
||||
extern bool CPU_CycleAutoAdjust;
|
||||
extern bool CPU_SkipCycleAutoAdjust;
|
||||
extern Bitu CPU_AutoDetermineMode;
|
||||
|
||||
extern Bitu CPU_ArchitectureType;
|
||||
|
||||
extern Bitu CPU_PrefetchQueueSize;
|
||||
|
||||
/* Some common Defines */
|
||||
/* A CPU Handler */
|
||||
typedef Bits (CPU_Decoder)(void);
|
||||
extern CPU_Decoder * cpudecoder;
|
||||
|
||||
Bits CPU_Core_Normal_Run(void);
|
||||
Bits CPU_Core_Normal_Trap_Run(void);
|
||||
Bits CPU_Core_Simple_Run(void);
|
||||
Bits CPU_Core_Full_Run(void);
|
||||
Bits CPU_Core_Dyn_X86_Run(void);
|
||||
Bits CPU_Core_Dyn_X86_Trap_Run(void);
|
||||
Bits CPU_Core_Dynrec_Run(void);
|
||||
Bits CPU_Core_Dynrec_Trap_Run(void);
|
||||
Bits CPU_Core_Prefetch_Run(void);
|
||||
Bits CPU_Core_Prefetch_Trap_Run(void);
|
||||
|
||||
void CPU_Enable_SkipAutoAdjust(void);
|
||||
void CPU_Disable_SkipAutoAdjust(void);
|
||||
void CPU_Reset_AutoAdjust(void);
|
||||
|
||||
|
||||
//CPU Stuff
|
||||
|
||||
extern Bit16u parity_lookup[256];
|
||||
|
||||
bool CPU_LLDT(Bitu selector);
|
||||
bool CPU_LTR(Bitu selector);
|
||||
void CPU_LIDT(Bitu limit,Bitu base);
|
||||
void CPU_LGDT(Bitu limit,Bitu base);
|
||||
|
||||
Bitu CPU_STR(void);
|
||||
Bitu CPU_SLDT(void);
|
||||
Bitu CPU_SIDT_base(void);
|
||||
Bitu CPU_SIDT_limit(void);
|
||||
Bitu CPU_SGDT_base(void);
|
||||
Bitu CPU_SGDT_limit(void);
|
||||
|
||||
void CPU_ARPL(Bitu & dest_sel,Bitu src_sel);
|
||||
void CPU_LAR(Bitu selector,Bitu & ar);
|
||||
void CPU_LSL(Bitu selector,Bitu & limit);
|
||||
|
||||
void CPU_SET_CRX(Bitu cr,Bitu value);
|
||||
bool CPU_WRITE_CRX(Bitu cr,Bitu value);
|
||||
Bitu CPU_GET_CRX(Bitu cr);
|
||||
bool CPU_READ_CRX(Bitu cr,Bit32u & retvalue);
|
||||
|
||||
bool CPU_WRITE_DRX(Bitu dr,Bitu value);
|
||||
bool CPU_READ_DRX(Bitu dr,Bit32u & retvalue);
|
||||
|
||||
bool CPU_WRITE_TRX(Bitu dr,Bitu value);
|
||||
bool CPU_READ_TRX(Bitu dr,Bit32u & retvalue);
|
||||
|
||||
Bitu CPU_SMSW(void);
|
||||
bool CPU_LMSW(Bitu word);
|
||||
|
||||
void CPU_VERR(Bitu selector);
|
||||
void CPU_VERW(Bitu selector);
|
||||
|
||||
void CPU_JMP(bool use32,Bitu selector,Bitu offset,Bitu oldeip);
|
||||
void CPU_CALL(bool use32,Bitu selector,Bitu offset,Bitu oldeip);
|
||||
void CPU_RET(bool use32,Bitu bytes,Bitu oldeip);
|
||||
void CPU_IRET(bool use32,Bitu oldeip);
|
||||
void CPU_HLT(Bitu oldeip);
|
||||
|
||||
bool CPU_POPF(Bitu use32);
|
||||
bool CPU_PUSHF(Bitu use32);
|
||||
bool CPU_CLI(void);
|
||||
bool CPU_STI(void);
|
||||
|
||||
bool CPU_IO_Exception(Bitu port,Bitu size);
|
||||
void CPU_RunException(void);
|
||||
|
||||
void CPU_ENTER(bool use32,Bitu bytes,Bitu level);
|
||||
|
||||
#define CPU_INT_SOFTWARE 0x1
|
||||
#define CPU_INT_EXCEPTION 0x2
|
||||
#define CPU_INT_HAS_ERROR 0x4
|
||||
#define CPU_INT_NOIOPLCHECK 0x8
|
||||
|
||||
void CPU_Interrupt(Bitu num,Bitu type,Bitu oldeip);
|
||||
static INLINE void CPU_HW_Interrupt(Bitu num) {
|
||||
CPU_Interrupt(num,0,reg_eip);
|
||||
}
|
||||
static INLINE void CPU_SW_Interrupt(Bitu num,Bitu oldeip) {
|
||||
CPU_Interrupt(num,CPU_INT_SOFTWARE,oldeip);
|
||||
}
|
||||
static INLINE void CPU_SW_Interrupt_NoIOPLCheck(Bitu num,Bitu oldeip) {
|
||||
CPU_Interrupt(num,CPU_INT_SOFTWARE|CPU_INT_NOIOPLCHECK,oldeip);
|
||||
}
|
||||
|
||||
bool CPU_PrepareException(Bitu which,Bitu error);
|
||||
void CPU_Exception(Bitu which,Bitu error=0);
|
||||
|
||||
bool CPU_SetSegGeneral(SegNames seg,Bitu value);
|
||||
bool CPU_PopSeg(SegNames seg,bool use32);
|
||||
|
||||
bool CPU_CPUID(void);
|
||||
Bitu CPU_Pop16(void);
|
||||
Bitu CPU_Pop32(void);
|
||||
void CPU_Push16(Bitu value);
|
||||
void CPU_Push32(Bitu value);
|
||||
|
||||
void CPU_SetFlags(Bitu word,Bitu mask);
|
||||
|
||||
|
||||
#define EXCEPTION_UD 6
|
||||
#define EXCEPTION_TS 10
|
||||
#define EXCEPTION_NP 11
|
||||
#define EXCEPTION_SS 12
|
||||
#define EXCEPTION_GP 13
|
||||
#define EXCEPTION_PF 14
|
||||
|
||||
#define CR0_PROTECTION 0x00000001
|
||||
#define CR0_MONITORPROCESSOR 0x00000002
|
||||
#define CR0_FPUEMULATION 0x00000004
|
||||
#define CR0_TASKSWITCH 0x00000008
|
||||
#define CR0_FPUPRESENT 0x00000010
|
||||
#define CR0_PAGING 0x80000000
|
||||
|
||||
|
||||
// *********************************************************************
|
||||
// Descriptor
|
||||
// *********************************************************************
|
||||
|
||||
#define DESC_INVALID 0x00
|
||||
#define DESC_286_TSS_A 0x01
|
||||
#define DESC_LDT 0x02
|
||||
#define DESC_286_TSS_B 0x03
|
||||
#define DESC_286_CALL_GATE 0x04
|
||||
#define DESC_TASK_GATE 0x05
|
||||
#define DESC_286_INT_GATE 0x06
|
||||
#define DESC_286_TRAP_GATE 0x07
|
||||
|
||||
#define DESC_386_TSS_A 0x09
|
||||
#define DESC_386_TSS_B 0x0b
|
||||
#define DESC_386_CALL_GATE 0x0c
|
||||
#define DESC_386_INT_GATE 0x0e
|
||||
#define DESC_386_TRAP_GATE 0x0f
|
||||
|
||||
/* EU/ED Expand UP/DOWN RO/RW Read Only/Read Write NA/A Accessed */
|
||||
#define DESC_DATA_EU_RO_NA 0x10
|
||||
#define DESC_DATA_EU_RO_A 0x11
|
||||
#define DESC_DATA_EU_RW_NA 0x12
|
||||
#define DESC_DATA_EU_RW_A 0x13
|
||||
#define DESC_DATA_ED_RO_NA 0x14
|
||||
#define DESC_DATA_ED_RO_A 0x15
|
||||
#define DESC_DATA_ED_RW_NA 0x16
|
||||
#define DESC_DATA_ED_RW_A 0x17
|
||||
|
||||
/* N/R Readable NC/C Confirming A/NA Accessed */
|
||||
#define DESC_CODE_N_NC_A 0x18
|
||||
#define DESC_CODE_N_NC_NA 0x19
|
||||
#define DESC_CODE_R_NC_A 0x1a
|
||||
#define DESC_CODE_R_NC_NA 0x1b
|
||||
#define DESC_CODE_N_C_A 0x1c
|
||||
#define DESC_CODE_N_C_NA 0x1d
|
||||
#define DESC_CODE_R_C_A 0x1e
|
||||
#define DESC_CODE_R_C_NA 0x1f
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
|
||||
struct S_Descriptor {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
Bit32u base_0_15 :16;
|
||||
Bit32u limit_0_15 :16;
|
||||
Bit32u base_24_31 :8;
|
||||
Bit32u g :1;
|
||||
Bit32u big :1;
|
||||
Bit32u r :1;
|
||||
Bit32u avl :1;
|
||||
Bit32u limit_16_19 :4;
|
||||
Bit32u p :1;
|
||||
Bit32u dpl :2;
|
||||
Bit32u type :5;
|
||||
Bit32u base_16_23 :8;
|
||||
#else
|
||||
Bit32u limit_0_15 :16;
|
||||
Bit32u base_0_15 :16;
|
||||
Bit32u base_16_23 :8;
|
||||
Bit32u type :5;
|
||||
Bit32u dpl :2;
|
||||
Bit32u p :1;
|
||||
Bit32u limit_16_19 :4;
|
||||
Bit32u avl :1;
|
||||
Bit32u r :1;
|
||||
Bit32u big :1;
|
||||
Bit32u g :1;
|
||||
Bit32u base_24_31 :8;
|
||||
#endif
|
||||
}GCC_ATTRIBUTE(packed);
|
||||
|
||||
struct G_Descriptor {
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
Bit32u selector: 16;
|
||||
Bit32u offset_0_15 :16;
|
||||
Bit32u offset_16_31 :16;
|
||||
Bit32u p :1;
|
||||
Bit32u dpl :2;
|
||||
Bit32u type :5;
|
||||
Bit32u reserved :3;
|
||||
Bit32u paramcount :5;
|
||||
#else
|
||||
Bit32u offset_0_15 :16;
|
||||
Bit32u selector :16;
|
||||
Bit32u paramcount :5;
|
||||
Bit32u reserved :3;
|
||||
Bit32u type :5;
|
||||
Bit32u dpl :2;
|
||||
Bit32u p :1;
|
||||
Bit32u offset_16_31 :16;
|
||||
#endif
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
|
||||
struct TSS_16 {
|
||||
Bit16u back; /* Back link to other task */
|
||||
Bit16u sp0; /* The CK stack pointer */
|
||||
Bit16u ss0; /* The CK stack selector */
|
||||
Bit16u sp1; /* The parent KL stack pointer */
|
||||
Bit16u ss1; /* The parent KL stack selector */
|
||||
Bit16u sp2; /* Unused */
|
||||
Bit16u ss2; /* Unused */
|
||||
Bit16u ip; /* The instruction pointer */
|
||||
Bit16u flags; /* The flags */
|
||||
Bit16u ax, cx, dx, bx; /* The general purpose registers */
|
||||
Bit16u sp, bp, si, di; /* The special purpose registers */
|
||||
Bit16u es; /* The extra selector */
|
||||
Bit16u cs; /* The code selector */
|
||||
Bit16u ss; /* The application stack selector */
|
||||
Bit16u ds; /* The data selector */
|
||||
Bit16u ldt; /* The local descriptor table */
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
|
||||
struct TSS_32 {
|
||||
Bit32u back; /* Back link to other task */
|
||||
Bit32u esp0; /* The CK stack pointer */
|
||||
Bit32u ss0; /* The CK stack selector */
|
||||
Bit32u esp1; /* The parent KL stack pointer */
|
||||
Bit32u ss1; /* The parent KL stack selector */
|
||||
Bit32u esp2; /* Unused */
|
||||
Bit32u ss2; /* Unused */
|
||||
Bit32u cr3; /* The page directory pointer */
|
||||
Bit32u eip; /* The instruction pointer */
|
||||
Bit32u eflags; /* The flags */
|
||||
Bit32u eax, ecx, edx, ebx; /* The general purpose registers */
|
||||
Bit32u esp, ebp, esi, edi; /* The special purpose registers */
|
||||
Bit32u es; /* The extra selector */
|
||||
Bit32u cs; /* The code selector */
|
||||
Bit32u ss; /* The application stack selector */
|
||||
Bit32u ds; /* The data selector */
|
||||
Bit32u fs; /* And another extra selector */
|
||||
Bit32u gs; /* ... and another one */
|
||||
Bit32u ldt; /* The local descriptor table */
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
class Descriptor
|
||||
{
|
||||
public:
|
||||
Descriptor() { saved.fill[0]=saved.fill[1]=0; }
|
||||
|
||||
void Load(PhysPt address);
|
||||
void Save(PhysPt address);
|
||||
|
||||
PhysPt GetBase (void) {
|
||||
return (saved.seg.base_24_31<<24) | (saved.seg.base_16_23<<16) | saved.seg.base_0_15;
|
||||
}
|
||||
Bitu GetLimit (void) {
|
||||
Bitu limit = (saved.seg.limit_16_19<<16) | saved.seg.limit_0_15;
|
||||
if (saved.seg.g) return (limit<<12) | 0xFFF;
|
||||
return limit;
|
||||
}
|
||||
Bitu GetOffset(void) {
|
||||
return (saved.gate.offset_16_31 << 16) | saved.gate.offset_0_15;
|
||||
}
|
||||
Bitu GetSelector(void) {
|
||||
return saved.gate.selector;
|
||||
}
|
||||
Bitu Type(void) {
|
||||
return saved.seg.type;
|
||||
}
|
||||
Bitu Conforming(void) {
|
||||
return saved.seg.type & 8;
|
||||
}
|
||||
Bitu DPL(void) {
|
||||
return saved.seg.dpl;
|
||||
}
|
||||
Bitu Big(void) {
|
||||
return saved.seg.big;
|
||||
}
|
||||
public:
|
||||
union {
|
||||
S_Descriptor seg;
|
||||
G_Descriptor gate;
|
||||
Bit32u fill[2];
|
||||
} saved;
|
||||
};
|
||||
|
||||
class DescriptorTable {
|
||||
public:
|
||||
PhysPt GetBase (void) { return table_base; }
|
||||
Bitu GetLimit (void) { return table_limit; }
|
||||
void SetBase (PhysPt _base) { table_base = _base; }
|
||||
void SetLimit (Bitu _limit) { table_limit= _limit; }
|
||||
|
||||
bool GetDescriptor (Bitu selector, Descriptor& desc) {
|
||||
selector&=~7;
|
||||
if (selector>=table_limit) return false;
|
||||
desc.Load(table_base+(selector));
|
||||
return true;
|
||||
}
|
||||
protected:
|
||||
PhysPt table_base;
|
||||
Bitu table_limit;
|
||||
};
|
||||
|
||||
class GDTDescriptorTable : public DescriptorTable {
|
||||
public:
|
||||
bool GetDescriptor(Bitu selector, Descriptor& desc) {
|
||||
Bitu address=selector & ~7;
|
||||
if (selector & 4) {
|
||||
if (address>=ldt_limit) return false;
|
||||
desc.Load(ldt_base+address);
|
||||
return true;
|
||||
} else {
|
||||
if (address>=table_limit) return false;
|
||||
desc.Load(table_base+address);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
bool SetDescriptor(Bitu selector, Descriptor& desc) {
|
||||
Bitu address=selector & ~7;
|
||||
if (selector & 4) {
|
||||
if (address>=ldt_limit) return false;
|
||||
desc.Save(ldt_base+address);
|
||||
return true;
|
||||
} else {
|
||||
if (address>=table_limit) return false;
|
||||
desc.Save(table_base+address);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Bitu SLDT(void) {
|
||||
return ldt_value;
|
||||
}
|
||||
bool LLDT(Bitu value) {
|
||||
if ((value&0xfffc)==0) {
|
||||
ldt_value=0;
|
||||
ldt_base=0;
|
||||
ldt_limit=0;
|
||||
return true;
|
||||
}
|
||||
Descriptor desc;
|
||||
if (!GetDescriptor(value,desc)) return !CPU_PrepareException(EXCEPTION_GP,value);
|
||||
if (desc.Type()!=DESC_LDT) return !CPU_PrepareException(EXCEPTION_GP,value);
|
||||
if (!desc.saved.seg.p) return !CPU_PrepareException(EXCEPTION_NP,value);
|
||||
ldt_base=desc.GetBase();
|
||||
ldt_limit=desc.GetLimit();
|
||||
ldt_value=value;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
PhysPt ldt_base;
|
||||
Bitu ldt_limit;
|
||||
Bitu ldt_value;
|
||||
};
|
||||
|
||||
class TSS_Descriptor : public Descriptor {
|
||||
public:
|
||||
Bitu IsBusy(void) {
|
||||
return saved.seg.type & 2;
|
||||
}
|
||||
Bitu Is386(void) {
|
||||
return saved.seg.type & 8;
|
||||
}
|
||||
void SetBusy(bool busy) {
|
||||
if (busy) saved.seg.type|=2;
|
||||
else saved.seg.type&=~2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct CPUBlock {
|
||||
Bitu cpl; /* Current Privilege */
|
||||
Bitu mpl;
|
||||
Bitu cr0;
|
||||
bool pmode; /* Is Protected mode enabled */
|
||||
GDTDescriptorTable gdt;
|
||||
DescriptorTable idt;
|
||||
struct {
|
||||
Bitu mask,notmask;
|
||||
bool big;
|
||||
} stack;
|
||||
struct {
|
||||
bool big;
|
||||
} code;
|
||||
struct {
|
||||
Bitu cs,eip;
|
||||
CPU_Decoder * old_decoder;
|
||||
} hlt;
|
||||
struct {
|
||||
Bitu which,error;
|
||||
} exception;
|
||||
Bits direction;
|
||||
bool trap_skip;
|
||||
Bit32u drx[8];
|
||||
Bit32u trx[8];
|
||||
};
|
||||
|
||||
extern CPUBlock cpu;
|
||||
|
||||
static INLINE void CPU_SetFlagsd(Bitu word) {
|
||||
Bitu mask=cpu.cpl ? FMASK_NORMAL : FMASK_ALL;
|
||||
CPU_SetFlags(word,mask);
|
||||
}
|
||||
|
||||
static INLINE void CPU_SetFlagsw(Bitu word) {
|
||||
Bitu mask=(cpu.cpl ? FMASK_NORMAL : FMASK_ALL) & 0xffff;
|
||||
CPU_SetFlags(word,mask);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
108
include/cross.h
Normal file
108
include/cross.h
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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: cross.h,v 1.21 2009/03/14 18:02:34 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_CROSS_H
|
||||
#define DOSBOX_CROSS_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <string>
|
||||
|
||||
#if defined (_MSC_VER) /* MS Visual C++ */
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#define LONGTYPE(a) a##i64
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
#else /* LINUX / GCC */
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#define LONGTYPE(a) a##LL
|
||||
#endif
|
||||
|
||||
#define CROSS_LEN 512 /* Maximum filename size */
|
||||
|
||||
|
||||
#if defined (WIN32) || defined (OS2) /* Win 32 & OS/2*/
|
||||
#define CROSS_FILENAME(blah)
|
||||
#define CROSS_FILESPLIT '\\'
|
||||
#define F_OK 0
|
||||
#else
|
||||
#define CROSS_FILENAME(blah) strreplace(blah,'\\','/')
|
||||
#define CROSS_FILESPLIT '/'
|
||||
#endif
|
||||
|
||||
#define CROSS_NONE 0
|
||||
#define CROSS_FILE 1
|
||||
#define CROSS_DIR 2
|
||||
#if defined (WIN32)
|
||||
#define ftruncate(blah,blah2) chsize(blah,blah2)
|
||||
#endif
|
||||
|
||||
//Solaris maybe others
|
||||
#if defined (DB_HAVE_NO_POWF)
|
||||
#include <math.h>
|
||||
static inline float powf (float x, float y) { return (float) pow (x,y); }
|
||||
#endif
|
||||
|
||||
class Cross {
|
||||
public:
|
||||
static void GetPlatformConfigDir(std::string& in);
|
||||
static void GetPlatformConfigName(std::string& in);
|
||||
static void CreatePlatformConfigDir(std::string& in);
|
||||
static void ResolveHomedir(std::string & temp_line);
|
||||
static void CreateDir(std::string const& temp);
|
||||
};
|
||||
|
||||
|
||||
#if defined (WIN32)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from
|
||||
#include <windows.h>
|
||||
|
||||
typedef struct dir_struct {
|
||||
HANDLE handle;
|
||||
char base_path[MAX_PATH+4];
|
||||
WIN32_FIND_DATA search_data;
|
||||
} dir_information;
|
||||
|
||||
#else
|
||||
|
||||
//#include <sys/types.h> //Included above
|
||||
#include <dirent.h>
|
||||
|
||||
typedef struct dir_struct {
|
||||
DIR* dir;
|
||||
char base_path[CROSS_LEN];
|
||||
} dir_information;
|
||||
|
||||
#endif
|
||||
|
||||
dir_information* open_directory(const char* dirname);
|
||||
bool read_directory_first(dir_information* dirp, char* entry_name, bool& is_directory);
|
||||
bool read_directory_next(dir_information* dirp, char* entry_name, bool& is_directory);
|
||||
void close_directory(dir_information* dirp);
|
||||
|
||||
#endif
|
35
include/debug.h
Normal file
35
include/debug.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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.
|
||||
*/
|
||||
|
||||
void DEBUG_SetupConsole(void);
|
||||
void DEBUG_DrawScreen(void);
|
||||
bool DEBUG_Breakpoint(void);
|
||||
bool DEBUG_IntBreakpoint(Bit8u intNum);
|
||||
void DEBUG_Enable(bool pressed);
|
||||
void DEBUG_CheckExecuteBreakpoint(Bit16u seg, Bit32u off);
|
||||
bool DEBUG_ExitLoop(void);
|
||||
void DEBUG_RefreshPage(char scroll);
|
||||
Bitu DEBUG_EnableDebugger(void);
|
||||
|
||||
extern Bitu cycle_count;
|
||||
extern Bitu debugCallback;
|
||||
|
||||
#ifdef C_HEAVY_DEBUG
|
||||
bool DEBUG_HeavyIsBreakpoint(void);
|
||||
void DEBUG_HeavyWriteLogInstruction(void);
|
||||
#endif
|
117
include/dma.h
Normal file
117
include/dma.h
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: dma.h,v 1.18 2008/09/13 20:04:28 c2woody Exp $ */
|
||||
|
||||
#ifndef DOSBOX_DMA_H
|
||||
#define DOSBOX_DMA_H
|
||||
|
||||
enum DMAEvent {
|
||||
DMA_REACHED_TC,
|
||||
DMA_MASKED,
|
||||
DMA_UNMASKED,
|
||||
DMA_TRANSFEREND
|
||||
};
|
||||
|
||||
class DmaChannel;
|
||||
typedef void (* DMA_CallBack)(DmaChannel * chan,DMAEvent event);
|
||||
|
||||
class DmaChannel {
|
||||
public:
|
||||
Bit32u pagebase;
|
||||
Bit16u baseaddr;
|
||||
Bit16u curraddr;
|
||||
Bit16u basecnt;
|
||||
Bit16u currcnt;
|
||||
Bit8u channum;
|
||||
Bit8u pagenum;
|
||||
Bit8u DMA16;
|
||||
bool increment;
|
||||
bool autoinit;
|
||||
Bit8u trantype;
|
||||
bool masked;
|
||||
bool tcount;
|
||||
bool request;
|
||||
DMA_CallBack callback;
|
||||
|
||||
DmaChannel(Bit8u num, bool dma16);
|
||||
void DoCallBack(DMAEvent event) {
|
||||
if (callback) (*callback)(this,event);
|
||||
}
|
||||
void SetMask(bool _mask) {
|
||||
masked=_mask;
|
||||
DoCallBack(masked ? DMA_MASKED : DMA_UNMASKED);
|
||||
}
|
||||
void Register_Callback(DMA_CallBack _cb) {
|
||||
callback = _cb;
|
||||
SetMask(masked);
|
||||
if (callback) Raise_Request();
|
||||
else Clear_Request();
|
||||
}
|
||||
void ReachedTC(void) {
|
||||
tcount=true;
|
||||
DoCallBack(DMA_REACHED_TC);
|
||||
}
|
||||
void SetPage(Bit8u val) {
|
||||
pagenum=val;
|
||||
pagebase=(pagenum >> DMA16) << (16+DMA16);
|
||||
}
|
||||
void Raise_Request(void) {
|
||||
request=true;
|
||||
}
|
||||
void Clear_Request(void) {
|
||||
request=false;
|
||||
}
|
||||
Bitu Read(Bitu size, Bit8u * buffer);
|
||||
Bitu Write(Bitu size, Bit8u * buffer);
|
||||
};
|
||||
|
||||
class DmaController {
|
||||
private:
|
||||
Bit8u ctrlnum;
|
||||
bool flipflop;
|
||||
DmaChannel *DmaChannels[4];
|
||||
public:
|
||||
IO_ReadHandleObject DMA_ReadHandler[0x11];
|
||||
IO_WriteHandleObject DMA_WriteHandler[0x11];
|
||||
DmaController(Bit8u num) {
|
||||
flipflop = false;
|
||||
ctrlnum = num; /* first or second DMA controller */
|
||||
for(Bit8u i=0;i<4;i++) {
|
||||
DmaChannels[i] = new DmaChannel(i+ctrlnum*4,ctrlnum==1);
|
||||
}
|
||||
}
|
||||
~DmaController(void) {
|
||||
for(Bit8u i=0;i<4;i++) {
|
||||
delete DmaChannels[i];
|
||||
}
|
||||
}
|
||||
DmaChannel * GetChannel(Bit8u chan) {
|
||||
if (chan<4) return DmaChannels[chan];
|
||||
else return NULL;
|
||||
}
|
||||
void WriteControllerReg(Bitu reg,Bitu val,Bitu len);
|
||||
Bitu ReadControllerReg(Bitu reg,Bitu len);
|
||||
};
|
||||
|
||||
DmaChannel * GetDMAChannel(Bit8u chan);
|
||||
|
||||
void CloseSecondDMAController(void);
|
||||
bool SecondDMAControllerAvailable(void);
|
||||
|
||||
#endif
|
643
include/dos_inc.h
Normal file
643
include/dos_inc.h
Normal file
@ -0,0 +1,643 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: dos_inc.h,v 1.77 2009/04/25 16:25:03 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_DOS_INC_H
|
||||
#define DOSBOX_DOS_INC_H
|
||||
|
||||
#ifndef DOSBOX_DOS_SYSTEM_H
|
||||
#include "dos_system.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
struct CommandTail{
|
||||
Bit8u count; /* number of bytes returned */
|
||||
char buffer[127]; /* the buffer itself */
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack ()
|
||||
#endif
|
||||
|
||||
struct DOS_Date {
|
||||
Bit16u year;
|
||||
Bit8u month;
|
||||
Bit8u day;
|
||||
};
|
||||
|
||||
struct DOS_Version {
|
||||
Bit8u major,minor,revision;
|
||||
};
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
union bootSector {
|
||||
struct entries {
|
||||
Bit8u jump[3];
|
||||
Bit8u oem_name[8];
|
||||
Bit16u bytesect;
|
||||
Bit8u sectclust;
|
||||
Bit16u reserve_sect;
|
||||
Bit8u misc[496];
|
||||
} bootdata;
|
||||
Bit8u rawdata[512];
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack ()
|
||||
#endif
|
||||
|
||||
|
||||
enum { MCB_FREE=0x0000,MCB_DOS=0x0008 };
|
||||
enum { RETURN_EXIT=0,RETURN_CTRLC=1,RETURN_ABORT=2,RETURN_TSR=3};
|
||||
|
||||
#define DOS_FILES 127
|
||||
#define DOS_DRIVES 26
|
||||
#define DOS_DEVICES 10
|
||||
|
||||
|
||||
// dos swappable area is 0x320 bytes beyond the sysvars table
|
||||
// device driver chain is inside sysvars
|
||||
#define DOS_INFOBLOCK_SEG 0x80 // sysvars (list of lists)
|
||||
#define DOS_CONDRV_SEG 0xa0
|
||||
#define DOS_CONSTRING_SEG 0xa8
|
||||
#define DOS_SDA_SEG 0xb2 // dos swappable area
|
||||
#define DOS_SDA_OFS 0
|
||||
#define DOS_CDS_SEG 0x108
|
||||
#define DOS_FIRST_SHELL 0x118
|
||||
#define DOS_MEM_START 0x158 //First Segment that DOS can use
|
||||
|
||||
#define DOS_PRIVATE_SEGMENT 0xc800
|
||||
#define DOS_PRIVATE_SEGMENT_END 0xd000
|
||||
|
||||
/* internal Dos Tables */
|
||||
|
||||
extern DOS_File * Files[DOS_FILES];
|
||||
extern DOS_Drive * Drives[DOS_DRIVES];
|
||||
extern DOS_Device * Devices[DOS_DEVICES];
|
||||
|
||||
extern Bit8u dos_copybuf[0x10000];
|
||||
|
||||
|
||||
void DOS_SetError(Bit16u code);
|
||||
|
||||
/* File Handling Routines */
|
||||
|
||||
enum { STDIN=0,STDOUT=1,STDERR=2,STDAUX=3,STDPRN=4};
|
||||
enum { HAND_NONE=0,HAND_FILE,HAND_DEVICE};
|
||||
|
||||
/* Routines for File Class */
|
||||
void DOS_SetupFiles (void);
|
||||
bool DOS_ReadFile(Bit16u handle,Bit8u * data,Bit16u * amount);
|
||||
bool DOS_WriteFile(Bit16u handle,Bit8u * data,Bit16u * amount);
|
||||
bool DOS_SeekFile(Bit16u handle,Bit32u * pos,Bit32u type);
|
||||
bool DOS_CloseFile(Bit16u handle);
|
||||
bool DOS_FlushFile(Bit16u handle);
|
||||
bool DOS_DuplicateEntry(Bit16u entry,Bit16u * newentry);
|
||||
bool DOS_ForceDuplicateEntry(Bit16u entry,Bit16u newentry);
|
||||
bool DOS_GetFileDate(Bit16u entry, Bit16u* otime, Bit16u* odate);
|
||||
|
||||
/* Routines for Drive Class */
|
||||
bool DOS_OpenFile(char const * name,Bit8u flags,Bit16u * entry);
|
||||
bool DOS_OpenFileExtended(char const * name, Bit16u flags, Bit16u createAttr, Bit16u action, Bit16u *entry, Bit16u* status);
|
||||
bool DOS_CreateFile(char const * name,Bit16u attribute,Bit16u * entry);
|
||||
bool DOS_UnlinkFile(char const * const name);
|
||||
bool DOS_FindFirst(char *search,Bit16u attr,bool fcb_findfirst=false);
|
||||
bool DOS_FindNext(void);
|
||||
bool DOS_Canonicalize(char const * const name,char * const big);
|
||||
bool DOS_CreateTempFile(char * const name,Bit16u * entry);
|
||||
bool DOS_FileExists(char const * const name);
|
||||
|
||||
/* Helper Functions */
|
||||
bool DOS_MakeName(char const * const name,char * const fullname,Bit8u * drive);
|
||||
/* Drive Handing Routines */
|
||||
Bit8u DOS_GetDefaultDrive(void);
|
||||
void DOS_SetDefaultDrive(Bit8u drive);
|
||||
bool DOS_SetDrive(Bit8u drive);
|
||||
bool DOS_GetCurrentDir(Bit8u drive,char * const buffer);
|
||||
bool DOS_ChangeDir(char const * const dir);
|
||||
bool DOS_MakeDir(char const * const dir);
|
||||
bool DOS_RemoveDir(char const * const dir);
|
||||
bool DOS_Rename(char const * const oldname,char const * const newname);
|
||||
bool DOS_GetFreeDiskSpace(Bit8u drive,Bit16u * bytes,Bit8u * sectors,Bit16u * clusters,Bit16u * free);
|
||||
bool DOS_GetFileAttr(char const * const name,Bit16u * attr);
|
||||
bool DOS_SetFileAttr(char const * const name,Bit16u attr);
|
||||
|
||||
/* IOCTL Stuff */
|
||||
bool DOS_IOCTL(void);
|
||||
bool DOS_GetSTDINStatus();
|
||||
Bit8u DOS_FindDevice(char const * name);
|
||||
void DOS_SetupDevices(void);
|
||||
|
||||
/* Execute and new process creation */
|
||||
bool DOS_NewPSP(Bit16u pspseg,Bit16u size);
|
||||
bool DOS_ChildPSP(Bit16u pspseg,Bit16u size);
|
||||
bool DOS_Execute(char * name,PhysPt block,Bit8u flags);
|
||||
bool DOS_Terminate(bool tsr,Bit8u exitcode);
|
||||
|
||||
/* Memory Handling Routines */
|
||||
void DOS_SetupMemory(void);
|
||||
bool DOS_AllocateMemory(Bit16u * segment,Bit16u * blocks);
|
||||
bool DOS_ResizeMemory(Bit16u segment,Bit16u * blocks);
|
||||
bool DOS_FreeMemory(Bit16u segment);
|
||||
void DOS_FreeProcessMemory(Bit16u pspseg);
|
||||
Bit16u DOS_GetMemory(Bit16u pages);
|
||||
bool DOS_SetMemAllocStrategy(Bit16u strat);
|
||||
Bit16u DOS_GetMemAllocStrategy(void);
|
||||
void DOS_BuildUMBChain(bool umb_active,bool ems_active);
|
||||
bool DOS_LinkUMBsToMemChain(Bit16u linkstate);
|
||||
|
||||
/* FCB stuff */
|
||||
bool DOS_FCBOpen(Bit16u seg,Bit16u offset);
|
||||
bool DOS_FCBCreate(Bit16u seg,Bit16u offset);
|
||||
bool DOS_FCBClose(Bit16u seg,Bit16u offset);
|
||||
bool DOS_FCBFindFirst(Bit16u seg,Bit16u offset);
|
||||
bool DOS_FCBFindNext(Bit16u seg,Bit16u offset);
|
||||
Bit8u DOS_FCBRead(Bit16u seg,Bit16u offset, Bit16u numBlocks);
|
||||
Bit8u DOS_FCBWrite(Bit16u seg,Bit16u offset,Bit16u numBlocks);
|
||||
Bit8u DOS_FCBRandomRead(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore);
|
||||
Bit8u DOS_FCBRandomWrite(Bit16u seg,Bit16u offset,Bit16u numRec,bool restore);
|
||||
bool DOS_FCBGetFileSize(Bit16u seg,Bit16u offset);
|
||||
bool DOS_FCBDeleteFile(Bit16u seg,Bit16u offset);
|
||||
bool DOS_FCBRenameFile(Bit16u seg, Bit16u offset);
|
||||
void DOS_FCBSetRandomRecord(Bit16u seg, Bit16u offset);
|
||||
Bit8u FCB_Parsename(Bit16u seg,Bit16u offset,Bit8u parser ,char *string, Bit8u *change);
|
||||
bool DOS_GetAllocationInfo(Bit8u drive,Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters);
|
||||
|
||||
/* Extra DOS Interrupts */
|
||||
void DOS_SetupMisc(void);
|
||||
|
||||
/* The DOS Tables */
|
||||
void DOS_SetupTables(void);
|
||||
|
||||
/* Internal DOS Setup Programs */
|
||||
void DOS_SetupPrograms(void);
|
||||
|
||||
/* Initialize Keyboard Layout */
|
||||
void DOS_KeyboardLayout_Init(Section* sec);
|
||||
|
||||
bool DOS_LayoutKey(Bitu key, Bit8u flags1, Bit8u flags2, Bit8u flags3);
|
||||
|
||||
enum {
|
||||
KEYB_NOERROR=0,
|
||||
KEYB_FILENOTFOUND,
|
||||
KEYB_INVALIDFILE,
|
||||
KEYB_LAYOUTNOTFOUND,
|
||||
KEYB_INVALIDCPFILE
|
||||
};
|
||||
|
||||
|
||||
static INLINE Bit16u long2para(Bit32u size) {
|
||||
if (size>0xFFFF0) return 0xffff;
|
||||
if (size&0xf) return (Bit16u)((size>>4)+1);
|
||||
else return (Bit16u)(size>>4);
|
||||
}
|
||||
|
||||
|
||||
static INLINE Bit16u DOS_PackTime(Bit16u hour,Bit16u min,Bit16u sec) {
|
||||
return (hour&0x1f)<<11 | (min&0x3f) << 5 | ((sec/2)&0x1f);
|
||||
}
|
||||
|
||||
static INLINE Bit16u DOS_PackDate(Bit16u year,Bit16u mon,Bit16u day) {
|
||||
return ((year-1980)&0x7f)<<9 | (mon&0x3f) << 5 | (day&0x1f);
|
||||
}
|
||||
|
||||
/* Dos Error Codes */
|
||||
#define DOSERR_NONE 0
|
||||
#define DOSERR_FUNCTION_NUMBER_INVALID 1
|
||||
#define DOSERR_FILE_NOT_FOUND 2
|
||||
#define DOSERR_PATH_NOT_FOUND 3
|
||||
#define DOSERR_TOO_MANY_OPEN_FILES 4
|
||||
#define DOSERR_ACCESS_DENIED 5
|
||||
#define DOSERR_INVALID_HANDLE 6
|
||||
#define DOSERR_MCB_DESTROYED 7
|
||||
#define DOSERR_INSUFFICIENT_MEMORY 8
|
||||
#define DOSERR_MB_ADDRESS_INVALID 9
|
||||
#define DOSERR_ENVIRONMENT_INVALID 10
|
||||
#define DOSERR_FORMAT_INVALID 11
|
||||
#define DOSERR_ACCESS_CODE_INVALID 12
|
||||
#define DOSERR_DATA_INVALID 13
|
||||
#define DOSERR_RESERVED 14
|
||||
#define DOSERR_FIXUP_OVERFLOW 14
|
||||
#define DOSERR_INVALID_DRIVE 15
|
||||
#define DOSERR_REMOVE_CURRENT_DIRECTORY 16
|
||||
#define DOSERR_NOT_SAME_DEVICE 17
|
||||
#define DOSERR_NO_MORE_FILES 18
|
||||
#define DOSERR_FILE_ALREADY_EXISTS 80
|
||||
|
||||
|
||||
/* Remains some classes used to access certain things */
|
||||
#define sOffset(s,m) ((char*)&(((s*)NULL)->m)-(char*)NULL)
|
||||
#define sGet(s,m) GetIt(sizeof(((s *)&pt)->m),(PhysPt)sOffset(s,m))
|
||||
#define sSave(s,m,val) SaveIt(sizeof(((s *)&pt)->m),(PhysPt)sOffset(s,m),val)
|
||||
|
||||
class MemStruct {
|
||||
public:
|
||||
Bitu GetIt(Bitu size,PhysPt addr) {
|
||||
switch (size) {
|
||||
case 1:return mem_readb(pt+addr);
|
||||
case 2:return mem_readw(pt+addr);
|
||||
case 4:return mem_readd(pt+addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void SaveIt(Bitu size,PhysPt addr,Bitu val) {
|
||||
switch (size) {
|
||||
case 1:mem_writeb(pt+addr,(Bit8u)val);break;
|
||||
case 2:mem_writew(pt+addr,(Bit16u)val);break;
|
||||
case 4:mem_writed(pt+addr,(Bit32u)val);break;
|
||||
}
|
||||
}
|
||||
void SetPt(Bit16u seg) { pt=PhysMake(seg,0);}
|
||||
void SetPt(Bit16u seg,Bit16u off) { pt=PhysMake(seg,off);}
|
||||
void SetPt(RealPt addr) { pt=Real2Phys(addr);}
|
||||
protected:
|
||||
PhysPt pt;
|
||||
};
|
||||
|
||||
class DOS_PSP :public MemStruct {
|
||||
public:
|
||||
DOS_PSP (Bit16u segment) { SetPt(segment);seg=segment;};
|
||||
void MakeNew (Bit16u memSize);
|
||||
void CopyFileTable (DOS_PSP* srcpsp,bool createchildpsp);
|
||||
Bit16u FindFreeFileEntry (void);
|
||||
void CloseFiles (void);
|
||||
|
||||
void SaveVectors (void);
|
||||
void RestoreVectors (void);
|
||||
void SetSize (Bit16u size) { sSave(sPSP,next_seg,size); };
|
||||
Bit16u GetSize (void) { return (Bit16u)sGet(sPSP,next_seg); };
|
||||
void SetEnvironment (Bit16u envseg) { sSave(sPSP,environment,envseg); };
|
||||
Bit16u GetEnvironment (void) { return (Bit16u)sGet(sPSP,environment); };
|
||||
Bit16u GetSegment (void) { return seg; };
|
||||
void SetFileHandle (Bit16u index, Bit8u handle);
|
||||
Bit8u GetFileHandle (Bit16u index);
|
||||
void SetParent (Bit16u parent) { sSave(sPSP,psp_parent,parent); };
|
||||
Bit16u GetParent (void) { return (Bit16u)sGet(sPSP,psp_parent); };
|
||||
void SetStack (RealPt stackpt) { sSave(sPSP,stack,stackpt); };
|
||||
RealPt GetStack (void) { return sGet(sPSP,stack); };
|
||||
void SetInt22 (RealPt int22pt) { sSave(sPSP,int_22,int22pt); };
|
||||
RealPt GetInt22 (void) { return sGet(sPSP,int_22); };
|
||||
void SetFCB1 (RealPt src);
|
||||
void SetFCB2 (RealPt src);
|
||||
void SetCommandTail (RealPt src);
|
||||
bool SetNumFiles (Bit16u fileNum);
|
||||
Bit16u FindEntryByHandle (Bit8u handle);
|
||||
|
||||
private:
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct sPSP {
|
||||
Bit8u exit[2]; /* CP/M-like exit poimt */
|
||||
Bit16u next_seg; /* Segment of first byte beyond memory allocated or program */
|
||||
Bit8u fill_1; /* single char fill */
|
||||
Bit8u far_call; /* far call opcode */
|
||||
RealPt cpm_entry; /* CPM Service Request address*/
|
||||
RealPt int_22; /* Terminate Address */
|
||||
RealPt int_23; /* Break Address */
|
||||
RealPt int_24; /* Critical Error Address */
|
||||
Bit16u psp_parent; /* Parent PSP Segment */
|
||||
Bit8u files[20]; /* File Table - 0xff is unused */
|
||||
Bit16u environment; /* Segment of evironment table */
|
||||
RealPt stack; /* SS:SP Save point for int 0x21 calls */
|
||||
Bit16u max_files; /* Maximum open files */
|
||||
RealPt file_table; /* Pointer to File Table PSP:0x18 */
|
||||
RealPt prev_psp; /* Pointer to previous PSP */
|
||||
Bit8u interim_flag;
|
||||
Bit8u truename_flag;
|
||||
Bit16u nn_flags;
|
||||
Bit16u dos_version;
|
||||
Bit8u fill_2[14]; /* Lot's of unused stuff i can't care aboue */
|
||||
Bit8u service[3]; /* INT 0x21 Service call int 0x21;retf; */
|
||||
Bit8u fill_3[9]; /* This has some blocks with FCB info */
|
||||
Bit8u fcb1[16]; /* first FCB */
|
||||
Bit8u fcb2[16]; /* second FCB */
|
||||
Bit8u fill_4[4]; /* unused */
|
||||
CommandTail cmdtail;
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
Bit16u seg;
|
||||
public:
|
||||
static Bit16u rootpsp;
|
||||
};
|
||||
|
||||
class DOS_ParamBlock:public MemStruct {
|
||||
public:
|
||||
DOS_ParamBlock(PhysPt addr) {pt=addr;}
|
||||
void Clear(void);
|
||||
void LoadData(void);
|
||||
void SaveData(void); /* Save it as an exec block */
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
struct sOverlay {
|
||||
Bit16u loadseg;
|
||||
Bit16u relocation;
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
struct sExec {
|
||||
Bit16u envseg;
|
||||
RealPt cmdtail;
|
||||
RealPt fcb1;
|
||||
RealPt fcb2;
|
||||
RealPt initsssp;
|
||||
RealPt initcsip;
|
||||
}GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
sExec exec;
|
||||
sOverlay overlay;
|
||||
};
|
||||
|
||||
class DOS_InfoBlock:public MemStruct {
|
||||
public:
|
||||
DOS_InfoBlock () {};
|
||||
void SetLocation(Bit16u seg);
|
||||
void SetFirstMCB(Bit16u _first_mcb);
|
||||
void SetBuffers(Bit16u x,Bit16u y);
|
||||
void SetCurDirStruct(Bit32u _curdirstruct);
|
||||
void SetFCBTable(Bit32u _fcbtable);
|
||||
void SetDeviceChainStart(Bit32u _devchain);
|
||||
void SetDiskBufferHeadPt(Bit32u _dbheadpt);
|
||||
void SetStartOfUMBChain(Bit16u _umbstartseg);
|
||||
void SetUMBChainState(Bit8u _umbchaining);
|
||||
Bit16u GetStartOfUMBChain(void);
|
||||
Bit8u GetUMBChainState(void);
|
||||
RealPt GetPointer(void);
|
||||
Bit32u GetDeviceChain(void);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct sDIB {
|
||||
Bit8u unknown1[4];
|
||||
Bit16u magicWord; // -0x22 needs to be 1
|
||||
Bit8u unknown2[8];
|
||||
Bit16u regCXfrom5e; // -0x18 CX from last int21/ah=5e
|
||||
Bit16u countLRUcache; // -0x16 LRU counter for FCB caching
|
||||
Bit16u countLRUopens; // -0x14 LRU counter for FCB openings
|
||||
Bit8u stuff[6]; // -0x12 some stuff, hopefully never used....
|
||||
Bit16u sharingCount; // -0x0c sharing retry count
|
||||
Bit16u sharingDelay; // -0x0a sharing retry delay
|
||||
RealPt diskBufPtr; // -0x08 pointer to disk buffer
|
||||
Bit16u ptrCONinput; // -0x04 pointer to con input
|
||||
Bit16u firstMCB; // -0x02 first memory control block
|
||||
RealPt firstDPB; // 0x00 first drive parameter block
|
||||
RealPt firstFileTable; // 0x04 first system file table
|
||||
RealPt activeClock; // 0x08 active clock device header
|
||||
RealPt activeCon; // 0x0c active console device header
|
||||
Bit16u maxSectorLength; // 0x10 maximum bytes per sector of any block device;
|
||||
RealPt diskInfoBuffer; // 0x12 pointer to disk info buffer
|
||||
RealPt curDirStructure; // 0x16 pointer to current array of directory structure
|
||||
RealPt fcbTable; // 0x1a pointer to system FCB table
|
||||
Bit16u protFCBs; // 0x1e protected fcbs
|
||||
Bit8u blockDevices; // 0x20 installed block devices
|
||||
Bit8u lastdrive; // 0x21 lastdrive
|
||||
Bit32u nulNextDriver; // 0x22 NUL driver next pointer
|
||||
Bit16u nulAttributes; // 0x26 NUL driver aattributes
|
||||
Bit32u nulStrategy; // 0x28 NUL driver strategy routine
|
||||
Bit8u nulString[8]; // 0x2c NUL driver name string
|
||||
Bit8u joindedDrives; // 0x34 joined drives
|
||||
Bit16u specialCodeSeg; // 0x35 special code segment
|
||||
RealPt setverPtr; // 0x37 pointer to setver
|
||||
Bit16u a20FixOfs; // 0x3b a20 fix routine offset
|
||||
Bit16u pspLastIfHMA; // 0x3d psp of last program (if dos in hma)
|
||||
Bit16u buffers_x; // 0x3f x in BUFFERS x,y
|
||||
Bit16u buffers_y; // 0x41 y in BUFFERS x,y
|
||||
Bit8u bootDrive; // 0x43 boot drive
|
||||
Bit8u useDwordMov; // 0x44 use dword moves
|
||||
Bit16u extendedSize; // 0x45 size of extended memory
|
||||
Bit32u diskBufferHeadPt; // 0x47 pointer to least-recently used buffer header
|
||||
Bit16u dirtyDiskBuffers; // 0x4b number of dirty disk buffers
|
||||
Bit32u lookaheadBufPt; // 0x4d pointer to lookahead buffer
|
||||
Bit16u lookaheadBufNumber; // 0x51 number of lookahead buffers
|
||||
Bit8u bufferLocation; // 0x53 workspace buffer location
|
||||
Bit32u workspaceBuffer; // 0x54 pointer to workspace buffer
|
||||
Bit8u unknown3[11]; // 0x58
|
||||
Bit8u chainingUMB; // 0x63 bit0: UMB chain linked to MCB chain
|
||||
Bit16u minMemForExec; // 0x64 minimum paragraphs needed for current program
|
||||
Bit16u startOfUMBChain; // 0x66 segment of first UMB-MCB
|
||||
Bit16u memAllocScanStart; // 0x68 start paragraph for memory allocation
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack ()
|
||||
#endif
|
||||
Bit16u seg;
|
||||
};
|
||||
|
||||
class DOS_DTA:public MemStruct{
|
||||
public:
|
||||
DOS_DTA(RealPt addr) { SetPt(addr); }
|
||||
|
||||
void SetupSearch(Bit8u _sdrive,Bit8u _sattr,char * _pattern);
|
||||
void SetResult(const char * _name,Bit32u _size,Bit16u _date,Bit16u _time,Bit8u _attr);
|
||||
|
||||
Bit8u GetSearchDrive(void);
|
||||
void GetSearchParams(Bit8u & _sattr,char * _spattern);
|
||||
void GetResult(char * _name,Bit32u & _size,Bit16u & _date,Bit16u & _time,Bit8u & _attr);
|
||||
|
||||
void SetDirID(Bit16u entry) { sSave(sDTA,dirID,entry); };
|
||||
void SetDirIDCluster(Bit16u entry) { sSave(sDTA,dirCluster,entry); };
|
||||
Bit16u GetDirID(void) { return (Bit16u)sGet(sDTA,dirID); };
|
||||
Bit16u GetDirIDCluster(void) { return (Bit16u)sGet(sDTA,dirCluster); };
|
||||
private:
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
struct sDTA {
|
||||
Bit8u sdrive; /* The Drive the search is taking place */
|
||||
Bit8u sname[8]; /* The Search pattern for the filename */
|
||||
Bit8u sext[3]; /* The Search pattern for the extenstion */
|
||||
Bit8u sattr; /* The Attributes that need to be found */
|
||||
Bit16u dirID; /* custom: dir-search ID for multiple searches at the same time */
|
||||
Bit16u dirCluster; /* custom (drive_fat only): cluster number for multiple searches at the same time */
|
||||
Bit8u fill[4];
|
||||
Bit8u attr;
|
||||
Bit16u time;
|
||||
Bit16u date;
|
||||
Bit32u size;
|
||||
char name[DOS_NAMELENGTH_ASCII];
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
};
|
||||
|
||||
class DOS_FCB: public MemStruct {
|
||||
public:
|
||||
DOS_FCB(Bit16u seg,Bit16u off);
|
||||
void Create(bool _extended);
|
||||
void SetName(Bit8u _drive,char * _fname,char * _ext);
|
||||
void SetSizeDateTime(Bit32u _size,Bit16u _date,Bit16u _time);
|
||||
void GetSizeDateTime(Bit32u & _size,Bit16u & _date,Bit16u & _time);
|
||||
void GetName(char * fillname);
|
||||
void FileOpen(Bit8u _fhandle);
|
||||
void FileClose(Bit8u & _fhandle);
|
||||
void GetRecord(Bit16u & _cur_block,Bit8u & _cur_rec);
|
||||
void SetRecord(Bit16u _cur_block,Bit8u _cur_rec);
|
||||
void GetSeqData(Bit8u & _fhandle,Bit16u & _rec_size);
|
||||
void GetRandom(Bit32u & _random);
|
||||
void SetRandom(Bit32u _random);
|
||||
Bit8u GetDrive(void);
|
||||
bool Extended(void);
|
||||
void GetAttr(Bit8u & attr);
|
||||
void SetAttr(Bit8u attr);
|
||||
bool Valid(void);
|
||||
private:
|
||||
bool extended;
|
||||
PhysPt real_pt;
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
struct sFCB {
|
||||
Bit8u drive; /* Drive number 0=default, 1=A, etc */
|
||||
Bit8u filename[8]; /* Space padded name */
|
||||
Bit8u ext[3]; /* Space padded extension */
|
||||
Bit16u cur_block; /* Current Block */
|
||||
Bit16u rec_size; /* Logical record size */
|
||||
Bit32u filesize; /* File Size */
|
||||
Bit16u date;
|
||||
Bit16u time;
|
||||
/* Reserved Block should be 8 bytes */
|
||||
Bit8u sft_entries;
|
||||
Bit8u share_attributes;
|
||||
Bit8u extra_info;
|
||||
Bit8u file_handle;
|
||||
Bit8u reserved[4];
|
||||
/* end */
|
||||
Bit8u cur_rec; /* Current record in current block */
|
||||
Bit32u rndm; /* Current relative record number */
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack ()
|
||||
#endif
|
||||
};
|
||||
|
||||
class DOS_MCB : public MemStruct{
|
||||
public:
|
||||
DOS_MCB(Bit16u seg) { SetPt(seg); }
|
||||
void SetFileName(char const * const _name) { MEM_BlockWrite(pt+offsetof(sMCB,filename),_name,8); }
|
||||
void GetFileName(char * const _name) { MEM_BlockRead(pt+offsetof(sMCB,filename),_name,8);_name[8]=0;}
|
||||
void SetType(Bit8u _type) { sSave(sMCB,type,_type);}
|
||||
void SetSize(Bit16u _size) { sSave(sMCB,size,_size);}
|
||||
void SetPSPSeg(Bit16u _pspseg) { sSave(sMCB,psp_segment,_pspseg);}
|
||||
Bit8u GetType(void) { return (Bit8u)sGet(sMCB,type);}
|
||||
Bit16u GetSize(void) { return (Bit16u)sGet(sMCB,size);}
|
||||
Bit16u GetPSPSeg(void) { return (Bit16u)sGet(sMCB,psp_segment);}
|
||||
private:
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
struct sMCB {
|
||||
Bit8u type;
|
||||
Bit16u psp_segment;
|
||||
Bit16u size;
|
||||
Bit8u unused[3];
|
||||
Bit8u filename[8];
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack ()
|
||||
#endif
|
||||
};
|
||||
|
||||
class DOS_SDA : public MemStruct {
|
||||
public:
|
||||
DOS_SDA(Bit16u _seg,Bit16u _offs) { SetPt(_seg,_offs); }
|
||||
void Init();
|
||||
void SetDrive(Bit8u _drive) { sSave(sSDA,current_drive, _drive); }
|
||||
void SetDTA(Bit32u _dta) { sSave(sSDA,current_dta, _dta); }
|
||||
void SetPSP(Bit16u _psp) { sSave(sSDA,current_psp, _psp); }
|
||||
Bit8u GetDrive(void) { return (Bit8u)sGet(sSDA,current_drive); }
|
||||
Bit16u GetPSP(void) { return (Bit16u)sGet(sSDA,current_psp); }
|
||||
Bit32u GetDTA(void) { return (Bit32u)sGet(sSDA,current_dta); }
|
||||
|
||||
|
||||
private:
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
struct sSDA {
|
||||
Bit8u crit_error_flag; /* 0x00 Critical Error Flag */
|
||||
Bit8u inDOS_flag; /* 0x01 InDOS flag (count of active INT 21 calls) */
|
||||
Bit8u drive_crit_error; /* 0x02 Drive on which current critical error occurred or FFh */
|
||||
Bit8u locus_of_last_error; /* 0x03 locus of last error */
|
||||
Bit16u extended_error_code; /* 0x04 extended error code of last error */
|
||||
Bit8u suggested_action; /* 0x06 suggested action for last error */
|
||||
Bit8u error_class; /* 0x07 class of last error*/
|
||||
Bit32u last_error_pointer; /* 0x08 ES:DI pointer for last error */
|
||||
Bit32u current_dta; /* 0x0C current DTA (Disk Transfer Address) */
|
||||
Bit16u current_psp; /* 0x10 current PSP */
|
||||
Bit16u sp_int_23; /* 0x12 stores SP across an INT 23 */
|
||||
Bit16u return_code; /* 0x14 return code from last process termination (zerod after reading with AH=4Dh) */
|
||||
Bit8u current_drive; /* 0x16 current drive */
|
||||
Bit8u extended_break_flag; /* 0x17 extended break flag */
|
||||
Bit8u fill[2]; /* 0x18 flag: code page switching || flag: copy of previous byte in case of INT 24 Abort*/
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
};
|
||||
extern DOS_InfoBlock dos_infoblock;
|
||||
|
||||
struct DOS_Block {
|
||||
DOS_Date date;
|
||||
DOS_Version version;
|
||||
Bit16u firstMCB;
|
||||
Bit16u errorcode;
|
||||
Bit16u psp(){return DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).GetPSP();};
|
||||
void psp(Bit16u _seg){ DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).SetPSP(_seg);};
|
||||
Bit16u env;
|
||||
RealPt cpmentry;
|
||||
RealPt dta(){return DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).GetDTA();};
|
||||
void dta(RealPt _dta){DOS_SDA(DOS_SDA_SEG,DOS_SDA_OFS).SetDTA(_dta);};
|
||||
Bit8u return_code,return_mode;
|
||||
|
||||
Bit8u current_drive;
|
||||
bool verify;
|
||||
bool breakcheck;
|
||||
bool echo; // if set to true dev_con::read will echo input
|
||||
struct {
|
||||
RealPt mediaid;
|
||||
RealPt tempdta;
|
||||
RealPt tempdta_fcbdelete;
|
||||
RealPt dbcs;
|
||||
RealPt filenamechar;
|
||||
RealPt collatingseq;
|
||||
Bit8u* country;//Will be copied to dos memory. resides in real mem
|
||||
Bit16u dpb; //Fake Disk parameter system using only the first entry so the drive letter matches
|
||||
} tables;
|
||||
Bit16u loaded_codepage;
|
||||
};
|
||||
|
||||
extern DOS_Block dos;
|
||||
|
||||
static Bit8u RealHandle(Bit16u handle) {
|
||||
DOS_PSP psp(dos.psp());
|
||||
return psp.GetFileHandle(handle);
|
||||
}
|
||||
|
||||
#endif
|
269
include/dos_system.h
Normal file
269
include/dos_system.h
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* 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: dos_system.h,v 1.47 2009/03/04 21:08:22 c2woody Exp $ */
|
||||
|
||||
#ifndef DOSBOX_DOS_SYSTEM_H
|
||||
#define DOSBOX_DOS_SYSTEM_H
|
||||
|
||||
#include <vector>
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_CROSS_H
|
||||
#include "cross.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_SUPPORT_H
|
||||
#include "support.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
#define DOS_NAMELENGTH 12
|
||||
#define DOS_NAMELENGTH_ASCII (DOS_NAMELENGTH+1)
|
||||
#define DOS_FCBNAME 15
|
||||
#define DOS_DIRDEPTH 8
|
||||
#define DOS_PATHLENGTH 80
|
||||
#define DOS_TEMPSIZE 1024
|
||||
|
||||
enum {
|
||||
DOS_ATTR_READ_ONLY= 0x01,
|
||||
DOS_ATTR_HIDDEN= 0x02,
|
||||
DOS_ATTR_SYSTEM= 0x04,
|
||||
DOS_ATTR_VOLUME= 0x08,
|
||||
DOS_ATTR_DIRECTORY= 0x10,
|
||||
DOS_ATTR_ARCHIVE= 0x20,
|
||||
DOS_ATTR_DEVICE= 0x40
|
||||
};
|
||||
|
||||
struct FileStat_Block {
|
||||
Bit32u size;
|
||||
Bit16u time;
|
||||
Bit16u date;
|
||||
Bit16u attr;
|
||||
};
|
||||
|
||||
class DOS_DTA;
|
||||
|
||||
class DOS_File {
|
||||
public:
|
||||
DOS_File():flags(0) { name=0; refCtr = 0; hdrive=0xff; };
|
||||
DOS_File(const DOS_File& orig);
|
||||
DOS_File & operator= (const DOS_File & orig);
|
||||
virtual ~DOS_File(){if(name) delete [] name;};
|
||||
virtual bool Read(Bit8u * data,Bit16u * size)=0;
|
||||
virtual bool Write(Bit8u * data,Bit16u * size)=0;
|
||||
virtual bool Seek(Bit32u * pos,Bit32u type)=0;
|
||||
virtual bool Close()=0;
|
||||
virtual Bit16u GetInformation(void)=0;
|
||||
virtual void SetName(const char* _name) { if (name) delete[] name; name = new char[strlen(_name)+1]; strcpy(name,_name); }
|
||||
virtual char* GetName(void) { return name; };
|
||||
virtual bool IsOpen() { return open; };
|
||||
virtual bool IsName(const char* _name) { if (!name) return false; return strcasecmp(name,_name)==0; };
|
||||
virtual void AddRef() { refCtr++; };
|
||||
virtual Bits RemoveRef() { return --refCtr; };
|
||||
virtual bool UpdateDateTimeFromHost() { return true; }
|
||||
void SetDrive(Bit8u drv) { hdrive=drv;}
|
||||
Bit8u GetDrive(void) { return hdrive;}
|
||||
Bit32u flags;
|
||||
Bit16u time;
|
||||
Bit16u date;
|
||||
Bit16u attr;
|
||||
Bits refCtr;
|
||||
bool open;
|
||||
char* name;
|
||||
/* Some Device Specific Stuff */
|
||||
private:
|
||||
Bit8u hdrive;
|
||||
};
|
||||
|
||||
class DOS_Device : public DOS_File {
|
||||
public:
|
||||
DOS_Device(const DOS_Device& orig):DOS_File(orig) {
|
||||
devnum=orig.devnum;
|
||||
open=true;
|
||||
}
|
||||
DOS_Device & operator= (const DOS_Device & orig) {
|
||||
DOS_File::operator=(orig);
|
||||
devnum=orig.devnum;
|
||||
open=true;
|
||||
return *this;
|
||||
}
|
||||
DOS_Device():DOS_File(),devnum(0){};
|
||||
virtual bool Read(Bit8u * data,Bit16u * size);
|
||||
virtual bool Write(Bit8u * data,Bit16u * size);
|
||||
virtual bool Seek(Bit32u * pos,Bit32u type);
|
||||
virtual bool Close();
|
||||
virtual Bit16u GetInformation(void);
|
||||
virtual bool ReadFromControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode);
|
||||
virtual bool WriteToControlChannel(PhysPt bufptr,Bit16u size,Bit16u * retcode);
|
||||
void SetDeviceNumber(Bitu num) { devnum=num;}
|
||||
private:
|
||||
Bitu devnum;
|
||||
};
|
||||
|
||||
/* The following variable can be lowered to free up some memory.
|
||||
* The negative side effect: The stored searches will be turned over faster.
|
||||
* Should not have impact on systems with few directory entries. */
|
||||
#define MAX_OPENDIRS 2048
|
||||
//Can be high as it's only storage (16 bit variable)
|
||||
|
||||
class DOS_Drive_Cache {
|
||||
public:
|
||||
DOS_Drive_Cache (void);
|
||||
DOS_Drive_Cache (const char* path);
|
||||
~DOS_Drive_Cache (void);
|
||||
|
||||
enum TDirSort { NOSORT, ALPHABETICAL, DIRALPHABETICAL, ALPHABETICALREV, DIRALPHABETICALREV };
|
||||
|
||||
void SetBaseDir (const char* path);
|
||||
void SetDirSort (TDirSort sort) { sortDirType = sort; };
|
||||
bool OpenDir (const char* path, Bit16u& id);
|
||||
bool ReadDir (Bit16u id, char* &result);
|
||||
|
||||
void ExpandName (char* path);
|
||||
char* GetExpandName (const char* path);
|
||||
bool GetShortName (const char* fullname, char* shortname);
|
||||
|
||||
bool FindFirst (char* path, Bitu& id);
|
||||
bool FindNext (Bitu id, char* &result);
|
||||
|
||||
void CacheOut (const char* path, bool ignoreLastDir = false);
|
||||
void AddEntry (const char* path, bool checkExist = false);
|
||||
void DeleteEntry (const char* path, bool ignoreLastDir = false);
|
||||
|
||||
void EmptyCache (void);
|
||||
void SetLabel (const char* name,bool cdrom,bool allowupdate);
|
||||
char* GetLabel (void) { return label; };
|
||||
|
||||
class CFileInfo {
|
||||
public:
|
||||
CFileInfo(void) {
|
||||
orgname[0] = shortname[0] = 0;
|
||||
nextEntry = shortNr = 0;
|
||||
isDir = false;
|
||||
}
|
||||
~CFileInfo(void) {
|
||||
for (Bit32u i=0; i<fileList.size(); i++) delete fileList[i];
|
||||
fileList.clear();
|
||||
longNameList.clear();
|
||||
};
|
||||
char orgname [CROSS_LEN];
|
||||
char shortname [DOS_NAMELENGTH_ASCII];
|
||||
bool isDir;
|
||||
Bitu nextEntry;
|
||||
Bitu shortNr;
|
||||
// contents
|
||||
std::vector<CFileInfo*> fileList;
|
||||
std::vector<CFileInfo*> longNameList;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
bool RemoveTrailingDot (char* shortname);
|
||||
Bits GetLongName (CFileInfo* info, char* shortname);
|
||||
void CreateShortName (CFileInfo* dir, CFileInfo* info);
|
||||
Bitu CreateShortNameID (CFileInfo* dir, const char* name);
|
||||
int CompareShortname (const char* compareName, const char* shortName);
|
||||
bool SetResult (CFileInfo* dir, char * &result, Bitu entryNr);
|
||||
bool IsCachedIn (CFileInfo* dir);
|
||||
CFileInfo* FindDirInfo (const char* path, char* expandedPath);
|
||||
bool RemoveSpaces (char* str);
|
||||
bool OpenDir (CFileInfo* dir, const char* path, Bit16u& id);
|
||||
void CreateEntry (CFileInfo* dir, const char* name, bool query_directory);
|
||||
void CopyEntry (CFileInfo* dir, CFileInfo* from);
|
||||
Bit16u GetFreeID (CFileInfo* dir);
|
||||
void Clear (void);
|
||||
|
||||
CFileInfo* dirBase;
|
||||
char dirPath [CROSS_LEN];
|
||||
char basePath [CROSS_LEN];
|
||||
bool dirFirstTime;
|
||||
TDirSort sortDirType;
|
||||
CFileInfo* save_dir;
|
||||
char save_path [CROSS_LEN];
|
||||
char save_expanded [CROSS_LEN];
|
||||
|
||||
Bit16u srchNr;
|
||||
CFileInfo* dirSearch [MAX_OPENDIRS];
|
||||
char dirSearchName [MAX_OPENDIRS];
|
||||
bool free [MAX_OPENDIRS];
|
||||
CFileInfo* dirFindFirst [MAX_OPENDIRS];
|
||||
Bitu nextFreeFindFirst;
|
||||
|
||||
char label [CROSS_LEN];
|
||||
bool updatelabel;
|
||||
};
|
||||
|
||||
class DOS_Drive {
|
||||
public:
|
||||
DOS_Drive();
|
||||
virtual ~DOS_Drive(){};
|
||||
virtual bool FileOpen(DOS_File * * file,char * name,Bit32u flags)=0;
|
||||
virtual bool FileCreate(DOS_File * * file,char * name,Bit16u attributes)=0;
|
||||
virtual bool FileUnlink(char * _name)=0;
|
||||
virtual bool RemoveDir(char * _dir)=0;
|
||||
virtual bool MakeDir(char * _dir)=0;
|
||||
virtual bool TestDir(char * _dir)=0;
|
||||
virtual bool FindFirst(char * _dir,DOS_DTA & dta,bool fcb_findfirst=false)=0;
|
||||
virtual bool FindNext(DOS_DTA & dta)=0;
|
||||
virtual bool GetFileAttr(char * name,Bit16u * attr)=0;
|
||||
virtual bool Rename(char * oldname,char * newname)=0;
|
||||
virtual bool AllocationInfo(Bit16u * _bytes_sector,Bit8u * _sectors_cluster,Bit16u * _total_clusters,Bit16u * _free_clusters)=0;
|
||||
virtual bool FileExists(const char* name)=0;
|
||||
virtual bool FileStat(const char* name, FileStat_Block * const stat_block)=0;
|
||||
virtual Bit8u GetMediaByte(void)=0;
|
||||
virtual void SetDir(const char* path) { strcpy(curdir,path); };
|
||||
virtual void EmptyCache(void) { dirCache.EmptyCache(); };
|
||||
virtual bool isRemote(void)=0;
|
||||
virtual bool isRemovable(void)=0;
|
||||
virtual Bits UnMount(void)=0;
|
||||
|
||||
char * GetInfo(void);
|
||||
char curdir[DOS_PATHLENGTH];
|
||||
char info[256];
|
||||
/* Can be overridden for example in iso images */
|
||||
virtual char const * GetLabel(){return dirCache.GetLabel();};
|
||||
|
||||
DOS_Drive_Cache dirCache;
|
||||
|
||||
// disk cycling functionality (request resources)
|
||||
virtual void Activate(void) {};
|
||||
};
|
||||
|
||||
enum { OPEN_READ=0,OPEN_WRITE=1,OPEN_READWRITE=2, DOS_NOT_INHERIT=128};
|
||||
enum { DOS_SEEK_SET=0,DOS_SEEK_CUR=1,DOS_SEEK_END=2};
|
||||
|
||||
|
||||
/*
|
||||
A multiplex handler should read the registers to check what function is being called
|
||||
If the handler returns false dos will stop checking other handlers
|
||||
*/
|
||||
|
||||
typedef bool (MultiplexHandler)(void);
|
||||
void DOS_AddMultiplexHandler(MultiplexHandler * handler);
|
||||
void DOS_DelMultiplexHandler(MultiplexHandler * handler);
|
||||
|
||||
/* AddDevice stores the pointer to a created device */
|
||||
void DOS_AddDevice(DOS_Device * adddev);
|
||||
/* DelDevice destroys the device that is pointed to. */
|
||||
void DOS_DelDevice(DOS_Device * dev);
|
||||
|
||||
void VFILE_Register(const char * name,Bit8u * data,Bit32u size);
|
||||
#endif
|
76
include/dosbox.h
Normal file
76
include/dosbox.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.h,v 1.31 2008/01/09 20:34:21 c2woody Exp $ */
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#define DOSBOX_DOSBOX_H
|
||||
|
||||
#include "config.h"
|
||||
|
||||
void E_Exit(const char * message,...) GCC_ATTRIBUTE( __format__(__printf__, 1, 2));
|
||||
|
||||
void MSG_Add(const char*,const char*); //add messages to the internal langaugefile
|
||||
const char* MSG_Get(char const *); //get messages from the internal langaugafile
|
||||
|
||||
class Section;
|
||||
|
||||
typedef Bitu (LoopHandler)(void);
|
||||
|
||||
void DOSBOX_RunMachine();
|
||||
void DOSBOX_SetLoop(LoopHandler * handler);
|
||||
void DOSBOX_SetNormalLoop();
|
||||
|
||||
void DOSBOX_Init(void);
|
||||
|
||||
class Config;
|
||||
extern Config * control;
|
||||
|
||||
enum MachineType {
|
||||
MCH_HERC,
|
||||
MCH_CGA,
|
||||
MCH_TANDY,
|
||||
MCH_PCJR,
|
||||
MCH_EGA,
|
||||
MCH_VGA
|
||||
};
|
||||
|
||||
enum SVGACards {
|
||||
SVGA_None,
|
||||
SVGA_S3Trio,
|
||||
SVGA_TsengET4K,
|
||||
SVGA_TsengET3K,
|
||||
SVGA_ParadisePVGA1A
|
||||
};
|
||||
|
||||
extern SVGACards svgaCard;
|
||||
extern MachineType machine;
|
||||
extern bool SDLNetInited;
|
||||
|
||||
#define IS_TANDY_ARCH ((machine==MCH_TANDY) || (machine==MCH_PCJR))
|
||||
#define IS_EGAVGA_ARCH ((machine==MCH_EGA) || (machine==MCH_VGA))
|
||||
#define IS_VGA_ARCH (machine==MCH_VGA)
|
||||
#define TANDY_ARCH_CASE MCH_TANDY: case MCH_PCJR
|
||||
#define EGAVGA_ARCH_CASE MCH_EGA: case MCH_VGA
|
||||
#define VGA_ARCH_CASE MCH_VGA
|
||||
|
||||
#ifndef DOSBOX_LOGGING_H
|
||||
#include "logging.h"
|
||||
#endif // the logging system.
|
||||
|
||||
#endif /* DOSBOX_DOSBOX_H */
|
154
include/fpu.h
Normal file
154
include/fpu.h
Normal file
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_FPU_H
|
||||
#define DOSBOX_FPU_H
|
||||
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
void FPU_ESC0_Normal(Bitu rm);
|
||||
void FPU_ESC0_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC1_Normal(Bitu rm);
|
||||
void FPU_ESC1_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC2_Normal(Bitu rm);
|
||||
void FPU_ESC2_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC3_Normal(Bitu rm);
|
||||
void FPU_ESC3_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC4_Normal(Bitu rm);
|
||||
void FPU_ESC4_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC5_Normal(Bitu rm);
|
||||
void FPU_ESC5_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC6_Normal(Bitu rm);
|
||||
void FPU_ESC6_EA(Bitu func,PhysPt ea);
|
||||
void FPU_ESC7_Normal(Bitu rm);
|
||||
void FPU_ESC7_EA(Bitu func,PhysPt ea);
|
||||
|
||||
|
||||
typedef union {
|
||||
double d;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
struct {
|
||||
Bit32u lower;
|
||||
Bit32s upper;
|
||||
} l;
|
||||
#else
|
||||
struct {
|
||||
Bit32s upper;
|
||||
Bit32u lower;
|
||||
} l;
|
||||
#endif
|
||||
Bit64s ll;
|
||||
} FPU_Reg;
|
||||
|
||||
typedef struct {
|
||||
Bit32u m1;
|
||||
Bit32u m2;
|
||||
Bit16u m3;
|
||||
|
||||
Bit16u d1;
|
||||
Bit32u d2;
|
||||
} FPU_P_Reg;
|
||||
|
||||
enum FPU_Tag {
|
||||
TAG_Valid = 0,
|
||||
TAG_Zero = 1,
|
||||
TAG_Weird = 2,
|
||||
TAG_Empty = 3
|
||||
};
|
||||
|
||||
enum FPU_Round {
|
||||
ROUND_Nearest = 0,
|
||||
ROUND_Down = 1,
|
||||
ROUND_Up = 2,
|
||||
ROUND_Chop = 3
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FPU_Reg regs[9];
|
||||
FPU_P_Reg p_regs[9];
|
||||
FPU_Tag tags[9];
|
||||
Bit16u cw,cw_mask_all;
|
||||
Bit16u sw;
|
||||
Bitu top;
|
||||
FPU_Round round;
|
||||
} FPU_rec;
|
||||
|
||||
|
||||
//get pi from a real library
|
||||
#define PI 3.14159265358979323846
|
||||
#define L2E 1.4426950408889634
|
||||
#define L2T 3.3219280948873623
|
||||
#define LN2 0.69314718055994531
|
||||
#define LG2 0.3010299956639812
|
||||
|
||||
|
||||
extern FPU_rec fpu;
|
||||
|
||||
#define TOP fpu.top
|
||||
#define STV(i) ( (fpu.top+ (i) ) & 7 )
|
||||
|
||||
|
||||
Bit16u FPU_GetTag(void);
|
||||
void FPU_FLDCW(PhysPt addr);
|
||||
|
||||
static INLINE void FPU_SetTag(Bit16u tag){
|
||||
for(Bitu i=0;i<8;i++)
|
||||
fpu.tags[i] = static_cast<FPU_Tag>((tag >>(2*i))&3);
|
||||
}
|
||||
|
||||
static INLINE void FPU_SetCW(Bitu word){
|
||||
fpu.cw = (Bit16u)word;
|
||||
fpu.cw_mask_all = (Bit16u)(word | 0x3f);
|
||||
fpu.round = (FPU_Round)((word >> 10) & 3);
|
||||
}
|
||||
|
||||
|
||||
static INLINE Bitu FPU_GET_TOP(void) {
|
||||
return (fpu.sw & 0x3800)>>11;
|
||||
}
|
||||
|
||||
static INLINE void FPU_SET_TOP(Bitu val){
|
||||
fpu.sw &= ~0x3800;
|
||||
fpu.sw |= (val&7)<<11;
|
||||
}
|
||||
|
||||
|
||||
static INLINE void FPU_SET_C0(Bitu C){
|
||||
fpu.sw &= ~0x0100;
|
||||
if(C) fpu.sw |= 0x0100;
|
||||
}
|
||||
|
||||
static INLINE void FPU_SET_C1(Bitu C){
|
||||
fpu.sw &= ~0x0200;
|
||||
if(C) fpu.sw |= 0x0200;
|
||||
}
|
||||
|
||||
static INLINE void FPU_SET_C2(Bitu C){
|
||||
fpu.sw &= ~0x0400;
|
||||
if(C) fpu.sw |= 0x0400;
|
||||
}
|
||||
|
||||
static INLINE void FPU_SET_C3(Bitu C){
|
||||
fpu.sw &= ~0x4000;
|
||||
if(C) fpu.sw |= 0x4000;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
50
include/hardware.h
Normal file
50
include/hardware.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_HARDWARE_H
|
||||
#define DOSBOX_HARDWARE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class Section;
|
||||
enum OPL_Mode {
|
||||
OPL_none,OPL_cms,OPL_opl2,OPL_dualopl2,OPL_opl3
|
||||
};
|
||||
#define CAPTURE_WAVE 0x01
|
||||
#define CAPTURE_OPL 0x02
|
||||
#define CAPTURE_MIDI 0x04
|
||||
#define CAPTURE_IMAGE 0x08
|
||||
#define CAPTURE_VIDEO 0x10
|
||||
|
||||
extern Bitu CaptureState;
|
||||
|
||||
void OPL_Init(Section* sec,OPL_Mode mode);
|
||||
void CMS_Init(Section* sec);
|
||||
void OPL_ShutDown(Section* sec);
|
||||
void CMS_ShutDown(Section* sec);
|
||||
|
||||
extern Bit8u adlib_commandreg;
|
||||
FILE * OpenCaptureFile(const char * type,const char * ext);
|
||||
|
||||
void CAPTURE_AddWave(Bit32u freq, Bit32u len, Bit16s * data);
|
||||
#define CAPTURE_FLAG_DBLW 0x1
|
||||
#define CAPTURE_FLAG_DBLH 0x2
|
||||
void CAPTURE_AddImage(Bitu width, Bitu height, Bitu bpp, Bitu pitch, Bitu flags, float fps, Bit8u * data, Bit8u * pal);
|
||||
void CAPTURE_AddMidi(bool sysex, Bitu len, Bit8u * data);
|
||||
|
||||
#endif
|
78
include/inout.h
Normal file
78
include/inout.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: inout.h,v 1.12 2009/04/25 16:25:03 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_INOUT_H
|
||||
#define DOSBOX_INOUT_H
|
||||
|
||||
#define IO_MAX (64*1024+3)
|
||||
|
||||
#define IO_MB 0x1
|
||||
#define IO_MW 0x2
|
||||
#define IO_MD 0x4
|
||||
#define IO_MA (IO_MB | IO_MW | IO_MD )
|
||||
|
||||
typedef Bitu IO_ReadHandler(Bitu port,Bitu iolen);
|
||||
typedef void IO_WriteHandler(Bitu port,Bitu val,Bitu iolen);
|
||||
|
||||
extern IO_WriteHandler * io_writehandlers[3][IO_MAX];
|
||||
extern IO_ReadHandler * io_readhandlers[3][IO_MAX];
|
||||
|
||||
void IO_RegisterReadHandler(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1);
|
||||
void IO_RegisterWriteHandler(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1);
|
||||
|
||||
void IO_FreeReadHandler(Bitu port,Bitu mask,Bitu range=1);
|
||||
void IO_FreeWriteHandler(Bitu port,Bitu mask,Bitu range=1);
|
||||
|
||||
void IO_WriteB(Bitu port,Bitu val);
|
||||
void IO_WriteW(Bitu port,Bitu val);
|
||||
void IO_WriteD(Bitu port,Bitu val);
|
||||
|
||||
Bitu IO_ReadB(Bitu port);
|
||||
Bitu IO_ReadW(Bitu port);
|
||||
Bitu IO_ReadD(Bitu port);
|
||||
|
||||
/* Classes to manage the IO objects created by the various devices.
|
||||
* The io objects will remove itself on destruction.*/
|
||||
class IO_Base{
|
||||
protected:
|
||||
bool installed;
|
||||
Bitu m_port, m_mask,m_range;
|
||||
public:
|
||||
IO_Base():installed(false){};
|
||||
};
|
||||
class IO_ReadHandleObject: private IO_Base{
|
||||
public:
|
||||
void Install(Bitu port,IO_ReadHandler * handler,Bitu mask,Bitu range=1);
|
||||
~IO_ReadHandleObject();
|
||||
};
|
||||
class IO_WriteHandleObject: private IO_Base{
|
||||
public:
|
||||
void Install(Bitu port,IO_WriteHandler * handler,Bitu mask,Bitu range=1);
|
||||
~IO_WriteHandleObject();
|
||||
};
|
||||
|
||||
static INLINE void IO_Write(Bitu port,Bit8u val) {
|
||||
IO_WriteB(port,val);
|
||||
}
|
||||
static INLINE Bit8u IO_Read(Bitu port){
|
||||
return (Bit8u)IO_ReadB(port);
|
||||
}
|
||||
|
||||
#endif
|
161
include/ipx.h
Normal file
161
include/ipx.h
Normal file
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: ipx.h,v 1.12 2007/01/13 08:35:49 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_IPX_H
|
||||
#define DOSBOX_IPX_H
|
||||
|
||||
// Uncomment this for a lot of debug messages:
|
||||
//#define IPX_DEBUGMSG
|
||||
|
||||
#ifdef IPX_DEBUGMSG
|
||||
#define LOG_IPX LOG_MSG
|
||||
#else
|
||||
#if defined (_MSC_VER)
|
||||
#define LOG_IPX
|
||||
#else
|
||||
#define LOG_IPX(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
// In Use Flag codes
|
||||
#define USEFLAG_AVAILABLE 0x00
|
||||
#define USEFLAG_AESTEMP 0xe0
|
||||
#define USEFLAG_IPXCRIT 0xf8
|
||||
#define USEFLAG_SPXLISTEN 0xf9
|
||||
#define USEFLAG_PROCESSING 0xfa
|
||||
#define USEFLAG_HOLDING 0xfb
|
||||
#define USEFLAG_AESWAITING 0xfc
|
||||
#define USEFLAG_AESCOUNT 0xfd
|
||||
#define USEFLAG_LISTENING 0xfe
|
||||
#define USEFLAG_SENDING 0xff
|
||||
|
||||
// Completion codes
|
||||
#define COMP_SUCCESS 0x00
|
||||
#define COMP_REMOTETERM 0xec
|
||||
#define COMP_DISCONNECT 0xed
|
||||
#define COMP_INVALIDID 0xee
|
||||
#define COMP_SPXTABLEFULL 0xef
|
||||
#define COMP_EVENTNOTCANCELED 0xf9
|
||||
#define COMP_NOCONNECTION 0xfa
|
||||
#define COMP_CANCELLED 0xfc
|
||||
#define COMP_MALFORMED 0xfd
|
||||
#define COMP_UNDELIVERABLE 0xfe
|
||||
#define COMP_HARDWAREERROR 0xff
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(1)
|
||||
#endif
|
||||
|
||||
// For Uint8 type
|
||||
#include "SDL_net.h"
|
||||
|
||||
struct PackedIP {
|
||||
Uint32 host;
|
||||
Uint16 port;
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
|
||||
struct nodeType {
|
||||
Uint8 node[6];
|
||||
} GCC_ATTRIBUTE(packed) ;
|
||||
|
||||
struct IPXHeader {
|
||||
Uint8 checkSum[2];
|
||||
Uint8 length[2];
|
||||
Uint8 transControl; // Transport control
|
||||
Uint8 pType; // Packet type
|
||||
|
||||
struct transport {
|
||||
Uint8 network[4];
|
||||
union addrtype {
|
||||
nodeType byNode;
|
||||
PackedIP byIP ;
|
||||
} GCC_ATTRIBUTE(packed) addr;
|
||||
Uint8 socket[2];
|
||||
} dest, src;
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
|
||||
struct fragmentDescriptor {
|
||||
Bit16u offset;
|
||||
Bit16u segment;
|
||||
Bit16u size;
|
||||
};
|
||||
|
||||
#define IPXBUFFERSIZE 1424
|
||||
|
||||
class ECBClass {
|
||||
public:
|
||||
RealPt ECBAddr;
|
||||
bool isInESRList;
|
||||
ECBClass *prevECB; // Linked List
|
||||
ECBClass *nextECB;
|
||||
|
||||
Bit8u iuflag; // Need to save data since we are not always in
|
||||
Bit16u mysocket; // real mode
|
||||
|
||||
Bit8u* databuffer; // received data is stored here until we get called
|
||||
Bitu buflen; // by Interrupt
|
||||
|
||||
#ifdef IPX_DEBUGMSG
|
||||
Bitu SerialNumber;
|
||||
#endif
|
||||
|
||||
ECBClass(Bit16u segment, Bit16u offset);
|
||||
Bit16u getSocket(void);
|
||||
|
||||
Bit8u getInUseFlag(void);
|
||||
|
||||
void setInUseFlag(Bit8u flagval);
|
||||
|
||||
void setCompletionFlag(Bit8u flagval);
|
||||
|
||||
Bit16u getFragCount(void);
|
||||
|
||||
bool writeData();
|
||||
void writeDataBuffer(Bit8u* buffer, Bit16u length);
|
||||
|
||||
void getFragDesc(Bit16u descNum, fragmentDescriptor *fragDesc);
|
||||
RealPt getESRAddr(void);
|
||||
|
||||
void NotifyESR(void);
|
||||
|
||||
void setImmAddress(Bit8u *immAddr);
|
||||
void getImmAddress(Bit8u* immAddr);
|
||||
|
||||
~ECBClass();
|
||||
};
|
||||
|
||||
// The following routines may not be needed on all systems. On my build of SDL the IPaddress structure is 8 octects
|
||||
// and therefore screws up my IPXheader structure since it needs to be packed.
|
||||
|
||||
void UnpackIP(PackedIP ipPack, IPaddress * ipAddr);
|
||||
void PackIP(IPaddress ipAddr, PackedIP *ipPack);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack()
|
||||
#endif
|
||||
|
||||
#endif
|
48
include/ipxserver.h
Normal file
48
include/ipxserver.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_IPXSERVER_H_
|
||||
#define DOSBOX_IPXSERVER_H_
|
||||
|
||||
#if C_IPX
|
||||
|
||||
#include "SDL_net.h"
|
||||
|
||||
struct packetBuffer {
|
||||
Bit8u buffer[1024];
|
||||
Bit16s packetSize; // Packet size remaining in read
|
||||
Bit16s packetRead; // Bytes read of total packet
|
||||
bool inPacket; // In packet reception flag
|
||||
bool connected; // Connected flag
|
||||
bool waitsize;
|
||||
};
|
||||
|
||||
#define SOCKETTABLESIZE 16
|
||||
#define CONVIP(hostvar) hostvar & 0xff, (hostvar >> 8) & 0xff, (hostvar >> 16) & 0xff, (hostvar >> 24) & 0xff
|
||||
#define CONVIPX(hostvar) hostvar[0], hostvar[1], hostvar[2], hostvar[3], hostvar[4], hostvar[5]
|
||||
|
||||
|
||||
void IPX_StopServer();
|
||||
bool IPX_StartServer(Bit16u portnum);
|
||||
bool IPX_isConnectedToServer(Bits tableNum, IPaddress ** ptrAddr);
|
||||
|
||||
Bit8u packetCRC(Bit8u *buffer, Bit16u bufSize);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
50
include/joystick.h
Normal file
50
include/joystick.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: joystick.h,v 1.12 2007/08/12 10:23:35 c2woody Exp $ */
|
||||
#ifndef DOSBOX_JOYSTICK_H
|
||||
#define DOSBOX_JOYSTICK_H
|
||||
void JOYSTICK_Enable(Bitu which,bool enabled);
|
||||
|
||||
void JOYSTICK_Button(Bitu which,Bitu num,bool pressed);
|
||||
|
||||
void JOYSTICK_Move_X(Bitu which,float x);
|
||||
|
||||
void JOYSTICK_Move_Y(Bitu which,float y);
|
||||
|
||||
bool JOYSTICK_IsEnabled(Bitu which);
|
||||
|
||||
bool JOYSTICK_GetButton(Bitu which, Bitu num);
|
||||
|
||||
float JOYSTICK_GetMove_X(Bitu which);
|
||||
|
||||
float JOYSTICK_GetMove_Y(Bitu which);
|
||||
|
||||
enum JoystickType {
|
||||
JOY_NONE,
|
||||
JOY_AUTO,
|
||||
JOY_2AXIS,
|
||||
JOY_4AXIS,
|
||||
JOY_4AXIS_2,
|
||||
JOY_FCS,
|
||||
JOY_CH
|
||||
};
|
||||
|
||||
extern JoystickType joytype;
|
||||
extern bool button_wrapping_enabled;
|
||||
#endif
|
53
include/keyboard.h
Normal file
53
include/keyboard.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_KEYBOARD_H
|
||||
#define DOSBOX_KEYBOARD_H
|
||||
|
||||
enum KBD_KEYS {
|
||||
KBD_NONE,
|
||||
KBD_1, KBD_2, KBD_3, KBD_4, KBD_5, KBD_6, KBD_7, KBD_8, KBD_9, KBD_0,
|
||||
KBD_q, KBD_w, KBD_e, KBD_r, KBD_t, KBD_y, KBD_u, KBD_i, KBD_o, KBD_p,
|
||||
KBD_a, KBD_s, KBD_d, KBD_f, KBD_g, KBD_h, KBD_j, KBD_k, KBD_l, KBD_z,
|
||||
KBD_x, KBD_c, KBD_v, KBD_b, KBD_n, KBD_m,
|
||||
KBD_f1, KBD_f2, KBD_f3, KBD_f4, KBD_f5, KBD_f6, KBD_f7, KBD_f8, KBD_f9, KBD_f10,KBD_f11,KBD_f12,
|
||||
|
||||
/*Now the weirder keys */
|
||||
|
||||
KBD_esc,KBD_tab,KBD_backspace,KBD_enter,KBD_space,
|
||||
KBD_leftalt,KBD_rightalt,KBD_leftctrl,KBD_rightctrl,KBD_leftshift,KBD_rightshift,
|
||||
KBD_capslock,KBD_scrolllock,KBD_numlock,
|
||||
|
||||
KBD_grave,KBD_minus,KBD_equals,KBD_backslash,KBD_leftbracket,KBD_rightbracket,
|
||||
KBD_semicolon,KBD_quote,KBD_period,KBD_comma,KBD_slash,KBD_extra_lt_gt,
|
||||
|
||||
KBD_printscreen,KBD_pause,
|
||||
KBD_insert,KBD_home,KBD_pageup,KBD_delete,KBD_end,KBD_pagedown,
|
||||
KBD_left,KBD_up,KBD_down,KBD_right,
|
||||
|
||||
KBD_kp1,KBD_kp2,KBD_kp3,KBD_kp4,KBD_kp5,KBD_kp6,KBD_kp7,KBD_kp8,KBD_kp9,KBD_kp0,
|
||||
KBD_kpdivide,KBD_kpmultiply,KBD_kpminus,KBD_kpplus,KBD_kpenter,KBD_kpperiod,
|
||||
|
||||
|
||||
KBD_LAST
|
||||
};
|
||||
|
||||
void KEYBOARD_ClrBuffer(void);
|
||||
void KEYBOARD_AddKey(KBD_KEYS keytype,bool pressed);
|
||||
|
||||
#endif
|
67
include/logging.h
Normal file
67
include/logging.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef DOSBOX_LOGGING_H
|
||||
#define DOSBOX_LOGGING_H
|
||||
enum LOG_TYPES {
|
||||
LOG_ALL,
|
||||
LOG_VGA, LOG_VGAGFX,LOG_VGAMISC,LOG_INT10,
|
||||
LOG_SB,LOG_DMACONTROL,
|
||||
LOG_FPU,LOG_CPU,LOG_PAGING,
|
||||
LOG_FCB,LOG_FILES,LOG_IOCTL,LOG_EXEC,LOG_DOSMISC,
|
||||
LOG_PIT,LOG_KEYBOARD,LOG_PIC,
|
||||
LOG_MOUSE,LOG_BIOS,LOG_GUI,LOG_MISC,
|
||||
LOG_IO,
|
||||
LOG_MAX
|
||||
};
|
||||
|
||||
enum LOG_SEVERITIES {
|
||||
LOG_NORMAL,
|
||||
LOG_WARN,
|
||||
LOG_ERROR
|
||||
};
|
||||
|
||||
#if C_DEBUG
|
||||
class LOG
|
||||
{
|
||||
LOG_TYPES d_type;
|
||||
LOG_SEVERITIES d_severity;
|
||||
public:
|
||||
|
||||
LOG (LOG_TYPES type , LOG_SEVERITIES severity):
|
||||
d_type(type),
|
||||
d_severity(severity)
|
||||
{}
|
||||
void operator() (char const* buf, ...) GCC_ATTRIBUTE(__format__(__printf__, 2, 3)); //../src/debug/debug_gui.cpp
|
||||
|
||||
};
|
||||
|
||||
void DEBUG_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2));
|
||||
#define LOG_MSG DEBUG_ShowMsg
|
||||
|
||||
#else //C_DEBUG
|
||||
|
||||
struct LOG
|
||||
{
|
||||
LOG(LOG_TYPES , LOG_SEVERITIES ) { }
|
||||
void operator()(char const* ) { }
|
||||
void operator()(char const* , double ) { }
|
||||
void operator()(char const* , double , double ) { }
|
||||
void operator()(char const* , double , double , double ) { }
|
||||
void operator()(char const* , double , double , double , double ) { }
|
||||
void operator()(char const* , double , double , double , double , double ) { }
|
||||
|
||||
void operator()(char const* , char const* ) { }
|
||||
void operator()(char const* , char const* , double ) { }
|
||||
void operator()(char const* , char const* , double ,double ) { }
|
||||
void operator()(char const* , double , char const* ) { }
|
||||
void operator()(char const* , double , double, char const* ) { }
|
||||
void operator()(char const* , char const*, char const*) { }
|
||||
|
||||
|
||||
}; //add missing operators to here
|
||||
//try to avoid anything smaller than bit32...
|
||||
void GFX_ShowMsg(char const* format,...) GCC_ATTRIBUTE(__format__(__printf__, 1, 2));
|
||||
#define LOG_MSG GFX_ShowMsg
|
||||
|
||||
#endif //C_DEBUG
|
||||
|
||||
|
||||
#endif //DOSBOX_LOGGING_H
|
39
include/mapper.h
Normal file
39
include/mapper.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_MAPPER_H
|
||||
#define DOSBOX_MAPPER_H
|
||||
|
||||
enum MapKeys {
|
||||
MK_f1,MK_f2,MK_f3,MK_f4,MK_f5,MK_f6,MK_f7,MK_f8,MK_f9,MK_f10,MK_f11,MK_f12,
|
||||
MK_return,MK_kpminus,MK_scrolllock,MK_printscreen,MK_pause
|
||||
|
||||
};
|
||||
|
||||
typedef void (MAPPER_Handler)(bool pressed);
|
||||
void MAPPER_AddHandler(MAPPER_Handler * handler,MapKeys key,Bitu mods,char const * const eventname,char const * const buttonname);
|
||||
void MAPPER_Init(void);
|
||||
void MAPPER_StartUp(Section * sec);
|
||||
void MAPPER_Run(bool pressed);
|
||||
void MAPPER_LosingFocus(void);
|
||||
|
||||
|
||||
#define MMOD1 0x1
|
||||
#define MMOD2 0x2
|
||||
|
||||
#endif
|
219
include/mem.h
Normal file
219
include/mem.h
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_MEM_H
|
||||
#define DOSBOX_MEM_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
|
||||
typedef Bit32u PhysPt;
|
||||
typedef Bit8u * HostPt;
|
||||
typedef Bit32u RealPt;
|
||||
|
||||
typedef Bit32s MemHandle;
|
||||
|
||||
#define MEM_PAGESIZE 4096
|
||||
|
||||
extern HostPt MemBase;
|
||||
HostPt GetMemBase(void);
|
||||
|
||||
bool MEM_A20_Enabled(void);
|
||||
void MEM_A20_Enable(bool enable);
|
||||
|
||||
/* Memory management / EMS mapping */
|
||||
HostPt MEM_GetBlockPage(void);
|
||||
Bitu MEM_FreeTotal(void); //Free 4 kb pages
|
||||
Bitu MEM_FreeLargest(void); //Largest free 4 kb pages block
|
||||
Bitu MEM_TotalPages(void); //Total amount of 4 kb pages
|
||||
Bitu MEM_AllocatedPages(MemHandle handle); // amount of allocated pages of handle
|
||||
MemHandle MEM_AllocatePages(Bitu pages,bool sequence);
|
||||
MemHandle MEM_GetNextFreePage(void);
|
||||
PhysPt MEM_AllocatePage(void);
|
||||
void MEM_ReleasePages(MemHandle handle);
|
||||
bool MEM_ReAllocatePages(MemHandle & handle,Bitu pages,bool sequence);
|
||||
|
||||
MemHandle MEM_NextHandle(MemHandle handle);
|
||||
MemHandle MEM_NextHandleAt(MemHandle handle,Bitu where);
|
||||
|
||||
/*
|
||||
The folowing six functions are used everywhere in the end so these should be changed for
|
||||
Working on big or little endian machines
|
||||
*/
|
||||
|
||||
#if defined(WORDS_BIGENDIAN) || !defined(C_UNALIGNED_MEMORY)
|
||||
|
||||
static INLINE Bit8u host_readb(HostPt off) {
|
||||
return off[0];
|
||||
}
|
||||
static INLINE Bit16u host_readw(HostPt off) {
|
||||
return off[0] | (off[1] << 8);
|
||||
}
|
||||
static INLINE Bit32u host_readd(HostPt off) {
|
||||
return off[0] | (off[1] << 8) | (off[2] << 16) | (off[3] << 24);
|
||||
}
|
||||
static INLINE void host_writeb(HostPt off,Bit8u val) {
|
||||
off[0]=val;
|
||||
}
|
||||
static INLINE void host_writew(HostPt off,Bit16u val) {
|
||||
off[0]=(Bit8u)(val);
|
||||
off[1]=(Bit8u)(val >> 8);
|
||||
}
|
||||
static INLINE void host_writed(HostPt off,Bit32u val) {
|
||||
off[0]=(Bit8u)(val);
|
||||
off[1]=(Bit8u)(val >> 8);
|
||||
off[2]=(Bit8u)(val >> 16);
|
||||
off[3]=(Bit8u)(val >> 24);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static INLINE Bit8u host_readb(HostPt off) {
|
||||
return *(Bit8u *)off;
|
||||
}
|
||||
static INLINE Bit16u host_readw(HostPt off) {
|
||||
return *(Bit16u *)off;
|
||||
}
|
||||
static INLINE Bit32u host_readd(HostPt off) {
|
||||
return *(Bit32u *)off;
|
||||
}
|
||||
static INLINE void host_writeb(HostPt off,Bit8u val) {
|
||||
*(Bit8u *)(off)=val;
|
||||
}
|
||||
static INLINE void host_writew(HostPt off,Bit16u val) {
|
||||
*(Bit16u *)(off)=val;
|
||||
}
|
||||
static INLINE void host_writed(HostPt off,Bit32u val) {
|
||||
*(Bit32u *)(off)=val;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
static INLINE void var_write(Bit8u * var, Bit8u val) {
|
||||
host_writeb((HostPt)var, val);
|
||||
}
|
||||
|
||||
static INLINE void var_write(Bit16u * var, Bit16u val) {
|
||||
host_writew((HostPt)var, val);
|
||||
}
|
||||
|
||||
static INLINE void var_write(Bit32u * var, Bit32u val) {
|
||||
host_writed((HostPt)var, val);
|
||||
}
|
||||
|
||||
/* The Folowing six functions are slower but they recognize the paged memory system */
|
||||
|
||||
Bit8u mem_readb(PhysPt pt);
|
||||
Bit16u mem_readw(PhysPt pt);
|
||||
Bit32u mem_readd(PhysPt pt);
|
||||
|
||||
void mem_writeb(PhysPt pt,Bit8u val);
|
||||
void mem_writew(PhysPt pt,Bit16u val);
|
||||
void mem_writed(PhysPt pt,Bit32u val);
|
||||
|
||||
static INLINE void phys_writeb(PhysPt addr,Bit8u val) {
|
||||
host_writeb(MemBase+addr,val);
|
||||
}
|
||||
static INLINE void phys_writew(PhysPt addr,Bit16u val){
|
||||
host_writew(MemBase+addr,val);
|
||||
}
|
||||
static INLINE void phys_writed(PhysPt addr,Bit32u val){
|
||||
host_writed(MemBase+addr,val);
|
||||
}
|
||||
|
||||
static INLINE Bit8u phys_readb(PhysPt addr) {
|
||||
return host_readb(MemBase+addr);
|
||||
}
|
||||
static INLINE Bit16u phys_readw(PhysPt addr){
|
||||
return host_readw(MemBase+addr);
|
||||
}
|
||||
static INLINE Bit32u phys_readd(PhysPt addr){
|
||||
return host_readd(MemBase+addr);
|
||||
}
|
||||
|
||||
/* These don't check for alignment, better be sure it's correct */
|
||||
|
||||
void MEM_BlockWrite(PhysPt pt,void const * const data,Bitu size);
|
||||
void MEM_BlockRead(PhysPt pt,void * data,Bitu size);
|
||||
void MEM_BlockCopy(PhysPt dest,PhysPt src,Bitu size);
|
||||
void MEM_StrCopy(PhysPt pt,char * data,Bitu size);
|
||||
|
||||
void mem_memcpy(PhysPt dest,PhysPt src,Bitu size);
|
||||
Bitu mem_strlen(PhysPt pt);
|
||||
void mem_strcpy(PhysPt dest,PhysPt src);
|
||||
|
||||
/* The folowing functions are all shortcuts to the above functions using physical addressing */
|
||||
|
||||
static INLINE Bit8u real_readb(Bit16u seg,Bit16u off) {
|
||||
return mem_readb((seg<<4)+off);
|
||||
}
|
||||
static INLINE Bit16u real_readw(Bit16u seg,Bit16u off) {
|
||||
return mem_readw((seg<<4)+off);
|
||||
}
|
||||
static INLINE Bit32u real_readd(Bit16u seg,Bit16u off) {
|
||||
return mem_readd((seg<<4)+off);
|
||||
}
|
||||
|
||||
static INLINE void real_writeb(Bit16u seg,Bit16u off,Bit8u val) {
|
||||
mem_writeb(((seg<<4)+off),val);
|
||||
}
|
||||
static INLINE void real_writew(Bit16u seg,Bit16u off,Bit16u val) {
|
||||
mem_writew(((seg<<4)+off),val);
|
||||
}
|
||||
static INLINE void real_writed(Bit16u seg,Bit16u off,Bit32u val) {
|
||||
mem_writed(((seg<<4)+off),val);
|
||||
}
|
||||
|
||||
|
||||
static INLINE Bit16u RealSeg(RealPt pt) {
|
||||
return (Bit16u)(pt>>16);
|
||||
}
|
||||
|
||||
static INLINE Bit16u RealOff(RealPt pt) {
|
||||
return (Bit16u)(pt&0xffff);
|
||||
}
|
||||
|
||||
static INLINE PhysPt Real2Phys(RealPt pt) {
|
||||
return (RealSeg(pt)<<4) +RealOff(pt);
|
||||
}
|
||||
|
||||
static INLINE PhysPt PhysMake(Bit16u seg,Bit16u off) {
|
||||
return (seg<<4)+off;
|
||||
}
|
||||
|
||||
static INLINE RealPt RealMake(Bit16u seg,Bit16u off) {
|
||||
return (seg<<16)+off;
|
||||
}
|
||||
|
||||
static INLINE void RealSetVec(Bit8u vec,RealPt pt) {
|
||||
mem_writed(vec<<2,pt);
|
||||
}
|
||||
|
||||
static INLINE void RealSetVec(Bit8u vec,RealPt pt,RealPt &old) {
|
||||
old = mem_readd(vec<<2);
|
||||
mem_writed(vec<<2,pt);
|
||||
}
|
||||
|
||||
static INLINE RealPt RealGetVec(Bit8u vec) {
|
||||
return mem_readd(vec<<2);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
114
include/mixer.h
Normal file
114
include/mixer.h
Normal file
@ -0,0 +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: mixer.h,v 1.19 2009/04/28 21:48:24 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_MIXER_H
|
||||
#define DOSBOX_MIXER_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
|
||||
typedef void (*MIXER_MixHandler)(Bit8u * sampdate,Bit32u len);
|
||||
typedef void (*MIXER_Handler)(Bitu len);
|
||||
|
||||
enum BlahModes {
|
||||
MIXER_8MONO,MIXER_8STEREO,
|
||||
MIXER_16MONO,MIXER_16STEREO
|
||||
};
|
||||
|
||||
enum MixerModes {
|
||||
M_8M,M_8S,
|
||||
M_16M,M_16S
|
||||
};
|
||||
|
||||
#define MIXER_BUFSIZE (16*1024)
|
||||
#define MIXER_BUFMASK (MIXER_BUFSIZE-1)
|
||||
extern Bit8u MixTemp[MIXER_BUFSIZE];
|
||||
|
||||
#define MAX_AUDIO ((1<<(16-1))-1)
|
||||
#define MIN_AUDIO -(1<<(16-1))
|
||||
|
||||
class MixerChannel {
|
||||
public:
|
||||
void SetVolume(float _left,float _right);
|
||||
void SetScale( float f );
|
||||
void UpdateVolume(void);
|
||||
void SetFreq(Bitu _freq);
|
||||
void Mix(Bitu _needed);
|
||||
void AddSilence(void); //Fill up until needed
|
||||
|
||||
template<class Type,bool stereo,bool signeddata,bool nativeorder>
|
||||
void AddSamples(Bitu len, const Type* data);
|
||||
|
||||
void AddSamples_m8(Bitu len, const Bit8u * data);
|
||||
void AddSamples_s8(Bitu len, const Bit8u * data);
|
||||
void AddSamples_m8s(Bitu len, const Bit8s * data);
|
||||
void AddSamples_s8s(Bitu len, const Bit8s * data);
|
||||
void AddSamples_m16(Bitu len, const Bit16s * data);
|
||||
void AddSamples_s16(Bitu len, const Bit16s * data);
|
||||
void AddSamples_m16u(Bitu len, const Bit16u * data);
|
||||
void AddSamples_s16u(Bitu len, const Bit16u * data);
|
||||
void AddSamples_m32(Bitu len, const Bit32s * data);
|
||||
void AddSamples_s32(Bitu len, const Bit32s * data);
|
||||
void AddSamples_m16_nonnative(Bitu len, const Bit16s * data);
|
||||
void AddSamples_s16_nonnative(Bitu len, const Bit16s * data);
|
||||
void AddSamples_m16u_nonnative(Bitu len, const Bit16u * data);
|
||||
void AddSamples_s16u_nonnative(Bitu len, const Bit16u * data);
|
||||
void AddSamples_m32_nonnative(Bitu len, const Bit32s * data);
|
||||
void AddSamples_s32_nonnative(Bitu len, const Bit32s * data);
|
||||
|
||||
void AddStretched(Bitu len,Bit16s * data); //Strech block up into needed data
|
||||
void FillUp(void);
|
||||
void Enable(bool _yesno);
|
||||
MIXER_Handler handler;
|
||||
float volmain[2];
|
||||
float scale;
|
||||
Bit32s volmul[2];
|
||||
Bitu freq_add,freq_index;
|
||||
Bitu done,needed;
|
||||
Bits last[2];
|
||||
const char * name;
|
||||
bool enabled;
|
||||
MixerChannel * next;
|
||||
};
|
||||
|
||||
MixerChannel * MIXER_AddChannel(MIXER_Handler handler,Bitu freq,const char * name);
|
||||
MixerChannel * MIXER_FindChannel(const char * name);
|
||||
/* Find the device you want to delete with findchannel "delchan gets deleted" */
|
||||
void MIXER_DelChannel(MixerChannel* delchan);
|
||||
|
||||
/* Object to maintain a mixerchannel; As all objects it registers itself with create
|
||||
* and removes itself when destroyed. */
|
||||
class MixerObject{
|
||||
private:
|
||||
bool installed;
|
||||
char m_name[32];
|
||||
public:
|
||||
MixerObject():installed(false){};
|
||||
MixerChannel* Install(MIXER_Handler handler,Bitu freq,const char * name);
|
||||
~MixerObject();
|
||||
};
|
||||
|
||||
|
||||
/* PC Speakers functions, tightly related to the timer functions */
|
||||
void PCSPEAKER_SetCounter(Bitu cntr,Bitu mode);
|
||||
void PCSPEAKER_SetType(Bitu mode);
|
||||
|
||||
#endif
|
180
include/modules.h
Normal file
180
include/modules.h
Normal file
@ -0,0 +1,180 @@
|
||||
/* Standard data types used */
|
||||
|
||||
typedef unsigned char Bit8u;
|
||||
typedef signed char Bit8s;
|
||||
typedef unsigned short Bit16u;
|
||||
typedef signed short Bit16s;
|
||||
typedef unsigned long Bit32u;
|
||||
typedef signed long Bit32s;
|
||||
#if defined(_MSC_VER)
|
||||
typedef unsigned __int64 Bit64u;
|
||||
typedef signed __int64 Bit64s;
|
||||
#else
|
||||
typedef unsigned long long int Bit64u;
|
||||
typedef signed long long int Bit64s;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Setting up pointers to all subfunctions */
|
||||
#ifdef MODULE_WANT_IO_READ
|
||||
typedef Bit8u (* IO_ReadHandler)(Bit32u port);
|
||||
static void (* IO_RegisterReadHandler)(Bit32u port,IO_ReadHandler handler,char * name);
|
||||
static void (* IO_FreeReadHandler)(Bit32u port);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_IO_WRITE
|
||||
typedef void (* IO_WriteHandler)(Bit32u port,Bit8u value);
|
||||
static void (* IO_RegisterWriteHandler)(Bit32u port,IO_WriteHandler handler,char * name);
|
||||
static void (* IO_FreeWriteHandler)(Bit32u port);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_IRQ_EOI
|
||||
typedef void (* IRQ_EOIHandler)(void);
|
||||
static void (* IRQ_RegisterEOIHandler)(Bit32u irq,IRQ_EOIHandler handler,char * name);
|
||||
static void (* IRQ_FreeEOIHandler)(Bit32u irq);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_IRQ
|
||||
static void (* IRQ_Activate)(Bit32u irq);
|
||||
static void (* IRQ_Deactivate)(Bit32u irq);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_TIMER
|
||||
typedef void (* TIMER_MicroHandler)(void);
|
||||
static void (* TIMER_RegisterMicroHandler)(TIMER_MicroHandler handler,Bit32u micro);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_TIMER_TICK
|
||||
typedef void (* TIMER_TickHandler)(Bit32u ticks);
|
||||
static void (* TIMER_RegisterTickHandler)(TIMER_TickHandler handler);
|
||||
#endif
|
||||
|
||||
/*
|
||||
4 8-bit and 4 16-bit channels you can read data from
|
||||
16-bit reads are word sized
|
||||
*/
|
||||
|
||||
#ifdef MODULE_WANT_DMA_READ
|
||||
static void (* DMA_8_Read)(Bit32u chan,Bit8u * data,Bit16u size);
|
||||
static void (* DMA_16_Read)(Bit32u chan,Bit8u * data,Bit16u size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
4 8-bit and 4 16-bit channels you can write data from
|
||||
16-bit writes are word sized
|
||||
*/
|
||||
|
||||
#ifdef MODULE_WANT_DMA_READ
|
||||
static void (* DMA_8_Write)(Bit32u chan,Bit8u * data,Bit16u size);
|
||||
static void (* DMA_16_Write)(Bit32u chan,Bit8u * data,Bit16u size);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MODULE_WANT_MIXER
|
||||
/* The len here means the amount of samples needed not the buffersize it needed to fill */
|
||||
typedef void (* MIXER_MixHandler)(Bit8u * sampdate,Bit32u len);
|
||||
|
||||
/* Different types if modes a mixer channel can work in */
|
||||
#define MIXER_8MONO 0
|
||||
#define MIXER_8STEREO 1
|
||||
#define MIXER_16MONO 2
|
||||
#define MIXER_16STEREO 3
|
||||
struct MIXER_Channel;
|
||||
|
||||
#define MAX_AUDIO ((1<<(16-1))-1)
|
||||
#define MIN_AUDIO -(1<<(16-1))
|
||||
|
||||
MIXER_Channel *(* MIXER_AddChannel)(MIXER_MixHandler handler,Bit32u freq,char * name);
|
||||
void (* MIXER_SetVolume)(MIXER_Channel * chan,Bit8u vol);
|
||||
void (* MIXER_SetFreq)(MIXER_Channel * chan,Bit32u freq);
|
||||
void (* MIXER_SetMode)(MIXER_Channel * chan,Bit8u mode);
|
||||
void (* MIXER_Enable)(MIXER_Channel * chan,bool enable);
|
||||
#endif
|
||||
|
||||
typedef bool (* MODULE_FindHandler)(char * name,void * * function);
|
||||
typedef char *(* MODULE_StartHandler)(MODULE_FindHandler find_handler);
|
||||
|
||||
#define MODULE_START_PROC "ModuleStart"
|
||||
|
||||
#ifdef MODULE_START_FUNCTION
|
||||
#include <stdio.h>
|
||||
|
||||
#define GET_FUNCTION(a) \
|
||||
if (!find_handler(#a ,(void * *) &a)) { \
|
||||
return "Can't find requested function"; \
|
||||
};
|
||||
|
||||
|
||||
#if defined (WIN32)
|
||||
#include <windows.h>
|
||||
BOOL APIENTRY DllMain( HANDLE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
char * ModuleStart (MODULE_FindHandler find_handler) {
|
||||
|
||||
#ifdef MODULE_WANT_IRQ_EOI
|
||||
GET_FUNCTION(IRQ_RegisterEOIHandler);
|
||||
GET_FUNCTION(IRQ_FreeEOIHandler);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_IRQ
|
||||
GET_FUNCTION(IRQ_Activate);
|
||||
GET_FUNCTION(IRQ_Deactivate);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_IO_READ
|
||||
GET_FUNCTION(IO_RegisterReadHandler);
|
||||
GET_FUNCTION(IO_FreeReadHandler);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_IO_WRITE
|
||||
GET_FUNCTION(IO_RegisterWriteHandler);
|
||||
GET_FUNCTION(IO_FreeWriteHandler);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_TIMER
|
||||
GET_FUNCTION(TIMER_RegisterMicroHandler);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_TIMER_TICKS
|
||||
GET_FUNCTION(TIMER_RegisterTickHandler);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_DMA_READ
|
||||
GET_FUNCTION(DMA_8_Read);
|
||||
GET_FUNCTION(DMA_16_Read);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_DMA_WRITE
|
||||
GET_FUNCTION(DMA_8_Write);
|
||||
GET_FUNCTION(DMA_16_Write);
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_WANT_MIXER
|
||||
GET_FUNCTION(MIXER_AddChannel);
|
||||
GET_FUNCTION(MIXER_SetVolume);
|
||||
GET_FUNCTION(MIXER_SetFreq);
|
||||
GET_FUNCTION(MIXER_SetMode);
|
||||
GET_FUNCTION(MIXER_Enable);
|
||||
#endif
|
||||
|
||||
return MODULE_START_FUNCTION;
|
||||
|
||||
}
|
||||
#if defined (WIN32)
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
42
include/mouse.h
Normal file
42
include/mouse.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: mouse.h,v 1.14 2008/03/08 22:04:44 c2woody Exp $ */
|
||||
|
||||
|
||||
#ifndef DOSBOX_MOUSE_H
|
||||
#define DOSBOX_MOUSE_H
|
||||
|
||||
|
||||
void Mouse_ShowCursor(void);
|
||||
void Mouse_HideCursor(void);
|
||||
|
||||
bool Mouse_SetPS2State(bool use);
|
||||
|
||||
void Mouse_ChangePS2Callback(Bit16u pseg, Bit16u pofs);
|
||||
|
||||
|
||||
void Mouse_CursorMoved(float xrel,float yrel,float x,float y,bool emulate);
|
||||
void Mouse_CursorSet(float x,float y);
|
||||
void Mouse_ButtonPressed(Bit8u button);
|
||||
void Mouse_ButtonReleased(Bit8u button);
|
||||
|
||||
void Mouse_AutoLock(bool enable);
|
||||
void Mouse_NewVideoMode(void);
|
||||
|
||||
#endif
|
366
include/paging.h
Normal file
366
include/paging.h
Normal file
@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: paging.h,v 1.32 2009/04/25 16:25:03 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_PAGING_H
|
||||
#define DOSBOX_PAGING_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
// disable this to reduce the size of the TLB
|
||||
// NOTE: does not work with the dynamic core (dynrec is fine)
|
||||
#define USE_FULL_TLB
|
||||
|
||||
class PageDirectory;
|
||||
|
||||
#define MEM_PAGE_SIZE (4096)
|
||||
#define XMS_START (0x110)
|
||||
|
||||
#if defined(USE_FULL_TLB)
|
||||
#define TLB_SIZE (1024*1024)
|
||||
#else
|
||||
#define TLB_SIZE 65536 // This must a power of 2 and greater then LINK_START
|
||||
#define BANK_SHIFT 28
|
||||
#define BANK_MASK 0xffff // always the same as TLB_SIZE-1?
|
||||
#define TLB_BANKS ((1024*1024/TLB_SIZE)-1)
|
||||
#endif
|
||||
|
||||
#define PFLAG_READABLE 0x1
|
||||
#define PFLAG_WRITEABLE 0x2
|
||||
#define PFLAG_HASROM 0x4
|
||||
#define PFLAG_HASCODE 0x8 //Page contains dynamic code
|
||||
#define PFLAG_NOCODE 0x10 //No dynamic code can be generated here
|
||||
#define PFLAG_INIT 0x20 //No dynamic code can be generated here
|
||||
|
||||
#define LINK_START ((1024+64)/4) //Start right after the HMA
|
||||
|
||||
//Allow 128 mb of memory to be linked
|
||||
#define PAGING_LINKS (128*1024/4)
|
||||
|
||||
class PageHandler {
|
||||
public:
|
||||
virtual ~PageHandler(void) { }
|
||||
virtual Bitu readb(PhysPt addr);
|
||||
virtual Bitu readw(PhysPt addr);
|
||||
virtual Bitu readd(PhysPt addr);
|
||||
virtual void writeb(PhysPt addr,Bitu val);
|
||||
virtual void writew(PhysPt addr,Bitu val);
|
||||
virtual void writed(PhysPt addr,Bitu val);
|
||||
virtual HostPt GetHostReadPt(Bitu phys_page);
|
||||
virtual HostPt GetHostWritePt(Bitu phys_page);
|
||||
virtual bool readb_checked(PhysPt addr,Bit8u * val);
|
||||
virtual bool readw_checked(PhysPt addr,Bit16u * val);
|
||||
virtual bool readd_checked(PhysPt addr,Bit32u * val);
|
||||
virtual bool writeb_checked(PhysPt addr,Bitu val);
|
||||
virtual bool writew_checked(PhysPt addr,Bitu val);
|
||||
virtual bool writed_checked(PhysPt addr,Bitu val);
|
||||
Bitu flags;
|
||||
};
|
||||
|
||||
/* Some other functions */
|
||||
void PAGING_Enable(bool enabled);
|
||||
bool PAGING_Enabled(void);
|
||||
|
||||
Bitu PAGING_GetDirBase(void);
|
||||
void PAGING_SetDirBase(Bitu cr3);
|
||||
void PAGING_InitTLB(void);
|
||||
void PAGING_ClearTLB(void);
|
||||
|
||||
void PAGING_LinkPage(Bitu lin_page,Bitu phys_page);
|
||||
void PAGING_LinkPage_ReadOnly(Bitu lin_page,Bitu phys_page);
|
||||
void PAGING_UnlinkPages(Bitu lin_page,Bitu pages);
|
||||
/* This maps the page directly, only use when paging is disabled */
|
||||
void PAGING_MapPage(Bitu lin_page,Bitu phys_page);
|
||||
bool PAGING_MakePhysPage(Bitu & page);
|
||||
bool PAGING_ForcePageInit(Bitu lin_addr);
|
||||
|
||||
void MEM_SetLFB(Bitu page, Bitu pages, PageHandler *handler, PageHandler *mmiohandler);
|
||||
void MEM_SetPageHandler(Bitu phys_page, Bitu pages, PageHandler * handler);
|
||||
void MEM_ResetPageHandler(Bitu phys_page, Bitu pages);
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack (1)
|
||||
#endif
|
||||
struct X86_PageEntryBlock{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
Bit32u base:20;
|
||||
Bit32u avl:3;
|
||||
Bit32u g:1;
|
||||
Bit32u pat:1;
|
||||
Bit32u d:1;
|
||||
Bit32u a:1;
|
||||
Bit32u pcd:1;
|
||||
Bit32u pwt:1;
|
||||
Bit32u us:1;
|
||||
Bit32u wr:1;
|
||||
Bit32u p:1;
|
||||
#else
|
||||
Bit32u p:1;
|
||||
Bit32u wr:1;
|
||||
Bit32u us:1;
|
||||
Bit32u pwt:1;
|
||||
Bit32u pcd:1;
|
||||
Bit32u a:1;
|
||||
Bit32u d:1;
|
||||
Bit32u pat:1;
|
||||
Bit32u g:1;
|
||||
Bit32u avl:3;
|
||||
Bit32u base:20;
|
||||
#endif
|
||||
} GCC_ATTRIBUTE(packed);
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack ()
|
||||
#endif
|
||||
|
||||
|
||||
union X86PageEntry {
|
||||
Bit32u load;
|
||||
X86_PageEntryBlock block;
|
||||
};
|
||||
|
||||
#if !defined(USE_FULL_TLB)
|
||||
typedef struct {
|
||||
HostPt read;
|
||||
HostPt write;
|
||||
PageHandler * readhandler;
|
||||
PageHandler * writehandler;
|
||||
Bit32u phys_page;
|
||||
} tlb_entry;
|
||||
#endif
|
||||
|
||||
struct PagingBlock {
|
||||
Bitu cr3;
|
||||
Bitu cr2;
|
||||
struct {
|
||||
Bitu page;
|
||||
PhysPt addr;
|
||||
} base;
|
||||
#if defined(USE_FULL_TLB)
|
||||
struct {
|
||||
HostPt read[TLB_SIZE];
|
||||
HostPt write[TLB_SIZE];
|
||||
PageHandler * readhandler[TLB_SIZE];
|
||||
PageHandler * writehandler[TLB_SIZE];
|
||||
Bit32u phys_page[TLB_SIZE];
|
||||
} tlb;
|
||||
#else
|
||||
tlb_entry tlbh[TLB_SIZE];
|
||||
tlb_entry *tlbh_banks[TLB_BANKS];
|
||||
#endif
|
||||
struct {
|
||||
Bitu used;
|
||||
Bit32u entries[PAGING_LINKS];
|
||||
} links;
|
||||
Bit32u firstmb[LINK_START];
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
extern PagingBlock paging;
|
||||
|
||||
/* Some support functions */
|
||||
|
||||
PageHandler * MEM_GetPageHandler(Bitu phys_page);
|
||||
|
||||
|
||||
/* Unaligned address handlers */
|
||||
Bit16u mem_unalignedreadw(PhysPt address);
|
||||
Bit32u mem_unalignedreadd(PhysPt address);
|
||||
void mem_unalignedwritew(PhysPt address,Bit16u val);
|
||||
void mem_unalignedwrited(PhysPt address,Bit32u val);
|
||||
|
||||
bool mem_unalignedreadw_checked(PhysPt address,Bit16u * val);
|
||||
bool mem_unalignedreadd_checked(PhysPt address,Bit32u * val);
|
||||
bool mem_unalignedwritew_checked(PhysPt address,Bit16u val);
|
||||
bool mem_unalignedwrited_checked(PhysPt address,Bit32u val);
|
||||
|
||||
#if defined(USE_FULL_TLB)
|
||||
|
||||
static INLINE HostPt get_tlb_read(PhysPt address) {
|
||||
return paging.tlb.read[address>>12];
|
||||
}
|
||||
static INLINE HostPt get_tlb_write(PhysPt address) {
|
||||
return paging.tlb.write[address>>12];
|
||||
}
|
||||
static INLINE PageHandler* get_tlb_readhandler(PhysPt address) {
|
||||
return paging.tlb.readhandler[address>>12];
|
||||
}
|
||||
static INLINE PageHandler* get_tlb_writehandler(PhysPt address) {
|
||||
return paging.tlb.writehandler[address>>12];
|
||||
}
|
||||
|
||||
/* Use these helper functions to access linear addresses in readX/writeX functions */
|
||||
static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
|
||||
return (paging.tlb.phys_page[linePage>>12]<<12);
|
||||
}
|
||||
|
||||
static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
|
||||
return (paging.tlb.phys_page[linAddr>>12]<<12)|(linAddr&0xfff);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void PAGING_InitTLBBank(tlb_entry **bank);
|
||||
|
||||
static INLINE tlb_entry *get_tlb_entry(PhysPt address) {
|
||||
Bitu index=(address>>12);
|
||||
if (TLB_BANKS && (index > TLB_SIZE)) {
|
||||
Bitu bank=(address>>BANK_SHIFT) - 1;
|
||||
if (!paging.tlbh_banks[bank])
|
||||
PAGING_InitTLBBank(&paging.tlbh_banks[bank]);
|
||||
return &paging.tlbh_banks[bank][index & BANK_MASK];
|
||||
}
|
||||
return &paging.tlbh[index];
|
||||
}
|
||||
|
||||
static INLINE HostPt get_tlb_read(PhysPt address) {
|
||||
return get_tlb_entry(address)->read;
|
||||
}
|
||||
static INLINE HostPt get_tlb_write(PhysPt address) {
|
||||
return get_tlb_entry(address)->write;
|
||||
}
|
||||
static INLINE PageHandler* get_tlb_readhandler(PhysPt address) {
|
||||
return get_tlb_entry(address)->readhandler;
|
||||
}
|
||||
static INLINE PageHandler* get_tlb_writehandler(PhysPt address) {
|
||||
return get_tlb_entry(address)->writehandler;
|
||||
}
|
||||
|
||||
/* Use these helper functions to access linear addresses in readX/writeX functions */
|
||||
static INLINE PhysPt PAGING_GetPhysicalPage(PhysPt linePage) {
|
||||
tlb_entry *entry = get_tlb_entry(linePage);
|
||||
return (entry->phys_page<<12);
|
||||
}
|
||||
|
||||
static INLINE PhysPt PAGING_GetPhysicalAddress(PhysPt linAddr) {
|
||||
tlb_entry *entry = get_tlb_entry(linAddr);
|
||||
return (entry->phys_page<<12)|(linAddr&0xfff);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Special inlined memory reading/writing */
|
||||
|
||||
static INLINE Bit8u mem_readb_inline(PhysPt address) {
|
||||
HostPt tlb_addr=get_tlb_read(address);
|
||||
if (tlb_addr) return host_readb(tlb_addr+address);
|
||||
else return (Bit8u)(get_tlb_readhandler(address))->readb(address);
|
||||
}
|
||||
|
||||
static INLINE Bit16u mem_readw_inline(PhysPt address) {
|
||||
if ((address & 0xfff)<0xfff) {
|
||||
HostPt tlb_addr=get_tlb_read(address);
|
||||
if (tlb_addr) return host_readw(tlb_addr+address);
|
||||
else return (Bit16u)(get_tlb_readhandler(address))->readw(address);
|
||||
} else return mem_unalignedreadw(address);
|
||||
}
|
||||
|
||||
static INLINE Bit32u mem_readd_inline(PhysPt address) {
|
||||
if ((address & 0xfff)<0xffd) {
|
||||
HostPt tlb_addr=get_tlb_read(address);
|
||||
if (tlb_addr) return host_readd(tlb_addr+address);
|
||||
else return (get_tlb_readhandler(address))->readd(address);
|
||||
} else return mem_unalignedreadd(address);
|
||||
}
|
||||
|
||||
static INLINE void mem_writeb_inline(PhysPt address,Bit8u val) {
|
||||
HostPt tlb_addr=get_tlb_write(address);
|
||||
if (tlb_addr) host_writeb(tlb_addr+address,val);
|
||||
else (get_tlb_writehandler(address))->writeb(address,val);
|
||||
}
|
||||
|
||||
static INLINE void mem_writew_inline(PhysPt address,Bit16u val) {
|
||||
if ((address & 0xfff)<0xfff) {
|
||||
HostPt tlb_addr=get_tlb_write(address);
|
||||
if (tlb_addr) host_writew(tlb_addr+address,val);
|
||||
else (get_tlb_writehandler(address))->writew(address,val);
|
||||
} else mem_unalignedwritew(address,val);
|
||||
}
|
||||
|
||||
static INLINE void mem_writed_inline(PhysPt address,Bit32u val) {
|
||||
if ((address & 0xfff)<0xffd) {
|
||||
HostPt tlb_addr=get_tlb_write(address);
|
||||
if (tlb_addr) host_writed(tlb_addr+address,val);
|
||||
else (get_tlb_writehandler(address))->writed(address,val);
|
||||
} else mem_unalignedwrited(address,val);
|
||||
}
|
||||
|
||||
|
||||
static INLINE bool mem_readb_checked(PhysPt address, Bit8u * val) {
|
||||
HostPt tlb_addr=get_tlb_read(address);
|
||||
if (tlb_addr) {
|
||||
*val=host_readb(tlb_addr+address);
|
||||
return false;
|
||||
} else return (get_tlb_readhandler(address))->readb_checked(address, val);
|
||||
}
|
||||
|
||||
static INLINE bool mem_readw_checked(PhysPt address, Bit16u * val) {
|
||||
if ((address & 0xfff)<0xfff) {
|
||||
HostPt tlb_addr=get_tlb_read(address);
|
||||
if (tlb_addr) {
|
||||
*val=host_readw(tlb_addr+address);
|
||||
return false;
|
||||
} else return (get_tlb_readhandler(address))->readw_checked(address, val);
|
||||
} else return mem_unalignedreadw_checked(address, val);
|
||||
}
|
||||
|
||||
static INLINE bool mem_readd_checked(PhysPt address, Bit32u * val) {
|
||||
if ((address & 0xfff)<0xffd) {
|
||||
HostPt tlb_addr=get_tlb_read(address);
|
||||
if (tlb_addr) {
|
||||
*val=host_readd(tlb_addr+address);
|
||||
return false;
|
||||
} else return (get_tlb_readhandler(address))->readd_checked(address, val);
|
||||
} else return mem_unalignedreadd_checked(address, val);
|
||||
}
|
||||
|
||||
static INLINE bool mem_writeb_checked(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);
|
||||
}
|
||||
|
||||
static INLINE bool mem_writew_checked(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);
|
||||
}
|
||||
|
||||
static INLINE bool mem_writed_checked(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);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
67
include/pic.h
Normal file
67
include/pic.h
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_PIC_H
|
||||
#define DOSBOX_PIC_H
|
||||
|
||||
|
||||
/* CPU Cycle Timing */
|
||||
extern Bit32s CPU_Cycles;
|
||||
extern Bit32s CPU_CycleLeft;
|
||||
extern Bit32s CPU_CycleMax;
|
||||
|
||||
typedef void (PIC_EOIHandler) (void);
|
||||
typedef void (* PIC_EventHandler)(Bitu val);
|
||||
|
||||
|
||||
#define PIC_MAXIRQ 15
|
||||
#define PIC_NOIRQ 0xFF
|
||||
|
||||
extern Bitu PIC_IRQCheck;
|
||||
extern Bitu PIC_IRQActive;
|
||||
extern Bitu PIC_Ticks;
|
||||
|
||||
static INLINE float PIC_TickIndex(void) {
|
||||
return (CPU_CycleMax-CPU_CycleLeft-CPU_Cycles)/(float)CPU_CycleMax;
|
||||
}
|
||||
|
||||
static INLINE Bits PIC_TickIndexND(void) {
|
||||
return CPU_CycleMax-CPU_CycleLeft-CPU_Cycles;
|
||||
}
|
||||
|
||||
static INLINE Bits PIC_MakeCycles(double amount) {
|
||||
return (Bits)(CPU_CycleMax*amount);
|
||||
}
|
||||
|
||||
static INLINE double PIC_FullIndex(void) {
|
||||
return PIC_Ticks+(double)PIC_TickIndex();
|
||||
}
|
||||
|
||||
void PIC_ActivateIRQ(Bitu irq);
|
||||
void PIC_DeActivateIRQ(Bitu irq);
|
||||
|
||||
void PIC_runIRQs(void);
|
||||
bool PIC_RunQueue(void);
|
||||
|
||||
//Delay in milliseconds
|
||||
void PIC_AddEvent(PIC_EventHandler handler,float delay,Bitu val=0);
|
||||
void PIC_RemoveEvents(PIC_EventHandler handler);
|
||||
void PIC_RemoveSpecificEvents(PIC_EventHandler handler, Bitu val);
|
||||
|
||||
void PIC_SetIRQMask(Bitu irq, bool masked);
|
||||
#endif
|
90
include/programs.h
Normal file
90
include/programs.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: programs.h,v 1.18 2009/03/11 20:18:37 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_PROGRAMS_H
|
||||
#define DOSBOX_PROGRAMS_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_DOS_INC_H
|
||||
#include "dos_inc.h"
|
||||
#endif
|
||||
|
||||
#ifndef CH_LIST
|
||||
#define CH_LIST
|
||||
#include <list>
|
||||
#endif
|
||||
|
||||
#ifndef CH_STRING
|
||||
#define CH_STRING
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
class CommandLine {
|
||||
public:
|
||||
CommandLine(int argc,char const * const argv[]);
|
||||
CommandLine(char const * const name,char const * const cmdline);
|
||||
const char * GetFileName(){ return file_name.c_str();}
|
||||
|
||||
bool FindExist(char const * const name,bool remove=false);
|
||||
bool FindHex(char const * const name,int & value,bool remove=false);
|
||||
bool FindInt(char const * const name,int & value,bool remove=false);
|
||||
bool FindString(char const * const name,std::string & value,bool remove=false);
|
||||
bool FindCommand(unsigned int which,std::string & value);
|
||||
bool FindStringBegin(char const * const begin,std::string & value, bool remove=false);
|
||||
bool FindStringRemain(char const * const name,std::string & value);
|
||||
bool GetStringRemain(std::string & value);
|
||||
unsigned int GetCount(void);
|
||||
void Shift(unsigned int amount=1);
|
||||
Bit16u Get_arglength();
|
||||
|
||||
private:
|
||||
typedef std::list<std::string>::iterator cmd_it;
|
||||
std::list<std::string> cmds;
|
||||
std::string file_name;
|
||||
bool FindEntry(char const * const name,cmd_it & it,bool neednext=false);
|
||||
};
|
||||
|
||||
class Program {
|
||||
public:
|
||||
Program();
|
||||
virtual ~Program(){
|
||||
delete cmd;
|
||||
delete psp;
|
||||
}
|
||||
std::string temp_line;
|
||||
CommandLine * cmd;
|
||||
DOS_PSP * psp;
|
||||
virtual void Run(void)=0;
|
||||
bool GetEnvStr(const char * entry,std::string & result);
|
||||
bool GetEnvNum(Bitu num,std::string & result);
|
||||
Bitu GetEnvCount(void);
|
||||
bool SetEnv(const char * entry,const char * new_string);
|
||||
void WriteOut(const char * format,...); /* Write to standard output */
|
||||
void WriteOut_NoParsing(const char * format); /* Write to standard output, no parsing */
|
||||
void ChangeToLongCmd();
|
||||
|
||||
};
|
||||
|
||||
typedef void (PROGRAMS_Main)(Program * * make);
|
||||
void PROGRAMS_MakeFile(char const * const name,PROGRAMS_Main * main);
|
||||
|
||||
#endif
|
169
include/regs.h
Normal file
169
include/regs.h
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_REGS_H
|
||||
#define DOSBOX_REGS_H
|
||||
|
||||
#ifndef DOSBOX_MEM_H
|
||||
#include "mem.h"
|
||||
#endif
|
||||
|
||||
#define FLAG_CF 0x00000001
|
||||
#define FLAG_PF 0x00000004
|
||||
#define FLAG_AF 0x00000010
|
||||
#define FLAG_ZF 0x00000040
|
||||
#define FLAG_SF 0x00000080
|
||||
#define FLAG_OF 0x00000800
|
||||
|
||||
#define FLAG_TF 0x00000100
|
||||
#define FLAG_IF 0x00000200
|
||||
#define FLAG_DF 0x00000400
|
||||
|
||||
#define FLAG_IOPL 0x00003000
|
||||
#define FLAG_NT 0x00004000
|
||||
#define FLAG_VM 0x00020000
|
||||
#define FLAG_AC 0x00040000
|
||||
#define FLAG_ID 0x00200000
|
||||
|
||||
#define FMASK_TEST (FLAG_CF | FLAG_PF | FLAG_AF | FLAG_ZF | FLAG_SF | FLAG_OF)
|
||||
#define FMASK_NORMAL (FMASK_TEST | FLAG_DF | FLAG_TF | FLAG_IF | FLAG_AC )
|
||||
#define FMASK_ALL (FMASK_NORMAL | FLAG_IOPL | FLAG_NT)
|
||||
|
||||
#define SETFLAGBIT(TYPE,TEST) if (TEST) reg_flags|=FLAG_ ## TYPE; else reg_flags&=~FLAG_ ## TYPE
|
||||
|
||||
#define GETFLAG(TYPE) (reg_flags & FLAG_ ## TYPE)
|
||||
#define GETFLAGBOOL(TYPE) ((reg_flags & FLAG_ ## TYPE) ? true : false )
|
||||
|
||||
#define GETFLAG_IOPL ((reg_flags & FLAG_IOPL) >> 12)
|
||||
|
||||
struct Segment {
|
||||
Bit16u val;
|
||||
PhysPt phys; /* The phyiscal address start in emulated machine */
|
||||
};
|
||||
|
||||
enum SegNames { es=0,cs,ss,ds,fs,gs};
|
||||
|
||||
struct Segments {
|
||||
Bitu val[8];
|
||||
PhysPt phys[8];
|
||||
};
|
||||
|
||||
union GenReg32 {
|
||||
Bit32u dword[1];
|
||||
Bit16u word[2];
|
||||
Bit8u byte[4];
|
||||
};
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
#define DW_INDEX 0
|
||||
#define W_INDEX 1
|
||||
#define BH_INDEX 2
|
||||
#define BL_INDEX 3
|
||||
|
||||
#else
|
||||
|
||||
#define DW_INDEX 0
|
||||
#define W_INDEX 0
|
||||
#define BH_INDEX 1
|
||||
#define BL_INDEX 0
|
||||
|
||||
#endif
|
||||
|
||||
struct CPU_Regs {
|
||||
GenReg32 regs[8],ip;
|
||||
Bitu flags;
|
||||
};
|
||||
|
||||
extern Segments Segs;
|
||||
extern CPU_Regs cpu_regs;
|
||||
|
||||
static INLINE PhysPt SegPhys(SegNames index) {
|
||||
return Segs.phys[index];
|
||||
}
|
||||
|
||||
static INLINE Bit16u SegValue(SegNames index) {
|
||||
return (Bit16u)Segs.val[index];
|
||||
}
|
||||
|
||||
static INLINE RealPt RealMakeSeg(SegNames index,Bit16u off) {
|
||||
return RealMake(SegValue(index),off);
|
||||
}
|
||||
|
||||
|
||||
static INLINE void SegSet16(Bitu index,Bit16u val) {
|
||||
Segs.val[index]=val;
|
||||
Segs.phys[index]=val << 4;
|
||||
}
|
||||
|
||||
enum {
|
||||
REGI_AX, REGI_CX, REGI_DX, REGI_BX,
|
||||
REGI_SP, REGI_BP, REGI_SI, REGI_DI
|
||||
};
|
||||
|
||||
enum {
|
||||
REGI_AL, REGI_CL, REGI_DL, REGI_BL,
|
||||
REGI_AH, REGI_CH, REGI_DH, REGI_BH
|
||||
};
|
||||
|
||||
|
||||
//macros to convert a 3-bit register index to the correct register
|
||||
#define reg_8l(reg) (cpu_regs.regs[(reg)].byte[BL_INDEX])
|
||||
#define reg_8h(reg) (cpu_regs.regs[(reg)].byte[BH_INDEX])
|
||||
#define reg_8(reg) ((reg) & 4 ? reg_8h((reg) & 3) : reg_8l((reg) & 3))
|
||||
#define reg_16(reg) (cpu_regs.regs[(reg)].word[W_INDEX])
|
||||
#define reg_32(reg) (cpu_regs.regs[(reg)].dword[DW_INDEX])
|
||||
|
||||
#define reg_al cpu_regs.regs[REGI_AX].byte[BL_INDEX]
|
||||
#define reg_ah cpu_regs.regs[REGI_AX].byte[BH_INDEX]
|
||||
#define reg_ax cpu_regs.regs[REGI_AX].word[W_INDEX]
|
||||
#define reg_eax cpu_regs.regs[REGI_AX].dword[DW_INDEX]
|
||||
|
||||
#define reg_bl cpu_regs.regs[REGI_BX].byte[BL_INDEX]
|
||||
#define reg_bh cpu_regs.regs[REGI_BX].byte[BH_INDEX]
|
||||
#define reg_bx cpu_regs.regs[REGI_BX].word[W_INDEX]
|
||||
#define reg_ebx cpu_regs.regs[REGI_BX].dword[DW_INDEX]
|
||||
|
||||
#define reg_cl cpu_regs.regs[REGI_CX].byte[BL_INDEX]
|
||||
#define reg_ch cpu_regs.regs[REGI_CX].byte[BH_INDEX]
|
||||
#define reg_cx cpu_regs.regs[REGI_CX].word[W_INDEX]
|
||||
#define reg_ecx cpu_regs.regs[REGI_CX].dword[DW_INDEX]
|
||||
|
||||
#define reg_dl cpu_regs.regs[REGI_DX].byte[BL_INDEX]
|
||||
#define reg_dh cpu_regs.regs[REGI_DX].byte[BH_INDEX]
|
||||
#define reg_dx cpu_regs.regs[REGI_DX].word[W_INDEX]
|
||||
#define reg_edx cpu_regs.regs[REGI_DX].dword[DW_INDEX]
|
||||
|
||||
#define reg_si cpu_regs.regs[REGI_SI].word[W_INDEX]
|
||||
#define reg_esi cpu_regs.regs[REGI_SI].dword[DW_INDEX]
|
||||
|
||||
#define reg_di cpu_regs.regs[REGI_DI].word[W_INDEX]
|
||||
#define reg_edi cpu_regs.regs[REGI_DI].dword[DW_INDEX]
|
||||
|
||||
#define reg_sp cpu_regs.regs[REGI_SP].word[W_INDEX]
|
||||
#define reg_esp cpu_regs.regs[REGI_SP].dword[DW_INDEX]
|
||||
|
||||
#define reg_bp cpu_regs.regs[REGI_BP].word[W_INDEX]
|
||||
#define reg_ebp cpu_regs.regs[REGI_BP].dword[DW_INDEX]
|
||||
|
||||
#define reg_ip cpu_regs.ip.word[W_INDEX]
|
||||
#define reg_eip cpu_regs.ip.dword[DW_INDEX]
|
||||
|
||||
#define reg_flags cpu_regs.flags
|
||||
|
||||
#endif
|
98
include/render.h
Normal file
98
include/render.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_RENDER_H
|
||||
#define DOSBOX_RENDER_H
|
||||
|
||||
// 0: complex scalers off, scaler cache off, some simple scalers off, memory requirements reduced
|
||||
// 1: complex scalers off, scaler cache off, all simple scalers on
|
||||
// 2: complex scalers off, scaler cache on
|
||||
// 3: complex scalers on
|
||||
#define RENDER_USE_ADVANCED_SCALERS 3
|
||||
|
||||
#include "../src/gui/render_scalers.h"
|
||||
|
||||
#define RENDER_SKIP_CACHE 16
|
||||
//Enable this for scalers to support 0 input for empty lines
|
||||
//#define RENDER_NULL_INPUT
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
Bit8u red;
|
||||
Bit8u green;
|
||||
Bit8u blue;
|
||||
Bit8u unused;
|
||||
} rgb[256];
|
||||
union {
|
||||
Bit16u b16[256];
|
||||
Bit32u b32[256];
|
||||
} lut;
|
||||
bool changed;
|
||||
Bit8u modified[256];
|
||||
Bitu first;
|
||||
Bitu last;
|
||||
} RenderPal_t;
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
Bitu width, start;
|
||||
Bitu height;
|
||||
Bitu bpp;
|
||||
bool dblw,dblh;
|
||||
double ratio;
|
||||
float fps;
|
||||
} src;
|
||||
struct {
|
||||
Bitu count;
|
||||
Bitu max;
|
||||
Bitu index;
|
||||
Bit8u hadSkip[RENDER_SKIP_CACHE];
|
||||
} frameskip;
|
||||
struct {
|
||||
Bitu size;
|
||||
scalerMode_t inMode;
|
||||
scalerMode_t outMode;
|
||||
scalerOperation_t op;
|
||||
bool clearCache;
|
||||
bool forced;
|
||||
ScalerLineHandler_t lineHandler;
|
||||
ScalerLineHandler_t linePalHandler;
|
||||
ScalerComplexHandler_t complexHandler;
|
||||
Bitu blocks, lastBlock;
|
||||
Bitu outPitch;
|
||||
Bit8u *outWrite;
|
||||
Bitu cachePitch;
|
||||
Bit8u *cacheRead;
|
||||
Bitu inHeight, inLine, outLine;
|
||||
} scale;
|
||||
RenderPal_t pal;
|
||||
bool updating;
|
||||
bool active;
|
||||
bool aspect;
|
||||
bool fullFrame;
|
||||
} Render_t;
|
||||
|
||||
extern Render_t render;
|
||||
extern ScalerLineHandler_t RENDER_DrawLine;
|
||||
void RENDER_SetSize(Bitu width,Bitu height,Bitu bpp,float fps,double ratio,bool dblw,bool dblh);
|
||||
bool RENDER_StartUpdate(void);
|
||||
void RENDER_EndUpdate( );
|
||||
void RENDER_SetPal(Bit8u entry,Bit8u red,Bit8u green,Bit8u blue);
|
||||
|
||||
|
||||
#endif
|
361
include/serialport.h
Normal file
361
include/serialport.h
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* $Id: serialport.h,v 1.16 2009/02/01 14:11:45 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_SERIALPORT_H
|
||||
#define DOSBOX_SERIALPORT_H
|
||||
|
||||
#define SERIAL_DEBUG 0
|
||||
|
||||
// Uncomment this for a lot of debug messages:
|
||||
//#define LOG_UART
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_INOUT_H
|
||||
#include "inout.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_TIMER_H
|
||||
#include "timer.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_DOS_INC_H
|
||||
#include "dos_inc.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_PROGRAMS_H
|
||||
#include "programs.h"
|
||||
#endif
|
||||
|
||||
#if SERIAL_DEBUG
|
||||
#include "hardware.h"
|
||||
#endif
|
||||
|
||||
// Serial port interface
|
||||
|
||||
class CSerial {
|
||||
public:
|
||||
|
||||
#if SERIAL_DEBUG
|
||||
FILE * debugfp;
|
||||
bool dbg_modemcontrol; // RTS,CTS,DTR,DSR,RI,CD
|
||||
bool dbg_serialtraffic;
|
||||
bool dbg_register;
|
||||
bool dbg_interrupt;
|
||||
bool dbg_aux;
|
||||
|
||||
#endif
|
||||
|
||||
static bool getBituSubstring(const char* name,Bitu* data, CommandLine* cmd);
|
||||
|
||||
bool InstallationSuccessful;// check after constructing. If
|
||||
// something was wrong, delete it right away.
|
||||
|
||||
// Constructor takes com port number (0-3)
|
||||
CSerial(Bitu id, CommandLine* cmd);
|
||||
|
||||
virtual ~CSerial();
|
||||
|
||||
IO_ReadHandleObject ReadHandler[8];
|
||||
IO_WriteHandleObject WriteHandler[8];
|
||||
|
||||
float bytetime; // how long a byte takes to transmit/receive in milliseconds
|
||||
void changeLineProperties();
|
||||
Bitu idnumber;
|
||||
|
||||
void setEvent(Bit16u type, float duration);
|
||||
void removeEvent(Bit16u type);
|
||||
void handleEvent(Bit16u type);
|
||||
virtual void handleUpperEvent(Bit16u type)=0;
|
||||
|
||||
// defines for event type
|
||||
#define SERIAL_TX_LOOPBACK_EVENT 0
|
||||
#define SERIAL_THR_LOOPBACK_EVENT 1
|
||||
#define SERIAL_ERRMSG_EVENT 2
|
||||
|
||||
#define SERIAL_TX_EVENT 3
|
||||
#define SERIAL_RX_EVENT 4
|
||||
#define SERIAL_POLLING_EVENT 5
|
||||
#define SERIAL_THR_EVENT 6
|
||||
|
||||
#define SERIAL_BASE_EVENT_COUNT 6
|
||||
|
||||
#define COMNUMBER idnumber+1
|
||||
|
||||
Bitu irq;
|
||||
|
||||
// CSerial requests an update of the input lines
|
||||
virtual void updateMSR()=0;
|
||||
|
||||
// Control lines from prepherial to serial port
|
||||
bool getDTR();
|
||||
bool getRTS();
|
||||
|
||||
bool getRI();
|
||||
bool getCD();
|
||||
bool getDSR();
|
||||
bool getCTS();
|
||||
|
||||
void setRI(bool value);
|
||||
void setDSR(bool value);
|
||||
void setCD(bool value);
|
||||
void setCTS(bool value);
|
||||
|
||||
// From serial port to prepherial
|
||||
// set output lines
|
||||
virtual void setRTSDTR(bool rts, bool dtr)=0;
|
||||
virtual void setRTS(bool val)=0;
|
||||
virtual void setDTR(bool val)=0;
|
||||
|
||||
// Register access
|
||||
void Write_THR(Bit8u data);
|
||||
void Write_IER(Bit8u data);
|
||||
void Write_FCR(Bit8u data);
|
||||
void Write_LCR(Bit8u data);
|
||||
void Write_MCR(Bit8u data);
|
||||
// Really old hardware seems to have the delta part of this register writable
|
||||
void Write_MSR(Bit8u data);
|
||||
void Write_SPR(Bit8u data);
|
||||
void Write_reserved(Bit8u data, Bit8u address);
|
||||
|
||||
Bitu Read_RHR();
|
||||
Bitu Read_IER();
|
||||
Bitu Read_ISR();
|
||||
Bitu Read_LCR();
|
||||
Bitu Read_MCR();
|
||||
Bitu Read_LSR();
|
||||
Bitu Read_MSR();
|
||||
Bitu Read_SPR();
|
||||
|
||||
// If a byte comes from loopback or prepherial, put it in here.
|
||||
void receiveByte(Bit8u data);
|
||||
|
||||
// If an error was received, put it here (in LSR register format)
|
||||
void receiveError(Bit8u errorword);
|
||||
|
||||
// depratched
|
||||
// connected device checks, if port can receive data:
|
||||
bool CanReceiveByte();
|
||||
|
||||
// when THR was shifted to TX
|
||||
void ByteTransmitting();
|
||||
|
||||
// When done sending, notify here
|
||||
void ByteTransmitted();
|
||||
|
||||
// Transmit byte to prepherial
|
||||
virtual void transmitByte(Bit8u val, bool first)=0;
|
||||
|
||||
// switch break state to the passed value
|
||||
virtual void setBreak(bool value)=0;
|
||||
|
||||
// change baudrate, number of bits, parity, word length al at once
|
||||
virtual void updatePortConfig(Bit16u divider, Bit8u lcr)=0;
|
||||
|
||||
void Init_Registers();
|
||||
|
||||
bool Putchar(Bit8u data, bool wait_dtr, bool wait_rts, Bitu timeout);
|
||||
bool Getchar(Bit8u* data, Bit8u* lsr, bool wait_dsr, Bitu timeout);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
DOS_Device* mydosdevice;
|
||||
|
||||
// I used this spec: http://www.exar.com/products/st16c450v420.pdf
|
||||
|
||||
void ComputeInterrupts();
|
||||
|
||||
// a sub-interrupt is triggered
|
||||
void rise(Bit8u priority);
|
||||
|
||||
// clears the pending sub-interrupt
|
||||
void clear(Bit8u priority);
|
||||
|
||||
#define ERROR_PRIORITY 4 // overrun, parity error, frame error, break
|
||||
#define RX_PRIORITY 1 // a byte has been received
|
||||
#define TX_PRIORITY 2 // tx buffer has become empty
|
||||
#define MSR_PRIORITY 8 // CRS, DSR, RI, DCD change
|
||||
#define NONE_PRIORITY 0
|
||||
|
||||
Bit8u waiting_interrupts; // these are on, but maybe not enabled
|
||||
|
||||
// 16C450 (no FIFO)
|
||||
// read/write name
|
||||
|
||||
Bit16u baud_divider;
|
||||
Bit8u RHR; // r Receive Holding Register, also LSB of Divisor Latch (r/w)
|
||||
#define RHR_OFFSET 0
|
||||
// Data: whole byte
|
||||
|
||||
Bit8u THR; // w Transmit Holding Register
|
||||
#define THR_OFFSET 0
|
||||
// Data: whole byte
|
||||
|
||||
Bit8u IER; // r/w Interrupt Enable Register, also MSB of Divisor Latch
|
||||
#define IER_OFFSET 1
|
||||
|
||||
bool irq_active;
|
||||
|
||||
#define RHR_INT_Enable_MASK 0x1
|
||||
#define THR_INT_Enable_MASK 0x2
|
||||
#define Receive_Line_INT_Enable_MASK 0x4
|
||||
#define Modem_Status_INT_Enable_MASK 0x8
|
||||
|
||||
Bit8u ISR; // r Interrupt Status Register
|
||||
#define ISR_OFFSET 2
|
||||
|
||||
#define ISR_CLEAR_VAL 0x1
|
||||
#define ISR_ERROR_VAL 0x6
|
||||
#define ISR_RX_VAL 0x4
|
||||
#define ISR_TX_VAL 0x2
|
||||
#define ISR_MSR_VAL 0x0
|
||||
public:
|
||||
Bit8u LCR; // r/w Line Control Register
|
||||
private:
|
||||
#define LCR_OFFSET 3
|
||||
// bit0: word length bit0
|
||||
// bit1: word length bit1
|
||||
// bit2: stop bits
|
||||
// bit3: parity enable
|
||||
// bit4: even parity
|
||||
// bit5: set parity
|
||||
// bit6: set break
|
||||
// bit7: divisor latch enable
|
||||
|
||||
|
||||
#define LCR_BREAK_MASK 0x40
|
||||
#define LCR_DIVISOR_Enable_MASK 0x80
|
||||
#define LCR_PORTCONFIG_MASK 0x3F
|
||||
|
||||
#define LCR_PARITY_NONE 0x0
|
||||
#define LCR_PARITY_ODD 0x8
|
||||
#define LCR_PARITY_EVEN 0x18
|
||||
#define LCR_PARITY_MARK 0x28
|
||||
#define LCR_PARITY_SPACE 0x38
|
||||
|
||||
#define LCR_DATABITS_5 0x0
|
||||
#define LCR_DATABITS_6 0x1
|
||||
#define LCR_DATABITS_7 0x2
|
||||
#define LCR_DATABITS_8 0x3
|
||||
|
||||
#define LCR_STOPBITS_1 0x0
|
||||
#define LCR_STOPBITS_MORE_THAN_1 0x4
|
||||
|
||||
// Modem Control Register
|
||||
// r/w
|
||||
#define MCR_OFFSET 4
|
||||
bool dtr; // bit0: DTR
|
||||
bool rts; // bit1: RTS
|
||||
bool op1; // bit2: OP1
|
||||
bool op2; // bit3: OP2
|
||||
bool loopback; // bit4: loop back enable
|
||||
|
||||
#define MCR_DTR_MASK 0x1
|
||||
#define MCR_RTS_MASK 0x2
|
||||
#define MCR_OP1_MASK 0x4
|
||||
#define MCR_OP2_MASK 0x8
|
||||
#define MCR_LOOPBACK_Enable_MASK 0x10
|
||||
public:
|
||||
Bit8u LSR; // r Line Status Register
|
||||
private:
|
||||
|
||||
#define LSR_OFFSET 5
|
||||
|
||||
#define LSR_RX_DATA_READY_MASK 0x1
|
||||
#define LSR_OVERRUN_ERROR_MASK 0x2
|
||||
#define LSR_PARITY_ERROR_MASK 0x4
|
||||
#define LSR_FRAMING_ERROR_MASK 0x8
|
||||
#define LSR_RX_BREAK_MASK 0x10
|
||||
#define LSR_TX_HOLDING_EMPTY_MASK 0x20
|
||||
#define LSR_TX_EMPTY_MASK 0x40
|
||||
|
||||
#define LSR_ERROR_MASK 0x1e
|
||||
|
||||
// error printing
|
||||
bool errormsg_pending;
|
||||
Bitu framingErrors;
|
||||
Bitu parityErrors;
|
||||
Bitu overrunErrors;
|
||||
Bitu overrunIF0;
|
||||
Bitu breakErrors;
|
||||
|
||||
|
||||
// Modem Status Register
|
||||
// r
|
||||
#define MSR_OFFSET 6
|
||||
bool d_cts; // bit0: deltaCTS
|
||||
bool d_dsr; // bit1: deltaDSR
|
||||
bool d_ri; // bit2: deltaRI
|
||||
bool d_cd; // bit3: deltaCD
|
||||
bool cts; // bit4: CTS
|
||||
bool dsr; // bit5: DSR
|
||||
bool ri; // bit6: RI
|
||||
bool cd; // bit7: CD
|
||||
|
||||
#define MSR_delta_MASK 0xf
|
||||
#define MSR_LINE_MASK 0xf0
|
||||
|
||||
#define MSR_dCTS_MASK 0x1
|
||||
#define MSR_dDSR_MASK 0x2
|
||||
#define MSR_dRI_MASK 0x4
|
||||
#define MSR_dCD_MASK 0x8
|
||||
#define MSR_CTS_MASK 0x10
|
||||
#define MSR_DSR_MASK 0x20
|
||||
#define MSR_RI_MASK 0x40
|
||||
#define MSR_CD_MASK 0x80
|
||||
|
||||
Bit8u SPR; // r/w Scratchpad Register
|
||||
#define SPR_OFFSET 7
|
||||
|
||||
|
||||
// For loopback purposes...
|
||||
Bit8u loopback_data;
|
||||
void transmitLoopbackByte(Bit8u val, bool value);
|
||||
|
||||
// 16C550 (FIFO)
|
||||
// TODO
|
||||
#define FCR_OFFSET 2
|
||||
bool fifo_warn;
|
||||
//Bit8u FCR; // FIFO Control Register
|
||||
|
||||
};
|
||||
|
||||
extern CSerial* serialports[];
|
||||
const Bit8u serial_defaultirq[4] = { 4, 3, 4, 3 };
|
||||
const Bit16u serial_baseaddr[4] = {0x3f8,0x2f8,0x3e8,0x2e8};
|
||||
const char* const serial_comname[]={"COM1","COM2","COM3","COM4"};
|
||||
|
||||
// the COM devices
|
||||
|
||||
class device_COM : public DOS_Device {
|
||||
public:
|
||||
// Creates a COM device that communicates with the num-th parallel port, i.e. is LPTnum
|
||||
device_COM(class CSerial* sc);
|
||||
~device_COM();
|
||||
bool Read(Bit8u * data,Bit16u * size);
|
||||
bool Write(Bit8u * data,Bit16u * size);
|
||||
bool Seek(Bit32u * pos,Bit32u type);
|
||||
bool Close();
|
||||
Bit16u GetInformation(void);
|
||||
private:
|
||||
CSerial* sclass;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
331
include/setup.h
Normal file
331
include/setup.h
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: setup.h,v 1.40 2009/02/15 20:01:08 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_SETUP_H
|
||||
#define DOSBOX_SETUP_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning ( disable : 4786 )
|
||||
#pragma warning ( disable : 4290 )
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef CH_LIST
|
||||
#define CH_LIST
|
||||
#include <list>
|
||||
#endif
|
||||
|
||||
#ifndef CH_VECTOR
|
||||
#define CH_VECTOR
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#ifndef CH_STRING
|
||||
#define CH_STRING
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
|
||||
class Hex {
|
||||
private:
|
||||
int _hex;
|
||||
public:
|
||||
Hex(int in):_hex(in) { };
|
||||
Hex():_hex(0) { };
|
||||
bool operator==(Hex const& other) {return _hex == other._hex;}
|
||||
operator int () const { return _hex; }
|
||||
|
||||
};
|
||||
|
||||
class Value {
|
||||
/*
|
||||
* Multitype storage container that is aware of the currently stored type in it.
|
||||
* Value st = "hello";
|
||||
* Value in = 1;
|
||||
* st = 12 //Exception
|
||||
* in = 12 //works
|
||||
*/
|
||||
private:
|
||||
Hex _hex;
|
||||
bool _bool;
|
||||
int _int;
|
||||
std::string* _string;
|
||||
double _double;
|
||||
public:
|
||||
class WrongType { }; // Conversion error class
|
||||
enum Etype { V_NONE, V_HEX, V_BOOL, V_INT, V_STRING, V_DOUBLE,V_CURRENT} type;
|
||||
|
||||
/* Constructors */
|
||||
Value() :_string(0), type(V_NONE) { };
|
||||
Value(Hex in) :_hex(in), type(V_HEX) { };
|
||||
Value(int in) :_int(in), type(V_INT) { };
|
||||
Value(bool in) :_bool(in), type(V_BOOL) { };
|
||||
Value(double in) :_double(in), type(V_DOUBLE) { };
|
||||
Value(std::string const& in) :_string(new std::string(in)),type(V_STRING) { };
|
||||
Value(char const * const in) :_string(new std::string(in)),type(V_STRING) { };
|
||||
Value(Value const& in):_string(0) {plaincopy(in);}
|
||||
~Value() { destroy();};
|
||||
Value(std::string const& in,Etype _t) :_string(0),type(V_NONE) {SetValue(in,_t);}
|
||||
|
||||
/* Assigment operators */
|
||||
Value& operator= (Hex in) throw(WrongType) { return copy(Value(in));}
|
||||
Value& operator= (int in) throw(WrongType) { return copy(Value(in));}
|
||||
Value& operator= (bool in) throw(WrongType) { return copy(Value(in));}
|
||||
Value& operator= (double in) throw(WrongType) { return copy(Value(in));}
|
||||
Value& operator= (std::string const& in) throw(WrongType) { return copy(Value(in));}
|
||||
Value& operator= (char const * const in) throw(WrongType) { return copy(Value(in));}
|
||||
Value& operator= (Value const& in) throw(WrongType) { return copy(Value(in));}
|
||||
|
||||
bool operator== (Value const & other);
|
||||
operator bool () const throw(WrongType);
|
||||
operator Hex () const throw(WrongType);
|
||||
operator int () const throw(WrongType);
|
||||
operator double () const throw(WrongType);
|
||||
operator char const* () const throw(WrongType);
|
||||
void SetValue(std::string const& in,Etype _type = V_CURRENT) throw(WrongType);
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
void destroy() throw();
|
||||
Value& copy(Value const& in) throw(WrongType);
|
||||
void plaincopy(Value const& in) throw();
|
||||
void set_hex(std::string const& in);
|
||||
void set_int(std::string const&in);
|
||||
void set_bool(std::string const& in);
|
||||
void set_string(std::string const& in);
|
||||
void set_double(std::string const& in);
|
||||
};
|
||||
|
||||
class Property {
|
||||
public:
|
||||
struct Changeable { enum Value {Always, WhenIdle,OnlyAtStart};};
|
||||
const std::string propname;
|
||||
|
||||
Property(std::string const& _propname, Changeable::Value when):propname(_propname),change(when) { }
|
||||
void Set_values(const char * const * in);
|
||||
void Set_help(std::string const& str);
|
||||
char const* Get_help();
|
||||
virtual void SetValue(std::string const& str)=0;
|
||||
Value const& GetValue() const { return value;}
|
||||
Value const& Get_Default_Value() const { return default_value; }
|
||||
//CheckValue returns true if value is in suggested_values;
|
||||
//Type specific properties are encouraged to override this and check for type
|
||||
//specific features.
|
||||
virtual bool CheckValue(Value const& in, bool warn);
|
||||
//Set interval value to in or default if in is invalid. force always sets the value.
|
||||
void SetVal(Value const& in, bool forced,bool warn=true) {if(forced || CheckValue(in,warn)) value = in; else value = default_value;}
|
||||
virtual ~Property(){ }
|
||||
virtual const std::vector<Value>& GetValues() const;
|
||||
Value::Etype Get_type(){return default_value.type;}
|
||||
|
||||
protected:
|
||||
Value value;
|
||||
std::vector<Value> suggested_values;
|
||||
typedef std::vector<Value>::iterator iter;
|
||||
Value default_value;
|
||||
const Changeable::Value change;
|
||||
};
|
||||
|
||||
class Prop_int:public Property {
|
||||
public:
|
||||
Prop_int(std::string const& _propname,Changeable::Value when, int _value)
|
||||
:Property(_propname,when) {
|
||||
default_value = value = _value;
|
||||
min = max = -1;
|
||||
}
|
||||
Prop_int(std::string const& _propname,Changeable::Value when, int _min,int _max,int _value)
|
||||
:Property(_propname,when) {
|
||||
default_value = value = _value;
|
||||
min = _min;
|
||||
max = _max;
|
||||
}
|
||||
void SetMinMax(Value const& min,Value const& max) {this->min = min; this->max=max;}
|
||||
void SetValue(std::string const& in);
|
||||
~Prop_int(){ }
|
||||
virtual bool CheckValue(Value const& in, bool warn);
|
||||
private:
|
||||
Value min,max;
|
||||
};
|
||||
|
||||
class Prop_double:public Property {
|
||||
public:
|
||||
Prop_double(std::string const & _propname, Changeable::Value when, double _value)
|
||||
:Property(_propname,when){
|
||||
default_value = value = _value;
|
||||
}
|
||||
void SetValue(std::string const& input);
|
||||
~Prop_double(){ }
|
||||
};
|
||||
|
||||
class Prop_bool:public Property {
|
||||
public:
|
||||
Prop_bool(std::string const& _propname, Changeable::Value when, bool _value)
|
||||
:Property(_propname,when) {
|
||||
default_value = value = _value;
|
||||
}
|
||||
void SetValue(std::string const& in);
|
||||
~Prop_bool(){ }
|
||||
};
|
||||
|
||||
class Prop_string:public Property{
|
||||
public:
|
||||
Prop_string(std::string const& _propname, Changeable::Value when, char const * const _value)
|
||||
:Property(_propname,when) {
|
||||
default_value = value = _value;
|
||||
}
|
||||
void SetValue(std::string const& in);
|
||||
virtual bool CheckValue(Value const& in, bool warn);
|
||||
~Prop_string(){ }
|
||||
};
|
||||
class Prop_path:public Prop_string{
|
||||
public:
|
||||
std::string realpath;
|
||||
Prop_path(std::string const& _propname, Changeable::Value when, char const * const _value)
|
||||
:Prop_string(_propname,when,_value) {
|
||||
default_value = value = _value;
|
||||
realpath = _value;
|
||||
}
|
||||
void SetValue(std::string const& in);
|
||||
~Prop_path(){ }
|
||||
};
|
||||
|
||||
class Prop_hex:public Property {
|
||||
public:
|
||||
Prop_hex(std::string const& _propname, Changeable::Value when, Hex _value)
|
||||
:Property(_propname,when) {
|
||||
default_value = value = _value;
|
||||
}
|
||||
void SetValue(std::string const& in);
|
||||
~Prop_hex(){ }
|
||||
};
|
||||
|
||||
#define NO_SUCH_PROPERTY "PROP_NOT_EXIST"
|
||||
class Section {
|
||||
private:
|
||||
typedef void (*SectionFunction)(Section*);
|
||||
/* Wrapper class around startup and shutdown functions. the variable
|
||||
* canchange indicates it can be called on configuration changes */
|
||||
struct Function_wrapper {
|
||||
SectionFunction function;
|
||||
bool canchange;
|
||||
Function_wrapper(SectionFunction const _fun,bool _ch){
|
||||
function=_fun;
|
||||
canchange=_ch;
|
||||
}
|
||||
};
|
||||
std::list<Function_wrapper> initfunctions;
|
||||
std::list<Function_wrapper> destroyfunctions;
|
||||
std::string sectionname;
|
||||
public:
|
||||
Section(std::string const& _sectionname):sectionname(_sectionname) { }
|
||||
|
||||
void AddInitFunction(SectionFunction func,bool canchange=false);
|
||||
void AddDestroyFunction(SectionFunction func,bool canchange=false);
|
||||
void ExecuteInit(bool initall=true);
|
||||
void ExecuteDestroy(bool destroyall=true);
|
||||
const char* GetName() const {return sectionname.c_str();}
|
||||
|
||||
virtual std::string GetPropValue(std::string const& _property) const =0;
|
||||
virtual void HandleInputline(std::string const& _line)=0;
|
||||
virtual void PrintData(FILE* outfile) const =0;
|
||||
virtual ~Section() { /*Children must call executedestroy ! */}
|
||||
};
|
||||
|
||||
class Prop_multival;
|
||||
class Prop_multival_remain;
|
||||
class Section_prop:public Section {
|
||||
private:
|
||||
std::list<Property*> properties;
|
||||
typedef std::list<Property*>::iterator it;
|
||||
typedef std::list<Property*>::const_iterator const_it;
|
||||
|
||||
public:
|
||||
Section_prop(std::string const& _sectionname):Section(_sectionname){}
|
||||
Prop_int* Add_int(std::string const& _propname, Property::Changeable::Value when, int _value=0);
|
||||
Prop_string* Add_string(std::string const& _propname, Property::Changeable::Value when, char const * const _value=NULL);
|
||||
Prop_path* Add_path(std::string const& _propname, Property::Changeable::Value when, char const * const _value=NULL);
|
||||
Prop_bool* Add_bool(std::string const& _propname, Property::Changeable::Value when, bool _value=false);
|
||||
Prop_hex* Add_hex(std::string const& _propname, Property::Changeable::Value when, Hex _value=0);
|
||||
// void Add_double(char const * const _propname, double _value=0.0);
|
||||
Prop_multival *Add_multi(std::string const& _propname, Property::Changeable::Value when,std::string const& sep);
|
||||
Prop_multival_remain *Add_multiremain(std::string const& _propname, Property::Changeable::Value when,std::string const& sep);
|
||||
|
||||
Property* Get_prop(int index);
|
||||
int Get_int(std::string const& _propname) const;
|
||||
const char* Get_string(std::string const& _propname) const;
|
||||
bool Get_bool(std::string const& _propname) const;
|
||||
Hex Get_hex(std::string const& _propname) const;
|
||||
double Get_double(std::string const& _propname) const;
|
||||
Prop_path* Get_path(std::string const& _propname) const;
|
||||
Prop_multival* Get_multival(std::string const& _propname) const;
|
||||
Prop_multival_remain* Get_multivalremain(std::string const& _propname) const;
|
||||
void HandleInputline(std::string const& gegevens);
|
||||
void PrintData(FILE* outfile) const;
|
||||
virtual std::string GetPropValue(std::string const& _property) const;
|
||||
//ExecuteDestroy should be here else the destroy functions use destroyed properties
|
||||
virtual ~Section_prop();
|
||||
};
|
||||
|
||||
class Prop_multival:public Property{
|
||||
protected:
|
||||
Section_prop* section;
|
||||
std::string seperator;
|
||||
void make_default_value();
|
||||
public:
|
||||
Prop_multival(std::string const& _propname, Changeable::Value when,std::string const& sep):Property(_propname,when), section(new Section_prop("")),seperator(sep) {
|
||||
default_value = value = "";
|
||||
}
|
||||
Section_prop *GetSection() { return section; }
|
||||
const Section_prop *GetSection() const { return section; }
|
||||
virtual void SetValue(std::string const& input);
|
||||
virtual const std::vector<Value>& GetValues() const;
|
||||
~Prop_multival() { delete section; }
|
||||
}; //value bevat totale string. setvalue zet elk van de sub properties en checked die.
|
||||
|
||||
class Prop_multival_remain:public Prop_multival{
|
||||
public:
|
||||
Prop_multival_remain(std::string const& _propname, Changeable::Value when,std::string const& sep):Prop_multival(_propname,when,sep){ }
|
||||
|
||||
virtual void SetValue(std::string const& input);
|
||||
};
|
||||
|
||||
|
||||
class Section_line: public Section{
|
||||
public:
|
||||
Section_line(std::string const& _sectionname):Section(_sectionname){}
|
||||
~Section_line(){ExecuteDestroy(true);}
|
||||
void HandleInputline(std::string const& gegevens);
|
||||
void PrintData(FILE* outfile) const;
|
||||
virtual std::string GetPropValue(std::string const& _property) const;
|
||||
std::string data;
|
||||
};
|
||||
|
||||
class Module_base {
|
||||
/* Base for all hardware and software "devices" */
|
||||
protected:
|
||||
Section* m_configuration;
|
||||
public:
|
||||
Module_base(Section* configuration){m_configuration=configuration;};
|
||||
// Module_base(Section* configuration, SaveState* state) {};
|
||||
virtual ~Module_base(){/*LOG_MSG("executed")*/;};//Destructors are required
|
||||
/* Returns true if succesful.*/
|
||||
virtual bool Change_Config(Section* /*newconfig*/) {return false;} ;
|
||||
};
|
||||
#endif
|
144
include/shell.h
Normal file
144
include/shell.h
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: shell.h,v 1.26 2009/03/23 10:55:35 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_SHELL_H
|
||||
#define DOSBOX_SHELL_H
|
||||
|
||||
#include <ctype.h>
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
#ifndef DOSBOX_PROGRAMS_H
|
||||
#include "programs.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#define CMD_MAXLINE 4096
|
||||
#define CMD_MAXCMDS 20
|
||||
#define CMD_OLDSIZE 4096
|
||||
extern Bitu call_shellstop;
|
||||
/* first_shell is used to add and delete stuff from the shell env
|
||||
* by "external" programs. (config) */
|
||||
extern Program * first_shell;
|
||||
|
||||
class DOS_Shell;
|
||||
|
||||
class BatchFile {
|
||||
public:
|
||||
BatchFile(DOS_Shell * host,char const* const name, char const * const cmd_line);
|
||||
virtual ~BatchFile();
|
||||
virtual bool ReadLine(char * line);
|
||||
bool Goto(char * where);
|
||||
void Shift(void);
|
||||
Bit16u file_handle;
|
||||
Bit32u location;
|
||||
bool echo;
|
||||
DOS_Shell * shell;
|
||||
BatchFile * prev;
|
||||
CommandLine * cmd;
|
||||
};
|
||||
|
||||
class AutoexecEditor;
|
||||
class DOS_Shell : public Program {
|
||||
private:
|
||||
friend class AutoexecEditor;
|
||||
std::list<std::string> l_history, l_completion;
|
||||
|
||||
char *completion_start;
|
||||
Bit16u completion_index;
|
||||
|
||||
public:
|
||||
|
||||
DOS_Shell();
|
||||
|
||||
void Run(void);
|
||||
void RunInternal(void); //for command /C
|
||||
/* A load of subfunctions */
|
||||
void ParseLine(char * line);
|
||||
Bitu GetRedirection(char *s, char **ifn, char **ofn,bool * append);
|
||||
void InputCommand(char * line);
|
||||
void ShowPrompt();
|
||||
void DoCommand(char * cmd);
|
||||
bool Execute(char * name,char * args);
|
||||
/* Checks if it matches a hardware-property */
|
||||
bool CheckConfig(char* cmd_in,char*line);
|
||||
/* Some internal used functions */
|
||||
char * Which(char * name);
|
||||
/* Some supported commands */
|
||||
void CMD_HELP(char * args);
|
||||
void CMD_CLS(char * args);
|
||||
void CMD_COPY(char * args);
|
||||
void CMD_DIR(char * args);
|
||||
void CMD_DELETE(char * args);
|
||||
void CMD_ECHO(char * args);
|
||||
void CMD_EXIT(char * args);
|
||||
void CMD_MKDIR(char * args);
|
||||
void CMD_CHDIR(char * args);
|
||||
void CMD_RMDIR(char * args);
|
||||
void CMD_SET(char * args);
|
||||
void CMD_IF(char * args);
|
||||
void CMD_GOTO(char * args);
|
||||
void CMD_TYPE(char * args);
|
||||
void CMD_REM(char * args);
|
||||
void CMD_RENAME(char * args);
|
||||
void CMD_CALL(char * args);
|
||||
void SyntaxError(void);
|
||||
void CMD_PAUSE(char * args);
|
||||
void CMD_SUBST(char* args);
|
||||
void CMD_LOADHIGH(char* args);
|
||||
void CMD_CHOICE(char * args);
|
||||
void CMD_ATTRIB(char * args);
|
||||
void CMD_PATH(char * args);
|
||||
void CMD_SHIFT(char * args);
|
||||
void CMD_VER(char * args);
|
||||
/* The shell's variables */
|
||||
Bit16u input_handle;
|
||||
BatchFile * bf;
|
||||
bool echo;
|
||||
bool exit;
|
||||
bool call;
|
||||
};
|
||||
|
||||
struct SHELL_Cmd {
|
||||
const char * name; /* Command name*/
|
||||
Bit32u flags; /* Flags about the command */
|
||||
void (DOS_Shell::*handler)(char * args); /* Handler for this command */
|
||||
const char * help; /* String with command help */
|
||||
};
|
||||
|
||||
/* Object to manage lines in the autoexec.bat The lines get removed from
|
||||
* the file if the object gets destroyed. The environment is updated
|
||||
* as well if the line set a a variable */
|
||||
class AutoexecObject{
|
||||
private:
|
||||
bool installed;
|
||||
std::string buf;
|
||||
public:
|
||||
AutoexecObject():installed(false){ };
|
||||
void Install(std::string const &in);
|
||||
void InstallBefore(std::string const &in);
|
||||
~AutoexecObject();
|
||||
private:
|
||||
void CreateAutoexec(void);
|
||||
};
|
||||
|
||||
#endif
|
60
include/support.h
Normal file
60
include/support.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: support.h,v 1.17 2009/04/25 16:25:03 harekiet Exp $ */
|
||||
|
||||
#ifndef DOSBOX_SUPPORT_H
|
||||
#define DOSBOX_SUPPORT_H
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <ctype.h>
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
|
||||
#if defined (_MSC_VER) /* MS Visual C++ */
|
||||
#define strcasecmp(a,b) stricmp(a,b)
|
||||
#define strncasecmp(a,b,n) _strnicmp(a,b,n)
|
||||
#endif
|
||||
|
||||
#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0)
|
||||
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
void strreplace(char * str,char o,char n);
|
||||
char *ltrim(char *str);
|
||||
char *rtrim(char *str);
|
||||
char *trim(char * str);
|
||||
char * upcase(char * str);
|
||||
char * lowcase(char * str);
|
||||
|
||||
bool ScanCMDBool(char * cmd,char const * const check);
|
||||
char * ScanCMDRemain(char * cmd);
|
||||
char * StripWord(char *&cmd);
|
||||
bool IsDecWord(char * word);
|
||||
bool IsHexWord(char * word);
|
||||
Bits ConvDecWord(char * word);
|
||||
Bits ConvHexWord(char * word);
|
||||
|
||||
void upcase(std::string &str);
|
||||
void lowcase(std::string &str);
|
||||
|
||||
#endif
|
38
include/timer.h
Normal file
38
include/timer.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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_TIMER_H
|
||||
#define DOSBOX_TIMER_H
|
||||
|
||||
/* underlying clock rate in HZ */
|
||||
#include <SDL.h>
|
||||
|
||||
#define PIT_TICK_RATE 1193182
|
||||
|
||||
#define GetTicks() SDL_GetTicks()
|
||||
|
||||
typedef void (*TIMER_TickHandler)(void);
|
||||
|
||||
/* Register a function that gets called everytime if 1 or more ticks pass */
|
||||
void TIMER_AddTickHandler(TIMER_TickHandler handler);
|
||||
void TIMER_DelTickHandler(TIMER_TickHandler handler);
|
||||
|
||||
/* This will add 1 milliscond to all timers */
|
||||
void TIMER_AddTick(void);
|
||||
|
||||
#endif
|
509
include/vga.h
Normal file
509
include/vga.h
Normal file
@ -0,0 +1,509 @@
|
||||
/*
|
||||
* 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: vga.h,v 1.46 2009/03/15 11:28:34 c2woody Exp $ */
|
||||
|
||||
#ifndef DOSBOX_VGA_H
|
||||
#define DOSBOX_VGA_H
|
||||
|
||||
#ifndef DOSBOX_DOSBOX_H
|
||||
#include "dosbox.h"
|
||||
#endif
|
||||
|
||||
//Don't enable keeping changes and mapping lfb probably...
|
||||
#define VGA_LFB_MAPPED
|
||||
//#define VGA_KEEP_CHANGES
|
||||
#define VGA_CHANGE_SHIFT 9
|
||||
|
||||
class PageHandler;
|
||||
|
||||
|
||||
enum VGAModes {
|
||||
M_CGA2, M_CGA4,
|
||||
M_EGA, M_VGA,
|
||||
M_LIN4, M_LIN8, M_LIN15, M_LIN16, M_LIN32,
|
||||
M_TEXT,
|
||||
M_HERC_GFX, M_HERC_TEXT,
|
||||
M_CGA16, M_TANDY2, M_TANDY4, M_TANDY16, M_TANDY_TEXT,
|
||||
M_ERROR
|
||||
};
|
||||
|
||||
|
||||
#define CLK_25 25175
|
||||
#define CLK_28 28322
|
||||
|
||||
#define MIN_VCO 180000
|
||||
#define MAX_VCO 360000
|
||||
|
||||
#define S3_CLOCK_REF 14318 /* KHz */
|
||||
#define S3_CLOCK(_M,_N,_R) ((S3_CLOCK_REF * ((_M) + 2)) / (((_N) + 2) * (1 << (_R))))
|
||||
#define S3_MAX_CLOCK 150000 /* KHz */
|
||||
|
||||
#define S3_XGA_1024 0x00
|
||||
#define S3_XGA_1152 0x01
|
||||
#define S3_XGA_640 0x40
|
||||
#define S3_XGA_800 0x80
|
||||
#define S3_XGA_1280 0xc0
|
||||
#define S3_XGA_WMASK (S3_XGA_640|S3_XGA_800|S3_XGA_1024|S3_XGA_1152|S3_XGA_1280)
|
||||
|
||||
#define S3_XGA_8BPP 0x00
|
||||
#define S3_XGA_16BPP 0x10
|
||||
#define S3_XGA_32BPP 0x30
|
||||
#define S3_XGA_CMASK (S3_XGA_8BPP|S3_XGA_16BPP|S3_XGA_32BPP)
|
||||
|
||||
typedef struct {
|
||||
bool attrindex;
|
||||
} VGA_Internal;
|
||||
|
||||
typedef struct {
|
||||
/* Memory handlers */
|
||||
Bitu mh_mask;
|
||||
|
||||
/* Video drawing */
|
||||
Bitu display_start;
|
||||
Bitu real_start;
|
||||
bool retrace; /* A retrace is active */
|
||||
Bitu scan_len;
|
||||
Bitu cursor_start;
|
||||
|
||||
/* Some other screen related variables */
|
||||
Bitu line_compare;
|
||||
bool chained; /* Enable or Disabled Chain 4 Mode */
|
||||
bool compatible_chain4;
|
||||
|
||||
/* Pixel Scrolling */
|
||||
Bit8u pel_panning; /* Amount of pixels to skip when starting horizontal line */
|
||||
Bit8u hlines_skip;
|
||||
Bit8u bytes_skip;
|
||||
Bit8u addr_shift;
|
||||
|
||||
/* Specific stuff memory write/read handling */
|
||||
|
||||
Bit8u read_mode;
|
||||
Bit8u write_mode;
|
||||
Bit8u read_map_select;
|
||||
Bit8u color_dont_care;
|
||||
Bit8u color_compare;
|
||||
Bit8u data_rotate;
|
||||
Bit8u raster_op;
|
||||
|
||||
Bit32u full_bit_mask;
|
||||
Bit32u full_map_mask;
|
||||
Bit32u full_not_map_mask;
|
||||
Bit32u full_set_reset;
|
||||
Bit32u full_not_enable_set_reset;
|
||||
Bit32u full_enable_set_reset;
|
||||
Bit32u full_enable_and_set_reset;
|
||||
} VGA_Config;
|
||||
|
||||
typedef struct {
|
||||
bool resizing;
|
||||
Bitu width;
|
||||
Bitu height;
|
||||
Bitu blocks;
|
||||
Bitu address;
|
||||
Bitu panning;
|
||||
Bitu bytes_skip;
|
||||
Bit8u *linear_base;
|
||||
Bitu linear_mask;
|
||||
Bitu address_add;
|
||||
Bitu line_length;
|
||||
Bitu address_line_total;
|
||||
Bitu address_line;
|
||||
Bitu lines_total;
|
||||
Bitu lines_done;
|
||||
Bitu lines_scaled;
|
||||
Bitu split_line;
|
||||
Bitu parts_total;
|
||||
Bitu parts_lines;
|
||||
Bitu parts_left;
|
||||
Bitu byte_panning_shift;
|
||||
struct {
|
||||
double framestart;
|
||||
double vrstart, vrend; // V-retrace
|
||||
double hrstart, hrend; // H-retrace
|
||||
double hblkstart, hblkend; // H-blanking
|
||||
double vblkstart, vblkend; // V-Blanking
|
||||
double vdend, vtotal;
|
||||
double hdend, htotal;
|
||||
double parts;
|
||||
} delay;
|
||||
double aspect_ratio;
|
||||
bool double_scan;
|
||||
bool doublewidth,doubleheight;
|
||||
Bit8u font[64*1024];
|
||||
Bit8u * font_tables[2];
|
||||
Bitu blinking;
|
||||
struct {
|
||||
Bitu address;
|
||||
Bit8u sline,eline;
|
||||
Bit8u count,delay;
|
||||
Bit8u enabled;
|
||||
} cursor;
|
||||
bool vret_triggered;
|
||||
} VGA_Draw;
|
||||
|
||||
typedef struct {
|
||||
Bit8u curmode;
|
||||
Bit16u originx, originy;
|
||||
Bit8u fstackpos, bstackpos;
|
||||
Bit8u forestack[3];
|
||||
Bit8u backstack[3];
|
||||
Bit16u startaddr;
|
||||
Bit8u posx, posy;
|
||||
Bit8u mc[64][64];
|
||||
} VGA_HWCURSOR;
|
||||
|
||||
typedef struct {
|
||||
Bit8u reg_lock1;
|
||||
Bit8u reg_lock2;
|
||||
Bit8u reg_31;
|
||||
Bit8u reg_35;
|
||||
Bit8u reg_36; // RAM size
|
||||
Bit8u reg_3a; // 4/8/doublepixel bit in there
|
||||
Bit8u reg_40; // 8415/A functionality register
|
||||
Bit8u reg_41; // BIOS flags
|
||||
Bit8u reg_43;
|
||||
Bit8u reg_45; // Hardware graphics cursor
|
||||
Bit8u reg_50;
|
||||
Bit8u reg_51;
|
||||
Bit8u reg_52;
|
||||
Bit8u reg_55;
|
||||
Bit8u reg_58;
|
||||
Bit8u reg_6b; // LFB BIOS scratchpad
|
||||
Bit8u ex_hor_overflow;
|
||||
Bit8u ex_ver_overflow;
|
||||
Bit16u la_window;
|
||||
Bit8u misc_control_2;
|
||||
Bit8u ext_mem_ctrl;
|
||||
Bitu xga_screen_width;
|
||||
VGAModes xga_color_mode;
|
||||
struct {
|
||||
Bit8u r;
|
||||
Bit8u n;
|
||||
Bit8u m;
|
||||
} clk[4],mclk;
|
||||
struct {
|
||||
Bit8u lock;
|
||||
Bit8u cmd;
|
||||
} pll;
|
||||
VGA_HWCURSOR hgc;
|
||||
} VGA_S3;
|
||||
|
||||
typedef struct {
|
||||
Bit8u mode_control;
|
||||
Bit8u enable_bits;
|
||||
} VGA_HERC;
|
||||
|
||||
typedef struct {
|
||||
Bit8u index;
|
||||
Bit8u htotal;
|
||||
Bit8u hdend;
|
||||
Bit8u hsyncp;
|
||||
Bit8u syncw;
|
||||
Bit8u vtotal;
|
||||
Bit8u vdend;
|
||||
Bit8u vadjust;
|
||||
Bit8u vsyncp;
|
||||
Bit8u vsyncw;
|
||||
Bit8u max_scanline;
|
||||
Bit8u lpen_low, lpen_high;
|
||||
Bit8u cursor_start;
|
||||
Bit8u cursor_end;
|
||||
} VGA_OTHER;
|
||||
|
||||
typedef struct {
|
||||
Bit8u pcjr_flipflop;
|
||||
Bit8u mode_control;
|
||||
Bit8u color_select;
|
||||
Bit8u disp_bank;
|
||||
Bit8u reg_index;
|
||||
Bit8u gfx_control;
|
||||
Bit8u palette_mask;
|
||||
Bit8u extended_ram;
|
||||
Bit8u border_color;
|
||||
Bit8u line_mask, line_shift;
|
||||
Bit8u draw_bank, mem_bank;
|
||||
Bit8u *draw_base, *mem_base;
|
||||
Bitu addr_mask;
|
||||
} VGA_TANDY;
|
||||
|
||||
typedef struct {
|
||||
Bit8u index;
|
||||
Bit8u reset;
|
||||
Bit8u clocking_mode;
|
||||
Bit8u map_mask;
|
||||
Bit8u character_map_select;
|
||||
Bit8u memory_mode;
|
||||
} VGA_Seq;
|
||||
|
||||
typedef struct {
|
||||
Bit8u palette[16];
|
||||
Bit8u mode_control;
|
||||
Bit8u horizontal_pel_panning;
|
||||
Bit8u overscan_color;
|
||||
Bit8u color_plane_enable;
|
||||
Bit8u color_select;
|
||||
Bit8u index;
|
||||
Bit8u enabled;
|
||||
} VGA_Attr;
|
||||
|
||||
typedef struct {
|
||||
Bit8u horizontal_total;
|
||||
Bit8u horizontal_display_end;
|
||||
Bit8u start_horizontal_blanking;
|
||||
Bit8u end_horizontal_blanking;
|
||||
Bit8u start_horizontal_retrace;
|
||||
Bit8u end_horizontal_retrace;
|
||||
Bit8u vertical_total;
|
||||
Bit8u overflow;
|
||||
Bit8u preset_row_scan;
|
||||
Bit8u maximum_scan_line;
|
||||
Bit8u cursor_start;
|
||||
Bit8u cursor_end;
|
||||
Bit8u start_address_high;
|
||||
Bit8u start_address_low;
|
||||
Bit8u cursor_location_high;
|
||||
Bit8u cursor_location_low;
|
||||
Bit8u vertical_retrace_start;
|
||||
Bit8u vertical_retrace_end;
|
||||
Bit8u vertical_display_end;
|
||||
Bit8u offset;
|
||||
Bit8u underline_location;
|
||||
Bit8u start_vertical_blanking;
|
||||
Bit8u end_vertical_blanking;
|
||||
Bit8u mode_control;
|
||||
Bit8u line_compare;
|
||||
|
||||
Bit8u index;
|
||||
bool read_only;
|
||||
} VGA_Crtc;
|
||||
|
||||
typedef struct {
|
||||
Bit8u index;
|
||||
Bit8u set_reset;
|
||||
Bit8u enable_set_reset;
|
||||
Bit8u color_compare;
|
||||
Bit8u data_rotate;
|
||||
Bit8u read_map_select;
|
||||
Bit8u mode;
|
||||
Bit8u miscellaneous;
|
||||
Bit8u color_dont_care;
|
||||
Bit8u bit_mask;
|
||||
} VGA_Gfx;
|
||||
|
||||
typedef struct {
|
||||
Bit8u red;
|
||||
Bit8u green;
|
||||
Bit8u blue;
|
||||
} RGBEntry;
|
||||
|
||||
typedef struct {
|
||||
Bit8u bits; /* DAC bits, usually 6 or 8 */
|
||||
Bit8u pel_mask;
|
||||
Bit8u pel_index;
|
||||
Bit8u state;
|
||||
Bit8u write_index;
|
||||
Bit8u read_index;
|
||||
Bitu first_changed;
|
||||
Bit8u combine[16];
|
||||
RGBEntry rgb[0x100];
|
||||
Bit16u xlat16[256];
|
||||
} VGA_Dac;
|
||||
|
||||
typedef struct {
|
||||
Bitu readStart, writeStart;
|
||||
Bitu bankMask;
|
||||
Bitu bank_read_full;
|
||||
Bitu bank_write_full;
|
||||
Bit8u bank_read;
|
||||
Bit8u bank_write;
|
||||
Bitu bank_size;
|
||||
} VGA_SVGA;
|
||||
|
||||
typedef union {
|
||||
Bit32u d;
|
||||
Bit8u b[4];
|
||||
} VGA_Latch;
|
||||
|
||||
typedef struct {
|
||||
Bit8u* linear;
|
||||
Bit8u* linear_orgptr;
|
||||
} VGA_Memory;
|
||||
|
||||
typedef struct {
|
||||
//Add a few more just to be safe
|
||||
Bit8u* map; /* allocated dynamically: [(VGA_MEMORY >> VGA_CHANGE_SHIFT) + 32] */
|
||||
Bit8u checkMask, frame, writeMask;
|
||||
bool active;
|
||||
Bit32u clearMask;
|
||||
Bit32u start, last;
|
||||
Bit32u lastAddress;
|
||||
} VGA_Changes;
|
||||
|
||||
typedef struct {
|
||||
Bit32u page;
|
||||
Bit32u addr;
|
||||
Bit32u mask;
|
||||
PageHandler *handler;
|
||||
} VGA_LFB;
|
||||
|
||||
typedef struct {
|
||||
VGAModes mode; /* The mode the vga system is in */
|
||||
VGAModes lastmode;
|
||||
Bits screenflip;
|
||||
Bit8u misc_output;
|
||||
VGA_Draw draw;
|
||||
VGA_Config config;
|
||||
VGA_Internal internal;
|
||||
/* Internal module groups */
|
||||
VGA_Seq seq;
|
||||
VGA_Attr attr;
|
||||
VGA_Crtc crtc;
|
||||
VGA_Gfx gfx;
|
||||
VGA_Dac dac;
|
||||
VGA_Latch latch;
|
||||
VGA_S3 s3;
|
||||
VGA_SVGA svga;
|
||||
VGA_HERC herc;
|
||||
VGA_TANDY tandy;
|
||||
VGA_OTHER other;
|
||||
VGA_Memory mem;
|
||||
Bit32u vmemwrap; /* this is assumed to be power of 2 */
|
||||
Bit8u* fastmem; /* memory for fast (usually 16-color) rendering, always twice as big as vmemsize */
|
||||
Bit8u* fastmem_orgptr;
|
||||
Bit32u vmemsize;
|
||||
#ifdef VGA_KEEP_CHANGES
|
||||
VGA_Changes changes;
|
||||
#endif
|
||||
VGA_LFB lfb;
|
||||
} VGA_Type;
|
||||
|
||||
|
||||
|
||||
/* Functions for different resolutions */
|
||||
void VGA_SetMode(VGAModes mode);
|
||||
void VGA_DetermineMode(void);
|
||||
void VGA_SetupHandlers(void);
|
||||
void VGA_StartResize(Bitu delay=50);
|
||||
void VGA_SetupDrawing(Bitu val);
|
||||
void VGA_CheckScanLength(void);
|
||||
void VGA_ChangedBank(void);
|
||||
|
||||
/* Some DAC/Attribute functions */
|
||||
void VGA_DAC_CombineColor(Bit8u attr,Bit8u pal);
|
||||
void VGA_DAC_SetEntry(Bitu entry,Bit8u red,Bit8u green,Bit8u blue);
|
||||
void VGA_ATTR_SetPalette(Bit8u index,Bit8u val);
|
||||
|
||||
/* The VGA Subfunction startups */
|
||||
void VGA_SetupAttr(void);
|
||||
void VGA_SetupMemory(Section* sec);
|
||||
void VGA_SetupDAC(void);
|
||||
void VGA_SetupCRTC(void);
|
||||
void VGA_SetupMisc(void);
|
||||
void VGA_SetupGFX(void);
|
||||
void VGA_SetupSEQ(void);
|
||||
void VGA_SetupOther(void);
|
||||
void VGA_SetupXGA(void);
|
||||
|
||||
/* Some Support Functions */
|
||||
void VGA_SetClock(Bitu which,Bitu target);
|
||||
void VGA_DACSetEntirePalette(void);
|
||||
void VGA_StartRetrace(void);
|
||||
void VGA_StartUpdateLFB(void);
|
||||
void VGA_SetBlinking(Bitu enabled);
|
||||
void VGA_SetCGA2Table(Bit8u val0,Bit8u val1);
|
||||
void VGA_SetCGA4Table(Bit8u val0,Bit8u val1,Bit8u val2,Bit8u val3);
|
||||
void VGA_ActivateHardwareCursor(void);
|
||||
void VGA_KillDrawing(void);
|
||||
|
||||
extern VGA_Type vga;
|
||||
|
||||
/* Support for modular SVGA implementation */
|
||||
/* Video mode extra data to be passed to FinishSetMode_SVGA().
|
||||
This structure will be in flux until all drivers (including S3)
|
||||
are properly separated. Right now it contains only three overflow
|
||||
fields in S3 format and relies on drivers re-interpreting those.
|
||||
For reference:
|
||||
ver_overflow:X|line_comp10|X|vretrace10|X|vbstart10|vdispend10|vtotal10
|
||||
hor_overflow:X|X|X|hretrace8|X|hblank8|hdispend8|htotal8
|
||||
offset is not currently used by drivers (useful only for S3 itself)
|
||||
It also contains basic int10 mode data - number, vtotal, htotal
|
||||
*/
|
||||
typedef struct {
|
||||
Bit8u ver_overflow;
|
||||
Bit8u hor_overflow;
|
||||
Bitu offset;
|
||||
Bitu modeNo;
|
||||
Bitu htotal;
|
||||
Bitu vtotal;
|
||||
} VGA_ModeExtraData;
|
||||
|
||||
// Vector function prototypes
|
||||
typedef void (*tWritePort)(Bitu reg,Bitu val,Bitu iolen);
|
||||
typedef Bitu (*tReadPort)(Bitu reg,Bitu iolen);
|
||||
typedef void (*tFinishSetMode)(Bitu crtc_base, VGA_ModeExtraData* modeData);
|
||||
typedef void (*tDetermineMode)();
|
||||
typedef void (*tSetClock)(Bitu which,Bitu target);
|
||||
typedef Bitu (*tGetClock)();
|
||||
typedef bool (*tHWCursorActive)();
|
||||
typedef bool (*tAcceptsMode)(Bitu modeNo);
|
||||
|
||||
struct SVGA_Driver {
|
||||
tWritePort write_p3d5;
|
||||
tReadPort read_p3d5;
|
||||
tWritePort write_p3c5;
|
||||
tReadPort read_p3c5;
|
||||
tWritePort write_p3c0;
|
||||
tReadPort read_p3c1;
|
||||
tWritePort write_p3cf;
|
||||
tReadPort read_p3cf;
|
||||
|
||||
tFinishSetMode set_video_mode;
|
||||
tDetermineMode determine_mode;
|
||||
tSetClock set_clock;
|
||||
tGetClock get_clock;
|
||||
tHWCursorActive hardware_cursor_active;
|
||||
tAcceptsMode accepts_mode;
|
||||
};
|
||||
|
||||
extern SVGA_Driver svga;
|
||||
|
||||
void SVGA_Setup_S3Trio(void);
|
||||
void SVGA_Setup_TsengET4K(void);
|
||||
void SVGA_Setup_TsengET3K(void);
|
||||
void SVGA_Setup_ParadisePVGA1A(void);
|
||||
void SVGA_Setup_Driver(void);
|
||||
|
||||
// Amount of video memory required for a mode, implemented in int10_modes.cpp
|
||||
Bitu VideoModeMemSize(Bitu mode);
|
||||
|
||||
extern Bit32u ExpandTable[256];
|
||||
extern Bit32u FillTable[16];
|
||||
extern Bit32u CGA_2_Table[16];
|
||||
extern Bit32u CGA_4_Table[256];
|
||||
extern Bit32u CGA_4_HiRes_Table[256];
|
||||
extern Bit32u CGA_16_Table[256];
|
||||
extern Bit32u TXT_Font_Table[16];
|
||||
extern Bit32u TXT_FG_Table[16];
|
||||
extern Bit32u TXT_BG_Table[16];
|
||||
extern Bit32u Expand16Table[4][16];
|
||||
extern Bit32u Expand16BigTable[0x10000];
|
||||
|
||||
|
||||
#endif
|
85
include/video.h
Normal file
85
include/video.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: video.h,v 1.25 2008/08/24 16:43:06 qbix79 Exp $ */
|
||||
|
||||
#ifndef DOSBOX_VIDEO_H
|
||||
#define DOSBOX_VIDEO_H
|
||||
|
||||
#define REDUCE_JOYSTICK_POLLING
|
||||
|
||||
typedef enum {
|
||||
GFX_CallBackReset,
|
||||
GFX_CallBackStop,
|
||||
GFX_CallBackRedraw
|
||||
} GFX_CallBackFunctions_t;
|
||||
|
||||
typedef void (*GFX_CallBack_t)( GFX_CallBackFunctions_t function );
|
||||
|
||||
struct GFX_PalEntry {
|
||||
Bit8u r;
|
||||
Bit8u g;
|
||||
Bit8u b;
|
||||
Bit8u unused;
|
||||
};
|
||||
|
||||
#define GFX_CAN_8 0x0001
|
||||
#define GFX_CAN_15 0x0002
|
||||
#define GFX_CAN_16 0x0004
|
||||
#define GFX_CAN_32 0x0008
|
||||
|
||||
#define GFX_LOVE_8 0x0010
|
||||
#define GFX_LOVE_15 0x0020
|
||||
#define GFX_LOVE_16 0x0040
|
||||
#define GFX_LOVE_32 0x0080
|
||||
|
||||
#define GFX_RGBONLY 0x0100
|
||||
|
||||
#define GFX_SCALING 0x1000
|
||||
#define GFX_HARDWARE 0x2000
|
||||
|
||||
#define GFX_CAN_RANDOM 0x4000 //If the interface can also do random access surface
|
||||
|
||||
void GFX_Events(void);
|
||||
void GFX_SetPalette(Bitu start,Bitu count,GFX_PalEntry * entries);
|
||||
Bitu GFX_GetBestMode(Bitu flags);
|
||||
Bitu GFX_GetRGB(Bit8u red,Bit8u green,Bit8u blue);
|
||||
Bitu GFX_SetSize(Bitu width,Bitu height,Bitu flags,double scalex,double scaley,GFX_CallBack_t cb);
|
||||
|
||||
void GFX_ResetScreen(void);
|
||||
void GFX_Start(void);
|
||||
void GFX_Stop(void);
|
||||
void GFX_SwitchFullScreen(void);
|
||||
bool GFX_StartUpdate(Bit8u * & pixels,Bitu & pitch);
|
||||
void GFX_EndUpdate( const Bit16u *changedLines );
|
||||
void GFX_GetSize(int &width, int &height, bool &fullscreen);
|
||||
void GFX_LosingFocus(void);
|
||||
|
||||
#if defined (WIN32)
|
||||
bool GFX_SDLUsingWinDIB(void);
|
||||
#endif
|
||||
|
||||
#if defined (REDUCE_JOYSTICK_POLLING)
|
||||
void MAPPER_UpdateJoysticks(void);
|
||||
#endif
|
||||
|
||||
/* Mouse related */
|
||||
void GFX_CaptureMouse(void);
|
||||
extern bool mouselocked; //true if mouse is confined to window
|
||||
|
||||
#endif
|
149
scripts/dosbox-installer.nsi
Normal file
149
scripts/dosbox-installer.nsi
Normal file
@ -0,0 +1,149 @@
|
||||
!define VER_MAYOR 0
|
||||
!define VER_MINOR 72
|
||||
!define APP_NAME "DOSBox ${VER_MAYOR}.${VER_MINOR} Installer"
|
||||
!define COMP_NAME "DOSBox Team"
|
||||
!define COPYRIGHT "Copyright © 2002-2008 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
|
||||
|
||||
ComponentText "Select components for DOSBox"
|
||||
; The stuff to install
|
||||
Section "!Core files" Core
|
||||
; Set output path to the installation directory.
|
||||
ClearErrors
|
||||
SetOutPath $INSTDIR
|
||||
IfErrors error_createdir
|
||||
SectionIn RO
|
||||
|
||||
; Put file there
|
||||
|
||||
CreateDirectory "$INSTDIR\capture"
|
||||
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 dosbox.conf
|
||||
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"
|
||||
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" "-conf $\"$INSTDIR\dosbox.conf$\"" "$INSTDIR\DOSBox.exe" 0
|
||||
CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox (noconsole).lnk" "$INSTDIR\DOSBox.exe" "-noconsole -conf $\"$INSTDIR\dosbox.conf$\"" "$INSTDIR\DOSBox.exe" 0
|
||||
CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\README.lnk" "$INSTDIR\README.txt"
|
||||
CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\DOSBox.conf.lnk" "notepad.exe" "$INSTDIR\dosbox.conf"
|
||||
CreateShortCut "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Capture folder.lnk" "$INSTDIR\capture"
|
||||
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
|
||||
|
||||
CreateShortCut "$DESKTOP\DOSBox ${VER_MAYOR}.${VER_MINOR}.lnk" "$INSTDIR\DOSBox.exe" "-conf $\"$INSTDIR\dosbox.conf$\"" "$INSTDIR\DOSBox.exe" 0
|
||||
|
||||
SectionEnd ; end the section
|
||||
|
||||
|
||||
UninstallText "This will uninstall DOSBox v${VER_MAYOR}.${VER_MINOR}. Hit next to continue."
|
||||
|
||||
Section "Uninstall"
|
||||
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\dosbox.conf
|
||||
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}\DOSBox.conf.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\capture"
|
||||
RMDir "$INSTDIR"
|
||||
RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}\Video"
|
||||
RMDir "$SMPROGRAMS\DOSBox-${VER_MAYOR}.${VER_MINOR}"
|
||||
SectionEnd
|
||||
|
||||
; eof
|
32
scripts/ega-switch.pl
Normal file
32
scripts/ega-switch.pl
Normal file
@ -0,0 +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);
|
25
scripts/font-switch.pl
Normal file
25
scripts/font-switch.pl
Normal file
@ -0,0 +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);
|
20
src/Makefile.am
Normal file
20
src/Makefile.am
Normal file
@ -0,0 +1,20 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
SUBDIRS = cpu debug dos fpu gui hardware libs ints misc shell platform
|
||||
|
||||
bin_PROGRAMS = dosbox
|
||||
|
||||
if HAVE_WINDRES
|
||||
ico_stuff = winres.rc
|
||||
endif
|
||||
|
||||
.rc.o:
|
||||
$(WINDRES) -o $@ $<
|
||||
|
||||
dosbox_SOURCES = dosbox.cpp $(ico_stuff)
|
||||
dosbox_LDADD = cpu/libcpu.a debug/libdebug.a dos/libdos.a fpu/libfpu.a hardware/libhardware.a gui/libgui.a \
|
||||
ints/libints.a misc/libmisc.a shell/libshell.a hardware/serialport/libserial.a libs/gui_tk/libgui_tk.a
|
||||
|
||||
EXTRA_DIST = winres.rc dosbox.ico
|
||||
|
||||
|
7
src/cpu/Makefile.am
Normal file
7
src/cpu/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
||||
SUBDIRS = core_full core_normal core_dyn_x86 core_dynrec
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
|
||||
noinst_LIBRARIES = libcpu.a
|
||||
libcpu_a_SOURCES = callback.cpp cpu.cpp flags.cpp modrm.cpp modrm.h core_full.cpp instructions.h \
|
||||
paging.cpp lazyflags.h core_normal.cpp core_simple.cpp core_prefetch.cpp \
|
||||
core_dyn_x86.cpp core_dynrec.cpp
|
575
src/cpu/callback.cpp
Normal file
575
src/cpu/callback.cpp
Normal file
@ -0,0 +1,575 @@
|
||||
/*
|
||||
* 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: callback.cpp,v 1.40 2009/03/03 18:30:41 c2woody Exp $ */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dosbox.h"
|
||||
#include "callback.h"
|
||||
#include "mem.h"
|
||||
#include "cpu.h"
|
||||
|
||||
/* CallBack are located at 0xF100:0 (see CB_SEG in callback.h)
|
||||
And they are 16 bytes each and you can define them to behave in certain ways like a
|
||||
far return or and IRET
|
||||
*/
|
||||
|
||||
CallBack_Handler CallBack_Handlers[CB_MAX];
|
||||
char* CallBack_Description[CB_MAX];
|
||||
|
||||
static Bitu call_stop,call_idle,call_default,call_default2;
|
||||
Bitu call_priv_io;
|
||||
|
||||
static Bitu illegal_handler(void) {
|
||||
E_Exit("Illegal CallBack Called");
|
||||
return 1;
|
||||
}
|
||||
|
||||
Bitu CALLBACK_Allocate(void) {
|
||||
for (Bitu i=1;(i<CB_MAX);i++) {
|
||||
if (CallBack_Handlers[i]==&illegal_handler) {
|
||||
CallBack_Handlers[i]=0;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
E_Exit("CALLBACK:Can't allocate handler.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CALLBACK_DeAllocate(Bitu in) {
|
||||
CallBack_Handlers[in]=&illegal_handler;
|
||||
}
|
||||
|
||||
|
||||
void CALLBACK_Idle(void) {
|
||||
/* this makes the cpu execute instructions to handle irq's and then come back */
|
||||
Bitu oldIF=GETFLAG(IF);
|
||||
SETFLAGBIT(IF,true);
|
||||
Bit16u oldcs=SegValue(cs);
|
||||
Bit32u oldeip=reg_eip;
|
||||
SegSet16(cs,CB_SEG);
|
||||
reg_eip=call_idle*CB_SIZE;
|
||||
DOSBOX_RunMachine();
|
||||
reg_eip=oldeip;
|
||||
SegSet16(cs,oldcs);
|
||||
SETFLAGBIT(IF,oldIF);
|
||||
if (!CPU_CycleAutoAdjust && CPU_Cycles>0)
|
||||
CPU_Cycles=0;
|
||||
}
|
||||
|
||||
static Bitu default_handler(void) {
|
||||
LOG(LOG_CPU,LOG_ERROR)("Illegal Unhandled Interrupt Called %X",lastint);
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
static Bitu stop_handler(void) {
|
||||
return CBRET_STOP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CALLBACK_RunRealFar(Bit16u seg,Bit16u off) {
|
||||
reg_sp-=4;
|
||||
mem_writew(SegPhys(ss)+reg_sp,call_stop*CB_SIZE);
|
||||
mem_writew(SegPhys(ss)+reg_sp+2,CB_SEG);
|
||||
Bit32u oldeip=reg_eip;
|
||||
Bit16u oldcs=SegValue(cs);
|
||||
reg_eip=off;
|
||||
SegSet16(cs,seg);
|
||||
DOSBOX_RunMachine();
|
||||
reg_eip=oldeip;
|
||||
SegSet16(cs,oldcs);
|
||||
}
|
||||
|
||||
void CALLBACK_RunRealInt(Bit8u intnum) {
|
||||
Bit32u oldeip=reg_eip;
|
||||
Bit16u oldcs=SegValue(cs);
|
||||
reg_eip=(CB_MAX*CB_SIZE)+(intnum*6);
|
||||
SegSet16(cs,CB_SEG);
|
||||
DOSBOX_RunMachine();
|
||||
reg_eip=oldeip;
|
||||
SegSet16(cs,oldcs);
|
||||
}
|
||||
|
||||
void CALLBACK_SZF(bool val) {
|
||||
Bit16u tempf=mem_readw(SegPhys(ss)+reg_sp+4) & 0xFFBF;
|
||||
Bit16u newZF=(val==true) << 6;
|
||||
mem_writew(SegPhys(ss)+reg_sp+4,(tempf | newZF));
|
||||
}
|
||||
|
||||
void CALLBACK_SCF(bool val) {
|
||||
Bit16u tempf=mem_readw(SegPhys(ss)+reg_sp+4) & 0xFFFE;
|
||||
Bit16u newCF=(val==true);
|
||||
mem_writew(SegPhys(ss)+reg_sp+4,(tempf | newCF));
|
||||
}
|
||||
|
||||
void CALLBACK_SetDescription(Bitu nr, const char* descr) {
|
||||
if (descr) {
|
||||
CallBack_Description[nr] = new char[strlen(descr)+1];
|
||||
strcpy(CallBack_Description[nr],descr);
|
||||
} else
|
||||
CallBack_Description[nr] = 0;
|
||||
}
|
||||
|
||||
const char* CALLBACK_GetDescription(Bitu nr) {
|
||||
if (nr>=CB_MAX) return 0;
|
||||
return CallBack_Description[nr];
|
||||
}
|
||||
|
||||
Bitu CALLBACK_SetupExtra(Bitu callback, Bitu type, PhysPt physAddress, bool use_cb=true) {
|
||||
if (callback>=CB_MAX)
|
||||
return 0;
|
||||
switch (type) {
|
||||
case CB_RETN:
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02, callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xC3); //A RETN Instruction
|
||||
return (use_cb?5:1);
|
||||
case CB_RETF:
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02, callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xCB); //A RETF Instruction
|
||||
return (use_cb?5:1);
|
||||
case CB_RETF8:
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02, callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xCA); //A RETF 8 Instruction
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x0008);
|
||||
return (use_cb?7:3);
|
||||
case CB_IRET:
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xCF); //An IRET Instruction
|
||||
return (use_cb?5:1);
|
||||
case CB_IRETD:
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x66); //An IRETD Instruction
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xCF);
|
||||
return (use_cb?6:2);
|
||||
case CB_IRET_STI:
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFB); //STI
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x03, callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xCF); //An IRET Instruction
|
||||
return (use_cb?6:2);
|
||||
case CB_IRET_EOI_PIC1:
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xb0); // mov al, 0x20
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0x20);
|
||||
phys_writeb(physAddress+0x03,(Bit8u)0xe6); // out 0x20, al
|
||||
phys_writeb(physAddress+0x04,(Bit8u)0x20);
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x0b:0x07);
|
||||
case CB_IRQ0: // timer int8
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x52); // push dx
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0x1e); // push ds
|
||||
phys_writew(physAddress+0x03,(Bit16u)0x1ccd); // int 1c
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0xfa); // cli
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0x1f); // pop ds
|
||||
phys_writeb(physAddress+0x07,(Bit8u)0x5a); // pop dx
|
||||
phys_writew(physAddress+0x08,(Bit16u)0x20b0); // mov al, 0x20
|
||||
phys_writew(physAddress+0x0a,(Bit16u)0x20e6); // out 0x20, al
|
||||
phys_writeb(physAddress+0x0c,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x0d,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x12:0x0e);
|
||||
case CB_IRQ1: // keyboard int9
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x60e4); // in al, 0x60
|
||||
phys_writew(physAddress+0x03,(Bit16u)0x4fb4); // mov ah, 0x4f
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0xf9); // stc
|
||||
phys_writew(physAddress+0x06,(Bit16u)0x15cd); // int 15
|
||||
if (use_cb) {
|
||||
phys_writew(physAddress+0x08,(Bit16u)0x0473); // jc skip
|
||||
phys_writeb(physAddress+0x0a,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x0b,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x0c,callback); //The immediate word
|
||||
// jump here to (skip):
|
||||
physAddress+=6;
|
||||
}
|
||||
phys_writeb(physAddress+0x08,(Bit8u)0xfa); // cli
|
||||
phys_writew(physAddress+0x09,(Bit16u)0x20b0); // mov al, 0x20
|
||||
phys_writew(physAddress+0x0b,(Bit16u)0x20e6); // out 0x20, al
|
||||
phys_writeb(physAddress+0x0d,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x0e,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x15:0x0f);
|
||||
case CB_IRQ9: // pic cascade interrupt
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x61b0); // mov al, 0x61
|
||||
phys_writew(physAddress+0x03,(Bit16u)0xa0e6); // out 0xa0, al
|
||||
phys_writew(physAddress+0x05,(Bit16u)0x0acd); // int a
|
||||
phys_writeb(physAddress+0x07,(Bit8u)0xfa); // cli
|
||||
phys_writeb(physAddress+0x08,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x09,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x0e:0x0a);
|
||||
case CB_IRQ12: // ps2 mouse int74
|
||||
if (!use_cb) E_Exit("int74 callback must implement a callback handler!");
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x1e); // push ds
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x06); // push es
|
||||
phys_writew(physAddress+0x02,(Bit16u)0x6066); // pushad
|
||||
phys_writeb(physAddress+0x04,(Bit8u)0xfc); // cld
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0xfb); // sti
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x07,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x08,callback); //The immediate word
|
||||
return 0x0a;
|
||||
case CB_IRQ12_RET: // ps2 mouse int74 return
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xfa); // cli
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x20b0); // mov al, 0x20
|
||||
phys_writew(physAddress+0x03,(Bit16u)0xa0e6); // out 0xa0, al
|
||||
phys_writew(physAddress+0x05,(Bit16u)0x20e6); // out 0x20, al
|
||||
phys_writew(physAddress+0x07,(Bit16u)0x6166); // popad
|
||||
phys_writeb(physAddress+0x09,(Bit8u)0x07); // pop es
|
||||
phys_writeb(physAddress+0x0a,(Bit8u)0x1f); // pop ds
|
||||
phys_writeb(physAddress+0x0b,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x10:0x0c);
|
||||
case CB_IRQ6_PCJR: // pcjr keyboard interrupt
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x60e4); // in al, 0x60
|
||||
phys_writew(physAddress+0x03,(Bit16u)0xe03c); // cmp al, 0xe0
|
||||
if (use_cb) {
|
||||
phys_writew(physAddress+0x05,(Bit16u)0x0674); // je skip
|
||||
phys_writeb(physAddress+0x07,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x08,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x09,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
} else {
|
||||
phys_writew(physAddress+0x05,(Bit16u)0x0274); // je skip
|
||||
}
|
||||
phys_writew(physAddress+0x07,(Bit16u)0x09cd); // int 9
|
||||
// jump here to (skip):
|
||||
phys_writeb(physAddress+0x09,(Bit8u)0xfa); // cli
|
||||
phys_writew(physAddress+0x0a,(Bit16u)0x20b0); // mov al, 0x20
|
||||
phys_writew(physAddress+0x0c,(Bit16u)0x20e6); // out 0x20, al
|
||||
phys_writeb(physAddress+0x0e,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x0f,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x14:0x10);
|
||||
case CB_MOUSE:
|
||||
phys_writew(physAddress+0x00,(Bit16u)0x07eb); // jmp i33hd
|
||||
physAddress+=9;
|
||||
// jump here to (i33hd):
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xCF); //An IRET Instruction
|
||||
return (use_cb?0x0e:0x0a);
|
||||
case CB_INT16:
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFB); //STI
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x03, callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xCF); //An IRET Instruction
|
||||
for (Bitu i=0;i<=0x0b;i++) phys_writeb(physAddress+0x02+i,0x90);
|
||||
phys_writew(physAddress+0x0e,(Bit16u)0xedeb); //jmp callback
|
||||
return (use_cb?0x10:0x0c);
|
||||
case CB_INT29: // fast console output
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x0eb4); // mov ah, 0x0e
|
||||
phys_writew(physAddress+0x03,(Bit16u)0x10cd); // int 10
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x0b:0x07);
|
||||
case CB_HOOKABLE:
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xEB); //jump near
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x03); //offset
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0x90); //NOP
|
||||
phys_writeb(physAddress+0x03,(Bit8u)0x90); //NOP
|
||||
phys_writeb(physAddress+0x04,(Bit8u)0x90); //NOP
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x07,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x05,(Bit8u)0xCB); //A RETF Instruction
|
||||
return (use_cb?0x0a:0x06);
|
||||
case CB_TDE_IRET: // TandyDAC end transfer
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x02,callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x50); // push ax
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xb8); // mov ax, 0x91fb
|
||||
phys_writew(physAddress+0x02,(Bit16u)0x91fb);
|
||||
phys_writew(physAddress+0x04,(Bit16u)0x15cd); // int 15
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0xfa); // cli
|
||||
phys_writew(physAddress+0x07,(Bit16u)0x20b0); // mov al, 0x20
|
||||
phys_writew(physAddress+0x09,(Bit16u)0x20e6); // out 0x20, al
|
||||
phys_writeb(physAddress+0x0b,(Bit8u)0x58); // pop ax
|
||||
phys_writeb(physAddress+0x0c,(Bit8u)0xcf); //An IRET Instruction
|
||||
return (use_cb?0x11:0x0d);
|
||||
/* case CB_IPXESR: // IPX ESR
|
||||
if (!use_cb) E_Exit("ipx esr must implement a callback handler!");
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0x1e); // push ds
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0x06); // push es
|
||||
phys_writew(physAddress+0x02,(Bit16u)0xa00f); // push fs
|
||||
phys_writew(physAddress+0x04,(Bit16u)0xa80f); // push gs
|
||||
phys_writeb(physAddress+0x06,(Bit8u)0x60); // pusha
|
||||
phys_writeb(physAddress+0x07,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x08,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x09,callback); //The immediate word
|
||||
phys_writeb(physAddress+0x0b,(Bit8u)0xCB); //A RETF Instruction
|
||||
return 0x0c;
|
||||
case CB_IPXESR_RET: // IPX ESR return
|
||||
if (use_cb) E_Exit("ipx esr return must not implement a callback handler!");
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xfa); // cli
|
||||
phys_writew(physAddress+0x01,(Bit16u)0x20b0); // mov al, 0x20
|
||||
phys_writew(physAddress+0x03,(Bit16u)0xa0e6); // out 0xa0, al
|
||||
phys_writew(physAddress+0x05,(Bit16u)0x20e6); // out 0x20, al
|
||||
phys_writeb(physAddress+0x07,(Bit8u)0x61); // popa
|
||||
phys_writew(physAddress+0x08,(Bit16u)0xA90F); // pop gs
|
||||
phys_writew(physAddress+0x0a,(Bit16u)0xA10F); // pop fs
|
||||
phys_writeb(physAddress+0x0c,(Bit8u)0x07); // pop es
|
||||
phys_writeb(physAddress+0x0d,(Bit8u)0x1f); // pop ds
|
||||
phys_writeb(physAddress+0x0e,(Bit8u)0xcf); //An IRET Instruction
|
||||
return 0x0f; */
|
||||
case CB_INT21:
|
||||
phys_writeb(physAddress+0x00,(Bit8u)0xFB); //STI
|
||||
if (use_cb) {
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xFE); //GRP 4
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0x38); //Extra Callback instruction
|
||||
phys_writew(physAddress+0x03, callback); //The immediate word
|
||||
physAddress+=4;
|
||||
}
|
||||
phys_writeb(physAddress+0x01,(Bit8u)0xCF); //An IRET Instruction
|
||||
phys_writeb(physAddress+0x02,(Bit8u)0xCB); //A RETF Instruction
|
||||
return (use_cb?7:3);
|
||||
|
||||
default:
|
||||
E_Exit("CALLBACK:Setup:Illegal type %d",type);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,const char* descr) {
|
||||
if (callback>=CB_MAX) return false;
|
||||
CALLBACK_SetupExtra(callback,type,CALLBACK_PhysPointer(callback)+0,(handler!=NULL));
|
||||
CallBack_Handlers[callback]=handler;
|
||||
CALLBACK_SetDescription(callback,descr);
|
||||
return true;
|
||||
}
|
||||
|
||||
Bitu CALLBACK_Setup(Bitu callback,CallBack_Handler handler,Bitu type,PhysPt addr,const char* descr) {
|
||||
if (callback>=CB_MAX) return 0;
|
||||
Bitu csize=CALLBACK_SetupExtra(callback,type,addr,(handler!=NULL));
|
||||
if (csize>0) {
|
||||
CallBack_Handlers[callback]=handler;
|
||||
CALLBACK_SetDescription(callback,descr);
|
||||
}
|
||||
return csize;
|
||||
}
|
||||
|
||||
void CALLBACK_RemoveSetup(Bitu callback) {
|
||||
for (Bitu i = 0;i < 16;i++) {
|
||||
phys_writeb(CALLBACK_PhysPointer(callback)+i ,(Bit8u) 0x00);
|
||||
}
|
||||
}
|
||||
|
||||
CALLBACK_HandlerObject::~CALLBACK_HandlerObject(){
|
||||
if(!installed) return;
|
||||
if(m_type == CALLBACK_HandlerObject::SETUP) {
|
||||
if(vectorhandler.installed){
|
||||
//See if we are the current handler. if so restore the old one
|
||||
if(RealGetVec(vectorhandler.interrupt) == Get_RealPointer()) {
|
||||
RealSetVec(vectorhandler.interrupt,vectorhandler.old_vector);
|
||||
} else
|
||||
LOG(LOG_MISC,LOG_WARN)("Interrupt vector changed on %X %s",vectorhandler.interrupt,CALLBACK_GetDescription(m_callback));
|
||||
}
|
||||
CALLBACK_RemoveSetup(m_callback);
|
||||
} else if(m_type == CALLBACK_HandlerObject::SETUPAT){
|
||||
E_Exit("Callback:SETUP at not handled yet.");
|
||||
} else if(m_type == CALLBACK_HandlerObject::NONE){
|
||||
//Do nothing. Merely DeAllocate the callback
|
||||
} else E_Exit("what kind of callback is this!");
|
||||
if(CallBack_Description[m_callback]) delete [] CallBack_Description[m_callback];
|
||||
CallBack_Description[m_callback] = 0;
|
||||
CALLBACK_DeAllocate(m_callback);
|
||||
}
|
||||
|
||||
void CALLBACK_HandlerObject::Install(CallBack_Handler handler,Bitu type,const char* description){
|
||||
if(!installed) {
|
||||
installed=true;
|
||||
m_type=SETUP;
|
||||
m_callback=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(m_callback,handler,type,description);
|
||||
} else E_Exit("Allready installed");
|
||||
}
|
||||
void CALLBACK_HandlerObject::Install(CallBack_Handler handler,Bitu type,PhysPt addr,const char* description){
|
||||
if(!installed) {
|
||||
installed=true;
|
||||
m_type=SETUP;
|
||||
m_callback=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(m_callback,handler,type,addr,description);
|
||||
} else E_Exit("Allready installed");
|
||||
}
|
||||
|
||||
void CALLBACK_HandlerObject::Allocate(CallBack_Handler handler,const char* description) {
|
||||
if(!installed) {
|
||||
installed=true;
|
||||
m_type=NONE;
|
||||
m_callback=CALLBACK_Allocate();
|
||||
CALLBACK_SetDescription(m_callback,description);
|
||||
CallBack_Handlers[m_callback]=handler;
|
||||
} else E_Exit("Allready installed");
|
||||
}
|
||||
|
||||
void CALLBACK_HandlerObject::Set_RealVec(Bit8u vec){
|
||||
if(!vectorhandler.installed) {
|
||||
vectorhandler.installed=true;
|
||||
vectorhandler.interrupt=vec;
|
||||
RealSetVec(vec,Get_RealPointer(),vectorhandler.old_vector);
|
||||
} else E_Exit ("double usage of vector handler");
|
||||
}
|
||||
|
||||
void CALLBACK_Init(Section* sec) {
|
||||
Bitu i;
|
||||
for (i=0;i<CB_MAX;i++) {
|
||||
CallBack_Handlers[i]=&illegal_handler;
|
||||
}
|
||||
|
||||
/* Setup the Stop Handler */
|
||||
call_stop=CALLBACK_Allocate();
|
||||
CallBack_Handlers[call_stop]=stop_handler;
|
||||
CALLBACK_SetDescription(call_stop,"stop");
|
||||
phys_writeb(CALLBACK_PhysPointer(call_stop)+0,0xFE);
|
||||
phys_writeb(CALLBACK_PhysPointer(call_stop)+1,0x38);
|
||||
phys_writew(CALLBACK_PhysPointer(call_stop)+2,call_stop);
|
||||
|
||||
/* Setup the idle handler */
|
||||
call_idle=CALLBACK_Allocate();
|
||||
CallBack_Handlers[call_idle]=stop_handler;
|
||||
CALLBACK_SetDescription(call_idle,"idle");
|
||||
for (i=0;i<=11;i++) phys_writeb(CALLBACK_PhysPointer(call_idle)+i,0x90);
|
||||
phys_writeb(CALLBACK_PhysPointer(call_idle)+12,0xFE);
|
||||
phys_writeb(CALLBACK_PhysPointer(call_idle)+13,0x38);
|
||||
phys_writew(CALLBACK_PhysPointer(call_idle)+14,call_idle);
|
||||
|
||||
/* Default handlers for unhandled interrupts that have to be non-null */
|
||||
call_default=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_default,&default_handler,CB_IRET,"default");
|
||||
call_default2=CALLBACK_Allocate();
|
||||
CALLBACK_Setup(call_default2,&default_handler,CB_IRET,"default");
|
||||
|
||||
/* Only setup default handler for first half of interrupt table */
|
||||
for (i=0;i<0x40;i++) {
|
||||
real_writed(0,i*4,CALLBACK_RealPointer(call_default));
|
||||
}
|
||||
/* Setup block of 0xCD 0xxx instructions */
|
||||
PhysPt rint_base=(CB_SEG << 4)+CB_MAX*CB_SIZE;
|
||||
for (i=0;i<=0xff;i++) {
|
||||
phys_writeb(rint_base,0xCD);
|
||||
phys_writeb(rint_base+1,i);
|
||||
phys_writeb(rint_base+2,0xFE);
|
||||
phys_writeb(rint_base+3,0x38);
|
||||
phys_writew(rint_base+4,call_stop);
|
||||
rint_base+=6;
|
||||
|
||||
}
|
||||
// setup a few interrupt handlers that point to bios IRETs by default
|
||||
real_writed(0,0x0e*4,CALLBACK_RealPointer(call_default2)); //design your own railroad
|
||||
real_writed(0,0x66*4,CALLBACK_RealPointer(call_default)); //war2d
|
||||
real_writed(0,0x67*4,CALLBACK_RealPointer(call_default));
|
||||
real_writed(0,0x68*4,CALLBACK_RealPointer(call_default));
|
||||
real_writed(0,0x5c*4,CALLBACK_RealPointer(call_default)); //Network stuff
|
||||
//real_writed(0,0xf*4,0); some games don't like it
|
||||
|
||||
call_priv_io=CALLBACK_Allocate();
|
||||
|
||||
// virtualizable in-out opcodes
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x00,(Bit8u)0xec); // in al, dx
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x01,(Bit8u)0xcb); // retf
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x02,(Bit8u)0xed); // in ax, dx
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x03,(Bit8u)0xcb); // retf
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x04,(Bit8u)0x66); // in eax, dx
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x05,(Bit8u)0xed);
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x06,(Bit8u)0xcb); // retf
|
||||
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x08,(Bit8u)0xee); // out dx, al
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x09,(Bit8u)0xcb); // retf
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0a,(Bit8u)0xef); // out dx, ax
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0b,(Bit8u)0xcb); // retf
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0c,(Bit8u)0x66); // out dx, eax
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0d,(Bit8u)0xef);
|
||||
phys_writeb(CALLBACK_PhysPointer(call_priv_io)+0x0e,(Bit8u)0xcb); // retf
|
||||
}
|
476
src/cpu/core_dyn_x86.cpp
Normal file
476
src/cpu/core_dyn_x86.cpp
Normal file
@ -0,0 +1,476 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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: core_dyn_x86.cpp,v 1.34 2007/11/24 17:26:48 c2woody Exp $ */
|
||||
|
||||
#include "dosbox.h"
|
||||
|
||||
#if (C_DYNAMIC_X86)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined (WIN32)
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#if (C_HAVE_MPROTECT)
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef PAGESIZE
|
||||
#define PAGESIZE 4096
|
||||
#endif
|
||||
#endif /* C_HAVE_MPROTECT */
|
||||
|
||||
#include "callback.h"
|
||||
#include "regs.h"
|
||||
#include "mem.h"
|
||||
#include "cpu.h"
|
||||
#include "debug.h"
|
||||
#include "paging.h"
|
||||
#include "inout.h"
|
||||
#include "fpu.h"
|
||||
|
||||
#define CACHE_MAXSIZE (4096*3)
|
||||
#define CACHE_TOTAL (1024*1024*8)
|
||||
#define CACHE_PAGES (512)
|
||||
#define CACHE_BLOCKS (64*1024)
|
||||
#define CACHE_ALIGN (16)
|
||||
#define DYN_HASH_SHIFT (4)
|
||||
#define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT)
|
||||
#define DYN_LINKS (16)
|
||||
|
||||
#if 0
|
||||
#define DYN_LOG LOG_MSG
|
||||
#else
|
||||
#define DYN_LOG
|
||||
#endif
|
||||
|
||||
#if C_FPU
|
||||
#define CPU_FPU 1 //Enable FPU escape instructions
|
||||
#endif
|
||||
|
||||
enum {
|
||||
G_EAX,G_ECX,G_EDX,G_EBX,
|
||||
G_ESP,G_EBP,G_ESI,G_EDI,
|
||||
G_ES,G_CS,G_SS,G_DS,G_FS,G_GS,
|
||||
G_FLAGS,G_NEWESP,G_EIP,
|
||||
G_EA,G_STACK,G_CYCLES,
|
||||
G_TMPB,G_TMPW,G_SHIFT,
|
||||
G_EXIT,
|
||||
G_MAX,
|
||||
};
|
||||
|
||||
enum SingleOps {
|
||||
SOP_INC,SOP_DEC,
|
||||
SOP_NOT,SOP_NEG,
|
||||
};
|
||||
|
||||
enum DualOps {
|
||||
DOP_ADD,DOP_ADC,
|
||||
DOP_SUB,DOP_SBB,
|
||||
DOP_CMP,DOP_XOR,
|
||||
DOP_AND,DOP_OR,
|
||||
DOP_TEST,
|
||||
DOP_MOV,
|
||||
DOP_XCHG,
|
||||
};
|
||||
|
||||
enum ShiftOps {
|
||||
SHIFT_ROL,SHIFT_ROR,
|
||||
SHIFT_RCL,SHIFT_RCR,
|
||||
SHIFT_SHL,SHIFT_SHR,
|
||||
SHIFT_SAL,SHIFT_SAR,
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
|
||||
enum BlockReturn {
|
||||
BR_Normal=0,
|
||||
BR_Cycles,
|
||||
BR_Link1,BR_Link2,
|
||||
BR_Opcode,
|
||||
#if (C_DEBUG)
|
||||
BR_OpcodeFull,
|
||||
#endif
|
||||
BR_Iret,
|
||||
BR_CallBack,
|
||||
BR_SMCBlock
|
||||
};
|
||||
|
||||
#define SMC_CURRENT_BLOCK 0xffff
|
||||
|
||||
|
||||
#define DYNFLG_HAS16 0x1 //Would like 8-bit host reg support
|
||||
#define DYNFLG_HAS8 0x2 //Would like 16-bit host reg support
|
||||
#define DYNFLG_LOAD 0x4 //Load value when accessed
|
||||
#define DYNFLG_SAVE 0x8 //Needs to be saved back at the end of block
|
||||
#define DYNFLG_CHANGED 0x10 //Value is in a register and changed from load
|
||||
#define DYNFLG_ACTIVE 0x20 //Register has an active value
|
||||
|
||||
class GenReg;
|
||||
class CodePageHandler;
|
||||
|
||||
struct DynReg {
|
||||
Bitu flags;
|
||||
GenReg * genreg;
|
||||
void * data;
|
||||
};
|
||||
|
||||
enum DynAccess {
|
||||
DA_d,DA_w,
|
||||
DA_bh,DA_bl
|
||||
};
|
||||
|
||||
enum ByteCombo {
|
||||
BC_ll,BC_lh,
|
||||
BC_hl,BC_hh,
|
||||
};
|
||||
|
||||
static DynReg DynRegs[G_MAX];
|
||||
#define DREG(_WHICH_) &DynRegs[G_ ## _WHICH_ ]
|
||||
|
||||
static struct {
|
||||
Bitu ea,tmpb,tmpd,stack,shift,newesp;
|
||||
} extra_regs;
|
||||
|
||||
static void IllegalOption(const char* msg) {
|
||||
E_Exit("DynCore: illegal option in %s",msg);
|
||||
}
|
||||
|
||||
#include "core_dyn_x86/cache.h"
|
||||
|
||||
static struct {
|
||||
Bitu callback;
|
||||
Bit32u readdata;
|
||||
} core_dyn;
|
||||
|
||||
static struct {
|
||||
Bit32u state[32];
|
||||
FPU_P_Reg temp,temp2;
|
||||
Bit32u dh_fpu_enabled;
|
||||
Bit32u state_used;
|
||||
Bit32u cw,host_cw;
|
||||
Bit8u temp_state[128];
|
||||
} dyn_dh_fpu;
|
||||
|
||||
|
||||
#include "core_dyn_x86/risc_x86.h"
|
||||
|
||||
struct DynState {
|
||||
DynReg regs[G_MAX];
|
||||
};
|
||||
|
||||
static void dyn_flags_host_to_gen(void) {
|
||||
gen_dop_word(DOP_MOV,true,DREG(EXIT),DREG(FLAGS));
|
||||
gen_dop_word_imm(DOP_AND,true,DREG(EXIT),FMASK_TEST);
|
||||
gen_load_flags(DREG(EXIT));
|
||||
gen_releasereg(DREG(EXIT));
|
||||
gen_releasereg(DREG(FLAGS));
|
||||
}
|
||||
|
||||
static void dyn_flags_gen_to_host(void) {
|
||||
gen_save_flags(DREG(EXIT));
|
||||
gen_dop_word_imm(DOP_AND,true,DREG(EXIT),FMASK_TEST);
|
||||
gen_dop_word_imm(DOP_AND,true,DREG(FLAGS),~FMASK_TEST);
|
||||
gen_dop_word(DOP_OR,true,DREG(FLAGS),DREG(EXIT)); //flags are marked for save
|
||||
gen_releasereg(DREG(EXIT));
|
||||
gen_releasereg(DREG(FLAGS));
|
||||
}
|
||||
|
||||
static void dyn_savestate(DynState * state) {
|
||||
for (Bitu i=0;i<G_MAX;i++) {
|
||||
state->regs[i].flags=DynRegs[i].flags;
|
||||
state->regs[i].genreg=DynRegs[i].genreg;
|
||||
}
|
||||
}
|
||||
|
||||
static void dyn_loadstate(DynState * state) {
|
||||
for (Bitu i=0;i<G_MAX;i++) {
|
||||
gen_setupreg(&DynRegs[i],&state->regs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void dyn_synchstate(DynState * state) {
|
||||
for (Bitu i=0;i<G_MAX;i++) {
|
||||
gen_synchreg(&DynRegs[i],&state->regs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void dyn_saveregister(DynReg * src_reg, DynReg * dst_reg) {
|
||||
dst_reg->flags=src_reg->flags;
|
||||
dst_reg->genreg=src_reg->genreg;
|
||||
}
|
||||
|
||||
static void dyn_restoreregister(DynReg * src_reg, DynReg * dst_reg) {
|
||||
dst_reg->flags=src_reg->flags;
|
||||
dst_reg->genreg=src_reg->genreg;
|
||||
dst_reg->genreg->dynreg=dst_reg; // necessary when register has been released
|
||||
}
|
||||
|
||||
#include "core_dyn_x86/decoder.h"
|
||||
|
||||
#if defined (_MSC_VER)
|
||||
#define DH_FPU_SAVE_REINIT \
|
||||
{ \
|
||||
__asm { \
|
||||
__asm fnsave dyn_dh_fpu.state[0] \
|
||||
} \
|
||||
dyn_dh_fpu.state_used=false; \
|
||||
dyn_dh_fpu.state[0]|=0x3f; \
|
||||
}
|
||||
#else
|
||||
#define DH_FPU_SAVE_REINIT \
|
||||
{ \
|
||||
__asm__ volatile ( \
|
||||
"fnsave %0 \n" \
|
||||
: \
|
||||
: "m" (dyn_dh_fpu.state[0]) \
|
||||
: "memory" \
|
||||
); \
|
||||
dyn_dh_fpu.state_used=false; \
|
||||
dyn_dh_fpu.state[0]|=0x3f; \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
Bits CPU_Core_Dyn_X86_Run(void) {
|
||||
/* Determine the linear address of CS:EIP */
|
||||
restart_core:
|
||||
PhysPt ip_point=SegPhys(cs)+reg_eip;
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
CodePageHandler * chandler=0;
|
||||
if (GCC_UNLIKELY(MakeCodePage(ip_point,chandler))) {
|
||||
CPU_Exception(cpu.exception.which,cpu.exception.error);
|
||||
goto restart_core;
|
||||
}
|
||||
if (!chandler) {
|
||||
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
|
||||
return CPU_Core_Normal_Run();
|
||||
}
|
||||
/* Find correct Dynamic Block to run */
|
||||
CacheBlock * block=chandler->FindCacheBlock(ip_point&4095);
|
||||
if (!block) {
|
||||
if (!chandler->invalidation_map || (chandler->invalidation_map[ip_point&4095]<4)) {
|
||||
block=CreateCacheBlock(chandler,ip_point,32);
|
||||
} else {
|
||||
Bitu old_cycles=CPU_Cycles;
|
||||
CPU_Cycles=1;
|
||||
Bits nc_retcode=CPU_Core_Normal_Run();
|
||||
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
|
||||
if (!nc_retcode) {
|
||||
CPU_Cycles=old_cycles-1;
|
||||
goto restart_core;
|
||||
}
|
||||
CPU_CycleLeft+=old_cycles;
|
||||
return nc_retcode;
|
||||
}
|
||||
}
|
||||
run_block:
|
||||
cache.block.running=0;
|
||||
BlockReturn ret=gen_runcode(block->cache.start);
|
||||
switch (ret) {
|
||||
case BR_Iret:
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) {
|
||||
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
|
||||
return debugCallback;
|
||||
}
|
||||
#endif
|
||||
if (!GETFLAG(TF)) goto restart_core;
|
||||
cpudecoder=CPU_Core_Dyn_X86_Trap_Run;
|
||||
if (!dyn_dh_fpu.state_used) return CBRET_NONE;
|
||||
DH_FPU_SAVE_REINIT
|
||||
return CBRET_NONE;
|
||||
case BR_Normal:
|
||||
/* Maybe check if we staying in the same page? */
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
goto restart_core;
|
||||
case BR_Cycles:
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
if (!dyn_dh_fpu.state_used) return CBRET_NONE;
|
||||
DH_FPU_SAVE_REINIT
|
||||
return CBRET_NONE;
|
||||
case BR_CallBack:
|
||||
if (!dyn_dh_fpu.state_used) return core_dyn.callback;
|
||||
DH_FPU_SAVE_REINIT
|
||||
return core_dyn.callback;
|
||||
case BR_SMCBlock:
|
||||
// LOG_MSG("selfmodification of running block at %x:%x",SegValue(cs),reg_eip);
|
||||
cpu.exception.which=0;
|
||||
// fallthrough, let the normal core handle the block-modifying instruction
|
||||
case BR_Opcode:
|
||||
CPU_CycleLeft+=CPU_Cycles;
|
||||
CPU_Cycles=1;
|
||||
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
|
||||
return CPU_Core_Normal_Run();
|
||||
#if (C_DEBUG)
|
||||
case BR_OpcodeFull:
|
||||
CPU_CycleLeft+=CPU_Cycles;
|
||||
CPU_Cycles=1;
|
||||
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
|
||||
return CPU_Core_Full_Run();
|
||||
#endif
|
||||
case BR_Link1:
|
||||
case BR_Link2:
|
||||
{
|
||||
Bitu temp_ip=SegPhys(cs)+reg_eip;
|
||||
CodePageHandler * temp_handler=(CodePageHandler *)get_tlb_readhandler(temp_ip);
|
||||
if (temp_handler->flags & PFLAG_HASCODE) {
|
||||
block=temp_handler->FindCacheBlock(temp_ip & 4095);
|
||||
if (!block) goto restart_core;
|
||||
cache.block.running->LinkTo(ret==BR_Link2,block);
|
||||
goto run_block;
|
||||
}
|
||||
}
|
||||
goto restart_core;
|
||||
}
|
||||
if (dyn_dh_fpu.state_used) DH_FPU_SAVE_REINIT
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
Bits CPU_Core_Dyn_X86_Trap_Run(void) {
|
||||
Bits oldCycles = CPU_Cycles;
|
||||
CPU_Cycles = 1;
|
||||
cpu.trap_skip = false;
|
||||
|
||||
Bits ret=CPU_Core_Normal_Run();
|
||||
if (!cpu.trap_skip) CPU_HW_Interrupt(1);
|
||||
CPU_Cycles = oldCycles-1;
|
||||
cpudecoder = &CPU_Core_Dyn_X86_Run;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CPU_Core_Dyn_X86_Init(void) {
|
||||
Bits i;
|
||||
/* Setup the global registers and their flags */
|
||||
for (i=0;i<G_MAX;i++) DynRegs[i].genreg=0;
|
||||
DynRegs[G_EAX].data=®_eax;
|
||||
DynRegs[G_EAX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_ECX].data=®_ecx;
|
||||
DynRegs[G_ECX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_EDX].data=®_edx;
|
||||
DynRegs[G_EDX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_EBX].data=®_ebx;
|
||||
DynRegs[G_EBX].flags=DYNFLG_HAS8|DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
|
||||
DynRegs[G_EBP].data=®_ebp;
|
||||
DynRegs[G_EBP].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_ESP].data=®_esp;
|
||||
DynRegs[G_ESP].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_EDI].data=®_edi;
|
||||
DynRegs[G_EDI].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_ESI].data=®_esi;
|
||||
DynRegs[G_ESI].flags=DYNFLG_HAS16|DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
|
||||
DynRegs[G_ES].data=&Segs.phys[es];
|
||||
DynRegs[G_ES].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_CS].data=&Segs.phys[cs];
|
||||
DynRegs[G_CS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_SS].data=&Segs.phys[ss];
|
||||
DynRegs[G_SS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_DS].data=&Segs.phys[ds];
|
||||
DynRegs[G_DS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_FS].data=&Segs.phys[fs];
|
||||
DynRegs[G_FS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_GS].data=&Segs.phys[gs];
|
||||
DynRegs[G_GS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
|
||||
DynRegs[G_FLAGS].data=®_flags;
|
||||
DynRegs[G_FLAGS].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
|
||||
DynRegs[G_NEWESP].data=&extra_regs.newesp;
|
||||
DynRegs[G_NEWESP].flags=0;
|
||||
|
||||
DynRegs[G_EIP].data=®_eip;
|
||||
DynRegs[G_EIP].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
|
||||
DynRegs[G_EA].data=&extra_regs.ea;
|
||||
DynRegs[G_EA].flags=0;
|
||||
DynRegs[G_STACK].data=&extra_regs.stack;
|
||||
DynRegs[G_STACK].flags=0;
|
||||
DynRegs[G_CYCLES].data=&CPU_Cycles;
|
||||
DynRegs[G_CYCLES].flags=DYNFLG_LOAD|DYNFLG_SAVE;
|
||||
DynRegs[G_TMPB].data=&extra_regs.tmpb;
|
||||
DynRegs[G_TMPB].flags=DYNFLG_HAS8|DYNFLG_HAS16;
|
||||
DynRegs[G_TMPW].data=&extra_regs.tmpd;
|
||||
DynRegs[G_TMPW].flags=DYNFLG_HAS16;
|
||||
DynRegs[G_SHIFT].data=&extra_regs.shift;
|
||||
DynRegs[G_SHIFT].flags=DYNFLG_HAS8|DYNFLG_HAS16;
|
||||
DynRegs[G_EXIT].data=0;
|
||||
DynRegs[G_EXIT].flags=DYNFLG_HAS16;
|
||||
/* Init the generator */
|
||||
gen_init();
|
||||
|
||||
/* Init the fpu state */
|
||||
dyn_dh_fpu.dh_fpu_enabled=true;
|
||||
dyn_dh_fpu.state_used=false;
|
||||
dyn_dh_fpu.cw=0x37f;
|
||||
#if defined (_MSC_VER)
|
||||
__asm {
|
||||
__asm finit
|
||||
__asm fsave dyn_dh_fpu.state[0]
|
||||
__asm fstcw dyn_dh_fpu.host_cw
|
||||
}
|
||||
#else
|
||||
__asm__ volatile (
|
||||
"finit \n"
|
||||
"fsave %0 \n"
|
||||
"fstcw %1 \n"
|
||||
:
|
||||
: "m" (dyn_dh_fpu.state[0]), "m" (dyn_dh_fpu.host_cw)
|
||||
: "memory"
|
||||
);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void CPU_Core_Dyn_X86_Cache_Init(bool enable_cache) {
|
||||
/* Initialize code cache and dynamic blocks */
|
||||
cache_init(enable_cache);
|
||||
}
|
||||
|
||||
void CPU_Core_Dyn_X86_Cache_Close(void) {
|
||||
cache_close();
|
||||
}
|
||||
|
||||
void CPU_Core_Dyn_X86_SetFPUMode(bool dh_fpu) {
|
||||
dyn_dh_fpu.dh_fpu_enabled=dh_fpu;
|
||||
}
|
||||
|
||||
#endif
|
2
src/cpu/core_dyn_x86/Makefile.am
Normal file
2
src/cpu/core_dyn_x86/Makefile.am
Normal file
@ -0,0 +1,2 @@
|
||||
noinst_HEADERS = cache.h helpers.h decoder.h risc_x86.h string.h \
|
||||
dyn_fpu.h dyn_fpu_dh.h
|
528
src/cpu/core_dyn_x86/cache.h
Normal file
528
src/cpu/core_dyn_x86/cache.h
Normal file
@ -0,0 +1,528 @@
|
||||
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){
|
||||
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){
|
||||
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){
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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;i<block->cache.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 (size<CACHE_MAXSIZE) {
|
||||
if (!nextblock)
|
||||
goto skipresize;
|
||||
size+=nextblock->cache.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;i<CACHE_BLOCKS-1;i++) {
|
||||
cache_blocks[i].link[0].to=(CacheBlock *)1;
|
||||
cache_blocks[i].link[1].to=(CacheBlock *)1;
|
||||
cache_blocks[i].cache.next=&cache_blocks[i+1];
|
||||
}
|
||||
}
|
||||
if (cache_code_start_ptr==NULL) {
|
||||
#if defined (WIN32)
|
||||
cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
|
||||
MEM_COMMIT,PAGE_EXECUTE_READWRITE);
|
||||
if (!cache_code_start_ptr)
|
||||
cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
|
||||
#else
|
||||
cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
|
||||
#endif
|
||||
if(!cache_code_start_ptr) E_Exit("Allocating dynamic core cache memory failed");
|
||||
|
||||
cache_code=(Bit8u*)(((int)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //MEM LEAK. store old pointer if you want to free it.
|
||||
|
||||
cache_code_link_blocks=cache_code;
|
||||
cache_code+=PAGESIZE_TEMP;
|
||||
|
||||
#if (C_HAVE_MPROTECT)
|
||||
if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
|
||||
LOG_MSG("Setting excute permission on the code cache has failed!");
|
||||
#endif
|
||||
CacheBlock * block=cache_getblock();
|
||||
cache.block.first=block;
|
||||
cache.block.active=block;
|
||||
block->cache.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;i<CACHE_PAGES;i++) {
|
||||
CodePageHandler * newpage=new CodePageHandler();
|
||||
newpage->next=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; */
|
||||
}
|
2680
src/cpu/core_dyn_x86/decoder.h
Normal file
2680
src/cpu/core_dyn_x86/decoder.h
Normal file
File diff suppressed because it is too large
Load Diff
665
src/cpu/core_dyn_x86/dyn_fpu.h
Normal file
665
src/cpu/core_dyn_x86/dyn_fpu.h
Normal file
@ -0,0 +1,665 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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.3 2007/06/14 17:47:24 c2woody Exp $ */
|
||||
|
||||
#include "dosbox.h"
|
||||
#if C_FPU
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#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 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
|
494
src/cpu/core_dyn_x86/dyn_fpu_dh.h
Normal file
494
src/cpu/core_dyn_x86/dyn_fpu_dh.h
Normal file
@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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.5 2007/09/29 13:23:59 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 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
|
69
src/cpu/core_dyn_x86/helpers.h
Normal file
69
src/cpu/core_dyn_x86/helpers.h
Normal file
@ -0,0 +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;
|
||||
}
|
1072
src/cpu/core_dyn_x86/risc_x86.h
Normal file
1072
src/cpu/core_dyn_x86/risc_x86.h
Normal file
File diff suppressed because it is too large
Load Diff
164
src/cpu/core_dyn_x86/string.h
Normal file
164
src/cpu/core_dyn_x86/string.h
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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));
|
||||
}
|
327
src/cpu/core_dynrec.cpp
Normal file
327
src/cpu/core_dynrec.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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: core_dynrec.cpp,v 1.11 2008/09/19 16:48:02 c2woody Exp $ */
|
||||
|
||||
#include "dosbox.h"
|
||||
|
||||
#if (C_DYNREC)
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined (WIN32)
|
||||
#include <windows.h>
|
||||
#include <winbase.h>
|
||||
#endif
|
||||
|
||||
#if (C_HAVE_MPROTECT)
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <limits.h>
|
||||
#ifndef PAGESIZE
|
||||
#define PAGESIZE 4096
|
||||
#endif
|
||||
#endif /* C_HAVE_MPROTECT */
|
||||
|
||||
#include "callback.h"
|
||||
#include "regs.h"
|
||||
#include "mem.h"
|
||||
#include "cpu.h"
|
||||
#include "debug.h"
|
||||
#include "paging.h"
|
||||
#include "inout.h"
|
||||
#include "lazyflags.h"
|
||||
|
||||
#define CACHE_MAXSIZE (4096*2)
|
||||
#define CACHE_TOTAL (1024*1024*8)
|
||||
#define CACHE_PAGES (512)
|
||||
#define CACHE_BLOCKS (128*1024)
|
||||
#define CACHE_ALIGN (16)
|
||||
#define DYN_HASH_SHIFT (4)
|
||||
#define DYN_PAGE_HASH (4096>>DYN_HASH_SHIFT)
|
||||
#define DYN_LINKS (16)
|
||||
|
||||
#if 0
|
||||
#define DYN_LOG LOG_MSG
|
||||
#else
|
||||
#define DYN_LOG
|
||||
#endif
|
||||
|
||||
#if C_FPU
|
||||
#define CPU_FPU 1 //Enable FPU escape instructions
|
||||
#endif
|
||||
|
||||
|
||||
// the emulated x86 registers
|
||||
#define DRC_REG_EAX 0
|
||||
#define DRC_REG_ECX 1
|
||||
#define DRC_REG_EDX 2
|
||||
#define DRC_REG_EBX 3
|
||||
#define DRC_REG_ESP 4
|
||||
#define DRC_REG_EBP 5
|
||||
#define DRC_REG_ESI 6
|
||||
#define DRC_REG_EDI 7
|
||||
|
||||
// the emulated x86 segment registers
|
||||
#define DRC_SEG_ES 0
|
||||
#define DRC_SEG_CS 1
|
||||
#define DRC_SEG_SS 2
|
||||
#define DRC_SEG_DS 3
|
||||
#define DRC_SEG_FS 4
|
||||
#define DRC_SEG_GS 5
|
||||
|
||||
|
||||
// access to a general register
|
||||
#define DRCD_REG_VAL(reg) (&cpu_regs.regs[reg].dword)
|
||||
// access to a segment register
|
||||
#define DRCD_SEG_VAL(seg) (&Segs.val[seg])
|
||||
// access to the physical value of a segment register/selector
|
||||
#define DRCD_SEG_PHYS(seg) (&Segs.phys[seg])
|
||||
|
||||
// access to an 8bit general register
|
||||
#define DRCD_REG_BYTE(reg,idx) (&cpu_regs.regs[reg].byte[idx])
|
||||
// access to 16/32bit general registers
|
||||
#define DRCD_REG_WORD(reg,dwrd) ((dwrd)?((void*)(&cpu_regs.regs[reg].dword)):((void*)(&cpu_regs.regs[reg].word)))
|
||||
|
||||
|
||||
enum BlockReturn {
|
||||
BR_Normal=0,
|
||||
BR_Cycles,
|
||||
BR_Link1,BR_Link2,
|
||||
BR_Opcode,
|
||||
#if (C_DEBUG)
|
||||
BR_OpcodeFull,
|
||||
#endif
|
||||
BR_Iret,
|
||||
BR_CallBack,
|
||||
BR_SMCBlock
|
||||
};
|
||||
|
||||
// identificator to signal self-modification of the currently executed block
|
||||
#define SMC_CURRENT_BLOCK 0xffff
|
||||
|
||||
|
||||
static void IllegalOptionDynrec(const char* msg) {
|
||||
E_Exit("DynrecCore: illegal option in %s",msg);
|
||||
}
|
||||
|
||||
static struct {
|
||||
BlockReturn (*runcode)(Bit8u*); // points to code that can start a block
|
||||
Bitu callback; // the occurred callback
|
||||
Bitu readdata; // spare space used when reading from memory
|
||||
Bit32u protected_regs[8]; // space to save/restore register values
|
||||
} core_dynrec;
|
||||
|
||||
|
||||
#include "core_dynrec/cache.h"
|
||||
|
||||
#define X86 0x01
|
||||
#define X86_64 0x02
|
||||
#define MIPSEL 0x03
|
||||
#define ARMV4LE 0x04
|
||||
|
||||
#if C_TARGETCPU == X86_64
|
||||
#include "core_dynrec/risc_x64.h"
|
||||
#elif C_TARGETCPU == X86
|
||||
#include "core_dynrec/risc_x86.h"
|
||||
#elif C_TARGETCPU == MIPSEL
|
||||
#include "core_dynrec/risc_mipsel32.h"
|
||||
#elif C_TARGETCPU == ARMV4LE
|
||||
#include "core_dynrec/risc_armv4le.h"
|
||||
#endif
|
||||
|
||||
#include "core_dynrec/decoder.h"
|
||||
|
||||
CacheBlockDynRec * LinkBlocks(BlockReturn ret) {
|
||||
CacheBlockDynRec * block=NULL;
|
||||
// the last instruction was a control flow modifying instruction
|
||||
Bitu temp_ip=SegPhys(cs)+reg_eip;
|
||||
CodePageHandlerDynRec * temp_handler=(CodePageHandlerDynRec *)get_tlb_readhandler(temp_ip);
|
||||
if (temp_handler->flags & PFLAG_HASCODE) {
|
||||
// see if the target is an already translated block
|
||||
block=temp_handler->FindCacheBlock(temp_ip & 4095);
|
||||
if (!block) return NULL;
|
||||
|
||||
// found it, link the current block to
|
||||
cache.block.running->LinkTo(ret==BR_Link2,block);
|
||||
return block;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
The core tries to find the block that should be executed next.
|
||||
If such a block is found, it is run, otherwise the instruction
|
||||
stream starting at ip_point is translated (see decoder.h) and
|
||||
makes up a new code block that will be run.
|
||||
When control is returned to CPU_Core_Dynrec_Run (which might
|
||||
be right after the block is run, or somewhen long after that
|
||||
due to the direct cacheblock linking) the returncode decides
|
||||
the next action. This might be continuing the translation and
|
||||
execution process, or returning from the core etc.
|
||||
*/
|
||||
|
||||
Bits CPU_Core_Dynrec_Run(void) {
|
||||
for (;;) {
|
||||
// Determine the linear address of CS:EIP
|
||||
PhysPt ip_point=SegPhys(cs)+reg_eip;
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
|
||||
CodePageHandlerDynRec * chandler=0;
|
||||
// see if the current page is present and contains code
|
||||
if (GCC_UNLIKELY(MakeCodePage(ip_point,chandler))) {
|
||||
// page not present, throw the exception
|
||||
CPU_Exception(cpu.exception.which,cpu.exception.error);
|
||||
continue;
|
||||
}
|
||||
|
||||
// page doesn't contain code or is special
|
||||
if (GCC_UNLIKELY(!chandler)) return CPU_Core_Normal_Run();
|
||||
|
||||
// find correct Dynamic Block to run
|
||||
CacheBlockDynRec * block=chandler->FindCacheBlock(ip_point&4095);
|
||||
if (!block) {
|
||||
// no block found, thus translate the instruction stream
|
||||
// unless the instruction is known to be modified
|
||||
if (!chandler->invalidation_map || (chandler->invalidation_map[ip_point&4095]<4)) {
|
||||
// translate up to 32 instructions
|
||||
block=CreateCacheBlock(chandler,ip_point,32);
|
||||
} else {
|
||||
// let the normal core handle this instruction to avoid zero-sized blocks
|
||||
Bitu old_cycles=CPU_Cycles;
|
||||
CPU_Cycles=1;
|
||||
Bits nc_retcode=CPU_Core_Normal_Run();
|
||||
if (!nc_retcode) {
|
||||
CPU_Cycles=old_cycles-1;
|
||||
continue;
|
||||
}
|
||||
CPU_CycleLeft+=old_cycles;
|
||||
return nc_retcode;
|
||||
}
|
||||
}
|
||||
|
||||
run_block:
|
||||
cache.block.running=0;
|
||||
// now we're ready to run the dynamic code block
|
||||
// BlockReturn ret=((BlockReturn (*)(void))(block->cache.start))();
|
||||
BlockReturn ret=core_dynrec.runcode(block->cache.start);
|
||||
|
||||
switch (ret) {
|
||||
case BR_Iret:
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
if (!GETFLAG(TF)) break;
|
||||
// trapflag is set, switch to the trap-aware decoder
|
||||
cpudecoder=CPU_Core_Dynrec_Trap_Run;
|
||||
return CBRET_NONE;
|
||||
|
||||
case BR_Normal:
|
||||
// the block was exited due to a non-predictable control flow
|
||||
// modifying instruction (like ret) or some nontrivial cpu state
|
||||
// changing instruction (for example switch to/from pmode),
|
||||
// or the maximal number of instructions to translate was reached
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case BR_Cycles:
|
||||
// cycles went negative, return from the core to handle
|
||||
// external events, schedule the pic...
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) return debugCallback;
|
||||
#endif
|
||||
return CBRET_NONE;
|
||||
|
||||
case BR_CallBack:
|
||||
// the callback code is executed in dosbox.conf, return the callback number
|
||||
FillFlags();
|
||||
return core_dynrec.callback;
|
||||
|
||||
case BR_SMCBlock:
|
||||
// LOG_MSG("selfmodification of running block at %x:%x",SegValue(cs),reg_eip);
|
||||
cpu.exception.which=0;
|
||||
// fallthrough, let the normal core handle the block-modifying instruction
|
||||
case BR_Opcode:
|
||||
// some instruction has been encountered that could not be translated
|
||||
// (thus it is not part of the code block), the normal core will
|
||||
// handle this instruction
|
||||
CPU_CycleLeft+=CPU_Cycles;
|
||||
CPU_Cycles=1;
|
||||
return CPU_Core_Normal_Run();
|
||||
|
||||
#if (C_DEBUG)
|
||||
case BR_OpcodeFull:
|
||||
CPU_CycleLeft+=CPU_Cycles;
|
||||
CPU_Cycles=1;
|
||||
return CPU_Core_Full_Run();
|
||||
#endif
|
||||
|
||||
case BR_Link1:
|
||||
case BR_Link2:
|
||||
block=LinkBlocks(ret);
|
||||
if (block) goto run_block;
|
||||
break;
|
||||
|
||||
default:
|
||||
E_Exit("Invalid return code %d", ret);
|
||||
}
|
||||
}
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
Bits CPU_Core_Dynrec_Trap_Run(void) {
|
||||
Bits oldCycles = CPU_Cycles;
|
||||
CPU_Cycles = 1;
|
||||
cpu.trap_skip = false;
|
||||
|
||||
// let the normal core execute the next (only one!) instruction
|
||||
Bits ret=CPU_Core_Normal_Run();
|
||||
|
||||
// trap to int1 unless the last instruction deferred this
|
||||
// (allows hardware interrupts to be served without interaction)
|
||||
if (!cpu.trap_skip) CPU_HW_Interrupt(1);
|
||||
|
||||
CPU_Cycles = oldCycles-1;
|
||||
// continue (either the trapflag was clear anyways, or the int1 cleared it)
|
||||
cpudecoder = &CPU_Core_Dynrec_Run;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CPU_Core_Dynrec_Init(void) {
|
||||
}
|
||||
|
||||
void CPU_Core_Dynrec_Cache_Init(bool enable_cache) {
|
||||
// Initialize code cache and dynamic blocks
|
||||
cache_init(enable_cache);
|
||||
}
|
||||
|
||||
void CPU_Core_Dynrec_Cache_Close(void) {
|
||||
cache_close();
|
||||
}
|
||||
|
||||
#endif
|
5
src/cpu/core_dynrec/Makefile.am
Normal file
5
src/cpu/core_dynrec/Makefile.am
Normal file
@ -0,0 +1,5 @@
|
||||
noinst_HEADERS = cache.h decoder.h decoder_basic.h decoder_opcodes.h \
|
||||
dyn_fpu.h operators.h risc_x64.h risc_x86.h risc_mipsel32.h \
|
||||
risc_armv4le.h risc_armv4le-common.h \
|
||||
risc_armv4le-s3.h risc_armv4le-o3.h risc_armv4le-thumb.h \
|
||||
risc_armv4le-thumb-iw.h risc_armv4le-thumb-niw.h
|
665
src/cpu/core_dynrec/cache.h
Normal file
665
src/cpu/core_dynrec/cache.h
Normal file
@ -0,0 +1,665 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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;i<block->cache.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 (size<CACHE_MAXSIZE) {
|
||||
if (!nextblock)
|
||||
goto skipresize;
|
||||
// merge blocks
|
||||
size+=nextblock->cache.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;i<CACHE_BLOCKS-1;i++) {
|
||||
cache_blocks[i].link[0].to=(CacheBlockDynRec *)1;
|
||||
cache_blocks[i].link[1].to=(CacheBlockDynRec *)1;
|
||||
cache_blocks[i].cache.next=&cache_blocks[i+1];
|
||||
}
|
||||
}
|
||||
if (cache_code_start_ptr==NULL) {
|
||||
// allocate the code cache memory
|
||||
#if defined (WIN32)
|
||||
cache_code_start_ptr=(Bit8u*)VirtualAlloc(0,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP,
|
||||
MEM_COMMIT,PAGE_EXECUTE_READWRITE);
|
||||
if (!cache_code_start_ptr)
|
||||
cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
|
||||
#else
|
||||
cache_code_start_ptr=(Bit8u*)malloc(CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP-1+PAGESIZE_TEMP);
|
||||
#endif
|
||||
if(!cache_code_start_ptr) E_Exit("Allocating dynamic cache failed");
|
||||
|
||||
// align the cache at a page boundary
|
||||
cache_code=(Bit8u*)(((long)cache_code_start_ptr + PAGESIZE_TEMP-1) & ~(PAGESIZE_TEMP-1)); //MEM LEAK. store old pointer if you want to free it.
|
||||
|
||||
cache_code_link_blocks=cache_code;
|
||||
cache_code=cache_code+PAGESIZE_TEMP;
|
||||
|
||||
#if (C_HAVE_MPROTECT)
|
||||
if(mprotect(cache_code_link_blocks,CACHE_TOTAL+CACHE_MAXSIZE+PAGESIZE_TEMP,PROT_WRITE|PROT_READ|PROT_EXEC))
|
||||
LOG_MSG("Setting excute permission on the code cache has failed");
|
||||
#endif
|
||||
CacheBlockDynRec * block=cache_getblock();
|
||||
cache.block.first=block;
|
||||
cache.block.active=block;
|
||||
block->cache.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;i<CACHE_PAGES;i++) {
|
||||
CodePageHandlerDynRec * newpage=new CodePageHandlerDynRec();
|
||||
newpage->next=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; */
|
||||
}
|
599
src/cpu/core_dynrec/decoder.h
Normal file
599
src/cpu/core_dynrec/decoder.h
Normal file
@ -0,0 +1,599 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.5 2008/09/19 16:48:02 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:
|
||||
if (dyn_grp4_ev()) goto core_close_block;
|
||||
break;
|
||||
|
||||
default:
|
||||
// DYN_LOG("Dynrec unhandled opcode %X",opcode);
|
||||
goto illegalopcode;
|
||||
}
|
||||
}
|
||||
// normal exit because the maximal number of opcodes has been reached
|
||||
dyn_set_eip_end();
|
||||
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;
|
||||
}
|
1239
src/cpu/core_dynrec/decoder_basic.h
Normal file
1239
src/cpu/core_dynrec/decoder_basic.h
Normal file
File diff suppressed because it is too large
Load Diff
1427
src/cpu/core_dynrec/decoder_opcodes.h
Normal file
1427
src/cpu/core_dynrec/decoder_opcodes.h
Normal file
File diff suppressed because it is too large
Load Diff
681
src/cpu/core_dynrec/dyn_fpu.h
Normal file
681
src/cpu/core_dynrec/dyn_fpu.h
Normal file
@ -0,0 +1,681 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "dosbox.h"
|
||||
#if C_FPU
|
||||
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#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 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
|
1995
src/cpu/core_dynrec/operators.h
Normal file
1995
src/cpu/core_dynrec/operators.h
Normal file
File diff suppressed because it is too large
Load Diff
102
src/cpu/core_dynrec/risc_armv4le-common.h
Normal file
102
src/cpu/core_dynrec/risc_armv4le-common.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.2 2008/09/19 16:48:02 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) {
|
||||
// GP2X BEGIN
|
||||
//flush cache
|
||||
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
|
||||
}
|
982
src/cpu/core_dynrec/risc_armv4le-o3.h
Normal file
982
src/cpu/core_dynrec/risc_armv4le-o3.h
Normal file
@ -0,0 +1,982 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.3 2008/09/19 16:48:02 c2woody Exp $ */
|
||||
|
||||
|
||||
/* ARMv4 (little endian) backend by M-HT (size-tweaked arm version) */
|
||||
|
||||
|
||||
// temporary registers
|
||||
#define temp1 HOST_ip
|
||||
#define temp2 HOST_v5
|
||||
#define temp3 HOST_v4
|
||||
|
||||
// register that holds function return values
|
||||
#define FC_RETOP HOST_v3
|
||||
|
||||
// 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
|
||||
|
||||
// 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) )
|
||||
|
||||
// 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(0xe1a00000 + (reg_dst << 12) + reg_src); // 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(0xe3a00000 + (dest_reg << 12)); // mov dest_reg, #0
|
||||
} else if (imm == 0xffffffff) {
|
||||
cache_addd(0xe3e00000 + (dest_reg << 12)); // 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(0xe2400000 + (dest_reg << 12) + (HOST_pc << 16) + (ROTATE_SCALE(scale) << 7) + (dist & 0xff)); // sub dest_reg, pc, #((dist & 0xff) << scale)
|
||||
first = 0;
|
||||
} else {
|
||||
cache_addd(0xe2400000 + (dest_reg << 12) + (dest_reg << 16) + (ROTATE_SCALE(scale) << 7) + (dist & 0xff)); // 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(0xe1a00000 + (dest_reg << 12) + HOST_pc); // mov dest_reg, pc
|
||||
} else {
|
||||
while (dist) {
|
||||
while ((dist & 3) == 0) {
|
||||
dist>>=2;
|
||||
scale+=2;
|
||||
}
|
||||
if (first) {
|
||||
cache_addd(0xe2800000 + (dest_reg << 12) + (HOST_pc << 16) + (ROTATE_SCALE(scale) << 7) + (dist & 0xff)); // add dest_reg, pc, #((dist & 0xff) << scale)
|
||||
first = 0;
|
||||
} else {
|
||||
cache_addd(0xe2800000 + (dest_reg << 12) + (dest_reg << 16) + (ROTATE_SCALE(scale) << 7) + (dist & 0xff)); // 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(0xe3a00000 + (dest_reg << 12) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // mov dest_reg, #((imm & 0xff) << scale)
|
||||
first = 0;
|
||||
} else {
|
||||
cache_addd(0xe3800000 + (dest_reg << 12) + (dest_reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // 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(0xe3e00000 + (dest_reg << 12) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // mvn dest_reg, #((imm2 & 0xff) << scale)
|
||||
first = 0;
|
||||
} else {
|
||||
cache_addd(0xe3c00000 + (dest_reg << 12) + (dest_reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // 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(0xe1d000b0 + (dest_reg << 12) + (data_reg << 16)); // ldrh dest_reg, [data_reg]
|
||||
cache_addd(0xe1d000b2 + (temp2 << 12) + (data_reg << 16)); // ldrh temp2, [data_reg, #2]
|
||||
cache_addd(0xe1800800 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #16
|
||||
} else {
|
||||
cache_addd(0xe5d00000 + (dest_reg << 12) + (data_reg << 16)); // ldrb dest_reg, [data_reg]
|
||||
cache_addd(0xe1d000b1 + (temp2 << 12) + (data_reg << 16)); // ldrh temp2, [data_reg, #1]
|
||||
cache_addd(0xe1800400 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #8
|
||||
cache_addd(0xe5d00003 + (temp2 << 12) + (data_reg << 16)); // ldrb temp2, [data_reg, #3]
|
||||
cache_addd(0xe1800c00 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #24
|
||||
}
|
||||
} else {
|
||||
cache_addd(0xe5900000 + (dest_reg << 12) + (data_reg << 16)); // ldr dest_reg, [data_reg]
|
||||
}
|
||||
} else {
|
||||
if ((Bit32u)data & 1) {
|
||||
cache_addd(0xe5d00000 + (dest_reg << 12) + (data_reg << 16)); // ldrb dest_reg, [data_reg]
|
||||
cache_addd(0xe5d00001 + (temp2 << 12) + (data_reg << 16)); // ldrb temp2, [data_reg, #1]
|
||||
cache_addd(0xe1800400 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #8
|
||||
} else {
|
||||
cache_addd(0xe1d000b0 + (dest_reg << 12) + (data_reg << 16)); // 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(0xe3a00000 + (dest_reg << 12)); // 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(0xe3a00000 + (dest_reg << 12) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // mov dest_reg, #((imm2 & 0xff) << scale)
|
||||
first = 0;
|
||||
} else {
|
||||
cache_addd(0xe3800000 + (dest_reg << 12) + (dest_reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // 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(0xe1c000b0 + (src_reg << 12) + (data_reg << 16)); // strh src_reg, [data_reg]
|
||||
cache_addd(0xe1a00820 + (temp2 << 12) + (src_reg)); // mov temp2, src_reg, lsr #16
|
||||
cache_addd(0xe1c000b2 + (temp2 << 12) + (data_reg << 16)); // strh temp2, [data_reg, #2]
|
||||
} else {
|
||||
cache_addd(0xe5c00000 + (src_reg << 12) + (data_reg << 16)); // strb src_reg, [data_reg]
|
||||
cache_addd(0xe1a00420 + (temp2 << 12) + (src_reg)); // mov temp2, src_reg, lsr #8
|
||||
cache_addd(0xe1c000b1 + (temp2 << 12) + (data_reg << 16)); // strh temp2, [data_reg, #1]
|
||||
cache_addd(0xe1a00820 + (temp2 << 12) + (temp2)); // mov temp2, temp2, lsr #16
|
||||
cache_addd(0xe5c00003 + (temp2 << 12) + (data_reg << 16)); // strb temp2, [data_reg, #3]
|
||||
}
|
||||
} else {
|
||||
cache_addd(0xe5800000 + (src_reg << 12) + (data_reg << 16)); // str src_reg, [data_reg]
|
||||
}
|
||||
} else {
|
||||
if ((Bit32u)dest & 1) {
|
||||
cache_addd(0xe5c00000 + (src_reg << 12) + (data_reg << 16)); // strb src_reg, [data_reg]
|
||||
cache_addd(0xe1a00420 + (temp2 << 12) + (src_reg)); // mov temp2, src_reg, lsr #8
|
||||
cache_addd(0xe5c00001 + (temp2 << 12) + (data_reg << 16)); // strb temp2, [data_reg, #1]
|
||||
} else {
|
||||
cache_addd(0xe1c000b0 + (src_reg << 12) + (data_reg << 16)); // 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(0xe5d00000 + (dest_reg << 12) + (temp1 << 16)); // 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(0xe3a00000 + (dest_reg << 12) + (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(temp1, (Bit32u)dest);
|
||||
cache_addd(0xe5c00000 + (src_reg << 12) + (temp1 << 16)); // 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(0xe1a00c00 + (reg << 12) + (reg)); // mov reg, reg, lsl #24
|
||||
cache_addd(0xe1a00c40 + (reg << 12) + (reg)); // mov reg, reg, asr #24
|
||||
} else {
|
||||
cache_addd(0xe20000ff + (reg << 12) + (reg << 16)); // 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(0xe1a00800 + (reg << 12) + (reg)); // mov reg, reg, lsl #16
|
||||
cache_addd(0xe1a00840 + (reg << 12) + (reg)); // mov reg, reg, asr #16
|
||||
} else {
|
||||
cache_addd(0xe1a00800 + (reg << 12) + (reg)); // mov reg, reg, lsl #16
|
||||
cache_addd(0xe1a00820 + (reg << 12) + (reg)); // 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(0xe0800000 + (reg << 12) + (reg << 16) + (temp3)); // 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(0xe2800001 + (reg << 12) + (reg << 16)); // add reg, reg, #1
|
||||
} else if (imm == 0xffffffff) {
|
||||
cache_addd(0xe2400001 + (reg << 12) + (reg << 16)); // 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(0xe0400000 + (reg << 12) + (reg << 16) + (temp3)); // sub reg, reg, temp3
|
||||
} else {
|
||||
cache_addd(0xe0800000 + (reg << 12) + (reg << 16) + (temp3)); // add reg, reg, temp3
|
||||
}
|
||||
} else {
|
||||
scale = 0;
|
||||
while (imm) {
|
||||
while ((imm & 3) == 0) {
|
||||
imm>>=2;
|
||||
scale+=2;
|
||||
}
|
||||
if (sub) {
|
||||
cache_addd(0xe2400000 + (reg << 12) + (reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // sub reg, reg, #((imm & 0xff) << scale)
|
||||
} else {
|
||||
cache_addd(0xe2800000 + (reg << 12) + (reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // 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(0xe3a00000 + (reg << 12)); // 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(0xe0000000 + (reg << 12) + (reg << 16) + (temp3)); // and reg, reg, temp3
|
||||
} else {
|
||||
scale = 0;
|
||||
while (imm2) {
|
||||
while ((imm2 & 3) == 0) {
|
||||
imm2>>=2;
|
||||
scale+=2;
|
||||
}
|
||||
cache_addd(0xe3c00000 + (reg << 12) + (reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // 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(0xe2800000 + (temp3 << 12) + (temp3 << 16) + ((Bit32s)imm)); // add temp3, temp3, #(imm)
|
||||
} else {
|
||||
cache_addd(0xe2400000 + (temp3 << 12) + (temp3 << 16) + (-((Bit32s)imm))); // 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(0xe0800000 + (temp3 << 12) + (temp3 << 16) + (temp2)); // 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(0xe2400000 + (temp3 << 12) + (temp3 << 16) + ((Bit32s)imm)); // sub temp3, temp3, #(imm)
|
||||
} else {
|
||||
cache_addd(0xe2800000 + (temp3 << 12) + (temp3 << 16) + (-((Bit32s)imm))); // 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(0xe0400000 + (temp3 << 12) + (temp3 << 16) + (temp2)); // 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(0xe0800000 + (dest_reg << 12) + (dest_reg << 16) + (scale_reg) + (scale << 7)); // 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(0xe1a00000 + (dest_reg << 12) + (dest_reg) + (scale << 7)); // 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(0xe5900004 + (temp1 << 12) + (HOST_pc << 16)); // ldr temp1, [pc, #4]
|
||||
cache_addd(0xe2800004 + (HOST_lr << 12) + (HOST_pc << 16)); // add lr, pc, #4
|
||||
cache_addd(0xe12fff10 + (temp1)); // bx temp1
|
||||
cache_addd((Bit32u)func); // .int func
|
||||
cache_addd(0xe1a00000 + (FC_RETOP << 12) + HOST_a1); // mov FC_RETOP, a1
|
||||
}
|
||||
|
||||
// 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(0xe2400000 + (temp3 << 12) + (temp3 << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // sub temp3, temp3, #((imm2 & 0xff) << scale)
|
||||
} else {
|
||||
cache_addd(0xe2800000 + (temp3 << 12) + (temp3 << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // add temp3, temp3, #((imm2 & 0xff) << scale)
|
||||
}
|
||||
imm2>>=8;
|
||||
scale+=8;
|
||||
}
|
||||
}
|
||||
|
||||
#if (1)
|
||||
// (*ptr) should be word aligned
|
||||
if ((imm & 0x03) == 0) {
|
||||
cache_addd(0xe5900000 + (temp1 << 12) + (temp3 << 16)); // ldr temp1, [temp3]
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
cache_addd(0xe5d00000 + (temp1 << 12) + (temp3 << 16)); // ldrb temp1, [temp3]
|
||||
cache_addd(0xe5d00001 + (temp2 << 12) + (temp3 << 16)); // ldrb temp2, [temp3, #1]
|
||||
cache_addd(0xe1800400 + (temp1 << 12) + (temp1 << 16) + (temp2)); // orr temp1, temp1, temp2, lsl #8
|
||||
cache_addd(0xe5d00002 + (temp2 << 12) + (temp3 << 16)); // ldrb temp2, [temp3, #2]
|
||||
cache_addd(0xe1800800 + (temp1 << 12) + (temp1 << 16) + (temp2)); // orr temp1, temp1, temp2, lsl #16
|
||||
cache_addd(0xe5d00003 + (temp2 << 12) + (temp3 << 16)); // ldrb temp2, [temp3, #3]
|
||||
cache_addd(0xe1800c00 + (temp1 << 12) + (temp1 << 16) + (temp2)); // orr temp1, temp1, temp2, lsl #24
|
||||
}
|
||||
|
||||
cache_addd(0xe12fff10 + (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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
} else {
|
||||
cache_addd(0xe1b00800 + (temp1 << 12) + (reg)); // movs temp1, reg, lsl #16
|
||||
}
|
||||
cache_addd(0x0a000000); // 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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
} else {
|
||||
cache_addd(0xe1b00800 + (temp1 << 12) + (reg)); // movs temp1, reg, lsl #16
|
||||
}
|
||||
cache_addd(0x1a000000); // 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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
} else {
|
||||
cache_addd(0xe31000ff + (reg << 16)); // tst reg, #0xff
|
||||
}
|
||||
cache_addd(0x0a000002); // beq nobranch
|
||||
cache_addd(0xe5900000 + (temp1 << 12) + (HOST_pc << 16)); // ldr temp1, [pc, #0]
|
||||
cache_addd(0xe12fff10 + (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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
cache_addd(0xca000002); // bgt nobranch
|
||||
cache_addd(0xe5900000 + (temp1 << 12) + (HOST_pc << 16)); // ldr temp1, [pc, #0]
|
||||
cache_addd(0xe12fff10 + (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(0xe92d0df0); // stmfd sp!, {v1-v5,v7,v8}
|
||||
|
||||
// adr: 8
|
||||
cache_addd(0xe5900000 + (FC_SEGS_ADDR << 12) + (HOST_pc << 16) + (64 - (8 + 8))); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
|
||||
// adr: 12
|
||||
cache_addd(0xe5900000 + (FC_REGS_ADDR << 12) + (HOST_pc << 16) + (68 - (12 + 8))); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
|
||||
cache_addd(0xe28fe004); // add lr, pc, #4
|
||||
cache_addd(0xe92d4000); // stmfd sp!, {lr}
|
||||
cache_addd(0xe12fff10); // bx r0
|
||||
cache_addd(0xe8bd0df0); // ldmfd sp!, {v1-v5,v7,v8}
|
||||
|
||||
cache_addd(0xe8bd4000); // ldmfd sp!, {lr}
|
||||
cache_addd(0xe12fff1e); // bx lr
|
||||
// fill up to 64 bytes
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // 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(0xe1a00000 + (HOST_a1 << 12) + FC_RETOP); // mov a1, FC_RETOP
|
||||
cache_addd(0xe8bd4000); // ldmfd sp!, {lr}
|
||||
cache_addd(0xe12fff1e); // 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=0xe0800000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // add FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_ORb:
|
||||
case t_ORw:
|
||||
case t_ORd:
|
||||
*(Bit32u*)pos=0xe1800000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // orr FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_ANDb:
|
||||
case t_ANDw:
|
||||
case t_ANDd:
|
||||
*(Bit32u*)pos=0xe0000000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // and FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SUBb:
|
||||
case t_SUBw:
|
||||
case t_SUBd:
|
||||
*(Bit32u*)pos=0xe0400000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // sub FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_XORb:
|
||||
case t_XORw:
|
||||
case t_XORd:
|
||||
*(Bit32u*)pos=0xe0200000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // eor FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_CMPb:
|
||||
case t_CMPw:
|
||||
case t_CMPd:
|
||||
case t_TESTb:
|
||||
case t_TESTw:
|
||||
case t_TESTd:
|
||||
*(Bit32u*)pos=0xea000000 + (3); // b (pc+3*4)
|
||||
break;
|
||||
case t_INCb:
|
||||
case t_INCw:
|
||||
case t_INCd:
|
||||
*(Bit32u*)pos=0xe2800000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (1); // add FC_RETOP, a1, #1
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_DECb:
|
||||
case t_DECw:
|
||||
case t_DECd:
|
||||
*(Bit32u*)pos=0xe2400000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (1); // sub FC_RETOP, a1, #1
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SHLb:
|
||||
case t_SHLw:
|
||||
case t_SHLd:
|
||||
*(Bit32u*)pos=0xe1a00010 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, lsl a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SHRb:
|
||||
*(Bit32u*)pos=0xe2000000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (0xff); // and FC_RETOP, a1, #0xff
|
||||
*(Bit32u*)(pos+4)=0xe1a00030 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, lsr a2
|
||||
*(Bit32u*)(pos+8)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SHRw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe1a00020 + (FC_RETOP << 12) + (FC_RETOP) + (16 << 7); // mov FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+8)=0xe1a00030 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, lsr a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SHRd:
|
||||
*(Bit32u*)pos=0xe1a00030 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, lsr a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SARb:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (24 << 7); // mov FC_RETOP, a1, lsl #24
|
||||
*(Bit32u*)(pos+4)=0xe1a00040 + (FC_RETOP << 12) + (FC_RETOP) + (24 << 7); // mov FC_RETOP, FC_RETOP, asr #24
|
||||
*(Bit32u*)(pos+8)=0xe1a00050 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, asr a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SARw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe1a00040 + (FC_RETOP << 12) + (FC_RETOP) + (16 << 7); // mov FC_RETOP, FC_RETOP, asr #16
|
||||
*(Bit32u*)(pos+8)=0xe1a00050 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, asr a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SARd:
|
||||
*(Bit32u*)pos=0xe1a00050 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, asr a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_RORb:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (24 << 7); // mov FC_RETOP, a1, lsl #24
|
||||
*(Bit32u*)(pos+4)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (8 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8
|
||||
*(Bit32u*)(pos+8)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+12)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_RORw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+8)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_RORd:
|
||||
*(Bit32u*)pos=0xe1a00070 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, ror a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_ROLb:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (24 << 7); // mov FC_RETOP, a1, lsl #24
|
||||
*(Bit32u*)(pos+4)=0xe2600000 + (HOST_a2 << 12) + (HOST_a2 << 16) + (32); // rsb a2, a2, #32
|
||||
*(Bit32u*)(pos+8)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (8 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8
|
||||
*(Bit32u*)(pos+12)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+16)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
break;
|
||||
case t_ROLw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe2600000 + (HOST_a2 << 12) + (HOST_a2 << 16) + (32); // rsb a2, a2, #32
|
||||
*(Bit32u*)(pos+8)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+12)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_ROLd:
|
||||
*(Bit32u*)pos=0xe2600000 + (HOST_a2 << 12) + (HOST_a2 << 16) + (32); // rsb a2, a2, #32
|
||||
*(Bit32u*)(pos+4)=0xe1a00070 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, ror a2
|
||||
*(Bit32u*)(pos+8)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_NEGb:
|
||||
case t_NEGw:
|
||||
case t_NEGd:
|
||||
*(Bit32u*)pos=0xe2600000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (0); // rsb FC_RETOP, a1, #0
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
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(0xe1d000b0 + (dest_reg << 12) + (FC_SEGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5900000 + (dest_reg << 12) + (FC_SEGS_ADDR << 16) + (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(0xe5900000 + (temp1 << 12) + (FC_SEGS_ADDR << 16) + (index)); // ldr temp1, [FC_SEGS_ADDR, #index]
|
||||
cache_addd(0xe0800000 + (reg << 12) + (reg << 16) + (temp1)); // 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(0xe1d000b0 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5900000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5900000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (index)); // ldr dest_reg, [FC_REGS_ADDR, #index]
|
||||
} else {
|
||||
cache_addd(0xe1d000b0 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5d00000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5d00000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5900000 + (temp2 << 12) + (FC_REGS_ADDR << 16) + (index)); // ldr temp2, [FC_REGS_ADDR, #index]
|
||||
cache_addd(0xe0800000 + (reg << 12) + (reg << 16) + (temp2)); // 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(0xe1c000b0 + (src_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5800000 + (src_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5800000 + (src_reg << 12) + (FC_REGS_ADDR << 16) + (index)); // str src_reg, [FC_REGS_ADDR, #index]
|
||||
} else {
|
||||
cache_addd(0xe1c000b0 + (src_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5c00000 + (src_reg << 12) + (FC_REGS_ADDR << 16) + (index)); // strb src_reg, [FC_REGS_ADDR, #index]
|
||||
}
|
||||
|
||||
#endif
|
817
src/cpu/core_dynrec/risc_armv4le-s3.h
Normal file
817
src/cpu/core_dynrec/risc_armv4le-s3.h
Normal file
@ -0,0 +1,817 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.3 2008/09/19 16:48:02 c2woody Exp $ */
|
||||
|
||||
|
||||
/* ARMv4 (little endian) backend by M-HT (speed-tweaked arm version) */
|
||||
|
||||
|
||||
// temporary registers
|
||||
#define temp1 HOST_ip
|
||||
#define temp2 HOST_v5
|
||||
#define temp3 HOST_v4
|
||||
|
||||
// register that holds function return values
|
||||
#define FC_RETOP HOST_v3
|
||||
|
||||
// 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
|
||||
|
||||
// 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) )
|
||||
|
||||
// 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(0xe1a00000 + (reg_dst << 12) + 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) {
|
||||
Bits first, scale;
|
||||
if (imm == 0) {
|
||||
cache_addd(0xe3a00000 + (dest_reg << 12)); // mov dest_reg, #0
|
||||
} else {
|
||||
scale = 0;
|
||||
first = 1;
|
||||
while (imm) {
|
||||
while ((imm & 3) == 0) {
|
||||
imm>>=2;
|
||||
scale+=2;
|
||||
}
|
||||
if (first) {
|
||||
cache_addd(0xe3a00000 + (dest_reg << 12) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // mov dest_reg, #((imm & 0xff) << scale)
|
||||
first = 0;
|
||||
} else {
|
||||
cache_addd(0xe3800000 + (dest_reg << 12) + (dest_reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // 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(0xe1d000b0 + (dest_reg << 12) + (data_reg << 16)); // ldrh dest_reg, [data_reg]
|
||||
cache_addd(0xe1d000b2 + (temp2 << 12) + (data_reg << 16)); // ldrh temp2, [data_reg, #2]
|
||||
cache_addd(0xe1800800 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #16
|
||||
} else {
|
||||
cache_addd(0xe5d00000 + (dest_reg << 12) + (data_reg << 16)); // ldrb dest_reg, [data_reg]
|
||||
cache_addd(0xe1d000b1 + (temp2 << 12) + (data_reg << 16)); // ldrh temp2, [data_reg, #1]
|
||||
cache_addd(0xe1800400 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #8
|
||||
cache_addd(0xe5d00003 + (temp2 << 12) + (data_reg << 16)); // ldrb temp2, [data_reg, #3]
|
||||
cache_addd(0xe1800c00 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #24
|
||||
}
|
||||
} else {
|
||||
cache_addd(0xe5900000 + (dest_reg << 12) + (data_reg << 16)); // ldr dest_reg, [data_reg]
|
||||
}
|
||||
} else {
|
||||
if ((Bit32u)data & 1) {
|
||||
cache_addd(0xe5d00000 + (dest_reg << 12) + (data_reg << 16)); // ldrb dest_reg, [data_reg]
|
||||
cache_addd(0xe5d00001 + (temp2 << 12) + (data_reg << 16)); // ldrb temp2, [data_reg, #1]
|
||||
cache_addd(0xe1800400 + (dest_reg << 12) + (dest_reg << 16) + (temp2)); // orr dest_reg, dest_reg, temp2, lsl #8
|
||||
} else {
|
||||
cache_addd(0xe1d000b0 + (dest_reg << 12) + (data_reg << 16)); // 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(0xe1c000b0 + (src_reg << 12) + (data_reg << 16)); // strh src_reg, [data_reg]
|
||||
cache_addd(0xe1a00820 + (temp2 << 12) + (src_reg)); // mov temp2, src_reg, lsr #16
|
||||
cache_addd(0xe1c000b2 + (temp2 << 12) + (data_reg << 16)); // strh temp2, [data_reg, #2]
|
||||
} else {
|
||||
cache_addd(0xe5c00000 + (src_reg << 12) + (data_reg << 16)); // strb src_reg, [data_reg]
|
||||
cache_addd(0xe1a00420 + (temp2 << 12) + (src_reg)); // mov temp2, src_reg, lsr #8
|
||||
cache_addd(0xe1c000b1 + (temp2 << 12) + (data_reg << 16)); // strh temp2, [data_reg, #1]
|
||||
cache_addd(0xe1a00820 + (temp2 << 12) + (temp2)); // mov temp2, temp2, lsr #16
|
||||
cache_addd(0xe5c00003 + (temp2 << 12) + (data_reg << 16)); // strb temp2, [data_reg, #3]
|
||||
}
|
||||
} else {
|
||||
cache_addd(0xe5800000 + (src_reg << 12) + (data_reg << 16)); // str src_reg, [data_reg]
|
||||
}
|
||||
} else {
|
||||
if ((Bit32u)dest & 1) {
|
||||
cache_addd(0xe5c00000 + (src_reg << 12) + (data_reg << 16)); // strb src_reg, [data_reg]
|
||||
cache_addd(0xe1a00420 + (temp2 << 12) + (src_reg)); // mov temp2, src_reg, lsr #8
|
||||
cache_addd(0xe5c00001 + (temp2 << 12) + (data_reg << 16)); // strb temp2, [data_reg, #1]
|
||||
} else {
|
||||
cache_addd(0xe1c000b0 + (src_reg << 12) + (data_reg << 16)); // 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(0xe5d00000 + (dest_reg << 12) + (temp1 << 16)); // 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(0xe3a00000 + (dest_reg << 12) + (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(temp1, (Bit32u)dest);
|
||||
cache_addd(0xe5c00000 + (src_reg << 12) + (temp1 << 16)); // 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(0xe1a00c00 + (reg << 12) + (reg)); // mov reg, reg, lsl #24
|
||||
cache_addd(0xe1a00c40 + (reg << 12) + (reg)); // mov reg, reg, asr #24
|
||||
} else {
|
||||
cache_addd(0xe20000ff + (reg << 12) + (reg << 16)); // 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(0xe1a00800 + (reg << 12) + (reg)); // mov reg, reg, lsl #16
|
||||
cache_addd(0xe1a00840 + (reg << 12) + (reg)); // mov reg, reg, asr #16
|
||||
} else {
|
||||
cache_addd(0xe1a00800 + (reg << 12) + (reg)); // mov reg, reg, lsl #16
|
||||
cache_addd(0xe1a00820 + (reg << 12) + (reg)); // 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(0xe0800000 + (reg << 12) + (reg << 16) + (temp3)); // 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(0xe2400001 + (reg << 12) + (reg << 16)); // sub reg, reg, #1
|
||||
} else {
|
||||
scale = 0;
|
||||
while (imm) {
|
||||
while ((imm & 3) == 0) {
|
||||
imm>>=2;
|
||||
scale+=2;
|
||||
}
|
||||
cache_addd(0xe2800000 + (reg << 12) + (reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm & 0xff)); // 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(0xe3a00000 + (reg << 12)); // mov reg, #0
|
||||
} else {
|
||||
scale = 0;
|
||||
while (imm2) {
|
||||
while ((imm2 & 3) == 0) {
|
||||
imm2>>=2;
|
||||
scale+=2;
|
||||
}
|
||||
cache_addd(0xe3c00000 + (reg << 12) + (reg << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // 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(0xe2800000 + (temp3 << 12) + (temp3 << 16) + ((Bit32s)imm)); // add temp3, temp3, #(imm)
|
||||
} else {
|
||||
cache_addd(0xe2400000 + (temp3 << 12) + (temp3 << 16) + (-((Bit32s)imm))); // 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(0xe0800000 + (temp3 << 12) + (temp3 << 16) + (temp2)); // 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(0xe2400000 + (temp3 << 12) + (temp3 << 16) + ((Bit32s)imm)); // sub temp3, temp3, #(imm)
|
||||
} else {
|
||||
cache_addd(0xe2800000 + (temp3 << 12) + (temp3 << 16) + (-((Bit32s)imm))); // 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(0xe0400000 + (temp3 << 12) + (temp3 << 16) + (temp2)); // 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(0xe0800000 + (dest_reg << 12) + (dest_reg << 16) + (scale_reg) + (scale << 7)); // 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(0xe1a00000 + (dest_reg << 12) + (dest_reg) + (scale << 7)); // 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(0xe5900004 + (temp1 << 12) + (HOST_pc << 16)); // ldr temp1, [pc, #4]
|
||||
cache_addd(0xe2800004 + (HOST_lr << 12) + (HOST_pc << 16)); // add lr, pc, #4
|
||||
cache_addd(0xe12fff10 + (temp1)); // bx temp1
|
||||
cache_addd((Bit32u)func); // .int func
|
||||
cache_addd(0xe1a00000 + (FC_RETOP << 12) + HOST_a1); // mov FC_RETOP, a1
|
||||
}
|
||||
|
||||
// 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(0xe2800000 + (temp3 << 12) + (temp3 << 16) + (ROTATE_SCALE(scale) << 7) + (imm2 & 0xff)); // add temp3, temp3, #((imm2 & 0xff) << scale)
|
||||
imm2>>=8;
|
||||
scale+=8;
|
||||
}
|
||||
}
|
||||
|
||||
#if (1)
|
||||
// (*ptr) should be word aligned
|
||||
if ((imm & 0x03) == 0) {
|
||||
cache_addd(0xe5900000 + (temp1 << 12) + (temp3 << 16)); // ldr temp1, [temp3]
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
cache_addd(0xe5d00000 + (temp1 << 12) + (temp3 << 16)); // ldrb temp1, [temp3]
|
||||
cache_addd(0xe5d00001 + (temp2 << 12) + (temp3 << 16)); // ldrb temp2, [temp3, #1]
|
||||
cache_addd(0xe1800400 + (temp1 << 12) + (temp1 << 16) + (temp2)); // orr temp1, temp1, temp2, lsl #8
|
||||
cache_addd(0xe5d00002 + (temp2 << 12) + (temp3 << 16)); // ldrb temp2, [temp3, #2]
|
||||
cache_addd(0xe1800800 + (temp1 << 12) + (temp1 << 16) + (temp2)); // orr temp1, temp1, temp2, lsl #16
|
||||
cache_addd(0xe5d00003 + (temp2 << 12) + (temp3 << 16)); // ldrb temp2, [temp3, #3]
|
||||
cache_addd(0xe1800c00 + (temp1 << 12) + (temp1 << 16) + (temp2)); // orr temp1, temp1, temp2, lsl #24
|
||||
}
|
||||
|
||||
cache_addd(0xe12fff10 + (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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
} else {
|
||||
cache_addd(0xe1b00800 + (temp1 << 12) + (reg)); // movs temp1, reg, lsl #16
|
||||
}
|
||||
cache_addd(0x0a000000); // 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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
} else {
|
||||
cache_addd(0xe1b00800 + (temp1 << 12) + (reg)); // movs temp1, reg, lsl #16
|
||||
}
|
||||
cache_addd(0x1a000000); // 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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
} else {
|
||||
cache_addd(0xe31000ff + (reg << 16)); // tst reg, #0xff
|
||||
}
|
||||
cache_addd(0x0a000002); // beq nobranch
|
||||
cache_addd(0xe5900000 + (temp1 << 12) + (HOST_pc << 16)); // ldr temp1, [pc, #0]
|
||||
cache_addd(0xe12fff10 + (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(0xe3500000 + (reg << 16)); // cmp reg, #0
|
||||
cache_addd(0xca000002); // bgt nobranch
|
||||
cache_addd(0xe5900000 + (temp1 << 12) + (HOST_pc << 16)); // ldr temp1, [pc, #0]
|
||||
cache_addd(0xe12fff10 + (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(0xe92d0df0); // stmfd sp!, {v1-v5,v7,v8}
|
||||
|
||||
// adr: 8
|
||||
cache_addd(0xe5900000 + (FC_SEGS_ADDR << 12) + (HOST_pc << 16) + (64 - (8 + 8))); // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
|
||||
// adr: 12
|
||||
cache_addd(0xe5900000 + (FC_REGS_ADDR << 12) + (HOST_pc << 16) + (68 - (12 + 8))); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
|
||||
cache_addd(0xe28fe004); // add lr, pc, #4
|
||||
cache_addd(0xe92d4000); // stmfd sp!, {lr}
|
||||
cache_addd(0xe12fff10); // bx r0
|
||||
cache_addd(0xe8bd0df0); // ldmfd sp!, {v1-v5,v7,v8}
|
||||
cache_addd(0xe8bd4000); // ldmfd sp!, {lr}
|
||||
cache_addd(0xe12fff1e); // bx lr
|
||||
// fill up to 64 bytes
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // nop
|
||||
cache_addd(0xe1a00000); // 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(0xe1a00000 + (HOST_a1 << 12) + FC_RETOP); // mov a1, FC_RETOP
|
||||
cache_addd(0xe8bd4000); // ldmfd sp!, {lr}
|
||||
cache_addd(0xe12fff1e); // 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=0xe0800000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // add FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_ORb:
|
||||
case t_ORw:
|
||||
case t_ORd:
|
||||
*(Bit32u*)pos=0xe1800000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // orr FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_ANDb:
|
||||
case t_ANDw:
|
||||
case t_ANDd:
|
||||
*(Bit32u*)pos=0xe0000000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // and FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SUBb:
|
||||
case t_SUBw:
|
||||
case t_SUBd:
|
||||
*(Bit32u*)pos=0xe0400000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // sub FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_XORb:
|
||||
case t_XORw:
|
||||
case t_XORd:
|
||||
*(Bit32u*)pos=0xe0200000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (HOST_a2); // eor FC_RETOP, a1, a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_CMPb:
|
||||
case t_CMPw:
|
||||
case t_CMPd:
|
||||
case t_TESTb:
|
||||
case t_TESTw:
|
||||
case t_TESTd:
|
||||
*(Bit32u*)pos=0xea000000 + (3); // b (pc+3*4)
|
||||
break;
|
||||
case t_INCb:
|
||||
case t_INCw:
|
||||
case t_INCd:
|
||||
*(Bit32u*)pos=0xe2800000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (1); // add FC_RETOP, a1, #1
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_DECb:
|
||||
case t_DECw:
|
||||
case t_DECd:
|
||||
*(Bit32u*)pos=0xe2400000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (1); // sub FC_RETOP, a1, #1
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SHLb:
|
||||
case t_SHLw:
|
||||
case t_SHLd:
|
||||
*(Bit32u*)pos=0xe1a00010 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, lsl a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SHRb:
|
||||
*(Bit32u*)pos=0xe2000000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (0xff); // and FC_RETOP, a1, #0xff
|
||||
*(Bit32u*)(pos+4)=0xe1a00030 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, lsr a2
|
||||
*(Bit32u*)(pos+8)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SHRw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe1a00020 + (FC_RETOP << 12) + (FC_RETOP) + (16 << 7); // mov FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+8)=0xe1a00030 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, lsr a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SHRd:
|
||||
*(Bit32u*)pos=0xe1a00030 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, lsr a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_SARb:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (24 << 7); // mov FC_RETOP, a1, lsl #24
|
||||
*(Bit32u*)(pos+4)=0xe1a00040 + (FC_RETOP << 12) + (FC_RETOP) + (24 << 7); // mov FC_RETOP, FC_RETOP, asr #24
|
||||
*(Bit32u*)(pos+8)=0xe1a00050 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, asr a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SARw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe1a00040 + (FC_RETOP << 12) + (FC_RETOP) + (16 << 7); // mov FC_RETOP, FC_RETOP, asr #16
|
||||
*(Bit32u*)(pos+8)=0xe1a00050 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, asr a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_SARd:
|
||||
*(Bit32u*)pos=0xe1a00050 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, asr a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_RORb:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (24 << 7); // mov FC_RETOP, a1, lsl #24
|
||||
*(Bit32u*)(pos+4)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (8 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8
|
||||
*(Bit32u*)(pos+8)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+12)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_RORw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+8)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_RORd:
|
||||
*(Bit32u*)pos=0xe1a00070 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, ror a2
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
break;
|
||||
case t_ROLb:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (24 << 7); // mov FC_RETOP, a1, lsl #24
|
||||
*(Bit32u*)(pos+4)=0xe2600000 + (HOST_a2 << 12) + (HOST_a2 << 16) + (32); // rsb a2, a2, #32
|
||||
*(Bit32u*)(pos+8)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (8 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #8
|
||||
*(Bit32u*)(pos+12)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+16)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
break;
|
||||
case t_ROLw:
|
||||
*(Bit32u*)pos=0xe1a00000 + (FC_RETOP << 12) + (HOST_a1) + (16 << 7); // mov FC_RETOP, a1, lsl #16
|
||||
*(Bit32u*)(pos+4)=0xe2600000 + (HOST_a2 << 12) + (HOST_a2 << 16) + (32); // rsb a2, a2, #32
|
||||
*(Bit32u*)(pos+8)=0xe1800020 + (FC_RETOP << 12) + (FC_RETOP << 16) + (FC_RETOP) + (16 << 7); // orr FC_RETOP, FC_RETOP, FC_RETOP, lsr #16
|
||||
*(Bit32u*)(pos+12)=0xe1a00070 + (FC_RETOP << 12) + (FC_RETOP) + (HOST_a2 << 8); // mov FC_RETOP, FC_RETOP, ror a2
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_ROLd:
|
||||
*(Bit32u*)pos=0xe2600000 + (HOST_a2 << 12) + (HOST_a2 << 16) + (32); // rsb a2, a2, #32
|
||||
*(Bit32u*)(pos+4)=0xe1a00070 + (FC_RETOP << 12) + (HOST_a1) + (HOST_a2 << 8); // mov FC_RETOP, a1, ror a2
|
||||
*(Bit32u*)(pos+8)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+12)=0xe1a00000; // nop
|
||||
*(Bit32u*)(pos+16)=0xe1a00000; // nop
|
||||
break;
|
||||
case t_NEGb:
|
||||
case t_NEGw:
|
||||
case t_NEGd:
|
||||
*(Bit32u*)pos=0xe2600000 + (FC_RETOP << 12) + (HOST_a1 << 16) + (0); // rsb FC_RETOP, a1, #0
|
||||
*(Bit32u*)(pos+4)=0xea000000 + (2); // b (pc+2*4)
|
||||
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(0xe1d000b0 + (dest_reg << 12) + (FC_SEGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5900000 + (dest_reg << 12) + (FC_SEGS_ADDR << 16) + (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(0xe5900000 + (temp1 << 12) + (FC_SEGS_ADDR << 16) + (index)); // ldr temp1, [FC_SEGS_ADDR, #index]
|
||||
cache_addd(0xe0800000 + (reg << 12) + (reg << 16) + (temp1)); // 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(0xe1d000b0 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5900000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5900000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (index)); // ldr dest_reg, [FC_REGS_ADDR, #index]
|
||||
} else {
|
||||
cache_addd(0xe1d000b0 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5d00000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5d00000 + (dest_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5900000 + (temp2 << 12) + (FC_REGS_ADDR << 16) + (index)); // ldr temp2, [FC_REGS_ADDR, #index]
|
||||
cache_addd(0xe0800000 + (reg << 12) + (reg << 16) + (temp2)); // 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(0xe1c000b0 + (src_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5800000 + (src_reg << 12) + (FC_REGS_ADDR << 16) + (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(0xe5800000 + (src_reg << 12) + (FC_REGS_ADDR << 16) + (index)); // str src_reg, [FC_REGS_ADDR, #index]
|
||||
} else {
|
||||
cache_addd(0xe1c000b0 + (src_reg << 12) + (FC_REGS_ADDR << 16) + ((index & 0xf0) << 4) + (index & 0x0f)); // 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(0xe5c00000 + (src_reg << 12) + (FC_REGS_ADDR << 16) + (index)); // strb src_reg, [FC_REGS_ADDR, #index]
|
||||
}
|
||||
|
||||
#endif
|
1289
src/cpu/core_dynrec/risc_armv4le-thumb-iw.h
Normal file
1289
src/cpu/core_dynrec/risc_armv4le-thumb-iw.h
Normal file
File diff suppressed because it is too large
Load Diff
1286
src/cpu/core_dynrec/risc_armv4le-thumb-niw.h
Normal file
1286
src/cpu/core_dynrec/risc_armv4le-thumb-niw.h
Normal file
File diff suppressed because it is too large
Load Diff
1078
src/cpu/core_dynrec/risc_armv4le-thumb.h
Normal file
1078
src/cpu/core_dynrec/risc_armv4le-thumb.h
Normal file
File diff suppressed because it is too large
Load Diff
31
src/cpu/core_dynrec/risc_armv4le.h
Normal file
31
src/cpu/core_dynrec/risc_armv4le.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.2 2008/09/02 20:44:41 c2woody 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"
|
748
src/cpu/core_dynrec/risc_mipsel32.h
Normal file
748
src/cpu/core_dynrec/risc_mipsel32.h
Normal file
@ -0,0 +1,748 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.4 2008/09/19 16:48:03 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
|
||||
|
||||
// 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
|
679
src/cpu/core_dynrec/risc_x64.h
Normal file
679
src/cpu/core_dynrec/risc_x64.h
Normal file
@ -0,0 +1,679 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.11 2008/09/02 20:44:41 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
|
||||
|
||||
// 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+TEMP_REG_DRC*(2^scale)+imm
|
||||
// ea_reg := op1 + op2 *(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+(TEMP_REG_DRC<<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) { }
|
513
src/cpu/core_dynrec/risc_x86.h
Normal file
513
src/cpu/core_dynrec/risc_x86.h
Normal file
@ -0,0 +1,513 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.8 2008/09/02 20:44:41 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
|
||||
|
||||
// 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+TEMP_REG_DRC*(2^scale)+imm
|
||||
// ea_reg := op1 + op2 *(2^scale)+imm
|
||||
cache_addb(0x8d); //LEA
|
||||
cache_addb(0x04+(dest_reg << 3)+rm_base); //The sib indicator
|
||||
cache_addb(dest_reg+(TEMP_REG_DRC<<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_addw(0xd0ff); // call eax
|
||||
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) { }
|
99
src/cpu/core_full.cpp
Normal file
99
src/cpu/core_full.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "dosbox.h"
|
||||
|
||||
#include "pic.h"
|
||||
#include "regs.h"
|
||||
#include "cpu.h"
|
||||
#include "lazyflags.h"
|
||||
#include "paging.h"
|
||||
#include "fpu.h"
|
||||
#include "debug.h"
|
||||
#include "inout.h"
|
||||
#include "callback.h"
|
||||
|
||||
|
||||
typedef PhysPt EAPoint;
|
||||
#define SegBase(c) SegPhys(c)
|
||||
|
||||
#define LoadMb(off) mem_readb_inline(off)
|
||||
#define LoadMw(off) mem_readw_inline(off)
|
||||
#define LoadMd(off) mem_readd_inline(off)
|
||||
|
||||
#define LoadMbs(off) (Bit8s)(LoadMb(off))
|
||||
#define LoadMws(off) (Bit16s)(LoadMw(off))
|
||||
#define LoadMds(off) (Bit32s)(LoadMd(off))
|
||||
|
||||
#define SaveMb(off,val) mem_writeb_inline(off,val)
|
||||
#define SaveMw(off,val) mem_writew_inline(off,val)
|
||||
#define SaveMd(off,val) mem_writed_inline(off,val)
|
||||
|
||||
#define LoadD(reg) reg
|
||||
#define SaveD(reg,val) reg=val
|
||||
|
||||
|
||||
|
||||
#include "core_full/loadwrite.h"
|
||||
#include "core_full/support.h"
|
||||
#include "core_full/optable.h"
|
||||
#include "instructions.h"
|
||||
|
||||
#define EXCEPTION(blah) \
|
||||
{ \
|
||||
Bit8u new_num=blah; \
|
||||
CPU_Exception(new_num,0); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
Bits CPU_Core_Full_Run(void) {
|
||||
FullData inst;
|
||||
while (CPU_Cycles-->0) {
|
||||
#if C_DEBUG
|
||||
cycle_count++;
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) {
|
||||
FillFlags();
|
||||
return debugCallback;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
LoadIP();
|
||||
inst.entry=cpu.code.big*0x200;
|
||||
inst.prefix=cpu.code.big;
|
||||
restartopcode:
|
||||
inst.entry=(inst.entry & 0xffffff00) | Fetchb();
|
||||
inst.code=OpCodeTable[inst.entry];
|
||||
#include "core_full/load.h"
|
||||
#include "core_full/op.h"
|
||||
#include "core_full/save.h"
|
||||
nextopcode:;
|
||||
SaveIP();
|
||||
continue;
|
||||
illegalopcode:
|
||||
LOG(LOG_CPU,LOG_NORMAL)("Illegal opcode");
|
||||
CPU_Exception(0x6,0);
|
||||
}
|
||||
FillFlags();
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
|
||||
void CPU_Core_Full_Init(void) {
|
||||
|
||||
}
|
3
src/cpu/core_full/Makefile.am
Normal file
3
src/cpu/core_full/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
noinst_HEADERS = ea_lookup.h load.h loadwrite.h op.h optable.h save.h \
|
||||
string.h support.h
|
237
src/cpu/core_full/ea_lookup.h
Normal file
237
src/cpu/core_full/ea_lookup.h
Normal file
@ -0,0 +1,237 @@
|
||||
{
|
||||
EAPoint seg_base;
|
||||
Bit16u off;
|
||||
switch ((inst.rm_mod<<3)|inst.rm_eai) {
|
||||
case 0x00:
|
||||
off=reg_bx+reg_si;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x01:
|
||||
off=reg_bx+reg_di;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x02:
|
||||
off=reg_bp+reg_si;
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x03:
|
||||
off=reg_bp+reg_di;
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x04:
|
||||
off=reg_si;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x05:
|
||||
off=reg_di;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x06:
|
||||
off=Fetchw();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x07:
|
||||
off=reg_bx;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
off=reg_bx+reg_si+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x09:
|
||||
off=reg_bx+reg_di+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0a:
|
||||
off=reg_bp+reg_si+Fetchbs();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x0b:
|
||||
off=reg_bp+reg_di+Fetchbs();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x0c:
|
||||
off=reg_si+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0d:
|
||||
off=reg_di+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0e:
|
||||
off=reg_bp+Fetchbs();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x0f:
|
||||
off=reg_bx+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
off=reg_bx+reg_si+Fetchws();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x11:
|
||||
off=reg_bx+reg_di+Fetchws();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x12:
|
||||
off=reg_bp+reg_si+Fetchws();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x13:
|
||||
off=reg_bp+reg_di+Fetchws();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x14:
|
||||
off=reg_si+Fetchws();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x15:
|
||||
off=reg_di+Fetchws();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x16:
|
||||
off=reg_bp+Fetchws();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x17:
|
||||
off=reg_bx+Fetchws();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
}
|
||||
inst.rm_off=off;
|
||||
if (inst.prefix & PREFIX_SEG) {
|
||||
inst.rm_eaa=inst.seg.base+off;
|
||||
} else {
|
||||
inst.rm_eaa=seg_base+off;
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
#define SIB(MODE) { \
|
||||
Bitu sib=Fetchb(); \
|
||||
switch (sib&7) { \
|
||||
case 0:seg_base=SegBase(ds);off=reg_eax;break; \
|
||||
case 1:seg_base=SegBase(ds);off=reg_ecx;break; \
|
||||
case 2:seg_base=SegBase(ds);off=reg_edx;break; \
|
||||
case 3:seg_base=SegBase(ds);off=reg_ebx;break; \
|
||||
case 4:seg_base=SegBase(ss);off=reg_esp;break; \
|
||||
case 5:if (!MODE) { seg_base=SegBase(ds);off=Fetchd();break; \
|
||||
} else { seg_base=SegBase(ss);off=reg_ebp;break;} \
|
||||
case 6:seg_base=SegBase(ds);off=reg_esi;break; \
|
||||
case 7:seg_base=SegBase(ds);off=reg_edi;break; \
|
||||
} \
|
||||
off+=*SIBIndex[(sib >> 3) &7] << (sib >> 6); \
|
||||
};
|
||||
static Bit32u SIBZero=0;
|
||||
static Bit32u * SIBIndex[8]= { ®_eax,®_ecx,®_edx,®_ebx,&SIBZero,®_ebp,®_esi,®_edi };
|
||||
EAPoint seg_base;
|
||||
Bit32u off;
|
||||
switch ((inst.rm_mod<<3)|inst.rm_eai) {
|
||||
case 0x00:
|
||||
off=reg_eax;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x01:
|
||||
off=reg_ecx;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x02:
|
||||
off=reg_edx;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x03:
|
||||
off=reg_ebx;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x04:
|
||||
SIB(0);
|
||||
break;
|
||||
case 0x05:
|
||||
off=Fetchd();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x06:
|
||||
off=reg_esi;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x07:
|
||||
off=reg_edi;
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
|
||||
case 0x08:
|
||||
off=reg_eax+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x09:
|
||||
off=reg_ecx+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0a:
|
||||
off=reg_edx+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0b:
|
||||
off=reg_ebx+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0c:
|
||||
SIB(1);
|
||||
off+=Fetchbs();
|
||||
break;
|
||||
case 0x0d:
|
||||
off=reg_ebp+Fetchbs();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x0e:
|
||||
off=reg_esi+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x0f:
|
||||
off=reg_edi+Fetchbs();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
off=reg_eax+Fetchds();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x11:
|
||||
off=reg_ecx+Fetchds();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x12:
|
||||
off=reg_edx+Fetchds();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x13:
|
||||
off=reg_ebx+Fetchds();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x14:
|
||||
SIB(1);
|
||||
off+=Fetchds();
|
||||
break;
|
||||
case 0x15:
|
||||
off=reg_ebp+Fetchds();
|
||||
seg_base=SegBase(ss);
|
||||
break;
|
||||
case 0x16:
|
||||
off=reg_esi+Fetchds();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
case 0x17:
|
||||
off=reg_edi+Fetchds();
|
||||
seg_base=SegBase(ds);
|
||||
break;
|
||||
}
|
||||
inst.rm_off=off;
|
||||
if (inst.prefix & PREFIX_SEG) {
|
||||
inst.rm_eaa=inst.seg.base+off;
|
||||
} else {
|
||||
inst.rm_eaa=seg_base+off;
|
||||
}
|
||||
}
|
489
src/cpu/core_full/load.h
Normal file
489
src/cpu/core_full/load.h
Normal file
@ -0,0 +1,489 @@
|
||||
switch (inst.code.load) {
|
||||
/* General loading */
|
||||
case L_POPwRM:
|
||||
inst_op1_w = Pop_16();
|
||||
goto case_L_MODRM;
|
||||
case L_POPdRM:
|
||||
inst_op1_d = Pop_32();
|
||||
goto case_L_MODRM;
|
||||
case L_MODRM_NVM:
|
||||
if ((reg_flags & FLAG_VM) || !cpu.pmode) goto illegalopcode;
|
||||
goto case_L_MODRM;
|
||||
case_L_MODRM:
|
||||
case L_MODRM:
|
||||
inst.rm=Fetchb();
|
||||
inst.rm_index=(inst.rm >> 3) & 7;
|
||||
inst.rm_eai=inst.rm&07;
|
||||
inst.rm_mod=inst.rm>>6;
|
||||
/* Decode address of mod/rm if needed */
|
||||
if (inst.rm<0xc0) {
|
||||
if (!(inst.prefix & PREFIX_ADDR))
|
||||
#include "ea_lookup.h"
|
||||
}
|
||||
l_MODRMswitch:
|
||||
switch (inst.code.extra) {
|
||||
/* Byte */
|
||||
case M_Ib:
|
||||
inst_op1_d=Fetchb();
|
||||
break;
|
||||
case M_Ebx:
|
||||
if (inst.rm<0xc0) inst_op1_ds=(Bit8s)LoadMb(inst.rm_eaa);
|
||||
else inst_op1_ds=(Bit8s)reg_8(inst.rm_eai);
|
||||
break;
|
||||
case M_EbIb:
|
||||
inst_op2_d=Fetchb();
|
||||
case M_Eb:
|
||||
if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa);
|
||||
else inst_op1_d=reg_8(inst.rm_eai);
|
||||
break;
|
||||
case M_EbGb:
|
||||
if (inst.rm<0xc0) inst_op1_d=LoadMb(inst.rm_eaa);
|
||||
else inst_op1_d=reg_8(inst.rm_eai);
|
||||
inst_op2_d=reg_8(inst.rm_index);
|
||||
break;
|
||||
case M_GbEb:
|
||||
if (inst.rm<0xc0) inst_op2_d=LoadMb(inst.rm_eaa);
|
||||
else inst_op2_d=reg_8(inst.rm_eai);
|
||||
case M_Gb:
|
||||
inst_op1_d=reg_8(inst.rm_index);;
|
||||
break;
|
||||
/* Word */
|
||||
case M_Iw:
|
||||
inst_op1_d=Fetchw();
|
||||
break;
|
||||
case M_EwxGwx:
|
||||
inst_op2_ds=(Bit16s)reg_16(inst.rm_index);
|
||||
goto l_M_Ewx;
|
||||
case M_EwxIbx:
|
||||
inst_op2_ds=Fetchbs();
|
||||
goto l_M_Ewx;
|
||||
case M_EwxIwx:
|
||||
inst_op2_ds=Fetchws();
|
||||
l_M_Ewx:
|
||||
case M_Ewx:
|
||||
if (inst.rm<0xc0) inst_op1_ds=(Bit16s)LoadMw(inst.rm_eaa);
|
||||
else inst_op1_ds=(Bit16s)reg_16(inst.rm_eai);
|
||||
break;
|
||||
case M_EwIb:
|
||||
inst_op2_d=Fetchb();
|
||||
goto l_M_Ew;
|
||||
case M_EwIbx:
|
||||
inst_op2_ds=Fetchbs();
|
||||
goto l_M_Ew;
|
||||
case M_EwIw:
|
||||
inst_op2_d=Fetchw();
|
||||
goto l_M_Ew;
|
||||
case M_EwGwCL:
|
||||
inst_imm_d=reg_cl;
|
||||
goto l_M_EwGw;
|
||||
case M_EwGwIb:
|
||||
inst_imm_d=Fetchb();
|
||||
goto l_M_EwGw;
|
||||
case M_EwGwt:
|
||||
inst_op2_d=reg_16(inst.rm_index);
|
||||
inst.rm_eaa+=((Bit16s)inst_op2_d >> 4) * 2;
|
||||
goto l_M_Ew;
|
||||
l_M_EwGw:
|
||||
case M_EwGw:
|
||||
inst_op2_d=reg_16(inst.rm_index);
|
||||
l_M_Ew:
|
||||
case M_Ew:
|
||||
if (inst.rm<0xc0) inst_op1_d=LoadMw(inst.rm_eaa);
|
||||
else inst_op1_d=reg_16(inst.rm_eai);
|
||||
break;
|
||||
case M_GwEw:
|
||||
if (inst.rm<0xc0) inst_op2_d=LoadMw(inst.rm_eaa);
|
||||
else inst_op2_d=reg_16(inst.rm_eai);
|
||||
case M_Gw:
|
||||
inst_op1_d=reg_16(inst.rm_index);;
|
||||
break;
|
||||
/* DWord */
|
||||
case M_Id:
|
||||
inst_op1_d=Fetchd();
|
||||
break;
|
||||
case M_EdxGdx:
|
||||
inst_op2_ds=(Bit32s)reg_32(inst.rm_index);
|
||||
case M_Edx:
|
||||
if (inst.rm<0xc0) inst_op1_d=(Bit32s)LoadMd(inst.rm_eaa);
|
||||
else inst_op1_d=(Bit32s)reg_32(inst.rm_eai);
|
||||
break;
|
||||
case M_EdIb:
|
||||
inst_op2_d=Fetchb();
|
||||
goto l_M_Ed;
|
||||
case M_EdIbx:
|
||||
inst_op2_ds=Fetchbs();
|
||||
goto l_M_Ed;
|
||||
case M_EdId:
|
||||
inst_op2_d=Fetchd();
|
||||
goto l_M_Ed;
|
||||
case M_EdGdCL:
|
||||
inst_imm_d=reg_cl;
|
||||
goto l_M_EdGd;
|
||||
case M_EdGdt:
|
||||
inst_op2_d=reg_32(inst.rm_index);
|
||||
inst.rm_eaa+=((Bit32s)inst_op2_d >> 5) * 4;
|
||||
goto l_M_Ed;
|
||||
case M_EdGdIb:
|
||||
inst_imm_d=Fetchb();
|
||||
goto l_M_EdGd;
|
||||
l_M_EdGd:
|
||||
case M_EdGd:
|
||||
inst_op2_d=reg_32(inst.rm_index);
|
||||
l_M_Ed:
|
||||
case M_Ed:
|
||||
if (inst.rm<0xc0) inst_op1_d=LoadMd(inst.rm_eaa);
|
||||
else inst_op1_d=reg_32(inst.rm_eai);
|
||||
break;
|
||||
case M_GdEd:
|
||||
if (inst.rm<0xc0) inst_op2_d=LoadMd(inst.rm_eaa);
|
||||
else inst_op2_d=reg_32(inst.rm_eai);
|
||||
case M_Gd:
|
||||
inst_op1_d=reg_32(inst.rm_index);
|
||||
break;
|
||||
/* Others */
|
||||
|
||||
case M_SEG:
|
||||
//TODO Check for limit
|
||||
inst_op1_d=SegValue((SegNames)inst.rm_index);
|
||||
break;
|
||||
case M_Efw:
|
||||
if (inst.rm>=0xc0) goto illegalopcode;
|
||||
inst_op1_d=LoadMw(inst.rm_eaa);
|
||||
inst_op2_d=LoadMw(inst.rm_eaa+2);
|
||||
break;
|
||||
case M_Efd:
|
||||
if (inst.rm>=0xc0) goto illegalopcode;
|
||||
inst_op1_d=LoadMd(inst.rm_eaa);
|
||||
inst_op2_d=LoadMw(inst.rm_eaa+4);
|
||||
break;
|
||||
case M_EA:
|
||||
inst_op1_d=inst.rm_off;
|
||||
break;
|
||||
case M_POPw:
|
||||
inst_op1_d = Pop_16();
|
||||
break;
|
||||
case M_POPd:
|
||||
inst_op1_d = Pop_32();
|
||||
break;
|
||||
case M_GRP:
|
||||
inst.code=Groups[inst.code.op][inst.rm_index];
|
||||
goto l_MODRMswitch;
|
||||
case M_GRP_Ib:
|
||||
inst_op2_d=Fetchb();
|
||||
inst.code=Groups[inst.code.op][inst.rm_index];
|
||||
goto l_MODRMswitch;
|
||||
case M_GRP_CL:
|
||||
inst_op2_d=reg_cl;
|
||||
inst.code=Groups[inst.code.op][inst.rm_index];
|
||||
goto l_MODRMswitch;
|
||||
case M_GRP_1:
|
||||
inst_op2_d=1;
|
||||
inst.code=Groups[inst.code.op][inst.rm_index];
|
||||
goto l_MODRMswitch;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("MODRM:Unhandled load %d entry %x",inst.code.extra,inst.entry);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case L_POPw:
|
||||
inst_op1_d = Pop_16();
|
||||
break;
|
||||
case L_POPd:
|
||||
inst_op1_d = Pop_32();
|
||||
break;
|
||||
case L_POPfw:
|
||||
inst_op1_d = Pop_16();
|
||||
inst_op2_d = Pop_16();
|
||||
break;
|
||||
case L_POPfd:
|
||||
inst_op1_d = Pop_32();
|
||||
inst_op2_d = Pop_16();
|
||||
break;
|
||||
case L_Ib:
|
||||
inst_op1_d=Fetchb();
|
||||
break;
|
||||
case L_Ibx:
|
||||
inst_op1_ds=Fetchbs();
|
||||
break;
|
||||
case L_Iw:
|
||||
inst_op1_d=Fetchw();
|
||||
break;
|
||||
case L_Iwx:
|
||||
inst_op1_ds=Fetchws();
|
||||
break;
|
||||
case L_Idx:
|
||||
case L_Id:
|
||||
inst_op1_d=Fetchd();
|
||||
break;
|
||||
case L_Ifw:
|
||||
inst_op1_d=Fetchw();
|
||||
inst_op2_d=Fetchw();
|
||||
break;
|
||||
case L_Ifd:
|
||||
inst_op1_d=Fetchd();
|
||||
inst_op2_d=Fetchw();
|
||||
break;
|
||||
/* Direct load of registers */
|
||||
case L_REGbIb:
|
||||
inst_op2_d=Fetchb();
|
||||
case L_REGb:
|
||||
inst_op1_d=reg_8(inst.code.extra);
|
||||
break;
|
||||
case L_REGwIw:
|
||||
inst_op2_d=Fetchw();
|
||||
case L_REGw:
|
||||
inst_op1_d=reg_16(inst.code.extra);
|
||||
break;
|
||||
case L_REGdId:
|
||||
inst_op2_d=Fetchd();
|
||||
case L_REGd:
|
||||
inst_op1_d=reg_32(inst.code.extra);
|
||||
break;
|
||||
case L_SEG:
|
||||
inst_op1_d=SegValue((SegNames)inst.code.extra);
|
||||
break;
|
||||
/* Depending on addressize */
|
||||
case L_OP:
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
inst.rm_eaa=Fetchd();
|
||||
} else {
|
||||
inst.rm_eaa=Fetchw();
|
||||
}
|
||||
if (inst.prefix & PREFIX_SEG) {
|
||||
inst.rm_eaa+=inst.seg.base;
|
||||
} else {
|
||||
inst.rm_eaa+=SegBase(ds);
|
||||
}
|
||||
break;
|
||||
/* Special cases */
|
||||
case L_DOUBLE:
|
||||
inst.entry|=0x100;
|
||||
goto restartopcode;
|
||||
case L_PRESEG:
|
||||
inst.prefix|=PREFIX_SEG;
|
||||
inst.seg.base=SegBase((SegNames)inst.code.extra);
|
||||
goto restartopcode;
|
||||
case L_PREREPNE:
|
||||
inst.prefix|=PREFIX_REP;
|
||||
inst.repz=false;
|
||||
goto restartopcode;
|
||||
case L_PREREP:
|
||||
inst.prefix|=PREFIX_REP;
|
||||
inst.repz=true;
|
||||
goto restartopcode;
|
||||
case L_PREOP:
|
||||
inst.entry=(cpu.code.big ^1) * 0x200;
|
||||
goto restartopcode;
|
||||
case L_PREADD:
|
||||
inst.prefix=(inst.prefix & ~1) | (cpu.code.big ^ 1);
|
||||
goto restartopcode;
|
||||
case L_VAL:
|
||||
inst_op1_d=inst.code.extra;
|
||||
break;
|
||||
case L_INTO:
|
||||
if (!get_OF()) goto nextopcode;
|
||||
inst_op1_d=4;
|
||||
break;
|
||||
case D_IRETw:
|
||||
CPU_IRET(false,GetIP());
|
||||
if (GETFLAG(IF) && PIC_IRQCheck) {
|
||||
return CBRET_NONE;
|
||||
}
|
||||
continue;
|
||||
case D_IRETd:
|
||||
CPU_IRET(true,GetIP());
|
||||
if (GETFLAG(IF) && PIC_IRQCheck)
|
||||
return CBRET_NONE;
|
||||
continue;
|
||||
case D_RETFwIw:
|
||||
{
|
||||
Bitu words=Fetchw();
|
||||
FillFlags();
|
||||
CPU_RET(false,words,GetIP());
|
||||
continue;
|
||||
}
|
||||
case D_RETFw:
|
||||
FillFlags();
|
||||
CPU_RET(false,0,GetIP());
|
||||
continue;
|
||||
case D_RETFdIw:
|
||||
{
|
||||
Bitu words=Fetchw();
|
||||
FillFlags();
|
||||
CPU_RET(true,words,GetIP());
|
||||
continue;
|
||||
}
|
||||
case D_RETFd:
|
||||
FillFlags();
|
||||
CPU_RET(true,0,GetIP());
|
||||
continue;
|
||||
/* Direct operations */
|
||||
case L_STRING:
|
||||
#include "string.h"
|
||||
goto nextopcode;
|
||||
case D_PUSHAw:
|
||||
{
|
||||
Bit16u old_sp=reg_sp;
|
||||
Push_16(reg_ax);Push_16(reg_cx);Push_16(reg_dx);Push_16(reg_bx);
|
||||
Push_16(old_sp);Push_16(reg_bp);Push_16(reg_si);Push_16(reg_di);
|
||||
}
|
||||
goto nextopcode;
|
||||
case D_PUSHAd:
|
||||
{
|
||||
Bit32u old_esp=reg_esp;
|
||||
Push_32(reg_eax);Push_32(reg_ecx);Push_32(reg_edx);Push_32(reg_ebx);
|
||||
Push_32(old_esp);Push_32(reg_ebp);Push_32(reg_esi);Push_32(reg_edi);
|
||||
}
|
||||
goto nextopcode;
|
||||
case D_POPAw:
|
||||
reg_di=Pop_16();reg_si=Pop_16();reg_bp=Pop_16();Pop_16();//Don't save SP
|
||||
reg_bx=Pop_16();reg_dx=Pop_16();reg_cx=Pop_16();reg_ax=Pop_16();
|
||||
goto nextopcode;
|
||||
case D_POPAd:
|
||||
reg_edi=Pop_32();reg_esi=Pop_32();reg_ebp=Pop_32();Pop_32();//Don't save ESP
|
||||
reg_ebx=Pop_32();reg_edx=Pop_32();reg_ecx=Pop_32();reg_eax=Pop_32();
|
||||
goto nextopcode;
|
||||
case D_POPSEGw:
|
||||
if (CPU_PopSeg((SegNames)inst.code.extra,false)) RunException();
|
||||
goto nextopcode;
|
||||
case D_POPSEGd:
|
||||
if (CPU_PopSeg((SegNames)inst.code.extra,true)) RunException();
|
||||
goto nextopcode;
|
||||
case D_SETALC:
|
||||
reg_al = get_CF() ? 0xFF : 0;
|
||||
goto nextopcode;
|
||||
case D_XLAT:
|
||||
if (inst.prefix & PREFIX_SEG) {
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
reg_al=LoadMb(inst.seg.base+(Bit32u)(reg_ebx+reg_al));
|
||||
} else {
|
||||
reg_al=LoadMb(inst.seg.base+(Bit16u)(reg_bx+reg_al));
|
||||
}
|
||||
} else {
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
reg_al=LoadMb(SegBase(ds)+(Bit32u)(reg_ebx+reg_al));
|
||||
} else {
|
||||
reg_al=LoadMb(SegBase(ds)+(Bit16u)(reg_bx+reg_al));
|
||||
}
|
||||
}
|
||||
goto nextopcode;
|
||||
case D_CBW:
|
||||
reg_ax=(Bit8s)reg_al;
|
||||
goto nextopcode;
|
||||
case D_CWDE:
|
||||
reg_eax=(Bit16s)reg_ax;
|
||||
goto nextopcode;
|
||||
case D_CWD:
|
||||
if (reg_ax & 0x8000) reg_dx=0xffff;
|
||||
else reg_dx=0;
|
||||
goto nextopcode;
|
||||
case D_CDQ:
|
||||
if (reg_eax & 0x80000000) reg_edx=0xffffffff;
|
||||
else reg_edx=0;
|
||||
goto nextopcode;
|
||||
case D_CLI:
|
||||
if (CPU_CLI()) RunException();
|
||||
goto nextopcode;
|
||||
case D_STI:
|
||||
if (CPU_STI()) RunException();
|
||||
goto nextopcode;
|
||||
case D_STC:
|
||||
FillFlags();SETFLAGBIT(CF,true);
|
||||
goto nextopcode;
|
||||
case D_CLC:
|
||||
FillFlags();SETFLAGBIT(CF,false);
|
||||
goto nextopcode;
|
||||
case D_CMC:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,!(reg_flags & FLAG_CF));
|
||||
goto nextopcode;
|
||||
case D_CLD:
|
||||
SETFLAGBIT(DF,false);
|
||||
cpu.direction=1;
|
||||
goto nextopcode;
|
||||
case D_STD:
|
||||
SETFLAGBIT(DF,true);
|
||||
cpu.direction=-1;
|
||||
goto nextopcode;
|
||||
case D_PUSHF:
|
||||
if (CPU_PUSHF(inst.code.extra)) RunException();
|
||||
goto nextopcode;
|
||||
case D_POPF:
|
||||
if (CPU_POPF(inst.code.extra)) RunException();
|
||||
if (GETFLAG(IF) && PIC_IRQCheck) {
|
||||
SaveIP();
|
||||
return CBRET_NONE;
|
||||
}
|
||||
goto nextopcode;
|
||||
case D_SAHF:
|
||||
SETFLAGSb(reg_ah);
|
||||
goto nextopcode;
|
||||
case D_LAHF:
|
||||
FillFlags();
|
||||
reg_ah=reg_flags&0xff;
|
||||
goto nextopcode;
|
||||
case D_WAIT:
|
||||
case D_NOP:
|
||||
goto nextopcode;
|
||||
case D_LOCK: /* FIXME: according to intel, LOCK should raise an exception if it's not followed by one of a small set of instructions;
|
||||
probably doesn't matter for our purposes as it is a pentium prefix anyhow */
|
||||
LOG(LOG_CPU,LOG_NORMAL)("CPU:LOCK");
|
||||
goto nextopcode;
|
||||
case D_ENTERw:
|
||||
{
|
||||
Bitu bytes=Fetchw();
|
||||
Bitu level=Fetchb();
|
||||
CPU_ENTER(false,bytes,level);
|
||||
goto nextopcode;
|
||||
}
|
||||
case D_ENTERd:
|
||||
{
|
||||
Bitu bytes=Fetchw();
|
||||
Bitu level=Fetchb();
|
||||
CPU_ENTER(true,bytes,level);
|
||||
goto nextopcode;
|
||||
}
|
||||
case D_LEAVEw:
|
||||
reg_esp&=cpu.stack.notmask;
|
||||
reg_esp|=(reg_ebp&cpu.stack.mask);
|
||||
reg_bp=Pop_16();
|
||||
goto nextopcode;
|
||||
case D_LEAVEd:
|
||||
reg_esp&=cpu.stack.notmask;
|
||||
reg_esp|=(reg_ebp&cpu.stack.mask);
|
||||
reg_ebp=Pop_32();
|
||||
goto nextopcode;
|
||||
case D_DAA:
|
||||
DAA();
|
||||
goto nextopcode;
|
||||
case D_DAS:
|
||||
DAS();
|
||||
goto nextopcode;
|
||||
case D_AAA:
|
||||
AAA();
|
||||
goto nextopcode;
|
||||
case D_AAS:
|
||||
AAS();
|
||||
goto nextopcode;
|
||||
case D_CPUID:
|
||||
if (!CPU_CPUID()) goto illegalopcode;
|
||||
goto nextopcode;
|
||||
case D_HLT:
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
FillFlags();
|
||||
CPU_HLT(GetIP());
|
||||
return CBRET_NONE;
|
||||
case D_CLTS:
|
||||
if (cpu.pmode && cpu.cpl) goto illegalopcode;
|
||||
cpu.cr0&=(~CR0_TASKSWITCH);
|
||||
goto nextopcode;
|
||||
case D_ICEBP:
|
||||
CPU_SW_Interrupt_NoIOPLCheck(1,GetIP());
|
||||
continue;
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("LOAD:Unhandled code %d opcode %X",inst.code.load,inst.entry);
|
||||
goto illegalopcode;
|
||||
}
|
||||
|
39
src/cpu/core_full/loadwrite.h
Normal file
39
src/cpu/core_full/loadwrite.h
Normal file
@ -0,0 +1,39 @@
|
||||
#define SaveIP() reg_eip=(Bit32u)(inst.cseip-SegBase(cs));
|
||||
#define LoadIP() inst.cseip=SegBase(cs)+reg_eip;
|
||||
#define GetIP() (inst.cseip-SegBase(cs))
|
||||
|
||||
#define RunException() { \
|
||||
CPU_Exception(cpu.exception.which,cpu.exception.error); \
|
||||
continue; \
|
||||
}
|
||||
|
||||
static INLINE Bit8u the_Fetchb(EAPoint & loc) {
|
||||
Bit8u temp=LoadMb(loc);
|
||||
loc+=1;
|
||||
return temp;
|
||||
}
|
||||
|
||||
static INLINE Bit16u the_Fetchw(EAPoint & loc) {
|
||||
Bit16u temp=LoadMw(loc);
|
||||
loc+=2;
|
||||
return temp;
|
||||
}
|
||||
static INLINE Bit32u the_Fetchd(EAPoint & loc) {
|
||||
Bit32u temp=LoadMd(loc);
|
||||
loc+=4;
|
||||
return temp;
|
||||
}
|
||||
|
||||
#define Fetchb() the_Fetchb(inst.cseip)
|
||||
#define Fetchw() the_Fetchw(inst.cseip)
|
||||
#define Fetchd() the_Fetchd(inst.cseip)
|
||||
|
||||
#define Fetchbs() (Bit8s)the_Fetchb(inst.cseip)
|
||||
#define Fetchws() (Bit16s)the_Fetchw(inst.cseip)
|
||||
#define Fetchds() (Bit32s)the_Fetchd(inst.cseip)
|
||||
|
||||
#define Push_16 CPU_Push16
|
||||
#define Push_32 CPU_Push32
|
||||
#define Pop_16 CPU_Pop16
|
||||
#define Pop_32 CPU_Pop32
|
||||
|
645
src/cpu/core_full/op.h
Normal file
645
src/cpu/core_full/op.h
Normal file
@ -0,0 +1,645 @@
|
||||
/* Do the actual opcode */
|
||||
switch (inst.code.op) {
|
||||
case t_ADDb: case t_ADDw: case t_ADDd:
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d + lf_var2d;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_CMPb: case t_CMPw: case t_CMPd:
|
||||
case t_SUBb: case t_SUBw: case t_SUBd:
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d - lf_var2d;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_ORb: case t_ORw: case t_ORd:
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d | lf_var2d;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_XORb: case t_XORw: case t_XORd:
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d ^ lf_var2d;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_TESTb: case t_TESTw: case t_TESTd:
|
||||
case t_ANDb: case t_ANDw: case t_ANDd:
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d & lf_var2d;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_ADCb: case t_ADCw: case t_ADCd:
|
||||
lflags.oldcf=(get_CF()!=0);
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d + lf_var2d + lflags.oldcf;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_SBBb: case t_SBBw: case t_SBBd:
|
||||
lflags.oldcf=(get_CF()!=0);
|
||||
lf_var1d=inst_op1_d;
|
||||
lf_var2d=inst_op2_d;
|
||||
inst_op1_d=lf_resd=lf_var1d - lf_var2d - lflags.oldcf;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_INCb: case t_INCw: case t_INCd:
|
||||
LoadCF;
|
||||
lf_var1d=inst_op1_d;
|
||||
inst_op1_d=lf_resd=inst_op1_d+1;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
case t_DECb: case t_DECw: case t_DECd:
|
||||
LoadCF;
|
||||
lf_var1d=inst_op1_d;
|
||||
inst_op1_d=lf_resd=inst_op1_d-1;
|
||||
lflags.type=inst.code.op;
|
||||
break;
|
||||
/* Using the instructions.h defines */
|
||||
case t_ROLb:
|
||||
ROLB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_ROLw:
|
||||
ROLW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_ROLd:
|
||||
ROLD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case t_RORb:
|
||||
RORB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_RORw:
|
||||
RORW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_RORd:
|
||||
RORD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case t_RCLb:
|
||||
RCLB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_RCLw:
|
||||
RCLW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_RCLd:
|
||||
RCLD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case t_RCRb:
|
||||
RCRB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_RCRw:
|
||||
RCRW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_RCRd:
|
||||
RCRD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case t_SHLb:
|
||||
SHLB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_SHLw:
|
||||
SHLW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_SHLd:
|
||||
SHLD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case t_SHRb:
|
||||
SHRB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_SHRw:
|
||||
SHRW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_SHRd:
|
||||
SHRD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case t_SARb:
|
||||
SARB(inst_op1_b,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_SARw:
|
||||
SARW(inst_op1_w,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
case t_SARd:
|
||||
SARD(inst_op1_d,inst_op2_b,LoadD,SaveD);
|
||||
break;
|
||||
|
||||
case O_DSHLw:
|
||||
{
|
||||
DSHLW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD);
|
||||
break;
|
||||
}
|
||||
case O_DSHRw:
|
||||
{
|
||||
DSHRW(inst_op1_w,inst_op2_w,inst_imm_b,LoadD,SaveD);
|
||||
break;
|
||||
}
|
||||
case O_DSHLd:
|
||||
{
|
||||
DSHLD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD);
|
||||
break;
|
||||
}
|
||||
case O_DSHRd:
|
||||
{
|
||||
DSHRD(inst_op1_d,inst_op2_d,inst_imm_b,LoadD,SaveD);
|
||||
break;
|
||||
}
|
||||
|
||||
case t_NEGb:
|
||||
lf_var1b=inst_op1_b;
|
||||
inst_op1_b=lf_resb=0-inst_op1_b;
|
||||
lflags.type=t_NEGb;
|
||||
break;
|
||||
case t_NEGw:
|
||||
lf_var1w=inst_op1_w;
|
||||
inst_op1_w=lf_resw=0-inst_op1_w;
|
||||
lflags.type=t_NEGw;
|
||||
break;
|
||||
case t_NEGd:
|
||||
lf_var1d=inst_op1_d;
|
||||
inst_op1_d=lf_resd=0-inst_op1_d;
|
||||
lflags.type=t_NEGd;
|
||||
break;
|
||||
|
||||
case O_NOT:
|
||||
inst_op1_d=~inst_op1_d;
|
||||
break;
|
||||
|
||||
/* Special instructions */
|
||||
case O_IMULRw:
|
||||
DIMULW(inst_op1_ws,inst_op1_ws,inst_op2_ws,LoadD,SaveD);
|
||||
break;
|
||||
case O_IMULRd:
|
||||
DIMULD(inst_op1_ds,inst_op1_ds,inst_op2_ds,LoadD,SaveD);
|
||||
break;
|
||||
case O_MULb:
|
||||
MULB(inst_op1_b,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_MULw:
|
||||
MULW(inst_op1_w,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_MULd:
|
||||
MULD(inst_op1_d,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_IMULb:
|
||||
IMULB(inst_op1_b,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_IMULw:
|
||||
IMULW(inst_op1_w,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_IMULd:
|
||||
IMULD(inst_op1_d,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_DIVb:
|
||||
DIVB(inst_op1_b,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_DIVw:
|
||||
DIVW(inst_op1_w,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_DIVd:
|
||||
DIVD(inst_op1_d,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_IDIVb:
|
||||
IDIVB(inst_op1_b,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_IDIVw:
|
||||
IDIVW(inst_op1_w,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_IDIVd:
|
||||
IDIVD(inst_op1_d,LoadD,0);
|
||||
goto nextopcode;
|
||||
case O_AAM:
|
||||
AAM(inst_op1_b);
|
||||
goto nextopcode;
|
||||
case O_AAD:
|
||||
AAD(inst_op1_b);
|
||||
goto nextopcode;
|
||||
|
||||
case O_C_O: inst.cond=TFLG_O; break;
|
||||
case O_C_NO: inst.cond=TFLG_NO; break;
|
||||
case O_C_B: inst.cond=TFLG_B; break;
|
||||
case O_C_NB: inst.cond=TFLG_NB; break;
|
||||
case O_C_Z: inst.cond=TFLG_Z; break;
|
||||
case O_C_NZ: inst.cond=TFLG_NZ; break;
|
||||
case O_C_BE: inst.cond=TFLG_BE; break;
|
||||
case O_C_NBE: inst.cond=TFLG_NBE; break;
|
||||
case O_C_S: inst.cond=TFLG_S; break;
|
||||
case O_C_NS: inst.cond=TFLG_NS; break;
|
||||
case O_C_P: inst.cond=TFLG_P; break;
|
||||
case O_C_NP: inst.cond=TFLG_NP; break;
|
||||
case O_C_L: inst.cond=TFLG_L; break;
|
||||
case O_C_NL: inst.cond=TFLG_NL; break;
|
||||
case O_C_LE: inst.cond=TFLG_LE; break;
|
||||
case O_C_NLE: inst.cond=TFLG_NLE; break;
|
||||
|
||||
case O_ALOP:
|
||||
reg_al=LoadMb(inst.rm_eaa);
|
||||
goto nextopcode;
|
||||
case O_AXOP:
|
||||
reg_ax=LoadMw(inst.rm_eaa);
|
||||
goto nextopcode;
|
||||
case O_EAXOP:
|
||||
reg_eax=LoadMd(inst.rm_eaa);
|
||||
goto nextopcode;
|
||||
case O_OPAL:
|
||||
SaveMb(inst.rm_eaa,reg_al);
|
||||
goto nextopcode;
|
||||
case O_OPAX:
|
||||
SaveMw(inst.rm_eaa,reg_ax);
|
||||
goto nextopcode;
|
||||
case O_OPEAX:
|
||||
SaveMd(inst.rm_eaa,reg_eax);
|
||||
goto nextopcode;
|
||||
case O_SEGDS:
|
||||
inst.code.extra=ds;
|
||||
break;
|
||||
case O_SEGES:
|
||||
inst.code.extra=es;
|
||||
break;
|
||||
case O_SEGFS:
|
||||
inst.code.extra=fs;
|
||||
break;
|
||||
case O_SEGGS:
|
||||
inst.code.extra=gs;
|
||||
break;
|
||||
case O_SEGSS:
|
||||
inst.code.extra=ss;
|
||||
break;
|
||||
|
||||
case O_LOOP:
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
if (--reg_ecx) break;
|
||||
} else {
|
||||
if (--reg_cx) break;
|
||||
}
|
||||
goto nextopcode;
|
||||
case O_LOOPZ:
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
if (--reg_ecx && get_ZF()) break;
|
||||
} else {
|
||||
if (--reg_cx && get_ZF()) break;
|
||||
}
|
||||
goto nextopcode;
|
||||
case O_LOOPNZ:
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
if (--reg_ecx && !get_ZF()) break;
|
||||
} else {
|
||||
if (--reg_cx && !get_ZF()) break;
|
||||
}
|
||||
goto nextopcode;
|
||||
case O_JCXZ:
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
if (reg_ecx) goto nextopcode;
|
||||
} else {
|
||||
if (reg_cx) goto nextopcode;
|
||||
}
|
||||
break;
|
||||
case O_XCHG_AX:
|
||||
{
|
||||
Bit16u temp=reg_ax;
|
||||
reg_ax=inst_op1_w;
|
||||
inst_op1_w=temp;
|
||||
break;
|
||||
}
|
||||
case O_XCHG_EAX:
|
||||
{
|
||||
Bit32u temp=reg_eax;
|
||||
reg_eax=inst_op1_d;
|
||||
inst_op1_d=temp;
|
||||
break;
|
||||
}
|
||||
case O_CALLNw:
|
||||
SaveIP();
|
||||
Push_16(reg_ip);
|
||||
break;
|
||||
case O_CALLNd:
|
||||
SaveIP();
|
||||
Push_32(reg_eip);
|
||||
break;
|
||||
case O_CALLFw:
|
||||
FillFlags();
|
||||
CPU_CALL(false,inst_op2_d,inst_op1_d,GetIP());
|
||||
continue;
|
||||
case O_CALLFd:
|
||||
FillFlags();
|
||||
CPU_CALL(true,inst_op2_d,inst_op1_d,GetIP());
|
||||
continue;
|
||||
case O_JMPFw:
|
||||
FillFlags();
|
||||
CPU_JMP(false,inst_op2_d,inst_op1_d,GetIP());
|
||||
continue;
|
||||
case O_JMPFd:
|
||||
FillFlags();
|
||||
CPU_JMP(true,inst_op2_d,inst_op1_d,GetIP());
|
||||
continue;
|
||||
case O_INT:
|
||||
#if C_DEBUG
|
||||
FillFlags();
|
||||
if (((inst.entry & 0xFF)==0xcc) && DEBUG_Breakpoint())
|
||||
return debugCallback;
|
||||
else if (DEBUG_IntBreakpoint(inst_op1_b))
|
||||
return debugCallback;
|
||||
#endif
|
||||
CPU_SW_Interrupt(inst_op1_b,GetIP());
|
||||
continue;
|
||||
case O_INb:
|
||||
if (CPU_IO_Exception(inst_op1_d,1)) RunException();
|
||||
reg_al=IO_ReadB(inst_op1_d);
|
||||
goto nextopcode;
|
||||
case O_INw:
|
||||
if (CPU_IO_Exception(inst_op1_d,2)) RunException();
|
||||
reg_ax=IO_ReadW(inst_op1_d);
|
||||
goto nextopcode;
|
||||
case O_INd:
|
||||
if (CPU_IO_Exception(inst_op1_d,4)) RunException();
|
||||
reg_eax=IO_ReadD(inst_op1_d);
|
||||
goto nextopcode;
|
||||
case O_OUTb:
|
||||
if (CPU_IO_Exception(inst_op1_d,1)) RunException();
|
||||
IO_WriteB(inst_op1_d,reg_al);
|
||||
goto nextopcode;
|
||||
case O_OUTw:
|
||||
if (CPU_IO_Exception(inst_op1_d,2)) RunException();
|
||||
IO_WriteW(inst_op1_d,reg_ax);
|
||||
goto nextopcode;
|
||||
case O_OUTd:
|
||||
if (CPU_IO_Exception(inst_op1_d,4)) RunException();
|
||||
IO_WriteD(inst_op1_d,reg_eax);
|
||||
goto nextopcode;
|
||||
case O_CBACK:
|
||||
FillFlags();SaveIP();
|
||||
return inst_op1_d;
|
||||
case O_GRP6w:
|
||||
case O_GRP6d:
|
||||
if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegalopcode;
|
||||
switch (inst.rm_index) {
|
||||
case 0x00: /* SLDT */
|
||||
inst_op1_d=(Bit32u)CPU_SLDT();
|
||||
break;
|
||||
case 0x01: /* STR */
|
||||
inst_op1_d=(Bit32u)CPU_STR();
|
||||
break;
|
||||
case 0x02: /* LLDT */
|
||||
if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
if (CPU_LLDT(inst_op1_d)) RunException();
|
||||
goto nextopcode; /* Else value will saved */
|
||||
case 0x03: /* LTR */
|
||||
if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
if (CPU_LTR(inst_op1_d)) RunException();
|
||||
goto nextopcode; /* Else value will saved */
|
||||
case 0x04: /* VERR */
|
||||
CPU_VERR(inst_op1_d);
|
||||
goto nextopcode; /* Else value will saved */
|
||||
case 0x05: /* VERW */
|
||||
CPU_VERW(inst_op1_d);
|
||||
goto nextopcode; /* Else value will saved */
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("Group 6 Illegal subfunction %X",inst.rm_index);
|
||||
goto illegalopcode;
|
||||
}
|
||||
break;
|
||||
case O_GRP7w:
|
||||
case O_GRP7d:
|
||||
switch (inst.rm_index) {
|
||||
case 0: /* SGDT */
|
||||
SaveMw(inst.rm_eaa,CPU_SGDT_limit());
|
||||
SaveMd(inst.rm_eaa+2,CPU_SGDT_base());
|
||||
goto nextopcode;
|
||||
case 1: /* SIDT */
|
||||
SaveMw(inst.rm_eaa,CPU_SIDT_limit());
|
||||
SaveMd(inst.rm_eaa+2,CPU_SIDT_base());
|
||||
goto nextopcode;
|
||||
case 2: /* LGDT */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
CPU_LGDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF));
|
||||
goto nextopcode;
|
||||
case 3: /* LIDT */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
CPU_LIDT(LoadMw(inst.rm_eaa),LoadMd(inst.rm_eaa+2)&((inst.code.op == O_GRP7w) ? 0xFFFFFF : 0xFFFFFFFF));
|
||||
goto nextopcode;
|
||||
case 4: /* SMSW */
|
||||
inst_op1_d=CPU_SMSW();
|
||||
break;
|
||||
case 6: /* LMSW */
|
||||
FillFlags();
|
||||
if (CPU_LMSW(inst_op1_w)) RunException();
|
||||
goto nextopcode;
|
||||
case 7: /* INVLPG */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
FillFlags();
|
||||
PAGING_ClearTLB();
|
||||
goto nextopcode;
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("Group 7 Illegal subfunction %X",inst.rm_index);
|
||||
goto illegalopcode;
|
||||
}
|
||||
break;
|
||||
case O_M_CRx_Rd:
|
||||
if (CPU_WRITE_CRX(inst.rm_index,inst_op1_d)) RunException();
|
||||
break;
|
||||
case O_M_Rd_CRx:
|
||||
if (CPU_READ_CRX(inst.rm_index,inst_op1_d)) RunException();
|
||||
break;
|
||||
case O_M_DRx_Rd:
|
||||
if (CPU_WRITE_DRX(inst.rm_index,inst_op1_d)) RunException();
|
||||
break;
|
||||
case O_M_Rd_DRx:
|
||||
if (CPU_READ_DRX(inst.rm_index,inst_op1_d)) RunException();
|
||||
break;
|
||||
case O_M_TRx_Rd:
|
||||
if (CPU_WRITE_TRX(inst.rm_index,inst_op1_d)) RunException();
|
||||
break;
|
||||
case O_M_Rd_TRx:
|
||||
if (CPU_READ_TRX(inst.rm_index,inst_op1_d)) RunException();
|
||||
break;
|
||||
case O_LAR:
|
||||
{
|
||||
Bitu ar=inst_op2_d;
|
||||
CPU_LAR(inst_op1_w,ar);
|
||||
inst_op1_d=(Bit32u)ar;
|
||||
}
|
||||
break;
|
||||
case O_LSL:
|
||||
{
|
||||
Bitu limit=inst_op2_d;
|
||||
CPU_LSL(inst_op1_w,limit);
|
||||
inst_op1_d=(Bit32u)limit;
|
||||
}
|
||||
break;
|
||||
case O_ARPL:
|
||||
{
|
||||
Bitu new_sel=inst_op1_d;
|
||||
CPU_ARPL(new_sel,inst_op2_d);
|
||||
inst_op1_d=(Bit32u)new_sel;
|
||||
}
|
||||
break;
|
||||
case O_BSFw:
|
||||
{
|
||||
FillFlags();
|
||||
if (!inst_op1_w) {
|
||||
SETFLAGBIT(ZF,true);
|
||||
goto nextopcode;
|
||||
} else {
|
||||
Bitu count=0;
|
||||
while (1) {
|
||||
if (inst_op1_w & 0x1) break;
|
||||
count++;inst_op1_w>>=1;
|
||||
}
|
||||
inst_op1_d=count;
|
||||
SETFLAGBIT(ZF,false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case O_BSFd:
|
||||
{
|
||||
FillFlags();
|
||||
if (!inst_op1_d) {
|
||||
SETFLAGBIT(ZF,true);
|
||||
goto nextopcode;
|
||||
} else {
|
||||
Bitu count=0;
|
||||
while (1) {
|
||||
if (inst_op1_d & 0x1) break;
|
||||
count++;inst_op1_d>>=1;
|
||||
}
|
||||
inst_op1_d=count;
|
||||
SETFLAGBIT(ZF,false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case O_BSRw:
|
||||
{
|
||||
FillFlags();
|
||||
if (!inst_op1_w) {
|
||||
SETFLAGBIT(ZF,true);
|
||||
goto nextopcode;
|
||||
} else {
|
||||
Bitu count=15;
|
||||
while (1) {
|
||||
if (inst_op1_w & 0x8000) break;
|
||||
count--;inst_op1_w<<=1;
|
||||
}
|
||||
inst_op1_d=count;
|
||||
SETFLAGBIT(ZF,false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case O_BSRd:
|
||||
{
|
||||
FillFlags();
|
||||
if (!inst_op1_d) {
|
||||
SETFLAGBIT(ZF,true);
|
||||
goto nextopcode;
|
||||
} else {
|
||||
Bitu count=31;
|
||||
while (1) {
|
||||
if (inst_op1_d & 0x80000000) break;
|
||||
count--;inst_op1_d<<=1;
|
||||
}
|
||||
inst_op1_d=count;
|
||||
SETFLAGBIT(ZF,false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case O_BTw:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
|
||||
break;
|
||||
case O_BTSw:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
|
||||
inst_op1_d|=(1 << (inst_op2_d & 15));
|
||||
break;
|
||||
case O_BTCw:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
|
||||
inst_op1_d^=(1 << (inst_op2_d & 15));
|
||||
break;
|
||||
case O_BTRw:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 15))));
|
||||
inst_op1_d&=~(1 << (inst_op2_d & 15));
|
||||
break;
|
||||
case O_BTd:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
|
||||
break;
|
||||
case O_BTSd:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
|
||||
inst_op1_d|=(1 << (inst_op2_d & 31));
|
||||
break;
|
||||
case O_BTCd:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
|
||||
inst_op1_d^=(1 << (inst_op2_d & 31));
|
||||
break;
|
||||
case O_BTRd:
|
||||
FillFlags();
|
||||
SETFLAGBIT(CF,(inst_op1_d & (1 << (inst_op2_d & 31))));
|
||||
inst_op1_d&=~(1 << (inst_op2_d & 31));
|
||||
break;
|
||||
case O_BSWAP:
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegalopcode;
|
||||
BSWAP(inst_op1_d);
|
||||
break;
|
||||
case O_CMPXCHG:
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486NEWSLOW) goto illegalopcode;
|
||||
FillFlags();
|
||||
if (inst_op1_d==reg_eax) {
|
||||
inst_op1_d=reg_32(inst.rm_index);
|
||||
if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); // early write-pf
|
||||
SETFLAGBIT(ZF,1);
|
||||
} else {
|
||||
if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d); // early write-pf
|
||||
reg_eax=inst_op1_d;
|
||||
SETFLAGBIT(ZF,0);
|
||||
}
|
||||
break;
|
||||
case O_FPU:
|
||||
#if C_FPU
|
||||
switch (((inst.rm>=0xc0) << 3) | inst.code.save) {
|
||||
case 0x00: FPU_ESC0_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x01: FPU_ESC1_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x02: FPU_ESC2_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x03: FPU_ESC3_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x04: FPU_ESC4_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x05: FPU_ESC5_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x06: FPU_ESC6_EA(inst.rm,inst.rm_eaa);break;
|
||||
case 0x07: FPU_ESC7_EA(inst.rm,inst.rm_eaa);break;
|
||||
|
||||
case 0x08: FPU_ESC0_Normal(inst.rm);break;
|
||||
case 0x09: FPU_ESC1_Normal(inst.rm);break;
|
||||
case 0x0a: FPU_ESC2_Normal(inst.rm);break;
|
||||
case 0x0b: FPU_ESC3_Normal(inst.rm);break;
|
||||
case 0x0c: FPU_ESC4_Normal(inst.rm);break;
|
||||
case 0x0d: FPU_ESC5_Normal(inst.rm);break;
|
||||
case 0x0e: FPU_ESC6_Normal(inst.rm);break;
|
||||
case 0x0f: FPU_ESC7_Normal(inst.rm);break;
|
||||
}
|
||||
goto nextopcode;
|
||||
#else
|
||||
LOG(LOG_CPU,LOG_ERROR)("Unhandled FPU ESCAPE %d",inst.code.save);
|
||||
goto nextopcode;
|
||||
#endif
|
||||
case O_BOUNDw:
|
||||
{
|
||||
Bit16s bound_min, bound_max;
|
||||
bound_min=LoadMw(inst.rm_eaa);
|
||||
bound_max=LoadMw(inst.rm_eaa+2);
|
||||
if ( (((Bit16s)inst_op1_w) < bound_min) || (((Bit16s)inst_op1_w) > bound_max) ) {
|
||||
EXCEPTION(5);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("OP:Unhandled code %d entry %X",inst.code.op,inst.entry);
|
||||
|
||||
}
|
814
src/cpu/core_full/optable.h
Normal file
814
src/cpu/core_full/optable.h
Normal file
@ -0,0 +1,814 @@
|
||||
/* Big ass opcode table normal,double, 66 normal, 66 double */
|
||||
static OpCode OpCodeTable[1024]={
|
||||
/* 0x00 - 0x07 */
|
||||
{L_MODRM ,t_ADDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADDw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_ADDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADDw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_ADDb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ADDw ,S_REGw ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHw,es },{D_POPSEGw,0 ,0 ,es },
|
||||
/* 0x08 - 0x0f */
|
||||
{L_MODRM ,t_ORb ,S_Eb ,M_EbGb },{L_MODRM ,t_ORw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_ORb ,S_Gb ,M_GbEb },{L_MODRM ,t_ORw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_ORb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ORw ,S_REGw ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHw,cs },{L_DOUBLE ,0 ,0 ,0 },
|
||||
|
||||
/* 0x10 - 0x17 */
|
||||
{L_MODRM ,t_ADCb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADCw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_ADCb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADCw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_ADCb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ADCw ,S_REGw ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHw,ss },{D_POPSEGw,0 ,0 ,ss },
|
||||
/* 0x18 - 0x1f */
|
||||
{L_MODRM ,t_SBBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SBBw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_SBBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SBBw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_SBBb ,S_REGb ,REGI_AL },{L_REGwIw ,t_SBBw ,S_REGw ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHw,ds },{D_POPSEGw,0 ,0 ,ds },
|
||||
|
||||
/* 0x20 - 0x27 */
|
||||
{L_MODRM ,t_ANDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ANDw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_ANDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ANDw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_ANDb ,S_REGb ,REGI_AL },{L_REGwIw ,t_ANDw ,S_REGw ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,es },{D_DAA ,0 ,0 ,0 },
|
||||
/* 0x28 - 0x2f */
|
||||
{L_MODRM ,t_SUBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SUBw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_SUBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SUBw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_SUBb ,S_REGb ,REGI_AL },{L_REGwIw ,t_SUBw ,S_REGw ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,cs },{D_DAS ,0 ,0 ,0 },
|
||||
|
||||
/* 0x30 - 0x37 */
|
||||
{L_MODRM ,t_XORb ,S_Eb ,M_EbGb },{L_MODRM ,t_XORw ,S_Ew ,M_EwGw },
|
||||
{L_MODRM ,t_XORb ,S_Gb ,M_GbEb },{L_MODRM ,t_XORw ,S_Gw ,M_GwEw },
|
||||
{L_REGbIb ,t_XORb ,S_REGb ,REGI_AL },{L_REGwIw ,t_XORw ,S_REGw ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,ss },{D_AAA ,0 ,0 ,0 },
|
||||
/* 0x38 - 0x3f */
|
||||
{L_MODRM ,t_CMPb ,0 ,M_EbGb },{L_MODRM ,t_CMPw ,0 ,M_EwGw },
|
||||
{L_MODRM ,t_CMPb ,0 ,M_GbEb },{L_MODRM ,t_CMPw ,0 ,M_GwEw },
|
||||
{L_REGbIb ,t_CMPb ,0 ,REGI_AL },{L_REGwIw ,t_CMPw ,0 ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,ds },{D_AAS ,0 ,0 ,0 },
|
||||
|
||||
/* 0x40 - 0x47 */
|
||||
{L_REGw ,t_INCw ,S_REGw ,REGI_AX},{L_REGw ,t_INCw ,S_REGw ,REGI_CX},
|
||||
{L_REGw ,t_INCw ,S_REGw ,REGI_DX},{L_REGw ,t_INCw ,S_REGw ,REGI_BX},
|
||||
{L_REGw ,t_INCw ,S_REGw ,REGI_SP},{L_REGw ,t_INCw ,S_REGw ,REGI_BP},
|
||||
{L_REGw ,t_INCw ,S_REGw ,REGI_SI},{L_REGw ,t_INCw ,S_REGw ,REGI_DI},
|
||||
/* 0x48 - 0x4f */
|
||||
{L_REGw ,t_DECw ,S_REGw ,REGI_AX},{L_REGw ,t_DECw ,S_REGw ,REGI_CX},
|
||||
{L_REGw ,t_DECw ,S_REGw ,REGI_DX},{L_REGw ,t_DECw ,S_REGw ,REGI_BX},
|
||||
{L_REGw ,t_DECw ,S_REGw ,REGI_SP},{L_REGw ,t_DECw ,S_REGw ,REGI_BP},
|
||||
{L_REGw ,t_DECw ,S_REGw ,REGI_SI},{L_REGw ,t_DECw ,S_REGw ,REGI_DI},
|
||||
|
||||
/* 0x50 - 0x57 */
|
||||
{L_REGw ,0 ,S_PUSHw,REGI_AX},{L_REGw ,0 ,S_PUSHw,REGI_CX},
|
||||
{L_REGw ,0 ,S_PUSHw,REGI_DX},{L_REGw ,0 ,S_PUSHw,REGI_BX},
|
||||
{L_REGw ,0 ,S_PUSHw,REGI_SP},{L_REGw ,0 ,S_PUSHw,REGI_BP},
|
||||
{L_REGw ,0 ,S_PUSHw,REGI_SI},{L_REGw ,0 ,S_PUSHw,REGI_DI},
|
||||
/* 0x58 - 0x5f */
|
||||
{L_POPw ,0 ,S_REGw ,REGI_AX},{L_POPw ,0 ,S_REGw ,REGI_CX},
|
||||
{L_POPw ,0 ,S_REGw ,REGI_DX},{L_POPw ,0 ,S_REGw ,REGI_BX},
|
||||
{L_POPw ,0 ,S_REGw ,REGI_SP},{L_POPw ,0 ,S_REGw ,REGI_BP},
|
||||
{L_POPw ,0 ,S_REGw ,REGI_SI},{L_POPw ,0 ,S_REGw ,REGI_DI},
|
||||
|
||||
|
||||
/* 0x60 - 0x67 */
|
||||
{D_PUSHAw ,0 ,0 ,0 },{D_POPAw ,0 ,0 ,0 },
|
||||
{L_MODRM ,O_BOUNDw ,0 ,M_Gw },{L_MODRM_NVM ,O_ARPL ,S_Ew ,M_EwGw },
|
||||
{L_PRESEG ,0 ,0 ,fs },{L_PRESEG ,0 ,0 ,gs },
|
||||
{L_PREOP ,0 ,0 ,0 },{L_PREADD ,0 ,0 ,0 },
|
||||
/* 0x68 - 0x6f */
|
||||
{L_Iw ,0 ,S_PUSHw,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxIwx},
|
||||
{L_Ibx ,0 ,S_PUSHw,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxIbx},
|
||||
{L_STRING ,R_INSB ,0 ,0 },{L_STRING ,R_INSW ,0 ,0 },
|
||||
{L_STRING ,R_OUTSB ,0 ,0 },{L_STRING ,R_OUTSW ,0 ,0 },
|
||||
|
||||
|
||||
/* 0x70 - 0x77 */
|
||||
{L_Ibx ,O_C_O ,S_C_AIPw,0 },{L_Ibx ,O_C_NO ,S_C_AIPw,0 },
|
||||
{L_Ibx ,O_C_B ,S_C_AIPw,0 },{L_Ibx ,O_C_NB ,S_C_AIPw,0 },
|
||||
{L_Ibx ,O_C_Z ,S_C_AIPw,0 },{L_Ibx ,O_C_NZ ,S_C_AIPw,0 },
|
||||
{L_Ibx ,O_C_BE ,S_C_AIPw,0 },{L_Ibx ,O_C_NBE ,S_C_AIPw,0 },
|
||||
/* 0x78 - 0x7f */
|
||||
{L_Ibx ,O_C_S ,S_C_AIPw,0 },{L_Ibx ,O_C_NS ,S_C_AIPw,0 },
|
||||
{L_Ibx ,O_C_P ,S_C_AIPw,0 },{L_Ibx ,O_C_NP ,S_C_AIPw,0 },
|
||||
{L_Ibx ,O_C_L ,S_C_AIPw,0 },{L_Ibx ,O_C_NL ,S_C_AIPw,0 },
|
||||
{L_Ibx ,O_C_LE ,S_C_AIPw,0 },{L_Ibx ,O_C_NLE ,S_C_AIPw,0 },
|
||||
|
||||
|
||||
/* 0x80 - 0x87 */
|
||||
{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,1 ,0 ,M_GRP },
|
||||
{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,3 ,0 ,M_GRP },
|
||||
{L_MODRM ,t_TESTb ,0 ,M_EbGb },{L_MODRM ,t_TESTw ,0 ,M_EwGw },
|
||||
{L_MODRM ,0 ,S_EbGb ,M_GbEb },{L_MODRM ,0 ,S_EwGw ,M_GwEw },
|
||||
/* 0x88 - 0x8f */
|
||||
{L_MODRM ,0 ,S_Eb ,M_Gb },{L_MODRM ,0 ,S_Ew ,M_Gw },
|
||||
{L_MODRM ,0 ,S_Gb ,M_Eb },{L_MODRM ,0 ,S_Gw ,M_Ew },
|
||||
{L_MODRM ,0 ,S_Ew ,M_SEG },{L_MODRM ,0 ,S_Gw ,M_EA },
|
||||
{L_MODRM ,0 ,S_SEGm ,M_Ew },{L_POPwRM ,0 ,S_Ew ,M_None },
|
||||
|
||||
/* 0x90 - 0x97 */
|
||||
{D_NOP ,0 ,0 ,0 },{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_CX},
|
||||
{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_DX},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_BX},
|
||||
{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_SP},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_BP},
|
||||
{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_SI},{L_REGw ,O_XCHG_AX ,S_REGw ,REGI_DI},
|
||||
/* 0x98 - 0x9f */
|
||||
{D_CBW ,0 ,0 ,0 },{D_CWD ,0 ,0 ,0 },
|
||||
{L_Ifw ,O_CALLFw ,0 ,0 },{D_WAIT ,0 ,0 ,0 },
|
||||
{D_PUSHF ,0 ,0 ,0 },{D_POPF ,0 ,0 ,0 },
|
||||
{D_SAHF ,0 ,0 ,0 },{D_LAHF ,0 ,0 ,0 },
|
||||
|
||||
|
||||
/* 0xa0 - 0xa7 */
|
||||
{L_OP ,O_ALOP ,0 ,0 },{L_OP ,O_AXOP ,0 ,0 },
|
||||
{L_OP ,O_OPAL ,0 ,0 },{L_OP ,O_OPAX ,0 ,0 },
|
||||
{L_STRING ,R_MOVSB ,0 ,0 },{L_STRING ,R_MOVSW ,0 ,0 },
|
||||
{L_STRING ,R_CMPSB ,0 ,0 },{L_STRING ,R_CMPSW ,0 ,0 },
|
||||
/* 0xa8 - 0xaf */
|
||||
{L_REGbIb ,t_TESTb ,0 ,REGI_AL},{L_REGwIw ,t_TESTw ,0 ,REGI_AX},
|
||||
{L_STRING ,R_STOSB ,0 ,0 },{L_STRING ,R_STOSW ,0 ,0 },
|
||||
{L_STRING ,R_LODSB ,0 ,0 },{L_STRING ,R_LODSW ,0 ,0 },
|
||||
{L_STRING ,R_SCASB ,0 ,0 },{L_STRING ,R_SCASW ,0 ,0 },
|
||||
|
||||
/* 0xb0 - 0xb7 */
|
||||
{L_Ib ,0 ,S_REGb ,REGI_AL},{L_Ib ,0 ,S_REGb ,REGI_CL},
|
||||
{L_Ib ,0 ,S_REGb ,REGI_DL},{L_Ib ,0 ,S_REGb ,REGI_BL},
|
||||
{L_Ib ,0 ,S_REGb ,REGI_AH},{L_Ib ,0 ,S_REGb ,REGI_CH},
|
||||
{L_Ib ,0 ,S_REGb ,REGI_DH},{L_Ib ,0 ,S_REGb ,REGI_BH},
|
||||
/* 0xb8 - 0xbf */
|
||||
{L_Iw ,0 ,S_REGw ,REGI_AX},{L_Iw ,0 ,S_REGw ,REGI_CX},
|
||||
{L_Iw ,0 ,S_REGw ,REGI_DX},{L_Iw ,0 ,S_REGw ,REGI_BX},
|
||||
{L_Iw ,0 ,S_REGw ,REGI_SP},{L_Iw ,0 ,S_REGw ,REGI_BP},
|
||||
{L_Iw ,0 ,S_REGw ,REGI_SI},{L_Iw ,0 ,S_REGw ,REGI_DI},
|
||||
|
||||
/* 0xc0 - 0xc7 */
|
||||
{L_MODRM ,5 ,0 ,M_GRP_Ib },{L_MODRM ,6 ,0 ,M_GRP_Ib },
|
||||
{L_POPw ,0 ,S_IPIw ,0 },{L_POPw ,0 ,S_IP ,0 },
|
||||
{L_MODRM ,O_SEGES ,S_SEGGw,M_Efw },{L_MODRM ,O_SEGDS ,S_SEGGw,M_Efw },
|
||||
{L_MODRM ,0 ,S_Eb ,M_Ib },{L_MODRM ,0 ,S_Ew ,M_Iw },
|
||||
/* 0xc8 - 0xcf */
|
||||
{D_ENTERw ,0 ,0 ,0 },{D_LEAVEw ,0 ,0 ,0 },
|
||||
{D_RETFwIw ,0 ,0 ,0 },{D_RETFw ,0 ,0 ,0 },
|
||||
{L_VAL ,O_INT ,0 ,3 },{L_Ib ,O_INT ,0 ,0 },
|
||||
{L_INTO ,O_INT ,0 ,0 },{D_IRETw ,0 ,0 ,0 },
|
||||
|
||||
/* 0xd0 - 0xd7 */
|
||||
{L_MODRM ,5 ,0 ,M_GRP_1 },{L_MODRM ,6 ,0 ,M_GRP_1 },
|
||||
{L_MODRM ,5 ,0 ,M_GRP_CL },{L_MODRM ,6 ,0 ,M_GRP_CL },
|
||||
{L_Ib ,O_AAM ,0 ,0 },{L_Ib ,O_AAD ,0 ,0 },
|
||||
{D_SETALC ,0 ,0 ,0 },{D_XLAT ,0 ,0 ,0 },
|
||||
//TODO FPU
|
||||
/* 0xd8 - 0xdf */
|
||||
{L_MODRM ,O_FPU ,0 ,0 },{L_MODRM ,O_FPU ,1 ,0 },
|
||||
{L_MODRM ,O_FPU ,2 ,0 },{L_MODRM ,O_FPU ,3 ,0 },
|
||||
{L_MODRM ,O_FPU ,4 ,0 },{L_MODRM ,O_FPU ,5 ,0 },
|
||||
{L_MODRM ,O_FPU ,6 ,0 },{L_MODRM ,O_FPU ,7 ,0 },
|
||||
|
||||
/* 0xe0 - 0xe7 */
|
||||
{L_Ibx ,O_LOOPNZ ,S_AIPw ,0 },{L_Ibx ,O_LOOPZ ,S_AIPw ,0 },
|
||||
{L_Ibx ,O_LOOP ,S_AIPw ,0 },{L_Ibx ,O_JCXZ ,S_AIPw ,0 },
|
||||
{L_Ib ,O_INb ,0 ,0 },{L_Ib ,O_INw ,0 ,0 },
|
||||
{L_Ib ,O_OUTb ,0 ,0 },{L_Ib ,O_OUTw ,0 ,0 },
|
||||
/* 0xe8 - 0xef */
|
||||
{L_Iw ,O_CALLNw ,S_AIPw ,0 },{L_Iwx ,0 ,S_AIPw ,0 },
|
||||
{L_Ifw ,O_JMPFw ,0 ,0 },{L_Ibx ,0 ,S_AIPw ,0 },
|
||||
{L_REGw ,O_INb ,0 ,REGI_DX},{L_REGw ,O_INw ,0 ,REGI_DX},
|
||||
{L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTw ,0 ,REGI_DX},
|
||||
|
||||
/* 0xf0 - 0xf7 */
|
||||
{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 },
|
||||
{L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 },
|
||||
{D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 },
|
||||
{L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,9 ,0 ,M_GRP },
|
||||
/* 0xf8 - 0xff */
|
||||
{D_CLC ,0 ,0 ,0 },{D_STC ,0 ,0 ,0 },
|
||||
{D_CLI ,0 ,0 ,0 },{D_STI ,0 ,0 ,0 },
|
||||
{D_CLD ,0 ,0 ,0 },{D_STD ,0 ,0 ,0 },
|
||||
{L_MODRM ,0xb ,0 ,M_GRP },{L_MODRM ,0xc ,0 ,M_GRP },
|
||||
|
||||
/* 0x100 - 0x107 */
|
||||
{L_MODRM ,O_GRP6w ,S_Ew ,M_Ew },{L_MODRM ,O_GRP7w ,S_Ew ,M_Ew },
|
||||
{L_MODRM_NVM ,O_LAR ,S_Gw ,M_EwGw },{L_MODRM_NVM ,O_LSL ,S_Gw ,M_EwGw },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{D_CLTS ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x108 - 0x10f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x110 - 0x117 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x118 - 0x11f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x120 - 0x127 */
|
||||
{L_MODRM ,O_M_Rd_CRx ,S_Ed ,0 },{L_MODRM ,O_M_Rd_DRx ,S_Ed ,0 },
|
||||
{L_MODRM ,O_M_CRx_Rd ,0 ,M_Ed },{L_MODRM ,O_M_DRx_Rd ,0 ,M_Ed },
|
||||
{L_MODRM ,O_M_Rd_TRx ,S_Ed ,0 },{0 ,0 ,0 ,0 },
|
||||
{L_MODRM ,O_M_TRx_Rd ,0 ,M_Ed },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x128 - 0x12f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x130 - 0x137 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x138 - 0x13f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x140 - 0x147 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x148 - 0x14f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x150 - 0x157 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x158 - 0x15f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x160 - 0x167 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x168 - 0x16f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
|
||||
/* 0x170 - 0x177 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x178 - 0x17f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x180 - 0x187 */
|
||||
{L_Iwx ,O_C_O ,S_C_AIPw,0 },{L_Iwx ,O_C_NO ,S_C_AIPw,0 },
|
||||
{L_Iwx ,O_C_B ,S_C_AIPw,0 },{L_Iwx ,O_C_NB ,S_C_AIPw,0 },
|
||||
{L_Iwx ,O_C_Z ,S_C_AIPw,0 },{L_Iwx ,O_C_NZ ,S_C_AIPw,0 },
|
||||
{L_Iwx ,O_C_BE ,S_C_AIPw,0 },{L_Iwx ,O_C_NBE ,S_C_AIPw,0 },
|
||||
/* 0x188 - 0x18f */
|
||||
{L_Iwx ,O_C_S ,S_C_AIPw,0 },{L_Iwx ,O_C_NS ,S_C_AIPw,0 },
|
||||
{L_Iwx ,O_C_P ,S_C_AIPw,0 },{L_Iwx ,O_C_NP ,S_C_AIPw,0 },
|
||||
{L_Iwx ,O_C_L ,S_C_AIPw,0 },{L_Iwx ,O_C_NL ,S_C_AIPw,0 },
|
||||
{L_Iwx ,O_C_LE ,S_C_AIPw,0 },{L_Iwx ,O_C_NLE ,S_C_AIPw,0 },
|
||||
|
||||
/* 0x190 - 0x197 */
|
||||
{L_MODRM ,O_C_O ,S_C_Eb,0 },{L_MODRM ,O_C_NO ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_B ,S_C_Eb,0 },{L_MODRM ,O_C_NB ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_Z ,S_C_Eb,0 },{L_MODRM ,O_C_NZ ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_BE ,S_C_Eb,0 },{L_MODRM ,O_C_NBE ,S_C_Eb,0 },
|
||||
/* 0x198 - 0x19f */
|
||||
{L_MODRM ,O_C_S ,S_C_Eb,0 },{L_MODRM ,O_C_NS ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_P ,S_C_Eb,0 },{L_MODRM ,O_C_NP ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_L ,S_C_Eb,0 },{L_MODRM ,O_C_NL ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_LE ,S_C_Eb,0 },{L_MODRM ,O_C_NLE ,S_C_Eb,0 },
|
||||
|
||||
/* 0x1a0 - 0x1a7 */
|
||||
{L_SEG ,0 ,S_PUSHw ,fs },{D_POPSEGw,0 ,0 ,fs },
|
||||
{D_CPUID ,0 ,0 ,0 },{L_MODRM ,O_BTw ,S_Ew ,M_EwGwt },
|
||||
{L_MODRM ,O_DSHLw ,S_Ew,M_EwGwIb },{L_MODRM ,O_DSHLw ,S_Ew ,M_EwGwCL },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x1a8 - 0x1af */
|
||||
{L_SEG ,0 ,S_PUSHw ,gs },{D_POPSEGw,0 ,0 ,gs },
|
||||
{0 ,0 ,0 ,0 },{L_MODRM ,O_BTSw ,S_Ew ,M_EwGwt },
|
||||
{L_MODRM ,O_DSHRw ,S_Ew,M_EwGwIb },{L_MODRM ,O_DSHRw ,S_Ew ,M_EwGwCL },
|
||||
{0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRw ,S_Gw ,M_EwxGwx },
|
||||
|
||||
/* 0x1b0 - 0x1b7 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{L_MODRM ,O_SEGSS ,S_SEGGw,M_Efw },{L_MODRM ,O_BTRw ,S_Ew ,M_EwGwt },
|
||||
{L_MODRM ,O_SEGFS ,S_SEGGw,M_Efw },{L_MODRM ,O_SEGGS ,S_SEGGw,M_Efw },
|
||||
{L_MODRM ,0 ,S_Gw ,M_Eb },{L_MODRM ,0 ,S_Gw ,M_Ew },
|
||||
/* 0x1b8 - 0x1bf */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{L_MODRM ,0xe ,0 ,M_GRP },{L_MODRM ,O_BTCw ,S_Ew ,M_EwGwt },
|
||||
{L_MODRM ,O_BSFw ,S_Gw ,M_Ew },{L_MODRM ,O_BSRw ,S_Gw ,M_Ew },
|
||||
{L_MODRM ,0 ,S_Gw ,M_Ebx },{L_MODRM ,0 ,S_Gw ,M_Ewx },
|
||||
|
||||
/* 0x1c0 - 0x1cc */
|
||||
{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDw ,S_EwGw ,M_GwEw },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x1c8 - 0x1cf */
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_AX},{L_REGd ,O_BSWAP ,S_REGd ,REGI_CX},
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_DX},{L_REGd ,O_BSWAP ,S_REGd ,REGI_BX},
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_SP},{L_REGd ,O_BSWAP ,S_REGd ,REGI_BP},
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_SI},{L_REGd ,O_BSWAP ,S_REGd ,REGI_DI},
|
||||
|
||||
/* 0x1d0 - 0x1d7 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x1d8 - 0x1df */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x1e0 - 0x1ee */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x1e8 - 0x1ef */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x1f0 - 0x1fc */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x1f8 - 0x1ff */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
|
||||
/* 0x200 - 0x207 */
|
||||
{L_MODRM ,t_ADDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADDd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_ADDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADDd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_ADDb ,S_REGb ,REGI_AL },{L_REGdId ,t_ADDd ,S_REGd ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHd,es },{D_POPSEGd,0 ,0 ,es },
|
||||
/* 0x208 - 0x20f */
|
||||
{L_MODRM ,t_ORb ,S_Eb ,M_EbGb },{L_MODRM ,t_ORd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_ORb ,S_Gb ,M_GbEb },{L_MODRM ,t_ORd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_ORb ,S_REGb ,REGI_AL },{L_REGdId ,t_ORd ,S_REGd ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHd,cs },{L_DOUBLE ,0 ,0 ,0 },
|
||||
|
||||
/* 0x210 - 0x217 */
|
||||
{L_MODRM ,t_ADCb ,S_Eb ,M_EbGb },{L_MODRM ,t_ADCd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_ADCb ,S_Gb ,M_GbEb },{L_MODRM ,t_ADCd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_ADCb ,S_REGb ,REGI_AL },{L_REGdId ,t_ADCd ,S_REGd ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHd,ss },{D_POPSEGd,0 ,0 ,ss },
|
||||
/* 0x218 - 0x21f */
|
||||
{L_MODRM ,t_SBBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SBBd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_SBBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SBBd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_SBBb ,S_REGb ,REGI_AL },{L_REGdId ,t_SBBd ,S_REGd ,REGI_AX },
|
||||
{L_SEG ,0 ,S_PUSHd,ds },{D_POPSEGd,0 ,0 ,ds },
|
||||
|
||||
/* 0x220 - 0x227 */
|
||||
{L_MODRM ,t_ANDb ,S_Eb ,M_EbGb },{L_MODRM ,t_ANDd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_ANDb ,S_Gb ,M_GbEb },{L_MODRM ,t_ANDd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_ANDb ,S_REGb ,REGI_AL },{L_REGdId ,t_ANDd ,S_REGd ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,es },{D_DAA ,0 ,0 ,0 },
|
||||
/* 0x228 - 0x22f */
|
||||
{L_MODRM ,t_SUBb ,S_Eb ,M_EbGb },{L_MODRM ,t_SUBd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_SUBb ,S_Gb ,M_GbEb },{L_MODRM ,t_SUBd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_SUBb ,S_REGb ,REGI_AL },{L_REGdId ,t_SUBd ,S_REGd ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,cs },{D_DAS ,0 ,0 ,0 },
|
||||
|
||||
/* 0x230 - 0x237 */
|
||||
{L_MODRM ,t_XORb ,S_Eb ,M_EbGb },{L_MODRM ,t_XORd ,S_Ed ,M_EdGd },
|
||||
{L_MODRM ,t_XORb ,S_Gb ,M_GbEb },{L_MODRM ,t_XORd ,S_Gd ,M_GdEd },
|
||||
{L_REGbIb ,t_XORb ,S_REGb ,REGI_AL },{L_REGdId ,t_XORd ,S_REGd ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,ss },{D_AAA ,0 ,0 ,0 },
|
||||
/* 0x238 - 0x23f */
|
||||
{L_MODRM ,t_CMPb ,0 ,M_EbGb },{L_MODRM ,t_CMPd ,0 ,M_EdGd },
|
||||
{L_MODRM ,t_CMPb ,0 ,M_GbEb },{L_MODRM ,t_CMPd ,0 ,M_GdEd },
|
||||
{L_REGbIb ,t_CMPb ,0 ,REGI_AL },{L_REGdId ,t_CMPd ,0 ,REGI_AX },
|
||||
{L_PRESEG ,0 ,0 ,ds },{D_AAS ,0 ,0 ,0 },
|
||||
|
||||
/* 0x240 - 0x247 */
|
||||
{L_REGd ,t_INCd ,S_REGd ,REGI_AX},{L_REGd ,t_INCd ,S_REGd ,REGI_CX},
|
||||
{L_REGd ,t_INCd ,S_REGd ,REGI_DX},{L_REGd ,t_INCd ,S_REGd ,REGI_BX},
|
||||
{L_REGd ,t_INCd ,S_REGd ,REGI_SP},{L_REGd ,t_INCd ,S_REGd ,REGI_BP},
|
||||
{L_REGd ,t_INCd ,S_REGd ,REGI_SI},{L_REGd ,t_INCd ,S_REGd ,REGI_DI},
|
||||
/* 0x248 - 0x24f */
|
||||
{L_REGd ,t_DECd ,S_REGd ,REGI_AX},{L_REGd ,t_DECd ,S_REGd ,REGI_CX},
|
||||
{L_REGd ,t_DECd ,S_REGd ,REGI_DX},{L_REGd ,t_DECd ,S_REGd ,REGI_BX},
|
||||
{L_REGd ,t_DECd ,S_REGd ,REGI_SP},{L_REGd ,t_DECd ,S_REGd ,REGI_BP},
|
||||
{L_REGd ,t_DECd ,S_REGd ,REGI_SI},{L_REGd ,t_DECd ,S_REGd ,REGI_DI},
|
||||
|
||||
/* 0x250 - 0x257 */
|
||||
{L_REGd ,0 ,S_PUSHd,REGI_AX},{L_REGd ,0 ,S_PUSHd,REGI_CX},
|
||||
{L_REGd ,0 ,S_PUSHd,REGI_DX},{L_REGd ,0 ,S_PUSHd,REGI_BX},
|
||||
{L_REGd ,0 ,S_PUSHd,REGI_SP},{L_REGd ,0 ,S_PUSHd,REGI_BP},
|
||||
{L_REGd ,0 ,S_PUSHd,REGI_SI},{L_REGd ,0 ,S_PUSHd,REGI_DI},
|
||||
/* 0x258 - 0x25f */
|
||||
{L_POPd ,0 ,S_REGd ,REGI_AX},{L_POPd ,0 ,S_REGd ,REGI_CX},
|
||||
{L_POPd ,0 ,S_REGd ,REGI_DX},{L_POPd ,0 ,S_REGd ,REGI_BX},
|
||||
{L_POPd ,0 ,S_REGd ,REGI_SP},{L_POPd ,0 ,S_REGd ,REGI_BP},
|
||||
{L_POPd ,0 ,S_REGd ,REGI_SI},{L_POPd ,0 ,S_REGd ,REGI_DI},
|
||||
|
||||
/* 0x260 - 0x267 */
|
||||
{D_PUSHAd ,0 ,0 ,0 },{D_POPAd ,0 ,0 ,0 },
|
||||
{L_MODRM ,O_BOUNDd ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{L_PRESEG ,0 ,0 ,fs },{L_PRESEG ,0 ,0 ,gs },
|
||||
{L_PREOP ,0 ,0 ,0 },{L_PREADD ,0 ,0 ,0 },
|
||||
/* 0x268 - 0x26f */
|
||||
{L_Id ,0 ,S_PUSHd,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdId},
|
||||
{L_Ibx ,0 ,S_PUSHd,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdIbx},
|
||||
{L_STRING ,R_INSB ,0 ,0 },{L_STRING ,R_INSD ,0 ,0 },
|
||||
{L_STRING ,R_OUTSB ,0 ,0 },{L_STRING ,R_OUTSD ,0 ,0 },
|
||||
|
||||
/* 0x270 - 0x277 */
|
||||
{L_Ibx ,O_C_O ,S_C_AIPd,0 },{L_Ibx ,O_C_NO ,S_C_AIPd,0 },
|
||||
{L_Ibx ,O_C_B ,S_C_AIPd,0 },{L_Ibx ,O_C_NB ,S_C_AIPd,0 },
|
||||
{L_Ibx ,O_C_Z ,S_C_AIPd,0 },{L_Ibx ,O_C_NZ ,S_C_AIPd,0 },
|
||||
{L_Ibx ,O_C_BE ,S_C_AIPd,0 },{L_Ibx ,O_C_NBE ,S_C_AIPd,0 },
|
||||
/* 0x278 - 0x27f */
|
||||
{L_Ibx ,O_C_S ,S_C_AIPd,0 },{L_Ibx ,O_C_NS ,S_C_AIPd,0 },
|
||||
{L_Ibx ,O_C_P ,S_C_AIPd,0 },{L_Ibx ,O_C_NP ,S_C_AIPd,0 },
|
||||
{L_Ibx ,O_C_L ,S_C_AIPd,0 },{L_Ibx ,O_C_NL ,S_C_AIPd,0 },
|
||||
{L_Ibx ,O_C_LE ,S_C_AIPd,0 },{L_Ibx ,O_C_NLE ,S_C_AIPd,0 },
|
||||
|
||||
/* 0x280 - 0x287 */
|
||||
{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,2 ,0 ,M_GRP },
|
||||
{L_MODRM ,0 ,0 ,M_GRP },{L_MODRM ,4 ,0 ,M_GRP },
|
||||
{L_MODRM ,t_TESTb ,0 ,M_EbGb },{L_MODRM ,t_TESTd ,0 ,M_EdGd },
|
||||
{L_MODRM ,0 ,S_EbGb ,M_GbEb },{L_MODRM ,0 ,S_EdGd ,M_GdEd },
|
||||
/* 0x288 - 0x28f */
|
||||
{L_MODRM ,0 ,S_Eb ,M_Gb },{L_MODRM ,0 ,S_Ed ,M_Gd },
|
||||
{L_MODRM ,0 ,S_Gb ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ed },
|
||||
{L_MODRM ,0 ,S_EdMw ,M_SEG },{L_MODRM ,0 ,S_Gd ,M_EA },
|
||||
{L_MODRM ,0 ,S_SEGm ,M_Ew },{L_POPdRM ,0 ,S_Ed ,M_None },
|
||||
|
||||
/* 0x290 - 0x297 */
|
||||
{D_NOP ,0 ,0 ,0 },{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_CX},
|
||||
{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_DX},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_BX},
|
||||
{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_SP},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_BP},
|
||||
{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_SI},{L_REGd ,O_XCHG_EAX ,S_REGd ,REGI_DI},
|
||||
/* 0x298 - 0x29f */
|
||||
{D_CWDE ,0 ,0 ,0 },{D_CDQ ,0 ,0 ,0 },
|
||||
{L_Ifd ,O_CALLFd ,0 ,0 },{D_WAIT ,0 ,0 ,0 },
|
||||
{D_PUSHF ,0 ,0 ,true },{D_POPF ,0 ,0 ,true },
|
||||
{D_SAHF ,0 ,0 ,0 },{D_LAHF ,0 ,0 ,0 },
|
||||
|
||||
/* 0x2a0 - 0x2a7 */
|
||||
{L_OP ,O_ALOP ,0 ,0 },{L_OP ,O_EAXOP ,0 ,0 },
|
||||
{L_OP ,O_OPAL ,0 ,0 },{L_OP ,O_OPEAX ,0 ,0 },
|
||||
{L_STRING ,R_MOVSB ,0 ,0 },{L_STRING ,R_MOVSD ,0 ,0 },
|
||||
{L_STRING ,R_CMPSB ,0 ,0 },{L_STRING ,R_CMPSD ,0 ,0 },
|
||||
/* 0x2a8 - 0x2af */
|
||||
{L_REGbIb ,t_TESTb ,0 ,REGI_AL},{L_REGdId ,t_TESTd ,0 ,REGI_AX},
|
||||
{L_STRING ,R_STOSB ,0 ,0 },{L_STRING ,R_STOSD ,0 ,0 },
|
||||
{L_STRING ,R_LODSB ,0 ,0 },{L_STRING ,R_LODSD ,0 ,0 },
|
||||
{L_STRING ,R_SCASB ,0 ,0 },{L_STRING ,R_SCASD ,0 ,0 },
|
||||
|
||||
/* 0x2b0 - 0x2b7 */
|
||||
{L_Ib ,0 ,S_REGb ,REGI_AL},{L_Ib ,0 ,S_REGb ,REGI_CL},
|
||||
{L_Ib ,0 ,S_REGb ,REGI_DL},{L_Ib ,0 ,S_REGb ,REGI_BL},
|
||||
{L_Ib ,0 ,S_REGb ,REGI_AH},{L_Ib ,0 ,S_REGb ,REGI_CH},
|
||||
{L_Ib ,0 ,S_REGb ,REGI_DH},{L_Ib ,0 ,S_REGb ,REGI_BH},
|
||||
/* 0x2b8 - 0x2bf */
|
||||
{L_Id ,0 ,S_REGd ,REGI_AX},{L_Id ,0 ,S_REGd ,REGI_CX},
|
||||
{L_Id ,0 ,S_REGd ,REGI_DX},{L_Id ,0 ,S_REGd ,REGI_BX},
|
||||
{L_Id ,0 ,S_REGd ,REGI_SP},{L_Id ,0 ,S_REGd ,REGI_BP},
|
||||
{L_Id ,0 ,S_REGd ,REGI_SI},{L_Id ,0 ,S_REGd ,REGI_DI},
|
||||
|
||||
/* 0x2c0 - 0x2c7 */
|
||||
{L_MODRM ,5 ,0 ,M_GRP_Ib },{L_MODRM ,7 ,0 ,M_GRP_Ib },
|
||||
{L_POPd ,0 ,S_IPIw ,0 },{L_POPd ,0 ,S_IP ,0 },
|
||||
{L_MODRM ,O_SEGES ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGDS ,S_SEGGd,M_Efd },
|
||||
{L_MODRM ,0 ,S_Eb ,M_Ib },{L_MODRM ,0 ,S_Ed ,M_Id },
|
||||
/* 0x2c8 - 0x2cf */
|
||||
{D_ENTERd ,0 ,0 ,0 },{D_LEAVEd ,0 ,0 ,0 },
|
||||
{D_RETFdIw ,0 ,0 ,0 },{D_RETFd ,0 ,0 ,0 },
|
||||
{L_VAL ,O_INT ,0 ,3 },{L_Ib ,O_INT ,0 ,0 },
|
||||
{L_INTO ,O_INT ,0 ,0 },{D_IRETd ,0 ,0 ,0 },
|
||||
|
||||
/* 0x2d0 - 0x2d7 */
|
||||
{L_MODRM ,5 ,0 ,M_GRP_1 },{L_MODRM ,7 ,0 ,M_GRP_1 },
|
||||
{L_MODRM ,5 ,0 ,M_GRP_CL },{L_MODRM ,7 ,0 ,M_GRP_CL },
|
||||
{L_Ib ,O_AAM ,0 ,0 },{L_Ib ,O_AAD ,0 ,0 },
|
||||
{D_SETALC ,0 ,0 ,0 },{D_XLAT ,0 ,0 ,0 },
|
||||
/* 0x2d8 - 0x2df */
|
||||
{L_MODRM ,O_FPU ,0 ,0 },{L_MODRM ,O_FPU ,1 ,0 },
|
||||
{L_MODRM ,O_FPU ,2 ,0 },{L_MODRM ,O_FPU ,3 ,0 },
|
||||
{L_MODRM ,O_FPU ,4 ,0 },{L_MODRM ,O_FPU ,5 ,0 },
|
||||
{L_MODRM ,O_FPU ,6 ,0 },{L_MODRM ,O_FPU ,7 ,0 },
|
||||
|
||||
/* 0x2e0 - 0x2e7 */
|
||||
{L_Ibx ,O_LOOPNZ ,S_AIPd ,0 },{L_Ibx ,O_LOOPZ ,S_AIPd ,0 },
|
||||
{L_Ibx ,O_LOOP ,S_AIPd ,0 },{L_Ibx ,O_JCXZ ,S_AIPd ,0 },
|
||||
{L_Ib ,O_INb ,0 ,0 },{L_Ib ,O_INd ,0 ,0 },
|
||||
{L_Ib ,O_OUTb ,0 ,0 },{L_Ib ,O_OUTd ,0 ,0 },
|
||||
/* 0x2e8 - 0x2ef */
|
||||
{L_Id ,O_CALLNd ,S_AIPd ,0 },{L_Idx ,0 ,S_AIPd ,0 },
|
||||
{L_Ifd ,O_JMPFd ,0 ,0 },{L_Ibx ,0 ,S_AIPd ,0 },
|
||||
{L_REGw ,O_INb ,0 ,REGI_DX},{L_REGw ,O_INd ,0 ,REGI_DX},
|
||||
{L_REGw ,O_OUTb ,0 ,REGI_DX},{L_REGw ,O_OUTd ,0 ,REGI_DX},
|
||||
|
||||
/* 0x2f0 - 0x2f7 */
|
||||
{D_LOCK ,0 ,0 ,0 },{D_ICEBP ,0 ,0 ,0 },
|
||||
{L_PREREPNE ,0 ,0 ,0 },{L_PREREP ,0 ,0 ,0 },
|
||||
{D_HLT ,0 ,0 ,0 },{D_CMC ,0 ,0 ,0 },
|
||||
{L_MODRM ,8 ,0 ,M_GRP },{L_MODRM ,0xa ,0 ,M_GRP },
|
||||
/* 0x2f8 - 0x2ff */
|
||||
{D_CLC ,0 ,0 ,0 },{D_STC ,0 ,0 ,0 },
|
||||
{D_CLI ,0 ,0 ,0 },{D_STI ,0 ,0 ,0 },
|
||||
{D_CLD ,0 ,0 ,0 },{D_STD ,0 ,0 ,0 },
|
||||
{L_MODRM ,0xb ,0 ,M_GRP },{L_MODRM ,0xd ,0 ,M_GRP },
|
||||
|
||||
|
||||
/* 0x300 - 0x307 */
|
||||
{L_MODRM ,O_GRP6d ,S_Ew ,M_Ew },{L_MODRM ,O_GRP7d ,S_Ew ,M_Ew },
|
||||
{L_MODRM_NVM ,O_LAR ,S_Gd ,M_EdGd },{L_MODRM_NVM ,O_LSL ,S_Gd ,M_EdGd },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{D_CLTS ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x308 - 0x30f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x310 - 0x317 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x318 - 0x31f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x320 - 0x327 */
|
||||
{L_MODRM ,O_M_Rd_CRx ,S_Ed ,0 },{L_MODRM ,O_M_Rd_DRx ,S_Ed ,0 },
|
||||
{L_MODRM ,O_M_CRx_Rd ,0 ,M_Ed },{L_MODRM ,O_M_DRx_Rd ,0 ,M_Ed },
|
||||
{L_MODRM ,O_M_Rd_TRx ,S_Ed ,0 },{0 ,0 ,0 ,0 },
|
||||
{L_MODRM ,O_M_TRx_Rd ,0 ,M_Ed },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x328 - 0x32f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x330 - 0x337 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x338 - 0x33f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x340 - 0x347 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x348 - 0x34f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x350 - 0x357 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x358 - 0x35f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x360 - 0x367 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x368 - 0x36f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
|
||||
/* 0x370 - 0x377 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x378 - 0x37f */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x380 - 0x387 */
|
||||
{L_Idx ,O_C_O ,S_C_AIPd,0 },{L_Idx ,O_C_NO ,S_C_AIPd,0 },
|
||||
{L_Idx ,O_C_B ,S_C_AIPd,0 },{L_Idx ,O_C_NB ,S_C_AIPd,0 },
|
||||
{L_Idx ,O_C_Z ,S_C_AIPd,0 },{L_Idx ,O_C_NZ ,S_C_AIPd,0 },
|
||||
{L_Idx ,O_C_BE ,S_C_AIPd,0 },{L_Idx ,O_C_NBE ,S_C_AIPd,0 },
|
||||
/* 0x388 - 0x38f */
|
||||
{L_Idx ,O_C_S ,S_C_AIPd,0 },{L_Idx ,O_C_NS ,S_C_AIPd,0 },
|
||||
{L_Idx ,O_C_P ,S_C_AIPd,0 },{L_Idx ,O_C_NP ,S_C_AIPd,0 },
|
||||
{L_Idx ,O_C_L ,S_C_AIPd,0 },{L_Idx ,O_C_NL ,S_C_AIPd,0 },
|
||||
{L_Idx ,O_C_LE ,S_C_AIPd,0 },{L_Idx ,O_C_NLE ,S_C_AIPd,0 },
|
||||
|
||||
/* 0x390 - 0x397 */
|
||||
{L_MODRM ,O_C_O ,S_C_Eb,0 },{L_MODRM ,O_C_NO ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_B ,S_C_Eb,0 },{L_MODRM ,O_C_NB ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_Z ,S_C_Eb,0 },{L_MODRM ,O_C_NZ ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_BE ,S_C_Eb,0 },{L_MODRM ,O_C_NBE ,S_C_Eb,0 },
|
||||
/* 0x398 - 0x39f */
|
||||
{L_MODRM ,O_C_S ,S_C_Eb,0 },{L_MODRM ,O_C_NS ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_P ,S_C_Eb,0 },{L_MODRM ,O_C_NP ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_L ,S_C_Eb,0 },{L_MODRM ,O_C_NL ,S_C_Eb,0 },
|
||||
{L_MODRM ,O_C_LE ,S_C_Eb,0 },{L_MODRM ,O_C_NLE ,S_C_Eb,0 },
|
||||
|
||||
/* 0x3a0 - 0x3a7 */
|
||||
{L_SEG ,0 ,S_PUSHd ,fs },{D_POPSEGd,0 ,0 ,fs },
|
||||
{D_CPUID ,0 ,0 ,0 },{L_MODRM ,O_BTd ,S_Ed ,M_EdGdt },
|
||||
{L_MODRM ,O_DSHLd ,S_Ed,M_EdGdIb },{L_MODRM ,O_DSHLd ,S_Ed ,M_EdGdCL },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x3a8 - 0x3af */
|
||||
{L_SEG ,0 ,S_PUSHd ,gs },{D_POPSEGd,0 ,0 ,gs },
|
||||
{0 ,0 ,0 ,0 },{L_MODRM ,O_BTSd ,S_Ed ,M_EdGdt },
|
||||
{L_MODRM ,O_DSHRd ,S_Ed,M_EdGdIb },{L_MODRM ,O_DSHRd ,S_Ed ,M_EdGdCL },
|
||||
{0 ,0 ,0 ,0 },{L_MODRM ,O_IMULRd ,S_Gd ,M_EdxGdx },
|
||||
|
||||
/* 0x3b0 - 0x3b7 */
|
||||
{0 ,0 ,0 ,0 },{L_MODRM ,O_CMPXCHG ,S_Ed ,M_Ed },
|
||||
{L_MODRM ,O_SEGSS ,S_SEGGd,M_Efd },{L_MODRM ,O_BTRd ,S_Ed ,M_EdGdt },
|
||||
{L_MODRM ,O_SEGFS ,S_SEGGd,M_Efd },{L_MODRM ,O_SEGGS ,S_SEGGd,M_Efd },
|
||||
{L_MODRM ,0 ,S_Gd ,M_Eb },{L_MODRM ,0 ,S_Gd ,M_Ew },
|
||||
/* 0x3b8 - 0x3bf */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{L_MODRM ,0xf ,0 ,M_GRP },{L_MODRM ,O_BTCd ,S_Ed ,M_EdGdt },
|
||||
{L_MODRM ,O_BSFd ,S_Gd ,M_Ed },{L_MODRM ,O_BSRd ,S_Gd ,M_Ed },
|
||||
{L_MODRM ,0 ,S_Gd ,M_Ebx },{L_MODRM ,0 ,S_Gd ,M_Ewx },
|
||||
|
||||
/* 0x3c0 - 0x3cc */
|
||||
{L_MODRM ,t_ADDb ,S_EbGb ,M_GbEb },{L_MODRM ,t_ADDd ,S_EdGd ,M_GdEd },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x3c8 - 0x3cf */
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_AX},{L_REGd ,O_BSWAP ,S_REGd ,REGI_CX},
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_DX},{L_REGd ,O_BSWAP ,S_REGd ,REGI_BX},
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_SP},{L_REGd ,O_BSWAP ,S_REGd ,REGI_BP},
|
||||
{L_REGd ,O_BSWAP ,S_REGd ,REGI_SI},{L_REGd ,O_BSWAP ,S_REGd ,REGI_DI},
|
||||
|
||||
/* 0x3d0 - 0x3d7 */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x3d8 - 0x3df */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x3e0 - 0x3ee */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x3e8 - 0x3ef */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
/* 0x3f0 - 0x3fc */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
/* 0x3f8 - 0x3ff */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
|
||||
};
|
||||
|
||||
static OpCode Groups[16][8]={
|
||||
{ /* 0x00 Group 1 Eb,Ib */
|
||||
{0 ,t_ADDb ,S_Eb ,M_EbIb },{0 ,t_ORb ,S_Eb ,M_EbIb },
|
||||
{0 ,t_ADCb ,S_Eb ,M_EbIb },{0 ,t_SBBb ,S_Eb ,M_EbIb },
|
||||
{0 ,t_ANDb ,S_Eb ,M_EbIb },{0 ,t_SUBb ,S_Eb ,M_EbIb },
|
||||
{0 ,t_XORb ,S_Eb ,M_EbIb },{0 ,t_CMPb ,0 ,M_EbIb },
|
||||
},{ /* 0x01 Group 1 Ew,Iw */
|
||||
{0 ,t_ADDw ,S_Ew ,M_EwIw },{0 ,t_ORw ,S_Ew ,M_EwIw },
|
||||
{0 ,t_ADCw ,S_Ew ,M_EwIw },{0 ,t_SBBw ,S_Ew ,M_EwIw },
|
||||
{0 ,t_ANDw ,S_Ew ,M_EwIw },{0 ,t_SUBw ,S_Ew ,M_EwIw },
|
||||
{0 ,t_XORw ,S_Ew ,M_EwIw },{0 ,t_CMPw ,0 ,M_EwIw },
|
||||
},{ /* 0x02 Group 1 Ed,Id */
|
||||
{0 ,t_ADDd ,S_Ed ,M_EdId },{0 ,t_ORd ,S_Ed ,M_EdId },
|
||||
{0 ,t_ADCd ,S_Ed ,M_EdId },{0 ,t_SBBd ,S_Ed ,M_EdId },
|
||||
{0 ,t_ANDd ,S_Ed ,M_EdId },{0 ,t_SUBd ,S_Ed ,M_EdId },
|
||||
{0 ,t_XORd ,S_Ed ,M_EdId },{0 ,t_CMPd ,0 ,M_EdId },
|
||||
},{ /* 0x03 Group 1 Ew,Ibx */
|
||||
{0 ,t_ADDw ,S_Ew ,M_EwIbx },{0 ,t_ORw ,S_Ew ,M_EwIbx },
|
||||
{0 ,t_ADCw ,S_Ew ,M_EwIbx },{0 ,t_SBBw ,S_Ew ,M_EwIbx },
|
||||
{0 ,t_ANDw ,S_Ew ,M_EwIbx },{0 ,t_SUBw ,S_Ew ,M_EwIbx },
|
||||
{0 ,t_XORw ,S_Ew ,M_EwIbx },{0 ,t_CMPw ,0 ,M_EwIbx },
|
||||
},{ /* 0x04 Group 1 Ed,Ibx */
|
||||
{0 ,t_ADDd ,S_Ed ,M_EdIbx },{0 ,t_ORd ,S_Ed ,M_EdIbx },
|
||||
{0 ,t_ADCd ,S_Ed ,M_EdIbx },{0 ,t_SBBd ,S_Ed ,M_EdIbx },
|
||||
{0 ,t_ANDd ,S_Ed ,M_EdIbx },{0 ,t_SUBd ,S_Ed ,M_EdIbx },
|
||||
{0 ,t_XORd ,S_Ed ,M_EdIbx },{0 ,t_CMPd ,0 ,M_EdIbx },
|
||||
|
||||
},{ /* 0x05 Group 2 Eb,XXX */
|
||||
{0 ,t_ROLb ,S_Eb ,M_Eb },{0 ,t_RORb ,S_Eb ,M_Eb },
|
||||
{0 ,t_RCLb ,S_Eb ,M_Eb },{0 ,t_RCRb ,S_Eb ,M_Eb },
|
||||
{0 ,t_SHLb ,S_Eb ,M_Eb },{0 ,t_SHRb ,S_Eb ,M_Eb },
|
||||
{0 ,t_SHLb ,S_Eb ,M_Eb },{0 ,t_SARb ,S_Eb ,M_Eb },
|
||||
},{ /* 0x06 Group 2 Ew,XXX */
|
||||
{0 ,t_ROLw ,S_Ew ,M_Ew },{0 ,t_RORw ,S_Ew ,M_Ew },
|
||||
{0 ,t_RCLw ,S_Ew ,M_Ew },{0 ,t_RCRw ,S_Ew ,M_Ew },
|
||||
{0 ,t_SHLw ,S_Ew ,M_Ew },{0 ,t_SHRw ,S_Ew ,M_Ew },
|
||||
{0 ,t_SHLw ,S_Ew ,M_Ew },{0 ,t_SARw ,S_Ew ,M_Ew },
|
||||
},{ /* 0x07 Group 2 Ed,XXX */
|
||||
{0 ,t_ROLd ,S_Ed ,M_Ed },{0 ,t_RORd ,S_Ed ,M_Ed },
|
||||
{0 ,t_RCLd ,S_Ed ,M_Ed },{0 ,t_RCRd ,S_Ed ,M_Ed },
|
||||
{0 ,t_SHLd ,S_Ed ,M_Ed },{0 ,t_SHRd ,S_Ed ,M_Ed },
|
||||
{0 ,t_SHLd ,S_Ed ,M_Ed },{0 ,t_SARd ,S_Ed ,M_Ed },
|
||||
|
||||
|
||||
},{ /* 0x08 Group 3 Eb */
|
||||
{0 ,t_TESTb ,0 ,M_EbIb },{0 ,t_TESTb ,0 ,M_EbIb },
|
||||
{0 ,O_NOT ,S_Eb ,M_Eb },{0 ,t_NEGb ,S_Eb ,M_Eb },
|
||||
{0 ,O_MULb ,0 ,M_Eb },{0 ,O_IMULb ,0 ,M_Eb },
|
||||
{0 ,O_DIVb ,0 ,M_Eb },{0 ,O_IDIVb ,0 ,M_Eb },
|
||||
},{ /* 0x09 Group 3 Ew */
|
||||
{0 ,t_TESTw ,0 ,M_EwIw },{0 ,t_TESTw ,0 ,M_EwIw },
|
||||
{0 ,O_NOT ,S_Ew ,M_Ew },{0 ,t_NEGw ,S_Ew ,M_Ew },
|
||||
{0 ,O_MULw ,0 ,M_Ew },{0 ,O_IMULw ,0 ,M_Ew },
|
||||
{0 ,O_DIVw ,0 ,M_Ew },{0 ,O_IDIVw ,0 ,M_Ew },
|
||||
},{ /* 0x0a Group 3 Ed */
|
||||
{0 ,t_TESTd ,0 ,M_EdId },{0 ,t_TESTd ,0 ,M_EdId },
|
||||
{0 ,O_NOT ,S_Ed ,M_Ed },{0 ,t_NEGd ,S_Ed ,M_Ed },
|
||||
{0 ,O_MULd ,0 ,M_Ed },{0 ,O_IMULd ,0 ,M_Ed },
|
||||
{0 ,O_DIVd ,0 ,M_Ed },{0 ,O_IDIVd ,0 ,M_Ed },
|
||||
|
||||
},{ /* 0x0b Group 4 Eb */
|
||||
{0 ,t_INCb ,S_Eb ,M_Eb },{0 ,t_DECb ,S_Eb ,M_Eb },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,O_CBACK ,0 ,M_Iw },
|
||||
},{ /* 0x0c Group 5 Ew */
|
||||
{0 ,t_INCw ,S_Ew ,M_Ew },{0 ,t_DECw ,S_Ew ,M_Ew },
|
||||
{0 ,O_CALLNw ,S_IP ,M_Ew },{0 ,O_CALLFw ,0 ,M_Efw },
|
||||
{0 ,0 ,S_IP ,M_Ew },{0 ,O_JMPFw ,0 ,M_Efw },
|
||||
{0 ,0 ,S_PUSHw,M_Ew },{0 ,0 ,0 ,0 },
|
||||
},{ /* 0x0d Group 5 Ed */
|
||||
{0 ,t_INCd ,S_Ed ,M_Ed },{0 ,t_DECd ,S_Ed ,M_Ed },
|
||||
{0 ,O_CALLNd ,S_IP ,M_Ed },{0 ,O_CALLFd ,0 ,M_Efd },
|
||||
{0 ,0 ,S_IP ,M_Ed },{0 ,O_JMPFd ,0 ,M_Efd },
|
||||
{0 ,0 ,S_PUSHd,M_Ed },{0 ,0 ,0 ,0 },
|
||||
|
||||
|
||||
},{ /* 0x0e Group 8 Ew */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,O_BTw ,S_Ew ,M_EwIb },{0 ,O_BTSw ,S_Ew ,M_EwIb },
|
||||
{0 ,O_BTRw ,S_Ew ,M_EwIb },{0 ,O_BTCw ,S_Ew ,M_EwIb },
|
||||
},{ /* 0x0f Group 8 Ed */
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,0 ,0 ,0 },{0 ,0 ,0 ,0 },
|
||||
{0 ,O_BTd ,S_Ed ,M_EdIb },{0 ,O_BTSd ,S_Ed ,M_EdIb },
|
||||
{0 ,O_BTRd ,S_Ed ,M_EdIb },{0 ,O_BTCd ,S_Ed ,M_EdIb },
|
||||
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
99
src/cpu/core_full/save.h
Normal file
99
src/cpu/core_full/save.h
Normal file
@ -0,0 +1,99 @@
|
||||
/* Write the data from the opcode */
|
||||
switch (inst.code.save) {
|
||||
/* Byte */
|
||||
case S_C_Eb:
|
||||
inst_op1_b=inst.cond ? 1 : 0;
|
||||
case S_Eb:
|
||||
if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b);
|
||||
else reg_8(inst.rm_eai)=inst_op1_b;
|
||||
break;
|
||||
case S_Gb:
|
||||
reg_8(inst.rm_index)=inst_op1_b;
|
||||
break;
|
||||
case S_EbGb:
|
||||
if (inst.rm<0xc0) SaveMb(inst.rm_eaa,inst_op1_b);
|
||||
else reg_8(inst.rm_eai)=inst_op1_b;
|
||||
reg_8(inst.rm_index)=inst_op2_b;
|
||||
break;
|
||||
/* Word */
|
||||
case S_Ew:
|
||||
if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w);
|
||||
else reg_16(inst.rm_eai)=inst_op1_w;
|
||||
break;
|
||||
case S_Gw:
|
||||
reg_16(inst.rm_index)=inst_op1_w;
|
||||
break;
|
||||
case S_EwGw:
|
||||
if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w);
|
||||
else reg_16(inst.rm_eai)=inst_op1_w;
|
||||
reg_16(inst.rm_index)=inst_op2_w;
|
||||
break;
|
||||
/* Dword */
|
||||
case S_Ed:
|
||||
if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d);
|
||||
else reg_32(inst.rm_eai)=inst_op1_d;
|
||||
break;
|
||||
case S_EdMw: /* Special one 16 to memory, 32 zero extend to reg */
|
||||
if (inst.rm<0xc0) SaveMw(inst.rm_eaa,inst_op1_w);
|
||||
else reg_32(inst.rm_eai)=inst_op1_d;
|
||||
break;
|
||||
case S_Gd:
|
||||
reg_32(inst.rm_index)=inst_op1_d;
|
||||
break;
|
||||
case S_EdGd:
|
||||
if (inst.rm<0xc0) SaveMd(inst.rm_eaa,inst_op1_d);
|
||||
else reg_32(inst.rm_eai)=inst_op1_d;
|
||||
reg_32(inst.rm_index)=inst_op2_d;
|
||||
break;
|
||||
|
||||
case S_REGb:
|
||||
reg_8(inst.code.extra)=inst_op1_b;
|
||||
break;
|
||||
case S_REGw:
|
||||
reg_16(inst.code.extra)=inst_op1_w;
|
||||
break;
|
||||
case S_REGd:
|
||||
reg_32(inst.code.extra)=inst_op1_d;
|
||||
break;
|
||||
case S_SEGm:
|
||||
if (CPU_SetSegGeneral((SegNames)inst.rm_index,inst_op1_w)) RunException();
|
||||
break;
|
||||
case S_SEGGw:
|
||||
if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException();
|
||||
reg_16(inst.rm_index)=inst_op1_w;
|
||||
break;
|
||||
case S_SEGGd:
|
||||
if (CPU_SetSegGeneral((SegNames)inst.code.extra,inst_op2_w)) RunException();
|
||||
reg_32(inst.rm_index)=inst_op1_d;
|
||||
break;
|
||||
case S_PUSHw:
|
||||
Push_16(inst_op1_w);
|
||||
break;
|
||||
case S_PUSHd:
|
||||
Push_32(inst_op1_d);
|
||||
break;
|
||||
|
||||
case S_C_AIPw:
|
||||
if (!inst.cond) goto nextopcode;
|
||||
case S_AIPw:
|
||||
SaveIP();
|
||||
reg_eip+=inst_op1_d;
|
||||
reg_eip&=0xffff;
|
||||
continue;
|
||||
case S_C_AIPd:
|
||||
if (!inst.cond) goto nextopcode;
|
||||
case S_AIPd:
|
||||
SaveIP();
|
||||
reg_eip+=inst_op1_d;
|
||||
continue;
|
||||
case S_IPIw:
|
||||
reg_esp+=Fetchw();
|
||||
case S_IP:
|
||||
SaveIP();
|
||||
reg_eip=inst_op1_d;
|
||||
continue;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("SAVE:Unhandled code %d entry %X",inst.code.save,inst.entry);
|
||||
}
|
227
src/cpu/core_full/string.h
Normal file
227
src/cpu/core_full/string.h
Normal file
@ -0,0 +1,227 @@
|
||||
{
|
||||
EAPoint si_base,di_base;
|
||||
Bitu si_index,di_index;
|
||||
Bitu add_mask;
|
||||
Bitu count,count_left;
|
||||
Bits add_index;
|
||||
|
||||
if (inst.prefix & PREFIX_SEG) si_base=inst.seg.base;
|
||||
else si_base=SegBase(ds);
|
||||
di_base=SegBase(es);
|
||||
if (inst.prefix & PREFIX_ADDR) {
|
||||
add_mask=0xFFFFFFFF;
|
||||
si_index=reg_esi;
|
||||
di_index=reg_edi;
|
||||
count=reg_ecx;
|
||||
} else {
|
||||
add_mask=0xFFFF;
|
||||
si_index=reg_si;
|
||||
di_index=reg_di;
|
||||
count=reg_cx;
|
||||
}
|
||||
if (!(inst.prefix & PREFIX_REP)) {
|
||||
count=1;
|
||||
} else {
|
||||
/* Calculate amount of ops to do before cycles run out */
|
||||
CPU_Cycles++;
|
||||
if ((count>(Bitu)CPU_Cycles) && (inst.code.op<R_SCASB)) {
|
||||
count_left=count-CPU_Cycles;
|
||||
count=CPU_Cycles;
|
||||
CPU_Cycles=0;
|
||||
LoadIP();
|
||||
} else {
|
||||
/* Won't interrupt scas and cmps instruction since they can interrupt themselves */
|
||||
if (inst.code.op<R_SCASB) CPU_Cycles-=count;
|
||||
count_left=0;
|
||||
}
|
||||
}
|
||||
add_index=cpu.direction;
|
||||
if (count) switch (inst.code.op) {
|
||||
case R_OUTSB:
|
||||
for (;count>0;count--) {
|
||||
IO_WriteB(reg_dx,LoadMb(si_base+si_index));
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_OUTSW:
|
||||
add_index<<=1;
|
||||
for (;count>0;count--) {
|
||||
IO_WriteW(reg_dx,LoadMw(si_base+si_index));
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_OUTSD:
|
||||
add_index<<=2;
|
||||
for (;count>0;count--) {
|
||||
IO_WriteD(reg_dx,LoadMd(si_base+si_index));
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_INSB:
|
||||
for (;count>0;count--) {
|
||||
SaveMb(di_base+di_index,IO_ReadB(reg_dx));
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_INSW:
|
||||
add_index<<=1;
|
||||
for (;count>0;count--) {
|
||||
SaveMw(di_base+di_index,IO_ReadW(reg_dx));
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_STOSB:
|
||||
for (;count>0;count--) {
|
||||
SaveMb(di_base+di_index,reg_al);
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_STOSW:
|
||||
add_index<<=1;
|
||||
for (;count>0;count--) {
|
||||
SaveMw(di_base+di_index,reg_ax);
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_STOSD:
|
||||
add_index<<=2;
|
||||
for (;count>0;count--) {
|
||||
SaveMd(di_base+di_index,reg_eax);
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_MOVSB:
|
||||
for (;count>0;count--) {
|
||||
SaveMb(di_base+di_index,LoadMb(si_base+si_index));
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_MOVSW:
|
||||
add_index<<=1;
|
||||
for (;count>0;count--) {
|
||||
SaveMw(di_base+di_index,LoadMw(si_base+si_index));
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_MOVSD:
|
||||
add_index<<=2;
|
||||
for (;count>0;count--) {
|
||||
SaveMd(di_base+di_index,LoadMd(si_base+si_index));
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_LODSB:
|
||||
for (;count>0;count--) {
|
||||
reg_al=LoadMb(si_base+si_index);
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_LODSW:
|
||||
add_index<<=1;
|
||||
for (;count>0;count--) {
|
||||
reg_ax=LoadMw(si_base+si_index);
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_LODSD:
|
||||
add_index<<=2;
|
||||
for (;count>0;count--) {
|
||||
reg_eax=LoadMd(si_base+si_index);
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
}
|
||||
break;
|
||||
case R_SCASB:
|
||||
{
|
||||
Bit8u val2;
|
||||
for (;count>0;) {
|
||||
count--;CPU_Cycles--;
|
||||
val2=LoadMb(di_base+di_index);
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
if ((reg_al==val2)!=inst.repz) break;
|
||||
}
|
||||
CMPB(reg_al,val2,LoadD,0);
|
||||
}
|
||||
break;
|
||||
case R_SCASW:
|
||||
{
|
||||
add_index<<=1;Bit16u val2;
|
||||
for (;count>0;) {
|
||||
count--;CPU_Cycles--;
|
||||
val2=LoadMw(di_base+di_index);
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
if ((reg_ax==val2)!=inst.repz) break;
|
||||
}
|
||||
CMPW(reg_ax,val2,LoadD,0);
|
||||
}
|
||||
break;
|
||||
case R_SCASD:
|
||||
{
|
||||
add_index<<=2;Bit32u val2;
|
||||
for (;count>0;) {
|
||||
count--;CPU_Cycles--;
|
||||
val2=LoadMd(di_base+di_index);
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
if ((reg_eax==val2)!=inst.repz) break;
|
||||
}
|
||||
CMPD(reg_eax,val2,LoadD,0);
|
||||
}
|
||||
break;
|
||||
case R_CMPSB:
|
||||
{
|
||||
Bit8u val1,val2;
|
||||
for (;count>0;) {
|
||||
count--;CPU_Cycles--;
|
||||
val1=LoadMb(si_base+si_index);
|
||||
val2=LoadMb(di_base+di_index);
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
if ((val1==val2)!=inst.repz) break;
|
||||
}
|
||||
CMPB(val1,val2,LoadD,0);
|
||||
}
|
||||
break;
|
||||
case R_CMPSW:
|
||||
{
|
||||
add_index<<=1;Bit16u val1,val2;
|
||||
for (;count>0;) {
|
||||
count--;CPU_Cycles--;
|
||||
val1=LoadMw(si_base+si_index);
|
||||
val2=LoadMw(di_base+di_index);
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
if ((val1==val2)!=inst.repz) break;
|
||||
}
|
||||
CMPW(val1,val2,LoadD,0);
|
||||
}
|
||||
break;
|
||||
case R_CMPSD:
|
||||
{
|
||||
add_index<<=2;Bit32u val1,val2;
|
||||
for (;count>0;) {
|
||||
count--;CPU_Cycles--;
|
||||
val1=LoadMd(si_base+si_index);
|
||||
val2=LoadMd(di_base+di_index);
|
||||
si_index=(si_index+add_index) & add_mask;
|
||||
di_index=(di_index+add_index) & add_mask;
|
||||
if ((val1==val2)!=inst.repz) break;
|
||||
}
|
||||
CMPD(val1,val2,LoadD,0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(LOG_CPU,LOG_ERROR)("Unhandled string %d entry %X",inst.code.op,inst.entry);
|
||||
}
|
||||
/* Clean up after certain amount of instructions */
|
||||
reg_esi&=(~add_mask);
|
||||
reg_esi|=(si_index & add_mask);
|
||||
reg_edi&=(~add_mask);
|
||||
reg_edi|=(di_index & add_mask);
|
||||
if (inst.prefix & PREFIX_REP) {
|
||||
count+=count_left;
|
||||
reg_ecx&=(~add_mask);
|
||||
reg_ecx|=(count & add_mask);
|
||||
}
|
||||
}
|
248
src/cpu/core_full/support.h
Normal file
248
src/cpu/core_full/support.h
Normal file
@ -0,0 +1,248 @@
|
||||
enum {
|
||||
L_N=0,
|
||||
L_SKIP,
|
||||
/* Grouped ones using MOD/RM */
|
||||
L_MODRM,L_MODRM_NVM,L_POPwRM,L_POPdRM,
|
||||
|
||||
L_Ib,L_Iw,L_Id,
|
||||
L_Ibx,L_Iwx,L_Idx, //Sign extend
|
||||
L_Ifw,L_Ifd,
|
||||
L_OP,
|
||||
|
||||
L_REGb,L_REGw,L_REGd,
|
||||
L_REGbIb,L_REGwIw,L_REGdId,
|
||||
L_POPw,L_POPd,
|
||||
L_POPfw,L_POPfd,
|
||||
L_SEG,
|
||||
|
||||
L_INTO,
|
||||
|
||||
L_VAL,
|
||||
L_PRESEG,
|
||||
L_DOUBLE,
|
||||
L_PREOP,L_PREADD,L_PREREP,L_PREREPNE,
|
||||
L_STRING,
|
||||
|
||||
/* Direct ones */
|
||||
D_IRETw,D_IRETd,
|
||||
D_PUSHAw,D_PUSHAd,
|
||||
D_POPAw,D_POPAd,
|
||||
D_POPSEGw,D_POPSEGd,
|
||||
D_DAA,D_DAS,
|
||||
D_AAA,D_AAS,
|
||||
D_CBW,D_CWDE,
|
||||
D_CWD,D_CDQ,
|
||||
D_SETALC,
|
||||
D_XLAT,
|
||||
D_CLI,D_STI,D_STC,D_CLC,D_CMC,D_CLD,D_STD,
|
||||
D_NOP,D_WAIT,
|
||||
D_ENTERw,D_ENTERd,
|
||||
D_LEAVEw,D_LEAVEd,
|
||||
|
||||
D_RETFw,D_RETFd,
|
||||
D_RETFwIw,D_RETFdIw,
|
||||
D_POPF,D_PUSHF,
|
||||
D_SAHF,D_LAHF,
|
||||
D_CPUID,
|
||||
D_HLT,D_CLTS,
|
||||
D_LOCK,D_ICEBP,
|
||||
L_ERROR
|
||||
};
|
||||
|
||||
|
||||
enum {
|
||||
O_N=t_LASTFLAG,
|
||||
O_COND,
|
||||
O_XCHG_AX,O_XCHG_EAX,
|
||||
O_IMULRw,O_IMULRd,
|
||||
O_BOUNDw,O_BOUNDd,
|
||||
O_CALLNw,O_CALLNd,
|
||||
O_CALLFw,O_CALLFd,
|
||||
O_JMPFw,O_JMPFd,
|
||||
|
||||
O_OPAL,O_ALOP,
|
||||
O_OPAX,O_AXOP,
|
||||
O_OPEAX,O_EAXOP,
|
||||
O_INT,
|
||||
O_SEGDS,O_SEGES,O_SEGFS,O_SEGGS,O_SEGSS,
|
||||
O_LOOP,O_LOOPZ,O_LOOPNZ,O_JCXZ,
|
||||
O_INb,O_INw,O_INd,
|
||||
O_OUTb,O_OUTw,O_OUTd,
|
||||
|
||||
O_NOT,O_AAM,O_AAD,
|
||||
O_MULb,O_MULw,O_MULd,
|
||||
O_IMULb,O_IMULw,O_IMULd,
|
||||
O_DIVb,O_DIVw,O_DIVd,
|
||||
O_IDIVb,O_IDIVw,O_IDIVd,
|
||||
O_CBACK,
|
||||
|
||||
|
||||
O_DSHLw,O_DSHLd,
|
||||
O_DSHRw,O_DSHRd,
|
||||
O_C_O ,O_C_NO ,O_C_B ,O_C_NB ,O_C_Z ,O_C_NZ ,O_C_BE ,O_C_NBE,
|
||||
O_C_S ,O_C_NS ,O_C_P ,O_C_NP ,O_C_L ,O_C_NL ,O_C_LE ,O_C_NLE,
|
||||
|
||||
O_GRP6w,O_GRP6d,
|
||||
O_GRP7w,O_GRP7d,
|
||||
O_M_CRx_Rd,O_M_Rd_CRx,
|
||||
O_M_DRx_Rd,O_M_Rd_DRx,
|
||||
O_M_TRx_Rd,O_M_Rd_TRx,
|
||||
O_LAR,O_LSL,
|
||||
O_ARPL,
|
||||
|
||||
O_BTw,O_BTSw,O_BTRw,O_BTCw,
|
||||
O_BTd,O_BTSd,O_BTRd,O_BTCd,
|
||||
O_BSFw,O_BSRw,O_BSFd,O_BSRd,
|
||||
|
||||
O_BSWAP,O_CMPXCHG,
|
||||
O_FPU
|
||||
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
S_N=0,
|
||||
S_C_Eb,
|
||||
S_Eb,S_Gb,S_EbGb,
|
||||
S_Ew,S_Gw,S_EwGw,
|
||||
S_Ed,S_Gd,S_EdGd,S_EdMw,
|
||||
|
||||
|
||||
S_REGb,S_REGw,S_REGd,
|
||||
S_PUSHw,S_PUSHd,
|
||||
S_SEGm,
|
||||
S_SEGGw,S_SEGGd,
|
||||
|
||||
|
||||
S_AIPw,S_C_AIPw,
|
||||
S_AIPd,S_C_AIPd,
|
||||
|
||||
S_IP,S_IPIw
|
||||
};
|
||||
|
||||
enum {
|
||||
R_OUTSB,R_OUTSW,R_OUTSD,
|
||||
R_INSB,R_INSW,R_INSD,
|
||||
R_MOVSB,R_MOVSW,R_MOVSD,
|
||||
R_LODSB,R_LODSW,R_LODSD,
|
||||
R_STOSB,R_STOSW,R_STOSD,
|
||||
R_SCASB,R_SCASW,R_SCASD,
|
||||
R_CMPSB,R_CMPSW,R_CMPSD
|
||||
};
|
||||
|
||||
enum {
|
||||
M_None=0,
|
||||
M_Ebx,M_Eb,M_Gb,M_EbGb,M_GbEb,
|
||||
M_Ewx,M_Ew,M_Gw,M_EwGw,M_GwEw,M_EwxGwx,M_EwGwt,
|
||||
M_Edx,M_Ed,M_Gd,M_EdGd,M_GdEd,M_EdxGdx,M_EdGdt,
|
||||
|
||||
M_EbIb,M_EwIb,M_EdIb,
|
||||
M_EwIw,M_EwIbx,M_EwxIbx,M_EwxIwx,M_EwGwIb,M_EwGwCL,
|
||||
M_EdId,M_EdIbx,M_EdGdIb,M_EdGdCL,
|
||||
|
||||
M_Efw,M_Efd,
|
||||
|
||||
M_Ib,M_Iw,M_Id,
|
||||
|
||||
|
||||
M_SEG,M_EA,
|
||||
M_GRP,
|
||||
M_GRP_Ib,M_GRP_CL,M_GRP_1,
|
||||
|
||||
M_POPw,M_POPd
|
||||
};
|
||||
|
||||
struct OpCode {
|
||||
Bit8u load,op,save,extra;
|
||||
};
|
||||
|
||||
struct FullData {
|
||||
Bitu entry;
|
||||
Bitu rm;
|
||||
EAPoint rm_eaa;
|
||||
Bitu rm_off;
|
||||
Bitu rm_eai;
|
||||
Bitu rm_index;
|
||||
Bitu rm_mod;
|
||||
OpCode code;
|
||||
EAPoint cseip;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
union {
|
||||
Bit32u dword[1];
|
||||
Bit32s dwords[1];
|
||||
Bit16u word[2];
|
||||
Bit16s words[2];
|
||||
Bit8u byte[4];
|
||||
Bit8s bytes[4];
|
||||
} blah1,blah2,blah_imm;
|
||||
#else
|
||||
union {
|
||||
Bit8u b;Bit8s bs;
|
||||
Bit16u w;Bit16s ws;
|
||||
Bit32u d;Bit32s ds;
|
||||
} op1,op2,imm;
|
||||
#endif
|
||||
Bitu new_flags;
|
||||
struct {
|
||||
EAPoint base;
|
||||
} seg;
|
||||
Bitu cond;
|
||||
bool repz;
|
||||
Bitu prefix;
|
||||
};
|
||||
|
||||
/* Some defines to get the names correct. */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
|
||||
#define inst_op1_b inst.blah1.byte[3]
|
||||
#define inst_op1_bs inst.blah1.bytes[3]
|
||||
#define inst_op1_w inst.blah1.word[1]
|
||||
#define inst_op1_ws inst.blah1.words[1]
|
||||
#define inst_op1_d inst.blah1.dword[0]
|
||||
#define inst_op1_ds inst.blah1.dwords[0]
|
||||
|
||||
#define inst_op2_b inst.blah2.byte[3]
|
||||
#define inst_op2_bs inst.blah2.bytes[3]
|
||||
#define inst_op2_w inst.blah2.word[1]
|
||||
#define inst_op2_ws inst.blah2.words[1]
|
||||
#define inst_op2_d inst.blah2.dword[0]
|
||||
#define inst_op2_ds inst.blah2.dwords[0]
|
||||
|
||||
#define inst_imm_b inst.blah_imm.byte[3]
|
||||
#define inst_imm_bs inst.blah_imm.bytes[3]
|
||||
#define inst_imm_w inst.blah_imm.word[1]
|
||||
#define inst_imm_ws inst.blah_imm.words[1]
|
||||
#define inst_imm_d inst.blah_imm.dword[0]
|
||||
#define inst_imm_ds inst.blah_imm.dwords[0]
|
||||
|
||||
#else
|
||||
|
||||
#define inst_op1_b inst.op1.b
|
||||
#define inst_op1_bs inst.op1.bs
|
||||
#define inst_op1_w inst.op1.w
|
||||
#define inst_op1_ws inst.op1.ws
|
||||
#define inst_op1_d inst.op1.d
|
||||
#define inst_op1_ds inst.op1.ds
|
||||
|
||||
#define inst_op2_b inst.op2.b
|
||||
#define inst_op2_bs inst.op2.bs
|
||||
#define inst_op2_w inst.op2.w
|
||||
#define inst_op2_ws inst.op2.ws
|
||||
#define inst_op2_d inst.op2.d
|
||||
#define inst_op2_ds inst.op2.ds
|
||||
|
||||
#define inst_imm_b inst.imm.b
|
||||
#define inst_imm_bs inst.imm.bs
|
||||
#define inst_imm_w inst.imm.w
|
||||
#define inst_imm_ws inst.imm.ws
|
||||
#define inst_imm_d inst.imm.d
|
||||
#define inst_imm_ds inst.imm.ds
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define PREFIX_NONE 0x0
|
||||
#define PREFIX_ADDR 0x1
|
||||
#define PREFIX_SEG 0x2
|
||||
#define PREFIX_REP 0x4
|
||||
|
209
src/cpu/core_normal.cpp
Normal file
209
src/cpu/core_normal.cpp
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dosbox.h"
|
||||
#include "mem.h"
|
||||
#include "cpu.h"
|
||||
#include "lazyflags.h"
|
||||
#include "inout.h"
|
||||
#include "callback.h"
|
||||
#include "pic.h"
|
||||
#include "fpu.h"
|
||||
#include "paging.h"
|
||||
|
||||
#if C_DEBUG
|
||||
#include "debug.h"
|
||||
#endif
|
||||
|
||||
#if (!C_CORE_INLINE)
|
||||
#define LoadMb(off) mem_readb(off)
|
||||
#define LoadMw(off) mem_readw(off)
|
||||
#define LoadMd(off) mem_readd(off)
|
||||
#define SaveMb(off,val) mem_writeb(off,val)
|
||||
#define SaveMw(off,val) mem_writew(off,val)
|
||||
#define SaveMd(off,val) mem_writed(off,val)
|
||||
#else
|
||||
#include "paging.h"
|
||||
#define LoadMb(off) mem_readb_inline(off)
|
||||
#define LoadMw(off) mem_readw_inline(off)
|
||||
#define LoadMd(off) mem_readd_inline(off)
|
||||
#define SaveMb(off,val) mem_writeb_inline(off,val)
|
||||
#define SaveMw(off,val) mem_writew_inline(off,val)
|
||||
#define SaveMd(off,val) mem_writed_inline(off,val)
|
||||
#endif
|
||||
|
||||
extern Bitu cycle_count;
|
||||
|
||||
#if C_FPU
|
||||
#define CPU_FPU 1 //Enable FPU escape instructions
|
||||
#endif
|
||||
|
||||
#define CPU_PIC_CHECK 1
|
||||
#define CPU_TRAP_CHECK 1
|
||||
|
||||
#define OPCODE_NONE 0x000
|
||||
#define OPCODE_0F 0x100
|
||||
#define OPCODE_SIZE 0x200
|
||||
|
||||
#define PREFIX_ADDR 0x1
|
||||
#define PREFIX_REP 0x2
|
||||
|
||||
#define TEST_PREFIX_ADDR (core.prefixes & PREFIX_ADDR)
|
||||
#define TEST_PREFIX_REP (core.prefixes & PREFIX_REP)
|
||||
|
||||
#define DO_PREFIX_SEG(_SEG) \
|
||||
BaseDS=SegBase(_SEG); \
|
||||
BaseSS=SegBase(_SEG); \
|
||||
core.base_val_ds=_SEG; \
|
||||
goto restart_opcode;
|
||||
|
||||
#define DO_PREFIX_ADDR() \
|
||||
core.prefixes=(core.prefixes & ~PREFIX_ADDR) | \
|
||||
(cpu.code.big ^ PREFIX_ADDR); \
|
||||
core.ea_table=&EATable[(core.prefixes&1) * 256]; \
|
||||
goto restart_opcode;
|
||||
|
||||
#define DO_PREFIX_REP(_ZERO) \
|
||||
core.prefixes|=PREFIX_REP; \
|
||||
core.rep_zero=_ZERO; \
|
||||
goto restart_opcode;
|
||||
|
||||
typedef PhysPt (*GetEAHandler)(void);
|
||||
|
||||
static const Bit32u AddrMaskTable[2]={0x0000ffff,0xffffffff};
|
||||
|
||||
static struct {
|
||||
Bitu opcode_index;
|
||||
PhysPt cseip;
|
||||
PhysPt base_ds,base_ss;
|
||||
SegNames base_val_ds;
|
||||
bool rep_zero;
|
||||
Bitu prefixes;
|
||||
GetEAHandler * ea_table;
|
||||
} core;
|
||||
|
||||
#define GETIP (core.cseip-SegBase(cs))
|
||||
#define SAVEIP reg_eip=GETIP;
|
||||
#define LOADIP core.cseip=(SegBase(cs)+reg_eip);
|
||||
|
||||
#define SegBase(c) SegPhys(c)
|
||||
#define BaseDS core.base_ds
|
||||
#define BaseSS core.base_ss
|
||||
|
||||
static INLINE Bit8u Fetchb() {
|
||||
Bit8u temp=LoadMb(core.cseip);
|
||||
core.cseip+=1;
|
||||
return temp;
|
||||
}
|
||||
|
||||
static INLINE Bit16u Fetchw() {
|
||||
Bit16u temp=LoadMw(core.cseip);
|
||||
core.cseip+=2;
|
||||
return temp;
|
||||
}
|
||||
static INLINE Bit32u Fetchd() {
|
||||
Bit32u temp=LoadMd(core.cseip);
|
||||
core.cseip+=4;
|
||||
return temp;
|
||||
}
|
||||
|
||||
#define Push_16 CPU_Push16
|
||||
#define Push_32 CPU_Push32
|
||||
#define Pop_16 CPU_Pop16
|
||||
#define Pop_32 CPU_Pop32
|
||||
|
||||
#include "instructions.h"
|
||||
#include "core_normal/support.h"
|
||||
#include "core_normal/string.h"
|
||||
|
||||
|
||||
#define EALookupTable (core.ea_table)
|
||||
|
||||
Bits CPU_Core_Normal_Run(void) {
|
||||
while (CPU_Cycles-->0) {
|
||||
LOADIP;
|
||||
core.opcode_index=cpu.code.big*0x200;
|
||||
core.prefixes=cpu.code.big;
|
||||
core.ea_table=&EATable[cpu.code.big*256];
|
||||
BaseDS=SegBase(ds);
|
||||
BaseSS=SegBase(ss);
|
||||
core.base_val_ds=ds;
|
||||
#if C_DEBUG
|
||||
#if C_HEAVY_DEBUG
|
||||
if (DEBUG_HeavyIsBreakpoint()) {
|
||||
FillFlags();
|
||||
return debugCallback;
|
||||
};
|
||||
#endif
|
||||
cycle_count++;
|
||||
#endif
|
||||
restart_opcode:
|
||||
switch (core.opcode_index+Fetchb()) {
|
||||
#include "core_normal/prefix_none.h"
|
||||
#include "core_normal/prefix_0f.h"
|
||||
#include "core_normal/prefix_66.h"
|
||||
#include "core_normal/prefix_66_0f.h"
|
||||
default:
|
||||
illegal_opcode:
|
||||
#if C_DEBUG
|
||||
{
|
||||
Bitu len=(GETIP-reg_eip);
|
||||
LOADIP;
|
||||
if (len>16) len=16;
|
||||
char tempcode[16*2+1];char * writecode=tempcode;
|
||||
for (;len>0;len--) {
|
||||
sprintf(writecode,"%02X",mem_readb(core.cseip++));
|
||||
writecode+=2;
|
||||
}
|
||||
LOG(LOG_CPU,LOG_NORMAL)("Illegal/Unhandled opcode %s",tempcode);
|
||||
}
|
||||
#endif
|
||||
CPU_Exception(6,0);
|
||||
continue;
|
||||
}
|
||||
SAVEIP;
|
||||
}
|
||||
FillFlags();
|
||||
return CBRET_NONE;
|
||||
decode_end:
|
||||
SAVEIP;
|
||||
FillFlags();
|
||||
return CBRET_NONE;
|
||||
}
|
||||
|
||||
Bits CPU_Core_Normal_Trap_Run(void) {
|
||||
Bits oldCycles = CPU_Cycles;
|
||||
CPU_Cycles = 1;
|
||||
cpu.trap_skip = false;
|
||||
|
||||
Bits ret=CPU_Core_Normal_Run();
|
||||
if (!cpu.trap_skip) CPU_HW_Interrupt(1);
|
||||
CPU_Cycles = oldCycles-1;
|
||||
cpudecoder = &CPU_Core_Normal_Run;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CPU_Core_Normal_Init(void) {
|
||||
|
||||
}
|
||||
|
3
src/cpu/core_normal/Makefile.am
Normal file
3
src/cpu/core_normal/Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
|
||||
noinst_HEADERS = helpers.h prefix_none.h prefix_66.h prefix_0f.h support.h table_ea.h \
|
||||
prefix_66_0f.h string.h
|
162
src/cpu/core_normal/helpers.h
Normal file
162
src/cpu/core_normal/helpers.h
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2007 The DOSBox Team
|
||||
*
|
||||
* This 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.
|
||||
*/
|
||||
|
||||
|
||||
#define GetEAa \
|
||||
PhysPt eaa=EALookupTable[rm]();
|
||||
|
||||
#define GetRMEAa \
|
||||
GetRM; \
|
||||
GetEAa;
|
||||
|
||||
|
||||
#define RMEbGb(inst) \
|
||||
{ \
|
||||
GetRMrb; \
|
||||
if (rm >= 0xc0 ) {GetEArb;inst(*earb,*rmrb,LoadRb,SaveRb);} \
|
||||
else {GetEAa;inst(eaa,*rmrb,LoadMb,SaveMb);} \
|
||||
}
|
||||
|
||||
#define RMGbEb(inst) \
|
||||
{ \
|
||||
GetRMrb; \
|
||||
if (rm >= 0xc0 ) {GetEArb;inst(*rmrb,*earb,LoadRb,SaveRb);} \
|
||||
else {GetEAa;inst(*rmrb,LoadMb(eaa),LoadRb,SaveRb);} \
|
||||
}
|
||||
|
||||
#define RMEb(inst) \
|
||||
{ \
|
||||
if (rm >= 0xc0 ) {GetEArb;inst(*earb,LoadRb,SaveRb);} \
|
||||
else {GetEAa;inst(eaa,LoadMb,SaveMb);} \
|
||||
}
|
||||
|
||||
#define RMEwGw(inst) \
|
||||
{ \
|
||||
GetRMrw; \
|
||||
if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,LoadRw,SaveRw);} \
|
||||
else {GetEAa;inst(eaa,*rmrw,LoadMw,SaveMw);} \
|
||||
}
|
||||
|
||||
#define RMEwGwOp3(inst,op3) \
|
||||
{ \
|
||||
GetRMrw; \
|
||||
if (rm >= 0xc0 ) {GetEArw;inst(*earw,*rmrw,op3,LoadRw,SaveRw);} \
|
||||
else {GetEAa;inst(eaa,*rmrw,op3,LoadMw,SaveMw);} \
|
||||
}
|
||||
|
||||
#define RMGwEw(inst) \
|
||||
{ \
|
||||
GetRMrw; \
|
||||
if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,LoadRw,SaveRw);} \
|
||||
else {GetEAa;inst(*rmrw,LoadMw(eaa),LoadRw,SaveRw);} \
|
||||
}
|
||||
|
||||
#define RMGwEwOp3(inst,op3) \
|
||||
{ \
|
||||
GetRMrw; \
|
||||
if (rm >= 0xc0 ) {GetEArw;inst(*rmrw,*earw,op3,LoadRw,SaveRw);} \
|
||||
else {GetEAa;inst(*rmrw,LoadMw(eaa),op3,LoadRw,SaveRw);} \
|
||||
}
|
||||
|
||||
#define RMEw(inst) \
|
||||
{ \
|
||||
if (rm >= 0xc0 ) {GetEArw;inst(*earw,LoadRw,SaveRw);} \
|
||||
else {GetEAa;inst(eaa,LoadMw,SaveMw);} \
|
||||
}
|
||||
|
||||
#define RMEdGd(inst) \
|
||||
{ \
|
||||
GetRMrd; \
|
||||
if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,LoadRd,SaveRd);} \
|
||||
else {GetEAa;inst(eaa,*rmrd,LoadMd,SaveMd);} \
|
||||
}
|
||||
|
||||
#define RMEdGdOp3(inst,op3) \
|
||||
{ \
|
||||
GetRMrd; \
|
||||
if (rm >= 0xc0 ) {GetEArd;inst(*eard,*rmrd,op3,LoadRd,SaveRd);} \
|
||||
else {GetEAa;inst(eaa,*rmrd,op3,LoadMd,SaveMd);} \
|
||||
}
|
||||
|
||||
|
||||
#define RMGdEd(inst) \
|
||||
{ \
|
||||
GetRMrd; \
|
||||
if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,LoadRd,SaveRd);} \
|
||||
else {GetEAa;inst(*rmrd,LoadMd(eaa),LoadRd,SaveRd);} \
|
||||
}
|
||||
|
||||
#define RMGdEdOp3(inst,op3) \
|
||||
{ \
|
||||
GetRMrd; \
|
||||
if (rm >= 0xc0 ) {GetEArd;inst(*rmrd,*eard,op3,LoadRd,SaveRd);} \
|
||||
else {GetEAa;inst(*rmrd,LoadMd(eaa),op3,LoadRd,SaveRd);} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define RMEw(inst) \
|
||||
{ \
|
||||
if (rm >= 0xc0 ) {GetEArw;inst(*earw,LoadRw,SaveRw);} \
|
||||
else {GetEAa;inst(eaa,LoadMw,SaveMw);} \
|
||||
}
|
||||
|
||||
#define RMEd(inst) \
|
||||
{ \
|
||||
if (rm >= 0xc0 ) {GetEArd;inst(*eard,LoadRd,SaveRd);} \
|
||||
else {GetEAa;inst(eaa,LoadMd,SaveMd);} \
|
||||
}
|
||||
|
||||
#define ALIb(inst) \
|
||||
{ inst(reg_al,Fetchb(),LoadRb,SaveRb)}
|
||||
|
||||
#define AXIw(inst) \
|
||||
{ inst(reg_ax,Fetchw(),LoadRw,SaveRw);}
|
||||
|
||||
#define EAXId(inst) \
|
||||
{ inst(reg_eax,Fetchd(),LoadRd,SaveRd);}
|
||||
|
||||
#define FPU_ESC(code) { \
|
||||
Bit8u rm=Fetchb(); \
|
||||
if (rm >= 0xc0) { \
|
||||
FPU_ESC ## code ## _Normal(rm); \
|
||||
} else { \
|
||||
GetEAa;FPU_ESC ## code ## _EA(rm,eaa); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define CASE_W(_WHICH) \
|
||||
case (OPCODE_NONE+_WHICH):
|
||||
|
||||
#define CASE_D(_WHICH) \
|
||||
case (OPCODE_SIZE+_WHICH):
|
||||
|
||||
#define CASE_B(_WHICH) \
|
||||
CASE_W(_WHICH) \
|
||||
CASE_D(_WHICH)
|
||||
|
||||
#define CASE_0F_W(_WHICH) \
|
||||
case ((OPCODE_0F|OPCODE_NONE)+_WHICH):
|
||||
|
||||
#define CASE_0F_D(_WHICH) \
|
||||
case ((OPCODE_0F|OPCODE_SIZE)+_WHICH):
|
||||
|
||||
#define CASE_0F_B(_WHICH) \
|
||||
CASE_0F_W(_WHICH) \
|
||||
CASE_0F_D(_WHICH)
|
558
src/cpu/core_normal/prefix_0f.h
Normal file
558
src/cpu/core_normal/prefix_0f.h
Normal file
@ -0,0 +1,558 @@
|
||||
/*
|
||||
* Copyright (C) 2002-2008 The DOSBox Team
|
||||
*
|
||||
* This 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.
|
||||
*/
|
||||
|
||||
CASE_0F_W(0x00) /* GRP 6 Exxx */
|
||||
{
|
||||
if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
|
||||
GetRM;Bitu which=(rm>>3)&7;
|
||||
switch (which) {
|
||||
case 0x00: /* SLDT */
|
||||
case 0x01: /* STR */
|
||||
{
|
||||
Bitu saveval;
|
||||
if (!which) saveval=CPU_SLDT();
|
||||
else saveval=CPU_STR();
|
||||
if (rm >= 0xc0) {GetEArw;*earw=saveval;}
|
||||
else {GetEAa;SaveMw(eaa,saveval);}
|
||||
}
|
||||
break;
|
||||
case 0x02:case 0x03:case 0x04:case 0x05:
|
||||
{
|
||||
Bitu loadval;
|
||||
if (rm >= 0xc0 ) {GetEArw;loadval=*earw;}
|
||||
else {GetEAa;loadval=LoadMw(eaa);}
|
||||
switch (which) {
|
||||
case 0x02:
|
||||
if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
if (CPU_LLDT(loadval)) RUNEXCEPTION();
|
||||
break;
|
||||
case 0x03:
|
||||
if (cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
if (CPU_LTR(loadval)) RUNEXCEPTION();
|
||||
break;
|
||||
case 0x04:
|
||||
CPU_VERR(loadval);
|
||||
break;
|
||||
case 0x05:
|
||||
CPU_VERW(loadval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto illegal_opcode;
|
||||
}
|
||||
}
|
||||
break;
|
||||
CASE_0F_W(0x01) /* Group 7 Ew */
|
||||
{
|
||||
GetRM;Bitu which=(rm>>3)&7;
|
||||
if (rm < 0xc0) { //First ones all use EA
|
||||
GetEAa;Bitu limit;
|
||||
switch (which) {
|
||||
case 0x00: /* SGDT */
|
||||
SaveMw(eaa,CPU_SGDT_limit());
|
||||
SaveMd(eaa+2,CPU_SGDT_base());
|
||||
break;
|
||||
case 0x01: /* SIDT */
|
||||
SaveMw(eaa,CPU_SIDT_limit());
|
||||
SaveMd(eaa+2,CPU_SIDT_base());
|
||||
break;
|
||||
case 0x02: /* LGDT */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
CPU_LGDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF);
|
||||
break;
|
||||
case 0x03: /* LIDT */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
CPU_LIDT(LoadMw(eaa),LoadMd(eaa+2) & 0xFFFFFF);
|
||||
break;
|
||||
case 0x04: /* SMSW */
|
||||
SaveMw(eaa,CPU_SMSW());
|
||||
break;
|
||||
case 0x06: /* LMSW */
|
||||
limit=LoadMw(eaa);
|
||||
if (CPU_LMSW(limit)) RUNEXCEPTION();
|
||||
break;
|
||||
case 0x07: /* INVLPG */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
PAGING_ClearTLB();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GetEArw;
|
||||
switch (which) {
|
||||
case 0x02: /* LGDT */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
goto illegal_opcode;
|
||||
case 0x03: /* LIDT */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
goto illegal_opcode;
|
||||
case 0x04: /* SMSW */
|
||||
*earw=CPU_SMSW();
|
||||
break;
|
||||
case 0x06: /* LMSW */
|
||||
if (CPU_LMSW(*earw)) RUNEXCEPTION();
|
||||
break;
|
||||
default:
|
||||
goto illegal_opcode;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
CASE_0F_W(0x02) /* LAR Gw,Ew */
|
||||
{
|
||||
if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
|
||||
GetRMrw;Bitu ar=*rmrw;
|
||||
if (rm >= 0xc0) {
|
||||
GetEArw;CPU_LAR(*earw,ar);
|
||||
} else {
|
||||
GetEAa;CPU_LAR(LoadMw(eaa),ar);
|
||||
}
|
||||
*rmrw=(Bit16u)ar;
|
||||
}
|
||||
break;
|
||||
CASE_0F_W(0x03) /* LSL Gw,Ew */
|
||||
{
|
||||
if ((reg_flags & FLAG_VM) || (!cpu.pmode)) goto illegal_opcode;
|
||||
GetRMrw;Bitu limit=*rmrw;
|
||||
if (rm >= 0xc0) {
|
||||
GetEArw;CPU_LSL(*earw,limit);
|
||||
} else {
|
||||
GetEAa;CPU_LSL(LoadMw(eaa),limit);
|
||||
}
|
||||
*rmrw=(Bit16u)limit;
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x06) /* CLTS */
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
cpu.cr0&=(~CR0_TASKSWITCH);
|
||||
break;
|
||||
CASE_0F_B(0x08) /* INVD */
|
||||
CASE_0F_B(0x09) /* WBINVD */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
if (cpu.pmode && cpu.cpl) EXCEPTION(EXCEPTION_GP);
|
||||
break;
|
||||
CASE_0F_B(0x20) /* MOV Rd.CRx */
|
||||
{
|
||||
GetRM;
|
||||
Bitu which=(rm >> 3) & 7;
|
||||
if (rm < 0xc0 ) {
|
||||
rm |= 0xc0;
|
||||
LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%u with non-register",which);
|
||||
}
|
||||
GetEArd;
|
||||
Bit32u crx_value;
|
||||
if (CPU_READ_CRX(which,crx_value)) RUNEXCEPTION();
|
||||
*eard=crx_value;
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x21) /* MOV Rd,DRx */
|
||||
{
|
||||
GetRM;
|
||||
Bitu which=(rm >> 3) & 7;
|
||||
if (rm < 0xc0 ) {
|
||||
rm |= 0xc0;
|
||||
LOG(LOG_CPU,LOG_ERROR)("MOV XXX,DR%u with non-register",which);
|
||||
}
|
||||
GetEArd;
|
||||
Bit32u drx_value;
|
||||
if (CPU_READ_DRX(which,drx_value)) RUNEXCEPTION();
|
||||
*eard=drx_value;
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x22) /* MOV CRx,Rd */
|
||||
{
|
||||
GetRM;
|
||||
Bitu which=(rm >> 3) & 7;
|
||||
if (rm < 0xc0 ) {
|
||||
rm |= 0xc0;
|
||||
LOG(LOG_CPU,LOG_ERROR)("MOV XXX,CR%u with non-register",which);
|
||||
}
|
||||
GetEArd;
|
||||
if (CPU_WRITE_CRX(which,*eard)) RUNEXCEPTION();
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x23) /* MOV DRx,Rd */
|
||||
{
|
||||
GetRM;
|
||||
Bitu which=(rm >> 3) & 7;
|
||||
if (rm < 0xc0 ) {
|
||||
rm |= 0xc0;
|
||||
LOG(LOG_CPU,LOG_ERROR)("MOV DR%u,XXX with non-register",which);
|
||||
}
|
||||
GetEArd;
|
||||
if (CPU_WRITE_DRX(which,*eard)) RUNEXCEPTION();
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x24) /* MOV Rd,TRx */
|
||||
{
|
||||
GetRM;
|
||||
Bitu which=(rm >> 3) & 7;
|
||||
if (rm < 0xc0 ) {
|
||||
rm |= 0xc0;
|
||||
LOG(LOG_CPU,LOG_ERROR)("MOV XXX,TR%u with non-register",which);
|
||||
}
|
||||
GetEArd;
|
||||
Bit32u trx_value;
|
||||
if (CPU_READ_TRX(which,trx_value)) RUNEXCEPTION();
|
||||
*eard=trx_value;
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x26) /* MOV TRx,Rd */
|
||||
{
|
||||
GetRM;
|
||||
Bitu which=(rm >> 3) & 7;
|
||||
if (rm < 0xc0 ) {
|
||||
rm |= 0xc0;
|
||||
LOG(LOG_CPU,LOG_ERROR)("MOV TR%u,XXX with non-register",which);
|
||||
}
|
||||
GetEArd;
|
||||
if (CPU_WRITE_TRX(which,*eard)) RUNEXCEPTION();
|
||||
}
|
||||
break;
|
||||
CASE_0F_B(0x31) /* RDTSC */
|
||||
{
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_PENTIUMSLOW) goto illegal_opcode;
|
||||
Bit64s tsc=(Bit64s)(PIC_FullIndex()*(double)CPU_CycleMax);
|
||||
reg_edx=(Bit32u)(tsc>>32);
|
||||
reg_eax=(Bit32u)(tsc&0xffffffff);
|
||||
}
|
||||
break;
|
||||
CASE_0F_W(0x80) /* JO */
|
||||
JumpCond16_w(TFLG_O);break;
|
||||
CASE_0F_W(0x81) /* JNO */
|
||||
JumpCond16_w(TFLG_NO);break;
|
||||
CASE_0F_W(0x82) /* JB */
|
||||
JumpCond16_w(TFLG_B);break;
|
||||
CASE_0F_W(0x83) /* JNB */
|
||||
JumpCond16_w(TFLG_NB);break;
|
||||
CASE_0F_W(0x84) /* JZ */
|
||||
JumpCond16_w(TFLG_Z);break;
|
||||
CASE_0F_W(0x85) /* JNZ */
|
||||
JumpCond16_w(TFLG_NZ);break;
|
||||
CASE_0F_W(0x86) /* JBE */
|
||||
JumpCond16_w(TFLG_BE);break;
|
||||
CASE_0F_W(0x87) /* JNBE */
|
||||
JumpCond16_w(TFLG_NBE);break;
|
||||
CASE_0F_W(0x88) /* JS */
|
||||
JumpCond16_w(TFLG_S);break;
|
||||
CASE_0F_W(0x89) /* JNS */
|
||||
JumpCond16_w(TFLG_NS);break;
|
||||
CASE_0F_W(0x8a) /* JP */
|
||||
JumpCond16_w(TFLG_P);break;
|
||||
CASE_0F_W(0x8b) /* JNP */
|
||||
JumpCond16_w(TFLG_NP);break;
|
||||
CASE_0F_W(0x8c) /* JL */
|
||||
JumpCond16_w(TFLG_L);break;
|
||||
CASE_0F_W(0x8d) /* JNL */
|
||||
JumpCond16_w(TFLG_NL);break;
|
||||
CASE_0F_W(0x8e) /* JLE */
|
||||
JumpCond16_w(TFLG_LE);break;
|
||||
CASE_0F_W(0x8f) /* JNLE */
|
||||
JumpCond16_w(TFLG_NLE);break;
|
||||
CASE_0F_B(0x90) /* SETO */
|
||||
SETcc(TFLG_O);break;
|
||||
CASE_0F_B(0x91) /* SETNO */
|
||||
SETcc(TFLG_NO);break;
|
||||
CASE_0F_B(0x92) /* SETB */
|
||||
SETcc(TFLG_B);break;
|
||||
CASE_0F_B(0x93) /* SETNB */
|
||||
SETcc(TFLG_NB);break;
|
||||
CASE_0F_B(0x94) /* SETZ */
|
||||
SETcc(TFLG_Z);break;
|
||||
CASE_0F_B(0x95) /* SETNZ */
|
||||
SETcc(TFLG_NZ); break;
|
||||
CASE_0F_B(0x96) /* SETBE */
|
||||
SETcc(TFLG_BE);break;
|
||||
CASE_0F_B(0x97) /* SETNBE */
|
||||
SETcc(TFLG_NBE);break;
|
||||
CASE_0F_B(0x98) /* SETS */
|
||||
SETcc(TFLG_S);break;
|
||||
CASE_0F_B(0x99) /* SETNS */
|
||||
SETcc(TFLG_NS);break;
|
||||
CASE_0F_B(0x9a) /* SETP */
|
||||
SETcc(TFLG_P);break;
|
||||
CASE_0F_B(0x9b) /* SETNP */
|
||||
SETcc(TFLG_NP);break;
|
||||
CASE_0F_B(0x9c) /* SETL */
|
||||
SETcc(TFLG_L);break;
|
||||
CASE_0F_B(0x9d) /* SETNL */
|
||||
SETcc(TFLG_NL);break;
|
||||
CASE_0F_B(0x9e) /* SETLE */
|
||||
SETcc(TFLG_LE);break;
|
||||
CASE_0F_B(0x9f) /* SETNLE */
|
||||
SETcc(TFLG_NLE);break;
|
||||
|
||||
CASE_0F_W(0xa0) /* PUSH FS */
|
||||
Push_16(SegValue(fs));break;
|
||||
CASE_0F_W(0xa1) /* POP FS */
|
||||
if (CPU_PopSeg(fs,false)) RUNEXCEPTION();
|
||||
break;
|
||||
CASE_0F_B(0xa2) /* CPUID */
|
||||
if (!CPU_CPUID()) goto illegal_opcode;
|
||||
break;
|
||||
CASE_0F_W(0xa3) /* BT Ew,Gw */
|
||||
{
|
||||
FillFlags();GetRMrw;
|
||||
Bit16u mask=1 << (*rmrw & 15);
|
||||
if (rm >= 0xc0 ) {
|
||||
GetEArw;
|
||||
SETFLAGBIT(CF,(*earw & mask));
|
||||
} else {
|
||||
GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
|
||||
Bit16u old=LoadMw(eaa);
|
||||
SETFLAGBIT(CF,(old & mask));
|
||||
}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xa4) /* SHLD Ew,Gw,Ib */
|
||||
RMEwGwOp3(DSHLW,Fetchb());
|
||||
break;
|
||||
CASE_0F_W(0xa5) /* SHLD Ew,Gw,CL */
|
||||
RMEwGwOp3(DSHLW,reg_cl);
|
||||
break;
|
||||
CASE_0F_W(0xa8) /* PUSH GS */
|
||||
Push_16(SegValue(gs));break;
|
||||
CASE_0F_W(0xa9) /* POP GS */
|
||||
if (CPU_PopSeg(gs,false)) RUNEXCEPTION();
|
||||
break;
|
||||
CASE_0F_W(0xab) /* BTS Ew,Gw */
|
||||
{
|
||||
FillFlags();GetRMrw;
|
||||
Bit16u mask=1 << (*rmrw & 15);
|
||||
if (rm >= 0xc0 ) {
|
||||
GetEArw;
|
||||
SETFLAGBIT(CF,(*earw & mask));
|
||||
*earw|=mask;
|
||||
} else {
|
||||
GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
|
||||
Bit16u old=LoadMw(eaa);
|
||||
SETFLAGBIT(CF,(old & mask));
|
||||
SaveMw(eaa,old | mask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xac) /* SHRD Ew,Gw,Ib */
|
||||
RMEwGwOp3(DSHRW,Fetchb());
|
||||
break;
|
||||
CASE_0F_W(0xad) /* SHRD Ew,Gw,CL */
|
||||
RMEwGwOp3(DSHRW,reg_cl);
|
||||
break;
|
||||
CASE_0F_W(0xaf) /* IMUL Gw,Ew */
|
||||
RMGwEwOp3(DIMULW,*rmrw);
|
||||
break;
|
||||
CASE_0F_W(0xb2) /* LSS Ew */
|
||||
{
|
||||
GetRMrw;
|
||||
if (rm >= 0xc0) goto illegal_opcode;
|
||||
GetEAa;
|
||||
if (CPU_SetSegGeneral(ss,LoadMw(eaa+2))) RUNEXCEPTION();
|
||||
*rmrw=LoadMw(eaa);
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xb3) /* BTR Ew,Gw */
|
||||
{
|
||||
FillFlags();GetRMrw;
|
||||
Bit16u mask=1 << (*rmrw & 15);
|
||||
if (rm >= 0xc0 ) {
|
||||
GetEArw;
|
||||
SETFLAGBIT(CF,(*earw & mask));
|
||||
*earw&= ~mask;
|
||||
} else {
|
||||
GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
|
||||
Bit16u old=LoadMw(eaa);
|
||||
SETFLAGBIT(CF,(old & mask));
|
||||
SaveMw(eaa,old & ~mask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xb4) /* LFS Ew */
|
||||
{
|
||||
GetRMrw;
|
||||
if (rm >= 0xc0) goto illegal_opcode;
|
||||
GetEAa;
|
||||
if (CPU_SetSegGeneral(fs,LoadMw(eaa+2))) RUNEXCEPTION();
|
||||
*rmrw=LoadMw(eaa);
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xb5) /* LGS Ew */
|
||||
{
|
||||
GetRMrw;
|
||||
if (rm >= 0xc0) goto illegal_opcode;
|
||||
GetEAa;
|
||||
if (CPU_SetSegGeneral(gs,LoadMw(eaa+2))) RUNEXCEPTION();
|
||||
*rmrw=LoadMw(eaa);
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xb6) /* MOVZX Gw,Eb */
|
||||
{
|
||||
GetRMrw;
|
||||
if (rm >= 0xc0 ) {GetEArb;*rmrw=*earb;}
|
||||
else {GetEAa;*rmrw=LoadMb(eaa);}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xb7) /* MOVZX Gw,Ew */
|
||||
CASE_0F_W(0xbf) /* MOVSX Gw,Ew */
|
||||
{
|
||||
GetRMrw;
|
||||
if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;}
|
||||
else {GetEAa;*rmrw=LoadMw(eaa);}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xba) /* GRP8 Ew,Ib */
|
||||
{
|
||||
FillFlags();GetRM;
|
||||
if (rm >= 0xc0 ) {
|
||||
GetEArw;
|
||||
Bit16u mask=1 << (Fetchb() & 15);
|
||||
SETFLAGBIT(CF,(*earw & mask));
|
||||
switch (rm & 0x38) {
|
||||
case 0x20: /* BT */
|
||||
break;
|
||||
case 0x28: /* BTS */
|
||||
*earw|=mask;
|
||||
break;
|
||||
case 0x30: /* BTR */
|
||||
*earw&= ~mask;
|
||||
break;
|
||||
case 0x38: /* BTC */
|
||||
*earw^=mask;
|
||||
break;
|
||||
default:
|
||||
E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38);
|
||||
}
|
||||
} else {
|
||||
GetEAa;Bit16u old=LoadMw(eaa);
|
||||
Bit16u mask=1 << (Fetchb() & 15);
|
||||
SETFLAGBIT(CF,(old & mask));
|
||||
switch (rm & 0x38) {
|
||||
case 0x20: /* BT */
|
||||
break;
|
||||
case 0x28: /* BTS */
|
||||
SaveMw(eaa,old|mask);
|
||||
break;
|
||||
case 0x30: /* BTR */
|
||||
SaveMw(eaa,old & ~mask);
|
||||
break;
|
||||
case 0x38: /* BTC */
|
||||
SaveMw(eaa,old ^ mask);
|
||||
break;
|
||||
default:
|
||||
E_Exit("CPU:0F:BA:Illegal subfunction %X",rm & 0x38);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xbb) /* BTC Ew,Gw */
|
||||
{
|
||||
FillFlags();GetRMrw;
|
||||
Bit16u mask=1 << (*rmrw & 15);
|
||||
if (rm >= 0xc0 ) {
|
||||
GetEArw;
|
||||
SETFLAGBIT(CF,(*earw & mask));
|
||||
*earw^=mask;
|
||||
} else {
|
||||
GetEAa;eaa+=(((Bit16s)*rmrw)>>4)*2;
|
||||
Bit16u old=LoadMw(eaa);
|
||||
SETFLAGBIT(CF,(old & mask));
|
||||
SaveMw(eaa,old ^ mask);
|
||||
}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xbc) /* BSF Gw,Ew */
|
||||
{
|
||||
GetRMrw;
|
||||
Bit16u result,value;
|
||||
if (rm >= 0xc0) { GetEArw; value=*earw; }
|
||||
else { GetEAa; value=LoadMw(eaa); }
|
||||
if (value==0) {
|
||||
SETFLAGBIT(ZF,true);
|
||||
} else {
|
||||
result = 0;
|
||||
while ((value & 0x01)==0) { result++; value>>=1; }
|
||||
SETFLAGBIT(ZF,false);
|
||||
*rmrw = result;
|
||||
}
|
||||
lflags.type=t_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xbd) /* BSR Gw,Ew */
|
||||
{
|
||||
GetRMrw;
|
||||
Bit16u result,value;
|
||||
if (rm >= 0xc0) { GetEArw; value=*earw; }
|
||||
else { GetEAa; value=LoadMw(eaa); }
|
||||
if (value==0) {
|
||||
SETFLAGBIT(ZF,true);
|
||||
} else {
|
||||
result = 15; // Operandsize-1
|
||||
while ((value & 0x8000)==0) { result--; value<<=1; }
|
||||
SETFLAGBIT(ZF,false);
|
||||
*rmrw = result;
|
||||
}
|
||||
lflags.type=t_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xbe) /* MOVSX Gw,Eb */
|
||||
{
|
||||
GetRMrw;
|
||||
if (rm >= 0xc0 ) {GetEArb;*rmrw=*(Bit8s *)earb;}
|
||||
else {GetEAa;*rmrw=LoadMbs(eaa);}
|
||||
break;
|
||||
}
|
||||
CASE_0F_B(0xc0) /* XADD Gb,Eb */
|
||||
{
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
GetRMrb;Bit8u oldrmrb=*rmrb;
|
||||
if (rm >= 0xc0 ) {GetEArb;*rmrb=*earb;*earb+=oldrmrb;}
|
||||
else {GetEAa;*rmrb=LoadMb(eaa);SaveMb(eaa,LoadMb(eaa)+oldrmrb);}
|
||||
break;
|
||||
}
|
||||
CASE_0F_W(0xc1) /* XADD Gw,Ew */
|
||||
{
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
GetRMrw;Bit16u oldrmrw=*rmrw;
|
||||
if (rm >= 0xc0 ) {GetEArw;*rmrw=*earw;*earw+=oldrmrw;}
|
||||
else {GetEAa;*rmrw=LoadMw(eaa);SaveMw(eaa,LoadMw(eaa)+oldrmrw);}
|
||||
break;
|
||||
}
|
||||
CASE_0F_B(0xc8) /* BSWAP EAX */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_eax);break;
|
||||
CASE_0F_B(0xc9) /* BSWAP ECX */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_ecx);break;
|
||||
CASE_0F_B(0xca) /* BSWAP EDX */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_edx);break;
|
||||
CASE_0F_B(0xcb) /* BSWAP EBX */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_ebx);break;
|
||||
CASE_0F_B(0xcc) /* BSWAP ESP */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_esp);break;
|
||||
CASE_0F_B(0xcd) /* BSWAP EBP */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_ebp);break;
|
||||
CASE_0F_B(0xce) /* BSWAP ESI */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_esi);break;
|
||||
CASE_0F_B(0xcf) /* BSWAP EDI */
|
||||
if (CPU_ArchitectureType<CPU_ARCHTYPE_486OLDSLOW) goto illegal_opcode;
|
||||
BSWAP(reg_edi);break;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user