commit 3c253c2cf85556aa9c2232198c841dff63f20a39 Author: TomW Date: Sun Apr 21 14:54:35 2013 +0100 Add v0.7 source diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..92851102 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +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) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/acer386.nvr b/acer386.nvr new file mode 100644 index 00000000..cc5a06d9 Binary files /dev/null and b/acer386.nvr differ diff --git a/ami286.nvr b/ami286.nvr new file mode 100644 index 00000000..bfb993f2 Binary files /dev/null and b/ami286.nvr differ diff --git a/ami386.nvr b/ami386.nvr new file mode 100644 index 00000000..22563011 Binary files /dev/null and b/ami386.nvr differ diff --git a/ami486.nvr b/ami486.nvr new file mode 100644 index 00000000..70552798 Binary files /dev/null and b/ami486.nvr differ diff --git a/at.nvr b/at.nvr new file mode 100644 index 00000000..b5c94c19 Binary files /dev/null and b/at.nvr differ diff --git a/cmdpc30.nvr b/cmdpc30.nvr new file mode 100644 index 00000000..3e655183 Binary files /dev/null and b/cmdpc30.nvr differ diff --git a/dell200.nvr b/dell200.nvr new file mode 100644 index 00000000..b16f1849 Binary files /dev/null and b/dell200.nvr differ diff --git a/europc.nvr b/europc.nvr new file mode 100644 index 00000000..6757695c Binary files /dev/null and b/europc.nvr differ diff --git a/hot-433.nvr b/hot-433.nvr new file mode 100644 index 00000000..104e7113 Binary files /dev/null and b/hot-433.nvr differ diff --git a/mda.rom b/mda.rom new file mode 100644 index 00000000..1b92f042 Binary files /dev/null and b/mda.rom differ diff --git a/megapc.nvr b/megapc.nvr new file mode 100644 index 00000000..38927617 Binary files /dev/null and b/megapc.nvr differ diff --git a/pc1512.nvr b/pc1512.nvr new file mode 100644 index 00000000..b1f758b3 Binary files /dev/null and b/pc1512.nvr differ diff --git a/pc1640.nvr b/pc1640.nvr new file mode 100644 index 00000000..7171e74f Binary files /dev/null and b/pc1640.nvr differ diff --git a/pc2086.nvr b/pc2086.nvr new file mode 100644 index 00000000..40f56360 Binary files /dev/null and b/pc2086.nvr differ diff --git a/pc3086.nvr b/pc3086.nvr new file mode 100644 index 00000000..f340d66a Binary files /dev/null and b/pc3086.nvr differ diff --git a/readme.txt b/readme.txt new file mode 100644 index 00000000..905d3b80 --- /dev/null +++ b/readme.txt @@ -0,0 +1,483 @@ +PCem v0.7 + +Changes since v0.6: + +- New machines - DTK XT clone, Amstrad PC2086, Amstrad PC3086, Olivetti M24, Commodore PC 30 III, + PCI 486 clone +- New graphics cards - IBM EGA, Diamond Stealth 32 (ET4000/W32p), Paradise Bahamas 64 (S3 Vision864) +- IDE hard disc emulation. This replaces the old INT 13 trapping emulation on all models. For machines + which don't natively have IDE support, the XTIDE board is emulated. See the readme file for details. +- Fixed wrong code segment on page fault - eliminates some Win95 crashes +- Fixed trap flag on POPF/IRET - improves DOS box on Win95 +- Fixed various pmode stuff, OS/2 v1.3 works +- Fixed MMU caching bug, Win95 more stable, IE4 now works, Win98 now works, Linux now appears to work +- Major improvements to floppy disc emulation - fixed occasional disc corruption, works with OS/2 and Linux +- ATAPI identify command now returns an ATAPI version, Win95 native CD-ROM drivers now work. +- CD-ROM emulation now uses raw read for audio - works on Windows 7 +- Major internal changes to graphics emulation +- Major internal changes to memory and IO emulation +- Many other changes + + +PCem emulates the following machines: + +IBM 5150 PC (1981) +The original PC. This shipped in 1981 with a 4.77mhz 8088, 64k of RAM, and a cassette port. +Disc drives quickly became standard, along with more memory. + +ROM files needed: + +pc102782.bin +basicc11.f6 +basicc11.f8 +basicc11.fa +basicc11.fc + + +IBM 5160 XT (1983) +From a hardware perspective, this is a minor tweak of the original PC. It originally shipped +with 128k of RAM and a 10mb hard disc, both of which could be easily fitted to the 1981 machine. +However, this was targetted as businesses and was more successful than the original. + +ROM files needed: + +xt050986.0 +xt050986.1 + + +IBM AT (1984) +This was the 'next generation' PC, fully 16-bit with an 80286. The original model came with a 6mhz +286, which ran three times as fast as the XT. This model also introduced EGA. + +ROM files needed: + +at111585.0 +at111585.1 + + +Olivetti M24 (1984) +An enhanced XT clone, also known as the AT&T PC 6300. Has an 8086 CPU, and an unusual 'double-res' +CGA display. + +ROM files needed: + +olivetti_m24_version_1.43_low.bin +olivetti_m24_version_1.43_high.bin + + +Tandy 1000 (1985) +This is a clone of the unsuccessful IBM PCjr, which added better graphics and sound to the XT, +but removed much expandability plus some other hardware (such as the DMA controller). The Tandy +puts back the DMA controller and ISA slots, making it a much more useful machine. Many games +from the late 80s support the Tandy. + +ROM files needed: + +tandy1t1.020 + + +DTK Clone XT (1986) +A generic clone XT board. + +ROM files needed: + +DTK_ERSO_2.42_2764.bin + + +Amstrad PC1512 (1986) +This was Amstrad's first entry into the PC clone market (after the CPC and PCW machines), and +was the first cheap PC available in the UK, selling for only £500. It was a 'turbo' clone, +having an 8mhz 8086, as opposed to an 8088, and had 512k RAM as standard. It also had a +perculiar modification to its onboard CGA controller - the 640x200 mode had 16 colours instead +of the usual 2. This was put to good use by GEM, which shipped with the machine. + +Amstrad's CGA implementation has a few oddities, these are emulated as best as possible. This +mainly affects games defining unusual video modes, though 160x100x16 still works (as on the real +machine). + +ROM files needed: + +40043.v1 +40044.v2 +40078.ic127 + + +Amstrad PC1640 (1987) +Amstrad's followup to the PC1512, the PC1640 had 640k of RAM and onboard EGA, but was otherwise +mostly the same. + +ROM files needed: + +40043.v3 +40044.v3 +40100 + + +Sinclair PC200/Amstrad PC20 (1988) +This was Amstrad's entry to the 16-bit home computer market, intended to compete with the Atari +ST and Commodore Amiga. It's similar to the PC1512, but is based on Amstrad's portable PPC512 +system. With stock CGA and PC speaker, it couldn't compare with the ST or Amiga. + +ROM files needed: + +pc20v2.0 +pc20v2.1 +40109.bin + + +Schneider Euro PC (1988) +A German XT clone. An 'all-in-one' system like the Sinclair PC200. I don't know much about this +machine to be honest! This doesn't appear to work with the XTIDE BIOS, so therefore this is the +only model that does not support hard discs. + +ROM files needed: + +50145 +50146 + + +(c)Anonymous Generic Turbo XT BIOS (1988?) +This is a BIOS whose source code was made available on Usenet in 1988. It appears to be an +anonymous BIOS from an XT clone board. It was then heavily modified to fix bugs. The history of +this BIOS (and the source code) is at http://dizzie.narod.ru/bios.txt + +ROM files needed: + +pcxt.rom + + +Commodore PC30-III (1988) +A fairly generic 286 clone. + +ROM files needed: + +commodore pc 30 iii even.bin +commodore pc 30 iii odd.bin + + +Amstrad PC2086 (1989) +The PC2086 is essentially a PC1640 with VGA and 3.5" floppy drives. + +ROM files needed: + +40179.ic129 +40180.ic132 +40186.ic171 + + +Amstrad PC3086 (1990) +The PC3086 is a version of the PC2086 with a more standard case. + +ROM files needed: + +fc00.bin +c000.bin + + +Dell System 200 (1990?) +This is a pretty generic 286 clone with a Phoenix BIOS. + +HIMEM.SYS doesn't appear to work on this one, for some reason. + +ROM files needed: + +dell0.bin +dell1.bin + + +AMI 286 clone (1990) +This is a generic 286 clone with an AMI BIOS. + +ROM files needed: + +amic206.bin + + +Acermate 386SX/25N (1992?) +An integrated 386SX clone, with onboard Oak SVGA and IO. + +ROM files needed: +acer386.bin +oti067.bin + + +Amstrad MegaPC (1992) +A 386SX clone (otherwise known as the PC7386SX) with a built-in Sega Megadrive. Only the PC section +is emulated, obv. + +ROM files needed: +41651-bios lo.u18 +211253-bios hi.u19 + + +AMI 386 clone (1994) +This is a generic 386 clone with an AMI BIOS. The BIOS came from my 386DX/40, the motherboard is +dated June 1994. + +ROM files needed: + +ami495.bin + + +AMI 486 clone (1993) +This is a generic 486 clone with an AMI BIOS. The BIOS came from my 486SX/25, bought in December +1993. + +ROM files needed: + +ami1429.bin + + +AMI WinBIOS 486 clone (1994) +A 486 clone with a newer AMI BIOS. + +ROM files needed: + +ali1429g.amw + + +PCI 486 clone (1994) +A 486 clone with a PCI bus - specifically, a Shuttle HOT-433 board. Due to lack of documentation +this machine has some issues - in particular, don't enable the PCI IDE emulation. + +ROM files needed: + +hot-433.ami + + +PCem emulates the following graphics adapters : + +MDA - The original PC adapter. This displays 80x25 text in monochrome. + +Hercules - A clone of MDA, with the addition of a high-resolution 720x348 graphics mode. + +CGA - The most common of the original adapters, supporting 40x25 and 80x25 text, and + 320x200 in 4 colours, 640x200 in 2 colours, and a composite mode giving 160x200 in 16 colours. + +IBM EGA - The original 1984 IBM EGA card, with 256k VRAM. + +Trident 8900D SVGA - A low cost SVGA board circa 1992/1993. Not the greatest board in it's day, but + it has a reasonable VESA driver and (buggy) 15/16/24-bit colour modes. + +Tseng ET4000AX SVGA - A somewhat better SVGA board than the Trident, here you get better compatibility + and speed (on the real card, not the emulator) in exchange for being limited to 8-bit colour. + +Diamond Stealth 32 SVGA - An ET4000/W32p based board, has 15/16/24-bit colour modes, plus acceleration. + There is an odd bug with this one, where Windows 9x DOS boxes won't open with modes beyond 8-bit + colour. Supports PCI. + +Paradise Bahamas 64 - An S3 Vision864 based board. This has the best Windows drivers, but the default + VESA driver is poor. Supports PCI. + + +Some models have fixed graphics adapters : + +Olivetti M24 - CGA with double-res text modes and a 640x400 mode. I haven't seen a dump of the font + ROM for this yet, so if one is not provided the MDA font will be used - which looks slightly odd + as it is 14-line instead of 16-line. + +Tandy 1000 - CGA with various new modes - 160x200x16, 320x200x16, 640x200x4. Widely supported in 80s + games. + +Amstrad PC1512 - CGA with a new mode (640x200x16). Only supported in GEM to my knowledge. + +Amstrad PC1640 - Paradise EGA. + +Amstrad PC2086/PC3086 - Paradise PVGA1. An early SVGA clone with 256kb VRAM. + +Amstrad MegaPC - Paradise 90C11. A development of the PVGA1, with 512kb VRAM. + +Acer 386SX/25N - Oak OTI-067. Another 512kb SVGA clone. + + +Pcem emulates the following sound devices : + +PC speaker - The standard beeper on all PCs. Supports samples/RealSound. + +Tandy PSG - The Texas Instruments chip in the PCjr and Tandy 1000. Supports 3 voices plus + noise. I reused the emulator in B-em for this (slightly modified). + +Gameblaster - The Creative Labs Gameblaster/Creative Music System, Creative's first sound card + introduced in 1987. Has two Philips SAA1099, giving 12 voices of square waves plus 4 noise + voices. In stereo! + +Adlib - Has a Yamaha YM3812, giving 9 voices of 2 op FM, or 6 voices plus a useless drum section. + PCem uses Jarek Burczynski's emulator for this. + +Sound Blaster - Several Sound Blasters are emulated : + SB v1.0 - The original. Limited to 22khz, and no auto-init DMA (can cause crackles sometimes). + SB v1.5 - Adds auto-init DMA + SB v2.0 - Upped to 41khz + SB Pro v1.0 - Stereo, with twin OPL2 chips. + SB Pro v2.0 - Stereo, with OPL 3 chip + SB 16 - 16 bit stereo + All are set to Address 220, IRQ 7 and DMA 1 (and High DMA 5). IRQ and DMA can be changed for the + SB16. + The relevant SET line for autoexec.bat is + SET BLASTER = A220 I7 D1 Tx - where Tx is T1 for SB v1.0, T3 for SB v2.0, T4 for SB Pro, + and T6 for SB16. + The SB16 software seems to work (including Windows drivers), but you must stick to these settings. + +Gravis Ultrasound - 32 voice sample playback. PCem's emulation of this is a bit preliminary : + - Only older ULTRASND setup programs work, ie text mode instead of graphics (3.xx?) + - MIDI playback occasionally goes wrong + - 16-bit playback only uses top 8 bits of samples + - Some games, eg later versions of Epic Pinball, have no music + - No stereo + - Some clicking in sound output + - Does work well in lots of stuff though, eg Worms, Pinball Fantasies, Zone 66 etc. + - Settings are hardwired to Address 240, IRQ 5, DMA 3. The relevant SET line for autoexec.bat is + SET ULTRASND=240,3,3,5,12 + This means unlike on a real board, you don't have to run a init program on bootup for sound + to work. You do need to install the ULTRAMID patches if you want MIDI. + + +Other stuff emulated : + +Serial mouse - A Microsoft compatible serial mouse on COM1. Compatible drivers are all over the + place for this. + +M24 mouse - I haven't seen a DOS mouse driver for this yet, but the regular scancode mode works, as + does the Windows 1.x driver. + +PC1512 mouse - The PC1512's perculiar quadrature mouse. You need Amstrad's actual driver for this + one. + +PS/2 mouse - A PS/2 mouse is emulated on the MegaPC and 386SX/25N model. As with serial, compatible + drivers are common. + +ATAPI CD-ROM - Works with OAKCDROM.SYS and Windows 9x. It can only work with actual CD-ROM drives + at the minute, so to use ISO images you need a virtual CD drive. + + +XTIDE : + +The XTIDE board is emulated for machines that don't natively support IDE hard discs. + +You will need to download the XTIDE BIOS seperately. Of the various versions, ide_at.bin and ide_xt.bin +should be placed in the ROMS directory. ide_xt is used on all XT models, and ide_at is used on the IBM AT +and Commodore PC30-III machines. + +The BIOS is available at : + +http://code.google.com/p/xtideuniversalbios/ + +v2.0.0 beta 1 is the only version that has been tested. + + +Notes : + +- The AT and AMI 286 both fail part of their self test. This doesn't really affect anything, + just puts an irritating message on the screen. + +- The time on the PC1512 clock is wrong. The date is correct, though since the PC1512's bios isn't + Y2k compliant, it thinks it's 1988. + +- The envelope system on the Gameblaster isn't emulated. The noise may not be right either. + +- Some of the more unusual VGA features are not emulated. I haven't found anything that uses them yet. + +- Windows 3.x should work okay in all modes now. + +- Windows 95/98 run, with the following caveats : + - Mouse is not detected. Strangely, it still works - except during setup, when it stops working at one point. + Sometimes running the 'Add New Hardware' wizard a couple of times will find it. + - The default Trident driver only allows 16 and 256 colour modes. There is an alternative driver which enables + high and true colour modes, but it doesn't work with DirectX. + - Setup sometimes crashes in the first stage (during file copying). This appears to be a side effect of the + bugs fixed making OS/2 work. Unfortunately I haven't been able to eliminate this issue. + +- OS/2 1.3 seems to work okay, but I haven't tested it very thoroughly. + +- Linux appears to work. fdlinux runs okay, but is relatively useless. SuSE 6.3 seemed mostly okay, but I only + had the first disc of 6 when testing, so I didn't get very far. + +- Windows NT does not work at all. + + +Software tested: + +I removed most of this, and only put the stuff I actually tested on this release. + +Booter games : + +King's Quest (Tandy) +King's Quest (CGA) + + +DOS stuff : + +MS-DOS 3.30 +PC-DOS 3.30 +PC-DOS 5.02 +MS-DOS 6.22 + - Most of the supplied software seems to work, eg Drivespace, Defrag, Scandisk, QBASIC + etc + +OS/2 v1.3 + +Windows 3.0 (CGA, Hercules, EGA, VGA) (real and standard modes only) +Windows 3.1 (VGA, SVGA) (standard & enhanced modes) +Windows 95 +Windows 98 + +Works for Windows 3.0 +Microsoft Arcade +Internet Explorer 4 + +Jill of the Jungle (CGA,EGA,VGA) +Tetris +Zak McKraken (CGA, Tandy) + +Brix (VGA) +Commander Keen 4 (EGA) +Duke Nukem 2 (VGA) +Heartlight (VGA) +Jetpack (VGA) + +Cascada - Cronologia (VGA) +EMF - Verses +Renaissance - Amnesia +Future Crew - Second Reality + +386/486 stuff : + +Jungle Strike (EMM386) +Dawn Patrol (EMM386) (use ET4000 driver) + +Doom +Doom 2 +Duke Nukem 3D +Heretic +Hexen +Jazz Jackrabbit +Rise of the Triad +Simcity 2000 +Terminal Velocity +Tyrian +Trasnport Tycoon +Transport Tycoon Deluxe +X-Com : Terror From The Deep +Theme Hospital - DOS and Windows versions +Zone 66 (don't use DOS 6.22) +Pro Pinball : Timeshock + +Actua Soccer +Grand Theft Auto +Jazz Jackrabbit 2 +Magic Carpet +Network Q RAC Rally +Quake +WinQuake +Quake 2 (SLOW - unsurprisingly) +Tomb Raider +Screamer +Screamer Rally +Virtual Pool (accelerated drivers work with both S3 and ET4000/W32) +Jedi Knight +Command & Conquer : Red Alert +Simcity 2000 + +ZSNES +Genecyst +Kgen98 diff --git a/roms/acer386/roms.txt b/roms/acer386/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/acer386/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ami286/roms.txt b/roms/ami286/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/ami286/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ami386/roms.txt b/roms/ami386/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/ami386/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ami486/roms.txt b/roms/ami486/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/ami486/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/cmdpc30/roms.txt b/roms/cmdpc30/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/cmdpc30/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/dells200/roms.txt b/roms/dells200/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/dells200/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/dtk/roms.txt b/roms/dtk/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/dtk/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/europc/roms.txt b/roms/europc/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/europc/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/genxt/roms.txt b/roms/genxt/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/genxt/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/hot-433/roms.txt b/roms/hot-433/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/hot-433/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ibmat/roms.txt b/roms/ibmat/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/ibmat/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ibmpc/roms.txt b/roms/ibmpc/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/ibmpc/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ibmxt/roms.txt b/roms/ibmxt/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/ibmxt/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/megapc/roms.txt b/roms/megapc/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/megapc/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/olivetti_m24/roms.txt b/roms/olivetti_m24/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/olivetti_m24/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc1512/roms.txt b/roms/pc1512/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/pc1512/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc1640/roms.txt b/roms/pc1640/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/pc1640/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc200/roms.txt b/roms/pc200/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/pc200/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc2086/roms.txt b/roms/pc2086/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/pc2086/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc3086/roms.txt b/roms/pc3086/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/pc3086/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/tandy/roms.txt b/roms/tandy/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/tandy/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/win486/roms.txt b/roms/win486/roms.txt new file mode 100644 index 00000000..4e9bbdc7 --- /dev/null +++ b/roms/win486/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/src/286.c b/src/286.c new file mode 100644 index 00000000..8fe4b58d --- /dev/null +++ b/src/286.c @@ -0,0 +1,3787 @@ +#include "ibm.h" +#include "x86.h" +#include "x86_flags.h" +#include "cpu.h" +#include "pit.h" +#include "keyboard.h" + +#define getword getword286 + +#define checkio_perm(port) if (!IOPLp) \ + { \ + x86gpf(NULL,0); \ + break; \ + } + +#undef readmemb +#undef writememb + +#define readmemb(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF)?readmemb386l(s,a):ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]) +#define writememb(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememb386l(s,a,v); else ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]=v +#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v + +extern int keywaiting; + +#define checklimit(a) + +/*#define checklimit(a) if (msw&1 && (a)) \ + { \ + pclog("Seg limit GPF at %04X:%04X\n",CS,pc); \ + pclog("%04X %04X %04X %i %04X %04X\n", ealimitw, ealimit, eaaddr, mod, _ds.limit, _ss.limit); \ + x86gpf(NULL,0); \ + break; \ + }*/ + +#define NOTRM if (!(msw & 1))\ + { \ + x86_int(6); \ + break; \ + } + + +static inline uint8_t geteab() +{ + if (mod==3) + return (rm&4)?regs[rm&3].b.h:regs[rm&3].b.l; +// cycles-=3; + return readmemb(easeg, eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod==3) + return regs[rm].w; +// cycles-=3; +// if (output==3) printf("GETEAW %04X:%08X\n",easeg,eaaddr); + return readmemw(easeg, eaaddr); +} + +static inline uint16_t geteaw2() +{ + if (mod==3) + return regs[rm].w; +// cycles-=2; +// printf("Getting addr from %04X:%04X %05X\n",easeg,eaaddr+2,easeg+eaaddr+2); + return readmemw(easeg,(eaaddr+2)&0xFFFF); +} + +static inline void seteab(uint8_t val) +{ + if (mod==3) + { + if (rm&4) regs[rm&3].b.h=val; + else regs[rm&3].b.l=val; + } + else + { +// cycles-=2; + writememb(easeg, eaaddr, val); + } +} + +static inline void seteaw(uint16_t val) +{ + if (mod==3) + regs[rm].w=val; + else + { +// cycles-=2; + writememw(easeg, eaaddr, val); +// writememb(easeg+eaaddr+1,val>>8); + } +} + +#undef fetchea + +#define fetchea() { rmdat=readmemb(cs, pc); pc++; \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal286(); } + +void fetcheal286() +{ + if (!mod && rm==6) { eaaddr=getword(); easeg=ds; ealimit=_ds.limit; ealimitw=_ds.limitw; } + else + { + switch (mod) + { + case 0: + eaaddr=0; + break; + case 1: + eaaddr=(uint16_t)(int8_t)readmemb(cs, pc); pc++; + break; + case 2: + eaaddr=getword(); + break; + } + eaaddr+=(*mod1add[0][rm])+(*mod1add[1][rm]); + easeg=*mod1seg[rm]; + if (mod1seg[rm] == &ss) { ealimit=_ss.limit; ealimitw=_ss.limitw; } + else { ealimit=_ds.limit; ealimitw=_ds.limitw; } +// if (output) pclog("Limit %08X %08X %08X %08X\n",ealimit,_ds.limit,mod1seg[rm],&ss); + } + eaaddr&=0xFFFF; +} + +void rep286(int fv) +{ + uint8_t temp; + uint32_t c;//=CX; + uint8_t temp2; + uint16_t tempw,tempw2,tempw3,of=flags; + uint32_t ipc=oldpc;//pc-1; + int changeds=0; + uint32_t oldds; + uint32_t templ,templ2; + int tempz; + int tempi; +// if (output) pclog("REP32 %04X %04X ",use32,rep32); + startrep: + temp=opcode2=readmemb(cs,pc); pc++; +// if (firstrepcycle && temp==0xA5) pclog("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (output) pclog("REP %02X %04X\n",temp,ipc); + c = CX; +/* if (rep32 && (msw&1)) + { + if (temp!=0x67 && temp!=0x66 && (rep32|temp)!=0x1AB && (rep32|temp)!=0x3AB) pclog("32-bit REP %03X %08X %04X:%06X\n",temp|rep32,c,CS,pc); + }*/ + switch (temp) + { + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + rds=ES; + changeds=1; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + rds=CS; + changeds=1; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + rds=SS; + changeds=1; + goto startrep; + break; + case 0x3E: /*DS:*/ + oldds=ds; + ds=ds; + changeds=1; + goto startrep; + break; + case 0x6C: /*REP INSB*/ + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,DI,temp2); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x6D: /*REP INSW*/ + if (c>0) + { + tempw=inw(DX); + writememw(es,DI,tempw); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds,SI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x6F: /*REP OUTSW*/ + if (c>0) + { + tempw=readmemw(ds,SI); + if (abrt) break; +// pclog("OUTSW %04X -> %04X\n",SI,tempw); + outw(DX,tempw); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + if (c>0) + { + temp2=readmemb(ds,SI); if (abrt) break; + writememb(es,DI,temp2); if (abrt) break; +// if (output==3) pclog("MOVSB %08X:%04X -> %08X:%04X %02X\n",ds,SI,es,DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA5: /*REP MOVSW*/ + if (c>0) + { + tempw=readmemw(ds,SI); if (abrt) break; + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp=readmemb(ds,SI); + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + + case 0xAA: /*REP STOSB*/ + if (c>0) + { + writememb(es,DI,AL); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + if (c>0) + { + writememw(es,DI,AX); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAC: /*REP LODSB*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL=readmemb(ds,SI); + if (abrt) break; + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX=readmemw(ds,SI); + if (abrt) break; + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + setsub8(AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + + default: + pc=ipc; + cycles-=20; + x86illegal(); + pclog("Bad REP %02X\n", temp); + //dumpregs(); + //exit(-1); + } + CX=c; + if (changeds) ds=oldds; +// if (output) pclog("%03X %03X\n",rep32,use32); +} + +void x86illegal() +{ + uint16_t addr; + pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); +// if (output) +// { +// dumpregs(); +// exit(-1); +// } + if (msw&1) + { + pmodeint(6,0); + } + else + { + if (ssegs) { ss=oldss; _ss.limit=oldsslimit; _ss.limitw=oldsslimitw; } + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + addr=6<<2; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + cycles-=70; +} +//#endif +//#if 0 + +static inline uint8_t getbytef() +{ + uint8_t temp = readmemb(cs, pc); pc++; + return temp; +} +static inline uint16_t getwordf() +{ + uint16_t tempw = readmemw(cs, pc); pc+=2; + return tempw; +} + +/*Conditional jump timing is WRONG*/ +void exec286(int cycs) +{ + uint8_t temp,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + volatile int tempws, tempws2; + uint32_t templ, templ2, templ3; + int8_t temps; + int16_t temps16; + int c;//,cycdiff; + int tempi; + FILE *f; + int trap; + int cyclast; +// printf("Run 286! %i %i\n",cycles,cycs); + cycles+=cycs; +// i86_Execute(cycs); +// return; + while (cycles>0) + { + cyclast = cycdiff; + cycdiff=cycles; + oldcs=CS; + oldpc=pc; + oldcpl=CPL; + + opcodestart: + opcode = readmemb(cs, pc); + if (abrt) goto opcodeend; + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + + if (output && /*cs<0xF0000 && */!ssegs)//opcode!=0x26 && opcode!=0x36 && opcode!=0x2E && opcode!=0x3E) + { + if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) + { + if (!skipnextprint) printf("%04X(%06X):%04X : %04X %04X %04X %04X %04X(%06X) %04X(%06X) %04X(%06X) %04X(%06X) %04X %04X %04X %04X %02X %04X %04X %04X %04X %04X %08X %i %i %i %08X %i %f %f\n",CS,cs,pc,AX,BX,CX,DX,CS,cs,DS,ds,ES,es,SS,ss,DI,SI,BP,SP,opcode,flags,msw,ram[0x7c3e],ram[(0x7c3e)+3],ram[0x7c40],_ds.limitw,keybsenddelay,keywaiting,ins, _ss.limit, cyclast, pit.c[1], PITCONST); + skipnextprint=0; +// ins++; +/* if (ins==50000) + { + dumpregs(); + exit(-1); + }*/ +/* if (ins==500000) + { + dumpregs(); + exit(-1); + }*/ + } + } +//#endif + pc++; + inhlt=0; +// if (ins==500000) { dumpregs(); exit(0); }*/ + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); + //if (!rmdat && output) pc--; +/* if (!rmdat && output) + { + pclog("Crashed\n"); +// clear_keybuf(); +// readkey(); + dumpregs(); + exit(-1); + }*/ + if (mod == 3) + { + temp = getr8(rm); + temp2 = getr8(reg); + setadd8(temp, temp2); + setr8(rm, temp + temp2); + cycles -= 2; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp + temp2); if (abrt) break; + setadd8(temp, temp2); + cycles -= 7; + } + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + if (mod == 3) + { + setadd16(regs[rm].w, regs[reg].w); + regs[rm].w += regs[reg].w; + cycles -= 2; + } + else + { + tempw = geteaw(); if (abrt) break; + seteaw(tempw + regs[reg].w); if (abrt) break; + setadd16(tempw, regs[reg].w); + cycles -= 7; + } + break; + case 0x02: /*ADD reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + setadd8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x03: /*ADD reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setadd16(regs[reg].w,tempw); + regs[reg].w+=tempw; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x04: /*ADD AL,#8*/ + temp=getbytef(); + setadd8(AL,temp); + AL+=temp; + cycles -= 3; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getwordf(); + setadd16(AX,tempw); + AX+=tempw; + cycles -= 3; + break; + + case 0x06: /*PUSH ES*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); if (abrt) break; + SP-=2; + cycles-=3; + break; + case 0x07: + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_es); if (abrt) break; + SP+=2; + cycles -= (msw & 1) ? 20 : 5; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm) | getr8(reg); + setr8(rm, temp); + setznp8(temp); + cycles -= 2; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp | temp2); if (abrt) break; + setznp8(temp | temp2); + cycles -= 7; + } + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].w |= regs[reg].w; + setznp16(regs[rm].w); + cycles -= 2; + } + else + { + tempw = geteaw() | regs[reg].w; if (abrt) break; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= 7; + } + break; + case 0x0A: /*OR reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp|=getr8(reg); + setznp8(temp); + setr8(reg,temp); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw|=regs[reg].w; + setznp16(tempw); + regs[reg].w=tempw; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x0C: /*OR AL,#8*/ + AL|=getbytef(); + setznp8(AL); + cycles -= 2; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getwordf(); + setznp16(AX); + cycles -= 2; + break; + + case 0x0E: /*PUSH CS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); if (abrt) break; + SP-=2; + cycles-=3; + break; + + case 0x0F: + temp = readmemb(cs, pc); pc++; + opcode2 = temp; +// if (temp>5 && temp!=0x82 && temp!=0x85 && temp!=0x84 && temp!=0x87 && temp!=0x8D && temp!=0x8F && temp!=0x8C && temp!=0x20 && temp!=0x22) pclog("Using magic 386 0F instruction %02X!\n",temp); + switch (temp) + { + case 0: + fetchea(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*SLDT*/ + NOTRM + seteaw(ldt.seg); + cycles -= (mod == 3) ? 3 : 2; + break; + case 0x08: /*STR*/ + NOTRM + seteaw(tr.seg); + cycles -= (mod == 3) ? 3 : 2; + break; + case 0x10: /*LLDT*/ + if (CPL && (msw & 1)) + { + pclog("Invalid LLDT!\n"); + x86gpf(NULL,0); + break; + } + NOTRM + ldt.seg=geteaw(); +// pclog("Load LDT %04X ",ldt.seg); + templ=(ldt.seg&~7)+gdt.base; +// pclog("%06X ",gdt.base); + templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); + templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + if (abrt) break; + ldt.limit=templ3; + ldt.access=readmemb(0,templ+6); + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=templ2; +// /*if (output==3) */pclog("LLDT %04X %08X %04X %08X %08X\n",ldt.seg,ldt.base,ldt.limit,readmeml(0,templ),readmeml(0,templ+4)); + + cycles -= (mod == 3) ? 17 : 19; + break; + case 0x18: /*LTR*/ + if (CPL && (msw & 1)) + { + pclog("Invalid LTR!\n"); + x86gpf(NULL,0); + break; + } + NOTRM + tr.seg=geteaw(); + templ=(tr.seg&~7)+gdt.base; + templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); + templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + temp=readmemb(0,templ+5); + if (abrt) break; + tr.limit=templ3; + tr.access=readmemb(0,templ+6); + if (readmemb(0,templ+6)&0x80) + { + tr.limit<<=12; + tr.limit|=0xFFF; + } + tr.base=templ2; +// pclog("TR base = %08X\n",templ2); + tr.access=temp; + cycles -= (mod == 3) ? 17 : 19; + break; + case 0x20: /*VERR*/ + NOTRM + tempw=geteaw(); if (abrt) break; + flags&=~Z_FLAG; + if (!(tempw&0xFFFC)) break; /*Null selector*/ + cpl_override=1; + tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); + tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); + cpl_override=0; + if (abrt) break; + if (!(tempw2&0x1000)) tempi=0; + if ((tempw2&0xC00)!=0xC00) /*Exclude conforming code segments*/ + { + tempw3=(tempw2>>13)&3; /*Check permissions*/ + if (tempw3>13)&3; /*Check permissions*/ + if (tempw3> 16) | 0xFF00); + cycles -= 11; + break; + case 0x08: /*SIDT*/ + seteaw(idt.limit); + writememw(easeg, eaaddr + 2, idt.base); + writememw(easeg, eaaddr + 4, (idt.base >> 16) | 0xFF00); + cycles -= 12; + break; + case 0x10: /*LGDT*/ + if (CPL && (msw & 1)) + { + pclog("Invalid LGDT!\n"); + x86gpf(NULL,0); + break; + } + tempw=geteaw(); + templ=readmeml(0,easeg+eaaddr+2)&0xFFFFFF; + if (abrt) break; + gdt.limit=tempw; + gdt.base=templ; + cycles-=11; + break; + case 0x18: /*LIDT*/ + if (CPL && (msw & 1)) + { + pclog("Invalid LIDT!\n"); + x86gpf(NULL,0); + break; + } + tempw=geteaw(); + templ=readmeml(0,easeg+eaaddr+2)&0xFFFFFF; + if (abrt) break; + idt.limit=tempw; + idt.base=templ; + cycles-=12; + break; + + case 0x20: /*SMSW*/ + if (is486) seteaw(msw); + else seteaw(msw|0xFF00); +// pclog("SMSW %04X:%04X %04X %i\n",CS,pc,msw,is486); + cycles -= (mod == 3) ? 2 : 3; + break; + case 0x30: /*LMSW*/ + if (CPL && (msw&1)) + { + pclog("LMSW - ring not zero!\n"); + x86gpf(NULL,0); + break; + } + tempw=geteaw(); if (abrt) break; + if (msw&1) tempw|=1; + msw=tempw; + cycles -= (mod == 3) ? 3 : 6; + pclog("LMSW %04X %08X %04X:%04X\n", msw, cs, CS, pc); + break; + + default: + pclog("Bad 0F 01 opcode %02X\n",rmdat&0x38); + pc-=3; + x86illegal(); + break; +// dumpregs(); +// exit(-1); + } + break; + + case 2: /*LAR*/ + NOTRM + fetchea(); + tempw=geteaw(); if (abrt) break; +// pclog("LAR seg %04X\n",tempw); + + if (!(tempw&0xFFFC)) { flags&=~Z_FLAG; break; } /*Null selector*/ + tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); + if (tempi) + { + cpl_override=1; + tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); + cpl_override=0; + if (abrt) break; + } + flags&=~Z_FLAG; +// pclog("tempw2 %04X %i %04X %04X\n",tempw2,tempi,ldt.limit,gdt.limit); + if ((tempw2&0x1F00)==0x000) tempi=0; + if ((tempw2&0x1F00)==0x800) tempi=0; + if ((tempw2&0x1F00)==0xA00) tempi=0; + if ((tempw2&0x1F00)==0xD00) tempi=0; + if ((tempw2&0x1C00)<0x1C00) /*Exclude conforming code segments*/ + { + tempw3=(tempw2>>13)&3; + if (tempw3>13)&3; + if (tempw3 9)) + { + tempi = ((uint16_t)AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags |= tempw; + cycles -= 3; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm); + temp2 = getr8(reg); + setsub8(temp, temp2); + setr8(rm, temp - temp2); + cycles -= 2; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp - temp2); if (abrt) break; + setsub8(temp, temp2); + cycles -= 7; + } + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + if (mod == 3) + { + setsub16(regs[rm].w, regs[reg].w); + regs[rm].w -= regs[reg].w; + cycles -= 2; + } + else + { + tempw = geteaw(); if (abrt) break; + seteaw(tempw - regs[reg].w); if (abrt) break; + setsub16(tempw, regs[reg].w); + cycles -= 7; + } + break; + case 0x2A: /*SUB reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + setsub8(getr8(reg),temp); + setr8(reg,getr8(reg)-temp); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x2B: /*SUB reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setsub16(regs[reg].w,tempw); + regs[reg].w-=tempw; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x2C: /*SUB AL,#8*/ + temp=getbytef(); + setsub8(AL,temp); + AL-=temp; + cycles -= 3; + break; + case 0x2D: /*SUB AX,#16*/ + tempw=getwordf(); + setsub16(AX,tempw); + AX-=tempw; + cycles -= 3; + break; + + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + rds=CS; + ssegs=2; + cycles-=2; + goto opcodestart; + + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags |= tempw; + cycles -= 3; + break; + + case 0x30: /*XOR 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm) ^ getr8(reg); + setr8(rm, temp); + setznp8(temp); + cycles -= 2; + } + else + { + temp = geteab(); if (abrt) break; + temp ^= getr8(reg); + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= 7; + } + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].w ^= regs[reg].w; + setznp16(regs[rm].w); + cycles -= 2; + } + else + { + tempw = geteaw() ^ regs[reg].w; if (abrt) break; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= 7; + } + break; + case 0x32: /*XOR reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp^=getr8(reg); + setznp8(temp); + setr8(reg,temp); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x33: /*XOR reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw^=regs[reg].w; + setznp16(tempw); + regs[reg].w=tempw; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x34: /*XOR AL,#8*/ + AL^=getbytef(); + setznp8(AL); + cycles -= 3; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getwordf(); + setznp16(AX); + cycles -= 3; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + rds=SS; + ssegs=2; + cycles-=2; + goto opcodestart; +// break; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles -= 3; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); if (abrt) break; + setsub8(temp,getr8(reg)); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); if (abrt) break; +// if (output) pclog("CMP %04X %04X\n",tempw,regs[reg].w); + setsub16(tempw,regs[reg].w); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x3A: /*CMP reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; +// if (output) pclog("CMP %02X-%02X\n",getr8(reg),temp); + setsub8(getr8(reg),temp); + cycles -= (mod == 3) ? 2 : 6; + break; + case 0x3B: /*CMP reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setsub16(regs[reg].w,tempw); + cycles -= (mod == 3) ? 2 : 6; + break; + case 0x3C: /*CMP AL,#8*/ + temp=getbytef(); + setsub8(AL,temp); + cycles -= 3; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getwordf(); + setsub16(AX,tempw); + cycles -= 3; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + ssegs=2; + cycles-=2; + goto opcodestart; +// break; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles -= 3; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(regs[opcode&7].w,1); + regs[opcode&7].w++; + cycles -= 2; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(regs[opcode&7].w,1); + regs[opcode&7].w--; + cycles -= 2; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,regs[opcode&7].w); if (abrt) break; + SP-=2; + cycles -= 3; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (ssegs) ss=oldss; + SP+=2; + tempw=readmemw(ss,(SP-2)&0xFFFF); if (abrt) { SP-=2; break; } + regs[opcode&7].w=tempw; + cycles -= 5; + break; + + case 0x60: /*PUSHA*/ + writememw(ss,((SP-2)&0xFFFF),AX); + writememw(ss,((SP-4)&0xFFFF),CX); + writememw(ss,((SP-6)&0xFFFF),DX); + writememw(ss,((SP-8)&0xFFFF),BX); + writememw(ss,((SP-10)&0xFFFF),SP); + writememw(ss,((SP-12)&0xFFFF),BP); + writememw(ss,((SP-14)&0xFFFF),SI); + writememw(ss,((SP-16)&0xFFFF),DI); + if (!abrt) SP-=16; + cycles -= 17; + break; + case 0x61: /*POPA*/ + DI=readmemw(ss,((SP)&0xFFFF)); if (abrt) break; + SI=readmemw(ss,((SP+2)&0xFFFF)); if (abrt) break; + BP=readmemw(ss,((SP+4)&0xFFFF)); if (abrt) break; + BX=readmemw(ss,((SP+8)&0xFFFF)); if (abrt) break; + DX=readmemw(ss,((SP+10)&0xFFFF)); if (abrt) break; + CX=readmemw(ss,((SP+12)&0xFFFF)); if (abrt) break; + AX=readmemw(ss,((SP+14)&0xFFFF)); if (abrt) break; + SP+=16; + cycles -= 19; + break; + + case 0x62: /*BOUND*/ + fetchea(); + tempw=geteaw(); + tempw2=readmemw(easeg,eaaddr+2); if (abrt) break; + if (((int16_t)regs[reg].w<(int16_t)tempw) || ((int16_t)regs[reg].w>(int16_t)tempw2)) + { + x86_int(5); + } + cycles -= 13; + break; + + case 0x63: /*ARPL*/ + NOTRM + fetchea(); + tempw=geteaw(); if (abrt) break; + if ((tempw&3)<(regs[reg].w&3)) + { + tempw=(tempw&0xFFFC)|(regs[reg].w&3); + seteaw(tempw); if (abrt) break; + flags|=Z_FLAG; + } + else + flags&=~Z_FLAG; + cycles -= (mod == 3) ? 10 : 11; + break; + + case 0x68: /*PUSH #w*/ + tempw=getword(); + writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; + SP-=2; + cycles -= 3; + break; + case 0x69: /*IMUL r16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=getword(); if (abrt) break; + templ=((int)(int16_t)tempw)*((int)(int16_t)tempw2); + if ((templ>>16)!=0 && (templ>>16)!=0xFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + regs[reg].w=templ&0xFFFF; + cycles -= (mod == 3) ? 21 : 24; + break; + case 0x6A: /*PUSH #eb*/ + tempw=readmemb(cs,pc); pc++; + if (tempw&0x80) tempw|=0xFF00; + writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; + SP-=2; + cycles -= 3; + break; + case 0x6B: /*IMUL r8*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=readmemb(cs,pc); pc++; if (abrt) break; + if (tempw2&0x80) tempw2|=0xFF00; + templ=((int)(int16_t)tempw)*((int)(int16_t)tempw2); + if ((templ>>16)!=0 && ((templ>>16)&0xFFFF)!=0xFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + regs[reg].w=templ&0xFFFF; + cycles -= (mod == 3) ? 21 : 24; + break; + + case 0x6C: /*INSB*/ + checkio_perm(DX); + temp=inb(DX); + writememb(es,DI,temp); if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + cycles -= 5; + break; + case 0x6D: /*INSW*/ + checkio_perm(DX); + checkio_perm(DX+1); + tempw=inw(DX); + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles -= 5; + break; + case 0x6E: /*OUTSB*/ + temp=readmemb(ds,SI); if (abrt) break; + checkio_perm(DX); + if (flags&D_FLAG) SI--; + else SI++; + outb(DX,temp); + cycles -= 5; + break; + case 0x6F: /*OUTSW*/ + tempw=readmemw(ds,SI); if (abrt) break; + checkio_perm(DX); + checkio_perm(DX+1); + if (flags&D_FLAG) SI-=2; + else SI+=2; + outw(DX,tempw); +// outb(DX+1,tempw>>8); + cycles -= 5; + break; + + case 0x70: /*JO*/ + offset=(int8_t)getbytef(); + if (flags&V_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x71: /*JNO*/ + offset=(int8_t)getbytef(); + if (!(flags&V_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x72: /*JB*/ + offset=(int8_t)getbytef(); + if (flags&C_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x73: /*JNB*/ + offset=(int8_t)getbytef(); + if (!(flags&C_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x74: /*JZ*/ + offset=(int8_t)getbytef(); + if (flags&Z_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x75: /*JNZ*/ + offset=(int8_t)getbytef(); + if (!(flags&Z_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x76: /*JBE*/ + offset=(int8_t)getbytef(); + if (flags&(C_FLAG|Z_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x77: /*JNBE*/ + offset=(int8_t)getbytef(); + if (!(flags&(C_FLAG|Z_FLAG))) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x78: /*JS*/ + offset=(int8_t)getbytef(); + if (flags&N_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x79: /*JNS*/ + offset=(int8_t)getbytef(); + if (!(flags&N_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x7A: /*JP*/ + offset=(int8_t)getbytef(); + if (flags&P_FLAG) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x7B: /*JNP*/ + offset=(int8_t)getbytef(); + if (!(flags&P_FLAG)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x7C: /*JL*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x7D: /*JNL*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x7E: /*JLE*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + case 0x7F: /*JNLE*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { pc += offset; cycles -= 4; cycles -= 2; } + cycles -= 3; + break; + + + case 0x80: + case 0x82: + fetchea(); + temp=geteab(); if (abrt) break; + temp2=readmemb(cs,pc); pc++; if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + seteab(temp+temp2); if (abrt) break; + setadd8(temp,temp2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x10: /*ADC b,#8*/ + seteab(temp+temp2+tempc); if (abrt) break; + setadc8(temp,temp2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x18: /*SBB b,#8*/ + seteab(temp-(temp2+tempc)); if (abrt) break; + setsbc8(temp,temp2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x28: /*SUB b,#8*/ + seteab(temp-temp2); if (abrt) break; + setsub8(temp,temp2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles -= (mod == 3) ? 3 : 6; + break; + +// default: +// pclog("Bad 80 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=getword(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + seteaw(tempw+tempw2); if (abrt) break; + setadd16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x10: /*ADC w,#16*/ + seteaw(tempw+tempw2+tempc); if (abrt) break; + setadc16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x18: /*SBB w,#16*/ + seteaw(tempw-(tempw2+tempc)); if (abrt) break; + setsbc16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x28: /*SUB w,#16*/ + seteaw(tempw-tempw2); if (abrt) break; + setsub16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x38: /*CMP w,#16*/ +// pclog("CMP %04X %04X\n", tempw, tempw2); + setsub16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 6; + break; + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=readmemb(cs,pc); pc++; if (abrt) break; + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + seteaw(tempw+tempw2); if (abrt) break; + setadd16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x10: /*ADC w,#8*/ + seteaw(tempw+tempw2+tempc); if (abrt) break; + setadc16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x18: /*SBB w,#8*/ + seteaw(tempw-(tempw2+tempc)); if (abrt) break; + setsbc16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x28: /*SUB w,#8*/ + seteaw(tempw-tempw2); if (abrt) break; + setsub16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? 3 : 7; + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles -= (mod == 3) ? 3 : 6; + break; + +// default: +// pclog("Bad 83 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp2=getr8(reg); + setznp8(temp&temp2); + cycles -= (mod == 3) ? 2 : 6; + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=regs[reg].w; + setznp16(tempw&tempw2); + cycles -= (mod == 3) ? 2 : 6; + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); if (abrt) break; + seteab(getr8(reg)); if (abrt) break; + setr8(reg,temp); + cycles -= (mod == 3) ? 3 : 5; + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + seteaw(regs[reg].w); if (abrt) break; + regs[reg].w=tempw; + cycles -= (mod == 3) ? 3 : 5; + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(reg)); + cycles -= (mod == 3) ? 2 : 3; + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(regs[reg].w); + cycles -= (mod == 3) ? 2 : 3; + break; + case 0x8A: /*MOV reg,b*/ + fetchea(); + temp=geteab(); if (abrt) break; + setr8(reg,temp); + cycles -= (mod == 3) ? 5 : 3; + break; + case 0x8B: /*MOV reg,w*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + regs[reg].w=tempw; + cycles -= (mod == 3) ? 5 : 3; + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles -= (mod == 3) ? 2 : 3; + break; + + case 0x8D: /*LEA*/ + fetchea(); + regs[reg].w=eaaddr; + cycles -= 3; + break; + + case 0x8E: /*MOV sreg,w*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); if (abrt) break; + loadseg(tempw,&_es); + break; + case 0x18: /*DS*/ + tempw=geteaw(); if (abrt) break; + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + break; + case 0x10: /*SS*/ +// if (output==3) pclog("geteaw\n"); + tempw=geteaw(); if (abrt) break; +// if (output==3) pclog("loadseg\n"); + loadseg(tempw,&_ss); +// if (output==3) pclog("done\n"); + if (ssegs) oldss=ss; + skipnextprint=1; + noint=1; + break; + } + if (msw & 1) cycles -= (mod == 3) ? 17 : 19; + else cycles -= (mod == 3) ? 2 : 5; + break; + + case 0x8F: /*POPW*/ + if (ssegs) templ2=oldss; + else templ2=ss; + tempw=readmemw(templ2,SP); if (abrt) break; + SP+=2; + fetchea(); + if (ssegs) ss=oldss; + seteaw(tempw); + if (abrt) SP-=2; + cycles -= 5; + break; + + case 0x90: /*NOP*/ + cycles -= 3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=regs[opcode&7].w; + regs[opcode&7].w=tempw; + cycles -= 3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles -= 2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles -= 2; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); if (abrt) break; + tempw3 = CS; + templ2 = pc; + if (ssegs) ss=oldss; + oxpc=pc; + pc=tempw; + optype=CALL; + if (msw&1) loadcscall(tempw2); + else loadcs(tempw2); + optype=0; + if (abrt) break; + oldss=ss; + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,templ2); if (abrt) break; + SP-=4; + cycles -= (msw & 1) ? 26 : 13; + break; + case 0x9B: /*WAIT*/ + cycles -= 3; + break; + case 0x9C: /*PUSHF*/ + if (ssegs) ss=oldss; + if (msw & 1) { writememw(ss, ((SP-2)&0xFFFF), flags & 0x7fff); } + else { writememw(ss, ((SP-2)&0xFFFF), flags & 0x0fff); } + if (abrt) break; + SP-=2; + cycles -= 3; + break; + case 0x9D: /*POPF*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); if (abrt) break; + SP+=2; + if (!(CPL) || !(msw&1)) flags=(tempw&0xFFD5)|2; + else if (IOPLp) flags=(flags&0x3000)|(tempw&0x4FD5)|2; + else flags=(flags&0x7200)|(tempw&0x0DD5)|2; + pclog("POPF %04X %04X %04X:%04X\n", tempw, flags, CS, pc); + cycles -= 5; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|(AH&0xD5)|2; + cycles -= 2; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles -= 2; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); if (abrt) break; + temp=readmemb(ds,addr); if (abrt) break; + AL=temp; + cycles -= 5; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); if (abrt) break; + tempw=readmemw(ds,addr); if (abrt) break; + AX=tempw; + cycles -= 5; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); if (abrt) break; + writememb(ds,addr,AL); + cycles -= 3; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); if (abrt) break; + writememw(ds,addr,AX); + cycles -= 3; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds,SI); if (abrt) break; + writememb(es,DI,temp); if (abrt) break; + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles -= 5; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); if (abrt) break; + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles -= 5; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds,SI); + temp2=readmemb(es,DI); + if (abrt) break; + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles -= 8; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (abrt) break; + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles -= 8; + break; + case 0xA8: /*TEST AL,#8*/ + temp=getbytef(); + setznp8(AL&temp); + cycles -= 3; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getwordf(); + setznp16(AX&tempw); + cycles -= 3; + break; + case 0xAA: /*STOSB*/ + writememb(es,DI,AL); if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + cycles -= 3; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles -= 3; + break; + case 0xAC: /*LODSB*/ + temp=readmemb(ds,SI); + if (abrt) break; + AL=temp; + if (flags&D_FLAG) SI--; + else SI++; + cycles -= 5; + break; + case 0xAD: /*LODSW*/ + tempw=readmemw(ds,SI); + if (abrt) break; + AX=tempw; +// if (output) pclog("Load from %05X:%04X\n",ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles -= 5; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es,DI); + if (abrt) break; + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles -= 7; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + if (abrt) break; + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles -= 7; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=getbytef(); + cycles -= 2; + break; + case 0xB1: /*MOV CL,#8*/ + CL=getbytef(); + cycles -= 2; + break; + case 0xB2: /*MOV DL,#8*/ + DL=getbytef(); + cycles -= 2; + break; + case 0xB3: /*MOV BL,#8*/ + BL=getbytef(); + cycles -= 2; + break; + case 0xB4: /*MOV AH,#8*/ + AH=getbytef(); + cycles -= 2; + break; + case 0xB5: /*MOV CH,#8*/ + CH=getbytef(); + cycles -= 2; + break; + case 0xB6: /*MOV DH,#8*/ + DH=getbytef(); + cycles -= 2; + break; + case 0xB7: /*MOV BH,#8*/ + BH=getbytef(); + cycles -= 2; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + regs[opcode&7].w=getwordf(); + cycles -= 2; + break; + + case 0xC0: + fetchea(); + c=readmemb(cs,pc); pc++; + temp=geteab(); if (abrt) break; + c&=31; + if (!c) break; + cycles -= c; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x10: /*RCL b,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?1:0; + temp2=temp&0x80; + temp=(temp<<1)|tempc; + c--; + if (is486) cycles--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x18: /*RCR b,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?0x80:0; + temp2=temp&1; + temp=(temp>>1)|tempc; + c--; + if (is486) cycles--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x20: case 0x30: /*SHL b,CL*/ + seteab(temp<>c); if (abrt) break; + setznp8(temp>>c); + if ((temp>>(c-1))&1) flags|=C_FLAG; + if (c==1 && temp&0x80) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x38: /*SAR b,CL*/ + tempc=((temp>>(c-1))&1); + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + setznp8(temp); + if (tempc) flags|=C_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + +// default: +// pclog("Bad C0 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xC1: + fetchea(); + c=readmemb(cs,pc)&31; pc++; + tempw=geteaw(); if (abrt) break; + if (!c) break; + cycles -= c; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempw2) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x10: /*RCL w,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?1:0; + temp2=(tempw>>15); + tempw=(tempw<<1)|tempc; + c--; + if (is486) cycles--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x18: /*RCR w,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?0x8000:0; + temp2=tempw&1; + tempw=(tempw>>1)|tempc; + c--; + if (is486) cycles--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + seteaw(tempw<>c); if (abrt) break; + setznp16(tempw>>c); + if ((tempw>>(c-1))&1) flags|=C_FLAG; + if (c==1 && tempw&0x8000) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + tempc=(tempw>>(c-1))&1; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + +// default: +// pclog("Bad C1 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xC2: /*RET*/ + tempw=getword(); + if (ssegs) ss=oldss; + tempw2=readmemw(ss,SP); if (abrt) break; + SP+=2+tempw; + pc=tempw2; + cycles -= 11; + break; + case 0xC3: /*RET*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); if (abrt) break; + SP+=2; + pc=tempw; + cycles -= 11; + break; + case 0xC4: /*LES*/ + fetchea(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,eaaddr+2); if (abrt) break; + loadseg(tempw,&_es); if (abrt) break; + regs[reg].w=tempw2; + cycles -= 7; + break; + case 0xC5: /*LDS*/ + fetchea(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,eaaddr+2); if (abrt) break; + loadseg(tempw,&_ds); if (abrt) break; + if (ssegs) oldds=ds; + regs[reg].w=tempw2; + cycles -= 7; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=readmemb(cs,pc); pc++; if (abrt) break; + seteab(temp); + cycles -= (mod == 3) ? 2 : 3; + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); if (abrt) break; + seteaw(tempw); + cycles -= (mod == 3) ? 2 : 3; + break; + case 0xC8: /*ENTER*/ + tempw2=getword(); + tempi=readmemb(cs,pc); pc++; + templ=BP; + writememw(ss,((SP-2)&0xFFFF),BP); if (abrt) break; + SP-=2; + templ2=SP; + if (tempi>0) + { + while (--tempi) + { + BP-=2; + tempw=readmemw(ss,BP); + if (abrt) { SP=templ2; BP=templ; break; } + writememw(ss,((SP-2)&0xFFFF),tempw); SP-=2; + if (abrt) { SP=templ2; BP=templ; break; } + cycles-=(is486)?3:4; + } + writememw(ss,((SP-2)&0xFFFF),templ2); SP-=2; + if (abrt) { SP=templ2; BP=templ; break; } + cycles -= 4; + } + BP = templ2; + SP-=tempw2; + cycles -= 12; + break; + case 0xC9: /*LEAVE*/ + templ=SP; + SP=BP; + tempw=readmemw(ss,SP); SP+=2; + if (abrt) { SP=templ; break; } + BP=tempw; + cycles -= 5; + break; + case 0xCA: /*RETF*/ + tempw=getword(); + if (msw&1) + { + pmoderetf(0,tempw); + break; + } + tempw2=CPL; + if (ssegs) ss=oldss; + oxpc=pc; + pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + if (abrt) break; + SP+=4+tempw; + cycles -= 15; + break; + case 0xCB: /*RETF*/ + if (msw&1) + { + pmoderetf(0,0); + break; + } + tempw2=CPL; + if (ssegs) ss=oldss; + oxpc=pc; + pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + if (abrt) break; + SP+=4; + cycles -= 15; + break; + case 0xCC: /*INT 3*/ + if (msw&1) + { + pmodeint(3,1); + cycles -= 40; + } + else + { + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + addr=3<<2; +// flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= 23; + } + break; + case 0xCD: /*INT*/ + lastpc=pc; + lastcs=CS; + temp=readmemb(cs,pc); pc++; + intrt: + pclog("INT %02X %04X %04X %04X %04X %04X:%04X\n", temp, AX, BX, CX, DX, CS, pc); + if (1) + { + if (msw&1) + { +// pclog("PMODE int %02X %04X at %04X:%04X ",temp,AX,CS,pc); + pmodeint(temp,1); + cycles -= 40; +// pclog("to %04X:%04X\n",CS,pc); + } + else + { + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + addr=temp<<2; +// flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; +// pclog("%04X:%04X : ",CS,pc); + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= 23; +// pclog("INT %02X - %04X %04X:%04X\n",temp,addr,CS,pc); + } + } + break; + case 0xCE: /*INTO*/ + if (flags&V_FLAG) + { + temp=4; + goto intrt; +/* pclog("INTO interrupt!\n"); + dumpregs(); + exit(-1);*/ + } + cycles-=3; + break; + case 0xCF: /*IRET*/ + if (ssegs) ss=oldss; + if (msw&1) + { + optype=IRET; + pmodeiret(0); + optype=0; + } + else + { + tempw=CS; + tempw2=pc; + inint=0; + oxpc=pc; + pc=readmemw(ss,SP); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=(readmemw(ss,((SP+4)&0xFFFF))&0x0FD5)|2; + SP+=6; + } + cycles -= 17; + break; + + case 0xD0: + fetchea(); + temp=geteab(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + seteab((temp<<1)|((temp&0x80)?1:0)); if (abrt) break; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x08: /*ROR b,1*/ + seteab((temp>>1)|((temp&1)?0x80:0)); if (abrt) break; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + seteab((temp<<1)|temp2); if (abrt) break; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + seteab((temp>>1)|(temp2?0x80:0)); if (abrt) break; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x20: case 0x30: /*SHL b,1*/ + seteab(temp<<1); if (abrt) break; + setznp8(temp<<1); + if (temp&0x80) flags|=C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x28: /*SHR b,1*/ + seteab(temp>>1); if (abrt) break; + setznp8(temp>>1); + if (temp&1) flags|=C_FLAG; + if (temp&0x80) flags|=V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x38: /*SAR b,1*/ + seteab((temp>>1)|(temp&0x80)); if (abrt) break; + setznp8((temp>>1)|(temp&0x80)); + if (temp&1) flags|=C_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + +// default: +// pclog("Bad D0 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + case 0xD1: + fetchea(); + tempw=geteaw(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + seteaw((tempw<<1)|(tempw>>15)); if (abrt) break; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x08: /*ROR w,1*/ + seteaw((tempw>>1)|(tempw<<15)); if (abrt) break; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + seteaw((tempw<<1)|temp2); if (abrt) break; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + seteaw((tempw>>1)|(temp2?0x8000:0)); if (abrt) break; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x20: case 0x30: /*SHL w,1*/ + seteaw(tempw<<1); if (abrt) break; + setznp16(tempw<<1); + if (tempw&0x8000) flags|=C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x28: /*SHR w,1*/ + seteaw(tempw>>1); if (abrt) break; + setznp16(tempw>>1); + if (tempw&1) flags|=C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x38: /*SAR w,1*/ + seteaw((tempw>>1)|(tempw&0x8000)); if (abrt) break; + setznp16((tempw>>1)|(tempw&0x8000)); + if (tempw&1) flags|=C_FLAG; + cycles -= (mod == 3) ? 2 : 7; + break; + + default: + pclog("Bad D1 opcode %02X\n",rmdat&0x38); + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); if (abrt) break; + c=CL&31; +// cycles-=c; + if (!c) break; +// if (c>7) pclog("Shiftb %i %02X\n",rmdat&0x38,c); + cycles -= c; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x10: /*RCL b,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempc=temp&0x80; + temp<<=1; + if (templ) temp|=1; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x18: /*RCR b,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempc=temp&1; + temp>>=1; + if (templ) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x20: case 0x30: /*SHL b,CL*/ + seteab(temp<>c); if (abrt) break; + setznp8(temp>>c); + if ((temp>>(c-1))&1) flags|=C_FLAG; + if (c==1 && temp&0x80) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x38: /*SAR b,CL*/ + tempc=(temp>>(c-1))&1; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + setznp8(temp); + if (tempc) flags|=C_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + +// default: +// pclog("Bad D2 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); if (abrt) break; + c=CL&31; + if (!c) break; + cycles -= c; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempw2) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x10: /*RCL w,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempc=tempw&0x8000; + tempw=(tempw<<1)|templ; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + case 0x18: /*RCR w,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempw2=(templ&1)?0x8000:0; + tempc=tempw&1; + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + seteaw(tempw<>c); if (abrt) break; + setznp16(tempw>>c); + if ((tempw>>(c-1))&1) flags|=C_FLAG; + if (c==1 && tempw&0x8000) flags|=V_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + tempc=((int16_t)tempw>>(c-1))&1; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + cycles -= (mod == 3) ? 5 : 8; + break; + +// default: +// pclog("Bad D3 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD4: /*AAM*/ + tempws=readmemb(cs,pc); pc++; + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles -= 16; + break; + case 0xD5: /*AAD*/ + tempws=readmemb(cs,pc); pc++; + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles -= 14; + break; + case 0xD6: /*SETALC*/ + AL=(flags&C_FLAG)?0xFF:0; + cycles -= 3; + break; + case 0xD7: /*XLAT*/ + addr=(BX+AL)&0xFFFF; + temp=readmemb(ds,addr); if (abrt) break; + AL=temp; + cycles -= 5; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xD8: + case 0xDC: + case 0xDE: + case 0xDF: + if ((msw & 6) == 4) + { + pc=oldpc; + pmodeint(7,0); + cycles -= 40; + } + else + { + fetchea(); + } + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)readmemb(cs,pc); pc++; + CX--; + if (CX && !(flags&Z_FLAG)) { pc+=offset; cycles -= 4; cycles -= 2; } + cycles -= 4; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)readmemb(cs,pc); pc++; + CX--; + if (CX && (flags&Z_FLAG)) { pc+=offset; cycles -= 4; cycles -= 2; } + cycles -= 4; + break; + case 0xE2: /*LOOP*/ + offset=(int8_t)readmemb(cs,pc); pc++; + CX--; + if (CX) { pc+=offset; cycles -= 4; cycles -= 2; } + cycles -= 4; + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)readmemb(cs,pc); pc++; + if (!CX) { pc+=offset; cycles -= 4; cycles -= 2; } + cycles-=4; + break; + + case 0xE4: /*IN AL*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + pc++; + AL=inb(temp); + cycles -= 5; + break; + case 0xE5: /*IN AX*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + checkio_perm(temp+1); + pc++; + AX=inw(temp); + cycles -= 5; + break; + case 0xE6: /*OUT AL*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + pc++; + outb(temp,AL); + cycles -= 3; + break; + case 0xE7: /*OUT AX*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + checkio_perm(temp+1); + pc++; + outw(temp,AX); + cycles -= 3; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); if (abrt) break; + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),pc); if (abrt) break; + SP-=2; + pc+=(int16_t)tempw; + cycles -= 7; + break; + case 0xE9: /*JMP rel 16*/ + tempw=getword(); if (abrt) break; + pc+=(int16_t)tempw; + cycles -= 7; + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); if (abrt) { if (output==3) pclog("JMP ABRT\n"); break; } + oxpc=pc; + pc=addr; + loadcsjmp(tempw,oxpc); + cycles -= 11; + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)readmemb(cs,pc); pc++; + pc+=offset; + cycles -= 7; + break; + case 0xEC: /*IN AL,DX*/ + checkio_perm(DX); + AL=inb(DX); + cycles -= 5; + break; + case 0xED: /*IN AX,DX*/ + checkio_perm(DX); + checkio_perm(DX+1); + AX=inw(DX); + cycles -= 5; + break; + case 0xEE: /*OUT DX,AL*/ + checkio_perm(DX); + outb(DX,AL); + cycles -= 4; + break; + case 0xEF: /*OUT DX,AX*/ + checkio_perm(DX); + checkio_perm(DX+1); + outw(DX,AX); + cycles -= 4; + break; + + case 0xF0: /*LOCK*/ + break; + + case 0xF2: /*REPNE*/ + rep386(0); + break; + case 0xF3: /*REPE*/ + rep386(1); + break; + + case 0xF4: /*HLT*/ + inhlt=1; + pc--; + cycles -= 2; +/* if (!(flags & I_FLAG)) + { + pclog("Complete HLT\n"); + dumpregs(); + exit(-1); + }*/ + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles -= 2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + temp2=readmemb(cs,pc); pc++; if (abrt) break; +// pclog("TEST %02X,%02X\n",temp,temp2); +/* if (cs==0x700 && !temp && temp2==0x10) + { + dumpregs(); + exit(-1); + }*/ + temp&=temp2; + setznp8(temp); + cycles -= (mod == 3) ? 3 : 6; + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x20: /*MUL AL,b*/ +// setznp8(AL); + AX=AL*temp; +// if (AX) flags&=~Z_FLAG; +// else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles -= (mod == 3) ? 13 : 16; + break; + case 0x28: /*IMUL AL,b*/ +// setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; +// if (AX) flags&=~Z_FLAG; +// else flags|=Z_FLAG; + if (AH && AH!=0xFF) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles -= (mod == 3) ? 13 : 16; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) tempw2=tempw/temp; +// pclog("DIV %04X/%02X %04X:%04X\n",tempw,temp,CS,pc); + if (temp && !(tempw2&0xFF00)) + { + tempw2=tempw%temp; + AH=tempw2; + tempw/=temp; + AL=tempw&0xFF; + flags|=0x8D5; /*Not a Cyrix*/ + } + else + { + pclog("DIVb BY 0 %04X:%04X\n",cs>>4,pc); + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { +// pclog("%04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x30); +// dumpregs(); +// exit(-1); + } + cycles -= (mod == 3) ? 14 : 17; + break; + case 0x38: /*IDIV AL,b*/ +// pclog("IDIV %04X/%02X\n",tempw,temp); + tempws=(int)(int16_t)AX; + if (temp!=0) tempws2=tempws/(int)((int8_t)temp); + temps=tempws2&0xFF; + if ((temp!=0) && ((int)temps==tempws2)) + { + tempw2=tempws%(int)((int8_t)temp); + AH=tempw2&0xFF; + AL=tempws2&0xFF; + if (!cpu_iscyrix) flags|=0x8D5; /*Not a Cyrix*/ + } + else + { + pclog("IDIVb exception - %X / %08X = %X\n",tempws,temp,tempws2); +// pclog("IDIVb BY 0 %04X:%04X\n",cs>>4,pc); + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); + } + cycles -= (mod == 3) ? 17 : 20; + break; + + default: + pclog("Bad F6 opcode %02X\n",rmdat&0x38); + x86illegal(); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + tempw2=getword(); if (abrt) break; +// if (output==3) pclog("TEST %04X %04X\n",tempw,tempw2); + setznp16(tempw&tempw2); + cycles -= (mod == 3) ? 3 : 6; + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x20: /*MUL AX,w*/ +// setznp16(AX); + templ=AX*tempw; + AX=templ&0xFFFF; + DX=templ>>16; +// if (AX|DX) flags&=~Z_FLAG; +// else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles -= (mod == 3) ? 21 : 24; + break; + case 0x28: /*IMUL AX,w*/ + templ=(int)((int16_t)AX)*(int)((int16_t)tempw); + AX=templ&0xFFFF; + DX=templ>>16; + if (DX && DX!=0xFFFF) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles -= (mod == 3) ? 21 : 24; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; + if (tempw) templ2=templ/tempw; + if (tempw && !(templ2&0xFFFF0000)) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// AX=DX=0; +// break; + pclog("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); +// dumpregs(); +// exit(-1); + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { +// pclog("%04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X 1\n",cs>>4,pc,0xf7,0x30); + } + cycles -= (mod == 3) ? 22 : 25; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); + if (tempw!=0) tempws2=tempws/(int)((int16_t)tempw); + temps16=tempws2&0xFFFF; +// pclog("IDIV %i %i ",tempws,tempw); + if ((tempw!=0) && ((int)temps16==tempws2)) + { + DX=tempws%(int)((int16_t)tempw); + AX=tempws2&0xFFFF; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + pclog("IDIVw exception - %X / %08X = %X\n",tempws,tempw,tempws2); +// pclog("IDIVw BY 0 %04X:%04X\n",cs>>4,pc); +// DX=0; +// AX=0xFFFF; + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { +// pclog("%04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X 1\n",cs>>4,pc,0xf7,0x38); + } + cycles -= (mod == 3) ? 25 : 28; + break; + + default: + pclog("Bad F7 opcode %02X\n",rmdat&0x38); + x86illegal(); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles -= 2; + break; + case 0xF9: /*STC*/ +// pclog("STC %04X\n",pc); + flags|=C_FLAG; + cycles -= 2; + break; + case 0xFA: /*CLI*/ + if (!IOPLp) + { + x86gpf(NULL,0); + } + else + flags&=~I_FLAG; + cycles -= 3; + break; + case 0xFB: /*STI*/ + if (!IOPLp) + { + x86gpf(NULL,0); + } + else + flags|=I_FLAG; + cycles -= 2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles -= 2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles -= 2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); if (abrt) break; + if (rmdat&0x38) + { + seteab(temp-1); if (abrt) break; + flags&=~V_FLAG; + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + seteab(temp+1); if (abrt) break; + flags&=~V_FLAG; + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } + cycles -= (mod == 3) ? 2 : 7; + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); if (abrt) break; + seteaw(tempw+1); if (abrt) break; + setadd16nc(tempw,1); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); if (abrt) break; + seteaw(tempw-1); if (abrt) break; + setsub16nc(tempw,1); + cycles -= (mod == 3) ? 2 : 7; + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (abrt) break; + if (ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,pc); if (abrt) break; + SP-=2; + pc=tempw; + cycles -= (mod == 3) ? 7 : 11; + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,(eaaddr+2)); if (output==3) pclog("CALL FAR %04X:%04X\n",tempw,tempw2); if (abrt) break; + tempw3=CS; + templ2=pc; + if (ssegs) ss=oldss; + oxpc=pc; + pc=tempw; + optype=CALL; + if (msw&1) loadcscall(tempw2); + else loadcs(tempw2); + optype=0; + if (abrt) break; + oldss=ss; + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),templ2); + SP-=4; + cycles -= 16; + break; + case 0x20: /*JMP*/ + tempw=geteaw(); if (abrt) break; + pc=tempw; + cycles -= (mod == 3) ? 7 : 11; + break; + case 0x28: /*JMP far*/ + oxpc=pc; + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,eaaddr+2); if (abrt) break; + pc=tempw; + loadcsjmp(tempw2,oxpc); if (abrt) break; + cycles -= 15; + break; + case 0x30: /*PUSH w*/ + tempw=geteaw(); if (abrt) break; + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; + SP-=2; + cycles -= (mod==3) ? 3 : 5; + break; + + default: + pclog("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + //dumpregs(); + //exit(-1); + } + break; + + default: +// pc--; +// cycles-=8; +// break; + pclog("Bad opcode %02X at %04X:%04X from %04X:%04X %08X\n",opcode,cs>>4,pc,old8>>16,old8&0xFFFF,old82); + x86illegal(); +// dumpregs(); +// exit(-1); + } + opcodeend: + pc&=0xFFFF; + +// output = 3; +/* output = 3; + + if (pc == 0xcdd && CS == 0xf000) + { + dumpregs(); + exit(-1); + }*/ + //if (ins == 20768972) output = 3; + + if (ssegs) + { + ds=oldds; _ds.limit=olddslimit; _ds.limitw=olddslimitw; + ss=oldss; _ss.limit=oldsslimit; _ss.limitw=oldsslimitw; + ssegs=0; + } + if (abrt) + { + tempi = abrt; + abrt = 0; + x86_doabrt(tempi); + if (abrt) + { + abrt = 0; + CS = oldcs; + pc = oldpc; + pclog("Double fault\n"); +// dumpregs(); +// exit(-1); + pmodeint(8, 0); + if (abrt) + { + abrt = 0; + softresetx86(); + pclog("Triple fault - reset\n"); + } + } + } + cycdiff-=cycles; + + pit.c[0]-=cycdiff; + pit.c[1]-=cycdiff; + if (ppi.pb&1) pit.c[2]-=cycdiff; + + if ((pit.c[0]<1)||(pit.c[1]<1)||(pit.c[2]<1)) pit_poll(); + + spktime-=cycdiff; + if (spktime<=0.0) + { + spktime+=SPKCONST; +// pclog("1Poll spk\n"); + pollspk(); + pollgussamp(); + getsbsamp(); + polladlib(); + getdacsamp(); +// pclog("2Poll spk\n"); + } + soundtime-=cycdiff; + if (soundtime<=0.0) + { + soundtime+=SOUNDCONST; +// pclog("1Poll sound60hz\n"); + pollsound60hz(); +// pclog("2Poll sound60hz\n"); + } + gustime-=cycdiff; + while (gustime<=0.0) + { + gustime+=GUSCONST; + pollgus(); + } + gustime2-=cycdiff; + while (gustime2<=0.0) + { + gustime2+=GUSCONST2; + pollgus2(); + } + vidtime-=cycdiff; + if (vidtime<=0.0) + { +// pclog("1Poll video\n"); + pollvideo(); +// pclog("2Poll video\n"); + } + if (disctime) + { + disctime-=cycdiff/4; + if (disctime<=0) + { +// pclog("1Poll disc\n"); + disctime=0; + fdc_poll(); +// pclog("2Poll disc\n"); + } + } + if (mousedelay) + { + mousedelay-=20; + if (!mousedelay) + { +// pclog("1Poll mouse\n"); + mousecallback(); +// pclog("2Poll disc\n"); + } + } + if (sbenable) + { + sbcount-=cycdiff; + if (sbcount<0) + { + sbcount+=sblatcho; + pollsb(); + } + } + if (sb_enable_i) + { + sb_count_i-=cycdiff; + if (sb_count_i<0) + { + sb_count_i+=sblatchi; + sb_poll_i(); + } + } + rtctime-=cycdiff; + if (rtctime<0) + { + nvr_rtc(); + } + if (idecallback[0]) + { + idecallback[0]--; + if (idecallback[0]<=0) + { +// pclog("IDE time over\n"); + idecallback[0]=0; + callbackide(0); + } + } + if (idecallback[1]) + { + idecallback[1]--; + if (idecallback[1]<=0) + { +// pclog("IDE time over\n"); + idecallback[1]=0; + callbackide(1); + } + } + if (trap && (flags&T_FLAG) && !noint) + { + if (msw&1) + { + pmodeint(1,0); + cycles -= 40; + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + addr=1<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= 23; + } + } + else if ((flags&I_FLAG) && (((pic.pend&~pic.mask)&~pic.mask2) || ((pic2.pend&~pic2.mask)&~pic2.mask2)) && !ssegs && !noint) + { +// pclog("Test %02X %02X %02X\n", pic.pend, pic.mask, pic.mask2); + temp=picinterrupt(); + if (temp!=0xFF) + { +// pclog("286 int %02X %02X %02X %02X\n",temp, pic.pend, pic.mask, pic.mask2); + if (inhlt) pc++; +// intcount++; + if (msw&1) + { + pmodeint(temp,0); + cycles -= 40; + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + addr=temp<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= 23; + } + inint=1; + } + } + +/* if (pc==0xCC32 && es>0x180000) + { + pc=0xCBEB; +// output=1; +// timetolive=500000; + }*/ + + if (noint) noint=0; + ins++; + insc++; + +// if (ins == 25000000) output = 3; +/* if (timetolive) + { + timetolive--; + if (!timetolive) + { + dumpregs(); + exit(-1); + } //output=0; + }*/ + keybsenddelay--; + if (keybsenddelay<1) + { + keybsenddelay = 2500; + keyboard_poll(); + } + //output = 3; + } +} +//#endif diff --git a/src/386.c b/src/386.c new file mode 100644 index 00000000..7322ef7c --- /dev/null +++ b/src/386.c @@ -0,0 +1,8377 @@ +//61% +//Win 3.1 - Timer (vtdapi.386) IRQ handler 80020E04 stores to 800200F8 + +//11A2D +//3EF08 - SYS_FloatTime() + +#include +#include +#include +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "mem.h" +#include "cpu.h" +#include "fdc.h" +#include "video.h" + +extern int resets; +int gpf = 0; +int ins2 = 0; + +// pclog("IO perm fail on %04X\n",port); \ + + +#define checkio_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ + { \ + tempi = checkio(port); \ + if (abrt) break; \ + if (tempi) \ + { \ + x86gpf(NULL,0); \ + break; \ + } \ + } + + +int cpl_override=0; + +int has_fpu; +int fpucount=0; +int times; +uint16_t rds; +uint16_t ea_rseg; + +int hitits=0; + +uint32_t oldpc2; +int is486; +int cgate32; +uint8_t opcode2; +int incga; +int enters=0; +int ec; + +uint32_t ten3688; +int oldv86=0,oldpmode=0,itson=0; +uint8_t old22; +#undef readmemb +#undef writememb + +//#define readmemb(s,a) readmemb386l(s,a) +//#define writememb(s,a,v) writememb386l(s,a,v) + +//#define is486 1 + +#define readmemb(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF)?readmemb386l(s,a):ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]) + +#define writememb(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememb386l(s,a,v); else ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]=v + +#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v + + +/*#undef readmemw +#undef readmeml + +#define readmemb(s, a) readmemb386l(s, a) +#define readmemw(s, a) readmemwl(s, a) +#define readmeml(s, a) readmemll(s, a)*/ + +/*#define writememb(s,a,v) writememb386l(s, a, v) +#define writememw(s,a,v) writememwl(s, a, v) +#define writememl(s,a,v) writememll(s, a, v)*/ +//#define readmemb(s,a) readmemb((s)+(a)) +//#define writememb(s,a,v) writememb((s)+(a),v) +uint32_t mmucache[0x100000]; + +uint8_t romext[32768]; +uint8_t *ram,*rom,*vram,*vrom; +uint16_t biosmask; + +/*uint16_t getwordx() +{ + pc+=2; + return readmemw(cs,(pc-2)); +}*/ + +#define getword() getwordx() + + +//#define readmemb(s,a) readmemb386(s,a) +//#define writememb(s,a,v) writememb386(s,a,v) + +//uint32_t fetchdat; +uint32_t rmdat32; +#define rmdat rmdat32 +#define fetchdat rmdat32 +uint32_t backupregs[16]; +int oddeven=0; +int inttype,abrt; + + +uint32_t oldcs2; +uint32_t oldecx; +uint32_t op32; + +static inline uint16_t fastreadw(uint32_t a) +{ + uint32_t t; + if ((a&0xFFF)>0xFFE) + { + t=readmemb(0,a); + t|=(readmemb(0,a+1)<<8); + return t; + } + if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); + pccache2=getpccache(a); + pccache=a>>12; + return *((uint16_t *)&pccache2[a]); +} + +static inline uint32_t fastreadl(uint32_t a) +{ + uint8_t *t; + uint32_t val; + if ((a&0xFFF)<0xFFD) + { + if ((a>>12)!=pccache) + { + t = getpccache(a); + if (abrt) return 0; + pccache2 = t; + pccache=a>>12; + //return *((uint32_t *)&pccache2[a]); + } + return *((uint32_t *)&pccache2[a]); + } + val =readmemb(0,a); + val |=(readmemb(0,a+1)<<8); + val |=(readmemb(0,a+2)<<16); + val |=(readmemb(0,a+3)<<24); + return val; +} + +static inline uint16_t getword() +{ + pc+=2; + return fastreadw(cs+(pc-2)); +} + +static inline uint32_t getlong() +{ + pc+=4; + return fastreadl(cs+(pc-4)); +} + +uint32_t *eal_r, *eal_w; +static inline uint8_t geteab() +{ + if (mod==3) + return (rm&4)?regs[rm&3].b.h:regs[rm&3].b.l; + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod==3) + return regs[rm].w; +// cycles-=3; + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,eaaddr); +} + +static inline uint32_t geteal() +{ + if (mod==3) + return regs[rm].l; +// cycles-=3; + if (eal_r) return *eal_r; + return readmeml(easeg,eaaddr); +} + +#define seteab(v) if (mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); } else if (rm&4) regs[rm&3].b.h=v; else regs[rm].b.l=v +#define seteaw(v) if (mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); } else regs[rm].w=v +#define seteal(v) if (mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); } else regs[rm].l=v + +static inline void fetcheal32sib() +{ + uint8_t sib; + sib=rmdat>>8;// pc++; + switch (mod) + { + case 0: eaaddr=regs[sib&7].l; pc++; break; + case 1: eaaddr=((uint32_t)(int8_t)(rmdat>>16))+regs[sib&7].l; pc+=2; break; + case 2: eaaddr=(fastreadl(cs+pc+1))+regs[sib&7].l; pc+=5; break; + } + /*SIB byte present*/ + if ((sib&7)==5 && !mod) eaaddr=getlong(); + else if ((sib&6)==4) + { + easeg=ss; + ea_rseg=SS; + } + if (((sib>>3)&7)!=4) eaaddr+=regs[(sib>>3)&7].l<<(sib>>6); +} + +static inline void fetcheal32nosib() +{ + if (rm==5) + { + easeg=ss; + ea_rseg=SS; + } + if (mod==1) { eaaddr+=((uint32_t)(int8_t)(rmdat>>8)); pc++; } + else { eaaddr+=getlong(); } +} + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +void fetchea32() +{ + eal_r = eal_w = NULL; + if (op32&0x200) + { + /*rmdat=readmemw(cs,pc); */pc++; + reg=(rmdat>>3)&7; + mod=(rmdat>>6)&3; + rm=rmdat&7; + + if (mod!=3) + { + easeg=ds; + ea_rseg=DS; + if (rm==4) fetcheal32sib(); + else + { + eaaddr=regs[rm].l; + if (mod) fetcheal32nosib(); + else if (rm==5) eaaddr=getlong(); + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + if ( readlookup2[(easeg + eaaddr) >> 12] != 0xFFFFFFFF) + eal_r = (uint32_t *)&ram[ readlookup2[(easeg + eaaddr) >> 12] + ((easeg + eaaddr) & 0xFFF)]; + if (writelookup2[(easeg + eaaddr) >> 12] != 0xFFFFFFFF) + eal_w = (uint32_t *)&ram[writelookup2[(easeg + eaaddr) >> 12] + ((easeg + eaaddr) & 0xFFF)]; + } + } + } + else + { + /*rmdat=readmemb(cs,pc); */pc++; + reg=(rmdat>>3)&7; + mod=(rmdat>>6)&3; + rm=rmdat&7; + if (mod!=3) + { + if (!mod && rm==6) { eaaddr=(rmdat>>8)&0xFFFF; pc+=2; easeg=ds; ea_rseg=DS; } + else + { + switch (mod) + { + case 0: + eaaddr=0; + break; + case 1: + eaaddr=(uint16_t)(int8_t)(rmdat>>8); pc++; + break; + case 2: + eaaddr=getword(); + break; + } + eaaddr+=(*mod1add[0][rm])+(*mod1add[1][rm]); + easeg=*mod1seg[rm]; + if (mod1seg[rm]==&ss) ea_rseg=SS; + else ea_rseg=DS; + eaaddr&=0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + if ( readlookup2[(easeg + eaaddr) >> 12] != 0xFFFFFFFF) + eal_r = (uint32_t *)&ram[ readlookup2[(easeg + eaaddr) >> 12] + ((easeg + eaaddr) & 0xFFF)]; + if (writelookup2[(easeg + eaaddr) >> 12] != 0xFFFFFFFF) + eal_w = (uint32_t *)&ram[writelookup2[(easeg + eaaddr) >> 12] + ((easeg + eaaddr) & 0xFFF)]; + } +/* if (readlookup2[(easeg+eaaddr)>>12]!=0xFFFFFFFF && easeg!=0xFFFFFFFF && ((easeg+eaaddr)&0xFFF)<=0xFFC) + eal=(uint32_t *)&ram[readlookup2[(easeg+eaaddr)>>12]+((easeg+eaaddr)&0xFFF)];*/ + } + } +} + +#undef fetchea +#define fetchea() fetchea32(); if (abrt) break +#define fetchea2() rmdat=fastreadl(cs+pc); fetchea32(); if (abrt) break + +#include "x86_flags.h" + +void setadd32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + flags|=(znptable8[c&0xFF]&P_FLAG); + if (ca) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsub32nc(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + flags|=(znptable8[c&0xFF]&P_FLAG); + if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsbc32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + flags|=(znptable8[c&0xFF]&P_FLAG); + if ((c>a) || (c==a && tempc)) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) flags|=A_FLAG; +} + + + +void x86_int(int num) +{ + uint32_t addr; + pc=oldpc; + if (msw&1) + { + pmodeint(num,0); + } + else + { + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + } + addr=num<<2; + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + cycles-=70; +} + +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + break; \ + } + +void rep386(int fv) +{ + uint8_t temp; + uint32_t c;//=CX; + uint8_t temp2; + uint16_t tempw,tempw2,tempw3,of=flags; + uint32_t ipc=oldpc;//pc-1; + int changeds=0; + uint32_t oldds; + uint32_t rep32=op32; + uint32_t templ,templ2; + int tempz; + int tempi; +// if (output) pclog("REP32 %04X %04X ",use32,rep32); + startrep: + temp=opcode2=readmemb(cs,pc); pc++; +// if (firstrepcycle && temp==0xA5) pclog("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (output) pclog("REP %02X %04X\n",temp,ipc); + c=(rep32&0x200)?ECX:CX; +/* if (rep32 && (msw&1)) + { + if (temp!=0x67 && temp!=0x66 && (rep32|temp)!=0x1AB && (rep32|temp)!=0x3AB) pclog("32-bit REP %03X %08X %04X:%06X\n",temp|rep32,c,CS,pc); + }*/ + switch (temp|rep32) + { + case 0xC3: case 0x1C3: case 0x2C3: case 0x3C3: + pc--; + break; + case 0x08: + pc=ipc+1; + break; + case 0x26: case 0x126: case 0x226: case 0x326: /*ES:*/ + oldds=ds; + ds=es; + rds=ES; + changeds=1; + goto startrep; + break; + case 0x2E: case 0x12E: case 0x22E: case 0x32E: /*CS:*/ + oldds=ds; + ds=cs; + rds=CS; + changeds=1; + goto startrep; + break; + case 0x36: case 0x136: case 0x236: case 0x336: /*SS:*/ + oldds=ds; + ds=ss; + rds=SS; + changeds=1; + goto startrep; + break; + case 0x3E: case 0x13E: case 0x23E: case 0x33E: /*DS:*/ + oldds=ds; + ds=ds; + changeds=1; + goto startrep; + break; + case 0x64: case 0x164: case 0x264: case 0x364: /*FS:*/ + oldds=ds; + ds=fs; + rds=FS; + changeds=1; + goto startrep; + case 0x65: case 0x165: case 0x265: case 0x365: /*GS:*/ + oldds=ds; + ds=gs; + rds=GS; + changeds=1; + goto startrep; + case 0x66: case 0x166: case 0x266: case 0x366: /*Data size prefix*/ + rep32^=0x100; + goto startrep; + case 0x67: case 0x167: case 0x267: case 0x367: /*Address size prefix*/ + rep32^=0x200; + goto startrep; + case 0x6C: case 0x16C: /*REP INSB*/ + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,DI,temp2); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x26C: case 0x36C: /*REP INSB*/ + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,EDI,temp2); + if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x6D: /*REP INSW*/ + if (c>0) + { + tempw=inw(DX); + writememw(es,DI,tempw); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x16D: /*REP INSL*/ + if (c>0) + { + templ=inl(DX); + writememl(es,DI,templ); + if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x26D: /*REP INSW*/ + if (c>0) + { + tempw=inw(DX); + writememw(es,EDI,tempw); + if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x36D: /*REP INSL*/ + if (c>0) + { + templ=inl(DX); + writememl(es,EDI,templ); + if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x6E: case 0x16E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds,SI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x26E: case 0x36E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds,ESI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) ESI--; + else ESI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x6F: /*REP OUTSW*/ + if (c>0) + { + tempw=readmemw(ds,SI); + if (abrt) break; +// pclog("OUTSW %04X -> %04X\n",SI,tempw); + outw(DX,tempw); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x16F: /*REP OUTSL*/ + if (c > 0) + { + templ = readmeml(ds, SI); + if (abrt) break; + outl(DX, templ); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + c--; + cycles -= 14; + } + if (c > 0) { firstrepcycle = 0; pc = ipc; if (ssegs) ssegs++; } + else firstrepcycle = 1; + break; + case 0x26F: /*REP OUTSW*/ + if (c>0) + { + tempw=readmemw(ds,ESI); + if (abrt) break; + outw(DX,tempw); + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x36F: /*REP OUTSL*/ + if (c > 0) + { + templ = readmeml(ds, ESI); + if (abrt) break; + outl(DX, templ); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + c--; + cycles -= 14; + } + if (c > 0) { firstrepcycle = 0; pc = ipc; if (ssegs) ssegs++; } + else firstrepcycle = 1; + break; + case 0xA4: case 0x1A4: /*REP MOVSB*/ + if (c>0) + { + temp2=readmemb(ds,SI); if (abrt) break; + writememb(es,DI,temp2); if (abrt) break; +// if (output==3) pclog("MOVSB %08X:%04X -> %08X:%04X %02X\n",ds,SI,es,DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2A4: case 0x3A4: /*REP MOVSB*/ + if (c>0) + { + temp2=readmemb(ds,ESI); if (abrt) break; + writememb(es,EDI,temp2); if (abrt) break; + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA5: /*REP MOVSW*/ + if (c>0) + { + tempw=readmemw(ds,SI); if (abrt) break; + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x1A5: /*REP MOVSL*/ + if (c>0) + { + templ=readmeml(ds,SI); if (abrt) break; +// pclog("MOVSD %08X from %08X to %08X (%04X:%08X)\n", templ, ds+SI, es+DI, CS, pc); + writememl(es,DI,templ); if (abrt) break; + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2A5: /*REP MOVSW*/ + if (c>0) + { + tempw=readmemw(ds,ESI); if (abrt) break; + writememw(es,EDI,tempw); if (abrt) break; +// if (output) pclog("Written %04X from %08X to %08X %i %08X %04X %08X %04X\n",tempw,ds+ESI,es+EDI,c,ds,ES,es,ES); + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x3A5: /*REP MOVSL*/ + if (c>0) + { + templ=readmeml(ds,ESI); if (abrt) break; +// if ((EDI&0xFFFF0000)==0xA0000) cycles-=12; + writememl(es,EDI,templ); if (abrt) break; +// if (output) pclog("Load %08X from %08X to %08X %04X %08X %04X %08X\n",templ,ESI,EDI,DS,ds,ES,es); + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + c--; + cycles-=(is486)?3:4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA6: case 0x1A6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp=readmemb(ds,SI); + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2A6: case 0x3A6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp=readmemb(ds,ESI); + temp2=readmemb(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { +// pclog("CMPSW %05X %05X %08X %08X ", ds+SI, es+DI, readlookup2[(ds+SI)>>12], readlookup2[(es+DI)>>12]); + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); +// pclog("%04X %04X %02X\n", tempw, tempw2, ram[8]); + + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x1A7: /*REP CMPSL*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + templ=readmeml(ds,SI); + templ2=readmeml(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + c--; + cycles-=(is486)?7:9; + setsub32(templ,templ2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2A7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(ds,ESI); + tempw2=readmemw(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x3A7: /*REP CMPSL*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + templ=readmeml(ds,ESI); + templ2=readmeml(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + c--; + cycles-=(is486)?7:9; + setsub32(templ,templ2); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + + case 0xAA: case 0x1AA: /*REP STOSB*/ + if (c>0) + { + writememb(es,DI,AL); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2AA: case 0x3AA: /*REP STOSB*/ + if (c>0) + { + writememb(es,EDI,AL); + if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + if (c>0) + { + writememw(es,DI,AX); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2AB: /*REP STOSW*/ + if (c>0) + { + writememw(es,EDI,AX); + if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x1AB: /*REP STOSL*/ + if (c>0) + { + writememl(es,DI,EAX); + if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x3AB: /*REP STOSL*/ + if (c>0) + { + writememl(es,EDI,EAX); + if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=(is486)?4:5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAC: case 0x1AC: /*REP LODSB*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL=readmemb(ds,SI); + if (abrt) break; + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2AC: case 0x3AC: /*REP LODSB*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL=readmemb(ds,ESI); + if (abrt) break; + if (flags&D_FLAG) ESI--; + else ESI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX=readmemw(ds,SI); + if (abrt) break; + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x1AD: /*REP LODSL*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + EAX=readmeml(ds,SI); + if (abrt) break; + if (flags&D_FLAG) SI-=4; + else SI+=4; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2AD: /*REP LODSW*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX=readmemw(ds,ESI); + if (abrt) break; + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x3AD: /*REP LODSL*/ +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + EAX=readmeml(ds,ESI); + if (abrt) break; + if (flags&D_FLAG) ESI-=4; + else ESI+=4; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAE: case 0x1AE: /*REP SCASB*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + setsub8(AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2AE: case 0x3AE: /*REP SCASB*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; +// if (output) pclog("REP SCASB - %i %04X %i\n",fv,flags&Z_FLAG,c); + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es,EDI); + if (abrt) { flags=of; break; } +// if (output) pclog("Compare %02X,%02X\n",temp2,AL); + setsub8(AL,temp2); + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x1AF: /*REP SCASL*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + templ=readmeml(es,DI); + if (abrt) { flags=of; break; } + setsub32(EAX,templ); + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x2AF: /*REP SCASW*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,EDI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + case 0x3AF: /*REP SCASL*/ +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + templ=readmeml(es,EDI); + if (abrt) { flags=of; break; } + setsub32(EAX,templ); + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=(is486)?5:8; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; } + else firstrepcycle=1; + break; + + + default: + pc=ipc; + cycles-=20; + x86illegal(); + pclog("Bad REP %02X %i\n",temp,rep32>>8); + } + if (rep32&0x200) ECX=c; + else CX=c; + if (changeds) ds=oldds; +// if (output) pclog("%03X %03X\n",rep32,use32); +} + +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; +// pclog("CheckIO 1 %08X\n",tr.base); + if (abrt) return 0; +// pclog("CheckIO %04X %01X %01X %02X %04X %04X %08X ",CS,CPL,IOPL,port,t,t+(port>>3),tr.base+t+(port>>3)); + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + d=readmemb(tr.base,t+(port>>3)); + cpl_override = 0; +// pclog("%02X %02X\n",d,d&(1<<(port&7))); + return d&(1<<(port&7)); +} + +#define getbytef() ((uint8_t)(fetchdat)); pc++ +#define getwordf() ((uint16_t)(fetchdat)); pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); pc+=2 +int xout=0; + + +#define divexcp() { \ + pclog("Divide exception at %04X(%06X):%04X\n",CS,cs,pc); \ + pc=oldpc; \ + if (msw&1) pmodeint(0,0); \ + else \ + { \ + writememw(ss,(SP-2)&0xFFFF,flags); \ + writememw(ss,(SP-4)&0xFFFF,CS); \ + writememw(ss,(SP-6)&0xFFFF,pc); \ + SP-=6; \ + flags&=~I_FLAG; \ + oxpc=pc; \ + pc=readmemw(0,0); \ + loadcs(readmemw(0,2)); \ + } \ + return; \ +} + +void divl(uint32_t val) +{ + if (val==0) divexcp(); + uint64_t num=(((uint64_t)EDX)<<32)|EAX; + uint64_t quo=num/val; + uint32_t rem=num%val; + uint32_t quo32=(uint32_t)(quo&0xFFFFFFFF); + if (quo!=(uint64_t)quo32) divexcp(); + EDX=rem; + EAX=quo32; +} +void idivl(int32_t val) +{ + if (val==0) divexcp(); + int64_t num=(((uint64_t)EDX)<<32)|EAX; + int64_t quo=num/val; + int32_t rem=num%val; + int32_t quo32=(int32_t)(quo&0xFFFFFFFF); + if (quo!=(int64_t)quo32) divexcp(); + EDX=rem; + EAX=quo32; +} + +int oldi; + +uint32_t testr[9]; +int dontprint=0; +void exec386(int cycs) +{ + uint64_t temp64; + int64_t temp64i; + uint8_t temp,temp2; + uint16_t tempw,tempw2,tempw3,tempw4; + int8_t offset; + int8_t temps; + int16_t temps16; + volatile int tempws,tempws2; + uint32_t templ,templ2,templ3,addr; + int c,cycdiff; + int oldcyc; + int tempi; + int cyctot=0; + int trap; + + FILE *f; + + cycles+=cycs; +// output=3; + while (cycles>0) + { + cycdiff=0; + oldcyc=cycles; +// pclog("%i %02X\n", ins, ram[8]); + while (cycdiff<100) + { +/* testr[0]=EAX; testr[1]=EBX; testr[2]=ECX; testr[3]=EDX; + testr[4]=ESI; testr[5]=EDI; testr[6]=EBP; testr[7]=ESP; + testr[8]=flags;*/ +// oldcs2=oldcs; +// oldpc2=oldpc; + oldcs=CS; + oldpc=pc; + oldcpl=CPL; + op32=use32; + +dontprint=0; + + opcodestart: + fetchdat=fastreadl(cs+pc); + if (abrt) goto opcodeend; + + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + opcode=fetchdat&0xFF; + fetchdat>>=8; + + if (output==3 && !dontprint) + { + if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) + { + if (!skipnextprint) + { + pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,writelookup2, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, readmode); + //x87_print(); + } + skipnextprint=0; + } + } + dontprint=1; +//#endif + pc++; + inhlt=0; + switch ((opcode|op32)&0x3FF) + { + case 0x00: case 0x100: case 0x200: case 0x300: /*ADD 8,reg*/ + fetchea(); + //if (!rmdat && output) pc--; +/* if (!rmdat && output) + { + fatal("Crashed\n"); +// clear_keybuf(); +// readkey(); + + + }*/ + if (mod == 3) + { + temp = getr8(rm); + temp2 = getr8(reg); + setadd8(temp, temp2); + setr8(rm, temp + temp2); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp + temp2); if (abrt) break; + setadd8(temp, temp2); + cycles -= timing_mr; + } + break; + case 0x01: case 0x201: /*ADD 16,reg*/ + fetchea(); + if (mod == 3) + { + setadd16(regs[rm].w, regs[reg].w); + regs[rm].w += regs[reg].w; + cycles -= timing_rr; + } + else + { + tempw = geteaw(); if (abrt) break; + seteaw(tempw + regs[reg].w); if (abrt) break; + setadd16(tempw, regs[reg].w); + cycles -= timing_mr; + } + break; + case 0x101: case 0x301: /*ADD 32,reg*/ + fetchea(); + if (mod == 3) + { + setadd32(regs[rm].l, regs[reg].l); + regs[rm].l += regs[reg].l; + cycles -= timing_rr; + } + else + { + templ = geteal(); if (abrt) break; + seteal(templ + regs[reg].l); if (abrt) break; + setadd32(templ, regs[reg].l); + cycles -= timing_mrl; + } + break; + case 0x02: case 0x102: case 0x202: case 0x302: /*ADD reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + setadd8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x03: case 0x203: /*ADD reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setadd16(regs[reg].w,tempw); + regs[reg].w+=tempw; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x103: case 0x303: /*ADD reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + setadd32(regs[reg].l,templ); + regs[reg].l+=templ; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x04: case 0x104: case 0x204: case 0x304: /*ADD AL,#8*/ + temp=getbytef(); + setadd8(AL,temp); + AL+=temp; + cycles -= timing_rr; + break; + case 0x05: case 0x205: /*ADD AX,#16*/ + tempw=getwordf(); + setadd16(AX,tempw); + AX+=tempw; + cycles -= timing_rr; + break; + case 0x105: case 0x305: /*ADD EAX,#32*/ + templ=getlong(); if (abrt) break; + setadd32(EAX,templ); + EAX+=templ; + cycles -= timing_rr; + break; + + case 0x06: case 0x206: /*PUSH ES*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,ES); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),ES); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0x106: case 0x306: /*PUSH ES*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,ES); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),ES); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + case 0x07: case 0x207: /*POP ES*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_es); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_es); if (abrt) break; + SP+=2; + } + cycles-=(is486)?3:7; + break; + case 0x107: case 0x307: /*POP ES*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmeml(ss,ESP)&0xFFFF; if (abrt) break; + loadseg(tempw,&_es); if (abrt) break; + ESP+=4; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_es); if (abrt) break; + SP+=4; + } + cycles-=(is486)?3:7; + break; + + + case 0x08: case 0x108: case 0x208: case 0x308: /*OR 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm) | getr8(reg); + setr8(rm, temp); + setznp8(temp); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp | temp2); if (abrt) break; + setznp8(temp | temp2); + cycles -= timing_mr; + } + break; + case 0x09: case 0x209: /*OR 16,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].w |= regs[reg].w; + setznp16(regs[rm].w); + cycles -= timing_rr; + } + else + { + tempw = geteaw() | regs[reg].w; if (abrt) break; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= timing_mr; + } + break; + case 0x109: case 0x309: /*OR 32,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].l |= regs[reg].l; + setznp32(regs[rm].l); + cycles -= timing_rr; + } + else + { + templ = geteal() | regs[reg].l; if (abrt) break; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= timing_mrl; + } + break; + case 0x0A: case 0x10A: case 0x20A: case 0x30A: /*OR reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp|=getr8(reg); + setznp8(temp); + setr8(reg,temp); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x0B: case 0x20B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw|=regs[reg].w; + setznp16(tempw); + regs[reg].w=tempw; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x10B: case 0x30B: /*OR reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ|=regs[reg].l; + setznp32(templ); + regs[reg].l=templ; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x0C: case 0x10C: case 0x20C: case 0x30C: /*OR AL,#8*/ + AL|=getbytef(); + setznp8(AL); + cycles -= timing_rr; + break; + case 0x0D: case 0x20D: /*OR AX,#16*/ + AX|=getwordf(); + setznp16(AX); + cycles -= timing_rr; + break; + case 0x10D: case 0x30D: /*OR AX,#32*/ + templ=getlong(); if (abrt) break; + EAX|=templ; + setznp32(EAX); + cycles -= timing_rr; + break; + + case 0x0E: case 0x20E: /*PUSH CS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,CS); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),CS); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0x10E: case 0x30E: /*PUSH CS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,CS); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),CS); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + + case 0x0F: case 0x20F: + temp=fetchdat&0xFF/*readmemb(cs+pc)*/; pc++; + opcode2=temp; +// if (temp>5 && temp!=0x82 && temp!=0x85 && temp!=0x84 && temp!=0x87 && temp!=0x8D && temp!=0x8F && temp!=0x8C && temp!=0x20 && temp!=0x22) pclog("Using magic 386 0F instruction %02X!\n",temp); + switch (temp) + { + case 0: + if (!(cr0&1) || (eflags&VM_FLAG)) goto inv16; + fetchea2(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*SLDT*/ + NOTRM + seteaw(ldt.seg); + cycles-=4; + break; + case 0x08: /*STR*/ + NOTRM + seteaw(tr.seg); + cycles-=4; + break; + case 0x10: /*LLDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LLDT!\n"); + x86gpf(NULL,0); + break; + } + NOTRM + ldt.seg=geteaw(); +// pclog("Load LDT %04X ",ldt.seg); + templ=(ldt.seg&~7)+gdt.base; +// pclog("%06X ",gdt.base); + templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); + templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + if (abrt) break; + ldt.limit=templ3; + ldt.access=readmemb(0,templ+6); + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=templ2; +// /*if (output==3) */pclog("LLDT %04X %08X %04X %08X %08X\n",ldt.seg,ldt.base,ldt.limit,readmeml(0,templ),readmeml(0,templ+4)); + + cycles-=20; + break; + case 0x18: /*LTR*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LTR!\n"); + x86gpf(NULL,0); + break; + } + NOTRM + tr.seg=geteaw(); + templ=(tr.seg&~7)+gdt.base; + templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); + templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + temp=readmemb(0,templ+5); + if (abrt) break; + tr.limit=templ3; + tr.access=readmemb(0,templ+6); + if (readmemb(0,templ+6)&0x80) + { + tr.limit<<=12; + tr.limit|=0xFFF; + } + tr.base=templ2; +// pclog("TR base = %08X\n",templ2); + tr.access=temp; + cycles-=20; + break; + case 0x20: /*VERR*/ + NOTRM + tempw=geteaw(); if (abrt) break; + flags&=~Z_FLAG; + if (!(tempw&0xFFFC)) break; /*Null selector*/ + cpl_override=1; + tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); + tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); + cpl_override=0; + if (abrt) break; + if (!(tempw2&0x1000)) tempi=0; + if ((tempw2&0xC00)!=0xC00) /*Exclude conforming code segments*/ + { + tempw3=(tempw2>>13)&3; /*Check permissions*/ + if (tempw3>13)&3; /*Check permissions*/ + if (tempw3>16)&0xFF); + cycles-=7; //less seteaw time + break; + case 0x08: /*SIDT*/ + seteaw(idt.limit); + writememw(easeg,eaaddr+2,idt.base); + writememw(easeg,eaaddr+4,(idt.base>>16)&0xFF); + cycles-=7; + break; + case 0x10: /*LGDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LGDT!\n"); + x86gpf(NULL,0); + break; + } + tempw=geteaw(); + templ=readmeml(0,easeg+eaaddr+2)&0xFFFFFF; + if (abrt) break; + gdt.limit=tempw; + gdt.base=templ; + cycles-=11; + break; + case 0x18: /*LIDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LIDT!\n"); + x86gpf(NULL,0); + break; + } + tempw=geteaw(); + templ=readmeml(0,easeg+eaaddr+2)&0xFFFFFF; + if (abrt) break; + idt.limit=tempw; + idt.base=templ; + cycles-=11; + break; + + case 0x20: /*SMSW*/ + if (is486) seteaw(msw); + else seteaw(msw|0xFF00); +// pclog("SMSW %04X:%04X %04X %i\n",CS,pc,msw,is486); + cycles-=2; + break; + case 0x30: /*LMSW*/ + if ((CPL || eflags&VM_FLAG) && (msw&1)) + { + pclog("LMSW - ring not zero!\n"); + x86gpf(NULL,0); + break; + } + tempw=geteaw(); if (abrt) break; + if (msw&1) tempw|=1; + msw=tempw; + break; + + default: + pclog("Bad 0F 01 opcode %02X\n",rmdat&0x38); + pc-=3; + x86illegal(); + break; + } + break; + + case 2: /*LAR*/ + NOTRM + fetchea2(); + tempw=geteaw(); if (abrt) break; +// pclog("LAR seg %04X\n",tempw); + + if (!(tempw&0xFFFC)) { flags&=~Z_FLAG; break; } /*Null selector*/ + tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); + if (tempi) + { + cpl_override=1; + tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); + cpl_override=0; + if (abrt) break; + } + flags&=~Z_FLAG; +// pclog("tempw2 %04X %i %04X %04X\n",tempw2,tempi,ldt.limit,gdt.limit); + if ((tempw2&0x1F00)==0x000) tempi=0; + if ((tempw2&0x1F00)==0x800) tempi=0; + if ((tempw2&0x1F00)==0xA00) tempi=0; + if ((tempw2&0x1F00)==0xD00) tempi=0; + if ((tempw2&0x1C00)<0x1C00) /*Exclude conforming code segments*/ + { + tempw3=(tempw2>>13)&3; + if (tempw3>13)&3; + if (tempw3>31) flushmmucache(); + if ((regs[rm].l^cr0) & 0x80000001) flushmmucache(); + cr0=regs[rm].l;//&~2; + if (cpu_16bitbus) cr0 |= 0x10; +// if (cs<0xF0000 && cr0&1) output=3; + if (cr0&0x80000000) + { + } + else mmu_perm=4; + break; + case 2: + cr2=regs[rm].l; + break; + case 3: + cr3=regs[rm].l&~0xFFF; +// pclog("Loading CR3 with %08X at %08X:%08X\n",cr3,cs,pc); +// if (pc==0x204) output=3; + flushmmucache(); + break; + default: + pclog("Bad load CR%i\n",reg); + pc=oldpc; + x86illegal(); + break; + } + cycles-=10; + break; + case 0x23: /*MOV DRx,reg32*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL,0); + break; + } + fetchea2(); + cycles-=6; + break; + case 0x24: /*MOV reg32,TRx*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL,0); + break; + } + fetchea2(); + regs[rm].l=0; + cycles-=6; + break; + case 0x26: /*MOV TRx,reg32*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL,0); + break; + } + fetchea2(); + cycles-=6; + break; + + case 0x32: x86illegal(); break; + + case 0x80: /*JO*/ + tempw=getword2f(); + if (flags&V_FLAG) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x81: /*JNO*/ + tempw=getword2f(); + if (!(flags&V_FLAG)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x82: /*JB*/ + tempw=getword2f(); + if (flags&C_FLAG) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x83: /*JNB*/ + tempw=getword2f(); + if (!(flags&C_FLAG)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x84: /*JE*/ + tempw=getword2f(); + if (flags&Z_FLAG) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x85: /*JNE*/ + tempw=getword2f(); + if (!(flags&Z_FLAG)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x86: /*JBE*/ + tempw=getword2f(); + if (flags&(C_FLAG|Z_FLAG)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x87: /*JNBE*/ + tempw=getword2f(); + if (!(flags&(C_FLAG|Z_FLAG))) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x88: /*JS*/ + tempw=getword2f(); + if (flags&N_FLAG) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x89: /*JNS*/ + tempw=getword2f(); + if (!(flags&N_FLAG)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x8A: /*JP*/ + tempw=getword2f(); + if (flags&P_FLAG) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x8B: /*JNP*/ + tempw=getword2f(); + if (!(flags&P_FLAG)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x8C: /*JL*/ + tempw=getword2f(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x8D: /*JNL*/ + tempw=getword2f(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x8E: /*JLE*/ + tempw=getword2f(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + case 0x8F: /*JNLE*/ + tempw=getword2f(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { pc+=(int16_t)tempw; cycles-=timing_bt; } + cycles -= timing_bnt; + break; + + case 0x90: /*SETO*/ + fetchea2(); + seteab((flags&V_FLAG)?1:0); + cycles-=4; + break; + case 0x91: /*SETNO*/ + fetchea2(); + seteab((flags&V_FLAG)?0:1); + cycles-=4; + break; + case 0x92: /*SETC*/ + fetchea2(); + seteab((flags&C_FLAG)?1:0); + cycles-=4; + break; + case 0x93: /*SETAE*/ + fetchea2(); + seteab((flags&C_FLAG)?0:1); + cycles-=4; + break; + case 0x94: /*SETZ*/ + fetchea2(); + seteab((flags&Z_FLAG)?1:0); + cycles-=4; + break; + case 0x95: /*SETNZ*/ + fetchea2(); + seteab((flags&Z_FLAG)?0:1); + cycles-=4; + break; + case 0x96: /*SETBE*/ + fetchea2(); + seteab((flags&(C_FLAG|Z_FLAG))?1:0); + cycles-=4; + break; + case 0x97: /*SETNBE*/ + fetchea2(); + seteab((flags&(C_FLAG|Z_FLAG))?0:1); + cycles-=4; + break; + case 0x98: /*SETS*/ + fetchea2(); + seteab((flags&N_FLAG)?1:0); + cycles-=4; + break; + case 0x99: /*SETNS*/ + fetchea2(); + seteab((flags&N_FLAG)?0:1); + cycles-=4; + break; + case 0x9A: /*SETP*/ + fetchea2(); + seteab((flags&P_FLAG)?1:0); + cycles-=4; + break; + case 0x9B: /*SETNP*/ + fetchea2(); + seteab((flags&P_FLAG)?0:1); + cycles-=4; + break; + case 0x9C: /*SETL*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab(temp^temp2); + cycles-=4; + break; + case 0x9D: /*SETGE*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab((temp^temp2)?0:1); + cycles-=4; + break; + case 0x9E: /*SETLE*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab(((temp^temp2) || (flags&Z_FLAG))?1:0); + cycles-=4; + break; + case 0x9F: /*SETNLE*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab(((temp^temp2) || (flags&Z_FLAG))?0:1); + cycles-=4; + break; + + case 0xA0: /*PUSH FS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,FS); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),FS); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0xA1: /*POP FS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_fs); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_fs); if (abrt) break; + SP+=2; + } + cycles-=(is486)?3:7; + break; + case 0xA3: /*BT r16*/ + fetchea2(); + eaaddr+=((regs[reg].w/16)*2); eal_r = 0; + tempw=geteaw(); if (abrt) break; + if (tempw&(1<<(regs[reg].w&15))) flags|=C_FLAG; + else flags&=~C_FLAG; + cycles-=3; + break; + case 0xA4: /*SHLD imm*/ + fetchea2(); + temp=readmemb(cs,pc)&31; pc++; + if (temp) + { + tempw=geteaw(); if (abrt) break; + tempc=((tempw<<(temp-1))&0x8000)?1:0; + templ=(tempw<<16)|regs[reg].w; + if (temp<=16) tempw=templ>>(16-temp); + else tempw=(templ<>16; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + case 0xA5: /*SHLD CL*/ + fetchea2(); + temp=CL&31; + if (temp) + { + tempw=geteaw(); if (abrt) break; + tempc=((tempw<<(temp-1))&0x8000)?1:0; + templ=(tempw<<16)|regs[reg].w; + if (temp<=16) tempw=templ>>(16-temp); + else tempw=(templ<>16; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + case 0xA8: /*PUSH GS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,GS); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),GS); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0xA9: /*POP GS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_gs); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_gs); if (abrt) break; + SP+=2; + } + cycles-=(is486)?3:7; + break; + case 0xAB: /*BTS r16*/ + fetchea2(); + eaaddr+=((regs[reg].w/16)*2); eal_r = eal_w = 0; + tempw=geteaw(); if (abrt) break; + tempc=(tempw&(1<<(regs[reg].w&15)))?1:0; + tempw|=(1<<(regs[reg].w&15)); + seteaw(tempw); if (abrt) break; + if (tempc) flags|=C_FLAG; + else flags&=~C_FLAG; + cycles-=6; + break; + case 0xAC: /*SHRD imm*/ + fetchea2(); + temp=readmemb(cs,pc)&31; pc++; + if (temp) + { + tempw=geteaw(); if (abrt) break; + tempc=(tempw>>(temp-1))&1; + templ=tempw|(regs[reg].w<<16); + tempw=templ>>temp; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + case 0xAD: /*SHRD CL*/ + fetchea2(); + temp=CL&31; + if (temp) + { + tempw=geteaw(); if (abrt) break; + tempc=(tempw>>(temp-1))&1; + templ=tempw|(regs[reg].w<<16); + tempw=templ>>temp; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + + case 0xAF: /*IMUL reg16,rm16*/ + fetchea2(); + templ=(int32_t)(int16_t)regs[reg].w*(int32_t)(int16_t)geteaw(); + if (abrt) break; + regs[reg].w=templ&0xFFFF; + if ((templ>>16) && (templ>>16)!=0xFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + cycles-=18; + break; + + case 0xB0: /*CMPXCHG rm8, reg8*/ + if (!is486) goto inv16; + fetchea2(); + temp = geteab(); + setsub8(AL, temp); + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + cycles -= (mod == 3) ? 6 : 10; + break; + case 0xB1: /*CMPXCHG rm16, reg16*/ + if (!is486) goto inv16; + fetchea2(); + tempw = geteaw(); + setsub16(AX, tempw); + if (AX == tempw) seteaw(regs[reg].w); + else AX = tempw; + cycles -= (mod == 3) ? 6 : 10; + break; + + case 0xB3: /*BTR r16*/ + fetchea2(); + eaaddr+=((regs[reg].w/16)*2); eal_r = eal_w = 0; + tempw=geteaw(); if (abrt) break; + tempc=tempw&(1<<(regs[reg].w&15)); + tempw&=~(1<<(regs[reg].w&15)); + seteaw(tempw); if (abrt) break; + if (tempc) flags|=C_FLAG; + else flags&=~C_FLAG; + cycles-=6; + break; + + case 0xB2: /*LSS*/ + fetchea2(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+2)); if (abrt) break; + loadseg(tempw,&_ss); if (abrt) break; + regs[reg].w=tempw2; + oldss=ss; + cycles-=7; + break; + case 0xB4: /*LFS*/ + fetchea2(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+2)); if (abrt) break; + loadseg(tempw,&_fs); if (abrt) break; + regs[reg].w=tempw2; + cycles-=7; + break; + case 0xB5: /*LGS*/ + fetchea2(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+2)); if (abrt) break; + loadseg(tempw,&_gs); if (abrt) break; + regs[reg].w=tempw2; + cycles-=7; + break; + + case 0xB6: /*MOVZX b*/ + fetchea2(); + tempw=geteab(); if (abrt) break; + regs[reg].w=tempw; + cycles-=3; + break; + case 0xB7: /*MOVZX w*/ + fetchea2(); /*Slightly pointless?*/ + tempw=geteaw(); if (abrt) break; + regs[reg].w=tempw; + cycles-=3; + break; + case 0xBE: /*MOVSX b*/ + fetchea2(); + tempw=geteab(); if (abrt) break; + if (tempw&0x80) tempw|=0xFF00; + regs[reg].w=tempw; + cycles-=3; + break; + + case 0xBA: /*MORE?!?!?!*/ + fetchea2(); + switch (rmdat&0x38) + { + case 0x20: /*BT w,imm*/ + tempw=geteaw(); + temp=readmemb(cs,pc); pc++; if (abrt) break; + if (tempw&(1<= 0; tempi--) + { + cycles -= 3; + if (tempw & (1 << tempi)) + { + flags &= ~Z_FLAG; + regs[reg].w = tempi; + break; + } + } + } + cycles -= (is486) ? 6 : 10; + break; + + case 0xA2: /*CPUID*/ + if (CPUID) + { + cpu_CPUID(); + cycles-=9; + break; + } + goto inv16; + + case 0xC0: /*XADD b*/ + pclog("XADDb 16\n"); + fetchea2(); + temp=geteab(); if (abrt) break; + seteab(temp+getr8(reg)); if (abrt) break; + setadd8(temp,getr8(reg)); + setr8(reg,temp); + break; + case 0xC1: /*XADD w*/ + pclog("XADDw 16\n"); + fetchea2(); + tempw=geteaw(); if (abrt) break; + seteaw(tempw+regs[reg].w); if (abrt) break; + setadd16(tempw,regs[reg].w); + regs[reg].w=tempw; + break; + + case 0xA6: /*XBTS/CMPXCHG486*/ + pclog("CMPXCHG486\n"); +// output=1; + case 0xFF: /*Invalid - Windows 3.1 syscall trap?*/ + inv16: + pc-=2; + if (msw&1) + { + pmodeint(6,0); + } + else + { + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + } + addr=6<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + cycles-=70; + break; + + default: + pclog("Bad 16-bit 0F opcode %02X 386 %i\n",temp,ins); + pc=oldpc; + x86illegal(); + break; + } + break; + + case 0x10F: case 0x30F: + temp=fetchdat&0xFF/*readmemb(cs+pc)*/; pc++; + opcode2=temp; + switch (temp) + { + case 0: + if (!(cr0&1) || (eflags&VM_FLAG)) goto inv32; + fetchea2(); +// pclog("32-bit op %02X\n",rmdat&0x38); + switch (rmdat&0x38) + { + case 0x00: /*SLDT*/ + NOTRM + seteaw(ldt.seg); + cycles-=4; + break; + case 0x08: /*STR*/ + NOTRM + seteaw(tr.seg); + cycles-=4; + break; + case 0x10: /*LLDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LLDT32!\n"); + x86gpf(NULL,0); + break; + } + NOTRM + ldt.seg=geteaw(); if (abrt) break; + templ=(ldt.seg&~7)+gdt.base; + templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); + templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + if (abrt) break; + ldt.limit=templ3; + ldt.base=templ2; + ldt.access=readmemb(0,templ+6); + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } +// /*if (output==3) */pclog("LLDT32 %04X %08X %04X\n",ldt.seg,ldt.base,ldt.limit,readmeml(0,templ),readmeml(0,templ+4)); + cycles-=20; + break; + case 0x18: /*LTR*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LTR32!\n"); + x86gpf(NULL,0); + break; + } + NOTRM + tempw=geteaw(); if (abrt) break; + tr.seg=tempw; + templ=(tempw&~7)+gdt.base; + templ3=readmemw(0,templ)+((readmemb(0,templ+6)&0xF)<<16); + templ2=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + temp=readmemb(0,templ+5); + if (abrt) break; + tr.seg=tempw; + tr.limit=templ3; + tr.access=readmemb(0,templ+6); + if (readmemb(0,templ+6)&0x80) + { + tr.limit<<=12; + tr.limit|=0xFFF; + } + tr.base=templ2; +// pclog("TR base = %08X\n",templ2); + tr.access=temp; + cycles-=20; + break; + + case 0x20: /*VERR*/ + NOTRM + tempw=geteaw(); if (abrt) break; + flags&=~Z_FLAG; + if (!(tempw&0xFFFC)) break; /*Null selector*/ + cpl_override=1; + tempi=(tempw&~7)<((tempw&4)?ldt.limit:gdt.limit); + tempw2=readmemw(0,((tempw&4)?ldt.base:gdt.base)+(tempw&~7)+4); + cpl_override=0; + if (abrt) break; + if (!(tempw2&0x1000)) tempi=0; + if ((tempw2&0xC00)!=0xC00) /*Exclude conforming code segments*/ + { + tempw3=(tempw2>>13)&3; /*Check permissions*/ + if (tempw3>13)&3; /*Check permissions*/ + if (tempw3>13)&3; + if (tempw3>13)&3; + if (tempw3>31) flushmmucache(); + if ((regs[rm].l^cr0) & 0x80000001) flushmmucache(); + cr0=regs[rm].l;//&~2; + if (cpu_16bitbus) cr0 |= 0x10; +// if (cs<0xF0000 && cr0&1) output=3; + if (cr0&0x80000000) + { + } + else mmu_perm=4; + break; + case 2: + cr2=regs[rm].l; + break; + case 3: + cr3=regs[rm].l&~0xFFF; +// pclog("Loading CR3 with %08X at %08X:%08X\n",cr3,cs,pc); + flushmmucache(); + break; + default: + pclog("Bad load CR%i\n",reg); + pc=oldpc; + x86illegal(); + break; + } + cycles-=10; + break; + case 0x23: /*MOV DRx,reg32*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL,0); + break; + } + fetchea2(); + cycles-=6; + break; + case 0x24: /*MOV reg32,TRx*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL,0); + break; + } + fetchea2(); + regs[rm].l=0; + cycles-=6; + break; + case 0x26: /*MOV TRx,reg32*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL,0); + break; + } + fetchea2(); + cycles-=6; + break; + + case 0x80: /*JO*/ + templ=getlong(); if (abrt) break; + if (flags&V_FLAG) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x81: /*JNO*/ + templ=getlong(); if (abrt) break; + if (!(flags&V_FLAG)) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x82: /*JB*/ + templ=getlong(); if (abrt) break; + if (flags&C_FLAG) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x83: /*JNB*/ + templ=getlong(); if (abrt) break; + if (!(flags&C_FLAG)) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x84: /*JE*/ + templ=getlong(); if (abrt) break; + if (flags&Z_FLAG) pc+=templ; + cycles-=4; + break; + case 0x85: /*JNE*/ + templ=getlong(); if (abrt) break; + if (!(flags&Z_FLAG)) pc+=templ; + cycles-=4; + break; + case 0x86: /*JBE*/ + templ=getlong(); if (abrt) break; + if (flags&(C_FLAG|Z_FLAG)) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x87: /*JNBE*/ + templ=getlong(); if (abrt) break; + if (!(flags&(C_FLAG|Z_FLAG))) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x88: /*JS*/ + templ=getlong(); if (abrt) break; + if (flags&N_FLAG) pc+=templ; + cycles-=4; + break; + case 0x89: /*JNS*/ + templ=getlong(); if (abrt) break; + if (!(flags&N_FLAG)) pc+=templ; + cycles-=4; + break; + case 0x8A: /*JP*/ + templ=getlong(); if (abrt) break; + if (flags&P_FLAG) pc+=templ; + cycles-=4; + break; + case 0x8B: /*JNP*/ + templ=getlong(); if (abrt) break; + if (!(flags&P_FLAG)) pc+=templ; + cycles-=4; + break; + case 0x8C: /*JL*/ + templ=getlong(); if (abrt) break; + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x8D: /*JNL*/ + templ=getlong(); if (abrt) break; + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x8E: /*JLE*/ + templ=getlong(); if (abrt) break; + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + case 0x8F: /*JNLE*/ + templ=getlong(); if (abrt) break; + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { pc+=templ; cycles-=((is486)?2:4); } + cycles-=((is486)?1:3); + break; + + case 0x90: /*SETO*/ + fetchea2(); + seteab((flags&V_FLAG)?1:0); + cycles-=4; + break; + case 0x91: /*SETNO*/ + fetchea2(); + seteab((flags&V_FLAG)?0:1); + cycles-=4; + break; + case 0x92: /*SETC*/ + fetchea2(); + seteab((flags&C_FLAG)?1:0); + cycles-=4; + break; + case 0x93: /*SETAE*/ + fetchea2(); + seteab((flags&C_FLAG)?0:1); + cycles-=4; + break; + case 0x94: /*SETZ*/ + fetchea2(); + seteab((flags&Z_FLAG)?1:0); + cycles-=4; + break; + case 0x95: /*SETNZ*/ + fetchea2(); + seteab((flags&Z_FLAG)?0:1); + cycles-=4; + break; + case 0x96: /*SETBE*/ + fetchea2(); + seteab((flags&(C_FLAG|Z_FLAG))?1:0); + cycles-=4; + break; + case 0x97: /*SETNBE*/ + fetchea2(); + seteab((flags&(C_FLAG|Z_FLAG))?0:1); + cycles-=4; + break; + case 0x98: /*SETS*/ + fetchea2(); + seteab((flags&N_FLAG)?1:0); + cycles-=4; + break; + case 0x99: /*SETNS*/ + fetchea2(); + seteab((flags&N_FLAG)?0:1); + cycles-=4; + break; + case 0x9A: /*SETP*/ + fetchea2(); + seteab((flags&P_FLAG)?1:0); + cycles-=4; + break; + case 0x9B: /*SETNP*/ + fetchea2(); + seteab((flags&P_FLAG)?0:1); + cycles-=4; + break; + case 0x9C: /*SETL*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab(temp^temp2); + cycles-=4; + break; + case 0x9D: /*SETGE*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab((temp^temp2)?0:1); + cycles-=4; + break; + case 0x9E: /*SETLE*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab(((temp^temp2) || (flags&Z_FLAG))?1:0); + cycles-=4; + break; + case 0x9F: /*SETNLE*/ + fetchea2(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + seteab(((temp^temp2) || (flags&Z_FLAG))?0:1); + cycles-=4; + break; + + case 0xA0: /*PUSH FS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,FS); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),FS); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + case 0xA1: /*POP FS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_fs); if (abrt) break; + ESP+=4; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_fs); if (abrt) break; + SP+=4; + } + cycles-=(is486)?3:7; + break; + case 0xA8: /*PUSH GS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,GS); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),GS); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + case 0xA9: /*POP GS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_gs); if (abrt) break; + ESP+=4; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_gs); if (abrt) break; + SP+=4; + } + cycles-=(is486)?3:7; + break; + + case 0xA3: /*BT r32*/ + fetchea2(); + eaaddr+=((regs[reg].l/32)*4); eal_r = 0; + templ=geteal(); if (abrt) break; + if (templ&(1<<(regs[reg].l&31))) flags|=C_FLAG; + else flags&=~C_FLAG; + cycles-=3; + break; + case 0xA4: /*SHLD imm*/ + fetchea2(); + temp=readmemb(cs,pc)&31; pc++; + if (temp) + { + templ=geteal(); if (abrt) break; + tempc=((templ<<(temp-1))&0x80000000)?1:0; + templ=(templ<>(32-temp)); + seteal(templ); if (abrt) break; + setznp32(templ); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + case 0xA5: /*SHLD CL*/ + fetchea2(); + temp=CL&31; + if (temp) + { + templ=geteal(); if (abrt) break; + tempc=((templ<<(temp-1))&0x80000000)?1:0; + templ=(templ<>(32-temp)); + seteal(templ); if (abrt) break; + setznp32(templ); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + case 0xAB: /*BTS r32*/ + fetchea2(); + eaaddr+=((regs[reg].l/32)*4); eal_r = eal_w = 0; + templ=geteal(); if (abrt) break; + tempc=(templ&(1<<(regs[reg].l&31)))?1:0; + templ|=(1<<(regs[reg].l&31)); + seteal(templ); if (abrt) break; + if (tempc) flags|=C_FLAG; + else flags&=~C_FLAG; + cycles-=6; + break; + case 0xAC: /*SHRD imm*/ + fetchea2(); + temp=readmemb(cs,pc)&31; pc++; + if (temp) + { + templ=geteal(); if (abrt) break; + tempc=(templ>>(temp-1))&1; + templ=(templ>>temp)|(regs[reg].l<<(32-temp)); + seteal(templ); if (abrt) break; + setznp32(templ); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + case 0xAD: /*SHRD CL*/ + fetchea2(); + temp=CL&31; + if (temp) + { + templ=geteal(); if (abrt) break; + tempc=(templ>>(temp-1))&1; + templ=(templ>>temp)|(regs[reg].l<<(32-temp)); + seteal(templ); if (abrt) break; + setznp32(templ); + if (tempc) flags|=C_FLAG; + } + cycles-=3; + break; + + case 0xAF: /*IMUL reg32,rm32*/ + fetchea2(); + temp64=(int64_t)(int32_t)regs[reg].l*(int64_t)(int32_t)geteal(); + if (abrt) break; + regs[reg].l=temp64&0xFFFFFFFF; + if ((temp64>>32) && (temp64>>32)!=0xFFFFFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + cycles-=30; + break; + + case 0xB0: /*CMPXCHG rm8, reg8*/ + if (!is486) goto inv32; + fetchea2(); + temp = geteab(); + setsub8(AL, temp); + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + cycles -= (mod == 3) ? 6 : 10; + break; + case 0xB1: /*CMPXCHG rm32, reg32*/ + if (!is486) goto inv32; + fetchea2(); + templ = geteal(); + setsub32(EAX, templ); + if (EAX == templ) seteal(regs[reg].l); + else EAX = templ; + cycles -= (mod == 3) ? 6 : 10; + break; + + case 0xB3: /*BTR r32*/ + fetchea2(); + eaaddr+=((regs[reg].l/32)*4); eal_r = eal_w = 0; + templ=geteal(); if (abrt) break; + tempc=(templ&(1<<(regs[reg].l&31)))?1:0; + templ&=~(1<<(regs[reg].l&31)); + seteal(templ); if (abrt) break; + if (tempc) flags|=C_FLAG; + else flags&=~C_FLAG; + cycles-=6; + break; + + case 0xB2: /*LSS*/ + fetchea2(); + templ=readmeml(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+4)); if (abrt) break; + loadseg(tempw,&_ss); if (abrt) break; + regs[reg].l=templ; + oldss=ss; + cycles-=7; + break; + case 0xB4: /*LFS*/ + fetchea2(); + templ=readmeml(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+4)); if (abrt) break; + loadseg(tempw,&_fs); if (abrt) break; + regs[reg].l=templ; + cycles-=7; + break; + case 0xB5: /*LGS*/ + fetchea2(); + templ=readmeml(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+4)); if (abrt) break; + loadseg(tempw,&_gs); if (abrt) break; + regs[reg].l=templ; + cycles-=7; + break; + + case 0xB6: /*MOVZX b*/ + fetchea2(); + templ=geteab(); if (abrt) break; + regs[reg].l=templ; + cycles-=3; + break; + case 0xB7: /*MOVZX w*/ + fetchea2(); + templ=geteaw(); if (abrt) break; + regs[reg].l=templ; + cycles-=3; +// if (pc==0x30B) output=1; + break; + + case 0xBA: /*MORE?!?!?!*/ + fetchea2(); + switch (rmdat&0x38) + { + case 0x20: /*BT l,imm*/ + templ=geteal(); + temp=readmemb(cs,pc); pc++; + if (abrt) break; + if (templ&(1<=0;tempi--) + { + cycles -= 3; + if (templ&(1<>24)|((regs[temp&7].l>>8)&0xFF00)|((regs[temp&7].l<<8)&0xFF0000)|((regs[temp&7].l<<24)&0xFF000000); + cycles--; + break; + + case 0xA2: /*CPUID*/ + if (CPUID) + { + cpu_CPUID(); + cycles-=9; + break; + } + goto inv32; + + case 0xFF: + inv32: + pclog("INV32!\n"); + default: + pclog("Bad 32-bit 0F opcode %02X 386\n",temp); + pc=oldpc; + x86illegal(); + break; + } + break; + + case 0x10: case 0x110: case 0x210: case 0x310: /*ADC 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm); + temp2 = getr8(reg); + setadc8(temp, temp2); + setr8(rm, temp + temp2 + tempc); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp + temp2 + tempc); if (abrt) break; + setadc8(temp, temp2); + cycles -= timing_mr; + } + break; + case 0x11: case 0x211: /*ADC 16,reg*/ + fetchea(); + if (mod == 3) + { + setadc16(regs[rm].w, regs[reg].w); + regs[rm].w += regs[reg].w + tempc; + cycles -= timing_rr; + } + else + { + tempw = geteaw(); if (abrt) break; + tempw2 = regs[reg].w; + seteaw(tempw + tempw2 + tempc); if (abrt) break; + setadc16(tempw, tempw2); + cycles -= timing_mr; + } + break; + case 0x111: case 0x311: /*ADC 32,reg*/ + fetchea(); + if (mod == 3) + { + setadc32(regs[rm].l, regs[reg].l); + regs[rm].l += regs[reg].l + tempc; + cycles -= timing_rr; + } + else + { + templ = geteal(); if (abrt) break; + templ2 = regs[reg].l; + seteal(templ + templ2 + tempc); if (abrt) break; + setadc32(templ, templ2); + cycles -= timing_mrl; + } + break; + case 0x12: case 0x112: case 0x212: case 0x312: /*ADC reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + setadc8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp+tempc); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x13: case 0x213: /*ADC reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setadc16(regs[reg].w,tempw); + regs[reg].w+=tempw+tempc; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x113: case 0x313: /*ADC reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + setadc32(regs[reg].l,templ); + regs[reg].l+=templ+tempc; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x14: case 0x114: case 0x214: case 0x314: /*ADC AL,#8*/ + tempw=getbytef(); + setadc8(AL,tempw); + AL+=tempw+tempc; + cycles -= timing_rr; + break; + case 0x15: case 0x215: /*ADC AX,#16*/ + tempw=getwordf(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles -= timing_rr; + break; + case 0x115: case 0x315: /*ADC EAX,#32*/ + templ=getlong(); if (abrt) break; + setadc32(EAX,templ); + EAX+=templ+tempc; + cycles -= timing_rr; + break; + + case 0x16: case 0x216: /*PUSH SS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,SS); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),SS); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0x116: case 0x316: /*PUSH SS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,SS); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),SS); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + case 0x17: case 0x217: /*POP SS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_ss); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_ss); if (abrt) break; + SP+=2; + } + cycles-=(is486)?3:7; + break; + case 0x117: case 0x317: /*POP SS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_ss); if (abrt) break; + ESP+=4; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_ss); if (abrt) break; + SP+=4; + } + cycles-=(is486)?3:7; + break; + + case 0x18: case 0x118: case 0x218: case 0x318: /*SBB 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm); + temp2 = getr8(reg); + setsbc8(temp, temp2); + setr8(rm, temp - (temp2 + tempc)); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp - (temp2 + tempc)); if (abrt) break; + setsbc8(temp, temp2); + cycles -= timing_mr; + } + break; + case 0x19: case 0x219: /*SBB 16,reg*/ + fetchea(); + if (mod == 3) + { + setsbc16(regs[rm].w, regs[reg].w); + regs[rm].w -= (regs[reg].w + tempc); + cycles -= timing_rr; + } + else + { + tempw = geteaw(); if (abrt) break; + tempw2 = regs[reg].w; + seteaw(tempw - (tempw2 + tempc)); if (abrt) break; + setsbc16(tempw, tempw2); + cycles -= timing_mr; + } + break; + case 0x119: case 0x319: /*SBB 32,reg*/ + fetchea(); + if (mod == 3) + { + setsbc32(regs[rm].l, regs[reg].l); + regs[rm].l -= (regs[reg].l + tempc); + cycles -= timing_rr; + } + else + { + templ = geteal(); if (abrt) break; + templ2 = regs[reg].l; + seteal(templ - (templ2 + tempc)); if (abrt) break; + setsbc32(templ, templ2); + cycles -= timing_mrl; + } + break; + case 0x1A: case 0x11A: case 0x21A: case 0x31A: /*SBB reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + setsbc8(getr8(reg),temp); + setr8(reg,getr8(reg)-(temp+tempc)); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x1B: case 0x21B: /*SBB reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=regs[reg].w; + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + regs[reg].w=tempw2; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x11B: case 0x31B: /*SBB reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ2=regs[reg].l; + setsbc32(templ2,templ); + templ2-=(templ+tempc); + regs[reg].l=templ2; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x1C: case 0x11C: case 0x21C: case 0x31C: /*SBB AL,#8*/ + temp=getbytef(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=(is486)?1:2; + break; + case 0x1D: case 0x21D: /*SBB AX,#16*/ + tempw=getwordf(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=(is486)?1:2; + break; + case 0x11D: case 0x31D: /*SBB AX,#32*/ + templ=getlong(); if (abrt) break; + setsbc32(EAX,templ); + EAX-=(templ+tempc); + cycles-=(is486)?1:2; + break; + + case 0x1E: case 0x21E: /*PUSH DS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,DS); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),DS); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0x11E: case 0x31E: /*PUSH DS*/ + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,DS); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),DS); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + case 0x1F: case 0x21F: /*POP DS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_ds); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_ds); if (abrt) break; + SP+=2; + } + cycles-=(is486)?3:7; + break; + case 0x11F: case 0x31F: /*POP DS*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + loadseg(tempw,&_ds); if (abrt) break; + ESP+=4; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + loadseg(tempw,&_ds); if (abrt) break; + SP+=4; + } + cycles-=(is486)?3:7; + break; + + case 0x20: case 0x120: case 0x220: case 0x320: /*AND 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm) & getr8(reg); + setr8(rm, temp); + setznp8(temp); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp &= getr8(reg); + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= timing_mr; + } + break; + case 0x21: case 0x221: /*AND 16,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].w &= regs[reg].w; + setznp16(regs[rm].w); + cycles -= timing_rr; + } + else + { + tempw = geteaw() & regs[reg].w; if (abrt) break; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= timing_mr; + } + break; + case 0x121: case 0x321: /*AND 32,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].l &= regs[reg].l; + setznp32(regs[rm].l); + cycles -= timing_rr; + } + else + { + templ = geteal() & regs[reg].l; if (abrt) break; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= timing_mrl; + } + break; + case 0x22: case 0x122: case 0x222: case 0x322: /*AND reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp&=getr8(reg); + setznp8(temp); + setr8(reg,temp); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x23: case 0x223: /*AND reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw&=regs[reg].w; + setznp16(tempw); + regs[reg].w=tempw; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x123: case 0x323: /*AND reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ&=regs[reg].l; + setznp32(templ); + regs[reg].l=templ; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x24: case 0x124: case 0x224: case 0x324: /*AND AL,#8*/ + AL&=getbytef(); + setznp8(AL); + cycles -= timing_rr; + break; + case 0x25: case 0x225: /*AND AX,#16*/ + AX&=getwordf(); + setznp16(AX); + cycles -= timing_rr; + break; + case 0x125: case 0x325: /*AND EAX,#32*/ + templ=getlong(); if (abrt) break; + EAX&=templ; + setznp32(EAX); + cycles -= timing_rr; + break; + + case 0x26: case 0x126: case 0x226: case 0x326: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + rds=ES; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x27: case 0x127: case 0x227: case 0x327: /*DAA*/ + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + tempi = ((uint16_t)AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags |= tempw; + cycles-=4; + break; + + case 0x28: case 0x128: case 0x228: case 0x328: /*SUB 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm); + temp2 = getr8(reg); + setsub8(temp, temp2); + setr8(rm, temp - temp2); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp2 = getr8(reg); + seteab(temp - temp2); if (abrt) break; + setsub8(temp, temp2); + cycles -= timing_mr; + } + break; + case 0x29: case 0x229: /*SUB 16,reg*/ + fetchea(); + if (mod == 3) + { + setsub16(regs[rm].w, regs[reg].w); + regs[rm].w -= regs[reg].w; + cycles -= timing_rr; + } + else + { + tempw = geteaw(); if (abrt) break; + seteaw(tempw - regs[reg].w); if (abrt) break; + setsub16(tempw, regs[reg].w); + cycles -= timing_mr; + } + break; + case 0x129: case 0x329: /*SUB 32,reg*/ + fetchea(); + if (mod == 3) + { + setsub32(regs[rm].l, regs[reg].l); + regs[rm].l -= regs[reg].l; + cycles -= timing_rr; + } + else + { + templ = geteal(); if (abrt) break; + seteal(templ - regs[reg].l); if (abrt) break; + setsub32(templ, regs[reg].l); + cycles -= timing_mrl; + } + break; + case 0x2A: case 0x12A: case 0x22A: case 0x32A: /*SUB reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + setsub8(getr8(reg),temp); + setr8(reg,getr8(reg)-temp); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x2B: case 0x22B: /*SUB reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setsub16(regs[reg].w,tempw); + regs[reg].w-=tempw; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x12B: case 0x32B: /*SUB reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + setsub32(regs[reg].l,templ); + regs[reg].l-=templ; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x2C: case 0x12C: case 0x22C: case 0x32C: /*SUB AL,#8*/ + temp=getbytef(); + setsub8(AL,temp); + AL-=temp; + cycles -= timing_rr; + break; + case 0x2D: case 0x22D: /*SUB AX,#16*/ + tempw=getwordf(); + setsub16(AX,tempw); + AX-=tempw; + cycles -= timing_rr; + break; + case 0x12D: case 0x32D: /*SUB EAX,#32*/ + templ=getlong(); if (abrt) break; + setsub32(EAX,templ); + EAX-=templ; + cycles -= timing_rr; + break; + + case 0x2E: case 0x12E: case 0x22E: case 0x32E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + rds=CS; + ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: case 0x12F: case 0x22F: case 0x32F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags |= tempw; + cycles-=4; + break; + + case 0x30: case 0x130: case 0x230: case 0x330: /*XOR 8,reg*/ + fetchea(); + if (mod == 3) + { + temp = getr8(rm) ^ getr8(reg); + setr8(rm, temp); + setznp8(temp); + cycles -= timing_rr; + } + else + { + temp = geteab(); if (abrt) break; + temp ^= getr8(reg); + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= timing_mr; + } + break; + case 0x31: case 0x231: /*XOR 16,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].w ^= regs[reg].w; + setznp16(regs[rm].w); + cycles -= timing_rr; + } + else + { + tempw = geteaw() ^ regs[reg].w; if (abrt) break; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= timing_mr; + } + break; + case 0x131: case 0x331: /*XOR 32,reg*/ + fetchea(); + if (mod == 3) + { + regs[rm].l ^= regs[reg].l; + setznp32(regs[rm].l); + cycles -= timing_rr; + } + else + { + templ = geteal() ^ regs[reg].l; if (abrt) break; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= timing_mrl; + } + break; + case 0x32: case 0x132: case 0x232: case 0x332: /*XOR reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp^=getr8(reg); + setznp8(temp); + setr8(reg,temp); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x33: case 0x233: /*XOR reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw^=regs[reg].w; + setznp16(tempw); + regs[reg].w=tempw; + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x133: case 0x333: /*XOR reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ^=regs[reg].l; + setznp32(templ); + regs[reg].l=templ; + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x34: case 0x134: case 0x234: case 0x334: /*XOR AL,#8*/ + AL^=getbytef(); + setznp8(AL); + cycles -= timing_rr; + break; + case 0x35: case 0x235: /*XOR AX,#16*/ + AX^=getwordf(); + setznp16(AX); + cycles -= timing_rr; + break; + case 0x135: case 0x335: /*XOR EAX,#32*/ + templ=getlong(); if (abrt) break; + EAX^=templ; + setznp32(EAX); + cycles -= timing_rr; + break; + + case 0x36: case 0x136: case 0x236: case 0x336: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + rds=SS; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x37: case 0x137: case 0x237: case 0x337: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=(is486)?3:4; + break; + + case 0x38: case 0x138: case 0x238: case 0x338: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); if (abrt) break; + setsub8(temp,getr8(reg)); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x39: case 0x239: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); if (abrt) break; +// if (output) pclog("CMP %04X %04X\n",tempw,regs[reg].w); + setsub16(tempw,regs[reg].w); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x139: case 0x339: /*CMP 32,reg*/ + fetchea(); + templ=geteal(); if (abrt) break; + setsub32(templ,regs[reg].l); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x3A: case 0x13A: case 0x23A: case 0x33A: /*CMP reg,8*/ + fetchea(); + temp=geteab(); if (abrt) break; +// if (output) pclog("CMP %02X-%02X\n",getr8(reg),temp); + setsub8(getr8(reg),temp); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x3B: case 0x23B: /*CMP reg,16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + setsub16(regs[reg].w,tempw); + cycles -= (mod == 3) ? timing_rr : timing_rm; + break; + case 0x13B: case 0x33B: /*CMP reg,32*/ + fetchea(); + templ=geteal(); if (abrt) break; + setsub32(regs[reg].l,templ); + cycles -= (mod == 3) ? timing_rr : timing_rml; + break; + case 0x3C: case 0x13C: case 0x23C: case 0x33C: /*CMP AL,#8*/ + temp=getbytef(); + setsub8(AL,temp); + cycles -= timing_rr; + break; + case 0x3D: case 0x23D: /*CMP AX,#16*/ + tempw=getwordf(); + setsub16(AX,tempw); + cycles -= timing_rr; + break; + case 0x13D: case 0x33D: /*CMP EAX,#32*/ + templ=getlong(); if (abrt) break; + setsub32(EAX,templ); + cycles -= timing_rr; + break; + + case 0x3E: case 0x13E: case 0x23E: case 0x33E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x3F: case 0x13F: case 0x23F: case 0x33F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=(is486)?3:4; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x240: case 0x241: case 0x242: case 0x243: + case 0x244: case 0x245: case 0x246: case 0x247: + setadd16nc(regs[opcode&7].w,1); + regs[opcode&7].w++; + cycles -= timing_rr; + break; + case 0x140: case 0x141: case 0x142: case 0x143: /*INC r32*/ + case 0x144: case 0x145: case 0x146: case 0x147: + case 0x340: case 0x341: case 0x342: case 0x343: + case 0x344: case 0x345: case 0x346: case 0x347: + setadd32nc(regs[opcode&7].l,1); + regs[opcode&7].l++; + cycles -= timing_rr; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + case 0x248: case 0x249: case 0x24A: case 0x24B: + case 0x24C: case 0x24D: case 0x24E: case 0x24F: + setsub16nc(regs[opcode&7].w,1); + regs[opcode&7].w--; + cycles -= timing_rr; + break; + case 0x148: case 0x149: case 0x14A: case 0x14B: /*DEC r32*/ + case 0x14C: case 0x14D: case 0x14E: case 0x14F: + case 0x348: case 0x349: case 0x34A: case 0x34B: + case 0x34C: case 0x34D: case 0x34E: case 0x34F: + setsub32nc(regs[opcode&7].l,1); + regs[opcode&7].l--; + cycles -= timing_rr; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x250: case 0x251: case 0x252: case 0x253: + case 0x254: case 0x255: case 0x256: case 0x257: + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,regs[opcode&7].w); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,(SP-2)&0xFFFF,regs[opcode&7].w); if (abrt) break; + SP-=2; + } +// if (pc>=0x1A1BED && pc<0x1A1C00) pclog("PUSH %02X! %08X\n",opcode,ESP); + cycles-=(is486)?1:2; + break; + case 0x150: case 0x151: case 0x152: case 0x153: /*PUSH r32*/ + case 0x154: case 0x155: case 0x156: case 0x157: + case 0x350: case 0x351: case 0x352: case 0x353: + case 0x354: case 0x355: case 0x356: case 0x357: + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,regs[opcode&7].l); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,(SP-4)&0xFFFF,regs[opcode&7].l); if (abrt) break; + SP-=4; + } + cycles-=(is486)?1:2; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + case 0x258: case 0x259: case 0x25A: case 0x25B: + case 0x25C: case 0x25D: case 0x25E: case 0x25F: + if (ssegs) ss=oldss; + if (stack32) + { + ESP+=2; + tempw=readmemw(ss,ESP-2); if (abrt) { ESP-=2; break; } + } + else + { + SP+=2; + tempw=readmemw(ss,(SP-2)&0xFFFF); if (abrt) { SP-=2; break; } + } + regs[opcode&7].w=tempw; + cycles-=(is486)?1:4; + break; + case 0x158: case 0x159: case 0x15A: case 0x15B: /*POP r32*/ + case 0x15C: case 0x15D: case 0x15E: case 0x15F: + case 0x358: case 0x359: case 0x35A: case 0x35B: + case 0x35C: case 0x35D: case 0x35E: case 0x35F: + if (ssegs) ss=oldss; + if (stack32) + { + ESP+=4; + templ=readmeml(ss,ESP-4); if (abrt) { ESP-=4; break; } + } + else + { + SP+=4; + templ=readmeml(ss,(SP-4)&0xFFFF); if (abrt) { SP-=4; break; } + } + regs[opcode&7].l=templ; + cycles-=(is486)?1:4; + break; + + case 0x60: case 0x260: /*PUSHA*/ + if (stack32) + { + writememw(ss,ESP-2,AX); + writememw(ss,ESP-4,CX); + writememw(ss,ESP-6,DX); + writememw(ss,ESP-8,BX); + writememw(ss,ESP-10,SP); + writememw(ss,ESP-12,BP); + writememw(ss,ESP-14,SI); + writememw(ss,ESP-16,DI); + if (!abrt) ESP-=16; + } + else + { + writememw(ss,((SP-2)&0xFFFF),AX); + writememw(ss,((SP-4)&0xFFFF),CX); + writememw(ss,((SP-6)&0xFFFF),DX); + writememw(ss,((SP-8)&0xFFFF),BX); + writememw(ss,((SP-10)&0xFFFF),SP); + writememw(ss,((SP-12)&0xFFFF),BP); + writememw(ss,((SP-14)&0xFFFF),SI); + writememw(ss,((SP-16)&0xFFFF),DI); + if (!abrt) SP-=16; + } + cycles-=(is486)?11:18; + break; + case 0x61: case 0x261: /*POPA*/ + if (stack32) + { + DI=readmemw(ss,ESP); if (abrt) break; + SI=readmemw(ss,ESP+2); if (abrt) break; + BP=readmemw(ss,ESP+4); if (abrt) break; + BX=readmemw(ss,ESP+8); if (abrt) break; + DX=readmemw(ss,ESP+10); if (abrt) break; + CX=readmemw(ss,ESP+12); if (abrt) break; + AX=readmemw(ss,ESP+14); if (abrt) break; + ESP+=16; + } + else + { + DI=readmemw(ss,((SP)&0xFFFF)); if (abrt) break; + SI=readmemw(ss,((SP+2)&0xFFFF)); if (abrt) break; + BP=readmemw(ss,((SP+4)&0xFFFF)); if (abrt) break; + BX=readmemw(ss,((SP+8)&0xFFFF)); if (abrt) break; + DX=readmemw(ss,((SP+10)&0xFFFF)); if (abrt) break; + CX=readmemw(ss,((SP+12)&0xFFFF)); if (abrt) break; + AX=readmemw(ss,((SP+14)&0xFFFF)); if (abrt) break; + SP+=16; + } + cycles-=(is486)?9:24; + break; + case 0x160: case 0x360: /*PUSHA*/ + if (stack32) + { + writememl(ss,ESP-4,EAX); + writememl(ss,ESP-8,ECX); + writememl(ss,ESP-12,EDX); + writememl(ss,ESP-16,EBX); + writememl(ss,ESP-20,ESP); + writememl(ss,ESP-24,EBP); + writememl(ss,ESP-28,ESI); + writememl(ss,ESP-32,EDI); + if (!abrt) ESP-=32; + } + else + { + writememl(ss,((SP-4)&0xFFFF),EAX); + writememl(ss,((SP-8)&0xFFFF),ECX); + writememl(ss,((SP-12)&0xFFFF),EDX); + writememl(ss,((SP-16)&0xFFFF),EBX); + writememl(ss,((SP-20)&0xFFFF),ESP); + writememl(ss,((SP-24)&0xFFFF),EBP); + writememl(ss,((SP-28)&0xFFFF),ESI); + writememl(ss,((SP-32)&0xFFFF),EDI); + if (!abrt) SP-=32; + } + cycles-=(is486)?11:18; + break; + case 0x161: case 0x361: /*POPA*/ + if (stack32) + { + EDI=readmeml(ss,ESP); if (abrt) break; + ESI=readmeml(ss,ESP+4); if (abrt) break; + EBP=readmeml(ss,ESP+8); if (abrt) break; + EBX=readmeml(ss,ESP+16); if (abrt) break; + EDX=readmeml(ss,ESP+20); if (abrt) break; + ECX=readmeml(ss,ESP+24); if (abrt) break; + EAX=readmeml(ss,ESP+28); if (abrt) break; + ESP+=32; + } + else + { + EDI=readmeml(ss,((SP)&0xFFFF)); if (abrt) break; + ESI=readmeml(ss,((SP+4)&0xFFFF)); if (abrt) break; + EBP=readmeml(ss,((SP+8)&0xFFFF)); if (abrt) break; + EBX=readmeml(ss,((SP+16)&0xFFFF)); if (abrt) break; + EDX=readmeml(ss,((SP+20)&0xFFFF)); if (abrt) break; + ECX=readmeml(ss,((SP+24)&0xFFFF)); if (abrt) break; + EAX=readmeml(ss,((SP+28)&0xFFFF)); if (abrt) break; + SP+=32; + } + cycles-=(is486)?9:24; + break; + + case 0x62: case 0x262: /*BOUND*/ + fetchea(); + tempw=geteaw(); + tempw2=readmemw(easeg,eaaddr+2); if (abrt) break; + if (((int16_t)regs[reg].w<(int16_t)tempw) || ((int16_t)regs[reg].w>(int16_t)tempw2)) + { + x86_int(5); + } + cycles-=(is486)?7:10; + break; + case 0x162: case 0x362: /*BOUND*/ + fetchea(); + templ=geteal(); + templ2=readmeml(easeg,eaaddr+4); if (abrt) break; + if (((int32_t)regs[reg].l<(int32_t)templ) || ((int32_t)regs[reg].l>(int32_t)templ2)) + { + x86_int(5); + } + cycles-=(is486)?7:10; + break; + + + case 0x63: case 0x163: case 0x263: case 0x363: /*ARPL*/ + NOTRM + fetchea(); + tempw=geteaw(); if (abrt) break; + if ((tempw&3)<(regs[reg].w&3)) + { + tempw=(tempw&0xFFFC)|(regs[reg].w&3); + seteaw(tempw); if (abrt) break; + flags|=Z_FLAG; + } + else + flags&=~Z_FLAG; + cycles-=(is486)?9:20; + break; + case 0x64: case 0x164: case 0x264: case 0x364: /*FS:*/ + oldss=ss; + oldds=ds; + rds=FS; + ds=ss=fs; + ssegs=2; + cycles-=4; + goto opcodestart; + case 0x65: case 0x165: case 0x265: case 0x365: /*GS:*/ + oldss=ss; + oldds=ds; + rds=GS; + ds=ss=gs; + ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x66: case 0x166: case 0x266: case 0x366: /*Data size select*/ + op32=((use32&0x100)^0x100)|(op32&0x200); +// op32^=0x100; + cycles-=2; + goto opcodestart; + case 0x67: case 0x167: case 0x267: case 0x367: /*Address size select*/ + op32=((use32&0x200)^0x200)|(op32&0x100); +// op32^=0x200; + cycles-=2; + goto opcodestart; + + case 0x68: case 0x268: /*PUSH #w*/ + tempw=getword(); + if (stack32) + { + writememw(ss,ESP-2,tempw); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0x168: case 0x368: /*PUSH #l*/ + templ=getlong(); + if (stack32) + { + writememl(ss,ESP-4,templ); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),templ); if (abrt) break; + SP-=4; + } + cycles-=2; + break; + case 0x69: case 0x269: /*IMUL r16*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=getword(); if (abrt) break; + templ=((int)(int16_t)tempw)*((int)(int16_t)tempw2); + if ((templ>>16)!=0 && (templ>>16)!=0xFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + regs[reg].w=templ&0xFFFF; + cycles-=((mod==3)?14:17); + break; + case 0x169: case 0x369: /*IMUL r32*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ2=getlong(); if (abrt) break; + temp64=((int64_t)(int32_t)templ)*((int64_t)(int32_t)templ2); + if ((temp64>>32)!=0 && (temp64>>32)!=0xFFFFFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + regs[reg].l=temp64&0xFFFFFFFF; + cycles-=25; + break; + case 0x6A: case 0x26A:/*PUSH #eb*/ + tempw=readmemb(cs,pc); pc++; + if (tempw&0x80) tempw|=0xFF00; + if (output) pclog("PUSH %04X %i\n",tempw,stack32); + if (stack32) + { + writememw(ss,ESP-2,tempw); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; + SP-=2; + } + cycles-=2; + break; + case 0x16A: case 0x36A:/*PUSH #eb*/ + templ=readmemb(cs,pc); pc++; + if (templ&0x80) templ|=0xFFFFFF00; + if (output) pclog("PUSH %08X %i\n",templ,stack32); + if (stack32) + { + writememl(ss,ESP-4,templ); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),templ); if (abrt) break; + SP-=4; + } + cycles-=2; + break; +// #if 0 + case 0x6B: case 0x26B: /*IMUL r8*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=readmemb(cs,pc); pc++; if (abrt) break; + if (tempw2&0x80) tempw2|=0xFF00; + templ=((int)(int16_t)tempw)*((int)(int16_t)tempw2); +// pclog("IMULr8 %08X %08X %08X\n",tempw,tempw2,templ); + if ((templ>>16)!=0 && ((templ>>16)&0xFFFF)!=0xFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + regs[reg].w=templ&0xFFFF; + cycles-=((mod==3)?14:17); + break; + case 0x16B: case 0x36B: /*IMUL r8*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ2=readmemb(cs,pc); pc++; if (abrt) break; + if (templ2&0x80) templ2|=0xFFFFFF00; + temp64=((int64_t)(int32_t)templ)*((int64_t)(int32_t)templ2); +// pclog("IMULr8 %08X %08X %i\n",templ,templ2,temp64i>>32); + if ((temp64>>32)!=0 && (temp64>>32)!=0xFFFFFFFF) flags|=C_FLAG|V_FLAG; + else flags&=~(C_FLAG|V_FLAG); + regs[reg].l=temp64&0xFFFFFFFF; + cycles-=20; + break; +//#endif + case 0x6C: case 0x16C: /*INSB*/ + checkio_perm(DX); + temp=inb(DX); + writememb(es,DI,temp); if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + cycles-=15; + break; + case 0x26C: case 0x36C: /*INSB*/ + checkio_perm(DX); + temp=inb(DX); + writememb(es,EDI,temp); if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + cycles-=15; + break; + case 0x6D: /*INSW*/ + checkio_perm(DX); + checkio_perm(DX+1); + tempw=inw(DX); + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=15; + break; + case 0x16D: /*INSL*/ + checkio_perm(DX); + checkio_perm(DX+1); + checkio_perm(DX+2); + checkio_perm(DX+3); + templ=inl(DX); + writememl(es,DI,templ); if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + cycles-=15; + break; + case 0x26D: /*INSW*/ + checkio_perm(DX); + checkio_perm(DX+1); + tempw=inw(DX); + writememw(es,EDI,tempw); if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + cycles-=15; + break; + case 0x36D: /*INSL*/ + checkio_perm(DX); + checkio_perm(DX+1); + checkio_perm(DX+2); + checkio_perm(DX+3); + templ=inl(DX); + writememl(es,EDI,templ); if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + cycles-=15; + break; + case 0x6E: case 0x16E: /*OUTSB*/ + temp=readmemb(ds,SI); if (abrt) break; + checkio_perm(DX); + if (flags&D_FLAG) SI--; + else SI++; + outb(DX,temp); + cycles-=14; + break; + case 0x26E: case 0x36E: /*OUTSB*/ + checkio_perm(DX); + temp=readmemb(ds,ESI); if (abrt) break; + if (flags&D_FLAG) ESI--; + else ESI++; + outb(DX,temp); + cycles-=14; + break; + case 0x6F: /*OUTSW*/ + tempw=readmemw(ds,SI); if (abrt) break; + checkio_perm(DX); + checkio_perm(DX+1); + if (flags&D_FLAG) SI-=2; + else SI+=2; + outw(DX,tempw); +// outb(DX+1,tempw>>8); + cycles-=14; + break; + case 0x16F: /*OUTSL*/ + tempw=readmemw(ds,SI); if (abrt) break; + checkio_perm(DX); + checkio_perm(DX+1); + checkio_perm(DX+2); + checkio_perm(DX+3); + if (flags&D_FLAG) SI-=4; + else SI+=4; + outl(EDX,templ); + cycles-=14; + break; + case 0x26F: /*OUTSW*/ + tempw=readmemw(ds,ESI); if (abrt) break; + checkio_perm(DX); + checkio_perm(DX+1); + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + outw(DX,tempw); + cycles-=14; + break; + case 0x36F: /*OUTSL*/ + tempw=readmemw(ds,ESI); if (abrt) break; + checkio_perm(DX); + checkio_perm(DX+1); + checkio_perm(DX+2); + checkio_perm(DX+3); + if (flags&D_FLAG) ESI-=4; + else ESI+=4; + outl(EDX,templ); + cycles-=14; + break; + + case 0x70: case 0x170: case 0x270: case 0x370: /*JO*/ + offset=(int8_t)getbytef(); + if (flags&V_FLAG) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x71: case 0x171: case 0x271: case 0x371: /*JNO*/ + offset=(int8_t)getbytef(); + if (!(flags&V_FLAG)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x72: case 0x172: case 0x272: case 0x372: /*JB*/ + offset=(int8_t)getbytef(); + if (flags&C_FLAG) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x73: case 0x173: case 0x273: case 0x373: /*JNB*/ + offset=(int8_t)getbytef(); + if (!(flags&C_FLAG)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x74: case 0x174: case 0x274: case 0x374: /*JZ*/ + offset=(int8_t)getbytef(); + if (flags&Z_FLAG) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x75: case 0x175: case 0x275: case 0x375: /*JNZ*/ + offset=(int8_t)getbytef(); + if (!(flags&Z_FLAG)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x76: case 0x176: case 0x276: case 0x376: /*JBE*/ + offset=(int8_t)getbytef(); + if (flags&(C_FLAG|Z_FLAG)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x77: case 0x177: case 0x277: case 0x377: /*JNBE*/ + offset=(int8_t)getbytef(); + if (!(flags&(C_FLAG|Z_FLAG))) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x78: case 0x178: case 0x278: case 0x378: /*JS*/ + offset=(int8_t)getbytef(); + if (flags&N_FLAG) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x79: case 0x179: case 0x279: case 0x379: /*JNS*/ + offset=(int8_t)getbytef(); + if (!(flags&N_FLAG)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x7A: case 0x17A: case 0x27A: case 0x37A: /*JP*/ + offset=(int8_t)getbytef(); + if (flags&P_FLAG) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x7B: case 0x17B: case 0x27B: case 0x37B: /*JNP*/ + offset=(int8_t)getbytef(); + if (!(flags&P_FLAG)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x7C: case 0x17C: case 0x27C: case 0x37C: /*JL*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x7D: case 0x17D: case 0x27D: case 0x37D: /*JNL*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x7E: case 0x17E: case 0x27E: case 0x37E: /*JLE*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + case 0x7F: case 0x17F: case 0x27F: case 0x37F: /*JNLE*/ + offset=(int8_t)getbytef(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { pc += offset; cycles -= timing_bt; } + cycles -= timing_bnt; + break; + + + case 0x80: case 0x180: case 0x280: case 0x380: + case 0x82: case 0x182: case 0x282: case 0x382: + fetchea(); + temp=geteab(); if (abrt) break; + temp2=readmemb(cs,pc); pc++; if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + seteab(temp+temp2); if (abrt) break; + setadd8(temp,temp2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x10: /*ADC b,#8*/ + seteab(temp+temp2+tempc); if (abrt) break; + setadc8(temp,temp2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x18: /*SBB b,#8*/ + seteab(temp-(temp2+tempc)); if (abrt) break; + setsbc8(temp,temp2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x28: /*SUB b,#8*/ + seteab(temp-temp2); if (abrt) break; + setsub8(temp,temp2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + seteab(temp); if (abrt) break; + setznp8(temp); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:7); + break; + } + break; + + case 0x81: case 0x281: + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=getword(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + seteaw(tempw+tempw2); if (abrt) break; + setadd16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x10: /*ADC w,#16*/ + seteaw(tempw+tempw2+tempc); if (abrt) break; + setadc16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x18: /*SBB w,#16*/ + seteaw(tempw-(tempw2+tempc)); if (abrt) break; + setsbc16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x28: /*SUB w,#16*/ + seteaw(tempw-tempw2); if (abrt) break; + setsub16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x38: /*CMP w,#16*/ + setsub16(tempw,tempw2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:7); + break; + } + break; + case 0x181: case 0x381: + fetchea(); + templ=geteal(); if (abrt) break; + templ2=getlong(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ADD l,#32*/ + seteal(templ+templ2); if (abrt) break; + setadd32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x08: /*OR l,#32*/ + templ|=templ2; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x10: /*ADC l,#32*/ + seteal(templ+templ2+tempc); if (abrt) break; + setadc32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x20: /*AND l,#32*/ + templ&=templ2; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x18: /*SBB l,#32*/ + seteal(templ-(templ2+tempc)); if (abrt) break; + setsbc32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x28: /*SUB l,#32*/ + seteal(templ-templ2); if (abrt) break; + setsub32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x30: /*XOR l,#32*/ + templ^=templ2; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= (mod == 3) ? timing_rr : timing_mrl; + break; + case 0x38: /*CMP l,#32*/ + setsub32(templ,templ2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:7); + break; + } + break; + + case 0x83: case 0x283: + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=readmemb(cs,pc); pc++; if (abrt) break; + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + seteaw(tempw+tempw2); if (abrt) break; + setadd16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x10: /*ADC w,#8*/ + seteaw(tempw+tempw2+tempc); if (abrt) break; + setadc16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x18: /*SBB w,#8*/ + seteaw(tempw-(tempw2+tempc)); if (abrt) break; + setsbc16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x28: /*SUB w,#8*/ + seteaw(tempw-tempw2); if (abrt) break; + setsub16(tempw,tempw2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + seteaw(tempw); if (abrt) break; + setznp16(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:7); + break; + } + break; + case 0x183: case 0x383: + fetchea(); + templ=geteal(); if (abrt) break; + templ2=readmemb(cs,pc); pc++; if (abrt) break; + if (templ2&0x80) templ2|=0xFFFFFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD l,#32*/ + seteal(templ+templ2); if (abrt) break; + setadd32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x08: /*OR l,#32*/ + templ|=templ2; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x10: /*ADC l,#32*/ + seteal(templ+templ2+tempc); if (abrt) break; + setadc32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x20: /*AND l,#32*/ + templ&=templ2; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x18: /*SBB l,#32*/ + seteal(templ-(templ2+tempc)); if (abrt) break; + setsbc32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x28: /*SUB l,#32*/ + seteal(templ-templ2); if (abrt) break; + setsub32(templ,templ2); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x30: /*XOR l,#32*/ + templ^=templ2; + seteal(templ); if (abrt) break; + setznp32(templ); + cycles -= (mod == 3) ? timing_rr : timing_mr; + break; + case 0x38: /*CMP l,#32*/ + setsub32(templ,templ2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:7); + break; + } + break; + + case 0x84: case 0x184: case 0x284: case 0x384: /*TEST b,reg*/ + fetchea(); + temp=geteab(); if (abrt) break; + temp2=getr8(reg); + setznp8(temp&temp2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x85: case 0x285: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + tempw2=regs[reg].w; + setznp16(tempw&tempw2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x185: case 0x385: /*TEST l,reg*/ + fetchea(); + templ=geteal(); if (abrt) break; + templ2=regs[reg].l; + setznp32(templ&templ2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x86: case 0x186: case 0x286: case 0x386: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); if (abrt) break; + seteab(getr8(reg)); if (abrt) break; + setr8(reg,temp); + cycles-=((mod==3)?3:5); + break; + case 0x87: case 0x287: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + seteaw(regs[reg].w); if (abrt) break; + regs[reg].w=tempw; + cycles-=((mod==3)?3:5); + break; + case 0x187: case 0x387: /*XCHG l,reg*/ + fetchea(); + templ=geteal(); if (abrt) break; + seteal(regs[reg].l); if (abrt) break; + regs[reg].l=templ; + cycles-=((mod==3)?3:5); + break; + + case 0x88: case 0x188: case 0x288: case 0x388: /*MOV b,reg*/ + fetchea(); + seteab(getr8(reg)); + cycles-=(is486)?1:2; + break; + case 0x89: case 0x289: /*MOV w,reg*/ + fetchea(); + seteaw(regs[reg].w); + cycles-=(is486)?1:2; + break; + case 0x189: case 0x389: /*MOV l,reg*/ + fetchea(); + //if (output==3) pclog("Write %08X to %08X:%08X %08X %08X %08X\n",regs[reg].l,easeg,eaaddr,); + seteal(regs[reg].l); + cycles-=(is486)?1:2; + break; + case 0x8A: case 0x18A: case 0x28A: case 0x38A: /*MOV reg,b*/ + fetchea(); + temp=geteab(); if (abrt) break; + setr8(reg,temp); + if (is486) cycles--; + else cycles-=((mod==3)?2:4); + break; + case 0x8B: case 0x28B: /*MOV reg,w*/ + fetchea(); + tempw=geteaw(); if (abrt) break; + regs[reg].w=tempw; + if (is486) cycles--; + else cycles-=((mod==3)?2:4); + break; + case 0x18B: case 0x38B: /*MOV reg,l*/ + fetchea(); + templ=geteal(); if (abrt) break; + regs[reg].l=templ; + if (is486) cycles--; + else cycles-=((mod==3)?2:4); + break; + + case 0x8C: case 0x28C: /*MOV w,sreg*/ + fetchea(); +// if (output==3) pclog("MOV sreg %02X %08X\n",rmdat,fetchdat); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss=oldss; + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + cycles-=((mod==3)?2:3); + break; + case 0x18C: case 0x38C: /*MOV l,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + if (mod==3) regs[rm].l=ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod==3) regs[rm].l=CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds=oldds; + if (mod==3) regs[rm].l=DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss=oldss; + if (mod==3) regs[rm].l=SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod==3) regs[rm].l=FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod==3) regs[rm].l=GS; + else seteaw(GS); + break; + } + cycles-=((mod==3)?2:3); + break; + + case 0x8D: case 0x28D: /*LEA*/ + fetchea(); + regs[reg].w=eaaddr; + cycles -= timing_rr; + break; + case 0x18D: /*LEA*/ + fetchea(); + regs[reg].l=eaaddr&0xFFFF; + cycles -= timing_rr; + break; + case 0x38D: /*LEA*/ + fetchea(); + regs[reg].l=eaaddr; + cycles -= timing_rr; + break; + + case 0x8E: case 0x18E: case 0x28E: case 0x38E: /*MOV sreg,w*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); if (abrt) break; + loadseg(tempw,&_es); + break; + case 0x18: /*DS*/ + tempw=geteaw(); if (abrt) break; + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + break; + case 0x10: /*SS*/ +// if (output==3) pclog("geteaw\n"); + tempw=geteaw(); if (abrt) break; +// if (output==3) pclog("loadseg\n"); + loadseg(tempw,&_ss); +// if (output==3) pclog("done\n"); + if (ssegs) oldss=ss; + skipnextprint=1; + noint=1; + break; + case 0x20: /*FS*/ + tempw=geteaw(); if (abrt) break; + loadseg(tempw,&_fs); + break; + case 0x28: /*GS*/ + tempw=geteaw(); if (abrt) break; + loadseg(tempw,&_gs); + break; + } + cycles-=((mod==3)?2:5); + break; + + case 0x8F: case 0x28F: /*POPW*/ + if (ssegs) templ2=oldss; + else templ2=ss; + if (stack32) + { + tempw=readmemw(templ2,ESP); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(templ2,SP); if (abrt) break; + SP+=2; + } + fetchea(); + if (ssegs) ss=oldss; + seteaw(tempw); + if (abrt) + { + if (stack32) ESP-=2; + else SP-=2; + } + if (is486) cycles-=((mod==3)?1:6); + else cycles-=((mod==3)?4:5); + break; + case 0x18F: case 0x38F: /*POPL*/ + if (ssegs) templ2=oldss; + else templ2=ss; + if (stack32) + { + templ=readmeml(templ2,ESP); if (abrt) break; + ESP+=4; + } + else + { + templ=readmeml(templ2,SP); if (abrt) break; + SP+=4; + } + fetchea(); + if (ssegs) ss=oldss; + seteal(templ); + if (abrt) + { + if (stack32) ESP-=4; + else SP-=4; + } + if (is486) cycles-=((mod==3)?1:6); + else cycles-=((mod==3)?4:5); + break; + + case 0x90: case 0x190: case 0x290: case 0x390: /*NOP*/ + cycles-=(is486)?1:3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x291: case 0x292: case 0x293: + case 0x294: case 0x295: case 0x296: case 0x297: + tempw=AX; + AX=regs[opcode&7].w; + regs[opcode&7].w=tempw; + cycles-=3; + break; + case 0x191: case 0x192: case 0x193: /*XCHG EAX*/ + case 0x194: case 0x195: case 0x196: case 0x197: + case 0x391: case 0x392: case 0x393: /*XCHG EAX*/ + case 0x394: case 0x395: case 0x396: case 0x397: + templ=EAX; + EAX=regs[opcode&7].l; + regs[opcode&7].l=templ; + cycles-=3; + break; + + case 0x98: case 0x298: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=3; + break; + case 0x198: case 0x398: /*CWDE*/ + EAX=(AX&0x8000)?(0xFFFF0000|AX):AX; + cycles-=3; + break; + case 0x99: case 0x299: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=2; + break; + case 0x199: case 0x399: /*CDQ*/ + EDX=(EAX&0x80000000)?0xFFFFFFFF:0; + cycles-=2; + break; + case 0x9A: case 0x29A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); if (abrt) break; + if (output == 3) pclog("Call far %04X:%04X\n",tempw2,tempw); + tempw3=CS; + templ2 = pc; + if (output) pclog("Call far %08X\n",templ2); + if (ssegs) ss=oldss; + oxpc=pc; + pc=tempw; + optype=CALL; + cgate32=0; + if (output == 3) pclog("Load CS\n"); + if (msw&1) loadcscall(tempw2); + else loadcs(tempw2); + if (output == 3) pclog("%i %i\n", abrt, cgate32); + optype=0; +// if (output==3) pclog("CALL FAR 16 complete\n"); + if (abrt) break; + oldss=ss; + if (cgate32) goto writecall32; + writecall16: + cgate16=0; + if (stack32) + { + writememw(ss,ESP-2,tempw3); + writememw(ss,ESP-4,templ2); if (abrt) break; + ESP-=4; + } + else + { + writememw(ss,(SP-2)&0xFFFF,tempw3); + if (output) pclog("Write CS to %04X:%04X\n",SS,SP-2); + writememw(ss,(SP-4)&0xFFFF,templ2); if (abrt) break; + if (output) pclog("Write PC %08X to %04X:%04X\n", templ2, SS,SP-4); + SP-=4; + } + cycles-=(is486)?18:17; + break; + case 0x19A: case 0x39A: /*CALL FAR*/ +// if (output==3) pclog("CF 1 %08X\n",pc); + templ=getword(); templ|=(getword()<<16); +// if (output==3) pclog("CF 2\n"); + tempw2=getword(); if (abrt) break; +// if (output==3) pclog("CF 3 %04X:%08X\n",tempw2,templ); + tempw3=CS; + templ2 = pc; + if (ssegs) ss=oldss; + oxpc=pc; + pc=templ; + optype=CALL; + cgate16=0; +// if (output==3) pclog("Load CS\n"); + if (msw&1) loadcscall(tempw2); + else loadcs(tempw2); +// if (output==3) pclog("%i %i\n",notpresent,abrt); + optype=0; +// if (output==3) pclog("CALL FAR 32 complete\n"); + if (abrt) break; + oldss=ss; + if (cgate16) goto writecall16; + writecall32: + cgate32=0; + if (stack32) + { + writememl(ss,ESP-4,tempw3); + writememl(ss,ESP-8,templ2); if (abrt) break; + if (output) pclog("Write PC %08X to %04X:%04X\n", templ2, SS,ESP-8); + ESP-=8; + } + else + { + writememl(ss,(SP-4)&0xFFFF,tempw3); + writememl(ss,(SP-8)&0xFFFF,templ2); if (abrt) break; + if (output) pclog("Write PC %08X to %04X:%04X\n", templ2, SS,SP-8); + SP-=8; + } + cycles-=(is486)?18:17; + break; + case 0x9B: case 0x19B: case 0x29B: case 0x39B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: case 0x29C: /*PUSHF*/ + if (ssegs) ss=oldss; + if ((eflags&VM_FLAG) && (IOPL<3)) + { + x86gpf(NULL,0); + break; + } + if (stack32) + { + writememw(ss,ESP-2,flags); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); if (abrt) break; + SP-=2; + } + cycles-=4; + break; + case 0x19C: case 0x39C: /*PUSHFD*/ +// pclog("PUSHFD %04X(%08X):%08X\n",CS,cs,pc); + if (ssegs) ss=oldss; + if ((eflags&VM_FLAG) && (IOPL<3)) + { + x86gpf(NULL,0); + break; + } + if (CPUID) tempw=eflags&0x24; + else tempw=eflags&4; + if (stack32) + { + writememw(ss,ESP-2,tempw); + writememw(ss,ESP-4,flags); if (abrt) break; + ESP-=4; +// if (output==3) pclog("Pushing %04X %04X\n",eflags,flags); + } + else + { + writememw(ss,((SP-2)&0xFFFF),tempw); + writememw(ss,((SP-4)&0xFFFF),flags); if (abrt) break; + SP-=4; + } + cycles-=4; + break; + case 0x9D: case 0x29D: /*POPF*/ +// if (CS!=0x21 && CS!=0xF000) pclog("POPF %04X:%04X\n",CS,pc); + if (ssegs) ss=oldss; + if ((eflags&VM_FLAG) && (IOPL<3)) + { + x86gpf(NULL,0); + break; + } + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + SP+=2; + } +// pclog("POPF! %i %i %i\n",CPL,msw&1,IOPLp); + if (!(CPL) || !(msw&1)) flags=(tempw&0xFFD5)|2; + else if (IOPLp) flags=(flags&0x3000)|(tempw&0xCFD5)|2; + else flags=(flags&0xF200)|(tempw&0x0DD5)|2; +// if (flags==0xF000) pclog("POPF - flags now F000 %04X(%06X):%04X %08X %08X %08X\n",CS,cs,pc,old8,old82,old83); + cycles-=5; + break; + case 0x19D: case 0x39D: /*POPFD*/ + if (ssegs) ss=oldss; + if ((eflags&VM_FLAG) && (IOPL<3)) + { + x86gpf(NULL,0); + break; + } + if (stack32) + { + tempw=readmemw(ss,ESP); + tempw2=readmemw(ss,ESP+2); if (abrt) break; + ESP+=4; + } + else + { + tempw=readmemw(ss,SP); + tempw2=readmemw(ss,SP+2); if (abrt) break; + SP+=4; + } +// eflags|=0x200000; + if (!(CPL) || !(msw&1)) flags=(tempw&0xFFD5)|2; + else if (IOPLp) flags=(flags&0x3000)|(tempw&0xCFD5)|2; + else flags=(flags&0xF200)|(tempw&0x0DD5)|2; + tempw2&=(is486)?0x24:0; + tempw2|=(eflags&3); + if (CPUID) eflags=tempw2&0x27; + else if (is486) eflags=tempw2&7; + else eflags=tempw2&3; +// if (flags==0xF000) pclog("POPF - flags now F000 %04X(%06X):%04X %08X %08X %08X\n",CS,cs,pc,old8,old82,old83); + cycles-=5; + break; + case 0x9E: case 0x19E: case 0x29E: case 0x39E: /*SAHF*/ + flags=(flags&0xFF00)|(AH&0xD5)|2; + cycles-=3; + break; + case 0x9F: case 0x19F: case 0x29F: case 0x39F: /*LAHF*/ + AH=flags&0xFF; + cycles-=3; + break; + + case 0xA0: case 0x1A0: /*MOV AL,(w)*/ + addr=getword(); if (abrt) break; + temp=readmemb(ds,addr); if (abrt) break; + AL=temp; + cycles-=(is486)?1:4; + break; + case 0x2A0: case 0x3A0: /*MOV AL,(l)*/ + addr=getlong(); if (abrt) break; + temp=readmemb(ds,addr); if (abrt) break; + AL=temp; + cycles-=(is486)?1:4; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); if (abrt) break; + tempw=readmemw(ds,addr); if (abrt) break; + AX=tempw; + cycles-=(is486)?1:4; + break; + case 0x1A1: /*MOV EAX,(w)*/ + addr=getword(); if (abrt) break; + templ=readmeml(ds,addr); if (abrt) break; + EAX=templ; + cycles-=(is486)?1:4; + break; + case 0x2A1: /*MOV AX,(l)*/ + addr=getlong(); if (abrt) break; + tempw=readmemw(ds,addr); if (abrt) break; + AX=tempw; + cycles-=(is486)?1:4; + break; + case 0x3A1: /*MOV EAX,(l)*/ + addr=getlong(); if (abrt) break; + templ=readmeml(ds,addr); if (abrt) break; + EAX=templ; + cycles-=(is486)?1:4; + break; + case 0xA2: case 0x1A2: /*MOV (w),AL*/ + addr=getword(); if (abrt) break; + writememb(ds,addr,AL); + cycles-=(is486)?1:2; + break; + case 0x2A2: case 0x3A2: /*MOV (l),AL*/ + addr=getlong(); if (abrt) break; + writememb(ds,addr,AL); + cycles-=(is486)?1:2; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); if (abrt) break; + writememw(ds,addr,AX); + cycles-=(is486)?1:2; + break; + case 0x1A3: /*MOV (w),EAX*/ + addr=getword(); if (abrt) break; + writememl(ds,addr,EAX); + cycles-=(is486)?1:2; + break; + case 0x2A3: /*MOV (l),AX*/ + addr=getlong(); if (abrt) break; + writememw(ds,addr,AX); + cycles-=(is486)?1:2; + break; + case 0x3A3: /*MOV (l),EAX*/ + addr=getlong(); if (abrt) break; + writememl(ds,addr,EAX); + cycles-=(is486)?1:2; + break; + + case 0xA4: case 0x1A4: /*MOVSB*/ + temp=readmemb(ds,SI); if (abrt) break; + writememb(es,DI,temp); if (abrt) break; + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=7; + break; + case 0x2A4: case 0x3A4: /*MOVSB*/ + temp=readmemb(ds,ESI); if (abrt) break; + writememb(es,EDI,temp); if (abrt) break; + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + cycles-=7; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); if (abrt) break; + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=7; + break; + case 0x2A5: /*MOVSW*/ + tempw=readmemw(ds,ESI); if (abrt) break; + writememw(es,EDI,tempw); if (abrt) break; + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + cycles-=7; + break; + case 0x1A5: /*MOVSL*/ + templ=readmeml(ds,SI); if (abrt) break; + writememl(es,DI,templ); if (abrt) break; + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + cycles-=7; + break; + case 0x3A5: /*MOVSL*/ + templ=readmeml(ds,ESI); if (abrt) break; + writememl(es,EDI,templ); if (abrt) break; + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + cycles-=7; + break; + case 0xA6: case 0x1A6: /*CMPSB*/ + temp =readmemb(ds,SI); + temp2=readmemb(es,DI); + if (abrt) break; + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=(is486)?8:10; + break; + case 0x2A6: case 0x3A6: /*CMPSB*/ + temp =readmemb(ds,ESI); + temp2=readmemb(es,EDI); + if (abrt) break; + setsub8(temp,temp2); + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + cycles-=(is486)?8:10; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (abrt) break; + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=(is486)?8:10; + break; + case 0x1A7: /*CMPSL*/ + templ =readmeml(ds,SI); + templ2=readmeml(es,DI); + if (abrt) break; + setsub32(templ,templ2); + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + cycles-=(is486)?8:10; + break; + case 0x2A7: /*CMPSW*/ + tempw =readmemw(ds,ESI); + tempw2=readmemw(es,EDI); + if (abrt) break; + setsub16(tempw,tempw2); + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + cycles-=(is486)?8:10; + break; + case 0x3A7: /*CMPSL*/ + templ =readmeml(ds,ESI); + templ2=readmeml(es,EDI); + if (abrt) break; + setsub32(templ,templ2); + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + cycles-=(is486)?8:10; + break; + case 0xA8: case 0x1A8: case 0x2A8: case 0x3A8: /*TEST AL,#8*/ + temp=getbytef(); + setznp8(AL&temp); + cycles -= timing_rr; + break; + case 0xA9: case 0x2A9: /*TEST AX,#16*/ + tempw=getwordf(); + setznp16(AX&tempw); + cycles -= timing_rr; + break; + case 0x1A9: case 0x3A9: /*TEST EAX,#32*/ + templ=getlong(); if (abrt) break; + setznp32(EAX&templ); + cycles -= timing_rr; + break; + case 0xAA: case 0x1AA: /*STOSB*/ + writememb(es,DI,AL); if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + cycles-=4; + break; + case 0x2AA: case 0x3AA: /*STOSB*/ + writememb(es,EDI,AL); if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + cycles-=4; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=4; + break; + case 0x1AB: /*STOSL*/ + writememl(es,DI,EAX); if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + cycles-=4; + break; + case 0x2AB: /*STOSW*/ + writememw(es,EDI,AX); if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + cycles-=4; + break; + case 0x3AB: /*STOSL*/ + writememl(es,EDI,EAX); if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + cycles-=4; + break; + case 0xAC: case 0x1AC: /*LODSB*/ + temp=readmemb(ds,SI); + if (abrt) break; + AL=temp; +// if (output==3) pclog("LODSB %02X from %05X:%04X\n",AL,ds,SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=5; + break; + case 0x2AC: case 0x3AC: /*LODSB*/ + temp=readmemb(ds,ESI); + if (abrt) break; + AL=temp; + if (flags&D_FLAG) ESI--; + else ESI++; + cycles-=5; + break; + case 0xAD: /*LODSW*/ + tempw=readmemw(ds,SI); + if (abrt) break; + AX=tempw; +// if (output) pclog("Load from %05X:%04X\n",ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=5; + break; + case 0x1AD: /*LODSL*/ + templ=readmeml(ds,SI); + if (abrt) break; + EAX=templ; + if (flags&D_FLAG) SI-=4; + else SI+=4; + cycles-=5; + break; + case 0x2AD: /*LODSW*/ + tempw=readmemw(ds,ESI); + if (abrt) break; + AX=tempw; + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + cycles-=5; + break; + case 0x3AD: /*LODSL*/ + templ=readmeml(ds,ESI); + if (abrt) break; + EAX=templ; + if (flags&D_FLAG) ESI-=4; + else ESI+=4; + cycles-=5; + break; + case 0xAE: case 0x1AE: /*SCASB*/ + temp=readmemb(es,DI); + if (abrt) break; + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=7; + break; + case 0x2AE: case 0x3AE: /*SCASB*/ + temp=readmemb(es,EDI); + if (abrt) break; + setsub8(AL,temp); + if (flags&D_FLAG) EDI--; + else EDI++; + cycles-=7; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + if (abrt) break; + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=7; + break; + case 0x1AF: /*SCASL*/ + templ=readmeml(es,DI); + if (abrt) break; + setsub32(EAX,templ); + if (flags&D_FLAG) DI-=4; + else DI+=4; + cycles-=7; + break; + case 0x2AF: /*SCASW*/ + tempw=readmemw(es,EDI); + if (abrt) break; + setsub16(AX,tempw); + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + cycles-=7; + break; + case 0x3AF: /*SCASL*/ + templ=readmeml(es,EDI); + if (abrt) break; + setsub32(EAX,templ); + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + cycles-=7; + break; + + case 0xB0: case 0x1B0: case 0x2B0: case 0x3B0: /*MOV AL,#8*/ + AL=getbytef(); + cycles -= timing_rr; + break; + case 0xB1: case 0x1B1: case 0x2B1: case 0x3B1: /*MOV CL,#8*/ + CL=getbytef(); + cycles -= timing_rr; + break; + case 0xB2: case 0x1B2: case 0x2B2: case 0x3B2: /*MOV DL,#8*/ + DL=getbytef(); + cycles -= timing_rr; + break; + case 0xB3: case 0x1B3: case 0x2B3: case 0x3B3: /*MOV BL,#8*/ + BL=getbytef(); + cycles -= timing_rr; + break; + case 0xB4: case 0x1B4: case 0x2B4: case 0x3B4: /*MOV AH,#8*/ + AH=getbytef(); + cycles -= timing_rr; + break; + case 0xB5: case 0x1B5: case 0x2B5: case 0x3B5: /*MOV CH,#8*/ + CH=getbytef(); + cycles -= timing_rr; + break; + case 0xB6: case 0x1B6: case 0x2B6: case 0x3B6: /*MOV DH,#8*/ + DH=getbytef(); + cycles -= timing_rr; + break; + case 0xB7: case 0x1B7: case 0x2B7: case 0x3B7: /*MOV BH,#8*/ + BH=getbytef(); + cycles -= timing_rr; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + case 0x2B8: case 0x2B9: case 0x2BA: case 0x2BB: + case 0x2BC: case 0x2BD: case 0x2BE: case 0x2BF: + regs[opcode&7].w=getwordf(); + cycles -= timing_rr; + break; + case 0x1B8: case 0x1B9: case 0x1BA: case 0x1BB: /*MOV reg,#32*/ + case 0x1BC: case 0x1BD: case 0x1BE: case 0x1BF: + case 0x3B8: case 0x3B9: case 0x3BA: case 0x3BB: + case 0x3BC: case 0x3BD: case 0x3BE: case 0x3BF: + templ=getlong(); if (abrt) break; + regs[opcode&7].l=templ; + cycles -= timing_rr; + break; + + case 0xC0: case 0x1C0: case 0x2C0: case 0x3C0: + fetchea(); + c=readmemb(cs,pc); pc++; + temp=geteab(); if (abrt) break; + c&=31; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL b,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?1:0; + temp2=temp&0x80; + temp=(temp<<1)|tempc; + c--; + if (is486) cycles--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + case 0x18: /*RCR b,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?0x80:0; + temp2=temp&1; + temp=(temp>>1)|tempc; + c--; + if (is486) cycles--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + seteab(temp<>c); if (abrt) break; + setznp8(temp>>c); + if ((temp>>(c-1))&1) flags|=C_FLAG; + if (c==1 && temp&0x80) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x38: /*SAR b,CL*/ + tempc=((temp>>(c-1))&1); + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + setznp8(temp); + if (tempc) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + + case 0xC1: case 0x2C1: + fetchea(); + c=readmemb(cs,pc)&31; pc++; + tempw=geteaw(); if (abrt) break; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempw2) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL w,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?1:0; + temp2=(tempw>>15); + tempw=(tempw<<1)|tempc; + c--; + if (is486) cycles--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + case 0x18: /*RCR w,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?0x8000:0; + temp2=tempw&1; + tempw=(tempw>>1)|tempc; + c--; + if (is486) cycles--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + seteaw(tempw<>c); if (abrt) break; + setznp16(tempw>>c); + if ((tempw>>(c-1))&1) flags|=C_FLAG; + if (c==1 && tempw&0x8000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + tempc=(tempw>>(c-1))&1; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + case 0x1C1: case 0x3C1: + fetchea(); + c=readmemb(cs,pc); pc++; + c&=31; + templ=geteal(); if (abrt) break; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL l,CL*/ + while (c>0) + { + temp=(templ&0x80000000)?1:0; + templ=(templ<<1)|temp; + c--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp) flags|=C_FLAG; + if ((flags&C_FLAG)^(templ>>31)) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + case 0x08: /*ROR l,CL*/ + while (c>0) + { + templ2=(templ&1)?0x80000000:0; + templ=(templ>>1)|templ2; + c--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (templ2) flags|=C_FLAG; + if ((templ^(templ>>1))&0x40000000) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + case 0x10: /*RCL l,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(flags&C_FLAG)?1:0; + temp2=templ>>31; + templ=(templ<<1)|tempc; + c--; + if (is486) cycles--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(templ>>31)) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + case 0x18: /*RCR l,CL*/ + temp2=flags&C_FLAG; + while (c>0) + { + tempc=(temp2)?0x80000000:0; + temp2=templ&1; + templ=(templ>>1)|tempc; + c--; + if (is486) cycles--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((templ^(templ>>1))&0x40000000) flags|=V_FLAG; + cycles-=((mod==3)?9:10); + break; + + case 0x20: case 0x30: /*SHL l,CL*/ + seteal(templ<>c); if (abrt) break; + setznp32(templ>>c); + if ((templ>>(c-1))&1) flags|=C_FLAG; + if (c==1 && templ&0x80000000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + + case 0x38: /*SAR l,CL*/ + templ2=templ&0x80000000; + tempc=(templ>>(c-1))&1; + while (c>0) + { + templ=(templ>>1)|templ2; + c--; + } + seteal(templ); if (abrt) break; + setznp32(templ); + if (tempc) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + + + case 0xC2: case 0x2C2: /*RET*/ + tempw=getword(); + if (ssegs) ss=oldss; + if (stack32) + { + tempw2=readmemw(ss,ESP); if (abrt) break; + ESP+=2+tempw; + } + else + { + tempw2=readmemw(ss,SP); if (abrt) break; + SP+=2+tempw; + } + pc=tempw2; + cycles-=(is486)?5:10; + break; + case 0x1C2: case 0x3C2: /*RET*/ + tempw=getword(); + if (ssegs) ss=oldss; + if (stack32) + { + templ=readmeml(ss,ESP); if (abrt) break; + ESP+=4+tempw; + } + else + { + templ=readmeml(ss,SP); if (abrt) break; + SP+=4+tempw; + } + pc=templ; + cycles-=(is486)?5:10; + break; + case 0xC3: case 0x2C3: /*RET*/ + if (ssegs) ss=oldss; + if (stack32) + { + tempw=readmemw(ss,ESP); if (abrt) break; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); if (abrt) break; + SP+=2; + } + pc=tempw; + cycles-=(is486)?5:10; + break; + case 0x1C3: case 0x3C3: /*RET*/ + if (ssegs) ss=oldss; + if (stack32) + { + templ=readmeml(ss,ESP); if (abrt) break; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); if (abrt) break; + SP+=4; + } + pc=templ; + cycles-=(is486)?5:10; + break; + case 0xC4: case 0x2C4: /*LES*/ + fetchea(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,eaaddr+2); +// if (output==3) pclog("LES %04X:%08X %04X:%08X\n",easeg,eaaddr,tempw,tempw2); + if (abrt) break; + loadseg(tempw,&_es); + if (abrt) break; + regs[reg].w=tempw2; +// if (output==3) pclog("LES complete\n"); +// if (!ES) pclog("LES=0 %04X(%06X):%04X\n",CS,cs,pc); +// if (cr0&1) pclog("ES loaded with %04X %04X(%08X):%08X\n",tempw,CS,cs,pc); + cycles-=7; + break; + case 0x1C4: case 0x3C4: /*LES*/ + fetchea(); + templ=readmeml(easeg,eaaddr); + tempw=readmemw(easeg,eaaddr+4); + if (abrt) break; + loadseg(tempw,&_es); + if (abrt) break; + regs[reg].l=templ; + cycles-=7; + break; + case 0xC5: case 0x2C5: /*LDS*/ + fetchea(); + tempw2=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,eaaddr+2); + if (abrt) break; + loadseg(tempw,&_ds); + if (abrt) break; + if (ssegs) oldds=ds; + regs[reg].w=tempw2; + cycles-=7; + break; + case 0x1C5: case 0x3C5: /*LDS*/ + fetchea(); + templ=readmeml(easeg,eaaddr); + tempw=readmemw(easeg,eaaddr+4); + if (abrt) break; + loadseg(tempw,&_ds); + if (abrt) break; + if (ssegs) oldds=ds; + regs[reg].l=templ; + cycles-=7; + break; + case 0xC6: case 0x1C6: case 0x2C6: case 0x3C6: /*MOV b,#8*/ + fetchea(); + temp=readmemb(cs,pc); pc++; if (abrt) break; + seteab(temp); + cycles -= timing_rr; + break; + case 0xC7: case 0x2C7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); if (abrt) break; + seteaw(tempw); + cycles -= timing_rr; + break; + case 0x1C7: case 0x3C7: /*MOV l,#32*/ + fetchea(); + templ=getlong(); if (abrt) break; + seteal(templ); + cycles -= timing_rr; + break; + case 0xC8: case 0x2C8: /*ENTER*/ + tempw2=getword(); + tempi=readmemb(cs,pc); pc++; + templ=EBP; + if (stack32) { writememw(ss,(ESP-2),BP); if (abrt) break; ESP-=2; } + else { writememw(ss,((SP-2)&0xFFFF),BP); if (abrt) break; SP-=2; } + templ2=ESP; + if (tempi>0) + { + while (--tempi) + { + EBP-=2; + if (stack32) tempw=readmemw(ss,EBP); + else tempw=readmemw(ss,BP); + if (abrt) { ESP=templ2; EBP=templ; break; } + if (stack32) { writememw(ss,(ESP-2),tempw); ESP-=2; } + else { writememw(ss,((SP-2)&0xFFFF),tempw); SP-=2; } + if (abrt) { ESP=templ2; EBP=templ; break; } + cycles-=(is486)?3:4; + } + if (stack32) { writememw(ss,(ESP-2),templ2); ESP-=2; } + else { writememw(ss,((SP-2)&0xFFFF),templ2); SP-=2; } + if (abrt) { ESP=templ2; EBP=templ; break; } + cycles-=(is486)?3:5; + } + BP = templ2; + if (stack32) ESP-=tempw2; + else SP-=tempw2; + cycles-=(is486)?14:10; +// if (cr0&1) pclog("BP %04X\n",BP); +// if (output==3) pclog("\n"); + break; + case 0x1C8: case 0x3C8: /*ENTER*/ +// if (output==1 && SS==0xA0) +// { +// enters++; +// for (ec=0;ec0) + { + while (--tempi) + { + EBP-=4; + if (stack32) templ=readmeml(ss,EBP); + else templ=readmeml(ss,BP); + if (abrt) { ESP=templ2; EBP=templ3; break; } + if (stack32) { writememl(ss,(ESP-4),templ); ESP-=4; } + else { writememl(ss,((SP-4)&0xFFFF),templ); SP-=4; } + if (abrt) { ESP=templ2; EBP=templ3; break; } + cycles-=(is486)?3:4; + } + if (stack32) { writememl(ss,(ESP-4),templ2); ESP-=4; } + else { writememl(ss,((SP-4)&0xFFFF),templ2); SP-=4; } + if (abrt) { ESP=templ2; EBP=templ3; break; } + cycles-=(is486)?3:5; + } + EBP=templ2; + if (stack32) ESP-=tempw; + else SP-=tempw; + cycles-=(is486)?14:10; +// if (output==3) pclog("\n"); + break; + case 0xC9: case 0x2C9: /*LEAVE*/ + templ=ESP; + SP=BP; + if (stack32) { tempw=readmemw(ss,ESP); ESP+=2; } + else { tempw=readmemw(ss,SP); SP+=2; } + if (abrt) { ESP=templ; break; } + BP=tempw; + cycles-=4; +// if (output==1 && SS==0xA0) +// { +// for (ec=0;ectempw2) + { + if (stack32) + { + templ=readmeml(ss,ESP); + loadseg(readmeml(ss,ESP+4),&_ss); + ESP=templ; + } + else + { + templ=readmeml(ss,SP); + loadseg(readmeml(ss,SP+4),&_ss); + ESP=templ; + } + } + cycles-=(is486)?13:18; + break; + case 0xCC: case 0x1CC: case 0x2CC: case 0x3CC: /*INT 3*/ + if (msw&1) + { + pmodeint(3,1); + cycles-=(is486)?44:59; + } + else + { + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + } + addr=3<<2; +// flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles-=(is486)?26:33; + } + cycles-=23; + break; + case 0xCD: case 0x1CD: case 0x2CD: case 0x3CD: /*INT*/ + /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + break; + } + lastpc=pc; + lastcs=CS; + temp=readmemb(cs,pc); pc++; + intrt: + +// if (temp == 0x15 && AX == 0xc203) output = 3; +// /*if (temp == 0x13) */pclog("INT %02X %04X %04X %04X %04X:%04X %04X:%04X %c %i %i\n",temp,AX,BX,CX,DS,DX,CS,pc,(AL>31)?AL:' ', ins, ins2); + if (1) + { + if (msw&1) + { +// pclog("PMODE int %02X %04X at %04X:%04X ",temp,AX,CS,pc); + pmodeint(temp,1); + cycles-=(is486)?44:59; +// pclog("to %04X:%04X\n",CS,pc); + } + else + { + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + } + addr=temp<<2; +// flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; +// pclog("%04X:%04X : ",CS,pc); + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles-=(is486)?30:37; +// pclog("INT %02X - %04X %04X:%04X\n",temp,addr,CS,pc); + } + } + break; + case 0xCE: /*INTO*/ + if (flags&V_FLAG) + { + temp=4; + goto intrt; + } + cycles-=3; + break; + case 0xCF: case 0x2CF: /*IRET*/ +// if (CS == 0xc000) output = 0; +// pclog("IRET\n"); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + break; + } +// output=0; + if (ssegs) ss=oldss; + if (msw&1) + { + optype=IRET; + pmodeiret(0); + optype=0; + } + else + { + tempw=CS; + tempw2=pc; + inint=0; + oxpc=pc; + if (stack32) + { + pc=readmemw(ss,ESP); + loadcs(readmemw(ss,ESP+2)); + } + else + { + pc=readmemw(ss,SP); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + } + if (stack32) + { + flags=(readmemw(ss,ESP+4)&0xFFD5)|2; + ESP+=6; + } + else + { + flags=(readmemw(ss,((SP+4)&0xFFFF))&0xFFD5)|2; + SP+=6; + } + } + cycles-=(is486)?15:22; + break; + case 0x1CF: case 0x3CF: /*IRETD*/ +// if (output==3) output=1; +// pclog("IRET\n"); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + break; + } +// output=0; + if (ssegs) ss=oldss; + if (msw&1) + { + optype=IRET; + pmodeiret(1); + optype=0; + } + else + { + tempw=CS; + tempw2=pc; + inint=0; + oxpc=pc; + if (stack32) + { + pc=readmeml(ss,ESP); + templ=readmeml(ss,ESP+4); + } + else + { + pc=readmeml(ss,SP); + templ=readmeml(ss,((SP+4)&0xFFFF)); + } + if (stack32) + { + flags=(readmemw(ss,ESP+8)&0xFFD5)|2; + eflags=readmemw(ss,ESP+10); + ESP+=12; + } + else + { + flags=(readmemw(ss,(SP+8)&0xFFFF)&0xFFD5)|2; + eflags=readmemw(ss,(SP+10)&0xFFFF); + SP+=12; + } + loadcs(templ); + } + cycles-=(is486)?15:22; + break; + + case 0xD0: case 0x1D0: case 0x2D0: case 0x3D0: + fetchea(); + temp=geteab(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + seteab((temp<<1)|((temp&0x80)?1:0)); if (abrt) break; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR b,1*/ + seteab((temp>>1)|((temp&1)?0x80:0)); if (abrt) break; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + seteab((temp<<1)|temp2); if (abrt) break; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + seteab((temp>>1)|(temp2?0x80:0)); if (abrt) break; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x20: case 0x30: /*SHL b,1*/ + seteab(temp<<1); if (abrt) break; + setznp8(temp<<1); + if (temp&0x80) flags|=C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x28: /*SHR b,1*/ + seteab(temp>>1); if (abrt) break; + setznp8(temp>>1); + if (temp&1) flags|=C_FLAG; + if (temp&0x80) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x38: /*SAR b,1*/ + seteab((temp>>1)|(temp&0x80)); if (abrt) break; + setznp8((temp>>1)|(temp&0x80)); + if (temp&1) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + case 0xD1: case 0x2D1: + fetchea(); + tempw=geteaw(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + seteaw((tempw<<1)|(tempw>>15)); if (abrt) break; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR w,1*/ + seteaw((tempw>>1)|(tempw<<15)); if (abrt) break; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + seteaw((tempw<<1)|temp2); if (abrt) break; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + seteaw((tempw>>1)|(temp2?0x8000:0)); if (abrt) break; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x20: case 0x30: /*SHL w,1*/ + seteaw(tempw<<1); if (abrt) break; + setznp16(tempw<<1); + if (tempw&0x8000) flags|=C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x28: /*SHR w,1*/ + seteaw(tempw>>1); if (abrt) break; + setznp16(tempw>>1); + if (tempw&1) flags|=C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x38: /*SAR w,1*/ + seteaw((tempw>>1)|(tempw&0x8000)); if (abrt) break; + setznp16((tempw>>1)|(tempw&0x8000)); + if (tempw&1) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + + default: + pclog("Bad D1 opcode %02X\n",rmdat&0x38); + } + break; + case 0x1D1: case 0x3D1: + fetchea(); + templ=geteal(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL l,1*/ + seteal((templ<<1)|(templ>>31)); if (abrt) break; + if (templ&0x80000000) flags|=C_FLAG; + else flags&=~C_FLAG; + templ<<=1; + if (flags&C_FLAG) templ|=1; + if ((flags&C_FLAG)^(templ>>31)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR l,1*/ + seteal((templ>>1)|(templ<<31)); if (abrt) break; + if (templ&1) flags|=C_FLAG; + else flags&=~C_FLAG; + templ>>=1; + if (flags&C_FLAG) templ|=0x80000000; + if ((templ^(templ>>1))&0x40000000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL l,1*/ + temp2=flags&C_FLAG; + seteal((templ<<1)|temp2); if (abrt) break; + if (templ&0x80000000) flags|=C_FLAG; + else flags&=~C_FLAG; + templ<<=1; + if (temp2) templ|=1; + if ((flags&C_FLAG)^(templ>>31)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x18: /*RCR l,1*/ + temp2=flags&C_FLAG; + seteal((templ>>1)|(temp2?0x80000000:0)); if (abrt) break; + temp2=flags&C_FLAG; + if (templ&1) flags|=C_FLAG; + else flags&=~C_FLAG; + templ>>=1; + if (temp2) templ|=0x80000000; + if ((templ^(templ>>1))&0x40000000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x20: case 0x30: /*SHL l,1*/ + seteal(templ<<1); if (abrt) break; + setznp32(templ<<1); + if (templ&0x80000000) flags|=C_FLAG; + if ((templ^(templ<<1))&0x80000000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x28: /*SHR l,1*/ + seteal(templ>>1); if (abrt) break; + setznp32(templ>>1); + if (templ&1) flags|=C_FLAG; + if (templ&0x80000000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x38: /*SAR l,1*/ + seteal((templ>>1)|(templ&0x80000000)); if (abrt) break; + setznp32((templ>>1)|(templ&0x80000000)); + if (templ&1) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + + default: + pclog("Bad D1 opcode %02X\n",rmdat&0x38); + } + break; + + case 0xD2: case 0x1D2: case 0x2D2: case 0x3D2: + fetchea(); + temp=geteab(); if (abrt) break; + c=CL&31; +// cycles-=c; + if (!c) break; +// if (c>7) pclog("Shiftb %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp2) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL b,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempc=temp&0x80; + temp<<=1; + if (templ) temp|=1; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x18: /*RCR b,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempc=temp&1; + temp>>=1; + if (templ) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + seteab(temp<>c); if (abrt) break; + setznp8(temp>>c); + if ((temp>>(c-1))&1) flags|=C_FLAG; + if (c==1 && temp&0x80) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x38: /*SAR b,CL*/ + tempc=(temp>>(c-1))&1; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + } + seteab(temp); if (abrt) break; + setznp8(temp); + if (tempc) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + + case 0xD3: case 0x2D3: + fetchea(); + tempw=geteaw(); if (abrt) break; + c=CL&31; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempw2) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL w,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempc=tempw&0x8000; + tempw=(tempw<<1)|templ; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x18: /*RCR w,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ=tempc; + tempw2=(templ&1)?0x8000:0; + tempc=tempw&1; + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (tempc) flags|=C_FLAG; + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + seteaw(tempw<>c); if (abrt) break; + setznp16(tempw>>c); + if ((tempw>>(c-1))&1) flags|=C_FLAG; + if (c==1 && tempw&0x8000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + tempc=((int16_t)tempw>>(c-1))&1; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + } + seteaw(tempw); if (abrt) break; + setznp16(tempw); + if (tempc) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + case 0x1D3: case 0x3D3: + fetchea(); + templ=geteal(); if (abrt) break; + c=CL&31; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL l,CL*/ + while (c>0) + { + temp=(templ&0x80000000)?1:0; + templ=(templ<<1)|temp; + c--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (temp) flags|=C_FLAG; + if ((flags&C_FLAG)^(templ>>31)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x08: /*ROR l,CL*/ + while (c>0) + { + templ2=(templ&1)?0x80000000:0; + templ=(templ>>1)|templ2; + c--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (templ2) flags|=C_FLAG; + if ((templ^(templ>>1))&0x40000000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x10: /*RCL l,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ2=tempc; + tempc=(templ>>31); + templ=(templ<<1)|templ2; + c--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (templ2) flags|=C_FLAG; + if ((flags&C_FLAG)^(templ>>31)) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + case 0x18: /*RCR l,CL*/ + tempc=flags&C_FLAG; + while (c>0) + { + templ2=(tempc)?0x80000000:0; + tempc=templ&1; + templ=(templ>>1)|templ2; + c--; + } + seteal(templ); if (abrt) break; + flags&=~(C_FLAG|V_FLAG); + if (templ2) flags|=C_FLAG; + if ((templ^(templ>>1))&0x40000000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + + case 0x20: case 0x30: /*SHL l,CL*/ + seteal(templ<>c); if (abrt) break; + setznp32(templ>>c); + if ((templ>>(c-1))&1) flags|=C_FLAG; + if (c==1 && templ&0x80000000) flags|=V_FLAG; + cycles-=((mod==3)?3:7); + break; + + case 0x38: /*SAR w,CL*/ + templ2=templ&0x80000000; + tempc=(templ>>(c-1))&1; + while (c>0) + { + templ=(templ>>1)|templ2; + c--; + } + seteal(templ); if (abrt) break; + setznp32(templ); + if (tempc) flags|=C_FLAG; + cycles-=((mod==3)?3:7); + break; + } + break; + + + case 0xD4: case 0x1D4: case 0x2D4: case 0x3D4: /*AAM*/ + tempws=readmemb(cs,pc); pc++; + if (!tempws || cpu_manufacturer != MANU_INTEL) tempws = 10; + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles-=(is486)?15:17; + break; + case 0xD5: case 0x1D5: case 0x2D5: case 0x3D5: /*AAD*/ + tempws=readmemb(cs,pc); pc++; + if (cpu_manufacturer != MANU_INTEL) tempws = 10; + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles-=(is486)?14:19; + break; + case 0xD6: case 0x1D6: case 0x2D6: case 0x3D6: /*SETALC*/ + AL=(flags&C_FLAG)?0xFF:0; + cycles -= timing_rr; + break; + case 0xD7: case 0x1D7: /*XLAT*/ + addr=(BX+AL)&0xFFFF; + temp=readmemb(ds,addr); if (abrt) break; + AL=temp; + cycles-=5; + break; + case 0x2D7: case 0x3D7: /*XLAT*/ + addr=EBX+AL; + temp=readmemb(ds,addr); if (abrt) break; + AL=temp; + cycles-=5; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0x1D9: case 0x1DA: case 0x1DB: case 0x1DD: /*ESCAPE*/ + case 0x2D9: case 0x2DA: case 0x2DB: case 0x2DD: /*ESCAPE*/ + case 0x3D9: case 0x3DA: case 0x3DB: case 0x3DD: /*ESCAPE*/ + case 0xD8: case 0x1D8: case 0x2D8: case 0x3D8: + case 0xDC: case 0x1DC: case 0x2DC: case 0x3DC: + case 0xDE: case 0x1DE: case 0x2DE: case 0x3DE: + case 0xDF: case 0x1DF: case 0x2DF: case 0x3DF: + if ((cr0&6)==4) + { + pc=oldpc; + pmodeint(7,0); + cycles-=59; + } + else + { + fpucount++; + fetchea(); + if (hasfpu) + { + x87_pc_off=oldpc; + x87_pc_seg=CS; + x87_op_off=eaaddr; + x87_op_seg=ea_rseg; + switch (opcode) + { + case 0xD8: x87_d8(); break; + case 0xD9: x87_d9(); break; + case 0xDA: x87_da(); break; + case 0xDB: x87_db(); break; + case 0xDC: x87_dc(); break; + case 0xDD: x87_dd(); break; + case 0xDE: x87_de(); break; + case 0xDF: x87_df(); break; + } + } + //cycles-=8; + } + break; + + case 0xE0: case 0x1E0: /*LOOPNE*/ + offset=(int8_t)readmemb(cs,pc); pc++; + CX--; + if (CX && !(flags&Z_FLAG)) { pc+=offset; } + cycles-=(is486)?7:11; + break; + case 0x2E0: case 0x3E0: /*LOOPNE*/ + offset=(int8_t)readmemb(cs,pc); pc++; + ECX--; + if (ECX && !(flags&Z_FLAG)) { pc+=offset; } + cycles-=(is486)?7:11; + break; + case 0xE1: case 0x1E1: /*LOOPE*/ + offset=(int8_t)readmemb(cs,pc); pc++; + CX--; + if (CX && (flags&Z_FLAG)) { pc+=offset; } + cycles-=(is486)?7:11; + break; + case 0x2E1: case 0x3E1: /*LOOPE*/ + offset=(int8_t)readmemb(cs,pc); pc++; + ECX--; + if (ECX && (flags&Z_FLAG)) { pc+=offset; } + cycles-=(is486)?7:11; + break; + case 0xE2: case 0x1E2: /*LOOP*/ + offset=(int8_t)readmemb(cs,pc); pc++; + CX--; + if (CX) { pc+=offset; } + cycles-=(is486)?7:11; + break; + case 0x2E2: case 0x3E2: /*LOOP*/ + offset=(int8_t)readmemb(cs,pc); pc++; + ECX--; + if (ECX) { pc+=offset; } + cycles-=(is486)?7:11; + break; + case 0xE3: case 0x1E3: /*JCXZ*/ + offset=(int8_t)readmemb(cs,pc); pc++; + if (!CX) { pc+=offset; cycles-=4; } + cycles-=5; + break; + case 0x2E3: case 0x3E3: /*JECXZ*/ + offset=(int8_t)readmemb(cs,pc); pc++; + if (!ECX) { pc+=offset; cycles-=4; } + cycles-=5; + break; + + case 0xE4: case 0x1E4: case 0x2E4: case 0x3E4: /*IN AL*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + pc++; + AL=inb(temp); + cycles-=12; + break; + case 0xE5: case 0x2E5: /*IN AX*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + checkio_perm(temp+1); + pc++; + AX=inw(temp); + cycles-=12; + break; + case 0x1E5: case 0x3E5: /*IN EAX*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + checkio_perm(temp+1); + checkio_perm(temp+2); + checkio_perm(temp+3); + pc++; + EAX=inl(temp); + cycles-=12; + break; + case 0xE6: case 0x1E6: case 0x2E6: case 0x3E6: /*OUT AL*/ + temp=readmemb(cs,pc); +// if (output) pclog("OUT %02X,%02X - %08X\n",temp,AL,writelookup2); + checkio_perm(temp); + // if (output) pclog(" - %08X\n",writelookup2); + pc++; + outb(temp,AL); +// if (output) pclog(" - %08X\n",writelookup2); + cycles-=10; + break; + case 0xE7: case 0x2E7: /*OUT AX*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + checkio_perm(temp+1); + pc++; + outw(temp,AX); + cycles-=10; + break; + case 0x1E7: case 0x3E7: /*OUT EAX*/ + temp=readmemb(cs,pc); + checkio_perm(temp); + checkio_perm(temp+1); + checkio_perm(temp+2); + checkio_perm(temp+3); + pc++; + outl(temp,EAX); + cycles-=10; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); if (abrt) break; + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,pc); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),pc); if (abrt) break; + SP-=2; + } + pc+=(int16_t)tempw; + cycles-=(is486)?3:7; + break; + case 0x3E8: /*CALL rel 16*/ + templ=getlong(); if (abrt) break; + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,pc); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),pc); if (abrt) break; + SP-=4; + } + pc+=templ; + cycles-=(is486)?3:7; + break; + case 0xE9: case 0x2E9: /*JMP rel 16*/ + tempw=getword(); if (abrt) break; + pc+=(int16_t)tempw; + cycles-=(is486)?3:7; + break; + case 0x1E9: case 0x3E9: /*JMP rel 32*/ + templ=getlong(); if (abrt) break; + pc+=templ; + cycles-=(is486)?3:7; + break; + case 0xEA: case 0x2EA: /*JMP far*/ + addr=getword(); + tempw=getword(); if (abrt) { if (output==3) pclog("JMP ABRT\n"); break; } + oxpc=pc; + pc=addr; + loadcsjmp(tempw,oxpc); + cycles-=(is486)?17:12; + break; + case 0x1EA: case 0x3EA: /*JMP far*/ + templ=getlong(); + tempw=getword(); if (abrt) break; + oxpc=pc; + pc=templ; + loadcsjmp(tempw,oxpc); + cycles-=(is486)?17:12; + break; + case 0xEB: case 0x1EB: case 0x2EB: case 0x3EB: /*JMP rel*/ + offset=(int8_t)readmemb(cs,pc); pc++; + pc+=offset; + cycles-=(is486)?3:7; + break; + case 0xEC: case 0x1EC: case 0x2EC: case 0x3EC: /*IN AL,DX*/ + checkio_perm(DX); + AL=inb(DX); + cycles-=13; + break; + case 0xED: case 0x2ED: /*IN AX,DX*/ + checkio_perm(DX); + checkio_perm(DX+1); + AX=inw(DX); + cycles-=13; + break; + case 0x1ED: case 0x3ED: /*IN EAX,DX*/ + checkio_perm(DX); + checkio_perm(DX+1); + checkio_perm(DX+2); + checkio_perm(DX+3); + EAX=inl(DX); + cycles-=13; + break; + case 0xEE: case 0x1EE: case 0x2EE: case 0x3EE: /*OUT DX,AL*/ + checkio_perm(DX); + outb(DX,AL); + cycles-=11; + break; + case 0xEF: case 0x2EF: /*OUT DX,AX*/ + checkio_perm(DX); + checkio_perm(DX+1); + outw(DX,AX); + cycles-=11; + break; + case 0x1EF: case 0x3EF: /*OUT DX,EAX*/ + checkio_perm(DX); + checkio_perm(DX+1); + checkio_perm(DX+2); + checkio_perm(DX+3); + outl(DX,EAX); + cycles-=11; + break; + + case 0xF0: case 0x1F0: case 0x2F0: case 0x3F0: /*LOCK*/ + cycles-=4; + break; + + case 0xF2: case 0x1F2: case 0x2F2: case 0x3F2: /*REPNE*/ + rep386(0); + break; + case 0xF3: case 0x1F3: case 0x2F3: case 0x3F3: /*REPE*/ + rep386(1); + break; + + case 0xF4: case 0x1F4: case 0x2F4: case 0x3F4: /*HLT*/ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { +// pclog("Can't HLT\n"); + x86gpf(NULL,0); + //output=3; + break; + } + inhlt=1; + pc--; + if (!((flags&I_FLAG) && (((pic.pend&~pic.mask)&~pic.mask2) || ((pic2.pend&~pic2.mask)&~pic2.mask2)) && !ssegs && !noint)) cycles = oldcyc - 100; + else cycles-=5; + break; + case 0xF5: case 0x1F5: case 0x2F5: case 0x3F5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: case 0x1F6: case 0x2F6: case 0x3F6: + fetchea(); + temp=geteab(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + temp2=readmemb(cs,pc); pc++; if (abrt) break; +// pclog("TEST %02X,%02X\n",temp,temp2); + temp&=temp2; + setznp8(temp); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x20: /*MUL AL,b*/ +// setznp8(AL); + AX=AL*temp; +// if (AX) flags&=~Z_FLAG; +// else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=13; + break; + case 0x28: /*IMUL AL,b*/ +// setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; +// if (AX) flags&=~Z_FLAG; +// else flags|=Z_FLAG; + if (AH && AH!=0xFF) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=14; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) tempw2=tempw/temp; +// pclog("DIV %04X/%02X %04X:%04X\n",tempw,temp,CS,pc); + if (temp && !(tempw2&0xFF00)) + { + tempw2=tempw%temp; + AH=tempw2; + tempw/=temp; + AL=tempw&0xFF; + if (!cpu_iscyrix) flags|=0x8D5; /*Not a Cyrix*/ + } + else + { +// fatal("DIVb BY 0\n"); + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { +// pclog("%04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; + } + cycles-=(is486)?16:14; + break; + case 0x38: /*IDIV AL,b*/ +// pclog("IDIV %04X/%02X\n",tempw,temp); + tempws=(int)(int16_t)AX; + if (temp!=0) tempws2=tempws/(int)((int8_t)temp); + temps=tempws2&0xFF; + if ((temp!=0) && ((int)temps==tempws2)) + { + tempw2=tempws%(int)((int8_t)temp); + AH=tempw2&0xFF; + AL=tempws2&0xFF; + if (!cpu_iscyrix) flags|=0x8D5; /*Not a Cyrix*/ + } + else + { + pclog("IDIVb exception - %X / %08X = %X\n",tempws,temp,tempws2); +// pclog("IDIVb BY 0 %04X:%04X\n",cs>>4,pc); + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); + } + cycles-=19; + break; + + default: + pclog("Bad F6 opcode %02X\n",rmdat&0x38); + x86illegal(); + } + break; + + case 0xF7: case 0x2F7: + fetchea(); + tempw=geteaw(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + tempw2=getword(); if (abrt) break; +// if (output==3) pclog("TEST %04X %04X\n",tempw,tempw2); + setznp16(tempw&tempw2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x20: /*MUL AX,w*/ +// setznp16(AX); + templ=AX*tempw; + AX=templ&0xFFFF; + DX=templ>>16; +// if (AX|DX) flags&=~Z_FLAG; +// else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=21; + break; + case 0x28: /*IMUL AX,w*/ +// setznp16(AX); +// pclog("IMUL %i %i ",(int)((int16_t)AX),(int)((int16_t)tempw)); + templ=(int)((int16_t)AX)*(int)((int16_t)tempw); +// pclog("%i ",tempws); + AX=templ&0xFFFF; + DX=templ>>16; + if (DX && DX!=0xFFFF) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=22; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; + if (tempw) templ2=templ/tempw; + if (tempw && !(templ2&0xFFFF0000)) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { +// pclog("%04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X 1\n",cs>>4,pc,0xf7,0x30); + } + cycles-=(is486)?24:22; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); + if (tempw!=0) tempws2=tempws/(int)((int16_t)tempw); + temps16=tempws2&0xFFFF; +// pclog("IDIV %i %i ",tempws,tempw); + if ((tempw!=0) && ((int)temps16==tempws2)) + { + DX=tempws%(int)((int16_t)tempw); + AX=tempws2&0xFFFF; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + pclog("IDIVw exception - %X / %08X = %X\n",tempws,tempw,tempws2); +// pclog("IDIVw BY 0 %04X:%04X\n",cs>>4,pc); +// DX=0; +// AX=0xFFFF; + pc=oldpc; + if (msw&1) pmodeint(0,0); + else + { +// pclog("%04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + oxpc=pc; + pc=readmemw(0,0); + loadcs(readmemw(0,2)); + } +// cs=loadcs(CS); +// cs=CS<<4; +// pclog("Div by zero %04X:%04X %02X %02X 1\n",cs>>4,pc,0xf7,0x38); + } + cycles-=27; + break; + + default: + pclog("Bad F7 opcode %02X\n",rmdat&0x38); + x86illegal(); + } + break; + case 0x1F7: case 0x3F7: + fetchea(); + templ=geteal(); if (abrt) break; + switch (rmdat&0x38) + { + case 0x00: /*TEST l*/ + templ2=getlong(); if (abrt) break; + setznp32(templ&templ2); + if (is486) cycles-=((mod==3)?1:2); + else cycles-=((mod==3)?2:5); + break; + case 0x10: /*NOT l*/ + seteal(~templ); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x18: /*NEG l*/ + setsub32(0,templ); + templ=0-templ; + seteal(templ); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x20: /*MUL EAX,l*/ + temp64=(uint64_t)EAX*(uint64_t)templ; + EAX=temp64&0xFFFFFFFF; + EDX=temp64>>32; + if (EDX) flags|= (C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=21; + break; + case 0x28: /*IMUL EAX,l*/ + temp64=(int64_t)(int32_t)EAX*(int64_t)(int32_t)templ; + EAX=temp64&0xFFFFFFFF; + EDX=temp64>>32; + if (EDX && EDX!=0xFFFFFFFF) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=38; + break; + case 0x30: /*DIV EAX,l*/ + divl(templ); + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + cycles-=(is486)?40:38; + break; + case 0x38: /*IDIV EAX,l*/ + idivl((int32_t)templ); + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + cycles-=43; + break; + + default: + pclog("Bad F7 opcode %02X\n",rmdat&0x38); + x86illegal(); + } + break; + + case 0xF8: case 0x1F8: case 0x2F8: case 0x3F8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: case 0x1F9: case 0x2F9: case 0x3F9: /*STC*/ +// pclog("STC %04X\n",pc); + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: case 0x1FA: case 0x2FA: case 0x3FA: /*CLI*/ + if (!IOPLp) + { +// output=3; +// pclog("Can't CLI %i %i %04X:%08X\n",IOPL,CPL,CS,pc); +// if (CS==0x1C7 && pc==0x5BE) output=3; + x86gpf(NULL,0); + } + else + flags&=~I_FLAG; +// pclog("CLI at %04X:%04X\n",cs>>4,pc); + cycles-=3; + break; + case 0xFB: case 0x1FB: case 0x2FB: case 0x3FB: /*STI*/ + if (!IOPLp) + { +// pclog("Can't STI %04X:%08X\n",CS,pc); +// output=3; + x86gpf(NULL,0); + } + else + flags|=I_FLAG; +// pclog("STI at %04X:%04X\n",cs>>4,pc); + cycles-=2; + break; + case 0xFC: case 0x1FC: case 0x2FC: case 0x3FC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: case 0x1FD: case 0x2FD: case 0x3FD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: case 0x1FE: case 0x2FE: case 0x3FE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); if (abrt) break; + if (rmdat&0x38) + { + seteab(temp-1); if (abrt) break; + flags&=~V_FLAG; + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + seteab(temp+1); if (abrt) break; + flags&=~V_FLAG; + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + + case 0xFF: case 0x2FF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); if (abrt) break; + seteaw(tempw+1); if (abrt) break; + setadd16nc(tempw,1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); if (abrt) break; + seteaw(tempw-1); if (abrt) break; + setsub16nc(tempw,1); + cycles -= (mod == 3) ? timing_rr : timing_mm; + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (output) pclog("CALL %04X %08X:%08X\n", tempw, easeg, eaaddr); + if (abrt) break; + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,pc); if (abrt) break; + ESP-=2; + } + else + { + writememw(ss,(SP-2)&0xFFFF,pc); if (abrt) break; + SP-=2; + } + pc=tempw; + if (is486) cycles-=5; + else cycles-=((mod==3)?7:10); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,(eaaddr+2)); if (output==3) pclog("CALL FAR %04X:%04X\n",tempw,tempw2); if (abrt) break; + tempw3=CS; + templ2=pc; + if (ssegs) ss=oldss; + oxpc=pc; + pc=tempw; + optype=CALL; + cgate32=0; + if (msw&1) loadcscall(tempw2); + else loadcs(tempw2); + optype=0; + if (abrt) break; + oldss=ss; + if (cgate32) goto writecall32_2; + writecall16_2: + if (stack32) + { + writememw(ss,ESP-2,tempw3); + writememw(ss,ESP-4,templ2); + ESP-=4; + } + else + { + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),templ2); + SP-=4; + } + cycles-=(is486)?17:22; + break; + case 0x20: /*JMP*/ + tempw=geteaw(); if (abrt) break; + pc=tempw; + if (is486) cycles-=5; + else cycles-=((mod==3)?7:10); + break; + case 0x28: /*JMP far*/ + oxpc=pc; + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,eaaddr+2); if (abrt) break; + pc=tempw; + loadcsjmp(tempw2,oxpc); if (abrt) break; + cycles-=(is486)?13:12; + break; + case 0x30: /*PUSH w*/ + tempw=geteaw(); if (abrt) break; + if (ssegs) ss=oldss; + if (stack32) + { + writememw(ss,ESP-2,tempw); if (abrt) break; + ESP-=2; + } + else + { +// if (output) pclog("PUSH %04X to %04X\n",tempw,SP-2); + writememw(ss,((SP-2)&0xFFFF),tempw); if (abrt) break; + SP-=2; + } + cycles-=((mod==3)?2:5); + break; + + default: + pclog("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + break; + case 0x1FF: case 0x3FF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC l*/ + templ=geteal(); if (abrt) break; + seteal(templ+1); if (abrt) break; + setadd32nc(templ,1); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x08: /*DEC l*/ + templ=geteal(); if (abrt) break; + seteal(templ-1); if (abrt) break; + setsub32nc(templ,1); + cycles -= (mod == 3) ? timing_rr : timing_mml; + break; + case 0x10: /*CALL*/ + templ=geteal(); if (abrt) break; + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,pc); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,(SP-4)&0xFFFF,pc); if (abrt) break; + SP-=4; + } + pc=templ; + if (pc==0xFFFFFFFF) pclog("Failed CALL!\n"); + if (is486) cycles-=5; + else cycles-=((mod==3)?7:10); + break; + case 0x18: /*CALL far*/ + templ=readmeml(easeg,eaaddr); + tempw2=readmemw(easeg,(eaaddr+4)); if (abrt) break; + tempw3=CS; + templ2=pc; + if (ssegs) ss=oldss; + oxpc=pc; + pc=templ; + optype=CALL; + cgate16=0; + if (msw&1) loadcscall(tempw2); + else loadcs(tempw2); + optype=0; + if (abrt) break; + oldss=ss; + if (cgate16) goto writecall16_2; + writecall32_2: + if (stack32) + { + writememl(ss,ESP-4,tempw3); + writememl(ss,ESP-8,templ2); + ESP-=8; + } + else + { + writememl(ss,(SP-4)&0xFFFF,tempw3); + writememl(ss,(SP-8)&0xFFFF,templ2); + SP-=8; + } + if (pc==0xFFFFFFFF) pclog("Failed CALL far!\n"); + cycles-=(is486)?17:22; + break; + case 0x20: /*JMP*/ + templ=geteal(); if (abrt) break; + pc=templ; + if (is486) cycles-=5; + else cycles-=((mod==3)?7:12); + if (pc==0xFFFFFFFF) pclog("Failed JMP!\n"); + break; + case 0x28: /*JMP far*/ + oxpc=pc; + templ=readmeml(easeg,eaaddr); + templ2=readmeml(easeg,eaaddr+4); if (abrt) break; + pc=templ; + loadcsjmp(templ2,oxpc); + if (pc==0xFFFFFFFF) pclog("Failed JMP far!\n"); + cycles-=(is486)?13:12; + break; + case 0x30: /*PUSH l*/ + templ=geteal(); if (abrt) break; + if (ssegs) ss=oldss; + if (stack32) + { + writememl(ss,ESP-4,templ); if (abrt) break; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),templ); if (abrt) break; + SP-=4; + } + cycles-=((mod==3)?2:5); + break; + + default: + pclog("Bad 32-bit FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + break; + + default: +// pc--; +// cycles-=8; +// break; + pclog("Bad opcode %02X %i %03X at %04X:%04X from %04X:%04X %08X\n",opcode,op32>>8,opcode|op32,cs>>4,pc,old8>>16,old8&0xFFFF,old82); + x86illegal(); + } + opcodeend: + if (!use32) pc&=0xFFFF; + + if (ssegs) + { + ds=oldds; + ss=oldss; + rds=DS; + ssegs=0; + } + if (abrt) + { + +// if (CS == 0x228) pclog("Abort at %04X:%04X - %i %i %i\n",CS,pc,notpresent,nullseg,abrt); +/* if (testr[0]!=EAX) pclog("EAX corrupted %08X\n",pc); + if (testr[1]!=EBX) pclog("EBX corrupted %08X\n",pc); + if (testr[2]!=ECX) pclog("ECX corrupted %08X\n",pc); + if (testr[3]!=EDX) pclog("EDX corrupted %08X\n",pc); + if (testr[4]!=ESI) pclog("ESI corrupted %08X\n",pc); + if (testr[5]!=EDI) pclog("EDI corrupted %08X\n",pc); + if (testr[6]!=EBP) pclog("EBP corrupted %08X\n",pc); + if (testr[7]!=ESP) pclog("ESP corrupted %08X\n",pc); + if (testr[8]!=flags) pclog("FLAGS corrupted %08X\n",pc);*/ + tempi = abrt; + abrt = 0; + x86_doabrt(tempi); + if (abrt) + { + abrt = 0; + CS = oldcs; + pc = oldpc; + pclog("Double fault %i %i\n", ins, resets); + pmodeint(8, 0); + if (abrt) + { + abrt = 0; + softresetx86(); + pclog("Triple fault - reset\n"); + } + } + } + cycdiff=oldcyc-cycles; + + if (trap && (flags&T_FLAG) && !noint) + { +// oldpc=pc; +// oldcs=CS; +// printf("TRAP!!! %04X:%04X\n",CS,pc); + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + addr=1<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if ((flags&I_FLAG) && (((pic.pend&~pic.mask)&~pic.mask2) || ((pic2.pend&~pic2.mask)&~pic2.mask2)) && !noint) + { + temp=picinterrupt(); + if (temp!=0xFF) + { +// if (temp == 0x54) pclog("Take int 54\n"); +// if (output) output=3; +// pclog("Hardware int %02X %i %i %04X(%08X):%08X\n",temp,ins, ins2, CS,cs,pc); +// if (temp==0x54) output=3; + if (inhlt) pc++; + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + addr=temp<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=pc; + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); +// if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc); + } + inint=1; + } + } + if (noint) noint=0; + ins++; + insc++; + +/* if (times && ins == 9000000) output = 3; + if (CS == 0x1000 && pc == 0x1200) + fatal("Hit it\n");*/ +// if (!ins) ins2++; + + } + + keybsenddelay -= cycdiff; + if (keybsenddelay<1) + { + keybsenddelay = 1000; + keyboard_at_poll(); + } + + pit.c[0]-=cycdiff; + pit.c[1]-=cycdiff; + if (ppi.pb&1) pit.c[2]-=cycdiff; + if ((pit.c[0]<1)||(pit.c[1]<1)||(pit.c[2]<1)) pit_poll(); + spktime-=cycdiff; + if (spktime<=0.0) + { + spktime+=SPKCONST; +// pclog("1Poll spk\n"); + pollspk(); + pollgussamp(); + getsbsamp(); + polladlib(); + getdacsamp(); +// pclog("2Poll spk\n"); + } + soundtime-=cycdiff; + if (soundtime<=0.0) + { + soundtime+=SOUNDCONST; +// pclog("1Poll sound60hz\n"); + pollsound60hz(); +// pclog("2Poll sound60hz\n"); + } + gustime-=cycdiff; + while (gustime<=0.0) + { + gustime+=GUSCONST; + pollgus(); + } + gustime2-=cycdiff; + while (gustime2<=0.0) + { + gustime2+=GUSCONST2; + pollgus2(); + } + vidtime-=cycdiff; + if (vidtime<=0.0) + { +// pclog("1Poll video\n"); + pollvideo(); +// pclog("2Poll video\n"); + } + if (disctime) + { + disctime-=(cycdiff); + if (disctime<=0) + { +// pclog("1Poll disc\n"); + disctime=0; + fdc_poll(); +// pclog("2Poll disc\n"); + } + } + if (mousedelay) + { + mousedelay-=20; + if (!mousedelay) + { +// pclog("1Poll mouse\n"); + mousecallback(); +// pclog("2Poll disc\n"); + } + } + if (sbenable) + { + sbcount-=cycdiff; + if (sbcount<0) + { + sbcount+=sblatcho; + pollsb(); + } + } + if (sb_enable_i) + { + sb_count_i-=cycdiff; + if (sb_count_i<0) + { + sb_count_i+=sblatchi; + sb_poll_i(); + } + } + if (idecallback[0]) + { + idecallback[0]--; + if (idecallback[0]<=0) + { +// pclog("IDE time over\n"); + idecallback[0]=0; + callbackide(0); + } + } + if (idecallback[1]) + { + idecallback[1]--; + if (idecallback[1]<=0) + { +// pclog("IDE time over\n"); + idecallback[1]=0; + callbackide(1); + } + } + rtctime-=cycdiff; + if (rtctime<0) + { + nvr_rtc(); + } + } +} diff --git a/src/Makefile.mingw b/src/Makefile.mingw new file mode 100644 index 00000000..8f48c1aa --- /dev/null +++ b/src/Makefile.mingw @@ -0,0 +1,43 @@ +VPATH = . mame +CPP = g++.exe +CC = gcc.exe +WINDRES = windres.exe +CFLAGS = -O3 -march=i686 -fomit-frame-pointer +OBJ = 286.o 386.o acer386sx.o adlib.o ali1429.o amstrad.o cdrom-ioctl.o cms.o \ + config.o cpu.o dac.o dma.o ega.o fdc.o gus.o harddisk.o \ + headland.o ide.o io.o jim.o keyboard.o keyboard_amstrad.o keyboard_at.o \ + keyboard_olim24.o keyboard_xt.o lpt.o mcr.o mem.o model.o \ + mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \ + opti.o pc.o pci.o pic.o pit.o \ + ppi.o psg.o sblaster.o serial.o sound.o soundopenal.o um8881f.o \ + vid_cga.o vid_ega.o vid_et4000.o vid_et4000w32.o \ + vid_et4000w32i.o vid_hercules.o vid_icd2061.o vid_mda.o vid_olivetti_m24.o \ + vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o \ + vid_pc200.o vid_s3.o vid_sdac_ramdac.o vid_stg_ramdac.o \ + vid_svga.o vid_tandy.o vid_tkd8001_ramdac.o vid_tvga.o \ + vid_unk_ramdac.o video.o wd76c10.o win.o win-ddraw.o \ + win-keyboard.o win-mouse.o win-timer.o win-video.o x86.o \ + x86seg.o x87.o xtide.o pc.res +FMOBJ = fmopl.o ymf262.o + + +LIBS = -mwindows -lwinmm -lalut -lopenal32 -lddraw -ldinput -ldxguid + +PCem.exe: $(OBJ) $(FMOBJ) + $(CC) $(OBJ) $(FMOBJ) -o "PCem.exe" $(LIBS) + +all : PCem.exe + +clean : + del *.o + del *.exe + del *.res + +%.o : %.c + $(CC) $(CFLAGS) -c $< + +%.o : %.cc + $(CPP) $(CFLAGS) -c $< + +pc.res: pc.rc + $(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff \ No newline at end of file diff --git a/src/acer386sx.c b/src/acer386sx.c new file mode 100644 index 00000000..3e03ed77 --- /dev/null +++ b/src/acer386sx.c @@ -0,0 +1,33 @@ +#include "ibm.h" +#include "io.h" +#include "cpu.h" + +#include "acer386sx.h" + +static int acer_index = 0; +static uint8_t acer_regs[256]; + +void acer386sx_write(uint16_t addr, uint8_t val) +{ + if (addr & 1) + acer_regs[acer_index] = val; + else + acer_index = val; +} + +uint8_t acer386sx_read(uint16_t addr) +{ + if (addr & 1) + { + if ((acer_index >= 0xc0 || acer_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return acer_regs[acer_index]; + } + else + return acer_index; +} + +void acer386sx_init() +{ + io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL); +} diff --git a/src/acer386sx.h b/src/acer386sx.h new file mode 100644 index 00000000..12d98f19 --- /dev/null +++ b/src/acer386sx.h @@ -0,0 +1 @@ +void acer386sx_init(); diff --git a/src/adlib.c b/src/adlib.c new file mode 100644 index 00000000..d4b28283 --- /dev/null +++ b/src/adlib.c @@ -0,0 +1,187 @@ +#include +#include +#include "ibm.h" +#include "mame/fmopl.h" +#include "mame/ymf262.h" + +/*Interfaces between PCem and the actual Adlib emulator*/ + +static int adlib_inited = 0; +int adlibpos=0; +void *YM3812[2]; +void *YMF262; +int fm_timers[2][2],fm_timers_enable[2][2]; + +void adlib_write(uint16_t a, uint8_t v) +{ +// printf("Adlib write %04X %02X %i\n",a,v,sbtype); + if (!sbtype) return; + if (sbtype=SBPRO2) + { + switch (a) + { + case 0x220: case 0x221: + case 0x222: case 0x223: + case 0x228: case 0x229: + case 0x388: case 0x389: + temp=ymf262_read(YMF262,a); +// pclog("YMF262 read %03X %02X\n",a,temp); + cycles-=(int)(isa_timing * 8); + return temp; + } + } + if (!sbtype) return 0xFF; + switch (a) + { + case 0x220: case 0x221: + if (sbtype=SBPRO2) + { + ymf262_update_one(YMF262,ad_bufs,size); + for (c=0;c +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "cpu.h" + +#include "ali1429.h" + +static int ali1429_index; +static uint8_t ali1429_regs[256]; + +void ali1429_write(uint16_t port, uint8_t val) +{ +// return; + if (!(port&1)) ali1429_index=val; + else + { + ali1429_regs[ali1429_index]=val; +// pclog("ALI1429 write %02X %02X %04X:%04X %i\n",ali1429_index,val,CS,pc,ins); + switch (ali1429_index) + { + case 0x13: +/* if (val == 1) + { + times = 1; + ins = 0; + output = 3; + }*/ +// pclog("write 13 %02X %i\n",val,shadowbios); + if (!(val&0xC0)) + { + shadowbios=0; + if (!shadowbios_write) + mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL ); + else + mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); + flushmmucache(); + } + break; + case 0x14: + shadowbios=val&1;//((val&3)==1); + shadowbios_write=val&2; + switch (val & 3) + { + case 0: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, NULL, NULL, NULL ); break; + case 1: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, NULL, NULL, NULL ); break; + case 2: mem_sethandler(0xf0000, 0x10000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); break; + case 3: mem_sethandler(0xf0000, 0x10000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); break; + } + +// if (val==0x43) shadowbios=1; +// pclog("Shadow bios %i\n",shadowbios); + flushmmucache(); + break; + } + } +} + +uint8_t ali1429_read(uint16_t port) +{ + if (!(port&1)) return ali1429_index; + if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return ali1429_regs[ali1429_index]; +} + + +void ali1429_reset() +{ + memset(ali1429_regs,0xFF,256); +} + +void ali1429_init() +{ + io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL); +} diff --git a/src/ali1429.h b/src/ali1429.h new file mode 100644 index 00000000..ad950d67 --- /dev/null +++ b/src/ali1429.h @@ -0,0 +1 @@ +void ali1429_init(); diff --git a/src/amstrad.c b/src/amstrad.c new file mode 100644 index 00000000..2f5dee8c --- /dev/null +++ b/src/amstrad.c @@ -0,0 +1,84 @@ +#include "ibm.h" +#include "io.h" +#include "keyboard.h" +#include "lpt.h" +#include "mouse.h" + +#include "amstrad.h" + +static uint8_t amstrad_dead; + +uint8_t amstrad_read(uint16_t port) +{ + pclog("amstrad_read : %04X\n",port); + switch (port) + { + case 0x379: + return 7 | readdacfifo(); + case 0x37a: + if (romset == ROM_PC1512) return 0x20; + if (romset == ROM_PC200) return 0x80; + return 0; + case 0xdead: + return amstrad_dead; + } + return 0xff; +} + +void amstrad_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0xdead: + amstrad_dead = val; + break; + } +} + +static uint8_t mousex,mousey; + +void amstrad_mouse_write(uint16_t addr, uint8_t val) +{ +// pclog("Write mouse %04X %02X %04X:%04X\n", addr, val, CS, pc); + if (addr==0x78) mousex=0; + else mousey=0; +} + +uint8_t amstrad_mouse_read(uint16_t addr) +{ + uint8_t temp; +// printf("Read mouse %04X %04X:%04X %02X\n", addr, CS, pc, (addr == 0x78) ? mousex : mousey); + if (addr==0x78) return mousex; + return mousey; +} + +static int oldb = 0; + +void amstrad_mouse_poll(int x, int y, int b) +{ + mousex += x; + mousey += y; + + if ((b & 1) && !(oldb & 1)) + keyboard_send(0x7e); + if ((b & 2) && !(oldb & 2)) + keyboard_send(0x7d); + if (!(b & 1) && (oldb & 1)) + keyboard_send(0xfe); + if (!(b & 2) && (oldb & 2)) + keyboard_send(0xfd); + + oldb = b; +} + +void amstrad_init() +{ + lpt2_remove(); + + io_sethandler(0x0078, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL); + io_sethandler(0x007a, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL); + io_sethandler(0x0379, 0x0002, amstrad_read, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL); + + mouse_poll = amstrad_mouse_poll; +} diff --git a/src/amstrad.h b/src/amstrad.h new file mode 100644 index 00000000..f6deaffd --- /dev/null +++ b/src/amstrad.h @@ -0,0 +1,2 @@ +void amstrad_init(); + diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c new file mode 100644 index 00000000..59e8bb6b --- /dev/null +++ b/src/cdrom-ioctl.c @@ -0,0 +1,475 @@ +/*Win32 CD-ROM support via IOCTL*/ + +#include +#include +#include "ddk/ntddcdrm.h" +//#include "ntddcdrm.h" +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +int cdrom_drive; + +typedef struct _CDROM_TOC_SESSION_DATA { + UCHAR Length[2]; + UCHAR FirstCompleteSession; + UCHAR LastCompleteSession; + TRACK_DATA TrackData[1]; +} CDROM_TOC_SESSION_DATA, *PCDROM_TOC_SESSION_DATA; +static ATAPI ioctl_atapi; + +static int ioctl_inited = 0; +static char ioctl_path[8]; +static void ioctl_close(void); +static HANDLE hIOCTL; +static CDROM_TOC toc; +static int tocvalid = 0; + +#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int ioctl_cd_state = CD_STOPPED; +static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; + +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; +void ioctl_audio_callback(int16_t *output, int len) +{ + RAW_READ_INFO in; + DWORD count; + int c; +// return; +// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); + if (ioctl_cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + in.DiskOffset.LowPart = ioctl_cd_pos * 2048; + in.DiskOffset.HighPart = 0; + in.SectorCount = 1; + in.TrackMode = CDDA; + ioctl_open(0); +// pclog("Read to %i\n", cd_buflen); + if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL)) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + ioctl_cd_pos++; + cd_buflen += (2352 / 2); + } + ioctl_close(); + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + memcpy(output, cd_buffer, len * 2); +// for (c = 0; c < BUF_SIZE - len; c++) +// cd_buffer[c] = cd_buffer[c + cd_buflen]; + memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +// pclog("Done %i\n", GetTickCount()); +} + +void ioctl_audio_stop() +{ + ioctl_cd_state = CD_STOPPED; +} + +static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ + if (!cdrom_drive) return; + pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60); + len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60); + pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = len;// + 150; + ioctl_cd_state = CD_PLAYING; + pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len); +/* CDROM_PLAY_AUDIO_MSF msf; + long size; + BOOL b; + if (ismsf) + { + msf.StartingF=pos&0xFF; + msf.StartingS=(pos>>8)&0xFF; + msf.StartingM=(pos>>16)&0xFF; + msf.EndingF=len&0xFF; + msf.EndingS=(len>>8)&0xFF; + msf.EndingM=(len>>16)&0xFF; + } + else + { + msf.StartingF=(uint8_t)(addr%75); addr/=75; + msf.StartingS=(uint8_t)(addr%60); addr/=60; + msf.StartingM=(uint8_t)(addr); + addr=pos+len+150; + msf.EndingF=(uint8_t)(addr%75); addr/=75; + msf.EndingS=(uint8_t)(addr%60); addr/=60; + msf.EndingM=(uint8_t)(addr); + } + ioctl_open(0); + b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); + pclog("DeviceIoControl returns %i\n", (int) b); + ioctl_close();*/ +} + +static void ioctl_pause(void) +{ + long size; + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_resume(void) +{ + long size; + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_stop(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_seek(uint32_t pos) +{ + long size; + if (!cdrom_drive) return; + // ioctl_cd_state = CD_STOPPED; + pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; +/* pos+=150; + CDROM_SEEK_AUDIO_MSF msf; + msf.F=(uint8_t)(pos%75); pos/=75; + msf.S=(uint8_t)(pos%60); pos/=60; + msf.M=(uint8_t)(pos); +// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F); + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); + ioctl_close();*/ +} + +static int ioctl_ready(void) +{ + long size; + int temp; + CDROM_TOC ltoc; +// pclog("Ready? %i\n",cdrom_drive); + if (!cdrom_drive) return 0; + ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); + ioctl_close(); + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) || + !tocvalid) + { + ioctl_cd_state = CD_STOPPED; + /* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3], + toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/ + // atapi_discchanged(); +/* ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); + ioctl_close();*/ + toc=ltoc; + tocvalid=1; + return 0; + } +// pclog("IOCTL says ready\n"); + return 1; +// return (temp)?1:0; +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + long size; + int pos=0; + int c; + uint32_t temp, cdpos; + if (!cdrom_drive) return 0; + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); + ioctl_close(); + b[pos++]=sub.CurrentPosition.Control; + b[pos++]=sub.CurrentPosition.TrackNumber; + b[pos++]=sub.CurrentPosition.IndexNumber; +/* pclog("Read subchannel %02X %02X %02X %02X%02X%02X%02X %02X%02X%02X%02X\n",sub.CurrentPosition.Control,sub.CurrentPosition.TrackNumber,sub.CurrentPosition.IndexNumber, + sub.CurrentPosition.AbsoluteAddress[0],sub.CurrentPosition.AbsoluteAddress[1],sub.CurrentPosition.AbsoluteAddress[2],sub.CurrentPosition.AbsoluteAddress[3], + sub.CurrentPosition.TrackRelativeAddress[0],sub.CurrentPosition.TrackRelativeAddress[1],sub.CurrentPosition.TrackRelativeAddress[2],sub.CurrentPosition.TrackRelativeAddress[3]);*/ + cdpos = ioctl_cd_pos; + if (msf) + { + b[pos++] = (uint8_t)(cdpos % 75); cdpos /= 75; + b[pos++] = (uint8_t)(cdpos % 60); cdpos /= 60; + b[pos++] = (uint8_t)cdpos; + b[pos++] = 0; + b[pos++] = (uint8_t)(cdpos % 75); cdpos /= 75; + b[pos++] = (uint8_t)(cdpos % 60); cdpos /= 60; + b[pos++] = (uint8_t)cdpos; + b[pos++] = 0; + + +// for (c=0;c<4;c++) b[pos++]=sub.CurrentPosition.AbsoluteAddress[c]; +// for (c=0;c<4;c++) b[pos++]=sub.CurrentPosition.TrackRelativeAddress[c]; + } + else + { + b[pos++] = cdpos & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = cdpos & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 24) & 0xff; +/* temp=MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1],sub.CurrentPosition.AbsoluteAddress[2],sub.CurrentPosition.AbsoluteAddress[3]); + b[pos++]=temp>>24; + b[pos++]=temp>>16; + b[pos++]=temp>>8; + b[pos++]=temp; + temp=MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1],sub.CurrentPosition.TrackRelativeAddress[2],sub.CurrentPosition.TrackRelativeAddress[3]); + b[pos++]=temp>>24; + b[pos++]=temp>>16; + b[pos++]=temp>>8; + b[pos++]=temp;*/ + } + if (ioctl_cd_state == CD_PLAYING) return 0x11; + if (ioctl_cd_state == CD_PAUSED) return 0x12; + return 0x13; +// return sub.CurrentPosition.Header.AudioStatus; +} + +static void ioctl_eject(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(); +} + +static void ioctl_load(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(); +} + +static void ioctl_readsector(uint8_t *b, int sector) +{ + LARGE_INTEGER pos; + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + pos.QuadPart=sector*2048; + ioctl_open(0); + SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN); + ReadFile(hIOCTL,b,2048,&size,NULL); + ioctl_close(); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); + ioctl_close(); + tocvalid=1; +// pclog("Read TOC done! %i\n",single); + b[2]=toc.FirstTrack; + b[3]=toc.LastTrack; + d=0; + for (c=0;c<=toc.LastTrack;c++) + { + if (toc.TrackData[c].TrackNumber>=starttrack) + { + d=c; + break; + } + } + b[2]=toc.TrackData[c].TrackNumber; + for (c=d;c<=toc.LastTrack;c++) + { + if ((len+8)>maxlen) break; +// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3])); + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control; + b[len++]=toc.TrackData[c].TrackNumber; + b[len++]=0; /*Reserved*/ + if (msf) + { + b[len++]=toc.TrackData[c].Address[0]; + b[len++]=toc.TrackData[c].Address[1]; + b[len++]=toc.TrackData[c].Address[2]; + b[len++]=toc.TrackData[c].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + if (single) break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); +/* pclog("Table of Contents (%i bytes) : \n",size); + pclog("First track - %02X\n",toc.FirstTrack); + pclog("Last track - %02X\n",toc.LastTrack); + for (c=0;c<=toc.LastTrack;c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + for (c=0;c<=toc.LastTrack;c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/ + return len; +} + +static void ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + int len=4; + int size; + uint32_t temp; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_SESSION_DATA toc; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION; + toc_ex.Msf=msf; + toc_ex.SessionTrack=0; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(); +// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control; + b[len++]=toc.TrackData[0].TrackNumber; + b[len++]=0; /*Reserved*/ + if (msf) + { + b[len++]=toc.TrackData[0].Address[0]; + b[len++]=toc.TrackData[0].Address[1]; + b[len++]=toc.TrackData[0].Address[2]; + b[len++]=toc.TrackData[0].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]); + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } +} + +int ioctl_open(char d) +{ +// char s[8]; + if (!ioctl_inited) + { + sprintf(ioctl_path,"\\\\.\\%c:",d); + pclog("Path is %s\n",ioctl_path); + tocvalid=0; + } +// pclog("Opening %s\n",ioctl_path); + hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + if (!hIOCTL) + { + //fatal("IOCTL"); + } + atapi=&ioctl_atapi; + if (!ioctl_inited) + { + ioctl_inited=1; + CloseHandle(hIOCTL); + } + return 0; +} + +static void ioctl_close(void) +{ + CloseHandle(hIOCTL); +} + +static void ioctl_exit(void) +{ + ioctl_stop(); + ioctl_inited=0; + tocvalid=0; +} + +static ATAPI ioctl_atapi= +{ + ioctl_ready, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_getcurrentsubchannel, + ioctl_readsector, + ioctl_playaudio, + ioctl_seek, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom-ioctl.h b/src/cdrom-ioctl.h new file mode 100644 index 00000000..0c170acb --- /dev/null +++ b/src/cdrom-ioctl.h @@ -0,0 +1,9 @@ +#ifndef CDROM_IOCTL_H +#define CDROM_IOCTL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern int ioctl_open(char d); + +#endif /* ! CDROM_IOCTL_H */ diff --git a/src/cms.c b/src/cms.c new file mode 100644 index 00000000..f7afc055 --- /dev/null +++ b/src/cms.c @@ -0,0 +1,141 @@ +#include +#include "ibm.h" + +int cmsaddrs[2]; +uint8_t cmsregs[2][32]; +uint16_t cmslatch[12],cmsnoisefreq[12]; +int cmsfreq[12]; +float cmscount[12]; +int cmsvol[12][2]; +int cmsstat[12]; +uint16_t cmsnoise[4]; +int cmsnoisecount[4]; +int cmsnoisetype[4]; + +#define CMSCONST (62500.0/44100.0) + +void getcms(signed short *p, int size) +{ + int c,d; + int ena[12],noiseena[12]; + for (c=0;c<6;c++) + { + ena[c]=(cmsregs[0][0x14]&(1<=(22050)) + { + cmscount[d]-=(22050); + cmsstat[d]^=1; + } + } + else if (noiseena[d]) + { + if (cmsnoise[d/3]&1) p[c] +=(cmsvol[d][0]*90); + if (cmsnoise[d/3]&1) p[c+1]+=(cmsvol[d][0]*90); + } + } + for (d=0;d<4;d++) + { + cmsnoisecount[d]+=cmsnoisefreq[d]; + while (cmsnoisecount[d]>=22050) + { + cmsnoisecount[d]-=22050; + cmsnoise[d]<<=1; + if (!(((cmsnoise[d]&0x4000)>>8)^(cmsnoise[d]&0x40))) cmsnoise[d]|=1; + } + } + } +} + +void writecms(uint16_t addr, uint8_t val) +{ + int voice; + int chip=(addr&2)>>1; + if (addr&1) + cmsaddrs[chip]=val&31; + else + { + cmsregs[chip][cmsaddrs[chip]&31]=val; + switch (cmsaddrs[chip]&31) + { + case 0x00: case 0x01: case 0x02: /*Volume*/ + case 0x03: case 0x04: case 0x05: + voice=cmsaddrs[chip]&7; + if (chip) voice+=6; + cmsvol[voice][0]=val&0xF;//((val&0xF)+(val>>4))>>1; + cmsvol[voice][1]=val>>4; + break; + case 0x08: case 0x09: case 0x0A: /*Frequency*/ + case 0x0B: case 0x0C: case 0x0D: + voice=cmsaddrs[chip]&7; + if (chip) voice+=6; + cmslatch[voice]=(cmslatch[voice]&0x700)|val; + cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255)); + break; + case 0x10: case 0x11: case 0x12: /*Octave*/ + voice=(cmsaddrs[chip]&3)<<1; + if (chip) voice+=6; + cmslatch[voice]=(cmslatch[voice]&0xFF)|((val&7)<<8); + cmslatch[voice+1]=(cmslatch[voice+1]&0xFF)|((val&0x70)<<4); + cmsfreq[voice]=(15625<<(cmslatch[voice]>>8))/(511-(cmslatch[voice]&255)); + cmsfreq[voice+1]=(15625<<(cmslatch[voice+1]>>8))/(511-(cmslatch[voice+1]&255)); + break; + case 0x16: /*Noise*/ + voice=chip*2; + cmsnoisetype[voice]=val&3; + cmsnoisetype[voice+1]=(val>>4)&3; + break; + } + } +} + +uint8_t readcms(uint16_t addr) +{ + int chip=(addr&2)>>1; + if (addr&1) return cmsaddrs[chip]; + return cmsregs[chip][cmsaddrs[chip]&31]; +} + diff --git a/src/config.c b/src/config.c new file mode 100644 index 00000000..bf2f86d8 --- /dev/null +++ b/src/config.c @@ -0,0 +1,166 @@ +#include +#include +#include "config.h" + +static char config_file[256]; + +void set_config_file(char *s) +{ + strcpy(config_file, s); +} + +void config_new() +{ + FILE *f = fopen(config_file, "wt"); + fclose(f); +} + +int get_config_int(char *head, char *name, int def) +{ + char buffer[256]; + char name2[256]; + FILE *f = fopen(config_file, "rt"); + int c, d; + int res = def; + + if (!f) + return def; + + pclog("Searching for %s\n", name); + + while (1) + { + fgets(buffer, 255, f); + if (feof(f)) break; + + c = d = 0; + + while (buffer[c] == ' ' && buffer[c]) + c++; + + if (!buffer[c]) continue; + + while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c]) + name2[d++] = buffer[c++]; + + if (!buffer[c]) continue; + name2[d] = 0; + + pclog("Comparing %s and %s\n", name, name2); + if (strcmp(name, name2)) continue; + pclog("Found!\n"); + + while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c]) + c++; + + if (!buffer[c]) continue; + + sscanf(&buffer[c], "%i", &res); + pclog("Reading value - %i\n", res); + break; + } + + fclose(f); + return res; +} + +char config_return_string[256]; + +char *get_config_string(char *head, char *name, char *def) +{ + char buffer[256]; + char name2[256]; + FILE *f = fopen(config_file, "rt"); + int c, d; + + strcpy(config_return_string, def); + + if (!f) + return config_return_string; + + pclog("Searching for %s\n", name); + + while (1) + { + fgets(buffer, 255, f); + if (feof(f)) break; + + c = d = 0; + + while (buffer[c] == ' ' && buffer[c]) + c++; + + if (!buffer[c]) continue; + + while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c]) + name2[d++] = buffer[c++]; + + if (!buffer[c]) continue; + name2[d] = 0; + + pclog("Comparing %s and %s\n", name, name2); + if (strcmp(name, name2)) continue; + pclog("Found!\n"); + + while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c]) + c++; + + if (!buffer[c]) continue; + + strcpy(config_return_string, &buffer[c]); + + c = strlen(config_return_string) - 1; + pclog("string len %i\n", c); + while (config_return_string[c] <= 32 && config_return_string[c]) + config_return_string[c--] = 0; + + pclog("Reading value - %s\n", config_return_string); + break; + } + + fclose(f); + return config_return_string; +} + +void set_config_int(char *head, char *name, int val) +{ + FILE *f = fopen(config_file, "at"); + if (!f) pclog("set_config_int - !f\n"); + fprintf(f, "%s = %i\n", name, val); + pclog("Write %s = %i\n", name, val); + fclose(f); + pclog("fclose\n"); +} + +void set_config_string(char *head, char *name, char *val) +{ + FILE *f = fopen(config_file, "at"); + if (!f) pclog("set_config_string - !f\n"); + fprintf(f, "%s = %s\n", name, val); + pclog("Write %s = %s\n", name, val); + fclose(f); +} + +char *get_filename(char *s) +{ + int c = strlen(s) - 1; + while (c > 0) + { + if (s[c] == '/' || s[c] == '\\') + return &s[c+1]; + c--; + } + return s; +} + +void append_filename(char *dest, char *s1, char *s2, int size) +{ + sprintf(dest, "%s%s", s1, s2); +} + +void put_backslash(char *s) +{ + int c = strlen(s) - 1; + if (s[c] != '/' && s[c] != '\\') + s[c] = '/'; +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 00000000..4f681bdf --- /dev/null +++ b/src/config.h @@ -0,0 +1,5 @@ +void set_config_file(char *s); +int get_config_int(char *head, char *name, int def); +char *get_config_string(char *head, char *name, char *def); +void set_config_int(char *head, char *name, int val); +void set_config_string(char *head, char *name, char *val); diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 00000000..012ee013 --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,411 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" + +int cpu = 3, cpu_manufacturer = 0; +CPU *cpu_s; +int cpu_multi; +int cpu_iscyrix; +int cpu_16bitbus; +int cpu_busspeed; + +int timing_rr; +int timing_mr, timing_mrl; +int timing_rm, timing_rml; +int timing_mm, timing_mml; +int timing_bt, timing_bnt; + +/*Available cpuspeeds : + 0 = 16 MHz + 1 = 20 MHz + 2 = 25 MHz + 3 = 33 MHz + 4 = 40 MHz + 5 = 50 MHz + 6 = 66 MHz + 7 = 75 MHz + 8 = 80 MHz + 9 = 90 MHz + 10 = 100 MHz + 11 = 120 MHz + 12 = 133 MHz + 13 = 150 MHz + 14 = 160 MHz +*/ + +CPU cpus_8088[] = +{ + /*8088 standard*/ + {"8088/4.77", CPU_8088, 0, 4772727, 1, 0, 0, 0}, + {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0}, + {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0}, + {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0}, + {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_8086[] = +{ + /*8086 standard*/ + {"8086/7.16", CPU_8086, 1, 3579545*2, 1, 0, 0, 0}, + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0}, + {"8086/9.54", CPU_8086, 1, (3579545*8)/3, 1, 0, 0, 0}, + {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0}, + {"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0}, + {"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pc1512[] = +{ + /*8086 Amstrad*/ + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_286[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0}, + {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0}, + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0}, + {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0}, + {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0}, + {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0}, + {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ibmat[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_i386[] = +{ + /*i386*/ + {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0}, + {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0}, + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0}, + {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0}, + {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0x0308, 0, 0}, + {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0x0308, 0, 0}, + {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0}, + {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_acer[] = +{ + /*i386*/ + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am386[] = +{ + /*Am386*/ + {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0x2308, 0, 0}, + {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0x2308, 0, 0}, + {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0x2308, 0, 0}, + {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0x2308, 0, 0}, + {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0x2308, 0, 0}, + {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0x0308, 0, 0}, + {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0x0308, 0, 0}, + {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0x0308, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_486SDLC[] = +{ + /*Cx486SLC/DLC*/ + {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0, 0x0000}, + {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0, 0x0000}, + {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0, 0x0000}, + {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0, 0x0006}, + {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0, 0x0006}, + {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0, 0x0006}, + {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0, 0x0001}, + {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0, 0x0001}, + {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0, 0x0001}, + {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0, 0x0007}, + {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0, 0x0007}, + {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0, 0x0007}, + {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0, 0x0007}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_i486[] = +{ + /*i486*/ + {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 0x42a, 0, 0}, + {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 0x42a, 0, 0}, + {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 0x42a, 0, 0}, + {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 0x42a, 0, 0}, + {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 0x45b, 0, 0}, + {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 0x404, 0, 0}, + {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 0x404, 0, 0}, + {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 0x404, 0, 0}, + {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 0x430, 0, 0}, + {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 0x430, 0, 0}, + {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 0x430, 0, 0}, + {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 0x481, 0x481, 0}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_i486DX,10, 100000000, 3, 0x481, 0x481, 0}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am486[] = +{ + /*Am486/5x86*/ + {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 0x42a, 0, 0}, + {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 0x42a, 0, 0}, + {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 0x45b, 0x45b, 0}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 0x45b, 0x45b, 0}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/ + {"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 0x430, 0, 0}, + {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 0x430, 0, 0}, + {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 0x470, 0x470, 0}, + {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 0x470, 0x470, 0}, + {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 0x470, 0x470, 0}, + {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 0x482, 0x482, 0}, + {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 0x482, 0x482, 0}, + {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 0x482, 0x482, 0}, + {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 0x482, 0x482, 0}, + {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 0x4e0, 0x4e0, 0}, + {"Am5x86/P75+", CPU_Am486DX, 13, 150000000, 4, 0x4e0, 0x4e0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Cx486[] = +{ + /*Cx486/5x86*/ + {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 0x420, 0, 0x0010}, + {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 0x420, 0, 0x0010}, + {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 0x420, 0, 0x0010}, + {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 0x430, 0, 0x051a}, + {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 0x430, 0, 0x051a}, + {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 0x430, 0, 0x081b}, + {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 0x430, 0, 0x0b1b}, + {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 0x430, 0, 0x311b}, + {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 0x480, 0, 0x361f}, + {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 0x480, 0, 0x361f}, + {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 0x480, 0, 0x002f}, + {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 0x480, 0, 0x002f}, + {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 0x480, 0, 0x002f}, + {"", -1, 0, 0, 0} +}; + +void cpu_set_edx() +{ + EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset; +} + +void cpu_set() +{ + CPU *cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; + + CPUID = cpu_s->cpuid_model; + cpuspeed = cpu_s->speed; + is8086 = (cpu_s->cpu_type >= CPU_8088); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC); + hasfpu = (cpu_s->cpu_type >= CPU_i486DX); + cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86); + cpu_16bitbus = (cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); + if (cpu_s->multi) + cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + cpu_multi = cpu_s->multi; + + if (cpu_iscyrix) + io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL); + else + io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL); + + pclog("hasfpu - %i\n",hasfpu); + pclog("is486 - %i %i\n",is486,cpu_s->cpu_type); + + switch (cpu_s->cpu_type) + { + case CPU_386SX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 8; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 10; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + break; + + case CPU_386DX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 6; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 6; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + break; + + case CPU_486SLC: + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 5; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 7; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + break; + + case CPU_486DLC: + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + break; + + case CPU_i486SX: + case CPU_i486DX: + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + break; + + case CPU_Am486SX: + case CPU_Am486DX: + /*AMD timing identical to Intel*/ + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + break; + + case CPU_Cx486S: + case CPU_Cx486DX: + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 4-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + break; + + case CPU_Cx5x86: + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + break; + } +} + +void cpu_CPUID() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_i486DX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = 1; /*FPU*/ + } + else + EAX = 0; + break; + + case CPU_Am486SX: + if (!EAX) + { + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = EDX = 0; /*No FPU*/ + } + else + EAX = 0; + break; + + case CPU_Am486DX: + if (!EAX) + { + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = 1; /*FPU*/ + } + else + EAX = 0; + break; + } +} + + +static int cyrix_addr; + +void cyrix_write(uint16_t addr, uint8_t val) +{ + if (!(addr & 1)) cyrix_addr = val; +// else pclog("Write Cyrix %02X %02X\n",cyrix_addr,val); +} + +uint8_t cyrix_read(uint16_t addr) +{ + if (addr & 1) + { + switch (cyrix_addr) + { + case 0xfe: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id & 0xff; + case 0xff: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id >> 8; + } + if ((cyrix_addr & ~0xf0) == 0xc0) return 0xff; + if (cyrix_addr == 0x20 && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_Cx5x86) return 0xff; + } + return 0xff; +} diff --git a/src/cpu.h b/src/cpu.h new file mode 100644 index 00000000..340928a1 --- /dev/null +++ b/src/cpu.h @@ -0,0 +1,71 @@ +extern int cpu, cpu_manufacturer; + +/*808x class CPUs*/ +#define CPU_8088 0 +#define CPU_8086 1 + +/*286 class CPUs*/ +#define CPU_286 2 + +/*386 class CPUs*/ +#define CPU_386SX 3 +#define CPU_386DX 4 +#define CPU_486SLC 5 +#define CPU_486DLC 6 + +/*486 class CPUs*/ +#define CPU_i486SX 7 +#define CPU_Am486SX 8 +#define CPU_Cx486S 9 +#define CPU_i486DX 10 +#define CPU_Am486DX 11 +#define CPU_Cx486DX 12 +#define CPU_Cx5x86 13 + +#define MANU_INTEL 0 +#define MANU_AMD 1 +#define MANU_CYRIX 2 + +extern int timing_rr; +extern int timing_mr, timing_mrl; +extern int timing_rm, timing_rml; +extern int timing_mm, timing_mml; +extern int timing_bt, timing_bnt; + + + +typedef struct +{ + char name[16]; + int cpu_type; + int speed; + int rspeed; + int multi; + uint32_t edx_reset; + uint32_t cpuid_model; + uint16_t cyrix_id; +} CPU; + +extern CPU cpus_8088[]; +extern CPU cpus_8086[]; +extern CPU cpus_286[]; +extern CPU cpus_i386[]; +extern CPU cpus_Am386[]; +extern CPU cpus_486SDLC[]; +extern CPU cpus_i486[]; +extern CPU cpus_Am486[]; +extern CPU cpus_Cx486[]; + +extern CPU cpus_pc1512[]; +extern CPU cpus_ibmat[]; +extern CPU cpus_acer[]; + +extern int cpu_iscyrix; +extern int cpu_16bitbus; +extern int cpu_busspeed; +extern int cpu_multi; + +void cyrix_write(uint16_t addr, uint8_t val); +uint8_t cyrix_read(uint16_t addr); + +extern int is8086; diff --git a/src/dac.c b/src/dac.c new file mode 100644 index 00000000..44f79df9 --- /dev/null +++ b/src/dac.c @@ -0,0 +1,68 @@ +#include "ibm.h" + +uint8_t dac,dac2; +uint8_t dacctrl; +int lptfifo; +uint8_t dssbuffer[16]; +int dssstart=0,dssend=0; +int dssmode=0; + +void writedac(uint16_t addr, uint8_t val) +{ + if (dssmode) dac2=val; + else dac=val; +} + +void writedacctrl(uint16_t addr, uint8_t val) +{ +// printf("Write DAC ctrl %02X %i\n",val,lptfifo); + if (dacctrl&8 && !(val&8) && (lptfifo!=16)) + { +// dac=dac2; + dssbuffer[dssend++]=dac2; + dssend&=15; + lptfifo++; + } + dacctrl=val; +} + +uint8_t readdacfifo() +{ + if (lptfifo==16) return 0x40; + return 0; +} + +void pollss() +{ + if (lptfifo) + { + dac=dssbuffer[dssstart++]; + dssstart&=15; + lptfifo--; + } +} + +int16_t dacbuffer[SOUNDBUFLEN+20]; +int dacbufferpos=0; +void getdacsamp() +{ + if (dacbufferposSOUNDBUFLEN) dacbufferpos=SOUNDBUFLEN; + for (c=0;c>4,pc); + switch (addr&0xF) + { + case 0: +/* if (((dma.mode[0]>>2)&3)==2) + { + dma.ac[0]++; + dma.cc[0]--; + if (dma.cc[0]<0) + { + dma.ac[0]=dma.ab[0]; + dma.cc[0]=dma.cb[0]; + } + }*/ + case 2: case 4: case 6: /*Address registers*/ + dma.wp^=1; + if (dma.wp) return dma.ac[(addr>>1)&3]&0xFF; + return dma.ac[(addr>>1)&3]>>8; + case 1: case 3: case 5: case 7: /*Count registers*/ +// printf("DMA count %i = %04X\n", (addr>>1)&3, dma.cc[(addr>>1)&3]); + dma.wp^=1; + if (dma.wp) temp=dma.cc[(addr>>1)&3]&0xFF; + else temp=dma.cc[(addr>>1)&3]>>8; +// printf("%02X\n",temp); + return temp; + case 8: /*Status register*/ + temp=dma.stat; + dma.stat=0; + return temp|1; + case 0xD: + return 0; + } +// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc); + return dmaregs[addr&0xF]; +} + +void dma_write(uint16_t addr, uint8_t val) +{ +// printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc); + dmaregs[addr&0xF]=val; + switch (addr&0xF) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma.wp^=1; + if (dma.wp) dma.ab[(addr>>1)&3]=(dma.ab[(addr>>1)&3]&0xFF00)|val; + else dma.ab[(addr>>1)&3]=(dma.ab[(addr>>1)&3]&0xFF)|(val<<8); + dma.ac[(addr>>1)&3]=dma.ab[(addr>>1)&3]; + dmaon[(addr>>1)&3]=1; +// printf("DMA addr %i now %04X\n",(addr>>1)&3,dma.ac[(addr>>1)&3]); + return; + case 1: case 3: case 5: case 7: /*Count registers*/ + dma.wp^=1; + if (dma.wp) dma.cb[(addr>>1)&3]=(dma.cb[(addr>>1)&3]&0xFF00)|val; + else dma.cb[(addr>>1)&3]=(dma.cb[(addr>>1)&3]&0xFF)|(val<<8); + dma.cc[(addr>>1)&3]=dma.cb[(addr>>1)&3]; + dmaon[(addr>>1)&3]=1; +// printf("DMA count %i now %04X\n",(addr>>1)&3,dma.cc[(addr>>1)&3]); + return; + case 8: /*Control register*/ + dma.command = val; + return; + case 0xA: /*Mask*/ + if (val&4) dma.m|=(1<<(val&3)); + else dma.m&=~(1<<(val&3)); + return; + case 0xB: /*Mode*/ + dma.mode[val&3]=val; + return; + case 0xC: /*Clear FF*/ + dma.wp=0; + return; + case 0xD: /*Master clear*/ + dma.wp=0; + dma.m=0xF; + return; + case 0xF: /*Mask write*/ + dma.m=val&0xF; + return; + } +} + +uint8_t dma16_read(uint16_t addr) +{ + uint8_t temp; +// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc); + addr>>=1; + switch (addr&0xF) + { + case 0: + if (((dma16.mode[0]>>2)&3)==2) + { + dma16.ac[0]++; + dma16.cc[0]--; + if (dma16.cc[0]<0) + { + dma16.ac[0]=dma16.ab[0]; + dma16.cc[0]=dma16.cb[0]; + } + } + case 2: case 4: case 6: /*Address registers*/ + dma16.wp^=1; + if (dma16.wp) return dma16.ac[(addr>>1)&3]&0xFF; + return dma16.ac[(addr>>1)&3]>>8; + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16.wp^=1; +// printf("Read %04X\n",dma16.cc[1]); + if (dma16.wp) temp=dma16.cc[(addr>>1)&3]&0xFF; + else temp=dma16.cc[(addr>>1)&3]>>8; +// printf("%02X\n",temp); + return temp; + case 8: /*Status register*/ + temp=dma16.stat; + dma16.stat=0; + return temp|1; + } + return dma16regs[addr&0xF]; +} + +void dma16_write(uint16_t addr, uint8_t val) +{ +// printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc); + addr>>=1; + dma16regs[addr&0xF]=val; + switch (addr&0xF) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16.wp^=1; + if (dma16.wp) dma16.ab[(addr>>1)&3]=(dma16.ab[(addr>>1)&3]&0xFF00)|val; + else dma16.ab[(addr>>1)&3]=(dma16.ab[(addr>>1)&3]&0xFF)|(val<<8); + dma16.ac[(addr>>1)&3]=dma16.ab[(addr>>1)&3]; + dma16on[(addr>>1)&3]=1; +// printf("dma16 addr %i now %04X\n",(addr>>1)&3,dma16.ac[(addr>>1)&3]); + return; + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16.wp^=1; + if (dma16.wp) dma16.cb[(addr>>1)&3]=(dma16.cb[(addr>>1)&3]&0xFF00)|val; + else dma16.cb[(addr>>1)&3]=(dma16.cb[(addr>>1)&3]&0xFF)|(val<<8); + dma16.cc[(addr>>1)&3]=dma16.cb[(addr>>1)&3]; + dma16on[(addr>>1)&3]=1; +// printf("dma16 count %i now %04X\n",(addr>>1)&3,dma16.cc[(addr>>1)&3]); + return; + case 8: /*Control register*/ + return; + case 0xA: /*Mask*/ + if (val&4) dma16.m|=(1<<(val&3)); + else dma16.m&=~(1<<(val&3)); + return; + case 0xB: /*Mode*/ + dma16.mode[val&3]=val; + return; + case 0xC: /*Clear FF*/ + dma16.wp=0; + return; + case 0xD: /*Master clear*/ + dma16.wp=0; + dma16.m=0xF; + return; + case 0xF: /*Mask write*/ + dma16.m=val&0xF; + return; + } +} + +uint8_t dmapages[16]; +static int primed = 0; +void dma_page_write(uint16_t addr, uint8_t val) +{ + if (!(addr&0xF)) + { +// printf("Write page %03X %02X %04X:%04X\n",addr,val,CS,pc); +// if (val==0x29 && pc==0xD25) output=1; + } + dmapages[addr&0xF]=val; + switch (addr&0xF) + { + case 1: + dma.page[2]=(AT)?val:val&0xF; + break; + case 2: + dma.page[3]=(AT)?val:val&0xF; + break; + case 3: + dma.page[1]=(AT)?val:val&0xF; +// pclog("DMA1 page %02X\n",val); + break; + case 0xB: + dma16.page[1]=val; + break; + } +// printf("Page write %04X %02X\n",addr,val); +} + +uint8_t dma_page_read(uint16_t addr) +{ + return dmapages[addr&0xF]; +} + +void dma_init() +{ + io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL); + io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL); +} + +void dma16_init() +{ + io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL); + io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL); +} + + +uint8_t _dma_read(uint32_t addr) +{ + switch (addr&0xFFFF8000) + { + case 0xA0000: case 0xA8000: + return video_read_a000(addr); + case 0xB0000: + return video_read_b000(addr); + case 0xB8000: + return video_read_b800(addr); + } + if (isram[addr>>16]) return ram[addr]; + return 0xff; +} + +void _dma_write(uint32_t addr, uint8_t val) +{ + switch (addr&0xFFFF8000) + { + case 0xA0000: case 0xA8000: + video_write_a000(addr,val); + return; + case 0xB0000: + video_write_b000(addr,val); + return; + case 0xB8000: + video_write_b800(addr,val); + return; + case 0xC0000: case 0xC8000: case 0xD0000: case 0xD8000: + case 0xE0000: case 0xE8000: case 0xF0000: case 0xF8000: + return; + } + if (isram[addr>>16]) ram[addr]=val; +} +/*void writedma2(uint8_t val) +{ +// printf("Write to %05X %02X %i\n",(dma.page[2]<<16)+dma.ac[2],val,dma.m&4); + if (!(dma.m&4)) + { + ram[((dma.page[2]<<16)+dma.ac[2])&rammask]=val; + dma.ac[2]++; + dma.cc[2]--; + if (dma.cc[2]==-1) + { + dma.m|=4; + dma.stat|=4; + } + } +}*/ + +uint8_t readdma2() +{ + uint8_t temp; +// pclog("Read DMA2 %02X %02X\n",dma.m,dma.mode[2]); + if (dma.m&4) + { + fdc_abort(); + return 0xFF; + } + if ((dma.mode[2]&0xC)!=8) + { + fdc_abort(); + return 0xFF; + } + temp=_dma_read((dma.ac[2]+(dma.page[2]<<16))&rammask); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask]; +// pclog("DMA2 %02X %05X\n",temp,(dma.ac[2]+(dma.page[2]<<16))&rammask); + if (dma.mode[2]&0x20) dma.ac[2]--; + else dma.ac[2]++; + dma.cc[2]--; + if (!dma.cc[2] && (dma.mode[2]&0x10)) + { + dma.cc[2]=dma.cb[2]+1; + dma.ac[2]=dma.ab[2]; + } + else if (dma.cc[2]<=-1) + dma.m|=4; + return temp; +} + +void writedma2(uint8_t temp) +{ +// pclog("Write DMA2 %02X %02X %04X\n",dma.m,dma.mode[2],dma.cc[2]); + if (dma.m&4) + { + fdc_abort(); + return; + } + if ((dma.mode[2]&0xC)!=4) + { + fdc_abort(); + return; + } +// pclog("Write %05X %05X %02X\n",(dma.ac[2]+(dma.page[2]<<16)),rammask,temp); +// ram[(dma.ac[2]+(dma.page[2]<<16))&rammask]=temp; + _dma_write((dma.ac[2]+(dma.page[2]<<16))&rammask,temp); + if (dma.mode[2]&0x20) dma.ac[2]--; + else dma.ac[2]++; + dma.cc[2]--; + if (!dma.cc[2] && (dma.mode[2]&0x10)) + { + dma.cc[2]=dma.cb[2]+1; + dma.ac[2]=dma.ab[2]; + } + else if (dma.cc[2]<=-1) + { +// pclog("Reached TC\n"); + fdc_abort(); + dma.m|=4; + } +} + +uint8_t readdma1() +{ + uint8_t temp=0; + /*if ((dma.ac[1]+(dma.page[1]<<16))<0x800000) */temp=ram[(dma.ac[1]+(dma.page[1]<<16))&rammask]; +// printf("Read DMA1 from %05X %02X %04X %02X %i\n",dma.ac[1]+(dma.page[1]<<16),dma.mode[1],dma.cc[1],temp,dmaon[1]); + if (!dmaon[1]) + { +// printf("DMA off!\n"); + return temp; + } + dma.ac[1]++; + dma.cc[1]--; + if (dma.cc[1]<=-1 && (dma.mode[1]&0x10)) + { + dma.cc[1]=dma.cb[1]; + dma.ac[1]=dma.ab[1]; + } + else if (dma.cc[1]<=-1) + dmaon[1]=0; + return temp; +} + +uint16_t readdma5() +{ + uint16_t temp=0; +// pclog("Read DMA5 %i %04X\n",dma16on[1],dma16.cc[1]); + /*if ((dma16.ac[1]+(dma16.page[1]<<16))<0x800000) */temp=ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16))&rammask]|(ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16)+1)&rammask]<<8); + //readmemwl(dma16.ac[1]+(dma16.page[1]<<16)); +// printf("Read DMA1 from %05X %05X %02X %04X\n",dma.ac[1]+(dma.page[1]<<16),(dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16),dma16.mode[1],temp); + if (!dma16on[1]) + { +// printf("DMA off!\n"); + return temp; + } + dma16.ac[1]++; + dma16.cc[1]--; + if (dma16.cc[1]<=-1 && (dma16.mode[1]&0x10)) + { + dma16.cc[1]=dma16.cb[1]; + dma16.ac[1]=dma16.ab[1]; + } + else if (dma16.cc[1]<=-1) + dma16on[1]=0; + return temp; +} + +void writedma1(uint8_t temp) +{ + if (!dmaon[1]) return; + ram[(dma.ac[1]+(dma.page[1]<<16))&rammask]=temp; + dma.ac[1]++; + dma.cc[1]--; + if (!dma.cc[1] && (dma.mode[1]&0x10)) + { + dma.cc[1]=dma.cb[1]+1; + dma.ac[1]=dma.ab[1]; + } + else if (dma.cc[1]<=-1) + dmaon[1]=0; +} +void writedma5(uint16_t temp) +{ + if (!dma16on[1]) return; + ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16))&rammask]=temp; + ram[((dma16.ac[1]<<1)+((dma16.page[1]&~1)<<16)+1)&rammask]=temp>>8; + + dma16.ac[1]++; + dma16.cc[1]--; + if (dma16.cc[1]<=-1 && (dma16.mode[1]&0x10)) + { + dma16.cc[1]=dma16.cb[1]; + dma16.ac[1]=dma16.ab[1]; + } + else if (dma16.cc[1]<=-1) + dma16on[1]=0; +} + +int readdma3() +{ + uint8_t temp=ram[((dma.page[3]<<16)+dma.ac[3])&rammask]; + if (dma.m&8) + { + return -1; + } +// printf("Read DMA 3 - %02X %05X %i\n",temp,(dma.page[3]<<16)+dma.ac[3],dma.cc[3]); + if (!(dma.m&8)) + { + dma.ac[3]++; + dma.cc[3]--; + if (dma.cc[3]==-1) + { + dma.m|=8; + dma.stat|=8; + } + } + return temp; +} +void readdma0() +{ + if (AT) ppi.pb^=0x10; + if (dma.command & 4) return; +// if (AMSTRAD) return; + refreshread(); +// pclog("Read refresh %02X %02X %04X %04X\n",dma.m,dma.mode[0],dma.ac[0],dma.cc[0]); + if (dma.m&1) return; +// readmembl((dma.page[0]<<16)+dma.ac[0]); +// if (!(dma.m&1)) +// { + dma.ac[0]+=2; + dma.cc[0]--; + if (dma.cc[0]==-1) + { + dma.stat|=1; + dma.ac[0]=dma.ab[0]; + dma.cc[0]=dma.cb[0]; + } +// } +// ppi.pb^=0x10; +} + +void dumpdma() +{ + printf("Address : %04X %04X %04X %04X\n",dma.ac[0],dma.ac[1],dma.ac[2],dma.ac[3]); + printf("Count : %04X %04X %04X %04X\n",dma.cc[0],dma.cc[1],dma.cc[2],dma.cc[3]); + printf("Mask %02X Stat %02X\n",dma.m,dma.stat); +} diff --git a/src/dma.h b/src/dma.h new file mode 100644 index 00000000..e8209d74 --- /dev/null +++ b/src/dma.h @@ -0,0 +1,3 @@ +void dma_init(); +void dma16_init(); +void dma_reset(); diff --git a/src/ega.c b/src/ega.c new file mode 100644 index 00000000..e7c22d01 --- /dev/null +++ b/src/ega.c @@ -0,0 +1,298 @@ +#include "ibm.h" +#include "video.h" + +void doblit(); + +int egareads=0,egawrites=0; +int framecount=0; +int changeframecount=2; + +void redotextlookup(); +int output; +int svgaon=0; +uint32_t svgarbank,svgawbank; +uint8_t svgaseg,svgaseg2; +uint8_t svga3d8; + +uint8_t oldvram=0; +int frames; +int incga=1; +int hsync; +uint8_t cgastat; + +uint8_t gdcreg[16]; +int gdcaddr; +uint8_t attrregs[32]; +int attraddr,attrff=0; +uint8_t ega3c2; + +uint8_t rotatevga[8][256]; +uint8_t writemask,charset; +int writemode,readmode,readplane,chain4; +uint8_t colourcompare,colournocare; +uint8_t la,lb,lc,ld; + +uint8_t *vram; + +int egares; + +uint8_t seqregs[32]; +int seqaddr; + +uint8_t oak_regs[32]; +int oak_index; + + +extern int egaswitchread,egaswitches; +/*For VGA non-interlace colour, ID bits should be 1 1 0 or 6*/ +int vres=0; + +PALETTE vgapal; +uint32_t *pallook,pallook16[256],pallook64[256],pallook256[256]; +int dacread,dacwrite,dacpos=0; +int palchange=1; + +int fullchange; + +float dispontime,dispofftime,disptime; + +int ega_vtotal,ega_dispend,ega_vsyncstart,ega_split,ega_hdisp,ega_rowoffset; +int vidclock; +float cpuclock; + +int bpp; + +uint32_t vrammask; + +uint8_t changedvram[(8192*1024)/1024]; + + +int charseta,charsetb; + +int egapal[16]; + +int displine; + +int rowdbl=0; +int scrblank=0; + + + + +uint8_t edatlookup[4][4]; + +uint32_t textlookup[256][2][16][16]; + +/*void redotextlookup() +{ + int c,d,e; + uint32_t temp; + int coffset=(VGA)?0:64; + for (c=0;c<256;c++) + { + for (d=0;d<16;d++) + { +// printf("ATTR %i=%02X+%02X\n",d,attrregs[d],coffset); + for (e=0;e<16;e++) + { + temp=0; + if (c&0x80) temp|=(attrregs[d]+coffset); + else temp|=(attrregs[e]+coffset); + if (c&0x40) temp|=(attrregs[d]+coffset)<<8; + else temp|=(attrregs[e]+coffset)<<8; + if (c&0x20) temp|=(attrregs[d]+coffset)<<16; + else temp|=(attrregs[e]+coffset)<<16; + if (c&0x10) temp|=(attrregs[d]+coffset)<<24; + else temp|=(attrregs[e]+coffset)<<24; +// if (c==0x5) printf("%08X %i %i %02X %02X\n",temp,d,e,attrregs[d],attrregs[e]); + textlookup[c][0][d][e]=temp; + temp=0; + if (c&0x08) temp|=(attrregs[d]+coffset); + else temp|=(attrregs[e]+coffset); + if (c&0x04) temp|=(attrregs[d]+coffset)<<8; + else temp|=(attrregs[e]+coffset)<<8; + if (c&0x02) temp|=(attrregs[d]+coffset)<<16; + else temp|=(attrregs[e]+coffset)<<16; + if (c&0x01) temp|=(attrregs[d]+coffset)<<24; + else temp|=(attrregs[e]+coffset)<<24; + textlookup[c][1][d][e]=temp; + } + } + } +}*/ + +void initega() +{ + int c,d,e; + bpp=8; + for (c=0;c<256;c++) + { + e=c; + for (d=0;d<8;d++) + { + rotatevga[d][c]=e; + e=(e>>1)|((e&1)?0x80:0); + } + } + crtc[0xC]=crtc[0xD]=0; + if (romset==ROM_PC1640 || romset==ROM_PC1512) incga=1; + else incga=0; + for (c=0;c<4;c++) + { + for (d=0;d<4;d++) + { + edatlookup[c][d]=0; + if (c&1) edatlookup[c][d]|=1; + if (d&1) edatlookup[c][d]|=2; + if (c&2) edatlookup[c][d]|=0x10; + if (d&2) edatlookup[c][d]|=0x20; +// printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]); + } + } + /*redotextlookup();*/ + for (c=0;c<256;c++) + { + pallook64[c]=makecol32(((c>>2)&1)*0xAA,((c>>1)&1)*0xAA,(c&1)*0xAA); + pallook64[c]+=makecol32(((c>>5)&1)*0x55,((c>>4)&1)*0x55,((c>>3)&1)*0x55); + pallook16[c]=makecol32(((c>>2)&1)*0xAA,((c>>1)&1)*0xAA,(c&1)*0xAA); + pallook16[c]+=makecol32(((c>>4)&1)*0x55,((c>>4)&1)*0x55,((c>>4)&1)*0x55); + if ((c&0x17)==6) pallook16[c]=makecol32(0xAA,0x55,0); +// printf("%03i %08X\n",c,pallook[c]); + } + pallook=pallook16; + seqregs[0xC]=0x20; + vrammask=(ET4000)?0xFFFFF:0x1FFFFF; +// writeega_func=writeega; + gdcreg[6]=8; + gdcreg[8]=0xFF; + writemode=0; + chain4=0; + writemask=3; + + et4k_b8000=0; + + svgarbank=svgawbank=0; +} +uint32_t egabase,egaoffset; + +void cacheega() +{ + egabase=(crtc[0xC]<<8)|crtc[0xD]; + if (ET4000 || ET4000W32 || TRIDENT) + egabase|=((crtc[0x33]&3)<<18); +// printf("EGABASE %05X\n",egabase); +// egaoffset=8-((attrregs[0x13])&7); +// printf("Cache base!\n"); +} +void cacheega2() +{ +// egabase=(crtc[0xC]<<8)|crtc[0xD]; + if (gdcreg[5]&0x40) egaoffset=8-(((attrregs[0x13])&7)>>1); + else egaoffset=8-((attrregs[0x13])&7); +// printf("Cache offset!\n"); +} + +int olddisplines,oldxsize; + +int oldreadflash; +int oldegaaddr,oldegasplit; + +int vc,sc; +int egadispon=0; +int linepos; +int displine; +uint32_t ma,maback,ca; +int firstline,lastline; +int xsize,ysize; +int scrollcache; +int con,cursoron,cgablink; + +BITMAP *buffer,*vbuf,*buffer32; + +int linecountff=0; + +void dumpegaregs() +{ + int c; + printf("CRTC :"); + for (c=0;c<0x20;c++) printf(" %02X",crtc[c]); + printf("\n"); + printf(" EXT :"); + for (c=0;c<0x20;c++) printf(" %02X",crtc[c+32]); + printf("\n"); + printf(" EXT2:"); + for (c=0;c<0x20;c++) printf(" %02X",crtc[c+64]); + printf("\n"); + printf("SEQ :"); + for (c=0;c<0x10;c++) printf(" %02X",seqregs[c]); + printf("\n"); + printf(" EXT :"); + for (c=0;c<0x10;c++) printf(" %02X",seqregs[c + 0x10]); + printf("\n"); + printf("ATTR :"); + for (c=0;c<0x20;c++) printf(" %02X",attrregs[c]); + printf("\n"); + printf("GDC :"); + for (c=0;c<0x10;c++) printf(" %02X",gdcreg[c]); + printf("\n"); +// printf("OLD CTRL2 = %02X NEW CTRL2 = %02X DAC = %02X 3C2 = %02X\n",tridentoldctrl2,tridentnewctrl2,tridentdac,ega3c2); + printf("BPP = %02X\n",bpp); +} + +int oddeven; + +int wx,wy; +int vslines; + +int frames = 0; + +void doblit() +{ + startblit(); + if ((wx!=xsize || wy!=ysize) && !vid_resize) + { + xsize=wx; + ysize=wy+1; + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + if (vres) updatewindowsize(xsize,ysize<<1); + else updatewindowsize(xsize,ysize); + } + video_blit_memtoscreen(32, 0, 0, ysize, xsize, ysize); + if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); + endblit(); + frames++; +} + +int ega_getdepth() +{ + if (!(gdcreg[6]&1)) return 0; + switch (gdcreg[5]&0x60) + { + case 0x00: + return 4; + case 0x20: + return 2; + case 0x40: case 0x60: + if (TRIDENT || ET4000W32) return bpp; + return 8; + } +} + +int ega_getx() +{ + int x; + if (!(gdcreg[6]&1)) return (crtc[1]+1); + if ((attrregs[0x10]&0x40) && !(tridentoldctrl2&0x10)) x=(crtc[1]+1)*4; + else x=(crtc[1]+1)*8; + if (TRIDENT && (bpp==15 || bpp==16)) x>>=1; + if (TRIDENT && bpp==24) x=(x<<1)/3; + return x; +} + +int ega_gety() +{ + if (crtc[0x1E]&4) return (ega_dispend/((crtc[9]&31)+1))<<1; + if (crtc[9]&0x80) return (ega_dispend/((crtc[9]&31)+1))>>1; + return ega_dispend/((crtc[9]&31)+1); +} diff --git a/src/fdc.c b/src/fdc.c new file mode 100644 index 00000000..907856c9 --- /dev/null +++ b/src/fdc.c @@ -0,0 +1,806 @@ +#include +#include +#include "ibm.h" + +void fdc_poll(); +int timetolive; +int TRACKS[2] = {80, 80}; +int SECTORS[2]={9,9}; +int SIDES[2]={2,2}; +//#define SECTORS 9 +int output; +int lastbyte=0; +uint8_t disc[2][2][80][36][512]; +uint8_t disc_3f7; + +int discchanged[2]; +int discmodified[2]; +int discrate[2]; + +void loaddisc(int d, char *fn) +{ + FILE *f=fopen(fn,"rb"); + int h,t,s,b; + if (!f) + { + SECTORS[d]=9; SIDES[d]=1; + driveempty[d]=1; discrate[d]=4; + return; + } + driveempty[d]=0; + SIDES[d]=2; + fseek(f,-1,SEEK_END); + if (ftell(f)<=(160*1024)) { SECTORS[d]=8; TRACKS[d] = 40; SIDES[d]=1; discrate[d]=2; } + else if (ftell(f)<=(180*1024)) { SECTORS[d]=9; TRACKS[d] = 40; SIDES[d]=1; discrate[d]=2; } + else if (ftell(f)<=(320*1024)) { SECTORS[d]=8; TRACKS[d] = 40; discrate[d]=2; } + else if (ftell(f)<(1024*1024)) { SECTORS[d]=9; TRACKS[d] = 80; discrate[d]=2; } /*Double density*/ + else if (ftell(f)<(0x1A4000-1)) { SECTORS[d]=18; TRACKS[d] = 80; discrate[d]=0; } /*High density (not supported by Tandy 1000)*/ + else if (ftell(f) == 1884159) { SECTORS[d]=23; TRACKS[d] = 80; discrate[d]=0; } /*XDF format - used by OS/2 Warp*/ + else if (ftell(f) == 1763327) { SECTORS[d]=21; TRACKS[d] = 82; discrate[d]=0; } /*XDF format - used by OS/2 Warp*/ + else if (ftell(f)<(2048*1024)) { SECTORS[d]=21; TRACKS[d] = 80; discrate[d]=0; } /*DMF format - used by Windows 95*/ + else { SECTORS[d]=36; TRACKS[d] = 80; discrate[d]=3; } /*E density (not supported by anything)*/ + printf("Drive %c: has %i sectors and %i sides and is %i bytes long\n",'A'+d,SECTORS[0],SIDES[0],ftell(f)); + fseek(f,0,SEEK_SET); + for (t=0;t<80;t++) + { + for (h=0;h>4,pc,ins,fdc.st0,ins,fdc.rate); + switch (addr&7) + { + case 1: return; + case 2: /*DOR*/ +// if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3; +// printf("DOR was %02X\n",fdc.dor); + if (val&4) + { + fdc.stat=0x80; + fdc.pnum=fdc.ptot=0; + } + if ((val&4) && !(fdc.dor&4)) + { + disctime=128; + discint=-1; + fdc_reset(); + } + fdc.dor=val; +// printf("DOR now %02X\n",val); + return; + case 4: + if (val & 0x80) + { + disctime=128; + discint=-1; + fdc_reset(); + } + return; + case 5: /*Command register*/ +// pclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot); + if (fdc.pnum==fdc.ptot) + { + fdc.command=val; +// printf("Starting FDC command %02X\n",fdc.command); + switch (fdc.command&0x1F) + { + case 2: /*Read track*/ +// printf("Read track!\n"); + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + break; + case 3: /*Specify*/ + fdc.pnum=0; + fdc.ptot=2; + fdc.stat=0x90; + break; + case 4: /*Sense drive status*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + break; + case 5: /*Write data*/ +// printf("Write data!\n"); + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + readflash=1; + break; + case 6: /*Read data*/ + fullspeed(); + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + readflash=1; + break; + case 7: /*Recalibrate*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + break; + case 8: /*Sense interrupt status*/ +// printf("Sense interrupt status %i\n",fdc.drive); + fdc.lastdrive = fdc.drive; +// fdc.stat = 0x10 | (fdc.stat & 0xf); +// disctime=1024; + discint = 8; + fdc.pos = 0; + fdc_poll(); + break; + case 10: /*Read sector ID*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + fdc.pos=0; + break; + case 15: /*Seek*/ + fdc.pnum=0; + fdc.ptot=2; + fdc.stat=0x90; + break; + case 0x0e: /*Dump registers*/ + fdc.lastdrive = fdc.drive; + discint = 0x0e; + fdc.pos = 0; + fdc_poll(); + break; + case 0x10: /*Get version*/ + fdc.lastdrive = fdc.drive; + discint = 0x10; + fdc.pos = 0; + fdc_poll(); + break; + case 0x12: /*Set perpendicular mode*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x13: /*Configure*/ + fdc.pnum=0; + fdc.ptot=3; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x14: /*Unlock*/ + case 0x94: /*Lock*/ + fdc.lastdrive = fdc.drive; + discint = fdc.command; + fdc.pos = 0; + fdc_poll(); + break; + + case 0x18: + fdc.stat = 0x10; + discint = 0xfc; + fdc_poll(); + break; + + default: + pclog("Bad FDC command %02X\n",val); +// dumpregs(); +// exit(-1); + fdc.stat=0x10; + discint=0xfc; + disctime=200; + break; + } + } + else + { + fdc.params[fdc.pnum++]=val; + if (fdc.pnum==fdc.ptot) + { +// pclog("Got all params\n"); + fdc.stat=0x30; + discint=fdc.command&0x1F; + disctime=1024; + fdc.drive=fdc.params[0]&1; + if (discint==2 || discint==5 || discint==6) + { + fdc.track[fdc.drive]=fdc.params[1]; + fdc.head=fdc.params[2]; + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[4]; + if (!fdc.params[5]) + { + fdc.params[5]=fdc.sector; + } + if (fdc.params[5]>SECTORS[fdc.drive]) fdc.params[5]=SECTORS[fdc.drive]; + if (driveempty[fdc.drive]) + { +// pclog("Drive empty\n"); + discint=0xFE; + } + } + if (discint==2 || discint==5 || discint==6 || discint==10) + { +// pclog("Rate %i %i %i\n",fdc.rate,discrate[fdc.drive],driveempty[fdc.drive]); + if (fdc.rate!=discrate[fdc.drive]) + { +// pclog("Wrong rate %i %i\n",fdc.rate,discrate[fdc.drive]); + discint=0xFF; + disctime=1024; + } + if (driveempty[fdc.drive]) + { +// pclog("Drive empty\n"); + discint=0xFE; + disctime=1024; + } + } + if (discint == 7 || discint == 0xf) + { + fdc.stat = 1 << fdc.drive; +// disctime = 8000000; + } + if (discint == 0xf) + { + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + } +// if (discint==5) fdc.pos=512; + } + } + return; + case 7: + if (!AT) return; + fdc.rate=val&3; + + disc_3f7=val; + return; + } +// printf("Write FDC %04X %02X\n",addr,val); +// dumpregs(); +// exit(-1); +} + +int paramstogo=0; +uint8_t fdc_read(uint16_t addr) +{ + uint8_t temp; +// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,ins); + switch (addr&7) + { + case 1: /*???*/ + temp=0x50; + break; + case 3: + temp = 0x20; + break; + case 4: /*Status*/ + temp=fdc.stat; + break; + case 5: /*Data*/ + fdc.stat&=~0x80; + if (paramstogo) + { + paramstogo--; + temp=fdc.res[10 - paramstogo]; +// printf("Read param %i %02X\n",6-paramstogo,temp); + if (!paramstogo) + { + fdc.stat=0x80; +// fdc.st0=0; + } + else + { + fdc.stat|=0xC0; +// fdc_poll(); + } + } + else + { + if (lastbyte) + fdc.stat=0x80; + lastbyte=0; + temp=fdc.dat; + } + if (discint==0xA) disctime=1024; + fdc.stat &= 0xf0; + break; + case 7: /*Disk change*/ + if (fdc.dor & (0x10 << (fdc.dor & 1))) + temp = (discchanged[fdc.dor & 1] || driveempty[fdc.dor & 1])?0x80:0; + else + temp = 0; + if (AMSTRADIO) /*PC2086/3086 seem to reverse this bit*/ + temp ^= 0x80; +// printf("- DC %i %02X %02X %i %i - ",fdc.dor & 1, fdc.dor, 0x10 << (fdc.dor & 1), discchanged[fdc.dor & 1], driveempty[fdc.dor & 1]); +// discchanged[fdc.dor&1]=0; + break; + default: + temp=0xFF; +// printf("Bad read FDC %04X\n",addr); +// dumpregs(); +// exit(-1); + } +// /*if (addr!=0x3f4) */printf("%02X rate=%i\n",temp,fdc.rate); + return temp; +} + +int fdc_abort_f = 0; + +void fdc_abort() +{ + fdc_abort_f = 1; +// pclog("FDC ABORT\n"); +} + +static int fdc_reset_stat = 0; +void fdc_poll() +{ + int temp; +// pclog("fdc_poll %08X %i %02X\n", discint, fdc.drive, fdc.st0); + switch (discint) + { + case -3: /*End of command with interrupt*/ +// if (output) printf("EOC - interrupt!\n"); +//pclog("EOC\n"); + picint(0x40); + case -2: /*End of command*/ + fdc.stat = (fdc.stat & 0xf) | 0x80; + return; + case -1: /*Reset*/ +//pclog("Reset\n"); + picint(0x40); + fdc_reset_stat = 4; + return; + case 2: /*Read track*/ + if (!fdc.pos) + { +// printf("Read Track Side %i Track %i Sector %02X sector size %i end sector %02X %05X\n",fdc.head,fdc.track,fdc.sector,fdc.params[4],fdc.params[5],(dma.page[2]<<16)+dma.ac[2]); + } + if (fdc.pos<512) + { + fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]; +// pclog("Read %i %i %i %i %02X\n",fdc.head,fdc.track,fdc.sector,fdc.pos,fdc.dat); + writedma2(fdc.dat); + disctime=60; + } + else + { + disctime=0; + discint=-2; +// pclog("RT\n"); + picint(0x40); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[2]=0; + fdc.res[6]=fdc.track[fdc.drive]; + fdc.res[7]=fdc.head; + fdc.res[8]=fdc.sector; + fdc.res[9]=fdc.params[4]; + paramstogo=7; + return; + disctime=1024; + picint(0x40); + fdc.stat=0xD0; + switch (fdc.pos-512) + { + case 0: case 1: case 2: fdc.dat=0; break; + case 3: fdc.dat=fdc.track[fdc.drive]; break; + case 4: fdc.dat=fdc.head; break; + case 5: fdc.dat=fdc.sector; break; + case 6: fdc.dat=fdc.params[4]; discint=-2; lastbyte=1; break; + } + } + fdc.pos++; + if (fdc.pos==512 && fdc.params[5]!=1) + { + fdc.pos=0; + fdc.sector++; + if (fdc.sector==SECTORS[fdc.drive]+1) + { + fdc.sector=1; + } + fdc.params[5]--; + } + return; + case 3: /*Specify*/ + fdc.stat=0x80; + fdc.specify[0] = fdc.params[0]; + fdc.specify[1] = fdc.params[1]; + return; + case 4: /*Sense drive status*/ + fdc.res[10] = (fdc.params[0] & 7) | 0x28; + if (!fdc.track[fdc.drive]) fdc.res[10] |= 0x10; + + fdc.stat = (fdc.stat & 0xf) | 0xd0; + paramstogo = 1; + discint = 0; + disctime = 0; + return; + case 5: /*Write data*/ + discmodified[fdc.drive]=1; +// printf("Write data %i\n",fdc.pos); + if (!fdc.pos) + { +// printf("Write data Side %i Track %i Sector %02X sector size %i end sector %02X\n",fdc.params[2],fdc.params[1],fdc.params[3],fdc.params[4],fdc.params[5]); +// dumpregs(); +// exit(-1); + } + if (fdc.pos<512) + { + temp=readdma2(); + if (fdc_abort_f) + { + fdc_abort_f=0; + discint=0xFD; + disctime=50; + return; + } + else + { + fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]=temp; +// printf("Write data %i %i %02X %i:%i:%i:%i\n",fdc.sector-1,fdc.pos,fdc.dat,fdc.head,fdc.track[fdc.drive],fdc.sector-1,fdc.pos); + disctime=60; + } + } + else + { + disctime=0; + discint=-2; +// pclog("WD\n"); + picint(0x40); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0; + fdc.res[6]=0; + fdc.res[7]=fdc.track[fdc.drive]; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + disctime=1024; + picint(0x40); + fdc.stat=0xD0; + switch (fdc.pos-512) + { + case 0: fdc.dat=0x40; break; + case 1: fdc.dat=2; break; + case 2: fdc.dat=0; break; + case 3: fdc.dat=fdc.track[fdc.drive]; break; + case 4: fdc.dat=fdc.head; break; + case 5: fdc.dat=fdc.sector; break; + case 6: fdc.dat=fdc.params[4]; discint=-2; break; + } + } + fdc.pos++; + if (fdc.pos==512 && fdc.sector!=fdc.params[5]) + { + fdc.pos=0; + fdc.sector++; + } + return; + case 6: /*Read data*/ + if (!fdc.pos) + { +// printf("Reading sector %i track %i side %i drive %i %02X to %05X\n",fdc.sector,fdc.track[fdc.drive],fdc.head,fdc.drive,fdc.params[5],(dma.ac[2]+(dma.page[2]<<16))&rammask); + } + if (fdc.pos<512) + { + fdc.dat=disc[fdc.drive][fdc.head][fdc.track[fdc.drive]][fdc.sector-1][fdc.pos]; +// printf("Read disc %i %i %i %i %02X\n",fdc.head,fdc.track,fdc.sector,fdc.pos,fdc.dat); + writedma2(fdc.dat); + disctime=60; + } + else + { +// printf("End of command - params to go!\n"); + fdc_abort_f = 0; + disctime=0; + discint=-2; + picint(0x40); +// pclog("RD\n"); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.track[fdc.drive]; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + switch (fdc.pos-512) + { + case 0: case 1: case 2: fdc.dat=0; break; + case 3: fdc.dat=fdc.track[fdc.drive]; break; + case 4: fdc.dat=fdc.head; break; + case 5: fdc.dat=fdc.sector; break; + case 6: fdc.dat=fdc.params[4]; discint=-2; lastbyte=1; break; + } + } + fdc.pos++; + if (fdc.pos==512)// && fdc.sector!=fdc.params[5]) + { +// printf("Sector complete! %02X\n",fdc.params[5]); + fdc.pos=0; + fdc.sector++; + if (fdc.sector > fdc.params[5]) + { +// printf("Overrunnit!\n"); +// dumpregs(); +// exit(-1); + fdc.sector=1; + if (fdc.command & 0x80) + { + fdc.head ^= 1; + if (!fdc.head) + { + fdc.track[fdc.drive]++; + if (fdc.track[fdc.drive] >= TRACKS[fdc.drive]) + { + fdc.track[fdc.drive] = TRACKS[fdc.drive]; + fdc.pos = 512; + } + } + } + else + fdc.pos = 512; + } + if (fdc_abort_f) + fdc.pos = 512; + } + return; +/* printf("Read data\n"); + printf("Side %i Track %i Sector %i sector size %i\n",fdc.params[1],fdc.params[2],fdc.params[3],fdc.params[4]); + dumpregs(); + exit(-1);*/ + case 7: /*Recalibrate*/ + fdc.track[fdc.drive]=0; + if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; + fdc.st0=0x20|fdc.drive|(fdc.head?4:0); + discint=-3; + disctime=2048; +// printf("Recalibrate complete!\n"); + fdc.stat = 0x80 | (1 << fdc.drive); + return; + case 8: /*Sense interrupt status*/ +// pclog("Sense interrupt status %i\n", fdc_reset_stat); + + fdc.dat = fdc.st0; + + if (fdc_reset_stat) + { + fdc.st0 = (fdc.st0 & 0xf8) | (4 - fdc_reset_stat) | (fdc.head ? 4 : 0); + fdc_reset_stat--; + } + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[9] = fdc.st0; + fdc.res[10] = fdc.track[fdc.drive]; + if (!fdc_reset_stat) fdc.st0 = 0x80; + + paramstogo = 2; + discint = 0; + disctime = 0; + return; + case 10: /*Read sector ID*/ + disctime=0; + discint=-2; + picint(0x40); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0; + fdc.res[6]=0; + fdc.res[7]=fdc.track[fdc.drive]; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + fdc.sector++; + if (fdc.sector==SECTORS[fdc.drive]+1) + fdc.sector=1; + return; + case 15: /*Seek*/ + fdc.track[fdc.drive]=fdc.params[1]; + if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; +// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive); + fdc.st0=0x20|fdc.drive|(fdc.head?4:0); + discint=-3; + disctime=2048; + fdc.stat = 0x80 | (1 << fdc.drive); +// pclog("Stat %02X ST0 %02X\n", fdc.stat, fdc.st0); + return; + case 0x0e: /*Dump registers*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[3] = fdc.track[0]; + fdc.res[4] = fdc.track[1]; + fdc.res[5] = 0; + fdc.res[6] = 0; + fdc.res[7] = fdc.specify[0]; + fdc.res[8] = fdc.specify[1]; + fdc.res[9] = fdc.eot[fdc.drive]; + fdc.res[10] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0); + paramstogo=10; + discint=0; + disctime=0; + return; + + case 0x10: /*Version*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x90; + paramstogo=1; + discint=0; + disctime=0; + return; + + case 0x12: + fdc.perp = fdc.params[0]; + fdc.stat = 0x80; + disctime = 0; +// picint(0x40); + return; + case 0x13: /*Configure*/ + fdc.config = fdc.params[1]; + fdc.pretrk = fdc.params[2]; + fdc.stat = 0x80; + disctime = 0; +// picint(0x40); + return; + case 0x14: /*Unlock*/ + fdc.lock = 0; + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0; + paramstogo=1; + discint=0; + disctime=0; + return; + case 0x94: /*Lock*/ + fdc.lock = 1; + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x10; + paramstogo=1; + discint=0; + disctime=0; + return; + + + case 0xfc: /*Invalid*/ + fdc.dat = fdc.st0 = 0x80; +// pclog("Inv!\n"); + //picint(0x40); + fdc.stat = (fdc.stat & 0xf) | 0xd0; +// fdc.stat|=0xC0; + fdc.res[10] = fdc.st0; + paramstogo=1; + discint=0; + disctime=0; + return; + + case 0xFD: /*DMA aborted (PC1512)*/ + /*In the absence of other information, lie and claim the command completed successfully. + The PC1512 BIOS likes to program the FDC to write to all sectors on the track, but + program the DMA length to the number of sectors actually transferred. Not aborting + correctly causes disc corruption. + This only matters on writes, on reads the DMA controller will ignore excess data. + */ + pclog("DMA Aborted\n"); + disctime=0; + discint=-2; + picint(0x40); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0; + fdc.res[6]=0; + fdc.res[7]=fdc.track[fdc.drive]; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + case 0xFE: /*Drive empty*/ + pclog("Drive empty\n"); + fdc.stat = 0x10; + disctime = 0; +/* disctime=0; + discint=-2; + picint(0x40); + fdc.stat=0xD0; + fdc.res[4]=0xC8|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0; + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7;*/ + return; + case 0xFF: /*Wrong rate*/ + pclog("Wrong rate\n"); + disctime=0; + discint=-2; + picint(0x40); + fdc.stat=0xD0; + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=5; + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; + return; + } +// printf("Bad FDC disc int %i\n",discint); +// dumpregs(); +// exit(-1); +} + + +void fdc_init() +{ + io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL); + io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL); +} + +void fdc_remove() +{ + io_removehandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL); + io_removehandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL); +} diff --git a/src/fdc.h b/src/fdc.h new file mode 100644 index 00000000..9d2592f0 --- /dev/null +++ b/src/fdc.h @@ -0,0 +1,4 @@ +void fdc_init(); +void fdc_remove(); +void fdc_reset(); +void fdc_poll(); diff --git a/src/filters.h b/src/filters.h new file mode 100644 index 00000000..5a0625e0 --- /dev/null +++ b/src/filters.h @@ -0,0 +1,178 @@ +#define NCoef 2 + +//fc=350Hz +static inline float low_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00049713569693400649, + 0.00099427139386801299, + 0.00049713569693400649 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955470669530000, + 0.93726236021404663000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=350Hz +static inline float low_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.96839970114733542000, + -1.93679940229467080000, + 0.96839970114733542000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955471202770000, + 0.93726236021916731000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=3.5kHz +static inline float high_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.72248704753064896000, + -1.44497409506129790000, + 0.72248704753064896000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781670578510000, + 0.52352474706139873000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=3.5kHz +static inline float high_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.03927726802250377400, + 0.07855453604500754700, + 0.03927726802250377400 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781666419950000, + 0.52352474703279628000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + +#undef NCoef +#define NCoef 1 + +//fc=3.2kHz +static inline float sb_iir(int i, float NewSample) { +/* float ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + };*/ + + float ACoef[NCoef+1] = { + 0.17529642630084405000, + 0.17529642630084405000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -0.64940759319751051000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + diff --git a/src/gus.c b/src/gus.c new file mode 100644 index 00000000..e53c4408 --- /dev/null +++ b/src/gus.c @@ -0,0 +1,625 @@ +#include +#include +#include +#include "ibm.h" + +extern int ins; +extern int timetolive; +int output; +//#define GUSRATECONST (44100.0/48000.0) +uint8_t *gusram; + +struct +{ + int global; + uint32_t addr,dmaaddr; + int voice; + uint32_t start[32],end[32],cur[32]; + uint32_t startx[32],endx[32],curx[32]; + uint32_t rstart[32],rend[32],rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int t1on,t2on; + uint8_t tctrl; + uint16_t t1,t2,t1l,t2l; + uint8_t irqstatus,irqstatus2; + uint8_t adcommand; + int waveirqs[32],rampirqs[32]; + int voices; + uint8_t dmactrl; +} gus; + +double vol16bit[4096]; + +void initgus() +{ + int c; + for (c=0;c<32;c++) + { + gus.ctrl[c]=1; + gus.rctrl[c]=1; + gus.rfreq[c]=63*512; + } + gusram=malloc(1024*1024); + + double out = 1.0; + for (c=4095;c>=0;c--) { + vol16bit[c]=out;//(float)c/4095.0;//out; + out/=1.002709201; /* 0.0235 dB Steps */ + } + + printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); + gus.voices=14; + +} + +void dumpgus() +{ +/* FILE *f=fopen("gusram.dmp","wb"); + fwrite(gusram,1024*1024,1,f); + fclose(f);*/ +} + +void pollgusirqs() +{ + int c; + gus.irqstatus&=~0x60; + for (c=0;c<32;c++) + { + if (gus.waveirqs[c]) + { +// gus.waveirqs[c]=0; + gus.irqstatus2=0x60|c; + gus.irqstatus|=0x20; +// printf("Voice IRQ %i %02X %i\n",c,gus.irqstatus2,ins); + picintlevel(0x20); +// output=3; +// timetolive=5000; + return; + } + if (gus.rampirqs[c]) + { +// gus.rampirqs[c]=0; + gus.irqstatus2=0xA0|c; + gus.irqstatus|=0x40; +// printf("Ramp IRQ %i %02X %i\n",c,gus.irqstatus2,ins); + picintlevel(0x20); + return; + } + } + gus.irqstatus2=0xE0; +// gus.irqstatus&=~0x20; + if (!gus.irqstatus) picintc(0x20); +} + +int gusirqnext=0; + +void writegus(uint16_t addr, uint8_t val) +{ + int c,d; +// printf("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x342: /*Voice select*/ + gus.voice=val&31; + break; + case 0x343: /*Global select*/ + gus.global=val; + break; + case 0x344: /*Global low*/ +// if (gus.global!=0x43 && gus.global!=0x44) printf("Writing register %02X %02X %02X\n",gus.global,gus.voice,val); + switch (gus.global) + { + case 0: /*Voice control*/ +// if (val&1 && !(gus.ctrl[gus.voice]&1)) printf("Voice on %i\n",gus.voice); + gus.ctrl[gus.voice]=val; + break; + case 1: /*Frequency control*/ + gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF00)|val; + break; + case 2: /*Start addr high*/ + gus.startx[gus.voice]=(gus.startx[gus.voice]&0xF807F)|(val<<7); + gus.start[gus.voice]=(gus.start[gus.voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]); + break; + case 3: /*Start addr low*/ + gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFFFF00)|val; +// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]); + break; + case 4: /*End addr high*/ + gus.endx[gus.voice]=(gus.endx[gus.voice]&0xF807F)|(val<<7); + gus.end[gus.voice]=(gus.end[gus.voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]); + break; + case 5: /*End addr low*/ + gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFFFF00)|val; +// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); +// printf("RFREQ %02X %i %i %f\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6)))); + break; + + case 0x9: /*Current volume*/ + gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE0000)|(val<<9); +// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]); + break; + + case 0xA: /*Current addr high*/ + gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1F00FFFF)|(val<<16); +gus.curx[gus.voice]=(gus.curx[gus.voice]&0xF807F00)|((val<<7)<<8); +// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0F807F00)|((val<<7)<<8); +// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]); + break; + case 0xB: /*Current addr low*/ + gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFFFF00)|val; +// printf("Write %i cur %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]); + break; + + case 0x42: /*DMA address low*/ + gus.dmaaddr=(gus.dmaaddr&0xFF000)|(val<<4); + break; + + case 0x43: /*Address low*/ + gus.addr=(gus.addr&0xFFF00)|val; + break; + case 0x45: /*Timer control*/ +// printf("Timer control %02X\n",val); + gus.tctrl=val; + break; + } + break; + case 0x345: /*Global high*/ +// if (gus.global!=0x43 && gus.global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X\n",gus.global,gus.voice,val,CS,pc); + switch (gus.global) + { + case 0: /*Voice control*/ + if (!(val&1) && gus.ctrl[gus.voice]&1) + { +// printf("Voice on %i - start %05X end %05X freq %04X\n",gus.voice,gus.start[gus.voice],gus.end[gus.voice],gus.freq[gus.voice]); +// if (val&0x40) gus.cur[gus.voice]=gus.end[gus.voice]<<8; +// else gus.cur[gus.voice]=gus.start[gus.voice]<<8; + } + if (val&2) val|=1; + gus.waveirqs[gus.voice]=val&0x80; + gus.ctrl[gus.voice]=val&0x7F; + pollgusirqs(); + break; + case 1: /*Frequency control*/ + gus.freq[gus.voice]=(gus.freq[gus.voice]&0xFF)|(val<<8); + break; + case 2: /*Start addr high*/ + gus.startx[gus.voice]=(gus.startx[gus.voice]&0x07FFF)|(val<<15); + gus.start[gus.voice]=(gus.start[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i start %08X %08X %02X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice],val); + break; + case 3: /*Start addr low*/ + gus.startx[gus.voice]=(gus.startx[gus.voice]&0xFFF80)|(val&0x7F); + gus.start[gus.voice]=(gus.start[gus.voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i start %08X %08X\n",gus.voice,gus.start[gus.voice],gus.startx[gus.voice]); + break; + case 4: /*End addr high*/ + gus.endx[gus.voice]=(gus.endx[gus.voice]&0x07FFF)|(val<<15); + gus.end[gus.voice]=(gus.end[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i end %08X %08X %02X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice],val); + break; + case 5: /*End addr low*/ + gus.endx[gus.voice]=(gus.endx[gus.voice]&0xFFF80)|(val&0x7F); + gus.end[gus.voice]=(gus.end[gus.voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i end %08X %08X\n",gus.voice,gus.end[gus.voice],gus.endx[gus.voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus.rfreq[gus.voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); +// printf("RFREQ %02X %i %i %f %i\n",val,gus.voice,gus.rfreq[gus.voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))),ins); + break; + case 0x7: /*Ramp start*/ + gus.rstart[gus.voice]=val<<17; + break; + case 0x8: /*Ramp end*/ + gus.rend[gus.voice]=val<<17; + break; + case 0x9: /*Current volume*/ + gus.curvol[gus.voice]=gus.rcur[gus.voice]=(gus.rcur[gus.voice]&0x1FE00)|(val<<17); +// printf("Vol %i is %04X\n",gus.voice,gus.curvol[gus.voice]); + break; + + case 0xA: /*Current addr high*/ + gus.cur[gus.voice]=(gus.cur[gus.voice]&0x00FFFFFF)|((val&0x1F)<<24); +gus.curx[gus.voice]=(gus.curx[gus.voice]&0x07FFF00)|((val<<15)<<8); +// printf("Write %i cur %08X %08X %02X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice],val); +// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x007FFF00)|((val<<15)<<8); + break; + case 0xB: /*Current addr low*/ + gus.cur[gus.voice]=(gus.cur[gus.voice]&0x1FFF00FF)|(val<<8); +gus.curx[gus.voice]=(gus.curx[gus.voice]&0xFFF8000)|((val&0x7F)<<8); +// gus.cur[gus.voice]=(gus.cur[gus.voice]&0x0FFF8000)|((val&0x7F)<<8); +// printf("Write %i cur %08X %08X\n",gus.voice,gus.cur[gus.voice],gus.curx[gus.voice]); + break; + case 0xD: /*Ramp control*/ + if (val&2) val|=1; + gus.rampirqs[gus.voice]=val&0x80; + gus.rctrl[gus.voice]=val&0x7F; + pollgusirqs(); +// printf("Ramp control %02i %02X %02X %i\n",gus.voice,val,gus.rampirqs[gus.voice],ins); + break; + + case 0xE: + gus.voices=(val&63)+1; + if (gus.voices>32) gus.voices=32; + if (gus.voices<14) gus.voices=14; + gus.global=val; +// printf("GUS voices %i\n",val&31); + break; + + case 0x41: /*DMA*/ + if (val&1) + { +// printf("DMA start! %05X %02X\n",gus.dmaaddr,val); + c=0; + while (c<65536) + { + d=readdma3(); + if (d==-1) break; + if (val&0x80) d^=0x80; + gusram[gus.dmaaddr]=d; + gus.dmaaddr++; + gus.dmaaddr&=0xFFFFF; + c++; + } +// printf("Transferred %i bytes\n",c); + gus.dmactrl=val&~0x40; + if (val&0x20) gusirqnext=1; +// exit(-1); + } + break; + + case 0x42: /*DMA address low*/ + gus.dmaaddr=(gus.dmaaddr&0xFF0)|(val<<12); + break; + + case 0x43: /*Address low*/ + gus.addr=(gus.addr&0xF00FF)|(val<<8); + break; + case 0x44: /*Address high*/ + gus.addr=(gus.addr&0xFFFF)|((val<<16)&0xF0000); + break; + case 0x45: /*Timer control*/ + if (!(val&4)) gus.irqstatus&=~4; + if (!(val&8)) gus.irqstatus&=~8; +// printf("Timer control %02X\n",val); +/* if ((val&4) && !(gus.tctrl&4)) + { + gus.t1=gus.t1l; + gus.t1on=1; + }*/ + gus.tctrl=val; + break; + case 0x46: /*Timer 1*/ + gus.t1=gus.t1l=val; + gus.t1on=1; +// printf("GUS timer 1 %i\n",val); + break; + case 0x47: /*Timer 2*/ + gus.t2=gus.t2l=val<<2; + gus.t2on=1; +// printf("GUS timer 2 %i\n",val); + break; + } + break; + case 0x347: /*DRAM access*/ + gusram[gus.addr]=val; +// pclog("GUS RAM write %05X %02X\n",gus.addr,val); + gus.addr&=0xFFFFF; + break; + case 0x248: case 0x388: gus.adcommand=val; break; + } +} + +uint8_t readgus(uint16_t addr) +{ + uint8_t val; +// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus.global); +// output=3; + switch (addr) + { + case 0x240: return 0; + case 0x246: /*IRQ status*/ + val=gus.irqstatus; +// printf("246 status %02X\n",val); +// gus.irqstatus=0; +// if (gus.irqstatus2==0xE0) picintc(0x20); + return val; + case 0x24A: + return gus.adcommand; + case 0x24B: case 0x24F: return 0; + case 0x340: /*MIDI status*/ + case 0x341: /*MIDI data*/ + return 0; + case 0x342: return gus.voice; + case 0x343: return gus.global; + case 0x344: /*Global low*/ +// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("Reading register %02X %02X\n",gus.global,gus.voice); + switch (gus.global) + { + case 0x82: /*Start addr high*/ + return gus.start[gus.voice]>>16; + case 0x83: /*Start addr low*/ + return gus.start[gus.voice]&0xFF; + + case 0x89: /*Current volume*/ + return gus.rcur[gus.voice]>>9; + case 0x8A: /*Current addr high*/ + return gus.cur[gus.voice]>>16; + case 0x8B: /*Current addr low*/ + return gus.cur[gus.voice]&0xFF; + + case 0x8F: /*IRQ status*/ + val=gus.irqstatus2; +// pclog("Read IRQ status - %02X\n",val); + gus.rampirqs[gus.irqstatus2&0x1F]=0; + gus.waveirqs[gus.irqstatus2&0x1F]=0; + pollgusirqs(); + return val; + } + //fatal("Bad GUS global low read %02X\n",gus.global); + break; + case 0x345: /*Global high*/ +// /*if (gus.global!=0x43 && gus.global!=0x44) */printf("HReading register %02X %02X\n",gus.global,gus.voice); + switch (gus.global) + { + case 0x80: /*Voice control*/ + return gus.ctrl[gus.voice]|(gus.waveirqs[gus.voice]?0x80:0); + + case 0x82: /*Start addr high*/ + return gus.start[gus.voice]>>24; + case 0x83: /*Start addr low*/ + return gus.start[gus.voice]>>8; + + case 0x89: /*Current volume*/ + return gus.rcur[gus.voice]>>17; + + case 0x8A: /*Current addr high*/ + return gus.cur[gus.voice]>>24; + case 0x8B: /*Current addr low*/ + return gus.cur[gus.voice]>>8; + + case 0x8D: +// pclog("Read ramp control %02X %08X %08X %08X %08X\n",gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0),gus.rcur[gus.voice],gus.rfreq[gus.voice],gus.rstart[gus.voice],gus.rend[gus.voice]); + return gus.rctrl[gus.voice]|(gus.rampirqs[gus.voice]?0x80:0); + + case 0x8F: /*IRQ status*/ + val=gus.irqstatus2; +// pclog("Read IRQ status - %02X\n",val); + gus.rampirqs[gus.irqstatus2&0x1F]=0; + gus.waveirqs[gus.irqstatus2&0x1F]=0; + pollgusirqs(); + return val; + + case 0x41: /*DMA control*/ + val=gus.dmactrl|((gus.irqstatus&0x80)?0x40:0); + gus.irqstatus&=~0x80; + return val; + case 0x45: /*Timer control*/ + return gus.tctrl; + case 0x49: /*Sampling control*/ + return 0; + } + //fatal("Bad GUS global high read %02X\n",gus.global); + break; + case 0x346: return 0; + case 0x347: /*DRAM access*/ + val=gusram[gus.addr]; +// pclog("GUS RAM read %05X %02X\n",gus.addr,val); +// output=3; + gus.addr&=0xFFFFF; + return val; + case 0x349: return 0; + } +// printf("Bad GUS read %04X! %02X\n",addr,gus.global); +// exit(-1); + return 0; +} + +void pollgus() +{ + if (gus.t1on) + { + gus.t1++; + if (gus.t1>=0xFF) + { +// gus.t1on=0; + gus.t1=gus.t1l; + if (gus.tctrl&4) + { + picintlevel(0x20); + gus.irqstatus|=4; +// printf("GUS T1 IRQ!\n"); + } + } + } + if (gusirqnext) + { + gusirqnext=0; + gus.irqstatus|=0x80; + picintlevel(0x20); + } +} + +void pollgus2() +{ + if (gus.t2on) + { + gus.t2++; + if (gus.t2>=(0xFF<<2)) + { +// gus.t2on=0; + gus.t2=gus.t2l; + if (gus.tctrl&8) + { + picintlevel(0x20); + gus.irqstatus|=8; +// printf("GUS T2 IRQ!\n"); + } + } + } + if (gusirqnext) + { + gusirqnext=0; + gus.irqstatus|=0x80; + picintlevel(0x20); + } +} + +float gusfreqs[]= +{ + 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, + 23746,22866,22050,21289,20580,19916,19293 +}; + +int16_t gusbufferx[65536]; +int guspos=0; +void getgus(int16_t *p, int count) +{ + memcpy(p,gusbufferx,count*4); +// printf("Get %i samples %i\n",guspos,count); + guspos=0; + pollgusirqs(); +} + +void pollgussamp() +{ + uint32_t addr; + int c,d; + int16_t v; + int32_t vl; + int16_t p[2]; + float GUSRATECONST; + if (guspos>65500) return; +// return; + if (gus.voices<14) GUSRATECONST=44100.0/48000.0; + else GUSRATECONST=gusfreqs[gus.voices-14]/48000.0; +// printf("Voices %i freq %f\n",gus.voices,GUSRATECONST*48000.0); +// for (c=0;c>9; + addr=(addr&0xC0000)|((addr<<1)&0x3FFFE); + if (!(gus.freq[d]>>10)) /*Interpolate*/ + { + vl=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80)*(511-(gus.cur[d]&511)); + vl+=(int16_t)(int8_t)((gusram[(addr+3)&0xFFFFF]^0x80)-0x80)*(gus.cur[d]&511); + v=vl>>9; + } + else + v=(int16_t)(int8_t)((gusram[(addr+1)&0xFFFFF]^0x80)-0x80); + } + else + { + if (!(gus.freq[d]>>10)) /*Interpolate*/ + { + vl=((int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80))*(511-(gus.cur[d]&511)); + vl+=((int8_t)((gusram[((gus.cur[d]>>9)+1)&0xFFFFF]^0x80)-0x80))*(gus.cur[d]&511); + v=vl>>9; + } + else + v=(int16_t)(int8_t)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80); + } +// v=(int16_t)((float)((gusram[(gus.cur[d]>>9)&0xFFFFF]^0x80)-0x80)*32.0*vol16bit[(gus.rcur[d]>>13)&4095]); + if ((gus.rcur[d]>>13)>4095) v=(int16_t)(float)(v)*24.0*vol16bit[4095]; + else v=(int16_t)(float)(v)*24.0*vol16bit[(gus.rcur[d]>>13)&4095]; +// if (!d) printf("%08X %08X %08X %05X %08X %08X %04X %f %04X %08X %i\n",gus.cur[d],gus.start[d],gus.end[d],gus.cur[d]>>9,gus.startx[d],gus.endx[d],gus.rcur[d],vol16bit[0],v,gus.freq[d],ins); +// if (!d) +// { + p[0]+=v; + p[1]+=v; +// } +// printf("Data from %08X\n",gus.cur[d]>>8); + if (gus.ctrl[d]&0x40) + { + gus.cur[d]-=(gus.freq[d]>>1)*GUSRATECONST; + if (gus.cur[d]<=gus.start[d]) + { + if (!(gus.rctrl[d]&4)) + { + if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1; + else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40; + gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d]; + } + if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1; + } + } + else + { + gus.cur[d]+=(gus.freq[d]>>1)*GUSRATECONST; +// pclog("GUS add %08X %f\n",gus.freq[d],GUSRATECONST); + if (gus.cur[d]>=gus.end[d]) + { + if (!(gus.rctrl[d]&4)) + { +// gus.ctrl[d]|=1; + if (!(gus.ctrl[d]&8)) gus.ctrl[d]|=1; + else if (gus.ctrl[d]&0x10) gus.ctrl[d]^=0x40; + gus.cur[d]=(gus.ctrl[d]&0x40)?gus.end[d]:gus.start[d]; + } + if (gus.ctrl[d]&0x20) gus.waveirqs[d]=1; + } + } + } + if (!(gus.rctrl[d]&1)) + { + if (gus.rctrl[d]&0x40) + { + gus.rcur[d]-=gus.rfreq[d]*GUSRATECONST*16; +// printf("RCUR- %i %i %i %i %i\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]); + if (gus.rcur[d]<=gus.rstart[d]) + { + if (gus.rctrl[d]&8) gus.rcur[d]=gus.rend[d]<<8; + else gus.rctrl[d]|=1; + if (gus.rctrl[d]&0x20) + { + gus.rampirqs[d]=1; +// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]); + } + } + } + else + { + gus.rcur[d]+=gus.rfreq[d]*GUSRATECONST*16; +// printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus.rfreq[d],gus.rcur[d],gus.rstart[d],gus.rend[d]); + if (gus.rcur[d]>=gus.rend[d]) + { + if (gus.rctrl[d]&8) gus.rcur[d]=gus.rstart[d]<<8; + else gus.rctrl[d]|=1; + if (gus.rctrl[d]&0x20) + { + gus.rampirqs[d]=1; +// pclog("Causing ramp IRQ %02X\n",gus.rctrl[d]); + } + } + } + } + } + gusbufferx[guspos++]=p[0]; + gusbufferx[guspos++]=p[1]; + if (guspos==65536) guspos=0; +// } + pollgusirqs(); +} + +void gus_init() +{ + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL); + io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL); + io_sethandler(0x0388, 0x0001, NULL, NULL, NULL, writegus, NULL, NULL); +} diff --git a/src/harddisk.c b/src/harddisk.c new file mode 100644 index 00000000..cef4b0d4 --- /dev/null +++ b/src/harddisk.c @@ -0,0 +1,155 @@ +/*Due to the lack of a real hard disc BIOS (other than the WD ST-506 one in MESS), + I wrote this. It's better as it can handle bigger discs, but is (potentially) + less compatible.*/ +#include +#include +#include "ibm.h" + +extern int output; +void inithdc() +{ + return; + hdc[0].f=romfopen("hdc.img","rb+"); + if (!hdc[0].f) + { + hdc[0].f=romfopen("hdc.img","wb"); + putc(0,hdc[0].f); + fclose(hdc[0].f); + hdc[0].f=romfopen("hdc.img","rb+"); + } +// hdc[0].spt=16; +// hdc[0].hpc=5; +// hdc[0].tracks=977; + + hdc[1].f=romfopen("hdd.img","rb+"); + if (!hdc[1].f) + { + hdc[1].f=romfopen("hdd.img","wb"); + putc(0,hdc[1].f); + fclose(hdc[1].f); + hdc[1].f=romfopen("hdd.img","rb+"); + } +// hdc[1].spt=32; +// hdc[1].hpc=16; +// hdc[1].tracks=447; +} + +void int13hdc() +{ + int drv=DL&1; + int track,head,sector; + uint32_t addr; + int c,d; + uint8_t buf[512]; + fullspeed(); +// ram[0x475]=2; +// printf("INT 13 HDC %04X %04X %04X %04X %04X:%04X\n",AX,BX,CX,DX,CS,pc); + switch (AH) + { + case 0: /*Reset disk system*/ + AH=0; + flags&=~C_FLAG; + break; + case 2: /*Read sectors into memory*/ +// printf("Read %i sectors to %04X:%04X\n",AL,es>>4,BX); +// if (es==0xf940) output=3; + track=CH|((CL&0xC0)<<2); + sector=(CL&63)-1; + head=DH; + addr=((((track*hdc[drv].hpc)+head)*hdc[drv].spt)+sector)*512; +// printf("Read track %i head %i sector %i addr %08X HPC %i SPT %i %08X\n",track,head,sector,addr,hdc[drv].hpc,hdc[drv].spt,old8); + fseek(hdc[drv].f,addr,SEEK_SET); + for (c=0;c>2)&0xC0); +// printf("Drive params - %02X %02X %i %i\n",CL,CH,hdc[drv].tracks,hdc[drv].spt); + DH=hdc[drv].hpc-1; + DL=2; + flags&=~C_FLAG; + break; + case 0x10: /*Check drive ready*/ + AH=0; + flags&=~C_FLAG; + break; + case 0x18: /*Set media type*/ + AH=1; + flags|=C_FLAG; + break; + + default: + AH=1; + flags|=C_FLAG; +// printf("Bad HDC int 13 %04X\n",AX); +// dumpregs(); +// exit(-1); + } +} + +char tempbuf[512*63]; +void resizedrive(int drv) +{ + FILE *f; + int c,d,e; +// char temp[512*63]; + if (!drv) + { + fflush(hdc[0].f); + if (hdc[0].f) fclose(hdc[0].f); + f=romfopen("hdc.img","wb"); + } + else + { + fflush(hdc[1].f); + if (hdc[1].f) fclose(hdc[1].f); + f=romfopen("hdd.img","wb"); + } + memset(tempbuf,0,512*63); + for (c=0;c= 0xc0 || headland_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return headland_regs[headland_index]; + } + return headland_index; +} + +void headland_init() +{ + io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL); +} diff --git a/src/headland.h b/src/headland.h new file mode 100644 index 00000000..e736b815 --- /dev/null +++ b/src/headland.h @@ -0,0 +1 @@ +void headland_init(); diff --git a/src/ibm.h b/src/ibm.h new file mode 100644 index 00000000..5917f137 --- /dev/null +++ b/src/ibm.h @@ -0,0 +1,468 @@ +#include +#include +#define printf pclog + +/*Memory*/ +uint8_t *ram,*vram; + +unsigned char isram[0x10000]; + +uint32_t rammask; + +int readlookup[256],readlookupp[256]; +uint32_t *readlookup2; +int readlnext; +int writelookup[256],writelookupp[256]; +uint32_t *writelookup2; +int writelnext; + +extern int mmu_perm; + +#define readmemb(a) ((readlookup2[(a)>>12]==0xFFFFFFFF)?readmembl(a):ram[readlookup2[(a)>>12]+((a)&0xFFF)]) +#define readmemw(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE)?readmemwl(s,a):*((uint16_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))) +#define readmeml(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC)?readmemll(s,a):*((uint32_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))) + +//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v +//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a)) +//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v) + +//void writememb(uint32_t addr, uint8_t val); +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint8_t readmemb386l(uint32_t seg, uint32_t addr); +void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + +uint8_t *getpccache(uint32_t a); + +uint32_t mmutranslatereal(uint32_t addr, int rw); + +void addreadlookup(uint32_t virt, uint32_t phys); +void addwritelookup(uint32_t virt, uint32_t phys); + + +/*IO*/ +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t val); +uint16_t inw(uint16_t port); +void outw(uint16_t port, uint16_t val); +uint32_t inl(uint16_t port); +void outl(uint16_t port, uint32_t val); + +FILE *romfopen(char *fn, char *mode); +extern int shadowbios,shadowbios_write; +extern int cache; +extern int mem_size; +extern int readlnum,writelnum; +extern int memwaitstate; + + +/*Processor*/ +#define EAX regs[0].l +#define ECX regs[1].l +#define EDX regs[2].l +#define EBX regs[3].l +#define ESP regs[4].l +#define EBP regs[5].l +#define ESI regs[6].l +#define EDI regs[7].l +#define AX regs[0].w +#define CX regs[1].w +#define DX regs[2].w +#define BX regs[3].w +#define SP regs[4].w +#define BP regs[5].w +#define SI regs[6].w +#define DI regs[7].w +#define AL regs[0].b.l +#define AH regs[0].b.h +#define CL regs[1].b.l +#define CH regs[1].b.h +#define DL regs[2].b.l +#define DH regs[2].b.h +#define BL regs[3].b.l +#define BH regs[3].b.h + +typedef union +{ + uint32_t l; + uint16_t w; + struct + { + uint8_t l,h; + } b; +} x86reg; + +x86reg regs[8]; +uint16_t flags,eflags; +uint32_t /*cs,ds,es,ss,*/oldds,oldss,pc,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +//uint16_t msw; + +extern int ins,output; +extern int cycdiff; + +typedef struct +{ + uint32_t base; + uint32_t limit,limitw; + uint8_t access; + uint16_t seg; +} x86seg; + +x86seg gdt,ldt,idt,tr; +x86seg _cs,_ds,_es,_ss,_fs,_gs; +x86seg _oldds; + +uint32_t pccache; +uint8_t *pccache2; +/*Segments - + _cs,_ds,_es,_ss are the segment structures + CS,DS,ES,SS is the 16-bit data + cs,ds,es,ss are defines to the bases*/ +//uint16_t CS,DS,ES,SS; +#define CS _cs.seg +#define DS _ds.seg +#define ES _es.seg +#define SS _ss.seg +#define FS _fs.seg +#define GS _gs.seg +#define cs _cs.base +#define ds _ds.base +#define es _es.base +#define ss _ss.base +#define fs _fs.base +#define gs _gs.base + +#define CPL ((_cs.access>>5)&3) + +void loadseg(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); + +union +{ + uint32_t l; + uint16_t w; +} CR0; + +#define cr0 CR0.l +#define msw CR0.w + +uint32_t cr2,cr3; + +#define C_FLAG 0x0001 +#define P_FLAG 0x0004 +#define A_FLAG 0x0010 +#define Z_FLAG 0x0040 +#define N_FLAG 0x0080 +#define T_FLAG 0x0100 +#define I_FLAG 0x0200 +#define D_FLAG 0x0400 +#define V_FLAG 0x0800 +#define NT_FLAG 0x4000 +#define VM_FLAG 0x0002 /*In EFLAGS*/ + +#define WP_FLAG 0x10000 /*In CR0*/ + +#define IOPL ((flags>>12)&3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) +//#define IOPLp 1 + +//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL)) +extern int cycles; +extern int cycles_lost; +extern int is486; +extern uint8_t opcode; +extern int insc; +extern int fpucount; +extern float mips,flops; +extern int clockrate; +extern int cgate16; +extern int CPUID; + +extern int cpl_override; + +/*Timer*/ +typedef struct PIT +{ + uint32_t l[3]; + double c[3]; + uint8_t m[3]; + uint8_t ctrl,ctrls[2]; + int wp,rm[3],wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; +} PIT; + +PIT pit; +void setpitclock(float clock); +int pitcount; + +float pit_timer0_freq(); + + + +/*DMA*/ +typedef struct DMA +{ + uint16_t ab[4],ac[4]; + uint16_t cb[4]; + int cc[4]; + int wp; + uint8_t m,mode[4]; + uint8_t page[4]; + uint8_t stat; + uint8_t command; +} DMA; + +DMA dma,dma16; + + +/*PPI*/ +typedef struct PPI +{ + int s2; + uint8_t pa,pb; +} PPI; + +PPI ppi; +extern int key_inhibit; + + +/*PIC*/ +typedef struct PIC +{ + uint8_t icw1,mask,ins,pend,mask2; + int icw; + uint8_t vector; + int read; +} PIC; + +PIC pic,pic2; +extern int pic_intpending; +int intcount; + + +/*FDC*/ +typedef struct FDC +{ + uint8_t dor,stat,command,dat,st0; + int head,track[256],sector,drive,lastdrive; + int pos; + uint8_t params[256]; + uint8_t res[256]; + int pnum,ptot; + int rate; + uint8_t specify[256]; + int eot[256]; + int lock; + int perp; + uint8_t config, pretrk; +} FDC; + +FDC fdc; +int disctime; +char discfns[2][256]; +int driveempty[2]; + + +/*Config stuff*/ +#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) && (romset=ROM_IBMAT)) +#define HERCULES (gfxcard==GFX_HERCULES && (romset=ROM_IBMAT)) +#define AMSTRAD (romset==ROM_PC1512 || romset==ROM_PC1640 || romset==ROM_PC3086) +#define AMSTRADIO (romset==ROM_PC1512 || romset==ROM_PC1640 || romset==ROM_PC200 || romset==ROM_PC2086 || romset == ROM_PC3086) +#define TANDY (romset==ROM_TANDY/* || romset==ROM_IBMPCJR*/) +#define VID_EGA (gfxcard==GFX_EGA) +#define EGA (romset==ROM_PC1640 || VID_EGA || VGA) +#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) +#define SVGA (gfxcard==GFX_ET4000 && VGA) +#define TRIDENT (gfxcard==GFX_TVGA && !OTI067) +#define OTI067 (romset==ROM_ACER386) +#define ET4000 (gfxcard==GFX_ET4000 && VGA) +#define ET4000W32 (gfxcard==GFX_ET4000W32 && VGA) +#define AT (romset>=ROM_IBMAT) +#define PCI (romset == ROM_PCI486) + +#define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486) +int FASTDISC; +int ADLIB; +int GAMEBLASTER; + +enum +{ + ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/ + ROM_IBMXT, /*301 keyboard error*/ + ROM_GENXT, /*'Generic XT BIOS'*/ + ROM_DTKXT, + ROM_EUROPC, + ROM_OLIM24, + ROM_TANDY, + ROM_PC1512, + ROM_PC200, + ROM_PC1640, + ROM_PC2086, + ROM_PC3086, + ROM_IBMAT, + ROM_CMDPC30, + ROM_AMI286, + ROM_DELL200, + ROM_MISC286, + ROM_IBMAT386, + ROM_ACER386, + ROM_MEGAPC, + ROM_AMI386, + ROM_AMI486, + ROM_WIN486, + ROM_PCI486 +}; + +//#define ROM_IBMPCJR 5 /*Not working! ROMs are corrupt*/ +#define is386 (romset>=ROM_IBMAT386) +#define is386sx 0 + +int hasfpu; +int romset; + +#define GFX_CGA 0 +#define GFX_MDA 1 +#define GFX_HERCULES 2 +#define GFX_EGA 3 /*Using IBM EGA BIOS*/ +//#define GFX_OTI067 3 /*Using BIOS from Acer 386SX/25N - edit - only works with Acer BIOS! Stupid integrated systems*/ +#define GFX_TVGA 4 /*Using Trident 8900D BIOS*/ +#define GFX_ET4000 5 /*Tseng ET4000*/ +#define GFX_ET4000W32 6 /*Tseng ET4000/W32p (Diamond Stealth 32)*/ +#define GFX_BAHAMAS64 7 /*S3 Vision864 (Paradise Bahamas 64)*/ +#define GFX_N9_9FX 8 /*S3 764/Trio64 (Number Nine 9FX)*/ +#define GFX_STEALTH64 9 /*S3 Vision964 (Diamond Stealth 64 VRAM PCI)*/ + +int gfxcard; + +int cpuspeed; + + +/*Video*/ +void (*pollvideo)(); +void pollega(); +int readflash; +uint8_t hercctrl; +int slowega,egacycles,egacycles2; +extern uint8_t gdcreg[16]; +extern int incga; +extern int egareads,egawrites; +extern int cga_comp; +extern int vid_resize; +extern int winsizex,winsizey; +extern int chain4; + +uint8_t readvram(uint16_t addr); +void writevram(uint16_t addr, uint8_t val); +void writevramgen(uint16_t addr, uint8_t val); + +uint8_t readtandyvram(uint16_t addr); +void writetandy(uint16_t addr, uint8_t val); +void writetandyvram(uint16_t addr, uint8_t val); + +extern int et4k_b8000; +extern int changeframecount; +extern uint8_t changedvram[(8192*1024)/1024]; + +void writeega_chain4(uint32_t addr, uint8_t val); +extern uint32_t svgarbank,svgawbank; + +/*Serial*/ +extern int mousedelay; + + +/*Sound*/ +uint8_t spkstat; + +float spktime,soundtime,gustime,gustime2,vidtime,rtctime; +int ppispeakon; +//#define SPKCONST (8000000.0/44100.0) +float SPKCONST; +float SOUNDCONST; +float CASCONST; +float GUSCONST,GUSCONST2; +float CGACONST; +float MDACONST; +float VGACONST1,VGACONST2; +float RTCCONST; +int gated,speakval,speakon; + +#define SOUNDBUFLEN (48000/10) + + +/*Sound Blaster*/ +int sbenable,sblatchi,sblatcho,sbcount,sb_enable_i,sb_count_i; +int16_t sbdat; +void setsbclock(float clock); + +#define SADLIB 1 /*No DSP*/ +#define SB1 2 /*DSP v1.05*/ +#define SB15 3 /*DSP v2.00*/ +#define SB2 4 /*DSP v2.01 - needed for high-speed DMA*/ +#define SBPRO 5 /*DSP v3.00*/ +#define SBPRO2 6 /*DSP v3.02 + OPL3*/ +#define SB16 7 /*DSP v4.05 + OPL3*/ +int sbtype; + +struct +{ + int vocl,vocr,voc; + int midl,midr,mid; + int masl,masr,mas; +} sbpmixer; +extern int sb_freq; + +struct +{ + int master_l,master_r; + int voice_l,voice_r; + int fm_l,fm_r; + int bass_l,bass_r; + int treble_l,treble_r; + int filter; +} mixer; + + +int clocks[3][12][4]; +int at70hz; + +char pcempath[512]; + + +/*Hard disc*/ + +typedef struct +{ + FILE *f; + int spt,hpc; /*Sectors per track, heads per cylinder*/ + int tracks; +} PcemHDC; + +PcemHDC hdc[2]; + +/*Keyboard*/ +int keybsenddelay; +extern int kb_win; + + +/*CD-ROM*/ +extern int cdrom_drive; +extern int idecallback[2]; +extern int cdrom_enabled; + +void pclog(const char *format, ...); +extern int nmi; + +extern int times; + + +extern float isa_timing, bus_timing; diff --git a/src/ide.c b/src/ide.c new file mode 100644 index 00000000..46c6dee4 --- /dev/null +++ b/src/ide.c @@ -0,0 +1,1757 @@ +/*RPCemu v0.6 by Tom Walker + IDE emulation*/ +//#define RPCEMU_IDE + +#define IDE_TIME 5 + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#ifdef RPCEMU_IDE + #include "rpcemu.h" + #include "iomd.h" + #include "arm.h" +#else + #include "ibm.h" +#endif +#include "ide.h" + +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +/* ATA Commands */ +#define WIN_SRST 0x08 /* ATAPI Device Reset */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +#define WIN_READ 0x20 /* 28-Bit Read */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/ +#define WIN_WRITE 0x30 /* 28-Bit Write */ +#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */ +#define WIN_VERIFY 0x40 /* 28-Bit Verify */ +#define WIN_FORMAT 0x50 +#define WIN_SEEK 0x70 +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ +#define WIN_SETIDLE1 0xE3 +#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ + +/* ATAPI Commands */ +#define GPCMD_INQUIRY 0x12 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_10 0x28 +#define GPCMD_READ_CD 0xbe +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_SEEK 0x2b +#define GPCMD_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_TEST_UNIT_READY 0x00 + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* ATAPI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* ATAPI Additional Sense Codes */ +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_MEDIUM_NOT_PRESENT 0x3a + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 + +/** Evaluate to non-zero if the currently selected drive is an ATAPI device */ +#define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM) +/* +\ + (!ide.drive)*/ + +ATAPI *atapi; + +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM +}; + +typedef struct IDE +{ + int type; + int board; + uint8_t atastat; + uint8_t error; + int secount,sector,cylinder,head,drive,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + int packlen; + int spt,hpc; + int tracks; + int packetstatus; + int cdpos,cdlen; + uint8_t asc; + int discchanged; + int reset; + FILE *hdfile; + uint16_t buffer[65536]; + int irqstat; + int service; + int lba; + uint32_t lba_addr; + int skip512; +} IDE; + +IDE ide_drives[4]; + +IDE *ext_ide; + +char ide_fn[2][512]; + +static void callreadcd(IDE *ide); +static void atapicommand(int ide_board); + +int idecallback[2] = {0, 0}; + +int cur_ide[2]; + +uint8_t getstat(IDE *ide) { return ide->atastat; } + +static inline void ide_irq_raise(IDE *ide) +{ +// pclog("IDE_IRQ_RAISE\n"); + if (!(ide->fdisk&2)) { +#ifdef RPCEMU_IDE + iomd.irqb.status |= IOMD_IRQB_IDE; + updateirqs(); +#else +// if (ide->board && !ide->irqstat) pclog("IDE_IRQ_RAISE\n"); + picint((ide->board)?(1<<15):(1<<14)); +#endif + } + ide->irqstat=1; + ide->service=1; +} + +static inline void ide_irq_lower(IDE *ide) +{ +// pclog("IDE_IRQ_LOWER\n"); +// if (ide.board == 0) { +#ifdef RPCEMU_IDE + iomd.irqb.status &= ~IOMD_IRQB_IDE; + updateirqs(); +#else + picintc((ide->board)?(1<<15):(1<<14)); +#endif +// } + ide->irqstat=0; +} + +void ide_irq_update(IDE *ide) +{ +#ifdef RPCEMU_IDE + if (ide->irqstat && !(iomd.irqb.status & IOMD_IRQB_IDE) && !(ide->fdisk & 2)) { + iomd.irqb.status |= IOMD_IRQB_IDE; + updateirqs(); + } + else if (iomd.irqb.status & IOMD_IRQB_IDE) + { + iomd.irqb.status &= ~IOMD_IRQB_IDE; + updateirqs(); + } +#else + if (ide->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(ide->fdisk & 2)) + picint((ide->board)?(1<<15):(1<<14)); + else if ((pic2.pend|pic2.ins)&0x40) + picintc((ide->board)?(1<<15):(1<<14)); +#endif +} +/** + * Copy a string into a buffer, padding with spaces, and placing characters as + * if they were packed into 16-bit values, stored little-endian. + * + * @param str Destination buffer + * @param src Source string + * @param len Length of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + */ +static void +ide_padstr(char *str, const char *src, int len) +{ + int i, v; + + for (i = 0; i < len; i++) { + if (*src != '\0') { + v = *src++; + } else { + v = ' '; + } + str[i ^ 1] = v; + } +} + +/** + * Copy a string into a buffer, padding with spaces. Does not add string + * terminator. + * + * @param buf Destination buffer + * @param buf_size Size of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + * @param src Source string + */ +static void +ide_padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') { + buf[i] = *src++; + } else { + buf[i] = ' '; + } + } +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command + */ +static void ide_identify(IDE *ide) +{ + memset(ide->buffer, 0, 512); + + //ide->buffer[1] = 101; /* Cylinders */ + +#ifdef RPCEMU_IDE + ide->buffer[1] = 65535; /* Cylinders */ + ide->buffer[3] = 16; /* Heads */ + ide->buffer[6] = 63; /* Sectors */ +#else + ide->buffer[1] = hdc[cur_ide[0]].tracks; /* Cylinders */ + ide->buffer[3] = hdc[cur_ide[0]].hpc; /* Heads */ + ide->buffer[6] = hdc[cur_ide[0]].spt; /* Sectors */ +#endif + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ +#ifdef RPCEMU_IDE + ide_padstr((char *) (ide->buffer + 27), "RPCemuHD", 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 27), "PCemHD", 40); /* Model */ +#endif + ide->buffer[49] = (1<<9); /* LBA supported */ + ide->buffer[50] = 0x4000; /* Capabilities */ +#ifdef RPCEMU_IDE + ide->buffer[60] = (65535 * 16 * 63) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (65535 * 16 * 63) >> 16; +#else + ide->buffer[60] = (hdc[cur_ide[0]].tracks * hdc[cur_ide[0]].hpc * hdc[cur_ide[0]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (hdc[cur_ide[0]].tracks * hdc[cur_ide[0]].hpc * hdc[cur_ide[0]].spt) >> 16; +#endif +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void ide_atapi_identify(IDE *ide) +{ + memset(ide->buffer, 0, 512); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ +#ifdef RPCEMU_IDE + ide_padstr((char *) (ide->buffer + 27), "RPCemuCD", 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 27), "PCemCD", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ +} + +/** + * Fill in ide->buffer with the output of the ATAPI "MODE SENSE" command + * + * @param pos Offset within the buffer to start filling in data + * + * @return Offset within the buffer after the end of the data + */ +static uint32_t ide_atapi_mode_sense(IDE *ide, uint32_t pos, uint8_t type) +{ + uint8_t *buf = (uint8_t *) ide->buffer; +// pclog("ide_atapi_mode_sense %02X\n",type); + if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE) + { + /* &01 - Read error recovery */ + buf[pos++] = GPMODE_R_W_ERROR_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Error recovery parameters */ + buf[pos++] = 3; /* Read retry count */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE) + { + /* &0D - CD-ROM Parameters */ + buf[pos++] = GPMODE_CDROM_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */ + buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */ + buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE) + { + /* &0e - CD-ROM Audio Control Parameters */ + buf[pos++] = GPMODE_CDROM_AUDIO_PAGE; + buf[pos++] = 0xE; /* Page length */ + buf[pos++] = 4; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */ + buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */ + buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */ + buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 2 Volume */ + buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 3 Volume */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE) + { +// pclog("Capabilities page\n"); + /* &2A - CD-ROM capabilities and mechanical status */ + buf[pos++] = GPMODE_CAPABILITIES_PAGE; + buf[pos++] = 0x12; /* Page length */ + buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ + buf[pos++] = 1; /* Supports audio play, not multisession */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ + buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */ + buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Drive digital format */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + return pos; +} + +/* + * Return the sector offset for the current register values + */ +static off64_t ide_get_sector(IDE *ide) +{ + if (ide->lba) + { + return (off64_t)ide->lba_addr + ide->skip512; + } + else + { + int heads = ide->hpc; + int sectors = ide->spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } +} + +/** + * Move to the next sector using CHS addressing + */ +static void ide_next_sector(IDE *ide) +{ + if (ide->lba) + { + ide->lba_addr++; + } + else + { + ide->sector++; + if (ide->sector == (ide->spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->hpc) { + ide->head = 0; + ide->cylinder++; + } + } + } +} + +#ifdef RPCEMU_IDE +static void loadhd(IDE *ide, int d, const char *fn) +{ + char pathname[512]; + + append_filename(pathname, rpcemu_get_datadir(), fn, 512); + + rpclog("Loading %s\n",pathname); + if (ide->hdfile == NULL) { + /* Try to open existing hard disk image */ + ide->hdfile = fopen64(pathname, "rb+"); + if (ide->hdfile == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + ide->hdfile = fopen64(pathname, "wb+"); + if (ide->hdfile == NULL) { + fatal("Cannot create file '%s': %s", + pathname, strerror(errno)); + } + } else { + /* Failed for another reason */ + fatal("Cannot open file '%s': %s", + pathname, strerror(errno)); + } + } + } + + fseek(ide->hdfile, 0xfc1, SEEK_SET); + ide->spt = getc(ide->hdfile); + ide->hpc = getc(ide->hdfile); + ide->skip512 = 1; +// rpclog("First check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + if (!ide->spt || !ide->hpc) + { + fseek(ide->hdfile, 0xdc1, SEEK_SET); + ide->spt = getc(ide->hdfile); + ide->hpc = getc(ide->hdfile); +// rpclog("Second check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + ide->skip512 = 0; + if (!ide->spt || !ide->hpc) + { + ide->spt=63; + ide->hpc=16; + ide->skip512 = 1; +// rpclog("Final check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + } + } + + ide->type = IDE_HDD; + + rpclog("%i %i %i\n",ide->spt,ide->hpc,ide->skip512); +} +#else +static void loadhd(IDE *ide, int d, const char *fn) +{ + if (ide->hdfile == NULL) { + /* Try to open existing hard disk image */ + ide->hdfile = fopen64(fn, "rb+"); + if (ide->hdfile == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + ide->hdfile = fopen64(fn, "wb+"); + if (ide->hdfile == NULL) { + ide->type = IDE_NONE; +/* fatal("Cannot create file '%s': %s", + fn, strerror(errno));*/ + } + } else { + /* Failed for another reason */ + ide->type = IDE_NONE; +/* fatal("Cannot open file '%s': %s", + fn, strerror(errno));*/ + } + } + } + + ide->spt = hdc[d].spt; + ide->hpc = hdc[d].hpc; + ide->tracks = hdc[d].tracks; + ide->type = IDE_HDD; +} +#endif + +void resetide(void) +{ + int d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 4; d++) { + ide_drives[d].type = IDE_NONE; + if (ide_drives[d].hdfile != NULL) { + fclose(ide_drives[d].hdfile); + ide_drives[d].hdfile = NULL; + } + ide_drives[d].atastat = READY_STAT | DSC_STAT; + ide_drives[d].service = 0; + ide_drives[d].board = (d & 2) ? 1 : 0; + } + + idecallback[0]=idecallback[1]=0; +#ifdef RPCEMU_IDE + loadhd(&ide_drives[0], 0, "hd4.hdf"); + if (!config.cdromenabled) { + loadhd(&ide_drives[1], 1, "hd5.hdf"); + } + else + ide_drives[1].type = IDE_CDROM; +#else + loadhd(&ide_drives[0], 0, ide_fn[0]); + loadhd(&ide_drives[1], 1, ide_fn[1]); + if (cdrom_enabled) + ide_drives[2].type = IDE_CDROM; +#endif + + cur_ide[0] = 0; + cur_ide[1] = 2; + +// ide_drives[1].type = IDE_CDROM; +} + +int idetimes=0; +void writeidew(int ide_board, uint16_t val) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed write IDE %04X:%08X\n",CS,pc); + return; + }*/ +#endif +#ifdef _RPCEMU_BIG_ENDIAN + val=(val>>8)|(val<<8); +#endif +// pclog("Write IDEw %04X\n",val); + ide->buffer[ide->pos >> 1] = val; + ide->pos+=2; + + if (ide->packetstatus==4) + { + if (ide->pos>=(ide->packlen+2)) + { + ide->packetstatus=5; + idecallback[ide_board]=6*IDE_TIME; +// pclog("Packet over!\n"); + ide_irq_lower(ide); + } + return; + } + else if (ide->packetstatus==5) return; + else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC) + { + ide->pos=0; + ide->atastat = BUSY_STAT; + ide->packetstatus=1; + idecallback[ide_board]=6*IDE_TIME; + callbackide(ide_board); +// idecallback[ide_board]=60*IDE_TIME; +// if ((ide->buffer[0]&0xFF)==0x43) idecallback[ide_board]=1*IDE_TIME; +// pclog("Packet now waiting!\n"); +/* if (ide->buffer[0]==0x243) + { + idetimes++; + output=3; + }*/ + } + else if (ide->pos>=512) + { + ide->pos=0; + ide->atastat = BUSY_STAT; + idecallback[ide_board]=6*IDE_TIME; +// callbackide(ide_board); + } +} + +void writeide(int ide_board, uint16_t addr, uint8_t val) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t *idebufferb = (uint8_t *) ide->buffer; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed write IDE %04X:%08X\n",CS,pc); + return; + }*/ +#endif +// return; + addr|=0x80; +// if (ide_board) pclog("Write IDEb %04X %02X %04X(%08X):%04X %i %02X %02X\n",addr,val,CS,cs,pc,ins,ide->atastat,ide_drives[0].atastat); + /*if (idedebug) */ +// pclog("Write IDE %08X %02X %04X:%08X\n",addr,val,CS,pc); +// int c; +// rpclog("Write IDE %08X %02X %08X %08X\n",addr,val,PC,armregs[12]); + + if (ide->type == IDE_NONE && addr != 0x1f6) return; + + switch (addr) + { + case 0x1F0: /* Data */ + writeidew(ide_board, val | (val << 8)); + return; + + case 0x1F1: /* Features */ + ide->cylprecomp=val; + return; + + case 0x1F2: /* Sector count */ + ide->secount=val; + return; + + case 0x1F3: /* Sector */ + ide->sector=val; + ide->lba_addr=(ide->lba_addr&0xFFFFF00)|val; + return; + + case 0x1F4: /* Cylinder low */ + ide->cylinder=(ide->cylinder&0xFF00)|val; + ide->lba_addr=(ide->lba_addr&0xFFF00FF)|(val<<8); +// pclog("Write cylinder low %02X\n",val); + return; + + case 0x1F5: /* Cylinder high */ + ide->cylinder=(ide->cylinder&0xFF)|(val<<8); + ide->lba_addr=(ide->lba_addr&0xF00FFFF)|(val<<16); + return; + + case 0x1F6: /* Drive/Head */ +/* if (val==0xB0) + { + dumpregs(); + exit(-1); + }*/ + cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1); + ide = &ide_drives[cur_ide[ide_board]]; + + ide->head=val&0xF; + ide->lba=val&0x40; + + ide->lba_addr=(ide->lba_addr&0x0FFFFFF)|((val&0xF)<<24); + + ide_irq_update(ide); + return; + + case 0x1F7: /* Command register */ + if (ide->type == IDE_NONE) return; +// pclog("IDE command %02X drive %i\n",val,ide.drive); + ide_irq_lower(ide); + ide->command=val; + +// pclog("New IDE command - %02X %i %i\n",ide->command,cur_ide[ide_board],ide_board); + ide->error=0; + switch (val) + { + case WIN_SRST: /* ATAPI Device Reset */ + if (IDE_DRIVE_IS_CDROM(ide)) ide->atastat = BUSY_STAT; + else ide->atastat = READY_STAT; + idecallback[ide_board]=100*IDE_TIME; + return; + + case WIN_RESTORE: + case WIN_SEEK: + ide->atastat = READY_STAT; + idecallback[ide_board]=100*IDE_TIME; + return; + + case WIN_READ: + case WIN_READ_NORETRY: +/* if (ide.secount>1) + { + fatal("Read %i sectors from sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head); + }*/ +#if 0 + if (ide->lba) pclog("Read %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins); +#endif + ide->atastat = BUSY_STAT; + idecallback[ide_board]=200*IDE_TIME; + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: +/* if (ide.secount>1) + { + fatal("Write %i sectors to sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head); + }*/ +#if 0 + if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT; + ide->pos=0; + return; + + case WIN_VERIFY: +#if 0 + if (ide->lba) pclog("Read verify %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = BUSY_STAT; + idecallback[ide_board]=200*IDE_TIME; + return; + + case WIN_FORMAT: +// pclog("Format track %i head %i\n",ide.cylinder,ide.head); + ide->atastat = DRQ_STAT; +// idecallback[ide_board]=200; + ide->pos=0; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + ide->atastat = BUSY_STAT; + idecallback[ide_board]=200*IDE_TIME; +// pclog("SPECIFY\n"); +// output=1; + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + case WIN_PIDENTIFY: /* Identify Packet Device */ +// output=1; + case WIN_SETIDLE1: /* Idle */ + ide->atastat = BUSY_STAT; + idecallback[ide_board]=200*IDE_TIME; + return; + + case WIN_IDENTIFY: /* Identify Device */ + case 0xEF: +// output=3; +// timetolive=500; + ide->atastat = BUSY_STAT; + idecallback[ide_board]=200*IDE_TIME; + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + ide->packetstatus=0; + ide->atastat = BUSY_STAT; + idecallback[ide_board]=1;//30*IDE_TIME; + ide->pos=0; + return; + + case 0xF0: + default: + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide_irq_raise(ide); + return; + } +// fatal("Bad IDE command %02X\n", val); + return; + + case 0x3F6: /* Device control */ + if ((ide->fdisk&4) && !(val&4) && (ide->type != IDE_NONE)) + { + idecallback[ide_board]=500*IDE_TIME; + ide->reset = 1; + ide->atastat = BUSY_STAT; +// pclog("IDE Reset\n"); + } + ide->fdisk=val; + ide_irq_update(ide); + return; + } +// fatal("Bad IDE write %04X %02X\n", addr, val); +} + +uint8_t readide(int ide_board, uint16_t addr) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + const uint8_t *idebufferb = (const uint8_t *) ide->buffer; + uint8_t temp; + uint16_t tempw; + + addr|=0x80; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed read IDE %04X:%08X\n",CS,pc); + return 0xFF; + }*/ +#endif +// return 0xFF; + + if (ide->type == IDE_NONE && addr != 0x1f6) return 0xff; +// /*if (addr!=0x1F7 && addr!=0x3F6) */pclog("Read IDEb %04X %02X %02X %i %04X:%04X %i %04X\n",addr,ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board, BX); +//rpclog("Read IDE %08X %08X %02X\n",addr,PC,iomd.irqb.mask); + switch (addr) + { + case 0x1F0: /* Data */ + tempw = readidew(ide_board); +// pclog("Read IDEW %04X\n", tempw); + temp = tempw & 0xff; + break; + + case 0x1F1: /* Error */ +// pclog("Read error %02X\n",ide.error); + temp = ide->error; + break; + + case 0x1F2: /* Sector count */ +// pclog("Read sector count %02X\n",ide->secount); + temp = (uint8_t)ide->secount; + break; + + case 0x1F3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x1F4: /* Cylinder low */ +// pclog("Read cyl low %02X\n",ide.cylinder&0xFF); + temp = (uint8_t)(ide->cylinder&0xFF); + break; + + case 0x1F5: /* Cylinder high */ +// pclog("Read cyl low %02X\n",ide.cylinder>>8); + temp = (uint8_t)(ide->cylinder>>8); + break; + + case 0x1F6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + case 0x1F7: /* Status */ + if (ide->type == IDE_NONE) + { +// pclog("Return status 00\n"); + temp = 0; + break; + } + ide_irq_lower(ide); + if (ide->fdisk & 4) + temp = 0x80; + else if (ide->type == IDE_CDROM) + { +// pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); + temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + } + else + { +// && ide->service) return ide.atastat[ide.board]|SERVICE_STAT; +// pclog("Return status %02X\n",ide->atastat); + temp = ide->atastat; + } + break; + + case 0x3F6: /* Alternate Status */ +// pclog("3F6 read %02X\n",ide.atastat[ide.board]); +// if (output) output=0; + if (ide->type == IDE_NONE) + { +// pclog("Return status 00\n"); + temp = 0; + break; + } + if (ide->type == IDE_CDROM) + { +// pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); + temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + } + else + { +// && ide->service) return ide.atastat[ide.board]|SERVICE_STAT; +// pclog("Return status %02X\n",ide->atastat); + temp = ide->atastat; + } + break; + } +// if (ide_board) pclog("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board); + return temp; +// fatal("Bad IDE read %04X\n", addr); +} + +uint16_t readidew(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint16_t temp; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed read IDEw %04X:%08X\n",CS,pc); + return 0xFFFF; + }*/ +#endif +// return 0xFFFF; +// pclog("Read IDEw %04X %04X:%04X %02X %i\n",ide->buffer[ide->pos >> 1],CS,pc,opcode,ins); + +//if (idedebug) pclog("Read IDEW %08X\n",PC); + + temp = ide->buffer[ide->pos >> 1]; + #ifdef _RPCEMU_BIG_ENDIAN + temp=(temp>>8)|(temp<<8); + #endif + ide->pos+=2; + if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen)) + { +// pclog("Over! packlen %i %i\n",ide.packlen,ide.pos); + ide->pos=0; + if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6) + { +// pclog("Call readCD\n"); + callreadcd(ide); + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + ide->packetstatus=0; + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY) + { + ide->secount--; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + idecallback[ide_board]=6*IDE_TIME; +// callbackide(ide_board); + } + } + } + } +// if (ide_board) pclog("Read IDEw %04X\n",temp); + return temp; +} + +int times30=0; +void callbackide(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + off64_t addr; + int c; + ext_ide = ide; +// return; + if (ide->command==0x30) times30++; +// if (times30==2240) output=1; + //if (times30==2471 && ide->command==0xA0) output=1; +///*if (ide_board) */pclog("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]); +// if (times30==1294) +// output=1; + if (ide->reset) + { + ide->atastat = READY_STAT | DSC_STAT; + ide->error=1; + ide->secount=1; + ide->sector=1; + ide->head=0; + ide->cylinder=0; + ide->reset = 0; +// pclog("Reset callback\n"); + return; + } + switch (ide->command) + { + //Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. + case WIN_SRST: /*ATAPI Device Reset */ + ide->atastat = READY_STAT | DSC_STAT; + ide->error=1; /*Device passed*/ + ide->secount = ide->sector = 1; + if (IDE_DRIVE_IS_CDROM(ide)) { + ide->cylinder = 0xeb14; + ide->atastat = 0; + } else { + ide->cylinder = 0; + } + ide_irq_raise(ide); + if (IDE_DRIVE_IS_CDROM(ide)) + ide->service = 0; + return; + + case WIN_RESTORE: + case WIN_SEEK: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } +// pclog("Restore callback\n"); + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Read %i %i %i %08X\n",ide.cylinder,ide.head,ide.sector,addr); + /* if (ide.cylinder || ide.head) + { + fatal("Read from other cylinder/head"); + }*/ + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; +// pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]); +// if (addr) output=3; + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt); + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + ide_irq_raise(ide); + ide->secount--; + if (ide->secount) + { + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } + else + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_VERIFY: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + ide->pos=0; + ide->atastat = READY_STAT | DSC_STAT; +// pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount); + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_FORMAT: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Format cyl %i head %i offset %08X %08X %08X secount %i\n",ide.cylinder,ide.head,addr,addr>>32,addr,ide.secount); + fseeko64(ide->hdfile, addr, SEEK_SET); + memset(ide->buffer, 0, 512); + for (c=0;csecount;c++) + { + fwrite(ide->buffer, 512, 1, ide->hdfile); + } + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide->error=1; /*No error detected*/ + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (IDE_DRIVE_IS_CDROM(ide)) { +#ifndef RPCEMU_IDE + pclog("IS CDROM - ABORT\n"); +#endif + goto abort_cmd; + } + ide->spt=ide->secount; + ide->hpc=ide->head+1; + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE +// pclog("SPECIFY - %i sectors per track, %i heads per cylinder %i %i\n",ide->spt,ide->hpc,cur_ide[ide_board],ide_board); +#endif + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (IDE_DRIVE_IS_CDROM(ide)) { +// pclog("ATAPI identify\n"); + ide_atapi_identify(ide); + ide->pos=0; + ide->error=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } +// pclog("Not ATAPI\n"); + goto abort_cmd; + + case WIN_SETIDLE1: /* Idle */ + case 0xEF: + goto abort_cmd; + + case WIN_IDENTIFY: /* Identify Device */ + if (IDE_DRIVE_IS_CDROM(ide)) { + ide->secount=1; + ide->sector=1; + ide->cylinder=0xEB14; + ide->drive=ide->head=0; + goto abort_cmd; + } + if (ide->type != IDE_NONE) + { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; +// pclog("ID callback\n"); + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!IDE_DRIVE_IS_CDROM(ide)) goto abort_cmd; +// pclog("Packet callback! %i %08X\n",ide->packetstatus,ide); + if (!ide->packetstatus) + { + ide->pos=0; + ide->secount = (uint8_t)((ide->secount&0xF8)|1); + ide->atastat = DRQ_STAT |(ide->atastat&ERR_STAT); + //ide_irq_raise(ide); +// pclog("1 Preparing to recieve packet max DRQ count %04X\n",ide->cylinder); + } + else if (ide->packetstatus==1) + { + ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT); +// pclog("Running ATAPI command 2\n"); + atapicommand(ide_board); +// exit(-1); + } + else if (ide->packetstatus==2) + { +// pclog("packetstatus==2\n"); + ide->atastat = READY_STAT; + ide->secount=3; + ide_irq_raise(ide); +// if (iomd.irqb.mask&2) output=1; + } + else if (ide->packetstatus==3) + { + ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); +// rpclog("Recieve data packet 3! %02X\n",ide->atastat); + ide_irq_raise(ide); + ide->packetstatus=0xFF; + } + else if (ide->packetstatus==4) + { + ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); +// pclog("Send data packet 4!\n"); + ide_irq_raise(ide); +// ide.packetstatus=5; + ide->pos=2; + } + else if (ide->packetstatus==5) + { +// pclog("Packetstatus 5 !\n"); + atapicommand(ide_board); + } + else if (ide->packetstatus==6) /*READ CD callback*/ + { + ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); +// pclog("Recieve data packet 6!\n"); + ide_irq_raise(ide); +// ide.packetstatus=0xFF; + } + else if (ide->packetstatus==0x80) /*Error callback*/ + { +// pclog("Packet error\n"); + ide->atastat = READY_STAT | ERR_STAT; + ide_irq_raise(ide); + } + return; + } + +abort_cmd: + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide_irq_raise(ide); +} + +/*ATAPI CD-ROM emulation + This mostly seems to work. It is implemented only on Windows at the moment as + I haven't had time to implement any interfaces for it in the generic gui. + It mostly depends on driver files - cdrom-iso.c for ISO image files (in theory + on any platform) and cdrom-ioctl.c for Win32 IOCTL access. There's an ATAPI + interface defined in ide.h. + There are a couple of bugs in the CD audio handling. + */ + +struct +{ + int sensekey,asc,ascq; +} atapi_sense; + +static void atapi_notready(IDE *ide) +{ + /*Medium not present is 02/3A/--*/ + /*cylprecomp is error number*/ + /*SENSE/ASC/ASCQ*/ + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_NOT_READY << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + atapi_sense.sensekey=6; + atapi_sense.asc=0x28; + } else { + atapi_sense.sensekey=2; + atapi_sense.asc = ASC_MEDIUM_NOT_PRESENT; + } + ide->discchanged=0; + ide->packetstatus=0x80; + idecallback[ide->board]=50*IDE_TIME; +} + +void atapi_discchanged() +{ + ext_ide->discchanged=1; + atapi_sense.sensekey=6; + atapi_sense.asc=0x28; +} + +uint8_t atapi_prev; +int toctimes=0; +static void atapicommand(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t *idebufferb = (uint8_t *) ide->buffer; + int c; + int len; + int msf; + int pos=0; + unsigned char temp; +#ifndef RPCEMU_IDE + pclog("New ATAPI command %02X %i\n",idebufferb[0],ins); +#endif +// readflash=1; + msf=idebufferb[1]&2; + ide->cdlen=0; + if (idebufferb[0]!=GPCMD_REQUEST_SENSE) + { + atapi_prev=idebufferb[0]; + atapi_sense.sensekey=0; + atapi_sense.asc=0; + } + switch (idebufferb[0]) + { + case GPCMD_TEST_UNIT_READY: + if (!atapi->ready()) { atapi_notready(ide); return; } +// if (atapi->ready()) +// { + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; +// } +// else +// { +// pclog("Medium not present!\n"); +// } + break; + + case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */ + /*Will return 18 bytes of 0*/ + memset(idebufferb,0,512); +// switch (atapi_prev) +// { +// case GPCMD_TEST_UNIT_READY: + idebufferb[0]=0x80|0x70; + idebufferb[2]=atapi_sense.sensekey; + idebufferb[12]=atapi_sense.asc; + idebufferb[13]=atapi_sense.ascq; +// break; +// +// default: +// fatal("Bad REQUEST_SENSE following command %02X\n",atapi_prev); +// } + ide->packetstatus=3; + ide->cylinder=18; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=18; + break; + + case GPCMD_SET_SPEED: + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_READ_TOC_PMA_ATIP: +// pclog("Read TOC ready? %08X\n",ide); + if (!atapi->ready()) { atapi_notready(ide); return; } + toctimes++; +// if (toctimes==2) output=3; +// pclog("Read TOC %02X\n",idebufferb[9]); + switch (idebufferb[9]>>6) + { + case 0: /*Normal*/ + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc(idebufferb,idebufferb[6],msf,len,0); + break; + case 1: /*Multi session*/ + len=idebufferb[8]+(idebufferb[7]<<8); + atapi->readtoc_session(idebufferb,msf,len); + idebufferb[0]=0; idebufferb[1]=0xA; + break; + default: + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + } + ide->discchanged=0; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus=0x80; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad read TOC format\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X ",idebufferb[c]); + pclog("\n"); + exit(-1);*/ + } +// pclog("ATAPI buffer len %i\n",len); + ide->packetstatus=3; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; + return; + + case GPCMD_READ_CD: + if (!atapi->ready()) { atapi_notready(ide); return; } +// pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); + if (idebufferb[9]!=0x10) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + } + ide->discchanged=0; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus=0x80; + idecallback[ide_board]=50*IDE_TIME; + break; +// pclog("Bad flags bits %02X\n",idebufferb[9]); +// exit(-1); + } +/* if (idebufferb[6] || idebufferb[7] || (idebufferb[8]!=1)) + { + pclog("More than 1 sector!\n"); + exit(-1); + }*/ + ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; +// pclog("Read at %08X %08X\n",ide.cdpos,ide.cdpos*2048); + atapi->readsector(idebufferb,ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen>=0) ide->packetstatus=6; + else ide->packetstatus=3; + ide->cylinder=2048; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=2048; + return; + + case GPCMD_READ_10: + if (!atapi->ready()) { atapi_notready(ide); return; } +// pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); + + ide->cdlen=(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + if (!ide->cdlen) + { +// pclog("All done - callback set\n"); + ide->packetstatus=2; + idecallback[ide_board]=20*IDE_TIME; + break; + } + + atapi->readsector(idebufferb,ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen>=0) ide->packetstatus=6; + else ide->packetstatus=3; + ide->cylinder=2048; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=2048; + return; + + case GPCMD_READ_HEADER: + if (!atapi->ready()) { atapi_notready(ide); return; } + if (msf) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + } + ide->discchanged=0; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus=0x80; + idecallback[ide_board]=50*IDE_TIME; + break; +// pclog("Read Header MSF!\n"); +// exit(-1); + } + for (c=0;c<4;c++) idebufferb[c+4]=idebufferb[c+2]; + idebufferb[0]=1; /*2048 bytes user data*/ + idebufferb[1]=idebufferb[2]=idebufferb[3]=0; + + ide->packetstatus=3; + ide->cylinder=8; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=8; + return; + + case GPCMD_MODE_SENSE_10: +// output=3; +// pclog("Mode sense - ready?\n"); + if (!atapi->ready()) { atapi_notready(ide); return; } + len=(idebufferb[8]|(idebufferb[7]<<8)); + +//pclog("Mode sense %02X %i\n",idebufferb[2],len); + temp=idebufferb[2]; +// switch (idebufferb[2]) +// { +// case GPMODE_ALL_PAGES: +// case GPMODE_CAPABILITIES_PAGE: + for (c=0;c>8; + idebufferb[1]=len&255; + idebufferb[2]=3; /*120mm data CD-ROM*/ +// pclog("ATAPI buffer len %i\n",len); +/* for (c=0;cpacketstatus=3; + ide->cylinder=len; + ide->secount=2; +// ide.atastat = DRQ_STAT; + ide->pos=0; + idecallback[ide_board]=1000*IDE_TIME; + ide->packlen=len; +// pclog("Sending packet\n"); + return; + + case GPCMD_MODE_SELECT_10: +// if (!atapi->ready()) { atapi_notready(); return; } + if (ide->packetstatus==5) + { + ide->atastat = 0; +// pclog("Recieve data packet!\n"); + ide_irq_raise(ide); + ide->packetstatus=0xFF; + ide->pos=0; + // pclog("Length - %02X%02X\n",idebufferb[0],idebufferb[1]); +// pclog("Page %02X length %02X\n",idebufferb[8],idebufferb[9]); + } + else + { + len=(idebufferb[7]<<8)|idebufferb[8]; + ide->packetstatus=4; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=6*IDE_TIME; + ide->packlen=len; +/* pclog("Waiting for ARM to send packet %i\n",len); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X ",idebufferb[c]); + pclog("\n");*/ + } + return; + + case GPCMD_PLAY_AUDIO_12: + if (!atapi->ready()) { atapi_notready(ide); return; } + /*This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it*/ + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; + atapi->playaudio(pos,len,0); + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_PLAY_AUDIO_MSF: + if (!atapi->ready()) { atapi_notready(ide); return; } + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + atapi->playaudio(pos,len,1); + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_READ_SUBCHANNEL: + if (!atapi->ready()) { /*pclog("Read subchannel not ready\n"); */atapi_notready(ide); return; } + temp=idebufferb[2]&0x40; + if (idebufferb[3]!=1) + { +// pclog("Read subchannel check condition %02X\n",idebufferb[3]); + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + } + ide->discchanged=0; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus=0x80; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad read subchannel!\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + dumpregs(); + exit(-1);*/ + } + pos=0; + idebufferb[pos++]=0; + idebufferb[pos++]=0; /*Audio status*/ + idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ + idebufferb[pos++]=1; /*Format code*/ + idebufferb[1]=atapi->getcurrentsubchannel(&idebufferb[5],msf); +// pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); + len=11+5; + if (!temp) len=4; + ide->packetstatus=3; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=1000*IDE_TIME; + ide->packlen=len; + break; + + case GPCMD_START_STOP_UNIT: + if (idebufferb[4]!=2 && idebufferb[4]!=3 && idebufferb[4]) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + } + ide->discchanged=0; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus=0x80; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad start/stop unit command\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + exit(-1);*/ + } + if (!idebufferb[4]) atapi->stop(); + else if (idebufferb[4]==2) atapi->eject(); + else atapi->load(); + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_INQUIRY: + idebufferb[0] = 5; /*CD-ROM*/ + idebufferb[1] = 0x80; /*Removable*/ + idebufferb[2] = 0; + idebufferb[3] = 0x21; + idebufferb[4] = 31; + idebufferb[5] = 0; + idebufferb[6] = 0; + idebufferb[7] = 0; +#ifdef RPCEMU_IDE + ide_padstr8(idebufferb + 8, 8, "RPCemu"); /* Vendor */ + ide_padstr8(idebufferb + 16, 16, "RPCemuCD"); /* Product */ +#else + ide_padstr8(idebufferb + 8, 8, "PCem"); /* Vendor */ + ide_padstr8(idebufferb + 16, 16, "PCemCD"); /* Product */ +#endif + ide_padstr8(idebufferb + 32, 4, "v1.0"); /* Revision */ + + len=36; + ide->packetstatus=3; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; + break; + + case GPCMD_PREVENT_REMOVAL: + if (!atapi->ready()) { atapi_notready(ide); return; } + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_PAUSE_RESUME: + if (!atapi->ready()) { atapi_notready(ide); return; } + if (idebufferb[8]&1) atapi->resume(); + else atapi->pause(); + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_SEEK: + if (!atapi->ready()) { atapi_notready(ide); return; } + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + atapi->seek(pos); + ide->packetstatus=2; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_SEND_DVD_STRUCTURE: + default: + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (ide->discchanged) { + ide->error |= MCR_ERR; + } + ide->discchanged=0; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus=0x80; + idecallback[ide_board]=50*IDE_TIME; + break; + +/* default: + pclog("Bad ATAPI command %02X\n",idebufferb[0]); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + exit(-1);*/ + } +} + +static void callreadcd(IDE *ide) +{ + ide_irq_lower(ide); + if (ide->cdlen<=0) + { +// pclog("All done - callback set\n"); + ide->packetstatus=2; + idecallback[ide->board]=20*IDE_TIME; + return; + } +// pclog("Continue readcd! %i blocks left\n",ide->cdlen); + ide->atastat = BUSY_STAT; + + atapi->readsector((uint8_t *) ide->buffer, ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + ide->packetstatus=6; + ide->cylinder=2048; + ide->secount=2; + ide->pos=0; + idecallback[ide->board]=60*IDE_TIME; + ide->packlen=2048; +} + + + +void ide_write_pri(uint16_t addr, uint8_t val) +{ + writeide(0, addr, val); +} +void ide_write_pri_w(uint16_t addr, uint16_t val) +{ + writeidew(0, val); +} +uint8_t ide_read_pri(uint16_t addr) +{ + return readide(0, addr); +} +uint16_t ide_read_pri_w(uint16_t addr) +{ + return readidew(0); +} + +void ide_write_sec(uint16_t addr, uint8_t val) +{ + writeide(1, addr, val); +} +void ide_write_sec_w(uint16_t addr, uint16_t val) +{ + writeidew(1, val); +} +uint8_t ide_read_sec(uint16_t addr) +{ + return readide(1, addr); +} +uint16_t ide_read_sec_w(uint16_t addr) +{ + return readidew(1); +} + +void ide_init() +{ + io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, NULL, ide_write_pri, ide_write_pri_w, NULL); + io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL); + io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, NULL, ide_write_sec, ide_write_sec_w, NULL); + io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL); +} diff --git a/src/ide.h b/src/ide.h new file mode 100644 index 00000000..a1f47a64 --- /dev/null +++ b/src/ide.h @@ -0,0 +1,42 @@ +#ifndef __IDE__ +#define __IDE__ + +struct IDE; + +extern void writeide(int ide_board, uint16_t addr, uint8_t val); +extern void writeidew(int ide_board, uint16_t val); +extern uint8_t readide(int ide_board, uint16_t addr); +extern uint16_t readidew(int ide_board); +extern void callbackide(int ide_board); +extern void resetide(void); +extern void ide_init(); + +/*ATAPI stuff*/ +typedef struct ATAPI +{ + int (*ready)(void); + int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + void (*readtoc_session)(uint8_t *b, int msf, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); + void (*readsector)(uint8_t *b, int sector); + void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); + void (*seek)(uint32_t pos); + void (*load)(void); + void (*eject)(void); + void (*pause)(void); + void (*resume)(void); + void (*stop)(void); + void (*exit)(void); +} ATAPI; + +extern ATAPI *atapi; + +void atapi_discchanged(); + +extern int ideboard; + +extern int idecallback[2]; + +extern char ide_fn[2][512]; + +#endif //__IDE__ diff --git a/src/io.c b/src/io.c new file mode 100644 index 00000000..14fa12d2 --- /dev/null +++ b/src/io.c @@ -0,0 +1,196 @@ +#include "ibm.h" +#include "ide.h" +#include "video.h" +#include "cpu.h" + +uint8_t (*port_inb[0x10000][2])(uint16_t addr); +uint16_t (*port_inw[0x10000][2])(uint16_t addr); +uint32_t (*port_inl[0x10000][2])(uint16_t addr); + +void (*port_outb[0x10000][2])(uint16_t addr, uint8_t val); +void (*port_outw[0x10000][2])(uint16_t addr, uint16_t val); +void (*port_outl[0x10000][2])(uint16_t addr, uint32_t val); + +void io_init() +{ + int c; + for (c = 0; c < 0x10000; c++) + { + port_inb[c][0] = port_inw[c][0] = port_inl[c][0] = NULL; + port_outb[c][0] = port_outw[c][0] = port_outl[c][0] = NULL; + port_inb[c][1] = port_inw[c][1] = port_inl[c][1] = NULL; + port_outb[c][1] = port_outw[c][1] = port_outl[c][1] = NULL; + } +} + +void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr), + uint16_t (*inw)(uint16_t addr), + uint32_t (*inl)(uint16_t addr), + void (*outb)(uint16_t addr, uint8_t val), + void (*outw)(uint16_t addr, uint16_t val), + void (*outl)(uint16_t addr, uint32_t val)) +{ + int c; + for (c = 0; c < size; c++) + { + if (!port_inb[ base + c][0]) port_inb[ base + c][0] = inb; + else if (!port_inb[ base + c][1]) port_inb[ base + c][1] = inb; + if (!port_inw[ base + c][0]) port_inw[ base + c][0] = inw; + else if (!port_inw[ base + c][1]) port_inw[ base + c][1] = inw; + if (!port_inl[ base + c][0]) port_inl[ base + c][0] = inl; + else if (!port_inl[ base + c][1]) port_inl[ base + c][1] = inl; + if (!port_outb[base + c][0]) port_outb[base + c][0] = outb; + else if (!port_outb[base + c][1]) port_outb[base + c][1] = outb; + if (!port_outw[base + c][0]) port_outw[base + c][0] = outw; + else if (!port_outw[base + c][1]) port_outw[base + c][1] = outw; + if (!port_outl[base + c][0]) port_outl[base + c][0] = outl; + else if (!port_outl[base + c][1]) port_outl[base + c][1] = outl; + } +} + +void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr), + uint16_t (*inw)(uint16_t addr), + uint32_t (*inl)(uint16_t addr), + void (*outb)(uint16_t addr, uint8_t val), + void (*outw)(uint16_t addr, uint16_t val), + void (*outl)(uint16_t addr, uint32_t val)) +{ + int c; + for (c = 0; c < size; c++) + { + if (port_inb[ base + c][0] == inb) + port_inb[ base + c][0] = NULL; + if (port_inb[ base + c][1] == inb) + port_inb[ base + c][1] = NULL; + if (port_inw[ base + c][0] == inw) + port_inw[ base + c][0] = NULL; + if (port_inw[ base + c][1] == inw) + port_inw[ base + c][1] = NULL; + if (port_inl[ base + c][0] == inl) + port_inl[ base + c][0] = NULL; + if (port_inl[ base + c][1] == inl) + port_inl[ base + c][1] = NULL; + if (port_outb[ base + c][0] == outb) + port_outb[ base + c][0] = NULL; + if (port_outb[ base + c][1] == outb) + port_outb[ base + c][1] = NULL; + if (port_outw[ base + c][0] == outw) + port_outw[ base + c][0] = NULL; + if (port_outw[ base + c][1] == outw) + port_outw[ base + c][1] = NULL; + if (port_outl[ base + c][0] == outl) + port_outl[ base + c][0] = NULL; + if (port_outl[ base + c][1] == outl) + port_outl[ base + c][1] = NULL; + } +} + +uint8_t cgamode,cgastat=0,cgacol; +int hsync; +uint8_t lpt2dat; +int sw9; +int t237=0; +uint8_t inb(uint16_t port) +{ + uint8_t temp = 0xff; + int tempi; + if (port_inb[port][0]) + temp &= port_inb[port][0](port); + if (port_inb[port][1]) + temp &= port_inb[port][1](port); + return temp; + + if (port&0x80) sw9=2; +// if ((port&0x3F0)==0x3D0) printf("Video access read %03X %04X:%04X\n",port,cs>>4,pc); +// if (cs<0xF0000 || cs>0x100000) printf("IN %04X %04X(%06X):%08X\n",port,CS,cs,pc); +// /*if (output==3) */printf("IN %04X %04X:%04X\n",port,CS,pc); +// if (port == 0x23) pclog("IN %04X %04X:%08X\n", port, CS, pc); + switch (port) + { + case 0x220: case 0x221: case 0x222: case 0x223: /*Gameblaster*/ + if (sbtype>=SBPRO) return readsb(port); + if (GAMEBLASTER) return readcms(port); + return 0xFF; + } +// printf("Bad IN port %04X %04X:%04X\n",port,cs>>4,pc); + return 0xff; + /*dumpregs(); + exit(-1);*/ +} + +/*uint8_t inb(uint16_t port) +{ + uint8_t temp = _inb(port); +// if (port != 0x61) pclog("IN %04X %02X %04X(%08X):%08X %f %04X %i %i\n", port, temp, CS, cs, pc, pit.c[1], CX, keybsenddelay, GetTickCount()); + return temp; +}*/ + +uint8_t cpu_readport(uint32_t port) { return inb(port); } + +void outb(uint16_t port, uint8_t val) +{ +// /*if (output==3) */printf("OUT %04X %02X %04X(%08X):%08X %i %i\n", port, val, CS, cs, pc, ins, GetTickCount()); + if (port_outb[port][0]) + port_outb[port][0](port, val); + if (port_outb[port][1]) + port_outb[port][1](port, val); + return; + switch (port) + { + case 0x220: case 0x221: case 0x222: case 0x223: /*Gameblaster*/ + if (GAMEBLASTER) writecms(port,val); + return; + } + pclog("OUT %04X %02X %04X:%08X\n",port,val,CS,pc); +} + +uint16_t inw(uint16_t port) +{ + if (port_inw[port][0]) + return port_inw[port][0](port); + if (port_inw[port][1]) + return port_inw[port][1](port); + + return inb(port) | (inb(port + 1) << 8); +} + +void outw(uint16_t port, uint16_t val) +{ +// printf("OUTW %04X %04X %04X:%08X\n",port,val, CS, pc); + if (port_outw[port][0]) + port_outw[port][0](port, val); + if (port_outw[port][1]) + port_outw[port][1](port, val); + + if (port_outw[port][0] || port_outw[port][1]) + return; + + outb(port,val); + outb(port+1,val>>8); +} + +uint32_t inl(uint16_t port) +{ + if (port_inl[port][0]) + return port_inl[port][0](port); + if (port_inl[port][1]) + return port_inl[port][1](port); + + return inw(port) | (inw(port + 2) << 16); +} + +void outl(uint16_t port, uint32_t val) +{ + if (port_outl[port][0]) + port_outl[port][0](port, val); + if (port_outl[port][1]) + port_outl[port][1](port, val); + + if (port_outl[port][0] || port_outl[port][1]) + return; + + outw(port, val); + outw(port + 2, val >> 16); +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 00000000..3697cd51 --- /dev/null +++ b/src/io.h @@ -0,0 +1,17 @@ +void io_init(); + +void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr), + uint16_t (*inw)(uint16_t addr), + uint32_t (*inl)(uint16_t addr), + void (*outb)(uint16_t addr, uint8_t val), + void (*outw)(uint16_t addr, uint16_t val), + void (*outl)(uint16_t addr, uint32_t val)); + +void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr), + uint16_t (*inw)(uint16_t addr), + uint32_t (*inl)(uint16_t addr), + void (*outb)(uint16_t addr, uint8_t val), + void (*outw)(uint16_t addr, uint16_t val), + void (*outl)(uint16_t addr, uint32_t val)); diff --git a/src/jim.c b/src/jim.c new file mode 100644 index 00000000..43a1b60d --- /dev/null +++ b/src/jim.c @@ -0,0 +1,78 @@ +#include +#include +#include "ibm.h" + +uint8_t europcdat[16]; +struct +{ + uint8_t dat[16]; + int stat; + int addr; +} europc_rtc; + +void writejim(uint16_t addr, uint8_t val) +{ + if ((addr&0xFF0)==0x250) europcdat[addr&0xF]=val; + switch (addr) + { + case 0x25A: +// printf("Write RTC stat %i val %02X\n",europc_rtc.stat,val); + switch (europc_rtc.stat) + { + case 0: + europc_rtc.addr=val&0xF; + europc_rtc.stat++; +// printf("RTC addr now %02X - contents %02X\n",val&0xF,europc_rtc.dat[europc_rtc.addr]); + break; + case 1: + europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF)|(val<<4); + europc_rtc.stat++; + break; + case 2: + europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF0)|(val&0xF); + europc_rtc.stat=0; + break; + } + break; + } +// printf("Write JIM %04X %02X\n",addr,val); +} + +uint8_t readjim(uint16_t addr) +{ +// printf("Read JIM %04X\n",addr); + switch (addr) + { + case 0x250: case 0x251: case 0x252: case 0x253: return 0; + case 0x254: case 0x255: case 0x256: case 0x257: return europcdat[addr&0xF]; + case 0x25A: + if (europc_rtc.stat==1) + { + europc_rtc.stat=2; + return europc_rtc.dat[europc_rtc.addr]>>4; + } + if (europc_rtc.stat==2) + { + europc_rtc.stat=0; + return europc_rtc.dat[europc_rtc.addr]&0xF; + } + return 0; + } + return 0; +} + +void jim_init() +{ + uint8_t viddat; + memset(europc_rtc.dat,0,16); + europc_rtc.dat[0xF]=1; + europc_rtc.dat[3]=1; + europc_rtc.dat[4]=1; + europc_rtc.dat[5]=0x88; + if (gfxcard==GFX_CGA) viddat=0x12; + else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES) viddat=3; + else viddat=0x10; + europc_rtc.dat[0xB]=viddat; + europc_rtc.dat[0xD]=viddat; /*Checksum*/ + io_sethandler(0x250, 0x10, readjim, NULL, NULL, writejim, NULL, NULL); +} diff --git a/src/jim.h b/src/jim.h new file mode 100644 index 00000000..ed3759f1 --- /dev/null +++ b/src/jim.h @@ -0,0 +1 @@ +void jim_init(); diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 00000000..cb830b00 --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,280 @@ +#include "ibm.h" +#include "plat-keyboard.h" +#include "keyboard.h" + +int keybsendcallback = 0; + +typedef struct +{ + int scancodes_make[8]; + int scancodes_break[8]; +} scancode; + +static scancode scancode_set1[256] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} }, + { {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} }, + { {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} }, + { {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} }, + { {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} }, + { {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} }, + { {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} }, + { {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} }, + { {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} }, + { {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} }, + { {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} }, + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x2a, -1}, {0xe0, 0x8a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xb6, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/ + { {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0x47, -1}, {0xe0, 0xc7, -1} }, /*c4*/ + { {0xe0, 0x48, -1}, {0xe0, 0xc8, -1} }, { {0xe0, 0x49, -1}, {0xe0, 0xc9, -1} }, { {-1}, {-1} }, { {0xe0, 0x4b, -1}, {0xe0, 0xcb, -1} }, /*c8*/ + { {-1}, {-1} }, { {0xe0, 0x4d, -1}, {0xe0, 0xcd, -1} }, { {-1}, {-1} }, { {0xe0, 0x4f, -1}, {0xe0, 0xcf, -1} }, /*cc*/ + { {0xe0, 0x50, -1}, {0xe0, 0xd0, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xd1, -1} }, { {0xe0, 0x52, -1}, {0xe0, 0xd2, -1} }, { {0xe0, 0x53, -1}, {0xe0, 0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, -1}, {-1} } /*fc*/ +}; + +/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ +static scancode scancode_xt[256] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/ + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0x8a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/ + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*c8*/ + { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/ + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/ +}; + +/*Tandy keyboard has slightly different scancodes to XT*/ +static scancode scancode_tandy[256] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/ + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x2a, -1}, {0x8a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/ + { {0x29, -1}, {0xa9, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x2b, -1}, {0xab, -1} }, /*c8*/ + { {-1}, {-1} }, { {0x4e, -1}, {0xce, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/ + { {0x4a, -1}, {0xca, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/ +}; +static int oldkey[256]; +static int keydelay[256]; + +void (*keyboard_send)(uint8_t val); +void (*keyboard_poll)(); +int keyboard_scan = 1; + +void keyboard_process() +{ + int c; + int d; + scancode *scancodes = (AT) ? scancode_set1 : scancode_xt; + if (!keyboard_scan) return; + if (TANDY) scancodes = scancode_tandy; + + for (c = 0; c < 256; c++) + { + if (key[c]) keydelay[c]++; + else keydelay[c] = 0; + } + + for (c = 0; c < 256; c++) + { + if (key[c] != oldkey[c]) + { + oldkey[c] = key[c]; + if ( key[c] && scancodes[c].scancodes_make[0] == -1) + continue; + if (!key[c] && scancodes[c].scancodes_break[0] == -1) + continue; + pclog("Key %02X start\n", c); + d = 0; + if (key[c]) + { + while (scancodes[c].scancodes_make[d] != -1) + keyboard_send(scancodes[c].scancodes_make[d++]); + } + else + { + while (scancodes[c].scancodes_break[d] != -1) + keyboard_send(scancodes[c].scancodes_break[d++]); + } + } + } + + for (c = 0; c < 256; c++) + { + if (keydelay[c] >= 30) + { + keydelay[c] -= 10; + if (scancode_set1[c].scancodes_make[0] == -1) + continue; + + d = 0; + + while (scancode_set1[c].scancodes_make[d] != -1) + keyboard_send(scancode_set1[c].scancodes_make[d++]); + } + } +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 00000000..8a0ec9ca --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,3 @@ +extern void (*keyboard_send)(uint8_t val); +extern void (*keyboard_poll)(); +extern int keyboard_scan; diff --git a/src/keyboard_amstrad.c b/src/keyboard_amstrad.c new file mode 100644 index 00000000..4bdea887 --- /dev/null +++ b/src/keyboard_amstrad.c @@ -0,0 +1,168 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "sound.h" + +#include "keyboard.h" +#include "keyboard_amstrad.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + + uint8_t pa; + uint8_t pb; +} keyboard_amstrad; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t amstrad_systemstat_1, amstrad_systemstat_2; + +void keyboard_amstrad_poll() +{ + if (keyboard_amstrad.wantirq) + { + keyboard_amstrad.wantirq = 0; + picint(2); + pclog("keyboard_amstrad : take IRQ\n"); + } + if (key_queue_start != key_queue_end) + { + keyboard_amstrad.pa = key_queue[key_queue_start]; + pclog("Reading %02X from the key queue at %i\n", keyboard_amstrad.pa, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_amstrad.wantirq = 1; + } +} + +void keyboard_amstrad_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + pclog("keyboard_amstrad : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_amstrad_write(uint16_t port, uint8_t val) +{ + pclog("keyboard_amstrad : write %04X %02X %02X\n", port, val, keyboard_amstrad.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x61: + pclog("keyboard_amstrad : pb write %02X %02X %i %02X %i\n", val, keyboard_amstrad.pb, !(keyboard_amstrad.pb & 0x40), keyboard_amstrad.pb & 0x40, (val & 0x40)); + if (!(keyboard_amstrad.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ + { + pclog("keyboard_amstrad : reset keyboard\n"); + keyboard_amstrad_adddata(0xaa); + } + keyboard_amstrad.pb = val; + ppi.pb = val; + +/* if (AMSTRADIO) + keyboard_amstrad.s2 = val & 4; + else + keyboard_amstrad.s2 = val & 8;*/ + gated = ((val & 3) == 3); + if (gated) + wasgated = 1; + + if (val & 0x80) + keyboard_amstrad.pa = 0; + break; + + case 0x63: + break; + + case 0x64: + amstrad_systemstat_1 = val; + break; + + case 0x65: + amstrad_systemstat_2 = val; + break; + + default: + pclog("\nBad XT keyboard write %04X %02X\n", port, val); +// dumpregs(); +// exit(-1); + } +} + +uint8_t keyboard_amstrad_read(uint16_t port) +{ + uint8_t temp; +// pclog("keyboard_amstrad : read %04X ", port); + switch (port) + { + case 0x60: + if (keyboard_amstrad.pb & 0x80) + { + temp = (amstrad_systemstat_1 | 0xd) & 0x7f; + } + else + { + temp = keyboard_amstrad.pa; + if (key_queue_start == key_queue_end) + { + keyboard_amstrad.wantirq = 0; + } + else + { + keyboard_amstrad.pa = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_amstrad.wantirq = 1; + } + } + break; + + case 0x61: + temp = keyboard_amstrad.pb; + break; + + case 0x62: + if (keyboard_amstrad.pb & 0x04) + temp = amstrad_systemstat_2 & 0xf; + else + temp = amstrad_systemstat_2 >> 4; + temp |= (ppispeakon ? 0x20 : 0); + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); +// dumpregs(); +// exit(-1); + } +// pclog("%02X %04X:%04X\n", temp, CS, pc); + return temp; +} + +void keyboard_amstrad_reset() +{ + keyboard_amstrad.wantirq = 0; + + keyboard_scan = 1; +} + +void keyboard_amstrad_init() +{ + //return; + pclog("keyboard_amstrad_init\n"); + io_sethandler(0x0060, 0x0006, keyboard_amstrad_read, NULL, NULL, keyboard_amstrad_write, NULL, NULL); + keyboard_amstrad_reset(); + keyboard_send = keyboard_amstrad_adddata; + keyboard_poll = keyboard_amstrad_poll; +} diff --git a/src/keyboard_amstrad.h b/src/keyboard_amstrad.h new file mode 100644 index 00000000..76dd075d --- /dev/null +++ b/src/keyboard_amstrad.h @@ -0,0 +1,3 @@ +void keyboard_amstrad_init(); +void keyboard_amstrad_reset(); +void keyboard_amstrad_poll(); diff --git a/src/keyboard_at.c b/src/keyboard_at.c new file mode 100644 index 00000000..02dfd78b --- /dev/null +++ b/src/keyboard_at.c @@ -0,0 +1,436 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "sound.h" + +#include "keyboard.h" +#include "keyboard_at.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int initialised; + int want60; + int wantirq, wantirq12; + uint8_t command; + uint8_t status; + uint8_t mem[0x20]; + uint8_t out; + + uint8_t input_port; + uint8_t output_port; + + uint8_t key_command; + int key_wantdata; +} keyboard_at; + +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t mouse_queue[16]; +int mouse_queue_start = 0, mouse_queue_end = 0; + +void keyboard_at_poll() +{ + if (keyboard_at.wantirq) + { + keyboard_at.wantirq = 0; + picint(2); + pclog("keyboard_at : take IRQ\n"); + } + else if (keyboard_at.wantirq12) + { + keyboard_at.wantirq12 = 0; + picint(0x1000); + pclog("keyboard_at : take IRQ 12\n"); + } + if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) && + mouse_queue_start != mouse_queue_end) + { + pclog("Reading %02X from the mouse queue at %i\n", keyboard_at.out, key_queue_start); + keyboard_at.out = mouse_queue[mouse_queue_start]; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + keyboard_at.status |= STAT_OFULL | STAT_MFULL; + keyboard_at.status &= ~STAT_IFULL; + if (keyboard_at.mem[0] & 0x02) + keyboard_at.wantirq12 = 1; + } + else if (!(keyboard_at.status & STAT_OFULL) && !(keyboard_at.mem[0] & 0x10) && + key_queue_start != key_queue_end) + { + pclog("Reading %02X from the key queue at %i\n", keyboard_at.out, key_queue_start); + keyboard_at.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + if (keyboard_at.mem[0] & 0x01) + keyboard_at.wantirq = 1; + } + else if (!(keyboard_at.status & STAT_OFULL) && + key_ctrl_queue_start != key_ctrl_queue_end) + { + pclog("Reading %02X from the key ctrl_queue at %i\n", keyboard_at.out, key_ctrl_queue_start); + keyboard_at.out = key_ctrl_queue[key_ctrl_queue_start]; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + if (keyboard_at.mem[0] & 0x01) + keyboard_at.wantirq = 1; + } +} + +void keyboard_at_adddata(uint8_t val) +{ +// if (keyboard_at.status & STAT_OFULL) +// { + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + pclog("keyboard_at : %02X added to queue\n", val); +/* return; + } + keyboard_at.out = val; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + if (keyboard_at.mem[0] & 0x01) + keyboard_at.wantirq = 1; + pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/ +} + +void keyboard_at_adddata_keyboard(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + pclog("keyboard_at : %02X added to key queue\n", val); + return; +} + +void keyboard_at_adddata_mouse(uint8_t val) +{ + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; + pclog("keyboard_at : %02X added to mouse queue\n", val); + return; +} + +void keyboard_at_write(uint16_t port, uint8_t val) +{ + pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + if (keyboard_at.want60) + { + /*Write to controller*/ + keyboard_at.want60 = 0; + switch (keyboard_at.command) + { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + 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: + keyboard_at.mem[keyboard_at.command & 0x1f] = val; + if (keyboard_at.command == 0x60) + { + if ((val & 1) && (keyboard_at.status & STAT_OFULL)) + keyboard_at.wantirq = 1; + if (!(val & 1) && keyboard_at.wantirq) + keyboard_at.wantirq = 0; + } + break; + + case 0xcb: /*AMI - set keyboard mode*/ + break; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + break; + + case 0xd1: /*Write output port*/ + pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc); + if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/ + { + mem_a20_key = val & 0x02; + mem_a20_recalc(); +// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); + flushmmucache(); + } + keyboard_at.output_port = val; + break; + + case 0xd3: /*Write to mouse output buffer*/ + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /*Write to mouse*/ + if (mouse_write) + mouse_write(val); + break; + + default: + pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command); +// dumpregs(); +// exit(-1); + } + } + else + { + /*Write to keyboard*/ + keyboard_at.mem[0] &= ~0x10; + if (keyboard_at.key_wantdata) + { + keyboard_at.key_wantdata = 0; + switch (keyboard_at.key_command) + { + case 0xed: /*Set/reset LEDs*/ + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf3: /*Set typematic rate/delay*/ + keyboard_at_adddata_keyboard(0xfa); + break; + + default: + pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command); +// dumpregs(); +// exit(-1); + } + } + else + { + keyboard_at.key_command = val; + switch (val) + { + case 0x05: /*??? - sent by NT 4.0*/ + keyboard_at_adddata_keyboard(0xfe); + break; + + case 0xed: /*Set/reset LEDs*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf2: /*Read ID*/ + keyboard_at_adddata_keyboard(0xfa); + keyboard_at_adddata_keyboard(0xab); + keyboard_at_adddata_keyboard(0x41); + break; + + case 0xf3: /*Set typematic rate/delay*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf4: /*Enable keyboard*/ + keyboard_scan = 1; + break; + + case 0xff: /*Reset*/ + keyboard_at_adddata_keyboard(0xfa); + keyboard_at_adddata_keyboard(0xaa); + break; + + default: + pclog("Bad AT keyboard command %02X\n", val); + keyboard_at_adddata_keyboard(0xfe); +// dumpregs(); +// exit(-1); + } + } + } + break; + + case 0x61: + ppi.pb=val; + gated=((val&3)==3); + if (gated) wasgated=1; + break; + + case 0x64: + keyboard_at.want60 = 0; + keyboard_at.command = val; + /*New controller command*/ + switch (val) + { + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + keyboard_at_adddata(keyboard_at.mem[val & 0x1f]); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + 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: + keyboard_at.want60 = 1; + break; + + case 0xa1: /*AMI - get controlled version*/ + break; + + case 0xa7: /*Disable mouse port*/ + break; + + case 0xa9: /*Test mouse port*/ + keyboard_at_adddata(0x00); /*no error*/ + break; + + case 0xaa: /*Self-test*/ + if (!keyboard_at.initialised) + { + keyboard_at.initialised = 1; + key_ctrl_queue_start = key_ctrl_queue_end = 0; + keyboard_at.status &= ~STAT_OFULL; + } + keyboard_at.status |= STAT_SYSFLAG; + keyboard_at.mem[0] |= 0x04; + keyboard_at_adddata(0x55); + break; + + case 0xab: /*Interface test*/ + keyboard_at_adddata(0x00); /*no error*/ + break; + + case 0xad: /*Disable keyboard*/ + keyboard_at.mem[0] |= 0x10; + break; + + case 0xae: /*Enable keyboard*/ + keyboard_at.mem[0] &= ~0x10; + break; + + case 0xc0: /*Read input port*/ + keyboard_at_adddata(keyboard_at.input_port); + keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc); + break; + + case 0xc9: /*AMI - block P22 and P23 ??? */ + break; + + case 0xca: /*AMI - read keyboard mode*/ + keyboard_at_adddata(0x00); /*ISA mode*/ + break; + + case 0xcb: /*AMI - set keyboard mode*/ + keyboard_at.want60 = 1; + break; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + keyboard_at.want60 = 1; + break; + + case 0xd0: /*Read output port*/ + keyboard_at_adddata(keyboard_at.output_port); + break; + + case 0xd1: /*Write output port*/ + keyboard_at.want60 = 1; + break; + + case 0xd3: /*Write mouse output buffer*/ + keyboard_at.want60 = 1; + break; + + case 0xd4: /*Write to mouse*/ + keyboard_at.want60 = 1; + break; + + case 0xe0: /*Read test inputs*/ + keyboard_at_adddata(0x00); + break; + + case 0xef: /*??? - sent by AMI486*/ + break; + + case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/ + softresetx86(); /*Pulse reset!*/ + break; + + case 0xff: /*Pulse output port - but no pins selected - sent by MegaPC BIOS*/ + break; + + default: + pclog("Bad AT keyboard controller command %02X\n", val); +// dumpregs(); +// exit(-1); + } + } +} + +uint8_t keyboard_at_read(uint16_t port) +{ + uint8_t temp = 0xff; + cycles -= 4; +// if (port != 0x61) pclog("keyboard_at : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_at.out; + keyboard_at.status &= ~(STAT_OFULL | STAT_MFULL); + keyboard_at.wantirq = keyboard_at.wantirq12 = 0; + break; + + case 0x61: + if (ppispeakon) return (ppi.pb&~0xC0)|0x20; + return ppi.pb&~0xC0; + break; + + case 0x64: + temp = keyboard_at.status; + keyboard_at.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); + break; + } +// if (port != 0x61) pclog("%02X %08X\n", temp, rammask); + return temp; +} + +void keyboard_at_reset() +{ + keyboard_at.initialised = 0; + keyboard_at.status = STAT_LOCK | STAT_CD; + keyboard_at.mem[0] = 0x11; + keyboard_at.wantirq = 0; + keyboard_at.output_port = 0; + keyboard_at.input_port = 0xb0; + + keyboard_at.key_wantdata = 0; + + keyboard_scan = 1; +} + +void keyboard_at_init() +{ + //return; + io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL); + keyboard_at_reset(); + keyboard_send = keyboard_at_adddata_keyboard; + keyboard_poll = keyboard_at_poll; + mouse_write = NULL; +} diff --git a/src/keyboard_at.h b/src/keyboard_at.h new file mode 100644 index 00000000..9bd98ac8 --- /dev/null +++ b/src/keyboard_at.h @@ -0,0 +1,6 @@ +void keyboard_at_init(); +void keyboard_at_reset(); +void keyboard_at_poll(); + +void (*mouse_write)(uint8_t val); +extern int mouse_queue_start, mouse_queue_end; diff --git a/src/keyboard_olim24.c b/src/keyboard_olim24.c new file mode 100644 index 00000000..10724025 --- /dev/null +++ b/src/keyboard_olim24.c @@ -0,0 +1,285 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "mouse.h" + +#include "keyboard.h" +#include "keyboard_olim24.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + uint8_t command; + uint8_t status; + uint8_t out; + + uint8_t output_port; + + int param, param_total; + uint8_t params[16]; + + int mouse_mode; +} keyboard_olim24; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t mouse_scancodes[7]; + +void keyboard_olim24_poll() +{ + //pclog("poll %i\n", keyboard_olim24.wantirq); + if (keyboard_olim24.wantirq) + { + keyboard_olim24.wantirq = 0; + picint(2); + pclog("keyboard_olim24 : take IRQ\n"); + } + if (!(keyboard_olim24.status & STAT_OFULL) && key_queue_start != key_queue_end) + { + pclog("Reading %02X from the key queue at %i\n", keyboard_olim24.out, key_queue_start); + keyboard_olim24.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_olim24.status |= STAT_OFULL; + keyboard_olim24.status &= ~STAT_IFULL; + keyboard_olim24.wantirq = 1; + } +} + +void keyboard_olim24_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + pclog("keyboard_olim24 : %02X added to key queue %02X\n", val, keyboard_olim24.status); + return; +} + +void keyboard_olim24_write(uint16_t port, uint8_t val) +{ + pclog("keyboard_olim24 : write %04X %02X\n", port, val); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + if (keyboard_olim24.param != keyboard_olim24.param_total) + { + keyboard_olim24.params[keyboard_olim24.param++] = val; + if (keyboard_olim24.param == keyboard_olim24.param_total) + { + switch (keyboard_olim24.command) + { + case 0x11: + keyboard_olim24.mouse_mode = 0; + mouse_scancodes[0] = keyboard_olim24.params[0]; + mouse_scancodes[1] = keyboard_olim24.params[1]; + mouse_scancodes[2] = keyboard_olim24.params[2]; + mouse_scancodes[3] = keyboard_olim24.params[3]; + mouse_scancodes[4] = keyboard_olim24.params[4]; + mouse_scancodes[5] = keyboard_olim24.params[5]; + mouse_scancodes[6] = keyboard_olim24.params[6]; + break; + + case 0x12: + keyboard_olim24.mouse_mode = 1; + mouse_scancodes[0] = keyboard_olim24.params[0]; + mouse_scancodes[1] = keyboard_olim24.params[1]; + mouse_scancodes[2] = keyboard_olim24.params[2]; + break; + + default: + pclog("Bad keyboard command complete %02X\n", keyboard_olim24.command); +// dumpregs(); +// exit(-1); + } + } + } + else + { + keyboard_olim24.command = val; + switch (val) + { + case 0x01: /*Self-test*/ + break; + + case 0x05: /*Read ID*/ + keyboard_olim24_adddata(0x00); + break; + + case 0x11: + keyboard_olim24.param = 0; + keyboard_olim24.param_total = 9; + break; + + case 0x12: + keyboard_olim24.param = 0; + keyboard_olim24.param_total = 4; + break; + + default: + pclog("Bad keyboard command %02X\n", val); +// dumpregs(); +// exit(-1); + } + } + + break; + } +} + +uint8_t keyboard_olim24_read(uint16_t port) +{ + uint8_t temp; +// pclog("keyboard_olim24 : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_olim24.out; + if (key_queue_start == key_queue_end) + { + keyboard_olim24.status &= ~STAT_OFULL; + keyboard_olim24.wantirq = 0; + } + else + { + keyboard_olim24.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_olim24.status |= STAT_OFULL; + keyboard_olim24.status &= ~STAT_IFULL; + keyboard_olim24.wantirq = 1; + } + break; + + case 0x64: + temp = keyboard_olim24.status; + keyboard_olim24.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); + break; + + default: + pclog("\nBad olim24 keyboard read %04X\n", port); +// dumpregs(); +// exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_olim24_reset() +{ + keyboard_olim24.status = STAT_LOCK | STAT_CD; + keyboard_olim24.wantirq = 0; + + keyboard_scan = 1; + + keyboard_olim24.param = keyboard_olim24.param_total = 0; + + keyboard_olim24.mouse_mode = 0; + mouse_scancodes[0] = 0x1c; + mouse_scancodes[1] = 0x53; + mouse_scancodes[2] = 0x01; + mouse_scancodes[3] = 0x4b; + mouse_scancodes[4] = 0x4d; + mouse_scancodes[5] = 0x48; + mouse_scancodes[6] = 0x50; +} + +static int mouse_x = 0, mouse_y = 0, mouse_b = 0; +void mouse_olim24_poll(int x, int y, int b) +{ + mouse_x += x; + mouse_y += y; + + pclog("mouse_poll - %i, %i %i, %i\n", x, y, mouse_x, mouse_y); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 1) && !(mouse_b & 1)) + keyboard_olim24_adddata(mouse_scancodes[0]); + if (!(b & 1) && (mouse_b & 1)) + keyboard_olim24_adddata(mouse_scancodes[0] | 0x80); + mouse_b = (mouse_b & ~1) | (b & 1); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 2) && !(mouse_b & 2)) + keyboard_olim24_adddata(mouse_scancodes[2]); + if (!(b & 2) && (mouse_b & 2)) + keyboard_olim24_adddata(mouse_scancodes[2] | 0x80); + mouse_b = (mouse_b & ~2) | (b & 2); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 4) && !(mouse_b & 4)) + keyboard_olim24_adddata(mouse_scancodes[1]); + if (!(b & 4) && (mouse_b & 4)) + keyboard_olim24_adddata(mouse_scancodes[1] | 0x80); + mouse_b = (mouse_b & ~4) | (b & 4); + + if (keyboard_olim24.mouse_mode) + { + if (((key_queue_end - key_queue_start) & 0xf) > 12) return; + if (!mouse_x && !mouse_y) return; + + mouse_y = -mouse_y; + + if (mouse_x < -127) mouse_x = -127; + if (mouse_x > 127) mouse_x = 127; + if (mouse_x < -127) mouse_x = 0x80 | ((-mouse_x) & 0x7f); + + if (mouse_y < -127) mouse_y = -127; + if (mouse_y > 127) mouse_y = 127; + if (mouse_y < -127) mouse_y = 0x80 | ((-mouse_y) & 0x7f); + + keyboard_olim24_adddata(0xfe); + keyboard_olim24_adddata(mouse_x); + keyboard_olim24_adddata(mouse_y); + + mouse_x = mouse_y = 0; + } + else + { + while (mouse_x < -4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_x+=4; + keyboard_olim24_adddata(mouse_scancodes[3]); + } + while (mouse_x > 4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_x-=4; + keyboard_olim24_adddata(mouse_scancodes[4]); + } + while (mouse_y < -4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_y+=4; + keyboard_olim24_adddata(mouse_scancodes[5]); + } + while (mouse_y > 4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_y-=4; + keyboard_olim24_adddata(mouse_scancodes[6]); + } + } +} + +void keyboard_olim24_init() +{ + //return; + io_sethandler(0x0060, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL); + io_sethandler(0x0064, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL); + keyboard_olim24_reset(); + keyboard_send = keyboard_olim24_adddata; + keyboard_poll = keyboard_olim24_poll; + mouse_poll = mouse_olim24_poll; +} diff --git a/src/keyboard_olim24.h b/src/keyboard_olim24.h new file mode 100644 index 00000000..5400713f --- /dev/null +++ b/src/keyboard_olim24.h @@ -0,0 +1,3 @@ +void keyboard_olim24_init(); +void keyboard_olim24_reset(); +void keyboard_olim24_poll(); diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c new file mode 100644 index 00000000..1cc04a9f --- /dev/null +++ b/src/keyboard_xt.c @@ -0,0 +1,163 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "sound.h" + +#include "keyboard.h" +#include "keyboard_xt.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + + uint8_t pa; + uint8_t pb; +} keyboard_xt; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +void keyboard_xt_poll() +{ + if (keyboard_xt.wantirq) + { + keyboard_xt.wantirq = 0; + picint(2); + pclog("keyboard_xt : take IRQ\n"); + } + if (key_queue_start != key_queue_end) + { + keyboard_xt.pa = key_queue[key_queue_start]; + pclog("Reading %02X from the key queue at %i\n", keyboard_xt.pa, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_xt.wantirq = 1; + } +} + +void keyboard_xt_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + pclog("keyboard_xt : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_xt_write(uint16_t port, uint8_t val) +{ + pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x61: + pclog("keyboard_xt : pb write %02X %02X %i %02X %i\n", val, keyboard_xt.pb, !(keyboard_xt.pb & 0x40), keyboard_xt.pb & 0x40, (val & 0x40)); + if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ + { + pclog("keyboard_xt : reset keyboard\n"); + keyboard_xt_adddata(0xaa); + } + keyboard_xt.pb = val; + ppi.pb = val; +/* if (AMSTRADIO) + keyboard_xt.s2 = val & 4; + else + keyboard_xt.s2 = val & 8;*/ + gated = ((val & 3) == 3); + if (gated) + wasgated = 1; + + if (val & 0x80) + { + keyboard_xt.pa = 0; + picintc(2); + } + break; + } +} + +uint8_t keyboard_xt_read(uint16_t port) +{ + uint8_t temp; +// pclog("keyboard_xt : read %04X ", port); + switch (port) + { + case 0x60: + if (keyboard_xt.pb & 0x80) + { + if (VGA) + temp = 0x4D; + else if (MDA) + temp = 0x7D; + else + temp = 0x6D; + } + else + { + temp = keyboard_xt.pa; + if (key_queue_start == key_queue_end) + { + keyboard_xt.wantirq = 0; + } + else + { + keyboard_xt.pa = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_xt.wantirq = 1; + } + } + break; + + case 0x61: + temp = keyboard_xt.pb; + break; + + case 0x62: + if (keyboard_xt.pb & 0x08) + { + if (VGA) + temp = 4; + else if (MDA) + temp = 7; + else + temp = 6; + } + else + temp = 0xD; + temp |= (ppispeakon ? 0x20 : 0); + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); + //dumpregs(); + //exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_xt_reset() +{ + keyboard_xt.wantirq = 0; + + keyboard_scan = 1; +} + +void keyboard_xt_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL); + keyboard_xt_reset(); + keyboard_send = keyboard_xt_adddata; + keyboard_poll = keyboard_xt_poll; +} diff --git a/src/keyboard_xt.h b/src/keyboard_xt.h new file mode 100644 index 00000000..5da623a7 --- /dev/null +++ b/src/keyboard_xt.h @@ -0,0 +1,3 @@ +void keyboard_xt_init(); +void keyboard_xt_reset(); +void keyboard_xt_poll(); diff --git a/src/lpt.c b/src/lpt.c new file mode 100644 index 00000000..dbbe1a55 --- /dev/null +++ b/src/lpt.c @@ -0,0 +1,66 @@ +#include "ibm.h" +#include "io.h" + +#include "lpt.h" + +static uint8_t lpt1_dat, lpt2_dat; +void lpt1_write(uint16_t port, uint8_t val) +{ + switch (port & 3) + { + case 0: + writedac(val); + lpt1_dat = val; + break; + case 2: + writedacctrl(val); + break; + } +} +uint8_t lpt1_read(uint16_t port) +{ + switch (port & 3) + { + case 0: + return lpt1_dat; + case 1: + return readdacfifo(); + } + return 0xff; +} + +void lpt2_write(uint16_t port, uint8_t val) +{ + switch (port & 3) + { + case 0: + writedac(val); + lpt2_dat = val; + break; + case 2: + writedacctrl(val); + break; + } +} +uint8_t lpt2_read(uint16_t port) +{ + switch (port & 3) + { + case 0: + return lpt2_dat; + case 1: + return readdacfifo(); + } + return 0xff; +} + +void lpt_init() +{ + io_sethandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL); + io_sethandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL); +} + +void lpt2_remove() +{ + io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL); +} diff --git a/src/lpt.h b/src/lpt.h new file mode 100644 index 00000000..ad690bda --- /dev/null +++ b/src/lpt.h @@ -0,0 +1,2 @@ +void lpt_init(); +void lpt2_remove(); diff --git a/src/mame/fmopl.c b/src/mame/fmopl.c new file mode 100644 index 00000000..6c52e418 --- /dev/null +++ b/src/mame/fmopl.c @@ -0,0 +1,2613 @@ +/* +** +** File: fmopl.c - software implementation of FM sound generator +** types OPL and OPL2 +** +** Copyright Jarek Burczynski (bujar at mame dot net) +** Copyright Tatsuyuki Satoh , MultiArcadeMachineEmulator development +** +** Version 0.72 +** + +Revision History: + +04-08-2003 Jarek Burczynski: + - removed BFRDY hack. BFRDY is busy flag, and it should be 0 only when the chip + handles memory read/write or during the adpcm synthesis when the chip + requests another byte of ADPCM data. + +24-07-2003 Jarek Burczynski: + - added a small hack for Y8950 status BFRDY flag (bit 3 should be set after + some (unknown) delay). Right now it's always set. + +14-06-2003 Jarek Burczynski: + - implemented all of the status register flags in Y8950 emulation + - renamed y8950_set_delta_t_memory() parameters from _rom_ to _mem_ since + they can be either RAM or ROM + +08-10-2002 Jarek Burczynski (thanks to Dox for the YM3526 chip) + - corrected ym3526_read() to always set bit 2 and bit 1 + to HIGH state - identical to ym3812_read (verified on real YM3526) + +04-28-2002 Jarek Burczynski: + - binary exact Envelope Generator (verified on real YM3812); + compared to YM2151: the EG clock is equal to internal_clock, + rates are 2 times slower and volume resolution is one bit less + - modified interface functions (they no longer return pointer - + that's internal to the emulator now): + - new wrapper functions for OPLCreate: ym3526_init(), ym3812_init() and y8950_init() + - corrected 'off by one' error in feedback calculations (when feedback is off) + - enabled waveform usage (credit goes to Vlad Romascanu and zazzal22) + - speeded up noise generator calculations (Nicola Salmoria) + +03-24-2002 Jarek Burczynski (thanks to Dox for the YM3812 chip) + Complete rewrite (all verified on real YM3812): + - corrected sin_tab and tl_tab data + - corrected operator output calculations + - corrected waveform_select_enable register; + simply: ignore all writes to waveform_select register when + waveform_select_enable == 0 and do not change the waveform previously selected. + - corrected KSR handling + - corrected Envelope Generator: attack shape, Sustain mode and + Percussive/Non-percussive modes handling + - Envelope Generator rates are two times slower now + - LFO amplitude (tremolo) and phase modulation (vibrato) + - rhythm sounds phase generation + - white noise generator (big thanks to Olivier Galibert for mentioning Berlekamp-Massey algorithm) + - corrected key on/off handling (the 'key' signal is ORed from three sources: FM, rhythm and CSM) + - funky details (like ignoring output of operator 1 in BD rhythm sound when connect == 1) + +12-28-2001 Acho A. Tang + - reflected Delta-T EOS status on Y8950 status port. + - fixed subscription range of attack/decay tables + + + To do: + add delay before key off in CSM mode (see CSMKeyControll) + verify volume of the FM part on the Y8950 +*/ + +#include +#include +#include +#include +#include +//#include "emu.h" +//#include "ymdeltat.h" +#include "fmopl.h" + + + +/* output final shift */ +#if (OPL_SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<=0) + { + if (value < 0x0200) + return (value & ~0); + if (value < 0x0400) + return (value & ~1); + if (value < 0x0800) + return (value & ~3); + if (value < 0x1000) + return (value & ~7); + if (value < 0x2000) + return (value & ~15); + if (value < 0x4000) + return (value & ~31); + return (value & ~63); + } + /*else value < 0*/ + if (value > -0x0200) + return (~abs(value) & ~0); + if (value > -0x0400) + return (~abs(value) & ~1); + if (value > -0x0800) + return (~abs(value) & ~3); + if (value > -0x1000) + return (~abs(value) & ~7); + if (value > -0x2000) + return (~abs(value) & ~15); + if (value > -0x4000) + return (~abs(value) & ~31); + return (~abs(value) & ~63); +} + + +static FILE *sample[1]; + #if 1 /*save to MONO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = acc_calc(lt); \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = lt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = rt; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +#define LOG_CYM_FILE 0 +static FILE * cymfile = NULL; + + + +#define OPL_TYPE_WAVESEL 0x01 /* waveform select */ +#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */ +#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */ +#define OPL_TYPE_IO 0x08 /* I/O port */ + +/* ---------- Generic interface section ---------- */ +#define OPL_TYPE_YM3526 (0) +#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL) +#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO) + + + +typedef struct{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect1; /* slot1 output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + UINT16 wavetable; +} OPL_SLOT; + +typedef struct{ + OPL_SLOT SLOT[2]; + /* phase generator state */ + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ +} OPL_CH; + +/* OPL state */ +typedef struct fm_opl_f { + /* FM channel slots */ + OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT8 rhythm; /* Rhythm mode */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 wavesel; /* waveform select enable flag */ + + UINT32 T[2]; /* timer counters */ + UINT8 st[2]; /* timer enable */ + +#if BUILD_Y8950 + /* Delta-T ADPCM unit (Y8950) */ + + YM_DELTAT *deltat; + + /* Keyboard and I/O ports interface */ + UINT8 portDirection; + UINT8 portLatch; + OPL_PORTHANDLER_R porthandler_r; + OPL_PORTHANDLER_W porthandler_w; + void * port_param; + OPL_PORTHANDLER_R keyboardhandler_r; + OPL_PORTHANDLER_W keyboardhandler_w; + void * keyboard_param; +#endif + + /* external event callback handlers */ + OPL_TIMERHANDLER timer_handler; /* TIMER handler */ + void *TimerParam; /* TIMER parameter */ + OPL_IRQHANDLER IRQHandler; /* IRQ handler */ + void *IRQParam; /* IRQ parameter */ + OPL_UPDATEHANDLER UpdateHandler;/* stream update handler */ + void *UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + UINT8 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + UINT8 mode; /* Reg.08 : CSM,notesel,etc. */ + + UINT32 clock; /* master clock (Hz) */ + UINT32 rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + attotime TimerBase; /* Timer base time (==sampling time)*/ + running_device *device; +} FM_OPL; + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* key scale level */ +/* table is 3dB/octave , DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/2.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 (increment by 4) */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 2, 15 3 for attack */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/*note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ +/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, + 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML +}; +#undef ML + +/* TL_TAB_LEN is calculated as: +* 12 - sinus amplitude bits (Y axis) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (12*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>4) + +/* sin waveform table in 'decibel' scale */ +/* four waveforms on OPL2 type chips */ +static unsigned int sin_tab[SIN_LEN * 4]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (loosing precision is important) +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM3812) */ +static const INT8 lfo_pm_table[8*8*2] = { + +/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +}; + + +/* lock level of common table */ +static int num_lock = 0; + + +static void *cur_chip = NULL; /* current chip pointer */ +static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2; + +static signed int phase_modulation; /* phase modulation input (SLOT 2) */ +static signed int output[1]; + +#if BUILD_Y8950 +static INT32 output_deltat[4]; /* for Y8950 DELTA-T, chip is mono, that 4 here is just for safety */ +#endif + +static UINT32 LFO_AM; +static INT32 LFO_PM; + + + +INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* status set and IRQ handling */ +INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) +{ + /* set status flag */ + OPL->status |= flag; + if(!(OPL->status & 0x80)) + { + if(OPL->status & OPL->statusmask) + { /* IRQ on */ + OPL->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); + } + } +} + +/* status reset and IRQ handling */ +INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) +{ + /* reset status flag */ + OPL->status &=~flag; + if((OPL->status & 0x80)) + { + if (!(OPL->status & OPL->statusmask) ) + { + OPL->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); + } + } +} + +/* IRQ mask set */ +INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) +{ + OPL->statusmask = flag; + /* IRQ handling check */ + OPL_STATUS_SET(OPL,0); + OPL_STATUS_RESET(OPL,0); +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(FM_OPL *OPL) +{ + UINT8 tmp; + + /* LFO */ + OPL->lfo_am_cnt += OPL->lfo_am_inc; + if (OPL->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (OPL->lfo_am_depth) + LFO_AM = tmp; + else + LFO_AM = tmp>>2; + + OPL->lfo_pm_cnt += OPL->lfo_pm_inc; + LFO_PM = ((OPL->lfo_pm_cnt>>LFO_SH) & 7) | OPL->lfo_pm_depth_range; +} + +/* advance to next sample */ +INLINE void advance(FM_OPL *OPL) +{ + OPL_CH *CH; + OPL_SLOT *op; + int i; + + OPL->eg_timer += OPL->eg_timer_add; + + while (OPL->eg_timer >= OPL->eg_timer_overflow) + { + OPL->eg_timer -= OPL->eg_timer_overflow; + + OPL->eg_cnt++; + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_ar)-1) ) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((OPL->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_dr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ + if ( !(OPL->eg_cnt & ((1<eg_sh_rr)-1) ) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } + } + } + + for (i=0; i<9*2; i++) + { + CH = &OPL->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->Cnt += (OPL->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + OPL->noise_p += OPL->noise_f; + i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + OPL->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1; + OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (OPL->noise_rng & 1) OPL->noise_rng ^= 0x800302; + OPL->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) + +/* calculate output */ +INLINE void OPL_CALC_CH( OPL_CH *CH ) +{ + OPL_SLOT *SLOT; + unsigned int env; + signed int out; + + phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + *SLOT->connect1 += SLOT->op1_out[0]; + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise ) +{ + OPL_SLOT *SLOT; + signed int out; + unsigned int env; + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + phase_modulation = 0; + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + phase_modulation = SLOT->op1_out[0]; + /* else ignore output of operator 1 */ + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + output[0] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + /* HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) */ + /* SD (16) channel 7->slot 1 */ + /* TOM (14) channel 8->slot 1 */ + /* TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) */ + + /* Envelope generation based on: */ + /* HH channel 7->slot1 */ + /* SD channel 7->slot2 */ + /* TOM channel 8->slot1 */ + /* TOP channel 8->slot2 */ + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(SLOT7_1); + if( env < ENV_QUIET ) + { + + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + output[0] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + output[0] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET ) + output[0] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM3812) */ + env = volume_calc(SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + output[0] += op_calc(phase<wavetable) * 2; + } + +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 1; /* 12 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ]; + + for (i=1; i<12; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = -tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<12; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 /*+1*/ + i*2*TL_RES_LEN ] ); + logerror("\n"); + #endif + } + /*logerror("FMOPL.C: TL_TAB_LEN = %i elements (%i bytes)\n",TL_TAB_LEN, (int)sizeof(tl_tab));*/ + + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("FMOPL.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + } + + for (i=0; i>1) ]; + + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ + /* abs(output only first quarter of the sinus waveform) */ + + if (i & (1<<(SIN_BITS-2)) ) + sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; + + /*logerror("FMOPL.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); + logerror("FMOPL.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); + logerror("FMOPL.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] );*/ + } + /*logerror("FMOPL.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ + + +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","wb"); +#endif + + return 1; +} + +static void OPLCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif +} + + + +static void OPL_initalize(FM_OPL *OPL) +{ + int i; + + /* frequency base */ + OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / 72.0) / OPL->rate : 0; +#if 0 + OPL->rate = (double)OPL->clock / 72.0; + OPL->freqbase = 1.0; +#endif + + /*logerror("freqbase=%f\n", OPL->freqbase);*/ + + /* Timer base time */ + OPL->TimerBase = attotime_mul(ATTOTIME_IN_HZ(OPL->clock), 72); + + /* make fnumber -> increment counter table */ + for( i=0 ; i < 1024 ; i++ ) + { + /* opn phase increment counter = 20bit */ + OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("FMOPL.C: fn_tab[%4i] = %08x (dec=%8i)\n", + i, OPL->fn_tab[i]>>6, OPL->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("FMOPL.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("FMOPL.C: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + OPL->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + OPL->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("OPL->lfo_am_inc = %8x ; OPL->lfo_pm_inc = %8x\n", OPL->lfo_am_inc, OPL->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + OPL->noise_f = (1.0 / 1.0) * (1<freqbase; + + OPL->eg_timer_add = (1<freqbase; + OPL->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, OPL->eg_timer_overflow);*/ + +} + +INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* restart Phase Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ + SLOT->state = EG_ATT; + } + SLOT->key |= key_set; +} + +INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + } +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + CALC_FCSLOT(CH,SLOT); +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) +{ + OPL_CH *CH = &OPL->P_CH[slot/2]; + OPL_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + + +/* write a value v to register r on OPL chip */ +static void OPLWriteReg(FM_OPL *OPL, int r, int v) +{ + OPL_CH *CH; + int slot; + int block_fnum; + + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + if (LOG_CYM_FILE && (cymfile) && (r!=0) ) + { + fputc( (unsigned char)r, cymfile ); + fputc( (unsigned char)v, cymfile ); + } + + + switch(r&0xe0) + { + case 0x00: /* 00-1f:control */ + switch(r&0x1f) + { + case 0x01: /* waveform select enable */ + if(OPL->type&OPL_TYPE_WAVESEL) + { + OPL->wavesel = v&0x20; + /* do not change the waveform previously selected */ + } + break; + case 0x02: /* Timer 1 */ + OPL->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + OPL->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flag clear */ + OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */ + } + else + { /* set IRQ mask ,timer enable*/ + UINT8 st1 = v&1; + UINT8 st2 = (v>>1)&1; + + /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */ + OPL_STATUS_RESET(OPL, v & (0x78-0x08) ); + OPL_STATUSMASK_SET(OPL, (~v) & 0x78 ); + + /* timer 2 */ + if(OPL->st[1] != st2) + { + attotime period = st2 ? attotime_mul(OPL->TimerBase, OPL->T[1]) : attotime_zero; + OPL->st[1] = st2; + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,1,period); + } + /* timer 1 */ + if(OPL->st[0] != st1) + { + attotime period = st1 ? attotime_mul(OPL->TimerBase, OPL->T[0]) : attotime_zero; + OPL->st[0] = st1; + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,0,period); + } + } + break; +#if BUILD_Y8950 + case 0x06: /* Key Board OUT */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_w) + OPL->keyboardhandler_w(OPL->keyboard_param,v); + else + logerror("Y8950: write unmapped KEYBOARD port\n"); + } + break; + case 0x07: /* DELTA-T control 1 : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; +#endif + case 0x08: /* MODE,DELTA-T control 2 : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ + OPL->mode = v; +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v&0x0f); /* mask 4 LSBs in register 08 for DELTA-T unit */ +#endif + break; + +#if BUILD_Y8950 + case 0x09: /* START ADD */ + case 0x0a: + case 0x0b: /* STOP ADD */ + case 0x0c: + case 0x0d: /* PRESCALE */ + case 0x0e: + case 0x0f: /* ADPCM data write */ + case 0x10: /* DELTA-N */ + case 0x11: /* DELTA-N */ + case 0x12: /* ADPCM volume */ + if(OPL->type&OPL_TYPE_ADPCM) + YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v); + break; + + case 0x15: /* DAC data high 8 bits (F7,F6...F2) */ + case 0x16: /* DAC data low 2 bits (F1, F0 in bits 7,6) */ + case 0x17: /* DAC data shift (S2,S1,S0 in bits 2,1,0) */ + logerror("FMOPL.C: DAC data register written, but not implemented reg=%02x val=%02x\n",r,v); + break; + + case 0x18: /* I/O CTRL (Direction) */ + if(OPL->type&OPL_TYPE_IO) + OPL->portDirection = v&0x0f; + break; + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + OPL->portLatch = v; + if(OPL->porthandler_w) + OPL->porthandler_w(OPL->port_param,v&OPL->portDirection); + } + break; +#endif + default: + pclog("FMOPL.C: write to unknown register: %02x\n",r); + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(OPL,slot,v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(OPL,slot,v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(OPL,slot,v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(OPL,slot,v); + break; + case 0xa0: + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + { + OPL->lfo_am_depth = v & 0x80; + OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0; + + OPL->rhythm = v&0x3f; + + if(OPL->rhythm&0x20) + { + /* BD key on/off */ + if(v&0x10) + { + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT1], 2); + FM_KEYON (&OPL->P_CH[6].SLOT[SLOT2], 2); + } + else + { + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) FM_KEYON (&OPL->P_CH[7].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT1], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) FM_KEYON (&OPL->P_CH[8].SLOT[SLOT2], 2); + else FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + else + { + /* BD key off */ + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + FM_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + FM_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2],~2); + } + return; + } + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + CH->block_fnum = block_fnum; + + CH->ksl_base = ksl_tab[block_fnum>>6]; + CH->fc = OPL->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ + CH->kcode = (CH->block_fnum&0x1c00)>>9; + + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */ + /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ + /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ + if (OPL->mode&0x40) + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + else + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + case 0xc0: + /* FB,C */ + if( (r&0x0f) > 8) return; + CH = &OPL->P_CH[r&0x0f]; + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + CH->SLOT[SLOT1].connect1 = CH->SLOT[SLOT1].CON ? &output[0] : &phase_modulation; + break; + case 0xe0: /* waveform select */ + /* simply ignore write to the waveform select register if selecting not enabled in test register */ + if(OPL->wavesel) + { + slot = slot_array[r&0x1f]; + if(slot < 0) return; + CH = &OPL->P_CH[slot/2]; + + CH->SLOT[slot&1].wavetable = (v&0x03)*SIN_LEN; + } + break; + } +} + +static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +} + +/* lock/unlock for common table */ +static int OPL_LockTable(running_device *device) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + cur_chip = NULL; + /* allocate total level table (128kb space) */ + if( !init_tables() ) + { + num_lock--; + return -1; + } + + #if 0 + if (LOG_CYM_FILE) + { + cymfile = fopen("3812_.cym","wb"); + if (cymfile) + timer_pulse ( device->machine, ATTOTIME_IN_HZ(110), NULL, 0, cymfile_callback); /*110 Hz pulse timer*/ + else + logerror("Could not create file 3812_.cym\n"); + } + #endif + return 0; +} + +static void OPL_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + cur_chip = NULL; + OPLCloseTable(); + #if 0 + if (cymfile) + fclose (cymfile); + cymfile = NULL; + #endif +} + +static void OPLResetChip(FM_OPL *OPL) +{ + int c,s; + int i; + + OPL->eg_timer = 0; + OPL->eg_cnt = 0; + + OPL->noise_rng = 1; /* noise shift register */ + OPL->mode = 0; /* normal mode */ + OPL_STATUS_RESET(OPL,0x7f); + + /* reset with register write */ + OPLWriteReg(OPL,0x01,0); /* wavesel disable */ + OPLWriteReg(OPL,0x02,0); /* Timer1 */ + OPLWriteReg(OPL,0x03,0); /* Timer2 */ + OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ + for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); + + /* reset operator parameters */ + for( c = 0 ; c < 9 ; c++ ) + { + OPL_CH *CH = &OPL->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + /* wave table */ + CH->SLOT[s].wavetable = 0; + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +#if BUILD_Y8950 + if(OPL->type&OPL_TYPE_ADPCM) + { + YM_DELTAT *DELTAT = OPL->deltat; + + DELTAT->freqbase = OPL->freqbase; + DELTAT->output_pointer = &output_deltat[0]; + DELTAT->portshift = 5; + DELTAT->output_range = 1<<23; + YM_DELTAT_ADPCM_Reset(DELTAT,0,YM_DELTAT_EMULATION_MODE_NORMAL); + } +#endif +} + +#if 0 +static STATE_POSTLOAD( OPL_postload ) +{ + FM_OPL *OPL = (FM_OPL *)param; + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++ ) + { + OPL_CH *CH = &OPL->P_CH[ch]; + + /* Look up key scale level */ + UINT32 block_fnum = CH->block_fnum; + CH->ksl_base = ksl_tab[block_fnum >> 6]; + CH->fc = OPL->fn_tab[block_fnum & 0x03ff] >> (7 - (block_fnum >> 10)); + + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + /* Calculate key scale rate */ + SLOT->ksr = CH->kcode >> SLOT->KSR; + + /* Calculate attack, decay and release rates */ + if ((SLOT->ar + SLOT->ksr) < 16+62) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + + /* Calculate phase increment */ + SLOT->Incr = CH->fc * SLOT->mul; + + /* Total level */ + SLOT->TLL = SLOT->TL + (CH->ksl_base >> SLOT->ksl); + + /* Connect output */ + SLOT->connect1 = SLOT->CON ? &output[0] : &phase_modulation; + } + } +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + // We really should call the postlod function for the YM_DELTAT, but it's hard without registers + // (see the way the YM2610 does it) + //YM_DELTAT_postload(OPL->deltat, REGS); + } +#endif +} + + +static void OPLsave_state_channel(running_device *device, OPL_CH *CH) +{ + int slot, ch; + + for( ch=0 ; ch < 9 ; ch++, CH++ ) + { + /* channel */ + state_save_register_device_item(device, ch, CH->block_fnum); + state_save_register_device_item(device, ch, CH->kcode); + /* slots */ + for( slot=0 ; slot < 2 ; slot++ ) + { + OPL_SLOT *SLOT = &CH->SLOT[slot]; + + state_save_register_device_item(device, ch * 2 + slot, SLOT->ar); + state_save_register_device_item(device, ch * 2 + slot, SLOT->dr); + state_save_register_device_item(device, ch * 2 + slot, SLOT->rr); + state_save_register_device_item(device, ch * 2 + slot, SLOT->KSR); + state_save_register_device_item(device, ch * 2 + slot, SLOT->ksl); + state_save_register_device_item(device, ch * 2 + slot, SLOT->mul); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->Cnt); + state_save_register_device_item(device, ch * 2 + slot, SLOT->FB); + state_save_register_device_item_array(device, ch * 2 + slot, SLOT->op1_out); + state_save_register_device_item(device, ch * 2 + slot, SLOT->CON); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->eg_type); + state_save_register_device_item(device, ch * 2 + slot, SLOT->state); + state_save_register_device_item(device, ch * 2 + slot, SLOT->TL); + state_save_register_device_item(device, ch * 2 + slot, SLOT->volume); + state_save_register_device_item(device, ch * 2 + slot, SLOT->sl); + state_save_register_device_item(device, ch * 2 + slot, SLOT->key); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->AMmask); + state_save_register_device_item(device, ch * 2 + slot, SLOT->vib); + + state_save_register_device_item(device, ch * 2 + slot, SLOT->wavetable); + } + } +} + + +/* Register savestate for a virtual YM3812/YM3526Y8950 */ + +static void OPL_save_state(FM_OPL *OPL, running_device *device) +{ + OPLsave_state_channel(device, OPL->P_CH); + + state_save_register_device_item(device, 0, OPL->eg_cnt); + state_save_register_device_item(device, 0, OPL->eg_timer); + + state_save_register_device_item(device, 0, OPL->rhythm); + + state_save_register_device_item(device, 0, OPL->lfo_am_depth); + state_save_register_device_item(device, 0, OPL->lfo_pm_depth_range); + state_save_register_device_item(device, 0, OPL->lfo_am_cnt); + state_save_register_device_item(device, 0, OPL->lfo_pm_cnt); + + state_save_register_device_item(device, 0, OPL->noise_rng); + state_save_register_device_item(device, 0, OPL->noise_p); + + if( OPL->type & OPL_TYPE_WAVESEL ) + { + state_save_register_device_item(device, 0, OPL->wavesel); + } + + state_save_register_device_item_array(device, 0, OPL->T); + state_save_register_device_item_array(device, 0, OPL->st); + +#if BUILD_Y8950 + if ( (OPL->type & OPL_TYPE_ADPCM) && (OPL->deltat) ) + { + YM_DELTAT_savestate(device, OPL->deltat); + } + + if ( OPL->type & OPL_TYPE_IO ) + { + state_save_register_device_item(device, 0, OPL->portDirection); + state_save_register_device_item(device, 0, OPL->portLatch); + } +#endif + + state_save_register_device_item(device, 0, OPL->address); + state_save_register_device_item(device, 0, OPL->status); + state_save_register_device_item(device, 0, OPL->statusmask); + state_save_register_device_item(device, 0, OPL->mode); + + state_save_register_postload(device->machine, OPL_postload, OPL); +} +#endif + +/* Create one of virtual YM3812/YM3526/Y8950 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static FM_OPL *OPLCreate(running_device *device, UINT32 clock, UINT32 rate, int type) +{ + char *ptr; + FM_OPL *OPL; + int state_size; + + if (OPL_LockTable(device) == -1) return NULL; + + /* calculate OPL state size */ + state_size = sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); +#endif + + /* allocate memory block */ + ptr = (char *)malloc(state_size); //auto_alloc_array_clear(device->machine, UINT8, state_size); + memset(ptr,0,state_size); + OPL = (FM_OPL *)ptr; + + ptr += sizeof(FM_OPL); + +#if BUILD_Y8950 + if (type&OPL_TYPE_ADPCM) + { + OPL->deltat = (YM_DELTAT *)ptr; + } + ptr += sizeof(YM_DELTAT); +#endif + + OPL->device = device; + OPL->type = type; + OPL->clock = clock; + OPL->rate = rate; + + /* init global tables */ + OPL_initalize(OPL); + + return OPL; +} + +/* Destroy one of virtual YM3812 */ +static void OPLDestroy(FM_OPL *OPL) +{ + OPL_UnLockTable(); + free(OPL); +// auto_free(OPL->device->machine, OPL); +} + +/* Optional handlers */ + +static void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER timer_handler,void *param) +{ + OPL->timer_handler = timer_handler; + OPL->TimerParam = param; +} +static void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,void *param) +{ + OPL->IRQHandler = IRQHandler; + OPL->IRQParam = param; +} +static void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + OPL->UpdateHandler = UpdateHandler; + OPL->UpdateParam = param; +} + +static int OPLWrite(FM_OPL *OPL,int a,int v) +{ + if( !(a&1) ) + { /* address port */ + OPL->address = v & 0xff; + } + else + { /* data port */ + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + OPLWriteReg(OPL,OPL->address,v); + } + return OPL->status>>7; +} + +static unsigned char OPLRead(FM_OPL *OPL,int a) +{ + if( !(a&1) ) + { + /* status port */ + + #if BUILD_Y8950 + + if(OPL->type&OPL_TYPE_ADPCM) /* Y8950 */ + { + return (OPL->status & (OPL->statusmask|0x80)) | (OPL->deltat->PCM_BSY&1); + } + + #endif + + /* OPL and OPL2 */ + return OPL->status & (OPL->statusmask|0x80); + } + +#if BUILD_Y8950 + /* data port */ + switch(OPL->address) + { + case 0x05: /* KeyBoard IN */ + if(OPL->type&OPL_TYPE_KEYBOARD) + { + if(OPL->keyboardhandler_r) + return OPL->keyboardhandler_r(OPL->keyboard_param); + else + logerror("Y8950: read unmapped KEYBOARD port\n"); + } + return 0; + + case 0x0f: /* ADPCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + UINT8 val; + + val = YM_DELTAT_ADPCM_Read(OPL->deltat); + /*logerror("Y8950: read ADPCM value read=%02x\n",val);*/ + return val; + } + return 0; + + case 0x19: /* I/O DATA */ + if(OPL->type&OPL_TYPE_IO) + { + if(OPL->porthandler_r) + return OPL->porthandler_r(OPL->port_param); + else + logerror("Y8950:read unmapped I/O port\n"); + } + return 0; + case 0x1a: /* PCM-DATA */ + if(OPL->type&OPL_TYPE_ADPCM) + { + logerror("Y8950 A/D convertion is accessed but not implemented !\n"); + return 0x80; /* 2's complement PCM data - result from A/D convertion */ + } + return 0; + } +#endif + + return 0xff; +} + +/* CSM Key Controll */ +INLINE void CSMKeyControll(OPL_CH *CH) +{ + FM_KEYON (&CH->SLOT[SLOT1], 4); + FM_KEYON (&CH->SLOT[SLOT2], 4); + + /* The key off should happen exactly one sample later - not implemented correctly yet */ + + FM_KEYOFF(&CH->SLOT[SLOT1], ~4); + FM_KEYOFF(&CH->SLOT[SLOT2], ~4); +} + + +static int OPLTimerOver(FM_OPL *OPL,int c) +{ + if( c ) + { /* Timer B */ + OPL_STATUS_SET(OPL,0x20); + } + else + { /* Timer A */ + OPL_STATUS_SET(OPL,0x40); + /* CSM mode key,TL controll */ + if( OPL->mode & 0x80 ) + { /* CSM mode total level latch and auto key on */ + int ch; + if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); + for(ch=0; ch<9; ch++) + CSMKeyControll( &OPL->P_CH[ch] ); + } + } + /* reload timer */ + if (OPL->timer_handler) (OPL->timer_handler)(OPL->TimerParam,c,attotime_mul(OPL->TimerBase, OPL->T[c])); + return OPL->status>>7; +} + + +#define MAX_OPL_CHIPS 2 + + +#if (BUILD_YM3812) + +void * ym3812_init(running_device *device, UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3812 = OPLCreate(device,clock,rate,OPL_TYPE_YM3812); + if (YM3812) + { +// OPL_save_state(YM3812, device); + ym3812_reset_chip(YM3812); + } + return YM3812; +} + +void ym3812_shutdown(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + + /* emulator shutdown */ + OPLDestroy(YM3812); +} +void ym3812_reset_chip(void *chip) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLResetChip(YM3812); +} + +int ym3812_write(void *chip, int a, int v) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLWrite(YM3812, a, v); +} + +unsigned char ym3812_read(void *chip, int a) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + /* YM3812 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3812, a) | 0x06 ; +} +int ym3812_timer_over(void *chip, int c) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + return OPLTimerOver(YM3812, c); +} + +void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3812, timer_handler, param); +} +void ym3812_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3812, IRQHandler, param); +} +void ym3812_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3812 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3812, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3812's +** +** 'which' is the virtual YM3812 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3812 */ + + + +#if (BUILD_YM3526) + +void *ym3526_init(running_device *device, UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *YM3526 = OPLCreate(device,clock,rate,OPL_TYPE_YM3526); + if (YM3526) + { + OPL_save_state(YM3526, device); + ym3526_reset_chip(YM3526); + } + return YM3526; +} + +void ym3526_shutdown(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(YM3526); +} +void ym3526_reset_chip(void *chip) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLResetChip(YM3526); +} + +int ym3526_write(void *chip, int a, int v) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLWrite(YM3526, a, v); +} + +unsigned char ym3526_read(void *chip, int a) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + /* YM3526 always returns bit2 and bit1 in HIGH state */ + return OPLRead(YM3526, a) | 0x06 ; +} +int ym3526_timer_over(void *chip, int c) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + return OPLTimerOver(YM3526, c); +} + +void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetTimerHandler(YM3526, timer_handler, param); +} +void ym3526_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetIRQHandler(YM3526, IRQHandler, param); +} +void ym3526_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *YM3526 = (FM_OPL *)chip; + OPLSetUpdateHandler(YM3526, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + OPLSAMPLE *buf = buffer; + int i; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + + advance_lfo(OPL); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0]; + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} +#endif /* BUILD_YM3526 */ + + + + +#if BUILD_Y8950 + +static void Y8950_deltat_status_set(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_SET(Y8950, changebits); +} +static void Y8950_deltat_status_reset(void *chip, UINT8 changebits) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPL_STATUS_RESET(Y8950, changebits); +} + +void *y8950_init(running_device *device, UINT32 clock, UINT32 rate) +{ + /* emulator create */ + FM_OPL *Y8950 = OPLCreate(device,clock,rate,OPL_TYPE_Y8950); + if (Y8950) + { + Y8950->deltat->status_set_handler = Y8950_deltat_status_set; + Y8950->deltat->status_reset_handler = Y8950_deltat_status_reset; + Y8950->deltat->status_change_which_chip = Y8950; + Y8950->deltat->status_change_EOS_bit = 0x10; /* status flag: set bit4 on End Of Sample */ + Y8950->deltat->status_change_BRDY_bit = 0x08; /* status flag: set bit3 on BRDY (End Of: ADPCM analysis/synthesis, memory reading/writing) */ + + /*Y8950->deltat->write_time = 10.0 / clock;*/ /* a single byte write takes 10 cycles of main clock */ + /*Y8950->deltat->read_time = 8.0 / clock;*/ /* a single byte read takes 8 cycles of main clock */ + /* reset */ + OPL_save_state(Y8950, device); + y8950_reset_chip(Y8950); + } + + return Y8950; +} + +void y8950_shutdown(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + /* emulator shutdown */ + OPLDestroy(Y8950); +} +void y8950_reset_chip(void *chip) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLResetChip(Y8950); +} + +int y8950_write(void *chip, int a, int v) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLWrite(Y8950, a, v); +} + +unsigned char y8950_read(void *chip, int a) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLRead(Y8950, a); +} +int y8950_timer_over(void *chip, int c) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + return OPLTimerOver(Y8950, c); +} + +void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER timer_handler, void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetTimerHandler(Y8950, timer_handler, param); +} +void y8950_set_irq_handler(void *chip,OPL_IRQHANDLER IRQHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetIRQHandler(Y8950, IRQHandler, param); +} +void y8950_set_update_handler(void *chip,OPL_UPDATEHANDLER UpdateHandler,void *param) +{ + FM_OPL *Y8950 = (FM_OPL *)chip; + OPLSetUpdateHandler(Y8950, UpdateHandler, param); +} + +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->deltat->memory = (UINT8 *)(deltat_mem_ptr); + OPL->deltat->memory_size = deltat_mem_size; +} + +/* +** Generate samples for one of the Y8950's +** +** 'which' is the virtual Y8950 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length) +{ + int i; + FM_OPL *OPL = (FM_OPL *)chip; + UINT8 rhythm = OPL->rhythm&0x20; + YM_DELTAT *DELTAT = OPL->deltat; + OPLSAMPLE *buf = buffer; + + if( (void *)OPL != cur_chip ){ + cur_chip = (void *)OPL; + /* rhythm slots */ + SLOT7_1 = &OPL->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &OPL->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &OPL->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &OPL->P_CH[8].SLOT[SLOT2]; + + } + for( i=0; i < length ; i++ ) + { + int lt; + + output[0] = 0; + output_deltat[0] = 0; + + advance_lfo(OPL); + + /* deltaT ADPCM */ + if( DELTAT->portstate&0x80 ) + YM_DELTAT_ADPCM_CALC(DELTAT); + + /* FM part */ + OPL_CALC_CH(&OPL->P_CH[0]); + OPL_CALC_CH(&OPL->P_CH[1]); + OPL_CALC_CH(&OPL->P_CH[2]); + OPL_CALC_CH(&OPL->P_CH[3]); + OPL_CALC_CH(&OPL->P_CH[4]); + OPL_CALC_CH(&OPL->P_CH[5]); + + if(!rhythm) + { + OPL_CALC_CH(&OPL->P_CH[6]); + OPL_CALC_CH(&OPL->P_CH[7]); + OPL_CALC_CH(&OPL->P_CH[8]); + } + else /* Rhythm part */ + { + OPL_CALC_RH(&OPL->P_CH[0], (OPL->noise_rng>>0)&1 ); + } + + lt = output[0] + (output_deltat[0]>>11); + + lt >>= FINAL_SH; + + /* limit check */ + lt = limit( lt , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + buf[i] = lt; + + advance(OPL); + } + +} + +void y8950_set_port_handler(void *chip,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->porthandler_w = PortHandler_w; + OPL->porthandler_r = PortHandler_r; + OPL->port_param = param; +} + +void y8950_set_keyboard_handler(void *chip,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,void * param) +{ + FM_OPL *OPL = (FM_OPL *)chip; + OPL->keyboardhandler_w = KeyboardHandler_w; + OPL->keyboardhandler_r = KeyboardHandler_r; + OPL->keyboard_param = param; +} + +#endif + diff --git a/src/mame/fmopl.h b/src/mame/fmopl.h new file mode 100644 index 00000000..9bc19173 --- /dev/null +++ b/src/mame/fmopl.h @@ -0,0 +1,126 @@ +#pragma once + +#ifndef __FMOPL_H__ +#define __FMOPL_H__ + +#ifndef STUFF +#define STUFF +typedef int64_t attotime; +#define ATTOTIME_IN_HZ(x) (1000000000/(x)) +#define attotime_mul(x,y) ((x)*(y)) +#define attotime_to_double(x) ((double)(x)/1000000000.0) +#define attotime_zero 0 + +#define running_device void +#define INLINE static +//#define M_PI 3.142 +#endif + +/* --- select emulation chips --- */ +#define BUILD_YM3812 (1) +#define BUILD_YM3526 (0) +#define BUILD_Y8950 (0) + +/* select output bits size of output : 8 or 16 */ +#define OPL_SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif /* __OSDCOMM_H__ */ + +typedef signed short OPLSAMPLE; +/* +#if (OPL_SAMPLE_BITS==16) +typedef INT16 OPLSAMPLE; +#endif +#if (OPL_SAMPLE_BITS==8) +typedef INT8 OPLSAMPLE; +#endif +*/ + +typedef void (*OPL_TIMERHANDLER)(void *param,int timer,attotime period); +typedef void (*OPL_IRQHANDLER)(void *param,int irq); +typedef void (*OPL_UPDATEHANDLER)(void *param,int min_interval_us); +typedef void (*OPL_PORTHANDLER_W)(void *param,unsigned char data); +typedef unsigned char (*OPL_PORTHANDLER_R)(void *param); + + +#if BUILD_YM3812 + +void *ym3812_init(running_device *device, UINT32 clock, UINT32 rate); +void ym3812_shutdown(void *chip); +void ym3812_reset_chip(void *chip); +int ym3812_write(void *chip, int a, int v); +unsigned char ym3812_read(void *chip, int a); +int ym3812_timer_over(void *chip, int c); +void ym3812_update_one(void *chip, OPLSAMPLE *buffer, int length); + +void ym3812_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3812_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3812_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3812 */ + + +#if BUILD_YM3526 + +/* +** Initialize YM3526 emulator(s). +** +** 'num' is the number of virtual YM3526's to allocate +** 'clock' is the chip clock in Hz +** 'rate' is sampling rate +*/ +void *ym3526_init(running_device *device, UINT32 clock, UINT32 rate); +/* shutdown the YM3526 emulators*/ +void ym3526_shutdown(void *chip); +void ym3526_reset_chip(void *chip); +int ym3526_write(void *chip, int a, int v); +unsigned char ym3526_read(void *chip, int a); +int ym3526_timer_over(void *chip, int c); +/* +** Generate samples for one of the YM3526's +** +** 'which' is the virtual YM3526 number +** '*buffer' is the output buffer pointer +** 'length' is the number of samples that should be generated +*/ +void ym3526_update_one(void *chip, OPLSAMPLE *buffer, int length); + +void ym3526_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void ym3526_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void ym3526_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_YM3526 */ + + +#if BUILD_Y8950 + +/* Y8950 port handlers */ +void y8950_set_port_handler(void *chip, OPL_PORTHANDLER_W PortHandler_w, OPL_PORTHANDLER_R PortHandler_r, void *param); +void y8950_set_keyboard_handler(void *chip, OPL_PORTHANDLER_W KeyboardHandler_w, OPL_PORTHANDLER_R KeyboardHandler_r, void *param); +void y8950_set_delta_t_memory(void *chip, void * deltat_mem_ptr, int deltat_mem_size ); + +void * y8950_init(running_device *device, UINT32 clock, UINT32 rate); +void y8950_shutdown(void *chip); +void y8950_reset_chip(void *chip); +int y8950_write(void *chip, int a, int v); +unsigned char y8950_read (void *chip, int a); +int y8950_timer_over(void *chip, int c); +void y8950_update_one(void *chip, OPLSAMPLE *buffer, int length); + +void y8950_set_timer_handler(void *chip, OPL_TIMERHANDLER TimerHandler, void *param); +void y8950_set_irq_handler(void *chip, OPL_IRQHANDLER IRQHandler, void *param); +void y8950_set_update_handler(void *chip, OPL_UPDATEHANDLER UpdateHandler, void *param); + +#endif /* BUILD_Y8950 */ + + +#endif /* __FMOPL_H__ */ diff --git a/src/mame/ymf262.c b/src/mame/ymf262.c new file mode 100644 index 00000000..652a5161 --- /dev/null +++ b/src/mame/ymf262.c @@ -0,0 +1,2730 @@ +/* +** +** File: ymf262.c - software implementation of YMF262 +** FM sound generator type OPL3 +** +** Copyright Jarek Burczynski +** +** Version 0.2 +** + +Revision History: + +03-03-2003: initial release + - thanks to Olivier Galibert and Chris Hardy for YMF262 and YAC512 chips + - thanks to Stiletto for the datasheets + + Features as listed in 4MF262A6 data sheet: + 1. Registers are compatible with YM3812 (OPL2) FM sound source. + 2. Up to six sounds can be used as four-operator melody sounds for variety. + 3. 18 simultaneous melody sounds, or 15 melody sounds with 5 rhythm sounds (with two operators). + 4. 6 four-operator melody sounds and 6 two-operator melody sounds, or 6 four-operator melody + sounds, 3 two-operator melody sounds and 5 rhythm sounds (with four operators). + 5. 8 selectable waveforms. + 6. 4-channel sound output. + 7. YMF262 compabile DAC (YAC512) is available. + 8. LFO for vibrato and tremolo effedts. + 9. 2 programable timers. + 10. Shorter register access time compared with YM3812. + 11. 5V single supply silicon gate CMOS process. + 12. 24 Pin SOP Package (YMF262-M), 48 Pin SQFP Package (YMF262-S). + + +differences between OPL2 and OPL3 not documented in Yamaha datahasheets: +- sinus table is a little different: the negative part is off by one... + +- in order to enable selection of four different waveforms on OPL2 + one must set bit 5 in register 0x01(test). + on OPL3 this bit is ignored and 4-waveform select works *always*. + (Don't confuse this with OPL3's 8-waveform select.) + +- Envelope Generator: all 15 x rates take zero time on OPL3 + (on OPL2 15 0 and 15 1 rates take some time while 15 2 and 15 3 rates + take zero time) + +- channel calculations: output of operator 1 is in perfect sync with + output of operator 2 on OPL3; on OPL and OPL2 output of operator 1 + is always delayed by one sample compared to output of operator 2 + + +differences between OPL2 and OPL3 shown in datasheets: +- YMF262 does not support CSM mode + + +*/ + +#include +#include +#include +#include +#include +//#include "emu.h" +#include "ymf262.h" + + + +/* output final shift */ +#if (OPL3_SAMPLE_BITS==16) + #define FINAL_SH (0) + #define MAXOUT (+32767) + #define MINOUT (-32768) +#else + #define FINAL_SH (8) + #define MAXOUT (+127) + #define MINOUT (-128) +#endif + + +#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */ +#define EG_SH 16 /* 16.16 fixed point (EG timing) */ +#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */ +#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */ + +#define FREQ_MASK ((1<>8)&0xff,sample[0]); \ + } + #else /*save to STEREO file */ + #define SAVE_ALL_CHANNELS \ + { signed int pom = a; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + pom = b; \ + fputc((unsigned short)pom&0xff,sample[0]); \ + fputc(((unsigned short)pom>>8)&0xff,sample[0]); \ + } + #endif +#endif + +#define LOG_CYM_FILE 0 +static FILE * cymfile = NULL; + + + + + +#define OPL3_TYPE_YMF262 (0) /* 36 operators, 8 waveforms */ + + +typedef struct{ + UINT32 ar; /* attack rate: AR<<2 */ + UINT32 dr; /* decay rate: DR<<2 */ + UINT32 rr; /* release rate:RR<<2 */ + UINT8 KSR; /* key scale rate */ + UINT8 ksl; /* keyscale level */ + UINT8 ksr; /* key scale rate: kcode>>KSR */ + UINT8 mul; /* multiple: mul_tab[ML] */ + + /* Phase Generator */ + UINT32 Cnt; /* frequency counter */ + UINT32 Incr; /* frequency counter step */ + UINT8 FB; /* feedback shift value */ + INT32 *connect; /* slot output pointer */ + INT32 op1_out[2]; /* slot1 output for feedback */ + UINT8 CON; /* connection (algorithm) type */ + + /* Envelope Generator */ + UINT8 eg_type; /* percussive/non-percussive mode */ + UINT8 state; /* phase type */ + UINT32 TL; /* total level: TL << 2 */ + INT32 TLL; /* adjusted now TL */ + INT32 volume; /* envelope counter */ + UINT32 sl; /* sustain level: sl_tab[SL] */ + + UINT32 eg_m_ar; /* (attack state) */ + UINT8 eg_sh_ar; /* (attack state) */ + UINT8 eg_sel_ar; /* (attack state) */ + UINT32 eg_m_dr; /* (decay state) */ + UINT8 eg_sh_dr; /* (decay state) */ + UINT8 eg_sel_dr; /* (decay state) */ + UINT32 eg_m_rr; /* (release state) */ + UINT8 eg_sh_rr; /* (release state) */ + UINT8 eg_sel_rr; /* (release state) */ + + UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */ + + /* LFO */ + UINT32 AMmask; /* LFO Amplitude Modulation enable mask */ + UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/ + + /* waveform select */ + UINT8 waveform_number; + unsigned int wavetable; + +//unsigned char reserved[128-84];//speedup: pump up the struct size to power of 2 +unsigned char reserved[128-100];//speedup: pump up the struct size to power of 2 + +} OPL3_SLOT; + +typedef struct{ + OPL3_SLOT SLOT[2]; + + UINT32 block_fnum; /* block+fnum */ + UINT32 fc; /* Freq. Increment base */ + UINT32 ksl_base; /* KeyScaleLevel Base step */ + UINT8 kcode; /* key code (for key scaling) */ + + /* + there are 12 2-operator channels which can be combined in pairs + to form six 4-operator channel, they are: + 0 and 3, + 1 and 4, + 2 and 5, + 9 and 12, + 10 and 13, + 11 and 14 + */ + UINT8 extended; /* set to 1 if this channel forms up a 4op channel with another channel(only used by first of pair of channels, ie 0,1,2 and 9,10,11) */ + +unsigned char reserved[512-272];//speedup:pump up the struct size to power of 2 + +} OPL3_CH; + +/* OPL3 state */ +typedef struct { + OPL3_CH P_CH[18]; /* OPL3 chips have 18 channels */ + + UINT32 pan[18*4]; /* channels output masks (0xffffffff = enable); 4 masks per one channel */ + UINT32 pan_ctrl_value[18]; /* output control values 1 per one channel (1 value contains 4 masks) */ + + UINT32 eg_cnt; /* global envelope generator counter */ + UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/288 (288=8*36) */ + UINT32 eg_timer_add; /* step of eg_timer */ + UINT32 eg_timer_overflow; /* envelope generator timer overlfows every 1 sample (on real chip) */ + + UINT32 fn_tab[1024]; /* fnumber->increment counter */ + + /* LFO */ + UINT8 lfo_am_depth; + UINT8 lfo_pm_depth_range; + UINT32 lfo_am_cnt; + UINT32 lfo_am_inc; + UINT32 lfo_pm_cnt; + UINT32 lfo_pm_inc; + + UINT32 noise_rng; /* 23 bit noise shift register */ + UINT32 noise_p; /* current noise 'phase' */ + UINT32 noise_f; /* current noise period */ + + UINT8 OPL3_mode; /* OPL3 extension enable flag */ + + UINT8 rhythm; /* Rhythm mode */ + + int T[2]; /* timer counters */ + UINT8 st[2]; /* timer enable */ + + UINT32 address; /* address register */ + UINT8 status; /* status flag */ + UINT8 statusmask; /* status mask */ + + UINT8 nts; /* NTS (note select) */ + + /* external event callback handlers */ + OPL3_TIMERHANDLER timer_handler;/* TIMER handler */ + void *TimerParam; /* TIMER parameter */ + OPL3_IRQHANDLER IRQHandler; /* IRQ handler */ + void *IRQParam; /* IRQ parameter */ + OPL3_UPDATEHANDLER UpdateHandler;/* stream update handler */ + void *UpdateParam; /* stream update parameter */ + + UINT8 type; /* chip type */ + int clock; /* master clock (Hz) */ + int rate; /* sampling rate (Hz) */ + double freqbase; /* frequency base */ + attotime TimerBase; /* Timer base time (==sampling time)*/ + running_device *device; +} OPL3; + + + +/* mapping of register number (offset) to slot number used by the emulator */ +static const int slot_array[32]= +{ + 0, 2, 4, 1, 3, 5,-1,-1, + 6, 8,10, 7, 9,11,-1,-1, + 12,14,16,13,15,17,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1 +}; + +/* key scale level */ +/* table is 3dB/octave , DV converts this into 6dB/octave */ +/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */ +#define DV (0.1875/2.0) +static const UINT32 ksl_tab[8*16]= +{ + /* OCT 0 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + /* OCT 1 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, + 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, + /* OCT 2 */ + 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, + 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, + 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, + 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, + /* OCT 3 */ + 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, + 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, + 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, + 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, + /* OCT 4 */ + 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, + 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, + 9.000/DV, 9.750/DV,10.125/DV,10.500/DV, + 10.875/DV,11.250/DV,11.625/DV,12.000/DV, + /* OCT 5 */ + 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, + 9.000/DV,10.125/DV,10.875/DV,11.625/DV, + 12.000/DV,12.750/DV,13.125/DV,13.500/DV, + 13.875/DV,14.250/DV,14.625/DV,15.000/DV, + /* OCT 6 */ + 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, + 12.000/DV,13.125/DV,13.875/DV,14.625/DV, + 15.000/DV,15.750/DV,16.125/DV,16.500/DV, + 16.875/DV,17.250/DV,17.625/DV,18.000/DV, + /* OCT 7 */ + 0.000/DV, 9.000/DV,12.000/DV,13.875/DV, + 15.000/DV,16.125/DV,16.875/DV,17.625/DV, + 18.000/DV,18.750/DV,19.125/DV,19.500/DV, + 19.875/DV,20.250/DV,20.625/DV,21.000/DV +}; +#undef DV + +/* sustain level table (3dB per step) */ +/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/ +#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) ) +static const UINT32 sl_tab[16]={ + SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), + SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) +}; +#undef SC + + +#define RATE_STEPS (8) +static const unsigned char eg_inc[15*RATE_STEPS]={ + +/*cycle:0 1 2 3 4 5 6 7*/ + +/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */ +/* 1 */ 0,1, 0,1, 1,1, 0,1, /* rates 00..12 1 */ +/* 2 */ 0,1, 1,1, 0,1, 1,1, /* rates 00..12 2 */ +/* 3 */ 0,1, 1,1, 1,1, 1,1, /* rates 00..12 3 */ + +/* 4 */ 1,1, 1,1, 1,1, 1,1, /* rate 13 0 (increment by 1) */ +/* 5 */ 1,1, 1,2, 1,1, 1,2, /* rate 13 1 */ +/* 6 */ 1,2, 1,2, 1,2, 1,2, /* rate 13 2 */ +/* 7 */ 1,2, 2,2, 1,2, 2,2, /* rate 13 3 */ + +/* 8 */ 2,2, 2,2, 2,2, 2,2, /* rate 14 0 (increment by 2) */ +/* 9 */ 2,2, 2,4, 2,2, 2,4, /* rate 14 1 */ +/*10 */ 2,4, 2,4, 2,4, 2,4, /* rate 14 2 */ +/*11 */ 2,4, 4,4, 2,4, 4,4, /* rate 14 3 */ + +/*12 */ 4,4, 4,4, 4,4, 4,4, /* rates 15 0, 15 1, 15 2, 15 3 for decay */ +/*13 */ 8,8, 8,8, 8,8, 8,8, /* rates 15 0, 15 1, 15 2, 15 3 for attack (zero time) */ +/*14 */ 0,0, 0,0, 0,0, 0,0, /* infinity rates for attack and decay(s) */ +}; + + +#define O(a) (a*RATE_STEPS) + +/* note that there is no O(13) in this table - it's directly in the code */ +static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), +O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14), + +/* rates 00-12 */ +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), +O( 0),O( 1),O( 2),O( 3), + +/* rate 13 */ +O( 4),O( 5),O( 6),O( 7), + +/* rate 14 */ +O( 8),O( 9),O(10),O(11), + +/* rate 15 */ +O(12),O(12),O(12),O(12), + +/* 16 dummy rates (same as 15 3) */ +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), +O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12), + +}; +#undef O + +/*rate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 */ +/*shift 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, 0, 0 */ +/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */ + +#define O(a) (a*1) +static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */ +/* 16 infinite time rates */ +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), +O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0), + +/* rates 00-12 */ +O(12),O(12),O(12),O(12), +O(11),O(11),O(11),O(11), +O(10),O(10),O(10),O(10), +O( 9),O( 9),O( 9),O( 9), +O( 8),O( 8),O( 8),O( 8), +O( 7),O( 7),O( 7),O( 7), +O( 6),O( 6),O( 6),O( 6), +O( 5),O( 5),O( 5),O( 5), +O( 4),O( 4),O( 4),O( 4), +O( 3),O( 3),O( 3),O( 3), +O( 2),O( 2),O( 2),O( 2), +O( 1),O( 1),O( 1),O( 1), +O( 0),O( 0),O( 0),O( 0), + +/* rate 13 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 14 */ +O( 0),O( 0),O( 0),O( 0), + +/* rate 15 */ +O( 0),O( 0),O( 0),O( 0), + +/* 16 dummy rates (same as 15 3) */ +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), +O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0), + +}; +#undef O + + +/* multiple table */ +#define ML 2 +static const UINT8 mul_tab[16]= { +/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */ + 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, + 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML +}; +#undef ML + +/* TL_TAB_LEN is calculated as: + +* (12+1)=13 - sinus amplitude bits (Y axis) +* additional 1: to compensate for calculations of negative part of waveform +* (if we don't add it then the greatest possible _negative_ value would be -2 +* and we really need -1 for waveform #7) +* 2 - sinus sign bit (Y axis) +* TL_RES_LEN - sinus resolution (X axis) +*/ +#define TL_TAB_LEN (13*2*TL_RES_LEN) +static signed int tl_tab[TL_TAB_LEN]; + +#define ENV_QUIET (TL_TAB_LEN>>4) + +/* sin waveform table in 'decibel' scale */ +/* there are eight waveforms on OPL3 chips */ +static unsigned int sin_tab[SIN_LEN * 8]; + + +/* LFO Amplitude Modulation table (verified on real YM3812) + 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples + + Length: 210 elements. + + Each of the elements has to be repeated + exactly 64 times (on 64 consecutive samples). + The whole table takes: 64 * 210 = 13440 samples. + + When AM = 1 data is used directly + When AM = 0 data is divided by 4 before being used (loosing precision is important) +*/ + +#define LFO_AM_TAB_ELEMENTS 210 + +static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = { +0,0,0,0,0,0,0, +1,1,1,1, +2,2,2,2, +3,3,3,3, +4,4,4,4, +5,5,5,5, +6,6,6,6, +7,7,7,7, +8,8,8,8, +9,9,9,9, +10,10,10,10, +11,11,11,11, +12,12,12,12, +13,13,13,13, +14,14,14,14, +15,15,15,15, +16,16,16,16, +17,17,17,17, +18,18,18,18, +19,19,19,19, +20,20,20,20, +21,21,21,21, +22,22,22,22, +23,23,23,23, +24,24,24,24, +25,25,25,25, +26,26,26, +25,25,25,25, +24,24,24,24, +23,23,23,23, +22,22,22,22, +21,21,21,21, +20,20,20,20, +19,19,19,19, +18,18,18,18, +17,17,17,17, +16,16,16,16, +15,15,15,15, +14,14,14,14, +13,13,13,13, +12,12,12,12, +11,11,11,11, +10,10,10,10, +9,9,9,9, +8,8,8,8, +7,7,7,7, +6,6,6,6, +5,5,5,5, +4,4,4,4, +3,3,3,3, +2,2,2,2, +1,1,1,1 +}; + +/* LFO Phase Modulation table (verified on real YM3812) */ +static const INT8 lfo_pm_table[8*8*2] = { + +/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */ +0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */ +1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */ +2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/ +5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/ + +/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */ +3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/ +7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/ +}; + + +/* lock level of common table */ +static int num_lock = 0; + +/* work table */ +static void *cur_chip = NULL; /* current chip point */ +static OPL3_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2; + +static signed int phase_modulation; /* phase modulation input (SLOT 2) */ +static signed int phase_modulation2; /* phase modulation input (SLOT 3 in 4 operator channels) */ +static signed int chanout[18]; /* 18 channels */ + + +static UINT32 LFO_AM; +static INT32 LFO_PM; + + + +INLINE int limit( int val, int max, int min ) { + if ( val > max ) + val = max; + else if ( val < min ) + val = min; + + return val; +} + + +/* status set and IRQ handling */ +INLINE void OPL3_STATUS_SET(OPL3 *chip,int flag) +{ + /* set status flag masking out disabled IRQs */ + chip->status |= (flag & chip->statusmask); + if(!(chip->status & 0x80)) + { + if(chip->status & 0x7f) + { /* IRQ on */ + chip->status |= 0x80; + /* callback user interrupt handler (IRQ is OFF to ON) */ + if(chip->IRQHandler) (chip->IRQHandler)(chip->IRQParam,1); + } + } + pclog("Set %i %02X\n",flag,chip->status); +} + +/* status reset and IRQ handling */ +INLINE void OPL3_STATUS_RESET(OPL3 *chip,int flag) +{ + /* reset status flag */ + chip->status &= ~flag; + if(chip->status & 0x80) + { + if (!(chip->status & 0x7f)) + { + chip->status &= 0x7f; + /* callback user interrupt handler (IRQ is ON to OFF) */ + if(chip->IRQHandler) (chip->IRQHandler)(chip->IRQParam,0); + } + } + pclog("Reset %i %02X\n",flag,chip->status); +} + +/* IRQ mask set */ +INLINE void OPL3_STATUSMASK_SET(OPL3 *chip,int flag) +{ + chip->statusmask = flag; + /* IRQ handling check */ + OPL3_STATUS_SET(chip,0); + OPL3_STATUS_RESET(chip,0); +} + + +/* advance LFO to next sample */ +INLINE void advance_lfo(OPL3 *chip) +{ + UINT8 tmp; + + /* LFO */ + chip->lfo_am_cnt += chip->lfo_am_inc; + if (chip->lfo_am_cnt >= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt -= ((UINT32)LFO_AM_TAB_ELEMENTS<lfo_am_cnt >> LFO_SH ]; + + if (chip->lfo_am_depth) + LFO_AM = tmp; + else + LFO_AM = tmp>>2; + + chip->lfo_pm_cnt += chip->lfo_pm_inc; + LFO_PM = ((chip->lfo_pm_cnt>>LFO_SH) & 7) | chip->lfo_pm_depth_range; +} + +/* advance to next sample */ +INLINE void advance(OPL3 *chip) +{ + OPL3_CH *CH; + OPL3_SLOT *op; + int i; + + chip->eg_timer += chip->eg_timer_add; + + while (chip->eg_timer >= chip->eg_timer_overflow) + { + chip->eg_timer -= chip->eg_timer_overflow; + + chip->eg_cnt++; + + for (i=0; i<9*2*2; i++) + { + CH = &chip->P_CH[i/2]; + op = &CH->SLOT[i&1]; +#if 1 + /* Envelope Generator */ + switch(op->state) + { + case EG_ATT: /* attack phase */ +// if ( !(chip->eg_cnt & ((1<eg_sh_ar)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_ar) ) + { + op->volume += (~op->volume * + (eg_inc[op->eg_sel_ar + ((chip->eg_cnt>>op->eg_sh_ar)&7)]) + ) >>3; + + if (op->volume <= MIN_ATT_INDEX) + { + op->volume = MIN_ATT_INDEX; + op->state = EG_DEC; + } + + } + break; + + case EG_DEC: /* decay phase */ +// if ( !(chip->eg_cnt & ((1<eg_sh_dr)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_dr) ) + { + op->volume += eg_inc[op->eg_sel_dr + ((chip->eg_cnt>>op->eg_sh_dr)&7)]; + + if ( op->volume >= op->sl ) + op->state = EG_SUS; + + } + break; + + case EG_SUS: /* sustain phase */ + + /* this is important behaviour: + one can change percusive/non-percussive modes on the fly and + the chip will remain in sustain phase - verified on real YM3812 */ + + if(op->eg_type) /* non-percussive mode */ + { + /* do nothing */ + } + else /* percussive mode */ + { + /* during sustain phase chip adds Release Rate (in percussive mode) */ +// if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_rr) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + op->volume = MAX_ATT_INDEX; + } + /* else do nothing in sustain phase */ + } + break; + + case EG_REL: /* release phase */ +// if ( !(chip->eg_cnt & ((1<eg_sh_rr)-1) ) ) + if ( !(chip->eg_cnt & op->eg_m_rr) ) + { + op->volume += eg_inc[op->eg_sel_rr + ((chip->eg_cnt>>op->eg_sh_rr)&7)]; + + if ( op->volume >= MAX_ATT_INDEX ) + { + op->volume = MAX_ATT_INDEX; + op->state = EG_OFF; + } + + } + break; + + default: + break; + } +#endif + } + } + + for (i=0; i<9*2*2; i++) + { + CH = &chip->P_CH[i/2]; + op = &CH->SLOT[i&1]; + + /* Phase Generator */ + if(op->vib) + { + UINT8 block; + unsigned int block_fnum = CH->block_fnum; + + unsigned int fnum_lfo = (block_fnum&0x0380) >> 7; + + signed int lfo_fn_table_index_offset = lfo_pm_table[LFO_PM + 16*fnum_lfo ]; + + if (lfo_fn_table_index_offset) /* LFO phase modulation active */ + { + block_fnum += lfo_fn_table_index_offset; + block = (block_fnum&0x1c00) >> 10; + op->Cnt += (chip->fn_tab[block_fnum&0x03ff] >> (7-block)) * op->mul; + } + else /* LFO phase modulation = zero */ + { + op->Cnt += op->Incr; + } + } + else /* LFO phase modulation disabled for this operator */ + { + op->Cnt += op->Incr; + } + } + + /* The Noise Generator of the YM3812 is 23-bit shift register. + * Period is equal to 2^23-2 samples. + * Register works at sampling frequency of the chip, so output + * can change on every sample. + * + * Output of the register and input to the bit 22 is: + * bit0 XOR bit14 XOR bit15 XOR bit22 + * + * Simply use bit 22 as the noise output. + */ + + chip->noise_p += chip->noise_f; + i = chip->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */ + chip->noise_p &= FREQ_MASK; + while (i) + { + /* + UINT32 j; + j = ( (chip->noise_rng) ^ (chip->noise_rng>>14) ^ (chip->noise_rng>>15) ^ (chip->noise_rng>>22) ) & 1; + chip->noise_rng = (j<<22) | (chip->noise_rng>>1); + */ + + /* + Instead of doing all the logic operations above, we + use a trick here (and use bit 0 as the noise output). + The difference is only that the noise bit changes one + step ahead. This doesn't matter since we don't know + what is real state of the noise_rng after the reset. + */ + + if (chip->noise_rng & 1) chip->noise_rng ^= 0x800302; + chip->noise_rng >>= 1; + + i--; + } +} + + +INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + +INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab) +{ + UINT32 p; + + p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm))>>FREQ_SH) & SIN_MASK)]; + + if (p >= TL_TAB_LEN) + return 0; + return tl_tab[p]; +} + + +#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask)) + +/* calculate output of a standard 2 operator channel + (or 1st part of a 4-op channel) */ +INLINE void chan_calc( OPL3_CH *CH ) +{ + OPL3_SLOT *SLOT; + unsigned int env; + signed int out; + + phase_modulation = 0; + phase_modulation2= 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + *SLOT->connect += SLOT->op1_out[1]; +//logerror("out0=%5i vol0=%4i ", SLOT->op1_out[1], env ); + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + *SLOT->connect += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); + +//logerror("out1=%5i vol1=%4i\n", op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable), env ); + +} + +/* calculate output of a 2nd part of 4-op channel */ +INLINE void chan_calc_ext( OPL3_CH *CH ) +{ + OPL3_SLOT *SLOT; + unsigned int env; + + phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH->SLOT[SLOT1]; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + *SLOT->connect += op_calc(SLOT->Cnt, env, phase_modulation2, SLOT->wavetable ); + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + *SLOT->connect += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable); + +} + +/* + operators used in the rhythm sounds generation process: + + Envelope Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal + 6 / 0 12 50 70 90 f0 + + 6 / 1 15 53 73 93 f3 + + 7 / 0 13 51 71 91 f1 + + 7 / 1 16 54 74 94 f4 + + 8 / 0 14 52 72 92 f2 + + 8 / 1 17 55 75 95 f5 + + + Phase Generator: + +channel operator register number Bass High Snare Tom Top +/ slot number MULTIPLE Drum Hat Drum Tom Cymbal + 6 / 0 12 30 + + 6 / 1 15 33 + + 7 / 0 13 31 + + + + 7 / 1 16 34 ----- n o t u s e d ----- + 8 / 0 14 32 + + 8 / 1 17 35 + + + +channel operator register number Bass High Snare Tom Top +number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal + 6 12,15 B6 A6 + + + 7 13,16 B7 A7 + + + + + 8 14,17 B8 A8 + + + + +*/ + +/* calculate rhythm */ + +INLINE void chan_calc_rhythm( OPL3_CH *CH, unsigned int noise ) +{ + OPL3_SLOT *SLOT; + signed int out; + unsigned int env; + + + /* Bass Drum (verified on real YM3812): + - depends on the channel 6 'connect' register: + when connect = 0 it works the same as in normal (non-rhythm) mode (op1->op2->out) + when connect = 1 _only_ operator 2 is present on output (op2->out), operator 1 is ignored + - output sample always is multiplied by 2 + */ + + phase_modulation = 0; + + /* SLOT 1 */ + SLOT = &CH[6].SLOT[SLOT1]; + env = volume_calc(SLOT); + + out = SLOT->op1_out[0] + SLOT->op1_out[1]; + SLOT->op1_out[0] = SLOT->op1_out[1]; + + if (!SLOT->CON) + phase_modulation = SLOT->op1_out[0]; + //else ignore output of operator 1 + + SLOT->op1_out[1] = 0; + if( env < ENV_QUIET ) + { + if (!SLOT->FB) + out = 0; + SLOT->op1_out[1] = op_calc1(SLOT->Cnt, env, (out<FB), SLOT->wavetable ); + } + + /* SLOT 2 */ + SLOT++; + env = volume_calc(SLOT); + if( env < ENV_QUIET ) + chanout[6] += op_calc(SLOT->Cnt, env, phase_modulation, SLOT->wavetable) * 2; + + + /* Phase generation is based on: */ + // HH (13) channel 7->slot 1 combined with channel 8->slot 2 (same combination as TOP CYMBAL but different output phases) + // SD (16) channel 7->slot 1 + // TOM (14) channel 8->slot 1 + // TOP (17) channel 7->slot 1 combined with channel 8->slot 2 (same combination as HIGH HAT but different output phases) + + /* Envelope generation based on: */ + // HH channel 7->slot1 + // SD channel 7->slot2 + // TOM channel 8->slot1 + // TOP channel 8->slot2 + + + /* The following formulas can be well optimized. + I leave them in direct form for now (in case I've missed something). + */ + + /* High Hat (verified on real YM3812) */ + env = volume_calc(SLOT7_1); + if( env < ENV_QUIET ) + { + + /* high hat phase generation: + phase = d0 or 234 (based on frequency only) + phase = 34 or 2d0 (based on noise) + */ + + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0xd0; */ + /* when res1 = 1 phase = 0x200 | (0xd0>>2); */ + UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | (0xd0>>2); */ + if (res2) + phase = (0x200|(0xd0>>2)); + + + /* when phase & 0x200 is set and noise=1 then phase = 0x200|0xd0 */ + /* when phase & 0x200 is set and noise=0 then phase = 0x200|(0xd0>>2), ie no change */ + if (phase&0x200) + { + if (noise) + phase = 0x200|0xd0; + } + else + /* when phase & 0x200 is clear and noise=1 then phase = 0xd0>>2 */ + /* when phase & 0x200 is clear and noise=0 then phase = 0xd0, ie no change */ + { + if (noise) + phase = 0xd0>>2; + } + + chanout[7] += op_calc(phase<wavetable) * 2; + } + + /* Snare Drum (verified on real YM3812) */ + env = volume_calc(SLOT7_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit8 = ((SLOT7_1->Cnt>>FREQ_SH)>>8)&1; + + /* when bit8 = 0 phase = 0x100; */ + /* when bit8 = 1 phase = 0x200; */ + UINT32 phase = bit8 ? 0x200 : 0x100; + + /* Noise bit XOR'es phase by 0x100 */ + /* when noisebit = 0 pass the phase from calculation above */ + /* when noisebit = 1 phase ^= 0x100; */ + /* in other words: phase ^= (noisebit<<8); */ + if (noise) + phase ^= 0x100; + + chanout[7] += op_calc(phase<wavetable) * 2; + } + + /* Tom Tom (verified on real YM3812) */ + env = volume_calc(SLOT8_1); + if( env < ENV_QUIET ) + chanout[8] += op_calc(SLOT8_1->Cnt, env, 0, SLOT8_1->wavetable) * 2; + + /* Top Cymbal (verified on real YM3812) */ + env = volume_calc(SLOT8_2); + if( env < ENV_QUIET ) + { + /* base frequency derived from operator 1 in channel 7 */ + unsigned char bit7 = ((SLOT7_1->Cnt>>FREQ_SH)>>7)&1; + unsigned char bit3 = ((SLOT7_1->Cnt>>FREQ_SH)>>3)&1; + unsigned char bit2 = ((SLOT7_1->Cnt>>FREQ_SH)>>2)&1; + + unsigned char res1 = (bit2 ^ bit7) | bit3; + + /* when res1 = 0 phase = 0x000 | 0x100; */ + /* when res1 = 1 phase = 0x200 | 0x100; */ + UINT32 phase = res1 ? 0x300 : 0x100; + + /* enable gate based on frequency of operator 2 in channel 8 */ + unsigned char bit5e= ((SLOT8_2->Cnt>>FREQ_SH)>>5)&1; + unsigned char bit3e= ((SLOT8_2->Cnt>>FREQ_SH)>>3)&1; + + unsigned char res2 = (bit3e ^ bit5e); + /* when res2 = 0 pass the phase from calculation above (res1); */ + /* when res2 = 1 phase = 0x200 | 0x100; */ + if (res2) + phase = 0x300; + + chanout[8] += op_calc(phase<wavetable) * 2; + } + +} + + +/* generic table initialize */ +static int init_tables(void) +{ + signed int i,x; + signed int n; + double o,m; + + + for (x=0; x>= 4; /* 12 bits here */ + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + /* 11 bits here (rounded) */ + n <<= 1; /* 12 bits here (as in real chip) */ + tl_tab[ x*2 + 0 ] = n; + tl_tab[ x*2 + 1 ] = ~tl_tab[ x*2 + 0 ]; /* this *is* different from OPL2 (verified on real YMF262) */ + + for (i=1; i<13; i++) + { + tl_tab[ x*2+0 + i*2*TL_RES_LEN ] = tl_tab[ x*2+0 ]>>i; + tl_tab[ x*2+1 + i*2*TL_RES_LEN ] = ~tl_tab[ x*2+0 + i*2*TL_RES_LEN ]; /* this *is* different from OPL2 (verified on real YMF262) */ + } + #if 0 + logerror("tl %04i", x*2); + for (i=0; i<13; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 +0 + i*2*TL_RES_LEN ] ); /* positive */ + logerror("\n"); + + logerror("tl %04i", x*2); + for (i=0; i<13; i++) + logerror(", [%02i] %5i", i*2, tl_tab[ x*2 +1 + i*2*TL_RES_LEN ] ); /* negative */ + logerror("\n"); + #endif + } + + for (i=0; i0.0) + o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */ + else + o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */ + + o = o / (ENV_STEP/4); + + n = (int)(2.0*o); + if (n&1) /* round to nearest */ + n = (n>>1)+1; + else + n = n>>1; + + sin_tab[ i ] = n*2 + (m>=0.0? 0: 1 ); + + /*logerror("YMF262.C: sin [%4i (hex=%03x)]= %4i (tl_tab value=%5i)\n", i, i, sin_tab[i], tl_tab[sin_tab[i]] );*/ + } + + for (i=0; i>1) ]; + + /* waveform 3: _ _ _ _ */ + /* / |_/ |_/ |_/ |_*/ + /* abs(output only first quarter of the sinus waveform) */ + + if (i & (1<<(SIN_BITS-2)) ) + sin_tab[3*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[3*SIN_LEN+i] = sin_tab[i & (SIN_MASK>>2)]; + + /* waveform 4: */ + /* /\ ____/\ ____*/ + /* \/ \/ */ + /* output whole sinus waveform in half the cycle(step=2) and output 0 on the other half of cycle */ + + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[4*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[4*SIN_LEN+i] = sin_tab[i*2]; + + /* waveform 5: */ + /* /\/\____/\/\____*/ + /* */ + /* output abs(whole sinus) waveform in half the cycle(step=2) and output 0 on the other half of cycle */ + + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[5*SIN_LEN+i] = TL_TAB_LEN; + else + sin_tab[5*SIN_LEN+i] = sin_tab[(i*2) & (SIN_MASK>>1) ]; + + /* waveform 6: ____ ____ */ + /* */ + /* ____ ____*/ + /* output maximum in half the cycle and output minimum on the other half of cycle */ + + if (i & (1<<(SIN_BITS-1)) ) + sin_tab[6*SIN_LEN+i] = 1; /* negative */ + else + sin_tab[6*SIN_LEN+i] = 0; /* positive */ + + /* waveform 7: */ + /* |\____ |\____ */ + /* \| \|*/ + /* output sawtooth waveform */ + + if (i & (1<<(SIN_BITS-1)) ) + x = ((SIN_LEN-1)-i)*16 + 1; /* negative: from 8177 to 1 */ + else + x = i*16; /*positive: from 0 to 8176 */ + + if (x > TL_TAB_LEN) + x = TL_TAB_LEN; /* clip to the allowed range */ + + sin_tab[7*SIN_LEN+i] = x; + + //logerror("YMF262.C: sin1[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[1*SIN_LEN+i], tl_tab[sin_tab[1*SIN_LEN+i]] ); + //logerror("YMF262.C: sin2[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[2*SIN_LEN+i], tl_tab[sin_tab[2*SIN_LEN+i]] ); + //logerror("YMF262.C: sin3[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[3*SIN_LEN+i], tl_tab[sin_tab[3*SIN_LEN+i]] ); + //logerror("YMF262.C: sin4[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[4*SIN_LEN+i], tl_tab[sin_tab[4*SIN_LEN+i]] ); + //logerror("YMF262.C: sin5[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[5*SIN_LEN+i], tl_tab[sin_tab[5*SIN_LEN+i]] ); + //logerror("YMF262.C: sin6[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[6*SIN_LEN+i], tl_tab[sin_tab[6*SIN_LEN+i]] ); + //logerror("YMF262.C: sin7[%4i]= %4i (tl_tab value=%5i)\n", i, sin_tab[7*SIN_LEN+i], tl_tab[sin_tab[7*SIN_LEN+i]] ); + } + /*logerror("YMF262.C: ENV_QUIET= %08x (dec*8=%i)\n", ENV_QUIET, ENV_QUIET*8 );*/ + +#ifdef SAVE_SAMPLE + sample[0]=fopen("sampsum.pcm","wb"); +#endif + + return 1; +} + +static void OPLCloseTable( void ) +{ +#ifdef SAVE_SAMPLE + fclose(sample[0]); +#endif +} + + + +static void OPL3_initalize(OPL3 *chip) +{ + int i; + + /* frequency base */ + chip->freqbase = (chip->rate) ? ((double)chip->clock / (8.0*36)) / chip->rate : 0; +#if 0 + chip->rate = (double)chip->clock / (8.0*36); + chip->freqbase = 1.0; +#endif + + /* logerror("YMF262: freqbase=%f\n", chip->freqbase); */ + + /* Timer base time */ + chip->TimerBase = attotime_mul(ATTOTIME_IN_HZ(chip->clock), 8*36); + + /* make fnumber -> increment counter table */ + for( i=0 ; i < 1024 ; i++ ) + { + /* opn phase increment counter = 20bit */ + chip->fn_tab[i] = (UINT32)( (double)i * 64 * chip->freqbase * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */ +#if 0 + logerror("YMF262.C: fn_tab[%4i] = %08x (dec=%8i)\n", + i, chip->fn_tab[i]>>6, chip->fn_tab[i]>>6 ); +#endif + } + +#if 0 + for( i=0 ; i < 16 ; i++ ) + { + logerror("YMF262.C: sl_tab[%i] = %08x\n", + i, sl_tab[i] ); + } + for( i=0 ; i < 8 ; i++ ) + { + int j; + logerror("YMF262.C: ksl_tab[oct=%2i] =",i); + for (j=0; j<16; j++) + { + logerror("%08x ", ksl_tab[i*16+j] ); + } + logerror("\n"); + } +#endif + + + /* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */ + /* One entry from LFO_AM_TABLE lasts for 64 samples */ + chip->lfo_am_inc = (1.0 / 64.0 ) * (1<freqbase; + + /* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */ + chip->lfo_pm_inc = (1.0 / 1024.0) * (1<freqbase; + + /*logerror ("chip->lfo_am_inc = %8x ; chip->lfo_pm_inc = %8x\n", chip->lfo_am_inc, chip->lfo_pm_inc);*/ + + /* Noise generator: a step takes 1 sample */ + chip->noise_f = (1.0 / 1.0) * (1<freqbase; + + chip->eg_timer_add = (1<freqbase; + chip->eg_timer_overflow = ( 1 ) * (1<eg_timer_add, chip->eg_timer_overflow);*/ + +} + +INLINE void FM_KEYON(OPL3_SLOT *SLOT, UINT32 key_set) +{ + if( !SLOT->key ) + { + /* restart Phase Generator */ + SLOT->Cnt = 0; + /* phase -> Attack */ + SLOT->state = EG_ATT; + } + SLOT->key |= key_set; +} + +INLINE void FM_KEYOFF(OPL3_SLOT *SLOT, UINT32 key_clr) +{ + if( SLOT->key ) + { + SLOT->key &= key_clr; + + if( !SLOT->key ) + { + /* phase -> Release */ + if (SLOT->state>EG_REL) + SLOT->state = EG_REL; + } + } +} + +/* update phase increment counter of operator (also update the EG rates if necessary) */ +INLINE void CALC_FCSLOT(OPL3_CH *CH,OPL3_SLOT *SLOT) +{ + int ksr; + + /* (frequency) phase increment counter */ + SLOT->Incr = CH->fc * SLOT->mul; + ksr = CH->kcode >> SLOT->KSR; + + if( SLOT->ksr != ksr ) + { + SLOT->ksr = ksr; + + /* calculate envelope generator rates */ + if ((SLOT->ar + SLOT->ksr) < 16+60) + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_m_dr = (1<eg_sh_dr)-1; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_m_rr = (1<eg_sh_rr)-1; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; + } +} + +/* set multi,am,vib,EG-TYP,KSR,mul */ +INLINE void set_mul(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->mul = mul_tab[v&0x0f]; + SLOT->KSR = (v&0x10) ? 0 : 2; + SLOT->eg_type = (v&0x20); + SLOT->vib = (v&0x40); + SLOT->AMmask = (v&0x80) ? ~0 : 0; + + if (chip->OPL3_mode & 1) + { + int chan_no = slot/2; + + /* in OPL3 mode */ + //DO THIS: + //if this is one of the slots of 1st channel forming up a 4-op channel + //do normal operation + //else normal 2 operator function + //OR THIS: + //if this is one of the slots of 2nd channel forming up a 4-op channel + //update it using channel data of 1st channel of a pair + //else normal 2 operator function + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + /* normal */ + CALC_FCSLOT(CH,SLOT); + } + else + { + /* normal */ + CALC_FCSLOT(CH,SLOT); + } + break; + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + /* update this SLOT using frequency data for 1st channel of a pair */ + CALC_FCSLOT(CH-3,SLOT); + } + else + { + /* normal */ + CALC_FCSLOT(CH,SLOT); + } + break; + default: + /* normal */ + CALC_FCSLOT(CH,SLOT); + break; + } + } + else + { + /* in OPL2 mode */ + CALC_FCSLOT(CH,SLOT); + } +} + +/* set ksl & tl */ +INLINE void set_ksl_tl(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + int ksl = v>>6; /* 0 / 1.5 / 3.0 / 6.0 dB/OCT */ + + SLOT->ksl = ksl ? 3-ksl : 31; + SLOT->TL = (v&0x3f)<<(ENV_BITS-1-7); /* 7 bits TL (bit 6 = always 0) */ + + if (chip->OPL3_mode & 1) + { + int chan_no = slot/2; + + /* in OPL3 mode */ + //DO THIS: + //if this is one of the slots of 1st channel forming up a 4-op channel + //do normal operation + //else normal 2 operator function + //OR THIS: + //if this is one of the slots of 2nd channel forming up a 4-op channel + //update it using channel data of 1st channel of a pair + //else normal 2 operator function + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + else + { + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + break; + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + /* update this SLOT using frequency data for 1st channel of a pair */ + SLOT->TLL = SLOT->TL + ((CH-3)->ksl_base>>SLOT->ksl); + } + else + { + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + break; + default: + /* normal */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + break; + } + } + else + { + /* in OPL2 mode */ + SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); + } + +} + +/* set attack rate & decay rate */ +INLINE void set_ar_dr(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->ar = (v>>4) ? 16 + ((v>>4) <<2) : 0; + + if ((SLOT->ar + SLOT->ksr) < 16+60) /* verified on real YMF262 - all 15 x rates take "zero" time */ + { + SLOT->eg_sh_ar = eg_rate_shift [SLOT->ar + SLOT->ksr ]; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = eg_rate_select[SLOT->ar + SLOT->ksr ]; + } + else + { + SLOT->eg_sh_ar = 0; + SLOT->eg_m_ar = (1<eg_sh_ar)-1; + SLOT->eg_sel_ar = 13*RATE_STEPS; + } + + SLOT->dr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_dr = eg_rate_shift [SLOT->dr + SLOT->ksr ]; + SLOT->eg_m_dr = (1<eg_sh_dr)-1; + SLOT->eg_sel_dr = eg_rate_select[SLOT->dr + SLOT->ksr ]; +} + +/* set sustain level & release rate */ +INLINE void set_sl_rr(OPL3 *chip,int slot,int v) +{ + OPL3_CH *CH = &chip->P_CH[slot/2]; + OPL3_SLOT *SLOT = &CH->SLOT[slot&1]; + + SLOT->sl = sl_tab[ v>>4 ]; + + SLOT->rr = (v&0x0f)? 16 + ((v&0x0f)<<2) : 0; + SLOT->eg_sh_rr = eg_rate_shift [SLOT->rr + SLOT->ksr ]; + SLOT->eg_m_rr = (1<eg_sh_rr)-1; + SLOT->eg_sel_rr = eg_rate_select[SLOT->rr + SLOT->ksr ]; +} + + +static void update_channels(OPL3 *chip, OPL3_CH *CH) +{ + /* update channel passed as a parameter and a channel at CH+=3; */ + if (CH->extended) + { /* we've just switched to combined 4 operator mode */ + + } + else + { /* we've just switched to normal 2 operator mode */ + + } + +} + +/* write a value v to register r on OPL chip */ +static void OPL3WriteReg(OPL3 *chip, int r, int v) +{ + OPL3_CH *CH; + unsigned int ch_offset = 0; + int slot; + int block_fnum; + + + + if (LOG_CYM_FILE && (cymfile) && ((r&255)!=0) && (r!=255) ) + { + if (r>0xff) + fputc( (unsigned char)0xff, cymfile );/*mark writes to second register set*/ + + fputc( (unsigned char)r&0xff, cymfile ); + fputc( (unsigned char)v, cymfile ); + } + + if(r&0x100) + { + switch(r) + { + case 0x101: /* test register */ + return; + + case 0x104: /* 6 channels enable */ + { + UINT8 prev; + + CH = &chip->P_CH[0]; /* channel 0 */ + prev = CH->extended; + CH->extended = (v>>0) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 1 */ + prev = CH->extended; + CH->extended = (v>>1) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 2 */ + prev = CH->extended; + CH->extended = (v>>2) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + + + CH = &chip->P_CH[9]; /* channel 9 */ + prev = CH->extended; + CH->extended = (v>>3) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 10 */ + prev = CH->extended; + CH->extended = (v>>4) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + CH++; /* channel 11 */ + prev = CH->extended; + CH->extended = (v>>5) & 1; + if(prev != CH->extended) + update_channels(chip, CH); + + } + return; + + case 0x105: /* OPL3 extensions enable register */ + + chip->OPL3_mode = v&0x01; /* OPL3 mode when bit0=1 otherwise it is OPL2 mode */ + + /* following behaviour was tested on real YMF262, + switching OPL3/OPL2 modes on the fly: + - does not change the waveform previously selected (unless when ....) + - does not update CH.A, CH.B, CH.C and CH.D output selectors (registers c0-c8) (unless when ....) + - does not disable channels 9-17 on OPL3->OPL2 switch + - does not switch 4 operator channels back to 2 operator channels + */ + + return; + + default: + if (r < 0x120) + pclog("YMF262: write to unknown register (set#2): %03x value=%02x\n",r,v); + break; + } + + ch_offset = 9; /* register page #2 starts from channel 9 (counting from 0) */ + } + + /* adjust bus to 8 bits */ + r &= 0xff; + v &= 0xff; + + + switch(r&0xe0) + { + case 0x00: /* 00-1f:control */ + switch(r&0x1f) + { + case 0x01: /* test register */ + break; + case 0x02: /* Timer 1 */ + chip->T[0] = (256-v)*4; + break; + case 0x03: /* Timer 2 */ + chip->T[1] = (256-v)*16; + break; + case 0x04: /* IRQ clear / mask and Timer enable */ + if(v&0x80) + { /* IRQ flags clear */ + OPL3_STATUS_RESET(chip,0x60); + } + else + { /* set IRQ mask ,timer enable */ + UINT8 st1 = v & 1; + UINT8 st2 = (v>>1) & 1; + + /* IRQRST,T1MSK,t2MSK,x,x,x,ST2,ST1 */ + OPL3_STATUS_RESET(chip, v & 0x60); + OPL3_STATUSMASK_SET(chip, (~v) & 0x60 ); + + /* timer 2 */ + if(chip->st[1] != st2) + { + attotime period = st2 ? attotime_mul(chip->TimerBase, chip->T[1]) : attotime_zero; + chip->st[1] = st2; + if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,1,period); + } + /* timer 1 */ + if(chip->st[0] != st1) + { + attotime period = st1 ? attotime_mul(chip->TimerBase, chip->T[0]) : attotime_zero; + chip->st[0] = st1; + if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,0,period); + } + } + break; + case 0x08: /* x,NTS,x,x, x,x,x,x */ + chip->nts = v; + break; + + default: + pclog("YMF262: write to unknown register: %02x value=%02x\n",r,v); + break; + } + break; + case 0x20: /* am ON, vib ON, ksr, eg_type, mul */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_mul(chip, slot + ch_offset*2, v); + break; + case 0x40: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ksl_tl(chip, slot + ch_offset*2, v); + break; + case 0x60: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_ar_dr(chip, slot + ch_offset*2, v); + break; + case 0x80: + slot = slot_array[r&0x1f]; + if(slot < 0) return; + set_sl_rr(chip, slot + ch_offset*2, v); + break; + case 0xa0: + if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */ + { + if (ch_offset != 0) /* 0xbd register is present in set #1 only */ + return; + + chip->lfo_am_depth = v & 0x80; + chip->lfo_pm_depth_range = (v&0x40) ? 8 : 0; + + chip->rhythm = v&0x3f; + + if(chip->rhythm&0x20) + { + /* BD key on/off */ + if(v&0x10) + { + FM_KEYON (&chip->P_CH[6].SLOT[SLOT1], 2); + FM_KEYON (&chip->P_CH[6].SLOT[SLOT2], 2); + } + else + { + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT2],~2); + } + /* HH key on/off */ + if(v&0x01) FM_KEYON (&chip->P_CH[7].SLOT[SLOT1], 2); + else FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key on/off */ + if(v&0x08) FM_KEYON (&chip->P_CH[7].SLOT[SLOT2], 2); + else FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key on/off */ + if(v&0x04) FM_KEYON (&chip->P_CH[8].SLOT[SLOT1], 2); + else FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY key on/off */ + if(v&0x02) FM_KEYON (&chip->P_CH[8].SLOT[SLOT2], 2); + else FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + else + { + /* BD key off */ + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT1],~2); + FM_KEYOFF(&chip->P_CH[6].SLOT[SLOT2],~2); + /* HH key off */ + FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT1],~2); + /* SD key off */ + FM_KEYOFF(&chip->P_CH[7].SLOT[SLOT2],~2); + /* TOM key off */ + FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT1],~2); + /* TOP-CY off */ + FM_KEYOFF(&chip->P_CH[8].SLOT[SLOT2],~2); + } + return; + } + + /* keyon,block,fnum */ + if( (r&0x0f) > 8) return; + CH = &chip->P_CH[(r&0x0f) + ch_offset]; + + if(!(r&0x10)) + { /* a0-a8 */ + block_fnum = (CH->block_fnum&0x1f00) | v; + } + else + { /* b0-b8 */ + block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); + + if (chip->OPL3_mode & 1) + { + int chan_no = (r&0x0f) + ch_offset; + + /* in OPL3 mode */ + //DO THIS: + //if this is 1st channel forming up a 4-op channel + //ALSO keyon/off slots of 2nd channel forming up 4-op channel + //else normal 2 operator function keyon/off + //OR THIS: + //if this is 2nd channel forming up 4-op channel just do nothing + //else normal 2 operator function keyon/off + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + //if this is 1st channel forming up a 4-op channel + //ALSO keyon/off slots of 2nd channel forming up 4-op channel + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + FM_KEYON (&(CH+3)->SLOT[SLOT1], 1); + FM_KEYON (&(CH+3)->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + FM_KEYOFF(&(CH+3)->SLOT[SLOT1],~1); + FM_KEYOFF(&(CH+3)->SLOT[SLOT2],~1); + } + } + else + { + //else normal 2 operator function keyon/off + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + break; + + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + //if this is 2nd channel forming up 4-op channel just do nothing + } + else + { + //else normal 2 operator function keyon/off + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + break; + + default: + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + break; + } + } + else + { + if(v&0x20) + { + FM_KEYON (&CH->SLOT[SLOT1], 1); + FM_KEYON (&CH->SLOT[SLOT2], 1); + } + else + { + FM_KEYOFF(&CH->SLOT[SLOT1],~1); + FM_KEYOFF(&CH->SLOT[SLOT2],~1); + } + } + } + /* update */ + if(CH->block_fnum != block_fnum) + { + UINT8 block = block_fnum >> 10; + + CH->block_fnum = block_fnum; + + CH->ksl_base = ksl_tab[block_fnum>>6]; + CH->fc = chip->fn_tab[block_fnum&0x03ff] >> (7-block); + + /* BLK 2,1,0 bits -> bits 3,2,1 of kcode */ + CH->kcode = (CH->block_fnum&0x1c00)>>9; + + /* the info below is actually opposite to what is stated in the Manuals (verifed on real YMF262) */ + /* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */ + /* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */ + if (chip->nts&0x40) + CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */ + else + CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */ + + if (chip->OPL3_mode & 1) + { + int chan_no = (r&0x0f) + ch_offset; + /* in OPL3 mode */ + //DO THIS: + //if this is 1st channel forming up a 4-op channel + //ALSO update slots of 2nd channel forming up 4-op channel + //else normal 2 operator function keyon/off + //OR THIS: + //if this is 2nd channel forming up 4-op channel just do nothing + //else normal 2 operator function keyon/off + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + //if this is 1st channel forming up a 4-op channel + //ALSO update slots of 2nd channel forming up 4-op channel + + /* refresh Total Level in FOUR SLOTs of this channel and channel+3 using data from THIS channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + (CH+3)->SLOT[SLOT1].TLL = (CH+3)->SLOT[SLOT1].TL + (CH->ksl_base>>(CH+3)->SLOT[SLOT1].ksl); + (CH+3)->SLOT[SLOT2].TLL = (CH+3)->SLOT[SLOT2].TL + (CH->ksl_base>>(CH+3)->SLOT[SLOT2].ksl); + + /* refresh frequency counter in FOUR SLOTs of this channel and channel+3 using data from THIS channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + CALC_FCSLOT(CH,&(CH+3)->SLOT[SLOT1]); + CALC_FCSLOT(CH,&(CH+3)->SLOT[SLOT2]); + } + else + { + //else normal 2 operator function + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + //if this is 2nd channel forming up 4-op channel just do nothing + } + else + { + //else normal 2 operator function + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + break; + + default: + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + break; + } + } + else + { + /* in OPL2 mode */ + + /* refresh Total Level in both SLOTs of this channel */ + CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl); + CH->SLOT[SLOT2].TLL = CH->SLOT[SLOT2].TL + (CH->ksl_base>>CH->SLOT[SLOT2].ksl); + + /* refresh frequency counter in both SLOTs of this channel */ + CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); + CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); + } + } + break; + + case 0xc0: + /* CH.D, CH.C, CH.B, CH.A, FB(3bits), C */ + if( (r&0xf) > 8) return; + + CH = &chip->P_CH[(r&0xf) + ch_offset]; + + if( chip->OPL3_mode & 1 ) + { + int base = ((r&0xf) + ch_offset) * 4; + + /* OPL3 mode */ + chip->pan[ base ] = (v & 0x10) ? ~0 : 0; /* ch.A */ + chip->pan[ base +1 ] = (v & 0x20) ? ~0 : 0; /* ch.B */ + chip->pan[ base +2 ] = (v & 0x40) ? ~0 : 0; /* ch.C */ + chip->pan[ base +3 ] = (v & 0x80) ? ~0 : 0; /* ch.D */ + } + else + { + int base = ((r&0xf) + ch_offset) * 4; + + /* OPL2 mode - always enabled */ + chip->pan[ base ] = ~0; /* ch.A */ + chip->pan[ base +1 ] = ~0; /* ch.B */ + chip->pan[ base +2 ] = ~0; /* ch.C */ + chip->pan[ base +3 ] = ~0; /* ch.D */ + } + + chip->pan_ctrl_value[ (r&0xf) + ch_offset ] = v; /* store control value for OPL3/OPL2 mode switching on the fly */ + + CH->SLOT[SLOT1].FB = (v>>1)&7 ? ((v>>1)&7) + 7 : 0; + CH->SLOT[SLOT1].CON = v&1; + + if( chip->OPL3_mode & 1 ) + { + int chan_no = (r&0x0f) + ch_offset; + + switch(chan_no) + { + case 0: case 1: case 2: + case 9: case 10: case 11: + if (CH->extended) + { + UINT8 conn = (CH->SLOT[SLOT1].CON<<1) || ((CH+3)->SLOT[SLOT1].CON<<0); + switch(conn) + { + case 0: + /* 1 -> 2 -> 3 -> 4 - out */ + + CH->SLOT[SLOT1].connect = &phase_modulation; + CH->SLOT[SLOT2].connect = &phase_modulation2; + (CH+3)->SLOT[SLOT1].connect = &phase_modulation; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + case 1: + /* 1 -> 2 -\ + 3 -> 4 -+- out */ + + CH->SLOT[SLOT1].connect = &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + (CH+3)->SLOT[SLOT1].connect = &phase_modulation; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + case 2: + /* 1 -----------\ + 2 -> 3 -> 4 -+- out */ + + CH->SLOT[SLOT1].connect = &chanout[ chan_no ]; + CH->SLOT[SLOT2].connect = &phase_modulation2; + (CH+3)->SLOT[SLOT1].connect = &phase_modulation; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + case 3: + /* 1 ------\ + 2 -> 3 -+- out + 4 ------/ */ + CH->SLOT[SLOT1].connect = &chanout[ chan_no ]; + CH->SLOT[SLOT2].connect = &phase_modulation2; + (CH+3)->SLOT[SLOT1].connect = &chanout[ chan_no + 3 ]; + (CH+3)->SLOT[SLOT2].connect = &chanout[ chan_no + 3 ]; + break; + } + } + else + { + /* 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + } + break; + + case 3: case 4: case 5: + case 12: case 13: case 14: + if ((CH-3)->extended) + { + UINT8 conn = ((CH-3)->SLOT[SLOT1].CON<<1) || (CH->SLOT[SLOT1].CON<<0); + switch(conn) + { + case 0: + /* 1 -> 2 -> 3 -> 4 - out */ + + (CH-3)->SLOT[SLOT1].connect = &phase_modulation; + (CH-3)->SLOT[SLOT2].connect = &phase_modulation2; + CH->SLOT[SLOT1].connect = &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + case 1: + /* 1 -> 2 -\ + 3 -> 4 -+- out */ + + (CH-3)->SLOT[SLOT1].connect = &phase_modulation; + (CH-3)->SLOT[SLOT2].connect = &chanout[ chan_no - 3 ]; + CH->SLOT[SLOT1].connect = &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + case 2: + /* 1 -----------\ + 2 -> 3 -> 4 -+- out */ + + (CH-3)->SLOT[SLOT1].connect = &chanout[ chan_no - 3 ]; + (CH-3)->SLOT[SLOT2].connect = &phase_modulation2; + CH->SLOT[SLOT1].connect = &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + case 3: + /* 1 ------\ + 2 -> 3 -+- out + 4 ------/ */ + (CH-3)->SLOT[SLOT1].connect = &chanout[ chan_no - 3 ]; + (CH-3)->SLOT[SLOT2].connect = &phase_modulation2; + CH->SLOT[SLOT1].connect = &chanout[ chan_no ]; + CH->SLOT[SLOT2].connect = &chanout[ chan_no ]; + break; + } + } + else + { + /* 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + } + break; + + default: + /* 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + break; + } + } + else + { + /* OPL2 mode - always 2 operators mode */ + CH->SLOT[SLOT1].connect = CH->SLOT[SLOT1].CON ? &chanout[(r&0xf)+ch_offset] : &phase_modulation; + CH->SLOT[SLOT2].connect = &chanout[(r&0xf)+ch_offset]; + } + break; + + case 0xe0: /* waveform select */ + slot = slot_array[r&0x1f]; + if(slot < 0) return; + + slot += ch_offset*2; + + CH = &chip->P_CH[slot/2]; + + + /* store 3-bit value written regardless of current OPL2 or OPL3 mode... (verified on real YMF262) */ + v &= 7; + CH->SLOT[slot&1].waveform_number = v; + + /* ... but select only waveforms 0-3 in OPL2 mode */ + if( !(chip->OPL3_mode & 1) ) + { + v &= 3; /* we're in OPL2 mode */ + } + CH->SLOT[slot&1].wavetable = v * SIN_LEN; + break; + } +} + +static TIMER_CALLBACK( cymfile_callback ) +{ + if (cymfile) + { + fputc( (unsigned char)0, cymfile ); + } +} + +/* lock/unlock for common table */ +static int OPL3_LockTable(running_device *device) +{ + num_lock++; + if(num_lock>1) return 0; + + /* first time */ + + cur_chip = NULL; + + if( !init_tables() ) + { + num_lock--; + return -1; + } +#if 0 + if (LOG_CYM_FILE) + { + cymfile = fopen("ymf262_.cym","wb"); + if (cymfile) + timer_pulse ( device->machine, ATTOTIME_IN_HZ(110), NULL, 0, cymfile_callback); /*110 Hz pulse timer*/ + else + logerror("Could not create ymf262_.cym file\n"); + } +#endif + return 0; +} + +static void OPL3_UnLockTable(void) +{ + if(num_lock) num_lock--; + if(num_lock) return; + + /* last time */ + + cur_chip = NULL; + OPLCloseTable(); + + if (LOG_CYM_FILE) + fclose (cymfile); + cymfile = NULL; +} + +static void OPL3ResetChip(OPL3 *chip) +{ + int c,s; + + chip->eg_timer = 0; + chip->eg_cnt = 0; + + chip->noise_rng = 1; /* noise shift register */ + chip->nts = 0; /* note split */ + OPL3_STATUS_RESET(chip,0x60); + + /* reset with register write */ + OPL3WriteReg(chip,0x01,0); /* test register */ + OPL3WriteReg(chip,0x02,0); /* Timer1 */ + OPL3WriteReg(chip,0x03,0); /* Timer2 */ + OPL3WriteReg(chip,0x04,0); /* IRQ mask clear */ + + +//FIX IT registers 101, 104 and 105 + + +//FIX IT (dont change CH.D, CH.C, CH.B and CH.A in C0-C8 registers) + for(c = 0xff ; c >= 0x20 ; c-- ) + OPL3WriteReg(chip,c,0); +//FIX IT (dont change CH.D, CH.C, CH.B and CH.A in C0-C8 registers) + for(c = 0x1ff ; c >= 0x120 ; c-- ) + OPL3WriteReg(chip,c,0); + + + + /* reset operator parameters */ + for( c = 0 ; c < 9*2 ; c++ ) + { + OPL3_CH *CH = &chip->P_CH[c]; + for(s = 0 ; s < 2 ; s++ ) + { + CH->SLOT[s].state = EG_OFF; + CH->SLOT[s].volume = MAX_ATT_INDEX; + } + } +} + +/* Create one of virtual YMF262 */ +/* 'clock' is chip clock in Hz */ +/* 'rate' is sampling rate */ +static OPL3 *OPL3Create(running_device *device, int clock, int rate, int type) +{ + OPL3 *chip; + + if (OPL3_LockTable(device) == -1) return NULL; + + /* allocate memory block */ + chip = (OPL3 *)malloc(sizeof(OPL3));//auto_alloc_clear(device->machine, OPL3); + memset(chip,0,sizeof(OPL3)); + + chip->device = device; + chip->type = type; + chip->clock = clock; + chip->rate = rate; + + /* init global tables */ + OPL3_initalize(chip); + + /* reset chip */ + OPL3ResetChip(chip); + return chip; +} + +/* Destroy one of virtual YMF262 */ +static void OPL3Destroy(OPL3 *chip) +{ + OPL3_UnLockTable(); + free(chip); +// auto_free(chip->device->machine, chip); +} + + +/* Optional handlers */ + +static void OPL3SetTimerHandler(OPL3 *chip,OPL3_TIMERHANDLER timer_handler,void *param) +{ + chip->timer_handler = timer_handler; + chip->TimerParam = param; +} +static void OPL3SetIRQHandler(OPL3 *chip,OPL3_IRQHANDLER IRQHandler,void *param) +{ + chip->IRQHandler = IRQHandler; + chip->IRQParam = param; +} +static void OPL3SetUpdateHandler(OPL3 *chip,OPL3_UPDATEHANDLER UpdateHandler,void *param) +{ + chip->UpdateHandler = UpdateHandler; + chip->UpdateParam = param; +} + +/* YMF262 I/O interface */ +static int OPL3Write(OPL3 *chip, int a, int v) +{ + /* data bus is 8 bits */ + v &= 0xff; + +// pclog("OPL3 write %04X %02X\n",a,v); + + switch(a&3) + { + case 0: /* address port 0 (register set #1) */ + chip->address = v; + break; + + case 1: /* data port - ignore A1 */ + case 3: /* data port - ignore A1 */ + if(chip->UpdateHandler) chip->UpdateHandler(chip->UpdateParam,0); + OPL3WriteReg(chip,chip->address,v); + break; + + case 2: /* address port 1 (register set #2) */ + + /* verified on real YMF262: + in OPL3 mode: + address line A1 is stored during *address* write and ignored during *data* write. + + in OPL2 mode: + register set#2 writes go to register set#1 (ignoring A1) + verified on registers from set#2: 0x01, 0x04, 0x20-0xef + The only exception is register 0x05. + */ + if( chip->OPL3_mode & 1 ) + { + /* OPL3 mode */ + chip->address = v | 0x100; + } + else + { + /* in OPL2 mode the only accessible in set #2 is register 0x05 */ + if( v==5 ) + chip->address = v | 0x100; + else + chip->address = v; /* verified range: 0x01, 0x04, 0x20-0xef(set #2 becomes set #1 in opl2 mode) */ + } + break; + } + + return chip->status>>7; +} + +static unsigned char OPL3Read(OPL3 *chip,int a) +{ + if( a==0 ) + { + /* status port */ + return chip->status; + } + + return 0x00; /* verified on real YMF262 */ +} + + + +static int OPL3TimerOver(OPL3 *chip,int c) +{ + if( c ) + { /* Timer B */ + OPL3_STATUS_SET(chip,0x20); + } + else + { /* Timer A */ + OPL3_STATUS_SET(chip,0x40); + } + /* reload timer */ + if (chip->timer_handler) (chip->timer_handler)(chip->TimerParam,c,attotime_mul(chip->TimerBase, chip->T[c])); + return chip->status>>7; +} + + + + +void * ymf262_init(running_device *device, int clock, int rate) +{ + return OPL3Create(device,clock,rate,OPL3_TYPE_YMF262); +} + +void ymf262_shutdown(void *chip) +{ + OPL3Destroy((OPL3 *)chip); +} +void ymf262_reset_chip(void *chip) +{ + OPL3ResetChip((OPL3 *)chip); +} + +int ymf262_write(void *chip, int a, int v) +{ + return OPL3Write((OPL3 *)chip, a, v); +} + +unsigned char ymf262_read(void *chip, int a) +{ + /* Note on status register: */ + + /* YM3526(OPL) and YM3812(OPL2) return bit2 and bit1 in HIGH state */ + + /* YMF262(OPL3) always returns bit2 and bit1 in LOW state */ + /* which can be used to identify the chip */ + + /* YMF278(OPL4) returns bit2 in LOW and bit1 in HIGH state ??? info from manual - not verified */ + + return OPL3Read((OPL3 *)chip, a&3); +} +int ymf262_timer_over(void *chip, int c) +{ + return OPL3TimerOver((OPL3 *)chip, c); +} + +void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER timer_handler, void *param) +{ + OPL3SetTimerHandler((OPL3 *)chip, timer_handler, param); +} +void ymf262_set_irq_handler(void *chip,OPL3_IRQHANDLER IRQHandler,void *param) +{ + OPL3SetIRQHandler((OPL3 *)chip, IRQHandler, param); +} +void ymf262_set_update_handler(void *chip,OPL3_UPDATEHANDLER UpdateHandler,void *param) +{ + OPL3SetUpdateHandler((OPL3 *)chip, UpdateHandler, param); +} + + +/* +** Generate samples for one of the YMF262's +** +** 'which' is the virtual YMF262 number +** '**buffers' is table of 4 pointers to the buffers: CH.A, CH.B, CH.C and CH.D +** 'length' is the number of samples that should be generated +*/ +void ymf262_update_one(void *_chip, OPL3SAMPLE **buffers, int length) +{ + OPL3 *chip = (OPL3 *)_chip; + UINT8 rhythm = chip->rhythm&0x20; + + OPL3SAMPLE *ch_a = buffers[0]; + OPL3SAMPLE *ch_b = buffers[1]; + OPL3SAMPLE *ch_c = buffers[2]; + OPL3SAMPLE *ch_d = buffers[3]; + + int i; + + if( (void *)chip != cur_chip ){ + cur_chip = (void *)chip; + /* rhythm slots */ + SLOT7_1 = &chip->P_CH[7].SLOT[SLOT1]; + SLOT7_2 = &chip->P_CH[7].SLOT[SLOT2]; + SLOT8_1 = &chip->P_CH[8].SLOT[SLOT1]; + SLOT8_2 = &chip->P_CH[8].SLOT[SLOT2]; + } + for( i=0; i < length ; i++ ) + { + int a,b,c,d; + + + advance_lfo(chip); + + /* clear channel outputs */ + memset(chanout, 0, sizeof(signed int) * 18); + +#if 1 + /* register set #1 */ + chan_calc(&chip->P_CH[0]); /* extended 4op ch#0 part 1 or 2op ch#0 */ + if (chip->P_CH[0].extended) + chan_calc_ext(&chip->P_CH[3]); /* extended 4op ch#0 part 2 */ + else + chan_calc(&chip->P_CH[3]); /* standard 2op ch#3 */ + + + chan_calc(&chip->P_CH[1]); /* extended 4op ch#1 part 1 or 2op ch#1 */ + if (chip->P_CH[1].extended) + chan_calc_ext(&chip->P_CH[4]); /* extended 4op ch#1 part 2 */ + else + chan_calc(&chip->P_CH[4]); /* standard 2op ch#4 */ + + + chan_calc(&chip->P_CH[2]); /* extended 4op ch#2 part 1 or 2op ch#2 */ + if (chip->P_CH[2].extended) + chan_calc_ext(&chip->P_CH[5]); /* extended 4op ch#2 part 2 */ + else + chan_calc(&chip->P_CH[5]); /* standard 2op ch#5 */ + + + if(!rhythm) + { + chan_calc(&chip->P_CH[6]); + chan_calc(&chip->P_CH[7]); + chan_calc(&chip->P_CH[8]); + } + else /* Rhythm part */ + { + chan_calc_rhythm(&chip->P_CH[0], (chip->noise_rng>>0)&1 ); + } + + /* register set #2 */ + chan_calc(&chip->P_CH[ 9]); + if (chip->P_CH[9].extended) + chan_calc_ext(&chip->P_CH[12]); + else + chan_calc(&chip->P_CH[12]); + + + chan_calc(&chip->P_CH[10]); + if (chip->P_CH[10].extended) + chan_calc_ext(&chip->P_CH[13]); + else + chan_calc(&chip->P_CH[13]); + + + chan_calc(&chip->P_CH[11]); + if (chip->P_CH[11].extended) + chan_calc_ext(&chip->P_CH[14]); + else + chan_calc(&chip->P_CH[14]); + + + /* channels 15,16,17 are fixed 2-operator channels only */ + chan_calc(&chip->P_CH[15]); + chan_calc(&chip->P_CH[16]); + chan_calc(&chip->P_CH[17]); +#endif + + /* accumulator register set #1 */ + a = chanout[0] & chip->pan[0]; + b = chanout[0] & chip->pan[1]; + c = chanout[0] & chip->pan[2]; + d = chanout[0] & chip->pan[3]; +#if 1 + a += chanout[1] & chip->pan[4]; + b += chanout[1] & chip->pan[5]; + c += chanout[1] & chip->pan[6]; + d += chanout[1] & chip->pan[7]; + a += chanout[2] & chip->pan[8]; + b += chanout[2] & chip->pan[9]; + c += chanout[2] & chip->pan[10]; + d += chanout[2] & chip->pan[11]; + + a += chanout[3] & chip->pan[12]; + b += chanout[3] & chip->pan[13]; + c += chanout[3] & chip->pan[14]; + d += chanout[3] & chip->pan[15]; + a += chanout[4] & chip->pan[16]; + b += chanout[4] & chip->pan[17]; + c += chanout[4] & chip->pan[18]; + d += chanout[4] & chip->pan[19]; + a += chanout[5] & chip->pan[20]; + b += chanout[5] & chip->pan[21]; + c += chanout[5] & chip->pan[22]; + d += chanout[5] & chip->pan[23]; + + a += chanout[6] & chip->pan[24]; + b += chanout[6] & chip->pan[25]; + c += chanout[6] & chip->pan[26]; + d += chanout[6] & chip->pan[27]; + a += chanout[7] & chip->pan[28]; + b += chanout[7] & chip->pan[29]; + c += chanout[7] & chip->pan[30]; + d += chanout[7] & chip->pan[31]; + a += chanout[8] & chip->pan[32]; + b += chanout[8] & chip->pan[33]; + c += chanout[8] & chip->pan[34]; + d += chanout[8] & chip->pan[35]; + + /* accumulator register set #2 */ + a += chanout[9] & chip->pan[36]; + b += chanout[9] & chip->pan[37]; + c += chanout[9] & chip->pan[38]; + d += chanout[9] & chip->pan[39]; + a += chanout[10] & chip->pan[40]; + b += chanout[10] & chip->pan[41]; + c += chanout[10] & chip->pan[42]; + d += chanout[10] & chip->pan[43]; + a += chanout[11] & chip->pan[44]; + b += chanout[11] & chip->pan[45]; + c += chanout[11] & chip->pan[46]; + d += chanout[11] & chip->pan[47]; + + a += chanout[12] & chip->pan[48]; + b += chanout[12] & chip->pan[49]; + c += chanout[12] & chip->pan[50]; + d += chanout[12] & chip->pan[51]; + a += chanout[13] & chip->pan[52]; + b += chanout[13] & chip->pan[53]; + c += chanout[13] & chip->pan[54]; + d += chanout[13] & chip->pan[55]; + a += chanout[14] & chip->pan[56]; + b += chanout[14] & chip->pan[57]; + c += chanout[14] & chip->pan[58]; + d += chanout[14] & chip->pan[59]; + + a += chanout[15] & chip->pan[60]; + b += chanout[15] & chip->pan[61]; + c += chanout[15] & chip->pan[62]; + d += chanout[15] & chip->pan[63]; + a += chanout[16] & chip->pan[64]; + b += chanout[16] & chip->pan[65]; + c += chanout[16] & chip->pan[66]; + d += chanout[16] & chip->pan[67]; + a += chanout[17] & chip->pan[68]; + b += chanout[17] & chip->pan[69]; + c += chanout[17] & chip->pan[70]; + d += chanout[17] & chip->pan[71]; +#endif + a >>= FINAL_SH; + b >>= FINAL_SH; + c >>= FINAL_SH; + d >>= FINAL_SH; + + /* limit check */ + a = limit( a , MAXOUT, MINOUT ); + b = limit( b , MAXOUT, MINOUT ); + c = limit( c , MAXOUT, MINOUT ); + d = limit( d , MAXOUT, MINOUT ); + + #ifdef SAVE_SAMPLE + if (which==0) + { + SAVE_ALL_CHANNELS + } + #endif + + /* store to sound buffer */ + ch_a[i] = a; + ch_b[i] = b; + ch_c[i] = c; + ch_d[i] = d; + + advance(chip); + } + +} + diff --git a/src/mame/ymf262.h b/src/mame/ymf262.h new file mode 100644 index 00000000..293d6746 --- /dev/null +++ b/src/mame/ymf262.h @@ -0,0 +1,62 @@ +#pragma once + +#ifndef __YMF262_H__ +#define __YMF262_H__ + +#ifndef STUFF +#define STUFF +typedef int64_t attotime; +#define ATTOTIME_IN_HZ(x) (1000000000/(x)) +#define attotime_mul(x,y) ((x)*(y)) +#define attotime_to_double(x) ((double)(x)/1000000000.0) +#define attotime_zero 0 + +#define running_device void +#define INLINE static +//#define M_PI 3.142 +#endif + +/* select number of output bits: 8 or 16 */ +#define OPL3_SAMPLE_BITS 16 + +/* compiler dependence */ +#ifndef __OSDCOMM_H__ +#define __OSDCOMM_H__ +typedef unsigned char UINT8; /* unsigned 8bit */ +typedef unsigned short UINT16; /* unsigned 16bit */ +typedef unsigned int UINT32; /* unsigned 32bit */ +typedef signed char INT8; /* signed 8bit */ +typedef signed short INT16; /* signed 16bit */ +typedef signed int INT32; /* signed 32bit */ +#endif + +typedef signed short OPL3SAMPLE; +//typedef stream_sample_t OPL3SAMPLE; +/* +#if (OPL3_SAMPLE_BITS==16) +typedef INT16 OPL3SAMPLE; +#endif +#if (OPL3_SAMPLE_BITS==8) +typedef INT8 OPL3SAMPLE; +#endif +*/ + +typedef void (*OPL3_TIMERHANDLER)(void *param,int timer,attotime period); +typedef void (*OPL3_IRQHANDLER)(void *param,int irq); +typedef void (*OPL3_UPDATEHANDLER)(void *param,int min_interval_us); + + +void *ymf262_init(running_device *device, int clock, int rate); +void ymf262_shutdown(void *chip); +void ymf262_reset_chip(void *chip); +int ymf262_write(void *chip, int a, int v); +unsigned char ymf262_read(void *chip, int a); +int ymf262_timer_over(void *chip, int c); +void ymf262_update_one(void *chip, OPL3SAMPLE **buffers, int length); + +void ymf262_set_timer_handler(void *chip, OPL3_TIMERHANDLER TimerHandler, void *param); +void ymf262_set_irq_handler(void *chip, OPL3_IRQHANDLER IRQHandler, void *param); +void ymf262_set_update_handler(void *chip, OPL3_UPDATEHANDLER UpdateHandler, void *param); + + +#endif /* __YMF262_H__ */ diff --git a/src/mcr.c b/src/mcr.c new file mode 100644 index 00000000..32afaa10 --- /dev/null +++ b/src/mcr.c @@ -0,0 +1,37 @@ +/*INTEL 82355 MCR emulation + This chip was used as part of many 386 chipsets + It controls memory addressing and shadowing*/ +#include "ibm.h" + +int nextreg6; +uint8_t mcr22; +int mcrlock,mcrfirst; +void resetmcr() +{ + mcrlock=0; + mcrfirst=1; + shadowbios=0; +} + +void writemcr(uint16_t addr, uint8_t val) +{ + printf("Write MCR %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x22: + if (val==6 && mcr22==6) nextreg6=1; + else nextreg6=0; +// if ((val&1) && (mcr22&1)) shadowbios=1; +// if (!(val&1) && !(mcr22&1)) shadowbios=0; +// if (!mcrfirst) shadowbios=val&1; +// mcrfirst=0; +// dumpregs(); +// exit(-1); + break; + case 0x23: + if (nextreg6) shadowbios=!val; + break; + } + mcr22=val; +} + diff --git a/src/mem.c b/src/mem.c new file mode 100644 index 00000000..93502178 --- /dev/null +++ b/src/mem.c @@ -0,0 +1,1358 @@ +/*MESS ROM notes : + + - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM) + - pc2386 video BIOS is underdumped (16k instead of 24k) + - c386sx16 BIOS fails checksum +*/ + +#include +#include +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "x86.h" +#include "cpu.h" + +static uint8_t (*_mem_read_b[0x20000])(uint32_t addr); +static uint16_t (*_mem_read_w[0x20000])(uint32_t addr); +static uint32_t (*_mem_read_l[0x20000])(uint32_t addr); +static void (*_mem_write_b[0x20000])(uint32_t addr, uint8_t val); +static void (*_mem_write_w[0x20000])(uint32_t addr, uint16_t val); +static void (*_mem_write_l[0x20000])(uint32_t addr, uint32_t val); + +int shadowbios,shadowbios_write; + +uint32_t oldpc; +extern uint8_t opcode2; +unsigned char isram[0x10000]; +extern int ins; +extern int timetolive; + +int mem_size; +int cache=4; +uint32_t biosmask; +int readlnum=0,writelnum=0; +int cachesize=256; + +uint8_t *ram,*rom,*vram,*vrom; +uint8_t romext[32768]; + +FILE *romfopen(char *fn, char *mode) +{ + char s[512]; + pclog("romfopen %s\n", fn); + strcpy(s,pcempath); + pclog("s = %s\n", s); + put_backslash(s); + pclog("s = %s\n", s); + pclog("strcat %s %s\n", s, fn); + strcat(s,fn); + pclog("s = %s\n", s); + return fopen(s,mode); +} + +static void mem_load_xtide_bios() +{ + FILE *f; + f=romfopen("roms/ide_xt.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + fclose(f); + } +} + +static void mem_load_atide_bios() +{ + FILE *f; + f=romfopen("roms/ide_at.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + fclose(f); + } +} + +int loadbios() +{ + FILE *f=NULL,*ff=NULL; + int c; + + loadfont("mda.rom", 0); + + memset(vrom,0x63,0x8000); +// printf("Loadrom - VGA %i\n",VGA); + if (VID_EGA) + { + f=romfopen("roms/ibm_6277356_ega_card_u44_27128.bin","rb"); + if (f) + { + pclog("Read EGA ROM!\n"); + fread(vrom,16384,1,f); + if (vrom[0x3FFE]==0xAA && vrom[0x3FFF]==0x55) + { + pclog("Read EGA ROM in reverse\n"); + fseek(f,0,SEEK_SET); + for (c=0x3FFF;c>=0;c--) + vrom[c]=getc(f); + } + fclose(f); + } + } + if (VGA) + { + f=romfopen("roms/trident.bin","rb"); + if (f) + { + fread(vrom,32768,1,f); + fclose(f); + } + } + if (ET4000) + { + f=romfopen("roms/et4000.bin","rb"); + if (f) + { + fread(vrom,32768,1,f); + fclose(f); + } + } + if (ET4000W32) + { + f=romfopen("roms/et4000w32.bin","rb"); + if (f) + { + fread(vrom,32768,1,f); + fclose(f); + } + } + if (gfxcard == GFX_BAHAMAS64) + { + f=romfopen("roms/bahamas64.bin","rb"); + if (f) + { + fread(vrom,32768,1,f); + fclose(f); + } + } + if (gfxcard == GFX_N9_9FX) + { + f=romfopen("roms/s3_764.bin","rb"); + if (f) + { + fread(vrom,32768,1,f); + fclose(f); + } + } + if (gfxcard == GFX_STEALTH64) + { + f=romfopen("roms/TRIO64 (Ver. 1.5-07) [VGA] (S3 Incorporated).bin","rb"); + if (f) + { + fread(vrom,32768,1,f); + fclose(f); + } + } + + memset(romext,0x63,0x8000); + + biosmask = 0xffff; + + pclog("Starting with romset %i\n", romset); + + switch (romset) + { + case ROM_PC1512: + f=romfopen("roms/pc1512/40043.v1","rb"); + ff=romfopen("roms/pc1512/40044.v1","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + memset(vrom,0x63,0x8000); + mem_load_xtide_bios(); + loadfont("roms/pc1512/40078.ic127", 2); + return 1; + case ROM_PC1640: + f=romfopen("roms/pc1640/40044.v3","rb"); + ff=romfopen("roms/pc1640/40043.v3","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + f=romfopen("roms/pc1640/40100","rb"); + if (!f) break; + fread(vrom,0x8000,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_PC200: + f=romfopen("roms/pc200/pc20v2.1","rb"); + ff=romfopen("roms/pc200/pc20v2.0","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + memset(vrom,0x63,0x8000); + mem_load_xtide_bios(); + loadfont("roms/pc200/40109.bin", 1); + return 1; + case ROM_TANDY: + f=romfopen("roms/tandy/tandy1t1.020","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + memset(vrom,0x63,0x8000); + mem_load_xtide_bios(); + return 1; +/* case ROM_IBMPCJR: + f=fopen("pcjr/bios.rom","rb"); + fread(rom+0xE000,8192,1,f); + fclose(f); + f=fopen("pcjr/basic.rom","rb"); + fread(rom+0x6000,32768,1,f); + fclose(f); + break;*/ + case ROM_IBMXT: + f=romfopen("roms/ibmxt/xt.rom","rb"); + if (!f) + { + f=romfopen("roms/ibmxt/xt050986.0","rb"); + ff=romfopen("roms/ibmxt/xt050986.1","rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; + } + else + { + fread(rom,65536,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + } + break; + case ROM_GENXT: + f=romfopen("roms/genxt/pcxt.rom","rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_DTKXT: + f=romfopen("roms/dtk/DTK_ERSO_2.42_2764.bin","rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_OLIM24: + f = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_low.bin" ,"rb"); + ff = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_high.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x4000; c += 2) + { + rom[c + 0xc000] = getc(f); + rom[c + 0xc001] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_PC2086: + f = romfopen("roms/pc2086/40179.ic129" ,"rb"); + ff = romfopen("roms/pc2086/40180.ic132","rb"); + if (!f || !ff) break; + pclog("Loading BIOS\n"); + for (c = 0x0000; c < 0x4000; c += 2) + { + rom[c + 0x0000] = getc(f); + rom[c + 0x0001] = getc(ff); + } + pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]); + fclose(ff); + fclose(f); + f = romfopen("roms/pc2086/40186.ic171", "rb"); + if (!f) break; + pclog("Loading VBIOS\n"); + fread(vrom, 32768, 1, f); + fclose(f); + mem_load_xtide_bios(); + pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]); + biosmask = 0x3fff; + return 1; + + case ROM_PC3086: + f = romfopen("roms/pc3086/fc00.bin" ,"rb"); + if (!f) break; + fread(rom, 0x4000, 1, f); + fclose(f); + f = romfopen("roms/pc3086/c000.bin", "rb"); + if (!f) break; + pclog("Loading VBIOS\n"); + fread(vrom, 32768, 1, f); + fclose(f); + mem_load_xtide_bios(); + pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]); + biosmask = 0x3fff; + return 1; + + case ROM_IBMAT: +/* f=romfopen("roms/AMIC206.BIN","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_IBMAT386: + f=romfopen("roms/ibmat/at111585.0","rb"); + ff=romfopen("roms/ibmat/at111585.1","rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_atide_bios(); + return 1; + case ROM_CMDPC30: + f = romfopen("roms/cmdpc30/commodore pc 30 iii even.bin", "rb"); + ff = romfopen("roms/cmdpc30/commodore pc 30 iii odd.bin", "rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x8000; c += 2) + { + rom[c] = getc(f); + rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x7fff; + mem_load_atide_bios(); + return 1; + case ROM_DELL200: + f=romfopen("roms/dells200/dell0.bin","rb"); + ff=romfopen("roms/dells200/dell1.bin","rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; +/* case ROM_IBMAT386: + f=romfopen("roms/at386/at386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_AMI386: /*This uses the OPTi 82C495 chipset*/ +// f=romfopen("roms/at386/at386.bin","rb"); + f=romfopen("roms/ami386/ami386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1; + + + case ROM_ACER386: + f=romfopen("roms/acer386/acer386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + rom[0xB0]=0xB0-0x51; + rom[0x40d4]=0x51; /*PUSH CX*/ + f=romfopen("roms/acer386/oti067.bin","rb"); + if (!f) break; + fread(vrom,0x8000,1,f); + fclose(f); + vrom[0x5D]=0x74; + return 1; + + case ROM_AMI286: + f=romfopen("roms/ami286/amic206.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_EUROPC: +// return 0; + f=romfopen("roms/europc/50145","rb"); + if (!f) break; + fread(rom+0x8000,32768,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_IBMPC: + f=romfopen("roms/ibmpc/pc102782.bin","rb"); + if (!f) break; +// f=fopen("pc081682.bin","rb"); + fread(rom+0xE000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.f6","rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + fread(rom+0x6000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.f8","rb"); + if (!f) break; /*But if some of it is there, then all of it must be*/ + fread(rom+0x8000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.fa","rb"); + if (!f) break; + fread(rom+0xA000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.fc","rb"); + if (!f) break; + fread(rom+0xC000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_MEGAPC: + pclog("Loading MegaPC\n"); + f = romfopen("roms/megapc/41651-bios lo.u18", "rb"); + ff = romfopen("roms/megapc/211253-bios hi.u19", "rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x8000; c+=2) + { + vrom[c]=getc(f); + vrom[c+1]=getc(ff); + } + fseek(f, 0x8000, SEEK_SET); + fseek(ff, 0x8000, SEEK_SET); + for (c = 0x0000; c < 0x10000; c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; + + case ROM_AMI486: + f=romfopen("roms/ami486/ami486.BIN","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_WIN486: +// f=romfopen("roms/win486/win486.bin","rb"); + f=romfopen("roms/win486/ALI1429G.AMW","rb"); + + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_PCI486: + f=romfopen("roms/hot-433/hot-433.ami","rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + } + printf("Failed to load ROM!\n"); + if (f) fclose(f); + if (ff) fclose(ff); + return 0; +} + + + +uint32_t mmucache[0x100000]; +int mmucaches[64]; +int mmunext=0; +int abrt=0; + +void initmmucache() +{ + int c; +// if (output) pclog("initmmucache\n"); + memset(mmucache,0xFF,sizeof(mmucache)); + for (c=0;c<64;c++) mmucaches[c]=0xFFFFFFFF; + mmunext=0; +} + +void resetreadlookup() +{ + int c; +// /*if (output) */pclog("resetreadlookup\n"); + memset(readlookup2,0xFF,1024*1024*4); + for (c=0;c<256;c++) readlookup[c]=0xFFFFFFFF; + readlnext=0; + memset(writelookup2,0xFF,1024*1024*4); + for (c=0;c<256;c++) writelookup[c]=0xFFFFFFFF; + writelnext=0; + pccache=0xFFFFFFFF; +// readlnum=writelnum=0; + +} + +int mmuflush=0; +int mmu_perm=4; + +void flushmmucache() +{ + int c; +// /*if (output) */pclog("flushmmucache\n"); +/* for (c=0;c<16;c++) + { + if ( readlookup2[0xE0+c]!=0xFFFFFFFF) pclog("RL2 %02X = %08X\n",0xE0+c, readlookup2[0xE0+c]); + if (writelookup2[0xE0+c]!=0xFFFFFFFF) pclog("WL2 %02X = %08X\n",0xE0+c,writelookup2[0xE0+c]); + }*/ + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF) + { + readlookup2[readlookup[c]]=0xFFFFFFFF; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c]!=0xFFFFFFFF) + { + writelookup2[writelookup[c]]=0xFFFFFFFF; + writelookup[c]=0xFFFFFFFF; + } + } + mmuflush++; +// readlnum=writelnum=0; + pccache=(uint32_t)0xFFFFFFFF; + pccache2=(uint8_t *)0xFFFFFFFF; + +// memset(readlookup,0xFF,sizeof(readlookup)); +// memset(readlookup2,0xFF,1024*1024*4); +// memset(writelookup,0xFF,sizeof(writelookup)); +// memset(writelookup2,0xFF,1024*1024*4); +/* if (!(cr0>>31)) return;*/ + for (c=0;c<64;c++) + { + if (mmucaches[c]!=0xFFFFFFFF) + { + mmucache[mmucaches[c]]=0xFFFFFFFF; + mmucaches[c]=0xFFFFFFFF; + } + } +// pclog("Flush MMU cache\n"); + +/* for (c = 0; c < 1024*1024; c++) + { + if (readlookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + if (writelookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + }*/ +} + +void flushmmucache_nopc() +{ + int c; + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF) + { + readlookup2[readlookup[c]]=0xFFFFFFFF; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c]!=0xFFFFFFFF) + { + writelookup2[writelookup[c]]=0xFFFFFFFF; + writelookup[c]=0xFFFFFFFF; + } + } + mmuflush++; + for (c=0;c<64;c++) + { + if (mmucaches[c]!=0xFFFFFFFF) + { + mmucache[mmucaches[c]]=0xFFFFFFFF; + mmucaches[c]=0xFFFFFFFF; + } + } +} + +void flushmmucache_cr3() +{ + int c; +// /*if (output) */pclog("flushmmucache_cr3\n"); + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF)// && !readlookupp[c]) + { + readlookup2[readlookup[c]]=0xFFFFFFFF; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c]!=0xFFFFFFFF)// && !writelookupp[c]) + { + writelookup2[writelookup[c]]=0xFFFFFFFF; + writelookup[c]=0xFFFFFFFF; + } + } + for (c=0;c<64;c++) + { + if (mmucaches[c]!=0xFFFFFFFF) + { + mmucache[mmucaches[c]]=0xFFFFFFFF; + mmucaches[c]=0xFFFFFFFF; + } + } + +/* for (c = 0; c < 1024*1024; c++) + { + if (readlookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + if (writelookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + }*/ +} + +extern int output; +#define mmutranslate(addr,rw) mmutranslatereal(addr,rw) +//#define mmutranslate(addr,rw) ((mmucache[addr>>12]!=0xFFFFFFFF)?(mmucache[addr>>12]+(addr&0xFFF)):mmutranslatereal(addr,rw)) +int pctrans=0; + +extern uint32_t testr[9]; + +uint32_t mmutranslatereal(uint32_t addr, int rw) +{ + int mmuout=0; + uint32_t addr2; + uint32_t temp,temp2,temp3; + if (abrt) return -1; +/* if ((addr&~0xFFFFF)==0x77f00000) pclog("Do translate %08X %i %08X %08X\n",addr,rw,EAX,pc); + if (addr==0x77f61000) output = 3; + if (addr==0x77f62000) { dumpregs(); exit(-1); } + if (addr==0x77f9a000) { dumpregs(); exit(-1); }*/ + addr2=(cr3+((addr>>20)&0xFFC)); + temp=temp2=((uint32_t *)ram)[addr2>>2]; +// pclog("Do translate %08X %i %08X\n", addr, rw, temp); + if (!(temp&1))// || (CPL==3 && !(temp&4) && !cpl_override) || (rw && !(temp&2) && (CPL==3 || cr0&WP_FLAG))) + { +// if (/*output==3 && */!nopageerrors) pclog("Section not present! %08X %08X %02X %04X:%08X %i %i\n",addr,temp,opcode,CS,pc,CPL,rw); + + cr2=addr; + temp&=1; + if (CPL==3) temp|=4; + if (rw) temp|=2; + abrt = ABRT_PF; + abrt_error = temp; +/* if (addr == 0x70046D) + { + dumpregs(); + exit(-1); + }*/ + return -1; + } + temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + temp3=temp&temp2; +// pclog("Do translate %08X %08X\n", temp, temp3); + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + { +// if (!nopageerrors) pclog("Page not present! %08X %08X %02X %02X %04X:%08X %04X:%08X %i %i %i\n",addr,temp,opcode,opcode2,CS,pc,SS,ESP,ins,CPL,rw); +// if (addr == 0x815F6E90) output = 3; +/* if (addr == 0x10ADE020) output = 3; + if (addr == 0x10000008) + { + dumpregs(); + exit(-1); + }*/ + + cr2=addr; + temp&=1; + if (CPL==3) temp|=4; + if (rw) temp|=2; + abrt = ABRT_PF; + abrt_error = temp; +// pclog("%04X\n",abrt); + return -1; + } + mmu_perm=temp&4; + ((uint32_t *)ram)[addr2>>2]|=0x20; + ((uint32_t *)ram)[((temp2&~0xFFF)+((addr>>10)&0xFFC))>>2]|=(rw?0x60:0x20); +// /*if (output) */pclog("Translate %08X %08X %08X %08X:%08X %08X\n",addr,(temp&~0xFFF)+(addr&0xFFF),temp,cs,pc,EDI); + + return (temp&~0xFFF)+(addr&0xFFF); +} + +void mmu_invalidate(uint32_t addr) +{ +// readlookup2[addr >> 12] = writelookup2[addr >> 12] = 0xFFFFFFFF; + flushmmucache_cr3(); +} + +int memspeed[11]={256,320,384,512,640,768,1024,1152,1280,1536,1920}; +int memwaitstate; + +static int cachelookup[256]; +static uint8_t *cachelookup2; +static int cachelnext; + +void addreadlookup(uint32_t virt, uint32_t phys) +{ +// return; +// printf("Addreadlookup %08X %08X %08X %08X %08X %08X %02X %08X\n",virt,phys,cs,ds,es,ss,opcode,pc); + if (readlookup2[virt>>12]!=0xFFFFFFFF) + { +/* if (readlookup2[virt>>12] != phys&~0xfff) + { + pclog("addreadlookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); + dumpregs(); + exit(-1); + }*/ + return; + } + + + if (!cachelookup2[phys >> 12]) + { + readlnum++; + cycles-=memwaitstate; + if (cachelookup[cachelnext] != 0xffffffff) + cachelookup2[cachelookup[cachelnext]] = 0; + cachelookup[cachelnext] = phys >> 12; + cachelookup2[phys >> 12] = 1; + cachelnext = (cachelnext + 1) & (cachesize - 1); + } + + if (readlookup[readlnext]!=0xFFFFFFFF) + { + readlookup2[readlookup[readlnext]]=0xFFFFFFFF; +// readlnum--; + } + readlookup2[virt>>12]=phys&~0xFFF; + readlookupp[readlnext]=mmu_perm; + readlookup[readlnext++]=virt>>12; + readlnext&=(cachesize-1); +} + +void addwritelookup(uint32_t virt, uint32_t phys) +{ +// return; +// printf("Addwritelookup %08X %08X\n",virt,phys); + if (writelookup2[virt>>12]!=0xFFFFFFFF) + { +/* if (writelookup2[virt>>12] != phys&~0xfff) + { + pclog("addwritelookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); + dumpregs(); + exit(-1); + }*/ + return; + } + + if (!cachelookup2[phys >> 12]) + { + writelnum++; + cycles-=memwaitstate; + if (cachelookup[cachelnext] != 0xffffffff) + cachelookup2[cachelookup[cachelnext]] = 0; + cachelookup[cachelnext] = phys >> 12; + cachelookup2[phys >> 12] = 1; + cachelnext = (cachelnext + 1) & (cachesize - 1); + } + + cycles-=memwaitstate; + if (writelookup[writelnext]!=0xFFFFFFFF) + { + writelookup2[writelookup[writelnext]]=0xFFFFFFFF; +// writelnum--; + } + writelookup2[virt>>12]=phys&~0xFFF; + writelookupp[writelnext]=mmu_perm; + writelookup[writelnext++]=virt>>12; + writelnext&=(cachesize-1); +} + +#undef printf +uint8_t *getpccache(uint32_t a) +{ +// int logit=(a>0xFFFFF); + uint32_t a2=a; + if (readlookup2[a>>12]!=0xFFFFFFFF) return &ram[(uint8_t *)readlookup2[a>>12] - (uint8_t *)(a&~0xFFF)]; + if (cr0>>31) + { +// if (output==3) pclog("Translate GetPCCache %08X\n",a); +pctrans=1; + a=mmutranslate(a,0); + pctrans=0; +// if (output==3) pclog("GetPCCache output %08X\n",a); + if (a==0xFFFFFFFF) return ram; +/* { + printf("Bad getpccache %08X\n",a); + dumpregs(); + exit(-1); + }*/ + } + a&=rammask; + //if (output==3) pclog("Getpccache %08X %i\n",a,shadowbios); + if (isram[a>>16]) + { + //if (readlookup2[a>>12]!=0xFFFFFFFF) return &ram[readlookup2[a>>12]]; + if ((a>>16)!=0xF || shadowbios) + addreadlookup(a2,a); +// if (a > 0xc0000000) +// printf("%016X %016X %016X\n", ((long)a&0xFFFFF000), ((long)a2&~0xFFF), (uint8_t *)(a&0xFFFFF000) - (uint8_t *)(a2&~0xFFF)); + return &ram[(uint8_t *)(a&0xFFFFF000) - (uint8_t *)(a2&~0xFFF)]; + } +// if (logit) printf("PCCACHE - %08X -> %08X\n",a2,a); + switch (a>>16) + { + case 0xC: if (a&0x8000) return &romext[(uint8_t *)(a&0x7000) - (uint8_t *)(a2&~0xFFF)]; + return &vrom[(uint8_t *)(a&0x7000) - (uint8_t *)(a2&~0xFFF)]; + case 0xE: if (shadowbios) return &ram[(uint8_t *)(a&0xFFF000) - (uint8_t *)(a2&~0xFFF)]; + return &rom[(uint8_t *)((a & biosmask) & ~ 0xfff) - (uint8_t *)(a2 & ~0xFFF)]; + case 0xF: if (shadowbios) return &ram[(uint8_t *)(a&0xFFF000) - (uint8_t *)(a2&~0xFFF)]; + return &rom[(uint8_t *)((a & biosmask) & ~ 0xfff) - (uint8_t *)(a2 & ~0xFFF)]; + } + return &rom[(long)(a&0xF000) - (long)(a2&~0xFFF)]; + /*printf("Bad getpccache %08X\n",a); + dumpregs(); + exit(-1);*/ +} +#define printf pclog + +static uint32_t mem_logical_addr; +uint8_t readmembl(uint32_t addr) +{ + mem_logical_addr = addr; + if (cr0 >> 31) + { + addr = mmutranslate(addr, 0); + if (addr == 0xFFFFFFFF) return 0xFF; + } + addr &= rammask; + + switch (addr>>16) + { + case 13: if (romset==ROM_AMI286) return neat_readems(addr); return 0xFF; +// case 14: pclog("Read %06X\n", addr); if (shadowbios) { /*printf("Read shadow RAM %08X %02X\n",addr,ram[addr]);*/ return ram[addr]; } + } + if (_mem_read_b[addr >> 15]) return _mem_read_b[addr >> 15](addr); + return 0xFF; +} + +void writemembl(uint32_t addr, uint8_t val) +{ + mem_logical_addr = addr; + + if (cr0 >> 31) + { + addr = mmutranslate(addr,1); + if (addr == 0xFFFFFFFF) return; + } + addr &= rammask; + + switch (addr>>16) + { + case 13: if (romset==ROM_AMI286) neat_writeems(addr,val); return; +// case 14: printf("Write %08X %02X\n",addr,val); //ram[addr]=val; +// if (isram[(addr>>16)&0xFF]) ram[addr]=val; +// return; + } + if (_mem_write_b[addr >> 15]) _mem_write_b[addr >> 15](addr, val); +// else pclog("Bad write %08X %02X\n", addr, val); +} + +uint8_t readmemb386l(uint32_t seg, uint32_t addr) +{ + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rb %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr); + return -1; + } + mem_logical_addr = addr = addr + seg; + if (readlookup2[mem_logical_addr >> 12] != 0xFFFFFFFF) + { + return ram[readlookup2[mem_logical_addr >> 12] + (mem_logical_addr & 0xFFF)]; + } + + if (cr0 >> 31) + { + addr = mmutranslate(addr, 0); + if (addr == 0xFFFFFFFF) return 0xFF; + } + + addr &= rammask; + + if (_mem_read_b[addr >> 15]) return _mem_read_b[addr >> 15](addr); + return 0xFF; +} + +void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) +{ + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wb %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr); + return; + } + + mem_logical_addr = addr = addr + seg; + if (cr0 >> 31) + { + addr = mmutranslate(addr, 1); + if (addr == 0xFFFFFFFF) return; + } + + addr &= rammask; + + if (_mem_write_b[addr >> 15]) _mem_write_b[addr >> 15](addr, val); +// else pclog("Bad write %08X %02X\n", addr, val); +} + +uint16_t readmemwl(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFE) + { + if (cr0>>31) + { + if (mmutranslate(addr2, 0) == 0xffffffff) return; + if (mmutranslate(addr2+1, 0) == 0xffffffff) return; + } + if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); + else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rw %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr); + return -1; + } + if (cr0>>31) + { + addr2=mmutranslate(addr2,0); + if (addr2==0xFFFFFFFF) return 0xFFFF; + } + + addr2 &= rammask; + + if (_mem_read_w[addr2 >> 15]) return _mem_read_w[addr2 >> 15](addr2); + + if (_mem_read_b[addr2 >> 15]) + { + if (AT) return _mem_read_b[addr2 >> 15](addr2) | (_mem_read_b[(addr2 + 1) >> 15](addr2 + 1) << 8); + else return _mem_read_b[addr2 >> 15](addr2) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 15](seg + ((addr + 1) & 0xffff)) << 8); + } + return 0xffff; +} + +void writememwl(uint32_t seg, uint32_t addr, uint16_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFE) + { + if (cr0>>31) + { + if (mmutranslate(addr2, 1) == 0xffffffff) return; + if (mmutranslate(addr2+1, 1) == 0xffffffff) return; + } + if (is386) + { + writememb386l(seg,addr,val); + writememb386l(seg,addr+1,val>>8); + } + else + { + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); + } + return; + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr); + return; + } + if (cr0>>31) + { + addr2=mmutranslate(addr2,1); + if (addr2==0xFFFFFFFF) return; + } + + addr2 &= rammask; + + if (_mem_write_w[addr2 >> 15]) + { + _mem_write_w[addr2 >> 15](addr2, val); + return; + } + + if (_mem_write_b[addr2 >> 15]) + { + _mem_write_b[addr2 >> 15](addr2, val); + _mem_write_b[(addr2 + 1) >> 15](addr2 + 1, val >> 8); +// if (AT) _ +// else _mem_write_b[(seg + ((addr + 1) & 0xffff)) >> 15](seg + ((addr + 1) & 0xffff), val >> 8); + return; + } +// pclog("Bad write %08X %04X\n", addr, val); +} + +uint32_t readmemll(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate(addr2, 0) == 0xffffffff) return; + if (mmutranslate(addr2+3, 0) == 0xffffffff) return; + } + return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr); + return -1; + } + + if (cr0>>31) + { + addr2=mmutranslate(addr2,0); + if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + } + + addr2&=rammask; + + if (_mem_read_l[addr2 >> 15]) return _mem_read_l[addr2 >> 15](addr2); + + if (_mem_read_w[addr2 >> 15]) return _mem_read_w[addr2 >> 15](addr2) | (_mem_read_w[addr2 >> 15](addr2 + 2) << 16); + + if (_mem_read_b[addr2 >> 15]) return _mem_read_b[addr2 >> 15](addr2) | (_mem_read_b[addr2 >> 15](addr2 + 1) << 8) | (_mem_read_b[addr2 >> 15](addr2 + 2) << 16) | (_mem_read_b[addr2 >> 15](addr2 + 3) << 24); + + return 0xffffffff; +} + +void writememll(uint32_t seg, uint32_t addr, uint32_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate(addr2, 1) == 0xffffffff) return; + if (mmutranslate(addr2+3, 1) == 0xffffffff) return; + } + writememwl(seg,addr,val); + writememwl(seg,addr+2,val>>16); + return; + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,pc,opcode,addr); + return; + } + if (cr0>>31) + { + addr2=mmutranslate(addr2,1); + if (addr2==0xFFFFFFFF) return; + } + + addr2&=rammask; + + if (_mem_write_l[addr2 >> 15]) + { + _mem_write_l[addr2 >> 15](addr2, val); + return; + } + if (_mem_write_w[addr2 >> 15]) + { + _mem_write_w[addr2 >> 15](addr2, val); + _mem_write_w[addr2 >> 15](addr2 + 2, val >> 16); + return; + } + if (_mem_write_b[addr2 >> 15]) + { + _mem_write_b[addr2 >> 15](addr2, val); + _mem_write_b[addr2 >> 15](addr2 + 1, val >> 8); + _mem_write_b[addr2 >> 15](addr2 + 2, val >> 16); + _mem_write_b[addr2 >> 15](addr2 + 3, val >> 24); + return; + } +// pclog("Bad write %08X %08X\n", addr, val); +} + +uint8_t mem_read_ram(uint32_t addr) +{ +// if (addr < 0xa0000) pclog("Read RAMb %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t mem_read_ramw(uint32_t addr) +{ +// if (addr < 0xa0000) pclog("Read RAMw %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t mem_read_raml(uint32_t addr) +{ +// if (addr < 0xa0000) pclog("Read RAMl %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + +void mem_write_ram(uint32_t addr, uint8_t val) +{ + addwritelookup(mem_logical_addr, addr); + ram[addr] = val; +// if (addr >= 0xe0000 && addr < 0x100000) pclog("Write RAMb %08X\n", addr); +} +void mem_write_ramw(uint32_t addr, uint16_t val) +{ + addwritelookup(mem_logical_addr, addr); + *(uint16_t *)&ram[addr] = val; +// if (addr >= 0xe0000 && addr < 0x100000) pclog("Write RAMw %08X %04X:%04X\n", addr, CS, pc); +} +void mem_write_raml(uint32_t addr, uint32_t val) +{ + addwritelookup(mem_logical_addr, addr); + *(uint32_t *)&ram[addr] = val; +// if (addr >= 0xe0000 && addr < 0x100000) pclog("Write RAMl %08X %04X:%04X %04X:%04X %04X:%04X\n", addr, CS, pc, DS,SI, ES,DI); +} + +uint8_t mem_read_bios(uint32_t addr) +{ + if (AMIBIOS && (addr&0xFFFFF)==0xF8281) /*This is read constantly during AMIBIOS POST, but is never written to. It's clearly a status register of some kind, but for what?*/ + { +// pclog("Read magic addr %04X(%06X):%04X\n",CS,cs,pc); +// if (pc==0x547D) output=3; + return 0x40; + } +// if (output) pclog("Read BIOS %08X %02X %04X:%04X\n", addr, rom[addr & biosmask], CS, pc); + return rom[addr & biosmask]; +} +uint16_t mem_read_biosw(uint32_t addr) +{ +// if (output) pclog("Read BIOS %08X %04X %04X:%04X\n", addr, *(uint16_t *)&rom[addr & biosmask], CS, pc); + return *(uint16_t *)&rom[addr & biosmask]; +} +uint32_t mem_read_biosl(uint32_t addr) +{ +// if (output) pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc); + return *(uint32_t *)&rom[addr & biosmask]; +} + +uint8_t mem_read_vrom(uint32_t addr) +{ + return vrom[addr & 0x7fff]; +} +uint16_t mem_read_vromw(uint32_t addr) +{ + return *(uint16_t *)&vrom[addr & 0x7fff]; +} +uint32_t mem_read_vroml(uint32_t addr) +{ + return *(uint32_t *)&vrom[addr & 0x7fff]; +} + +uint8_t mem_read_romext(uint32_t addr) +{ + return romext[addr & 0x7fff]; +} +uint16_t mem_read_romextw(uint32_t addr) +{ + return *(uint16_t *)&romext[addr & 0x7fff]; +} +uint32_t mem_read_romextl(uint32_t addr) +{ + return *(uint32_t *)&romext[addr & 0x7fff]; +} + +void mem_init() +{ + int c; + ram=malloc(mem_size*1024*1024); + rom=malloc(0x20000); + vram=malloc(0x800000); + vrom=malloc(0x8000); + readlookup2=malloc(1024*1024*4); + writelookup2=malloc(1024*1024*4); + cachelookup2=malloc(1024*1024); + biosmask=65535; + makeznptable(); + memset(ram,0,mem_size*1024*1024); + for (c = 0; c < 0x10000; c++) isram[c] = 0; + for (c=0;c<(mem_size*16);c++) + { + isram[c]=1; + if (c >= 0xa && c<=0xF) isram[c]=0; + } + for (c = 0; c < 0x20000; c++) + _mem_read_b[c] = _mem_read_w[c] = _mem_read_l[c] = _mem_write_b[c] = _mem_write_w[c] = _mem_write_l[c] = NULL; + + mem_sethandler(0x00000, 0xa0000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); + if (mem_size > 1) + mem_sethandler(0x100000, (mem_size - 1) * 1024 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); + + mem_sethandler(0xc0000, 0x08000, mem_read_vrom, mem_read_vromw, mem_read_vroml, NULL, NULL, NULL); + mem_sethandler(0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL); + mem_sethandler(0xe0000, 0x20000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); +// pclog("Mem resize %i %i\n",mem_size,c); +} + +void mem_resize() +{ + int c; + free(ram); + ram=malloc(mem_size*1024*1024); + memset(ram,0,mem_size*1024*1024); + for (c = 0; c < 0x10000; c++) isram[c] = 0; + for (c=0;c<(mem_size*16);c++) + { + isram[c]=1; + if (c >= 0xa && c<=0xF) isram[c]=0; + } + for (c = 0; c < 0x20000; c++) + _mem_read_b[c] = _mem_read_w[c] = _mem_read_l[c] = _mem_write_b[c] = _mem_write_w[c] = _mem_write_l[c] = NULL; + + mem_sethandler(0x00000, 0xa0000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); + if (mem_size > 1) + mem_sethandler(0x100000, (mem_size - 1) * 1024 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml); + + mem_sethandler(0xc0000, 0x8000, mem_read_vrom, mem_read_vromw, mem_read_vroml, NULL, NULL, NULL); + mem_sethandler(0xc8000, 0x8000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL); + mem_sethandler(0xe0000, 0x20000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_ram, mem_write_ramw, mem_write_raml); +// pclog("Mem resize %i %i\n",mem_size,c); +} + +void mem_updatecache() +{ + flushmmucache(); + if (!is386) + { + cachesize=256; + memwaitstate=0; + return; + } + if (cpu_16bitbus) + memwaitstate = 512 * cpu_multi; + else + memwaitstate = 384 * cpu_multi; //memspeed[cpuspeed]; + switch (cache) + { + case 0: cachesize=32; break; + case 1: cachesize=64; break; + case 2: cachesize=128; break; + case 3: cachesize=256; break; + case 4: cachesize=256; memwaitstate=0; break; + } +} + +void mem_sethandler(uint32_t base, uint32_t size, + uint8_t (*read_b)(uint32_t addr), + uint16_t (*read_w)(uint32_t addr), + uint32_t (*read_l)(uint32_t addr), + void (*write_b)(uint32_t addr, uint8_t val), + void (*write_w)(uint32_t addr, uint16_t val), + void (*write_l)(uint32_t addr, uint32_t val)) +{ + uint32_t c; + for (c = base; c < base + size; c += 0x8000) + { + _mem_read_b[ c >> 15] = read_b; + _mem_read_w[ c >> 15] = read_w; + _mem_read_l[ c >> 15] = read_l; + _mem_write_b[c >> 15] = write_b; + _mem_write_w[c >> 15] = write_w; + _mem_write_l[c >> 15] = write_l; + } +} + +void mem_removehandler(uint32_t base, uint32_t size, + uint8_t (*read_b)(uint32_t addr), + uint16_t (*read_w)(uint32_t addr), + uint32_t (*read_l)(uint32_t addr), + void (*write_b)(uint32_t addr, uint8_t val), + void (*write_w)(uint32_t addr, uint16_t val), + void (*write_l)(uint32_t addr, uint32_t val)) +{ + uint32_t c; + if ((base + size) > 0xffff8000) + size = 0xffff0000 - base; + for (c = base; c < base + size; c += 0x8000) + { + if ( _mem_read_b[c >> 15] == read_b) _mem_read_b[c >> 15] = NULL; + if ( _mem_read_w[c >> 15] == read_w) _mem_read_w[c >> 15] = NULL; + if ( _mem_read_l[c >> 15] == read_l) _mem_read_l[c >> 15] = NULL; + if (_mem_write_b[c >> 15] == write_b) _mem_write_b[c >> 15] = NULL; + if (_mem_write_w[c >> 15] == write_w) _mem_write_w[c >> 15] = NULL; + if (_mem_write_l[c >> 15] == write_l) _mem_write_l[c >> 15] = NULL; + } +} + +int mem_a20_key = 0, mem_a20_alt = 0; +static int mem_a20_state = 0; + +void mem_a20_recalc() +{ + int state = mem_a20_key | mem_a20_alt; + pclog("A20 recalc %i %i\n", state, mem_a20_state); + if (state && !mem_a20_state) + { + rammask = 0xffffffff; + flushmmucache(); + } + else if (!state && mem_a20_state) + { + rammask = 0xffefffff; + flushmmucache(); + } + pclog("rammask now %08X\n", rammask); + mem_a20_state = state; +} diff --git a/src/mem.h b/src/mem.h new file mode 100644 index 00000000..dd496a7f --- /dev/null +++ b/src/mem.h @@ -0,0 +1,40 @@ +extern uint8_t *ram,*rom,*vram,*vrom; +extern uint8_t romext[32768]; +extern int readlnum,writelnum; +extern int memspeed[11]; +extern int nopageerrors; +extern int cache; +extern int memwaitstate; + +void mem_sethandler(uint32_t base, uint32_t size, + uint8_t (*read_b)(uint32_t addr), + uint16_t (*read_w)(uint32_t addr), + uint32_t (*read_l)(uint32_t addr), + void (*write_b)(uint32_t addr, uint8_t val), + void (*write_w)(uint32_t addr, uint16_t val), + void (*write_l)(uint32_t addr, uint32_t val)); + +void mem_removehandler(uint32_t base, uint32_t size, + uint8_t (*read_b)(uint32_t addr), + uint16_t (*read_w)(uint32_t addr), + uint32_t (*read_l)(uint32_t addr), + void (*write_b)(uint32_t addr, uint8_t val), + void (*write_w)(uint32_t addr, uint16_t val), + void (*write_l)(uint32_t addr, uint32_t val)); +extern int mem_a20_alt; +extern int mem_a20_key; +void mem_a20_recalc(); + +uint8_t mem_read_ram(uint32_t addr); +uint16_t mem_read_ramw(uint32_t addr); +uint32_t mem_read_raml(uint32_t addr); + +void mem_write_ram(uint32_t addr, uint8_t val); +void mem_write_ramw(uint32_t addr, uint16_t val); +void mem_write_raml(uint32_t addr, uint32_t val); + +uint8_t mem_read_bios(uint32_t addr); +uint16_t mem_read_biosw(uint32_t addr); +uint32_t mem_read_biosl(uint32_t addr); + +FILE *romfopen(char *fn, char *mode); diff --git a/src/model.c b/src/model.c new file mode 100644 index 00000000..4c4024cd --- /dev/null +++ b/src/model.c @@ -0,0 +1,200 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" + +#include "acer386sx.h" +#include "ali1429.h" +#include "amstrad.h" +#include "dma.h" +#include "fdc.h" +#include "headland.h" +#include "ide.h" +#include "jim.h" +#include "keyboard_xt.h" +#include "keyboard_at.h" +#include "keyboard_olim24.h" +#include "lpt.h" +#include "mouse_ps2.h" +#include "mouse_serial.h" +#include "neat.h" +#include "nvr.h" +#include "olivetti_m24.h" +#include "pci.h" +#include "pic.h" +#include "pit.h" +#include "psg.h" +#include "serial.h" +#include "um8881f.h" +#include "wd76c10.h" +#include "xtide.h" + +void xt_init(); +void tandy1k_init(); +void ams_init(); +void europc_init(); +void olim24_init(); +void at_init(); +void at_neat_init(); +void at_acer386sx_init(); +void at_wd76c10_init(); +void at_ali1429_init(); +void at_headland_init(); +void at_um8881f_init(); + +int model; + +MODEL models[] = +{ + {"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, + {"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, + {"Generic XT clone", ROM_GENXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, + {"DTK XT clone", ROM_DTKXT, { "", cpus_8088, "", NULL, "", NULL}, 0, xt_init}, + {"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, tandy1k_init}, + {"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512,"", NULL, "", NULL}, 1, ams_init}, + {"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init}, + {"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, europc_init}, + {"Olivetti M24", ROM_OLIM24, { "", cpus_8086, "", NULL, "", NULL}, 1, olim24_init}, + {"Amstrad PC1640", ROM_PC1640, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init}, + {"Amstrad PC2086", ROM_PC2086, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init}, + {"Amstrad PC3086", ROM_PC3086, { "", cpus_8086, "", NULL, "", NULL}, 1, ams_init}, + {"IBM AT", ROM_IBMAT, { "", cpus_ibmat, "", NULL, "", NULL}, 0, at_init}, + {"Commodore PC 30 III", ROM_CMDPC30, { "", cpus_286, "", NULL, "", NULL}, 0, at_init}, + {"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, at_neat_init}, + {"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, at_init}, + {"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, at_acer386sx_init}, + {"Amstrad MegaPC", ROM_MEGAPC, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 1, at_wd76c10_init}, + {"AMI 386 clone", ROM_AMI386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, at_headland_init}, + {"AMI 486 clone", ROM_AMI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_ali1429_init}, + {"AMI WinBIOS 486", ROM_WIN486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_ali1429_init}, + {"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, at_um8881f_init}, + {"", -1, {"", 0, "", 0, "", 0}, 0} +}; + +int model_getromset() +{ + return models[model].id; +} + +char *model_getname() +{ + return models[model].name; +} + +void common_init() +{ + dma_init(); + fdc_init(); + lpt_init(); + pic_init(); + pit_init(); + serial1_init(0x3f8); + serial2_init(0x2f8); +} + +void xt_init() +{ + common_init(); + keyboard_xt_init(); + mouse_serial_init(); + xtide_init(); +} + +void tandy1k_init() +{ + common_init(); + keyboard_xt_init(); + mouse_serial_init(); + psg_init(); + xtide_init(); +} + +void ams_init() +{ + common_init(); + amstrad_init(); + keyboard_amstrad_init(); + nvr_init(); + xtide_init(); +} + +void europc_init() +{ + common_init(); + jim_init(); + keyboard_xt_init(); + mouse_serial_init(); + xtide_init(); +} + +void olim24_init() +{ + common_init(); + keyboard_olim24_init(); + nvr_init(); + olivetti_m24_init(); + xtide_init(); +} + +void at_init() +{ + common_init(); + dma16_init(); + ide_init(); + keyboard_at_init(); + if (models[model].init == at_init) + mouse_serial_init(); + nvr_init(); + pic2_init(); +} + +void at_neat_init() +{ + at_init(); + mouse_serial_init(); + neat_init(); +} + +void at_acer386sx_init() +{ + at_init(); + mouse_ps2_init(); + acer386sx_init(); +} + +void at_wd76c10_init() +{ + at_init(); + mouse_ps2_init(); + wd76c10_init(); +} + +void at_headland_init() +{ + at_init(); + headland_init(); + mouse_serial_init(); +} + +void at_ali1429_init() +{ + at_init(); + ali1429_init(); + mouse_serial_init(); +} + +void at_um8881f_init() +{ + at_init(); + mouse_serial_init(); + pci_init(); + um8881f_init(); +} + +void model_init() +{ + pclog("Initting as %s\n", model_getname()); + io_init(); + + models[model].init(); +} diff --git a/src/model.h b/src/model.h new file mode 100644 index 00000000..2c26c777 --- /dev/null +++ b/src/model.h @@ -0,0 +1,16 @@ +typedef struct +{ + char name[24]; + int id; + struct + { + char name[8]; + CPU *cpus; + } cpu[3]; + int fixed_gfxcard; + void (*init)(); +} MODEL; + +extern MODEL models[]; + +extern int model; diff --git a/src/mouse.c b/src/mouse.c new file mode 100644 index 00000000..a9b45fef --- /dev/null +++ b/src/mouse.c @@ -0,0 +1,4 @@ +#include "ibm.h" +#include "mouse.h" + +void (*mouse_poll)(int x, int y, int b); diff --git a/src/mouse.h b/src/mouse.h new file mode 100644 index 00000000..44558be6 --- /dev/null +++ b/src/mouse.h @@ -0,0 +1,5 @@ +extern void (*mouse_poll)(int x, int y, int b); + +extern int mousepos; +extern int mousedelay; + diff --git a/src/mouse_ps2.c b/src/mouse_ps2.c new file mode 100644 index 00000000..d59acb1e --- /dev/null +++ b/src/mouse_ps2.c @@ -0,0 +1,152 @@ +#include "ibm.h" +#include "keyboard_at.h" +#include "mouse.h" +#include "mouse_ps2.h" +#include "plat-mouse.h" + +enum +{ + MOUSE_STREAM, + MOUSE_REMOTE, + MOUSE_ECHO +}; + +#define MOUSE_ENABLE 0x20 +#define MOUSE_SCALE 0x10 + +static struct +{ + int mode; + + uint8_t flags; + uint8_t resolution; + + uint8_t command; + + int cd; +} mouse_ps2; + +void mouse_ps2_write(uint8_t val) +{ + if (mouse_ps2.cd) + { + mouse_ps2.cd = 0; + switch (mouse_ps2.command) + { + case 0xe8: /*Set mouse resolution*/ + mouse_ps2.resolution = val; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf3: /*Set sample rate*/ + keyboard_at_adddata_mouse(0xfa); + break; + +// default: +// fatal("mouse_ps2 : Bad data write %02X for command %02X\n", val, mouse_ps2.command); + } + } + else + { + mouse_ps2.command = val; + switch (mouse_ps2.command) + { + case 0xe6: /*Set scaling to 1:1*/ + mouse_ps2.flags &= ~MOUSE_SCALE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe7: /*Set scaling to 2:1*/ + mouse_ps2.flags |= MOUSE_SCALE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe8: /*Set mouse resolution*/ + mouse_ps2.cd = 1; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf2: /*Read ID*/ + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0x00); + break; + + case 0xf3: /*Set sample rate*/ + mouse_ps2.cd = 1; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf4: /*Enable*/ + mouse_ps2.flags |= MOUSE_ENABLE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf5: /*Disable*/ + mouse_ps2.flags &= ~MOUSE_ENABLE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xff: /*Reset*/ + mouse_ps2.mode = MOUSE_STREAM; + mouse_ps2.flags = 0; + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); + break; + +// default: +// fatal("mouse_ps2 : Bad command %02X\n", val, mouse_ps2.command); + } + } +} + +static int ps2_x = 0, ps2_y = 0, ps2_b = 0; +void mouse_ps2_poll(int x, int y, int b) +{ + uint8_t packet[3] = {0x08, 0, 0}; + if (!x && !y && b == ps2_b) return; + ps2_x += x; + ps2_y -= y; + if (mouse_ps2.mode == MOUSE_STREAM && (mouse_ps2.flags & MOUSE_ENABLE) && + ((mouse_queue_end - mouse_queue_start) & 0xf) < 13) + { + ps2_b = b; + // pclog("Send packet : %i %i\n", ps2_x, ps2_y); + if (ps2_x > 255) + ps2_x = 255; + if (ps2_x < -256) + ps2_x = -256; + if (ps2_y > 255) + ps2_y = 255; + if (ps2_y < -256) + ps2_y = -256; + if (ps2_x < 0) + packet[0] |= 0x10; + if (ps2_y < 0) + packet[0] |= 0x20; + if (mouse_b & 1) + packet[0] |= 1; + if (mouse_b & 2) + packet[0] |= 2; + if (mouse_b & 4) + packet[0] |= 4; + packet[1] = ps2_x & 0xff; + packet[2] = ps2_y & 0xff; + + ps2_x = ps2_y = 0; + + keyboard_at_adddata_mouse(packet[0]); + keyboard_at_adddata_mouse(packet[1]); + keyboard_at_adddata_mouse(packet[2]); + } +} + + +void mouse_ps2_init() +{ + mouse_poll = mouse_ps2_poll; + mouse_write = mouse_ps2_write; + mouse_ps2.cd = 0; + mouse_ps2.flags = 0; + mouse_ps2.mode = MOUSE_STREAM; +} diff --git a/src/mouse_ps2.h b/src/mouse_ps2.h new file mode 100644 index 00000000..6edfb1f7 --- /dev/null +++ b/src/mouse_ps2.h @@ -0,0 +1 @@ +void mouse_ps2_init(); diff --git a/src/mouse_serial.c b/src/mouse_serial.c new file mode 100644 index 00000000..2aab6394 --- /dev/null +++ b/src/mouse_serial.c @@ -0,0 +1,66 @@ +#include "ibm.h" +#include "mouse.h" +#include "serial.h" + +static int oldb=0; + +void mouse_serial_poll(int x, int y, int b) +{ + uint8_t mousedat[3]; + + if (!(serial.ier&1)) return; + if (!x && !y && b==oldb) return; + + oldb=b; + if (x>127) x=127; + if (y>127) y=127; + if (x<-128) x=-128; + if (y<-128) y=-128; + + /*Use Microsoft format*/ + mousedat[0]=0x40; + mousedat[0]|=(((y>>6)&3)<<2); + mousedat[0]|=((x>>6)&3); + if (b&1) mousedat[0]|=0x20; + if (b&2) mousedat[0]|=0x10; + mousedat[1]=x&0x3F; + mousedat[2]=y&0x3F; + + if (!(serial.mctrl&0x10)) + { + serial_write_fifo(mousedat[0]); + serial_write_fifo(mousedat[1]); + serial_write_fifo(mousedat[2]); + } +} + +void mouse_serial_rcr() +{ + mousepos=-1; + mousedelay=1000; +} + +void mousecallback() +{ + if (mousepos == -1) + { + mousepos = 0; + serial_fifo_read = serial_fifo_write = 0; + serial.linestat &= ~1; + serial_write_fifo('M'); + } + else if (serial_fifo_read != serial_fifo_write) + { + serial.iir=4; + serial.linestat|=1; + if (serial.mctrl&8) picint(0x10); + } +// printf("Mouse callback\n"); +} + +void mouse_serial_init() +{ + mouse_poll = mouse_serial_poll; + serial_rcr = mouse_serial_rcr; +} + diff --git a/src/mouse_serial.h b/src/mouse_serial.h new file mode 100644 index 00000000..c8356029 --- /dev/null +++ b/src/mouse_serial.h @@ -0,0 +1 @@ +void mouse_serial_init(); diff --git a/src/neat.c b/src/neat.c new file mode 100644 index 00000000..3861c4ff --- /dev/null +++ b/src/neat.c @@ -0,0 +1,68 @@ +/*This is the chipset used in the AMI 286 clone model*/ +#include "ibm.h" +#include "io.h" +#include "neat.h" + +static uint8_t neat_regs[256]; +static int neat_index; +static int neat_emspage[4]; + +void neat_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x22: + neat_index = val; + break; + + case 0x23: + neat_regs[neat_index] = val; + switch (neat_index) + { + case 0x6E: /*EMS page extension*/ + neat_emspage[3] = (neat_emspage[3] & 0x7F) | (( val & 3) << 7); + neat_emspage[2] = (neat_emspage[2] & 0x7F) | (((val >> 2) & 3) << 7); + neat_emspage[1] = (neat_emspage[1] & 0x7F) | (((val >> 4) & 3) << 7); + neat_emspage[0] = (neat_emspage[0] & 0x7F) | (((val >> 6) & 3) << 7); + break; + } + break; + + case 0x0208: case 0x0209: case 0x4208: case 0x4209: + case 0x8208: case 0x8209: case 0xC208: case 0xC209: + neat_emspage[port >> 14] = (neat_emspage[port >> 14] & 0x180) | (val & 0x7F); + break; + } +} + +uint8_t neat_read(uint16_t port) +{ + switch (port) + { + case 0x22: + return neat_index; + + case 0x23: + return neat_regs[neat_index]; + } + return 0xff; +} + +void neat_writeems(uint32_t addr, uint8_t val) +{ + ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val; +} + +uint8_t neat_readems(uint32_t addr) +{ + return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)]; +} + +void neat_init() +{ + io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL); + io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL); + io_sethandler(0x4208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL); + io_sethandler(0x8208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL); + io_sethandler(0xc208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL); +} diff --git a/src/neat.h b/src/neat.h new file mode 100644 index 00000000..a7f295dd --- /dev/null +++ b/src/neat.h @@ -0,0 +1 @@ +void neat_init(); diff --git a/src/nvr.c b/src/nvr.c new file mode 100644 index 00000000..0fd89b6c --- /dev/null +++ b/src/nvr.c @@ -0,0 +1,204 @@ +#include +#include +#include "ibm.h" +#include "nvr.h" + +int oldromset; +int nvrmask=63; +uint8_t nvrram[128]; +int nvraddr; + +SYSTEMTIME systemtime; + +void getnvrtime() +{ + int c,d; + uint8_t baknvr[10]; +// memset(nvrram,0,10); +// return; + memcpy(baknvr,nvrram,10); + GetLocalTime(&systemtime); + d=systemtime.wSecond%10; + c=systemtime.wSecond/10; + nvrram[0]=d|(c<<4); + d=systemtime.wMinute%10; + c=systemtime.wMinute/10; + nvrram[2]=d|(c<<4); + d=systemtime.wHour%10; + c=systemtime.wHour/10; + nvrram[4]=d|(c<<4); + d=systemtime.wDayOfWeek%10; + c=systemtime.wDayOfWeek/10; + nvrram[6]=d|(c<<4); + d=systemtime.wDay%10; + c=systemtime.wDay/10; + nvrram[7]=d|(c<<4); + d=systemtime.wMonth%10; + c=systemtime.wMonth/10; + nvrram[8]=d|(c<<4); + d=systemtime.wYear%10; + c=(systemtime.wYear/10)%10; + nvrram[9]=d|(c<<4); + if (baknvr[0]!=nvrram[0] || + baknvr[2]!=nvrram[2] || + baknvr[4]!=nvrram[4] || + baknvr[6]!=nvrram[6] || + baknvr[7]!=nvrram[7] || + baknvr[8]!=nvrram[8] || + baknvr[9]!=nvrram[9]) nvrram[0xA]|=0x80; +} + +void nvr_recalc() +{ + int c; + float newrtctime; + c=1<<((nvrram[0xA]&0xF)-1); + newrtctime=RTCCONST*(float)c; + if (rtctime>newrtctime) rtctime=newrtctime; +} + +void nvr_rtc() +{ + int c; + if (!(nvrram[0xA]&0xF)) + { + rtctime=99999999; + return; + } + c=1<<((nvrram[0xA]&0xF)-1); + rtctime+=RTCCONST*(float)c; +// pclog("RTCtime now %f\n",rtctime); + nvrram[0xC]=0x40; + if (nvrram[0xB]&0x40) + { + nvrram[0xC]|=0x80; + if (AMSTRAD) picint(2); + else picint(0x100); +// pclog("RTC int\n"); + } +} + +void writenvr(uint16_t addr, uint8_t val) +{ + int c; +// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins); + if (addr&1) + { +// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins); + if (nvraddr >= 0xe && nvrram[nvraddr] != val) + savenvr(); + if (nvraddr!=0xC && nvraddr!=0xD) nvrram[nvraddr]=val; + + if (nvraddr==0xA) + { +// pclog("NVR rate %i\n",val&0xF); + if (val&0xF) + { + c=1<<((val&0xF)-1); + rtctime+=RTCCONST*(float)c; + } + else + rtctime=99999999; + } + } + else nvraddr=val&nvrmask; +} + +uint8_t readnvr(uint16_t addr) +{ + uint8_t temp; +// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc); + if (addr&1) + { + if (nvraddr<=0xA) getnvrtime(); + if (nvraddr==0xD) nvrram[0xD]|=0x80; + if (nvraddr==0xA) + { + temp=nvrram[0xA]; + nvrram[0xA]&=~0x80; + return temp; + } + if (nvraddr==0xC) + { + if (AMSTRAD) picintc(2); + else picintc(0x100); + temp=nvrram[0xC]; + nvrram[0xC]=0; + return temp; + } +// if (AMIBIOS && nvraddr==0x36) return 0; +// if (nvraddr==0xA) nvrram[0xA]^=0x80; + return nvrram[nvraddr]; + } + return nvraddr; +} + +void loadnvr() +{ + FILE *f; + int c; + nvrmask=63; + oldromset=romset; + switch (romset) + { + case ROM_PC1512: f = romfopen("pc1512.nvr", "rb"); break; + case ROM_PC1640: f = romfopen("pc1640.nvr", "rb"); break; + case ROM_PC200: f = romfopen("pc200.nvr", "rb"); break; + case ROM_PC2086: f = romfopen("pc2086.nvr", "rb"); break; + case ROM_PC3086: f = romfopen("pc3086.nvr", "rb"); break; + case ROM_IBMAT: f = romfopen("at.nvr" , "rb"); break; + case ROM_CMDPC30: f = romfopen("cmdpc30.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI286: f = romfopen("ami286.nvr", "rb"); nvrmask = 127; break; + case ROM_DELL200: f = romfopen("dell200.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMAT386: f = romfopen("at386.nvr" , "rb"); nvrmask = 127; break; + case ROM_ACER386: f = romfopen("acer386.nvr", "rb"); nvrmask = 127; break; + case ROM_MEGAPC: f = romfopen("megapc.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI386: f = romfopen("ami386.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI486: f = romfopen("ami486.nvr", "rb"); nvrmask = 127; break; + case ROM_WIN486: f = romfopen("win486.nvr", "rb"); nvrmask = 127; break; + case ROM_PCI486: f = romfopen("hot-433.nvr", "rb"); nvrmask = 127; break; + default: return; + } + if (!f) + { + memset(nvrram,0xFF,128); + return; + } + fread(nvrram,128,1,f); + fclose(f); + nvrram[0xA]=6; + nvrram[0xB]=0; + c=1<<((6&0xF)-1); + rtctime+=RTCCONST*(float)c; +} +void savenvr() +{ + FILE *f; + switch (oldromset) + { + case ROM_PC1512: f = romfopen("pc1512.nvr" , "wb"); break; + case ROM_PC1640: f = romfopen("pc1640.nvr" , "wb"); break; + case ROM_PC200: f = romfopen("pc200.nvr" , "wb"); break; + case ROM_PC2086: f = romfopen("pc2086.nvr" , "wb"); break; + case ROM_PC3086: f = romfopen("pc3086.nvr" , "wb"); break; + case ROM_IBMAT: f = romfopen("at.nvr" , "wb"); break; + case ROM_CMDPC30: f = romfopen("cmdpc30.nvr", "wb"); break; + case ROM_AMI286: f = romfopen("ami286.nvr" , "wb"); break; + case ROM_DELL200: f = romfopen("dell200.nvr", "wb"); break; + case ROM_IBMAT386: f = romfopen("at386.nvr" , "wb"); break; + case ROM_ACER386: f = romfopen("acer386.nvr", "wb"); break; + case ROM_MEGAPC: f = romfopen("megapc.nvr" , "wb"); break; + case ROM_AMI386: f = romfopen("ami386.nvr" , "wb"); break; + case ROM_AMI486: f = romfopen("ami486.nvr" , "wb"); break; + case ROM_WIN486: f = romfopen("win486.nvr" , "wb"); break; + case ROM_PCI486: f = romfopen("hot-433.nvr", "wb"); break; + default: return; + } + fwrite(nvrram,128,1,f); + fclose(f); +} + +void nvr_init() +{ + io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL); +} diff --git a/src/nvr.h b/src/nvr.h new file mode 100644 index 00000000..868b4577 --- /dev/null +++ b/src/nvr.h @@ -0,0 +1 @@ +void nvr_init(); diff --git a/src/olivetti_m24.c b/src/olivetti_m24.c new file mode 100644 index 00000000..d721d7c2 --- /dev/null +++ b/src/olivetti_m24.c @@ -0,0 +1,20 @@ +#include "ibm.h" +#include "io.h" +#include "olivetti_m24.h" + +uint8_t olivetti_m24_read(uint16_t port) +{ + switch (port) + { + case 0x66: + return 0x00; + case 0x67: + return 0x20 | 0x40 | 0x0C; + } + return 0xff; +} + +void olivetti_m24_init() +{ + io_sethandler(0x0066, 0x0002, olivetti_m24_read, NULL, NULL, NULL, NULL, NULL); +} diff --git a/src/olivetti_m24.h b/src/olivetti_m24.h new file mode 100644 index 00000000..72a6994e --- /dev/null +++ b/src/olivetti_m24.h @@ -0,0 +1 @@ +void olivetti_m24_init(); diff --git a/src/opti.c b/src/opti.c new file mode 100644 index 00000000..23ea454d --- /dev/null +++ b/src/opti.c @@ -0,0 +1,284 @@ +/*OPTi 82C495 emulation + This is the chipset used in the AMI386 model*/ +#include "ibm.h" + +uint8_t optiregs[0x10]; +int optireg; + +void writeopti(uint16_t addr, uint8_t val) +{ + switch (addr) + { + case 0x22: + optireg=val; + break; + case 0x24: + printf("Writing OPTI reg %02X %02X\n",optireg,val); + if (optireg>=0x20 && optireg<=0x2C) optiregs[optireg-0x20]=val; + break; + } +} + +uint8_t readopti(uint16_t addr) +{ + switch (addr) + { + case 0x24: + printf("Read OPTI reg %02X\n",optireg); + if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; + break; + } + return 0xFF; +} + +/*Details for the chipset from Ralph Brown's interrupt list + This describes the OPTi 82C493, the 82C495 seems similar except there is one + more register (2C) + +----------P00220024-------------------------- +PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS +Desc: The OPTi 486SXWB contains three chips and is designed for systems + running at 20, 25 and 33MHz. The chipset includes an 82C493 System + Controller (SYSC), the 82C392 Data Buffer Controller, and the + 82C206 Integrated peripheral Controller (IPC). +Note: every access to PORT 0024h must be preceded by a write to PORT 0022h, + even if the same register is being accessed a second time +SeeAlso: PORT 0022h"82C206" + +0022 ?W configuration register index (see #P0178) +0024 RW configuration register data + +(Table P0178) +Values for OPTi 82C493 System Controller configuration register index: + 20h Control Register 1 (see #P0179) + 21h Control Register 2 (see #P0180) + 22h Shadow RAM Control Register 1 (see #P0181) + 23h Shadow RAM Control Register 2 (see #P0182) + 24h DRAM Control Register 1 (see #P0183) + 25h DRAM Control Register 2 (see #P0184) + 26h Shadow RAM Control Register 3 (see #P0185) + 27h Control Register 3 (see #P0186) + 28h Non-cachable Block 1 Register 1 (see #P0187) + 29h Non-cachable Block 1 Register 2 (see #P0188) + 2Ah Non-cachable Block 2 Register 1 (see #P0187) + 2Bh Non-cachable Block 2 Register 2 (see #P0188) + +Bitfields for OPTi-82C493 Control Register 1: +Bit(s) Description (Table P0179) + 7-6 Revision of 82C493 (readonly) (default=01) + 5 Burst wait state control + 1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2 + 0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default) + (if bit 5 is set to 1, bit 4 must be set to 0) + 4 Cache memory data buffer output enable control + 0 = disable (default) + 1 = enable + (must be disabled for frequency <= 33Mhz) + 3 Single Address Latch Enable (ALE) + 0 = disable (default) + 1 = enable + (if enabled, SYSC will activate single ALE rather than multiples + during bus conversion cycles) + 2 enable Extra AT Cycle Wait State (default is 0 = disabled) + 1 Emulation keyboard Reset Control + 0 = disable (default) + 1 = enable + Note: This bit must be enabled in BIOS default value; enabling this + bit requires HALT instruction to be executed before SYSC + generates processor reset (CPURST) + 0 enable Alternative Fast Reset (default is 0 = disabled) +SeeAlso: #P0180,#P0186 + +Bitfields for OPTi-82C493 Control Register 2: +Bit(s) Description (Table P0180) + 7 Master Mode Byte Swap Enable + 0 = disable (default) + 1 = enable + 6 Emulation Keyboard Reset Delay Control + 0 = Generate reset pulse 2us later (default) + 1 = Generate reset pulse immediately + 5 disable Parity Check (default is 0 = enabled) + 4 Cache Enable + 0 = Cache disabled and DRAM burst mode enabled (default) + 1 = Cache enabled and DRAM burst mode disabled + 3-2 Cache Size + 00 64KB (default) + 01 128KB + 10 256KB + 11 512KB + 1 Secondary Cache Read Burst Cycles Control + 0 = 3-1-1-1 cycle (default) + 1 = 2-1-1-1 cycle + 0 Cache Write Wait State Control + 0 = 1 wait state (default) + 1 = 0 wait state +SeeAlso: #P0179,#P0186 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 1: +Bit(s) Description (Table P0181) + 7 ROM(F0000h - FFFFFh) Enable + 0 = read/write on write-protected DRAM + 1 = read from ROM, write to DRAM (default) + 6 Shadow RAM at D0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 5 Shadow RAM at E0000h - EFFFFh Area + 0 = disable shadow RAM (default) + E0000h - EFFFFh ROM is defaulted to reside on XD bus + 1 = enable shadow RAM + 4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area + 0 = disable (default) + 1 = enable + 3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 2 Hidden refresh enable (with holding CPU) + (Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used) + 1 = disable (default) + 0 = enable + 1 unused + 0 enable Slow Refresh (four times slower than normal refresh) + (default is 0 = disable) +SeeAlso: #P0182 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 2: +Bit(s) Description (Table P0182) + 7 enable Shadow RAM at EC000h - EFFFFh area + 6 enable Shadow RAM at E8000h - EBFFFh area + 5 enable Shadow RAM at E4000h - E7FFFh area + 4 enable Shadow RAM at E0000h - E3FFFh area + 3 enable Shadow RAM at DC000h - DFFFFh area + 2 enable Shadow RAM at D8000h - DBFFFh area + 1 enable Shadow RAM at D4000h - D7FFFh area + 0 enable Shadow RAM at D0000h - D3FFFh area +Note: the default is disabled (0) for all areas + +Bitfields for OPTi-82C493 DRAM Control Register 1: +Bit(s) Description (Table P0183) + 7 DRAM size + 0 = 256K DRAM mode + 1 = 1M and 4M DRAM mode + 6-4 DRAM types used for bank0 and bank1 + bits 7-4 Bank0 Bank1 + 0000 256K x + 0001 256K 256K + 0010 256K 1M + 0011 x x + 01xx x x + 1000 1M x (default) + 1001 1M 1M + 1010 1M 4M + 1011 4M 1M + 1100 4M x + 1101 4M 4M + 111x x x + 3 unused + 2-0 DRAM types used for bank2 and bank3 + bits 7,2-0 Bank2 Bank3 + x000 1M x + x001 1M 1M + x010 x x + x011 4M 1M + x100 4M x + x101 4M 4M + x11x x x (default) +SeeAlso: #P0184 + +Bitfields for OPTi-82C493 DRAM Control Register 2: +Bit(s) Description (Table P0184) + 7-6 Read cycle additional wait states + 00 not used + 01 = 0 + 10 = 1 + 11 = 2 (default) + 5-4 Write cycle additional wait states + 00 = 0 + 01 = 1 + 10 = 2 + 11 = 3 (default) + 3 Fast decode enable + 0 = disable fast decode. DRAM base wait states not changed (default) + 1 = enable fast decode. DRAM base wait state is decreased by 1 + Note: This function may be enabled in 20/25Mhz operation to speed up + DRAM access. If bit 4 of index register 21h (cache enable + bit) is enabled, this bit is automatically disabled--even if + set to 1 + 2 unused + 1-0 ATCLK selection + 00 ATCLK = CLKI/6 (default) + 01 ATCLK = CLKI/4 (default) + 10 ATCLK = CLKI/3 + 11 ATCLK = CLK2I/5 (CLKI * 2 /5) + Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be + set to 0 when 82C493 is reset. +SeeAlso: #P0183,#P0185 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 3: +Bit(s) Description (Table P0185) + 7 unused + 6 Shadow RAM copy enable for address C0000h - CFFFFh + 0 = Read/write at AT bus (default) + 1 = Read from AT bus and write into shadow RAM + 5 Shadow write protect at address C0000h - CFFFFh + 0 = Write protect disable (default) + 1 = Write protect enable + 4 enable Shadow RAM at C0000h - CFFFFh + 3 enable Shadow RAM at CC000h - CFFFFh + 2 enable Shadow RAM at C8000h - CBFFFh + 1 enable Shadow RAM at C4000h - C7FFFh + 0 enable Shadow RAM at C0000h - C3FFFh +Note: the default is disabled (0) for bits 4-0 +SeeAlso: #P0183,#P0184 + +Bitfields for OPTi-82C493 Control Register 3: +Bit(s) Description (Table P0186) + 7 enable NCA# pin to low state (default is 1 = enabled) + 6-5 unused + 4 Video BIOS at C0000h - C8000h non-cacheable + 0 = cacheable + 1 = non-cacheable (default) + 3-0 Cacheable address range for local memory + 0000 0 - 64MB + 0001 0 - 4MB (default) + 0010 0 - 8MB + 0011 0 - 12MB + 0100 0 - 16MB + 0101 0 - 20MB + 0110 0 - 24MB + 0111 0 - 28MB + 1000 0 - 32MB + 1001 0 - 36MB + 1010 0 - 40MB + 1011 0 - 44MB + 1100 0 - 48MB + 1101 0 - 52MB + 1110 0 - 56MB + 1111 0 - 60MB + Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or + 0-2 MB and independent of the value of bits 3-0 +SeeAlso: #P0179,#P0180 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 1: +Bit(s) Description (Table P0187) + 7-5 Size of non-cachable memory block + 000 64K + 001 128K + 010 256K + 011 512K + 1xx disabled (default) + 4-2 unused + 1-0 Address bits 25 and 24 of non-cachable memory block (default = 00) +Note: this register is used together with configuration register 29h + (non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to + define a non-cacheable block. The starting address must be a + multiple of the block size +SeeAlso: #P0178,#P0188 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 2: +Bit(s) Description (Table P0188) + 7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx) +Note: the block address is forced to be a multiple of the block size by + ignoring the appropriate number of the least-significant bits +SeeAlso: #P0178,#P0187 + +*/ diff --git a/src/pc.c b/src/pc.c new file mode 100644 index 00000000..447598b7 --- /dev/null +++ b/src/pc.c @@ -0,0 +1,491 @@ +#include +#include +#include "ibm.h" +#include "video.h" +#include "amstrad.h" +#include "dma.h" +#include "mem.h" +#include "ide.h" +#include "mouse.h" +#include "pic.h" +#include "pit.h" +#include "serial.h" +#include "cdrom-ioctl.h" +#include "cpu.h" +#include "model.h" +#include "plat-mouse.h" + +int cdrom_enabled; +int CPUID; +int kb_win; +int vid_resize; + +int cycles_lost = 0; + +int clockrate; +int insc=0; +float mips,flops; +extern int mmuflush; +extern int readlnum,writelnum; +void fullspeed(); + +int framecount,fps; +int pitsec; +int intcount; +int wakeups,wokeups; +int output; +int atfullspeed; +void loadconfig(); +void saveconfig(); +int infocus; +int mousecapture; +FILE *pclogf; +void pclog(const char *format, ...) +{ + char buf[256]; + return; + if (!pclogf) + pclogf=fopen("pclog.txt","wt"); +//return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); +fflush(pclogf); +} + +void fatal(const char *format, ...) +{ + char buf[256]; +// return; + if (!pclogf) + pclogf=fopen("pclog.txt","wt"); +//return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); + fflush(pclogf); + dumpregs(); + exit(-1); +} + +uint8_t cgastat; +int drawit=0; + +int pollmouse_delay = 2; +void pollmouse() +{ + int x,y; + pollmouse_delay--; + if (pollmouse_delay) return; + pollmouse_delay = 2; + poll_mouse(); + get_mouse_mickeys(&x,&y); + if (mouse_poll) + mouse_poll(x, y, mouse_b); + if (mousecapture) position_mouse(64,64); +} + +/*PC1512 languages - + 7=English + 6=German + 5=French + 4=Spanish + 3=Danish + 2=Swedish + 1=Italian + 3,2,1 all cause the self test to fail for some reason + */ + +int cpuspeed2; + +int clocks[3][12][4]= +{ + { + {4772728,13920,59660,5965}, /*4.77MHz*/ + {8000000,23333,110000,0}, /*8MHz*/ + {10000000,29166,137500,0}, /*10MHz*/ + {12000000,35000,165000,0}, /*12MHz*/ + {16000000,46666,220000,0}, /*16MHz*/ + }, + { + {8000000,23333,110000,0}, /*8MHz*/ + {12000000,35000,165000,0}, /*12MHz*/ + {16000000,46666,220000,0}, /*16MHz*/ + {20000000,58333,275000,0}, /*20MHz*/ + {25000000,72916,343751,0}, /*25MHz*/ + }, + { + {16000000, 46666,220000,0}, /*16MHz*/ + {20000000, 58333,275000,0}, /*20MHz*/ + {25000000, 72916,343751,0}, /*25MHz*/ + {33000000, 96000,454000,0}, /*33MHz*/ + {40000000,116666,550000,0}, /*40MHz*/ + {50000000, 72916*2,343751*2,0}, /*50MHz*/ + {33000000*2, 96000*2,454000*2,0}, /*66MHz*/ + {75000000, 72916*3,343751*3,0}, /*75MHz*/ + {80000000,116666*2,550000*2,0}, /*80MHz*/ + {100000000, 72916*4,343751*4,0}, /*100MHz*/ + {120000000,116666*3,550000*3,0}, /*120MHz*/ + {133000000, 96000*4,454000*4,0}, /*133MHz*/ + } +}; + +int updatestatus; +int win_title_update=0; + + +void onesec() +{ + fps=framecount; + framecount=0; + win_title_update=1; +} + +void pc_reset() +{ + resetx86(); + cpu_set(); + dma_reset(); + fdc_reset(); + pic_reset(); + pit_reset(); + serial_reset(); + + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + + adlib_reset(); + sb_reset(); + + ali1429_reset(); + et4000w32_reset(); + +// video_init(); +} + +void initpc() +{ + char *p; +// allegro_init(); + get_executable_name(pcempath,511); + pclog("executable_name = %s\n", pcempath); + p=get_filename(pcempath); + *p=0; + pclog("path = %s\n", pcempath); + + keyboard_init(); + mouse_init(); + + loadconfig(); + pclog("Config loaded\n"); + + cpuspeed2=(AT)?2:1; +// cpuspeed2=cpuspeed; + atfullspeed=0; + + pclog("Initvideo\n"); + + initvideo(); + mem_init(); + loadbios(); + + loaddisc(0,discfns[0]); + loaddisc(1,discfns[1]); + //loadfont(); + loadnvr(); + resetvideo(); + initsound(); + initpsg(); + inithdc(); + initega(); + initgus(); + resetide(); + ioctl_open(cdrom_drive); + model_init(); + video_init(); + adlib_init(); + sb_init(); + gus_init(); + + pc_reset(); + + pit_reset(); + install_int_ex(onesec,BPS_TO_TIMER(1)); +// install_int_ex(vsyncint,BPS_TO_TIMER(60)); +/* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); + mem_updatecache(); + ali1429_reset(); + et4000w32_reset(); +// CPUID=(is486 && (cpuspeed==7 || cpuspeed>=9)); +// pclog("Init - CPUID %i %i\n",CPUID,cpuspeed); + shadowbios=0; + +} + +void resetpc() +{ + pc_reset(); +// cpuspeed2=(AT)?2:1; +// atfullspeed=0; +///* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); + shadowbios=0; +} + +void resetpchard() +{ + mem_resize(); + model_init(); + pclog("Video_init\n"); + video_init(); + adlib_init(); + sb_init(); + gus_init(); + + pc_reset(); + + resetide(); + + loadnvr(); + +// cpuspeed2 = (AT)?2:1; +// atfullspeed = 0; +// setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + + shadowbios = 0; + ali1429_reset(); + + keyboard_at_reset(); + +// output=3; +} + +char romsets[17][40]={"IBM PC","IBM XT","Generic Turbo XT","Euro PC","Tandy 1000","Amstrad PC1512","Sinclair PC200","Amstrad PC1640","IBM AT","AMI 286 clone","Dell System 200","Misc 286","IBM AT 386","Misc 386","386 clone","486 clone","486 clone 2"}; +char clockspeeds[3][12][16]= +{ + {"4.77MHz","8MHz","10MHz","12MHz","16MHz"}, + {"8MHz","12MHz","16MHz","20MHz","25MHz"}, + {"16MHz","20MHz","25MHz","33MHz","40MHz","50MHz","66MHz","75MHz","80MHz","100MHz","120MHz","133MHz"}, +}; +int framecountx=0; +int sndcount=0; +int oldat70hz; + +int sreadlnum,swritelnum,segareads,segawrites, scycles_lost; + +int serial_fifo_read, serial_fifo_write; + +int emu_fps = 0; + +void runpc() +{ + char s[200]; + int done=0; + clockrate = models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed; + if (is386) exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + else if (AT) exec286(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + else execx86(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + keyboard_poll_host(); + keyboard_process(); +// checkkeys(); + pollmouse(); + framecountx++; + framecount++; + if (framecountx>=100) + { + framecountx=0; + mips=(float)insc/1000000.0f; + insc=0; + flops=(float)fpucount/1000000.0f; + fpucount=0; + sreadlnum=readlnum; + swritelnum=writelnum; + segareads=egareads; + segawrites=egawrites; + scycles_lost = cycles_lost; + updatestatus=1; + readlnum=writelnum=0; + egareads=egawrites=0; + cycles_lost = 0; + mmuflush=0; + pitsec=0; + intcount=0; + wakeups=wokeups=0; + intcount=pitcount=0; + emu_fps = frames; + frames = 0; + } + if (win_title_update) + { + win_title_update=0; + sprintf(s, "PCem v0.7 - %s - %s - %s - %i%% %i %04X %i", model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : "Press CTRL-END to release mouse", fps, et4000w32p_getclock(), ECX, ins); + set_window_title(s); + } + done++; +/* if ((at70hz && VGA)!=oldat70hz) + { + oldat70hz=(at70hz && VGA); + if (oldat70hz) setrefresh(70); //install_int_ex(vsyncint,BPS_TO_TIMER(70)); + else setrefresh(60); //install_int_ex(vsyncint,BPS_TO_TIMER(60)); + drawit=0; + done=0; + }*/ +// printf("End of run!\n"); +// } +} + +void fullspeed() +{ + cpuspeed2=cpuspeed; + if (!atfullspeed) + { + printf("Set fullspeed - %i %i %i\n",is386,AT,cpuspeed2); + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); +// if (is386) setpitclock(clocks[2][cpuspeed2][0]); +// else setpitclock(clocks[AT?1:0][cpuspeed2][0]); + } + atfullspeed=1; + nvr_recalc(); +} + +void speedchanged() +{ + if (atfullspeed) + { + cpuspeed2=cpuspeed; + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); +// if (is386) setpitclock(clocks[2][cpuspeed2][0]); +// else setpitclock(clocks[AT?1:0][cpuspeed2][0]); + } + mem_updatecache(); + nvr_recalc(); +} + +void closepc() +{ + atapi->exit(); +// ioctl_close(); + dumpegaregs(); + dumppic(); + dumpgus(); +// output=7; +// setpitclock(clocks[0][0][0]); +// while (1) runpc(); + savedisc(0); + savedisc(1); + dumpregs(); + closevideo(); +} + +/*int main() +{ + initpc(); + while (!key[KEY_F11]) + { + runpc(); + } + closepc(); + return 0; +} + +END_OF_MAIN();*/ + +int cga_comp=0; + +void loadconfig() +{ + char s[512]; + char *p; + append_filename(s,pcempath,"pcem.cfg",511); + set_config_file(s); + ADLIB=get_config_int(NULL,"adlib",1); + GAMEBLASTER=get_config_int(NULL,"gameblaster",0); + FASTDISC=get_config_int(NULL,"fast_disc",1); + + model = get_config_int(NULL, "model", 14); + pclog("Model %i\n", model); + romset = model_getromset(); + cpu_manufacturer = get_config_int(NULL, "cpu_manufacturer", 0); + cpu = get_config_int(NULL, "cpu", 0); + + gfxcard=get_config_int(NULL,"gfxcard",0); + video_speed = get_config_int(NULL, "video_speed", 3); + sbtype=get_config_int(NULL,"sndcard",SB2); + pclog("Model1 %i\n", model); + p=(char *)get_config_string(NULL,"disc_a",""); + if (p) strcpy(discfns[0],p); + else strcpy(discfns[0],""); + pclog("Model2 %i\n", model); + p=(char *)get_config_string(NULL,"disc_b",""); + if (p) strcpy(discfns[1],p); + else strcpy(discfns[1],""); + pclog("Model3 %i\n", model); + mem_size=get_config_int(NULL,"mem_size",4); + cdrom_drive=get_config_int(NULL,"cdrom_drive",0); + cdrom_enabled=get_config_int(NULL,"cdrom_enabled",0); + + slowega=get_config_int(NULL,"slow_video",1); + cache=get_config_int(NULL,"cache",3); + cga_comp=get_config_int(NULL,"cga_composite",0); + + kb_win=get_config_int(NULL,"kb_win",0); + vid_resize=get_config_int(NULL,"vid_resize",0); +// cpuspeed=2; + + hdc[0].spt=get_config_int(NULL,"hdc_sectors",0); + hdc[0].hpc=get_config_int(NULL,"hdc_heads",0); + hdc[0].tracks=get_config_int(NULL,"hdc_cylinders",0); + p = (char *)get_config_string(NULL, "hdc_fn", ""); + if (p) strcpy(ide_fn[0], p); + else strcpy(ide_fn[0], ""); + hdc[1].spt=get_config_int(NULL,"hdd_sectors",0); + hdc[1].hpc=get_config_int(NULL,"hdd_heads",0); + hdc[1].tracks=get_config_int(NULL,"hdd_cylinders",0); + p = (char *)get_config_string(NULL, "hdd_fn", ""); + if (p) strcpy(ide_fn[1], p); + else strcpy(ide_fn[1], ""); + pclog("Model4 %i\n", model); +} + +void saveconfig() +{ + pclog("saveconfig\n"); + config_new(); + pclog("config_new\n"); + set_config_int(NULL,"adlib",ADLIB); + pclog("sci 1\n"); + set_config_int(NULL,"gameblaster",GAMEBLASTER); + set_config_int(NULL,"fast_disc",FASTDISC); + + set_config_int(NULL, "model", model); + set_config_int(NULL, "cpu_manufacturer", cpu_manufacturer); + set_config_int(NULL, "cpu", cpu); + + set_config_int(NULL,"gfxcard",gfxcard); + set_config_int(NULL,"video_speed", video_speed); + set_config_int(NULL,"sndcard",sbtype); + set_config_int(NULL,"cpu_speed",cpuspeed); + set_config_int(NULL,"has_fpu",hasfpu); + set_config_int(NULL,"slow_video",slowega); + set_config_int(NULL,"cache",cache); + set_config_int(NULL,"cga_composite",cga_comp); + set_config_string(NULL,"disc_a",discfns[0]); + set_config_string(NULL,"disc_b",discfns[1]); + set_config_int(NULL,"mem_size",mem_size); + set_config_int(NULL,"cdrom_drive",cdrom_drive); + set_config_int(NULL,"cdrom_enabled",cdrom_enabled); + set_config_int(NULL,"kb_win",kb_win); + set_config_int(NULL,"vid_resize",vid_resize); + + set_config_int(NULL,"hdc_sectors",hdc[0].spt); + set_config_int(NULL,"hdc_heads",hdc[0].hpc); + set_config_int(NULL,"hdc_cylinders",hdc[0].tracks); + set_config_string(NULL, "hdc_fn", ide_fn[0]); + set_config_int(NULL,"hdd_sectors",hdc[1].spt); + set_config_int(NULL,"hdd_heads",hdc[1].hpc); + set_config_int(NULL,"hdd_cylinders",hdc[1].tracks); + set_config_string(NULL, "hdd_fn", ide_fn[1]); + pclog("saveconfig done\n"); +} diff --git a/src/pc.rc b/src/pc.rc new file mode 100644 index 00000000..a0ef5ad3 --- /dev/null +++ b/src/pc.rc @@ -0,0 +1,158 @@ +#include +#include "resources.h" + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Hard Reset", IDM_FILE_HRESET + MENUITEM "E&xit", IDM_FILE_EXIT + END + POPUP "&Disc" + BEGIN + MENUITEM "Change drive &A:...", IDM_DISC_A + MENUITEM "Change drive &B:...", IDM_DISC_B + MENUITEM "&Eject drive A:", IDM_EJECT_A + MENUITEM "Eject drive B:", IDM_EJECT_B + MENUITEM "&Configure hard discs...",IDM_HDCONF + END + POPUP "&Settings" + BEGIN + MENUITEM "&Configure...", IDM_CONFIG + POPUP "&CD-ROM" + BEGIN + MENUITEM "&Disabled", IDM_CDROM_DISABLED + MENUITEM "&Empty",IDM_CDROM_EMPTY + END + POPUP "&Video" + BEGIN + MENUITEM "&Resizeable window",IDM_VID_RESIZE + END + END + POPUP "&Misc" + BEGIN + MENUITEM "&Status", IDM_STATUS + END +END + +ConfigureDlg DIALOGEX 0, 0, 182, 240 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure PCem" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,17,216,50,14, WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,71,216,50,14, WS_TABSTOP + COMBOBOX IDC_COMBO1,62,16,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO2,62,36,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOCPUM,62,56,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO3,62,76,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOCHC,62,96,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOSPD,62,116,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOSND,62,136,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOMEM,62,152,107,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CONTROL "Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,172,118,10 + CONTROL "Composite CGA",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,188,118,10 + LTEXT "Machine :",IDC_STATIC,15,16,40,10 + LTEXT "Video :",IDC_STATIC,15,36,34,10 + LTEXT "CPU type :",IDC_STATIC,15,56,34,10 + LTEXT "CPU :",IDC_STATIC,15,76,34,10 + LTEXT "Cache :",IDC_STATIC,15,96,40,10 + LTEXT "Video speed :",IDC_STATIC,15,116,40,10 + LTEXT "Soundcard :",IDC_STATIC,15,136,40,10 + LTEXT "Memory :",IDC_STATIC,15,156,40,10 +END + +HdConfDlg DIALOGEX 0, 0, 186, 172 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure Hard Discs" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,152,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,152,50,14 + + LTEXT "C:",IDC_STATIC,7,6,27,10 + EDITTEXT IDC_EDITC, 7, 22, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_CFILE,7 + 136, 22, 16, 14 + PUSHBUTTON "New",IDC_CNEW,7 + 136 + 16, 22, 24, 14 + + EDITTEXT IDC_EDIT1,36,38,16,12, WS_DISABLED + EDITTEXT IDC_EDIT2,94,38,16,12, WS_DISABLED + EDITTEXT IDC_EDIT3,152,38,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,38,27,10 + LTEXT "Heads:",IDC_STATIC,63,38,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,38,32,12 + LTEXT "", IDC_TEXT1, 7, 54, 136, 12 + + LTEXT "D:",IDC_STATIC,7,76,27,10 + EDITTEXT IDC_EDITD, 7, 92, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_DFILE,7 + 136, 92, 16, 14 + PUSHBUTTON "New",IDC_DNEW,7 + 136 + 16, 92, 24, 14 + + EDITTEXT IDC_EDIT4,36,108,16,12, WS_DISABLED + EDITTEXT IDC_EDIT5,94,108,16,12, WS_DISABLED + EDITTEXT IDC_EDIT6,152,108,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,108,27,10 + LTEXT "Heads:",IDC_STATIC,63,108,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,108,32,12 + LTEXT "", IDC_TEXT2, 7, 124, 136, 12 + +END + +HdNewDlg DIALOGEX 0, 0, 186, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Hard Disc" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 + + EDITTEXT IDC_EDITC, 7, 6, 136, 12 + PUSHBUTTON "...",IDC_CFILE,7 + 136, 6, 16, 14 + + EDITTEXT IDC_EDIT1,36,22,16,12 + EDITTEXT IDC_EDIT2,94,22,16,12 + EDITTEXT IDC_EDIT3,152,22,28,12 + LTEXT "Sectors:",IDC_STATIC,7,22,27,10 + LTEXT "Heads:",IDC_STATIC,63,22,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22,32,12 + LTEXT "", IDC_TEXT1, 7, 38, 136, 12 +END + +HdSizeDlg DIALOGEX 0, 0, 186, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Hard disc parameters" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 + + LTEXT "Initial settings are based on file size",IDC_STATIC,7,6,170,10 + + EDITTEXT IDC_EDIT1,36,22,16,12 + EDITTEXT IDC_EDIT2,94,22,16,12 + EDITTEXT IDC_EDIT3,152,22,28,12 + LTEXT "Sectors:",IDC_STATIC,7,22,27,10 + LTEXT "Heads:",IDC_STATIC,63,22,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22,32,12 + LTEXT "", IDC_TEXT1, 7, 38, 136, 12 +END + +StatusDlg DIALOGEX 0,0,186,186 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "1",IDC_STEXT1,16,16,180,10 + LTEXT "2",IDC_STEXT2,16,28,180,10 + LTEXT "3",IDC_STEXT3,16,40,180,10 + LTEXT "4",IDC_STEXT4,16,52,180,10 + LTEXT "5",IDC_STEXT5,16,64,180,10 + LTEXT "6",IDC_STEXT6,16,76,180,10 + LTEXT "7",IDC_STEXT7,16,88,180,10 + LTEXT "8",IDC_STEXT8,16,100,180,10 + LTEXT "9",IDC_STEXT9,16,112,180,10 + LTEXT "10",IDC_STEXT10,16,124,180,10 + LTEXT "11",IDC_STEXT11,16,136,180,10 + LTEXT "12",IDC_STEXT12,16,148,180,10 + LTEXT "13",IDC_STEXT13,16,160,180,10 +END diff --git a/src/pci.c b/src/pci.c new file mode 100644 index 00000000..1c8d7b8a --- /dev/null +++ b/src/pci.c @@ -0,0 +1,99 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" + +#include "pci.h" + +void (*pci_card_write[32])(int func, int addr, uint8_t val); +uint8_t (*pci_card_read[32])(int func, int addr); +static int pci_index, pci_func, pci_card, pci_bus, pci_enable; +static uint8_t card_16[256]; +static uint8_t card_18[256]; + +void pci_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0xcf8: + pci_index = val; + break; + case 0xcf9: + pci_func = val & 7; + pci_card = val >> 3; + break; + case 0xcfa: + pci_bus = val; + break; + case 0xcfb: + pci_enable = val & 0x80; + break; + + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return; + + pclog("PCI write bus %i card %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_index | (port & 3), val, CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + pci_card_write[pci_card](pci_func, pci_index | (port & 3), val); + + break; + } +} + +uint8_t pci_read(uint16_t port) +{ + switch (port) + { + case 0xcf8: + return pci_index; + case 0xcf9: + return pci_card << 3; + case 0xcfa: + return pci_bus; + case 0xcfb: + return pci_enable; + + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return 0xff; + + pclog("PCI read bus %i card %i index %02X\n", pci_bus, pci_card, pci_index | (port & 3)); + + if (!pci_bus && pci_card_read[pci_card]) + return pci_card_read[pci_card](pci_func, pci_index | (port & 3)); + + return 0xff; + } +} + +void pci_init() +{ + int c; + + io_sethandler(0x0cf8, 0x0008, pci_read, NULL, NULL, pci_write, NULL, NULL); + + for (c = 0; c < 32; c++) + pci_card_read[c] = pci_card_write[c] = NULL; +} + +void pci_add_specific(int card, uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val)) +{ + pci_card_read[card] = read; + pci_card_write[card] = write; +} + +void pci_add(uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val)) +{ + int c; + + for (c = 0; c < 32; c++) + { + if (!pci_card_read[c] && !pci_card_write[c]) + { + pci_card_read[c] = read; + pci_card_write[c] = write; + return; + } + } +} diff --git a/src/pci.h b/src/pci.h new file mode 100644 index 00000000..457f65a3 --- /dev/null +++ b/src/pci.h @@ -0,0 +1,3 @@ +void pci_init(); +void pci_add_specific(int card, uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val)); +void pci_add(uint8_t (*read)(int func, int addr), void (*write)(int func, int addr, uint8_t val)); diff --git a/src/pic.c b/src/pic.c new file mode 100644 index 00000000..76c2f597 --- /dev/null +++ b/src/pic.c @@ -0,0 +1,313 @@ +#include "ibm.h" + +int output; +int intclear; +int keywaiting=0; +int pit0; +int pic_intpending; + +void pic_updatepending() +{ + pic_intpending = (((pic.pend&~pic.mask)&~pic.mask2) || ((pic2.pend&~pic2.mask)&~pic2.mask2)); +} + + +void pic_reset() +{ + pic.icw=0; + pic.mask=0xFF; + pic.mask2=0; + pic.pend=pic.ins=0; + pic.vector=8; + pic.read=1; + pic2.icw=0; + pic2.mask=0xFF; + pic.mask2=0; + pic2.pend=pic2.ins=0; + pic_intpending = 0; +} + +void pic_write(uint16_t addr, uint8_t val) +{ + int c; +// pclog("Write PIC %04X %02X %04X(%06X):%04X\n",addr,val,CS,cs,pc); + if (addr&1) + { + switch (pic.icw) + { + case 0: /*OCW1*/ +// printf("Write mask %02X %04X:%04X\n",val,CS,pc); + pic.mask=val; + pic_updatepending(); + break; + case 1: /*ICW2*/ + pic.vector=val&0xF8; +// printf("PIC vector now %02X\n",pic.vector); + // output=1; + if (pic.icw1&2) pic.icw=3; + else pic.icw=2; + break; + case 2: /*ICW3*/ + if (pic.icw1&1) pic.icw=3; + else pic.icw=0; + break; + case 3: /*ICW4*/ + pic.icw=0; + break; + } + } + else + { + if (val&16) /*ICW1*/ + { + pic.mask=0xFF; + pic.mask2=0; + pic.icw=1; + pic.icw1=val; + pic_updatepending(); + } + else if (!(val&8)) /*OCW2*/ + { +// printf("Clear ints - %02X %02X\n",pic.ins,val); + if ((val&0xE0)==0x60) + { +// pclog("Specific EOI - %02X %i\n",pic.ins,1<<(val&7)); + pic.ins&=~(1<<(val&7)); + pic.mask2&=~(1<<(val&7)); +// pic.pend&=(1<<(val&7)); +// if ((val&7)==1) pollkeywaiting(); + pic_updatepending(); + } + else + { + for (c=0;c<8;c++) + { + if (pic.ins&(1<0xFF) + { + pic2.pend|=(num>>8); + } + else + { + pic.pend|=num; + } + pic_updatepending(); +} + +void picintlevel(uint16_t num) +{ + int c = 0; + while (!(num & (1 << c))) c++; +// pclog("INTLEVEL %04X %i\n", num, c); + if (!pic_current[c]) + { + pic_current[c]=1; + if (num>0xFF) + { + pic2.pend|=(num>>8); + } + else + { + pic.pend|=num; + } + } + pic_updatepending(); +} +void picintc(uint16_t num) +{ + int c = 0; + while (!(num & (1 << c))) c++; +// pclog("INTC %04X %i\n", num, c); + pic_current[c]=0; + if (num>0xFF) pic2.pend&=~(num>>8); + else + { + pic.pend&=~num; + } +} + +uint8_t picinterrupt() +{ + uint8_t temp=pic.pend&~pic.mask; + int c; + for (c=0;c<8;c++) + { + if (temp&(1< +#include "ibm.h" +#include "pit.h" +#include "video.h" +#include "cpu.h" +/*B0 to 40, two writes to 43, then two reads - value does not change!*/ +/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ +//Tyrian writes 4300 or 17512 +int displine; + +int pitsec=0; +double PITCONST; +float cpuclock; +float isa_timing, bus_timing; + +int firsttime=1; +void setpitclock(float clock) +{ + float temp; +// printf("PIT clock %f\n",clock); + cpuclock=clock; + PITCONST=clock/1193182.0; + SPKCONST=clock/48000.0; + CGACONST=(clock/(19687500.0/11.0)); + MDACONST=(clock/1813000.0); + VGACONST1=(clock/25175000.0); + VGACONST2=(clock/28322000.0); + setsbclock(clock); + SOUNDCONST=clock/200.0; + CASCONST=PITCONST*1192; + isa_timing = clock/8000000.0; + bus_timing = clock/(double)cpu_busspeed; + video_updatetiming(); +// pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock); + GUSCONST=(clock/3125.0)/4.0; + GUSCONST2=(clock/3125.0)/4.0; //Timer 2 at different rate to 1? + video_recalctimings(); + RTCCONST=clock/32768.0; +} + +//#define PITCONST (8000000.0/1193000.0) +//#define PITCONST (cpuclock/1193000.0) +int pit0; +void pit_reset() +{ + memset(&pit,0,sizeof(PIT)); + pit.l[0]=0xFFFF; pit.c[0]=0xFFFF*PITCONST; + pit.l[1]=0xFFFF; pit.c[1]=0xFFFF*PITCONST; + pit.l[2]=0xFFFF; pit.c[2]=0xFFFF*PITCONST; + pit.m[0]=pit.m[1]=pit.m[2]=0; + pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0; + pit.thit[0]=1; + spkstat=0; +} + +void clearpit() +{ + pit.c[0]=(pit.l[0]<<2); +} + +float pit_timer0_freq() +{ +// pclog("PIT timer 0 freq %04X %f %f\n",pit.l[0],(float)pit.l[0],1193182.0f/(float)pit.l[0]); + return 1193182.0f/(float)pit.l[0]; +} +extern int ins; +void pit_write(uint16_t addr, uint8_t val) +{ + int t; + uint8_t oldctrl=pit.ctrl; + cycles -= (int)PITCONST; + pit0=1; +// printf("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins); + switch (addr&3) + { + case 3: /*CTRL*/ + if ((val&0xC0)==0xC0) + { + if (!(val&0x20)) + { + if (val&2) pit.rl[0]=pit.c[0]/PITCONST; + if (val&4) pit.rl[1]=pit.c[1]/PITCONST; + if (val&8) pit.rl[2]=pit.c[2]/PITCONST; + } + return; + } + pit.ctrls[val>>6]=pit.ctrl=val; + if ((val>>7)==3) + { + printf("Bad PIT reg select\n"); + return; +// dumpregs(); +// exit(-1); + } +// printf("CTRL write %02X\n",val); + if (!(pit.ctrl&0x30)) + { + pit.rl[val>>6]=pit.c[val>>6]/PITCONST; + if (pit.c[val>>6]<0) pit.rl[val>>6]=0; +// pclog("Timer latch %f %04X %04X\n",pit.c[0],pit.rl[0],pit.l[0]); + pit.ctrl|=0x30; + pit.rereadlatch[val>>6]=0; + pit.rm[val>>6]=3; + } + else + { + pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3; + pit.m[val>>6]=(val>>1)&7; + if (pit.m[val>>6]>5) + pit.m[val>>6]&=3; + if (!(pit.rm[val>>6])) + { + pit.rm[val>>6]=3; + pit.rl[val>>6]=pit.c[val>>6]/PITCONST; + } + pit.rereadlatch[val>>6]=1; + if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1; +// pclog("ppispeakon %i\n",ppispeakon); + } + pit.wp=0; + pit.thit[pit.ctrl>>6]=0; + break; + case 0: case 1: case 2: /*Timers*/ + t=addr&3; +// if (t==2) ppispeakon=speakon=0; +// pclog("Write timer %02X %i\n",pit.ctrls[t],pit.wm[t]); + switch (pit.wm[t]) + { + case 1: + pit.l[t]=val; + pit.thit[t]=0; + pit.c[t]=pit.l[t]*PITCONST; + picintc(1); + break; + case 2: + pit.l[t]=(val<<8); + pit.thit[t]=0; + pit.c[t]=pit.l[t]*PITCONST; + picintc(1); + break; + case 0: + pit.l[t]&=0xFF; + pit.l[t]|=(val<<8); + pit.c[t]=pit.l[t]*PITCONST; +// pclog("%04X %f\n",pit.l[t],pit.c[t]); + pit.thit[t]=0; + pit.wm[t]=3; + picintc(1); + break; + case 3: + pit.l[t]&=0xFF00; + pit.l[t]|=val; + pit.wm[t]=0; + break; +/* + if (pit.wp) + { + pit.l[t]&=0xFF; + pit.l[t]|=(val<<8); + pit.c[t]=pit.l[t]*PITCONST; + pit.thit[t]=0; + } + else + { + pit.l[t]&=0xFF00; + pit.l[t]|=val; + } + pit.rl[t]=pit.l[t]; + pit.wp^=1; + pit.rm[t]=3; + pit.rereadlatch[t]=1; + break;*/ + } + speakval=(((float)pit.l[2]/(float)pit.l[0])*0x4000)-0x2000; +// printf("Speakval now %i\n",speakval); +// if (speakval>0x2000) +// printf("Speaker overflow - %i %i %04X %04X\n",pit.l[0],pit.l[2],pit.l[0],pit.l[2]); + if (speakval>0x2000) speakval=0x2000; + if (!pit.l[t]) + { + pit.l[t]|=0x10000; + pit.c[t]=pit.l[t]*PITCONST; + } + break; + } +} + +uint8_t pit_read(uint16_t addr) +{ + uint8_t temp; + cycles -= (int)PITCONST; +// printf("Read PIT %04X ",addr); + switch (addr&3) + { + case 0: case 1: case 2: /*Timers*/ + if (pit.rereadlatch[addr&3])// || !(pit.ctrls[addr&3]&0x30)) + { + pit.rereadlatch[addr&3]=0; + pit.rl[addr&3]=pit.c[addr&3]/PITCONST; + if ((pit.c[addr&3]/PITCONST)>65536) pit.rl[addr&3]=0xFFFF; + } + switch (pit.rm[addr&3]) + { + case 0: + temp=pit.rl[addr&3]>>8; + pit.rm[addr&3]=3; + pit.rereadlatch[addr&3]=1; + break; + case 1: + temp=(pit.rl[addr&3])&0xFF; + pit.rereadlatch[addr&3]=1; + break; + case 2: + temp=(pit.rl[addr&3])>>8; + pit.rereadlatch[addr&3]=1; + break; + case 3: + temp=(pit.rl[addr&3])&0xFF; + if (pit.m[addr&3]&0x80) pit.m[addr&3]&=7; + else pit.rm[addr&3]=0; + break; + } + break; + case 3: /*Control*/ + temp=pit.ctrl; + } +// printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc); + return temp; +} + +void pit_poll() +{ + pitsec++; +// printf("Poll pit %f %f %f\n",pit.c[0],pit.c[1],pit.c[2]); + if (pit.c[0]<1) + { + if (pit.m[0]==0 || pit.m[0]==4) + { +// pit.c[0]&=0xFFFF; + pit.c[0]+=(0x10000*PITCONST); + } + else if (pit.m[0]==3 || pit.m[0]==2) + { + if (pit.l[0]) pit.c[0]+=((float)(pit.l[0]*PITCONST)); + else pit.c[0]+=((float)(0x10000*PITCONST)); + } +// pit.c[0]+=(pit.l[0]*PITCONST); +// printf("PIT over! %f %i\n",pit.c[0],pit.m[0]); + if (!pit.thit[0] && (pit.l[0]>0x14)) + { +// printf("PIT int!\n"); +/// printf("%05X %05X %02X\n",pit.c[0],pit.l[0],pit.ctrls[0]); + picint(1); + } + if (!pit.m[0] || pit.m[0]==4) pit.thit[0]=1; +// if ((pit.ctrls[0]&0xE)==2) pit.thit[0]=1; + pit0=0; + pitcount++; + } + if (pit.c[1]<1) + { + // if (output) printf("PIT1 over %02X\n",pit.m[1]); + if (pit.m[1]==0 || pit.m[1]==4) + { + pit.c[1]=0xFFFFFF*PITCONST; + } + else + { + pit.c[1]+=(pit.l[1]*PITCONST); + } +// if (output) pclog("%f %04X %02X\n",pit.c[1],pit.l[1],pit.ctrls[1]); +// printf("DMA0!\n"); + readdma0(); + } + if (pit.c[2]<1) + { +// printf("PIT 2 over %i\n",pit.m[2]); + if (!pit.m[2] || pit.m[2]==4) + { + pit.c[2]+=(0x10000*PITCONST); + speakon^=1; + ppispeakon^=1; + } + else + { + pit.c[2]+=((pit.l[2]*PITCONST)/2); + if (pit.l[2]>0x30) /*Some games use very high frequencies as 'speaker off'. This stops them from generating noise*/ + speakon^=1; + ppispeakon^=1; +// printf("Speakon %i %04X %i\n",speakon,pit.l[2],pit.c[2]); + } +// if (pit.ctrls[2]&0xE) pit.c[2]+=(pit.l[2]*PITCONST); +// spkstat^=0x20; + } +} + +void pit_init() +{ + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL); +} diff --git a/src/pit.h b/src/pit.h new file mode 100644 index 00000000..9ea790d2 --- /dev/null +++ b/src/pit.h @@ -0,0 +1,3 @@ +extern double PITCONST; +void pit_init(); +void pit_reset(); diff --git a/src/plat-dinput.h b/src/plat-dinput.h new file mode 100644 index 00000000..e9ab85d9 --- /dev/null +++ b/src/plat-dinput.h @@ -0,0 +1 @@ +extern LPDIRECTINPUT lpdi; diff --git a/src/plat-keyboard.h b/src/plat-keyboard.h new file mode 100644 index 00000000..da0e03c3 --- /dev/null +++ b/src/plat-keyboard.h @@ -0,0 +1,15 @@ +#ifdef __cplusplus +extern "C" { +#endif + void keyboard_init(); + void keyboard_close(); + void keyboard_poll_host(); + int key[256]; + + #define KEY_LCONTROL 0x1d + #define KEY_RCONTROL (0x1d | 0x80) + #define KEY_END (0x4f | 0x80) +#ifdef __cplusplus +} +#endif + diff --git a/src/plat-mouse.h b/src/plat-mouse.h new file mode 100644 index 00000000..ff020ea3 --- /dev/null +++ b/src/plat-mouse.h @@ -0,0 +1,13 @@ +#ifdef __cplusplus +extern "C" { +#endif + void mouse_init(); + void mouse_remove(); + extern int mouse_b; + void poll_mouse(); + void position_mouse(int x, int y); + void get_mouse_mickeys(int *x, int *y); +#ifdef __cplusplus +} +#endif + diff --git a/src/ppi.c b/src/ppi.c new file mode 100644 index 00000000..83cab9ba --- /dev/null +++ b/src/ppi.c @@ -0,0 +1,19 @@ +/*IBM 5150 cassette nonsense + Calls F979 twice + Expects CX to be nonzero, BX >$410 and <$540 + CX is loops between bit 4 of $62 changing + BX is timer difference between calls + */ + +#include "ibm.h" +#include "pit.h" + +#include "plat-keyboard.h" +#include "plat-mouse.h" + +void ppi_reset() +{ + ppi.pa=0x0;//0x1D; + ppi.pb=0x40; +} + diff --git a/src/ppi.h b/src/ppi.h new file mode 100644 index 00000000..2bdff7cb --- /dev/null +++ b/src/ppi.h @@ -0,0 +1 @@ +extern int wasgated; diff --git a/src/psg.c b/src/psg.c new file mode 100644 index 00000000..2aa4ea02 --- /dev/null +++ b/src/psg.c @@ -0,0 +1,206 @@ +#include "ibm.h" + +float volslog[16]= +{ + 0.00000f,0.59715f,0.75180f,0.94650f, + 1.19145f,1.50000f,1.88835f,2.37735f, + 2.99295f,3.76785f,4.74345f,5.97165f, + 7.51785f,9.46440f,11.9194f,15.0000f +}; + +float psgcount[4],psglatch[4]; +int psgstat[4]; +int snlatch[4],sncount[4]; +int snfreqlo[4],snfreqhi[4]; +int snvol[4]; +int curfreq[4]; +uint32_t snshift[2]={0x8000,0x8000}; + +#define SNCLOCK (2386360>>5) +uint8_t snnoise; + +void initpsg() +{ + int c; + for (c=0;c<4;c++) + { + psgcount[c]=psglatch[c]=100000; + psgstat[c]=0; + } +} + +#define PSGCONST (32000.0/48000.0) + +void getpsg(signed short *p, int size) +{ +// printf("Getpsg %08X %i\n",p,size); +// return; + int c,d; + for (c=0;c1.0) + { + psgcount[d]+=psglatch[d]; + psgstat[d]^=1; + } + if (psgcount[d]<=0.0) psgcount[d]=1.0; + } + d=(snnoise&4)?0:1; + if (snshift[d]&1) p[c]+=volslog[snvol[0]]*170; + psgcount[0]-=(512*PSGCONST); + while (psgcount[0]<=0.0 && psglatch[0]>1.0) + { + psgcount[0]+=psglatch[0]; + snshift[1]>>=1; + if (!snshift[1]) snshift[1]=0x4000; + if ((snshift[0]&1)^((snshift[0]&4)?1:0)^((snshift[0]&0x8000)?1:0)) + snshift[0]|=0x10000; + snshift[0]>>=1; + } + if (psgcount[0]<=0.0) psgcount[0]=1.0; + } +} + +int lasttone; +uint8_t firstdat; +void writepsg(uint16_t addr, uint8_t data) +{ + int c; + int freq; + pclog("Write PSG %02X\n", data); + if (data&0x80) + { + firstdat=data; + switch (data&0x70) + { + case 0: + snfreqlo[3]=data&0xF; + lasttone=3; + break; + case 0x10: + data&=0xF; + snvol[3]=0xF-data; + break; + case 0x20: + snfreqlo[2]=data&0xF; + lasttone=2; + break; + case 0x30: + data&=0xF; + snvol[2]=0xF-data; + break; + case 0x40: + snfreqlo[1]=data&0xF; + lasttone=1; + break; + case 0x50: + data&=0xF; + snvol[1]=0xF-data; + break; + case 0x60: + if ((data&3)!=(snnoise&3)) sncount[0]=0; + snnoise=data&0xF; + if ((data&3)==3) + { + curfreq[0]=curfreq[1]>>4; + snlatch[0]=snlatch[1]; + } + else + { + switch (data&3) + { + case 0: + snlatch[0]=128<<7; + curfreq[0]=SNCLOCK/256; + snlatch[0]=0x400; + sncount[0]=0; + break; + case 1: + snlatch[0]=256<<7; + curfreq[0]=SNCLOCK/512; + snlatch[0]=0x800; + sncount[0]=0; + break; + case 2: + snlatch[0]=512<<7; + curfreq[0]=SNCLOCK/1024; + snlatch[0]=0x1000; + sncount[0]=0; + break; + case 3: + snlatch[0]=snlatch[1]; + sncount[0]=0; + } + if (snnoise&4) snlatch[0]<<=1; + } + break; + case 0x70: + data&=0xF; + snvol[0]=0xF-data; + break; + } + } + else + { + if ((firstdat&0x70)==0x60) + { + if ((data&3)!=(snnoise&3)) sncount[0]=0; + snnoise=data&0xF; + if ((data&3)==3) + { + curfreq[0]=curfreq[1]>>4; + snlatch[0]=snlatch[1]; +// printf("SN 0 latch %04X\n",snlatch[0]); + } + else + { + switch (data&3) + { + case 0: + snlatch[0]=128<<7; + curfreq[0]=SNCLOCK/256; + snlatch[0]=0x400; + sncount[0]=0; + break; + case 1: + snlatch[0]=256<<7; + curfreq[0]=SNCLOCK/512; + snlatch[0]=0x800; + sncount[0]=0; + break; + case 2: + snlatch[0]=512<<7; + curfreq[0]=SNCLOCK/1024; + snlatch[0]=0x1000; + sncount[0]=0; + break; + case 3: + snlatch[0]=snlatch[1]; +// printf("SN 0 latch %04X\n",snlatch[0]); + sncount[0]=0; + } + if (snnoise&4) snlatch[0]<<=1; + } + return; + } + else + { + snfreqhi[lasttone]=data&0x3F; + freq=snfreqlo[lasttone]|(snfreqhi[lasttone]<<4); + snlatch[lasttone]=freq<<6; + } + } + for (c=0;c<4;c++) psglatch[c]=(float)snlatch[c]; +} + +void psg_init() +{ + pclog("psg_init\n"); + io_sethandler(0x00C0, 0x0001, NULL, NULL, NULL, writepsg, NULL, NULL); +} diff --git a/src/psg.h b/src/psg.h new file mode 100644 index 00000000..a4cf69d5 --- /dev/null +++ b/src/psg.h @@ -0,0 +1 @@ +void psg_init(); diff --git a/src/resources.h b/src/resources.h new file mode 100644 index 00000000..b718a203 --- /dev/null +++ b/src/resources.h @@ -0,0 +1,62 @@ +#define IDM_FILE_RESET 40000 +#define IDM_FILE_HRESET 40001 +#define IDM_FILE_EXIT 40002 +#define IDM_DISC_A 40010 +#define IDM_DISC_B 40011 +#define IDM_EJECT_A 40012 +#define IDM_EJECT_B 40013 +#define IDM_HDCONF 40014 +#define IDM_CONFIG 40020 +#define IDM_STATUS 40030 +#define IDM_KEY_ALLEGRO 40040 +#define IDM_KEY_WINDOWS 40041 +#define IDM_VID_RESIZE 40050 +#define IDM_CDROM_EMPTY 40100 +#define IDM_CDROM_REAL 40100 +#define IDM_CDROM_DISABLED 40200 + +#define IDC_COMBO1 1000 +#define IDC_COMBO2 1001 +#define IDC_COMBO3 1002 +#define IDC_COMBO4 1003 +#define IDC_COMBO5 1004 +#define IDC_COMBO386 1005 +#define IDC_COMBO486 1006 +#define IDC_COMBOSND 1007 +#define IDC_COMBOCHC 1008 +#define IDC_COMBOMEM 1009 +#define IDC_COMBOCPUM 1060 +#define IDC_COMBOSPD 1061 +#define IDC_CHECK1 1010 +#define IDC_CHECK2 1011 +#define IDC_CHECK3 1012 +#define IDC_CHECK4 1013 +#define IDC_STATIC 1020 +#define IDC_EDIT1 1030 +#define IDC_EDIT2 1031 +#define IDC_EDIT3 1032 +#define IDC_EDIT4 1033 +#define IDC_EDIT5 1034 +#define IDC_EDIT6 1035 +#define IDC_TEXT1 1040 +#define IDC_TEXT2 1041 +#define IDC_EDITC 1050 +#define IDC_CFILE 1051 +#define IDC_CNEW 1052 +#define IDC_EDITD 1053 +#define IDC_DFILE 1054 +#define IDC_DNEW 1055 + +#define IDC_STEXT1 1100 +#define IDC_STEXT2 1101 +#define IDC_STEXT3 1102 +#define IDC_STEXT4 1103 +#define IDC_STEXT5 1104 +#define IDC_STEXT6 1105 +#define IDC_STEXT7 1106 +#define IDC_STEXT8 1107 +#define IDC_STEXT9 1108 +#define IDC_STEXT10 1109 +#define IDC_STEXT11 1110 +#define IDC_STEXT12 1111 +#define IDC_STEXT13 1112 diff --git a/src/sblaster.c b/src/sblaster.c new file mode 100644 index 00000000..25038ec2 --- /dev/null +++ b/src/sblaster.c @@ -0,0 +1,1104 @@ +/*Jazz sample rates : + 386-33 - 12kHz + 486-33 - 20kHz + 486-50 - 32kHz + Pentium - 45kHz*/ + +#include +#include +#include "ibm.h" +#include "filters.h" +#include "io.h" + +static int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; +static int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; +static int sb_pausetime = -1; + +static uint8_t sb_read_data[256]; +static int sb_read_wp, sb_read_rp; +static int sb_speaker; + +static int sb_data_stat=-1; + +static int sb_irqnum = 7; + +static uint8_t sbe2; +static int sbe2count; + +static int sbe2dat[4][9] = { + { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, + { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, + { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, + { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } +}; + +static uint8_t sb_data[8]; +static int sb_commands[256]= +{ + -1,-1,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, + 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, + 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, + 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, + 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, + 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 +}; + +char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405}; + +/*These tables were 'borrowed' from DOSBox*/ + int8_t scaleMap4[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 + }; + uint8_t adjustMap4[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 + }; + + int8_t scaleMap26[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 + }; + uint8_t adjustMap26[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 + }; + + int8_t scaleMap2[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 + }; + uint8_t adjustMap2[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 + }; + + +int sb_freq; + +int sbtype=0; + +int writebusy=0; /*Needed for Amnesia*/ + +int16_t sbdatl=0,sbdatr=0; +int16_t sb16datl=0,sb16datr=0; + +int16_t sbdat; +uint8_t sbref; +int sbdacmode,sbdacpos,sbdat2; +int8_t sbstep; +int sbleftright=0; +int sbinput=0; +int sbreadstat,sbwritestat; +int sbreset; +uint8_t sbreaddat; +uint8_t sb_command,sbdata; +int sbcommandnext=1; +uint8_t sb_test; +int sb_timei,sb_timeo; +int sbcommandstat; +int sbhalted; +int adpcmstat=0; +int sbautolen; +int sbautoinit=0; +uint8_t sbcurcommand,sbdmacommand; +float SBCONST; +int sbstereo=0; + +int sbsamprate; +uint8_t sb_transfertype; +int sb_newtransfer; +int sb_dma16; +int sb_uart; +int sb_irq8,sb_irq16; +int sb_16_exit; + +uint8_t mixerindex; +uint8_t sb_mixer[256]; +uint8_t sb_asp_regs[256]; + + +int sb_att[]= +{ + 310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479, + 4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845, + 39036,46395,55140,65535 +}; + +void sb_irq(int irq8) +{ +// pclog("IRQ %i %02X\n",irq8,pic.mask); + if (irq8) sb_irq8=1; + else sb_irq16=1; + picint(1 << sb_irqnum); +} +void sb_irqc(int irq8) +{ + if (irq8) sb_irq8=0; + else sb_irq16=0; + picintc(1 << sb_irqnum); +} + +void sb_mixer_set() +{ + if (sbtype==SB16) + { + mixer.master_l=sb_att[sb_mixer[0x30]>>3]; + mixer.master_r=sb_att[sb_mixer[0x31]>>3]; + mixer.voice_l =sb_att[sb_mixer[0x32]>>3]; + mixer.voice_r =sb_att[sb_mixer[0x33]>>3]; + mixer.fm_l =sb_att[sb_mixer[0x34]>>3]; + mixer.fm_r =sb_att[sb_mixer[0x35]>>3]; + mixer.bass_l =sb_mixer[0x46]>>4; + mixer.bass_r =sb_mixer[0x47]>>4; + mixer.treble_l=sb_mixer[0x44]>>4; + mixer.treble_r=sb_mixer[0x45]>>4; + mixer.filter=0; + pclog("%02X %02X %02X %02X %02X %02X\n",sb_mixer[0x30],sb_mixer[0x31],sb_mixer[0x32],sb_mixer[0x33],sb_mixer[0x34],sb_mixer[0x35]); + pclog("Mixer - %04X %04X %04X %04X %04X %04X\n",mixer.master_l,mixer.master_r,mixer.voice_l,mixer.voice_r,mixer.fm_l,mixer.fm_r); + } + else if (sbtype==SBPRO || sbtype==SBPRO2) + { + mixer.master_l=sb_att[(sb_mixer[0x22]>>4)|0x11]; + mixer.master_r=sb_att[(sb_mixer[0x22]&0xF)|0x11]; + mixer.voice_l =sb_att[(sb_mixer[0x04]>>4)|0x11]; + mixer.voice_r =sb_att[(sb_mixer[0x04]&0xF)|0x11]; + mixer.fm_l =sb_att[(sb_mixer[0x26]>>4)|0x11]; + mixer.fm_r =sb_att[(sb_mixer[0x26]&0xF)|0x11]; + mixer.filter =!(sb_mixer[0xE]&0x20); + mixer.bass_l =mixer.bass_r =8; + mixer.treble_l=mixer.treble_r=8; + pclog("%02X %02X %02X\n",sb_mixer[0x04],sb_mixer[0x22],sb_mixer[0x26]); + pclog("Mixer - %04X %04X %04X %04X %04X %04X\n",mixer.master_l,mixer.master_r,mixer.voice_l,mixer.voice_r,mixer.fm_l,mixer.fm_r); + } + else + { + mixer.master_l=mixer.master_r=65535; + mixer.voice_l =mixer.voice_r =65535; + mixer.fm_l =mixer.fm_r =65535; + mixer.bass_l =mixer.bass_r =8; + mixer.treble_l=mixer.treble_r=8; + mixer.filter=1; + } +} + +void sb_mixer_reset() +{ + pclog("Mixer reset\n"); + if (sbtype==SB16) + { + sb_mixer[0x30]=31<<3; + sb_mixer[0x31]=31<<3; + sb_mixer[0x32]=31<<3; + sb_mixer[0x33]=31<<3; + sb_mixer[0x34]=31<<3; + sb_mixer[0x35]=31<<3; + sb_mixer[0x44]=8<<4; + sb_mixer[0x45]=8<<4; + sb_mixer[0x46]=8<<4; + sb_mixer[0x47]=8<<4; + sb_mixer[0x22]=(sb_mixer[0x30]&0xF0)|(sb_mixer[0x31]>>4); + sb_mixer[0x04]=(sb_mixer[0x32]&0xF0)|(sb_mixer[0x33]>>4); + sb_mixer[0x26]=(sb_mixer[0x34]&0xF0)|(sb_mixer[0x35]>>4); + } + if (sbtype==SBPRO || sbtype==SBPRO2) + { + sb_mixer[0x22]=0xFF; + sb_mixer[0x04]=0xFF; + sb_mixer[0x26]=0xFF; + sb_mixer[0xE]=0; + } +} + +void sb_dsp_reset() +{ + sbenable = sb_enable_i = 0; + sb_command = 0; + + sb_uart = 0; + sb_8_length = sbautolen = 0xFFFF; + + sb_irqc(0); + sb_irqc(1); + sb_16_pause = 0; + sb_read_wp = sb_read_rp = 0; + sb_data_stat = -1; + sb_speaker = 0; + sb_pausetime = -1; + sbe2 = 0xAA; + sbe2count = 0; + + sbreset = 0; + sbenable = sb_enable_i = sb_count_i = 0; + sbhalted = 0; + sbdmacommand = 0; + sbstereo = 0; + + picintc(1 << sb_irqnum); +} + +void sb_reset() +{ + int c; + + sb_dsp_reset(); + sb_mixer_reset(); + sb_mixer_set(); + + if (sbtype==SB16) sb_commands[8]=1; + else sb_commands[8]=-1; + + for (c = 0; c < 256; c++) + sb_asp_regs[c] = 0; + sb_asp_regs[5] = 0x01; + sb_asp_regs[9] = 0xf8; +} + +void setsbclock(float clock) +{ + SBCONST=clock/1000000.0f; + printf("SBCONST %f %f\n",SBCONST,clock); + if (sb_timeo>255) sblatcho=(int)(SBCONST*(1000000.0f/(float)(sb_timeo-256))); + else sblatcho=SBCONST*(256-sb_timeo); + if (sb_timei>255) sblatchi=(int)(SBCONST*(1000000.0f/(float)(sb_timei-256))); + else sblatchi=SBCONST*(256-sb_timei); +} + +void outmidi(uint8_t v) +{ + printf("Write MIDI %02X\n",v); +} + +void setsbtype(int type) +{ + sbtype=type; + sbstereo=0; + sb_mixer_set(); + if (sbtype==SB16) sb_commands[8]=1; + else sb_commands[8]=-1; +} + + + + + + + +void sb_add_data(uint8_t v) +{ + sb_read_data[sb_read_wp++]=v; + sb_read_wp&=0xFF; +} + +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 + +void sb_start_dma(int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + sb_8_length=len; + sb_8_format=format; + sb_8_autoinit=autoinit; + sb_8_pause=0; + sb_8_enable=1; + if (sb_16_enable && sb_16_output) sb_16_enable = 0; + sb_8_output=1; + sbenable=sb_8_enable; + sbleftright=0; + sbdacpos=0; +// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + sb_16_length=len; + sb_16_format=format; + sb_16_autoinit=autoinit; + sb_16_pause=0; + sb_16_enable=1; + if (sb_8_enable && sb_8_output) sb_8_enable = 0; + sb_16_output=1; + sbenable=sb_16_enable; +// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); + } +} + +void sb_start_dma_i(int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + sb_8_length=len; + sb_8_format=format; + sb_8_autoinit=autoinit; + sb_8_pause=0; + sb_8_enable=1; + if (sb_16_enable && !sb_16_output) sb_16_enable = 0; + sb_8_output=0; + sb_enable_i=sb_8_enable; +// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + sb_16_length=len; + sb_16_format=format; + sb_16_autoinit=autoinit; + sb_16_pause=0; + sb_16_enable=1; + if (sb_8_enable && !sb_8_output) sb_8_enable = 0; + sb_16_output=0; + sb_enable_i=sb_16_enable; +// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } +} + +uint8_t sb_8_read_dma() +{ + return readdma1(); +} +void sb_8_write_dma(uint8_t val) +{ + writedma1(val); +} +uint16_t sb_16_read_dma() +{ + return readdma5(); +} +void sb_16_write_dma(uint16_t val) +{ + writedma5(val); +} + +void sb_exec_command() +{ + int temp,c; +// pclog("SB command %02X\n",sb_command); + switch (sb_command) + { + case 0x10: /*8-bit direct mode*/ + sbdat=sbdatl=sbdatr=(sb_data[0]^0x80)<<8; + break; + case 0x14: /*8-bit single cycle DMA output*/ + sb_start_dma(1,0,0,sb_data[0]+(sb_data[1]<<8)); + break; + case 0x17: /*2-bit ADPCM output with reference*/ + sbref=sb_8_read_dma(); + sbstep=0; +// pclog("Ref byte 2 %02X\n",sbref); + case 0x16: /*2-bit ADPCM output*/ + sb_start_dma(1,0,ADPCM_2,sb_data[0]+(sb_data[1]<<8)); + sbdat2=sb_8_read_dma(); + sb_8_length--; + break; + case 0x1C: /*8-bit autoinit DMA output*/ + if (sbtype>8); + sb_add_data(sb_dsp_versions[sbtype]&0xFF); + break; + case 0xE2: /*Stupid ID/protection*/ + for (c=0;c<8;c++) + if (sb_data[0]&(1<>4,pc,sb_command); + switch (a&0xF) + { + case 0: case 1: case 2: case 3: /*OPL or Gameblaster*/ + if (GAMEBLASTER && sbtype < SBPRO) + writecms(a, v); + else if (sbtype >= SBPRO) + adlib_write(a,v); + return; + case 4: mixerindex=v; return; + case 5: + sb_mixer[mixerindex]=v; +// pclog("Write mixer data %02X %02X\n",mixerindex,sb_mixer[mixerindex]); + if (sbtype==SB16) + { + switch (mixerindex) + { + case 0x22: + sb_mixer[0x30]=((sb_mixer[0x22]>>4)|0x11)<<3; + sb_mixer[0x31]=((sb_mixer[0x22]&0xF)|0x11)<<3; + break; + case 0x04: + sb_mixer[0x32]=((sb_mixer[0x04]>>4)|0x11)<<3; + sb_mixer[0x33]=((sb_mixer[0x04]&0xF)|0x11)<<3; + break; + case 0x26: + sb_mixer[0x34]=((sb_mixer[0x26]>>4)|0x11)<<3; + sb_mixer[0x35]=((sb_mixer[0x26]&0xF)|0x11)<<3; + break; + case 0x80: + if (v & 1) sb_irqnum = 2; + if (v & 2) sb_irqnum = 5; + if (v & 4) sb_irqnum = 7; + if (v & 8) sb_irqnum = 10; + break; + } + } +// if (!mixerindex) sb_mixer_reset(); + sb_mixer_set(); + return; + case 6: /*Reset*/ + if (!(v&1) && (sbreset&1)) + { + sb_dsp_reset(); + sb_add_data(0xAA); + } + sbreset=v; + return; + case 8: case 9: adlib_write(a,v); return; /*OPL*/ + case 0xC: /*Command/data write*/ + if (sb_uart) return; + if (sb_data_stat==-1) + { + sb_command=v; +// if (sb_commands[v]==-1) +// fatal("Bad SB command %02X\n",v); + sb_data_stat++; + } + else + sb_data[sb_data_stat++]=v; + if (sb_data_stat==sb_commands[sb_command] || sb_commands[sb_command]==-1) + { + sb_exec_command(); + sb_data_stat=-1; + } + break; + } +} + +uint8_t sb_read(uint16_t a) +{ + uint8_t temp; +// if (a==0x224) output=1; +// printf("Read soundblaster %04X %04X:%04X\n",a,cs,pc); + switch (a&0xF) + { + case 0: case 1: case 2: case 3: /*OPL or GameBlaster*/ + if (GAMEBLASTER && sbtype < SBPRO) + return readcms(a); + return adlib_read(a); + break; + case 5: + if (sbtype=SB16) + { + switch (sb_irqnum) + { + case 2: return 1; /*IRQ 7*/ + case 5: return 2; /*IRQ 7*/ + case 7: return 4; /*IRQ 7*/ + case 10: return 8; /*IRQ 7*/ + } + } + if (mixerindex==0x81 && sbtype>=SB16) return 0x22; /*DMA 1 and 5*/ + if (mixerindex==0x82 && sbtype>=SB16) return ((sb_irq8)?1:0)|((sb_irq16)?2:0); + return sb_mixer[mixerindex]; + case 8: case 9: return adlib_read(a); /*OPL*/ + case 0xA: /*Read data*/ + if (sb_uart) return; + sbreaddat=sb_read_data[sb_read_rp]; + if (sb_read_rp!=sb_read_wp) + { + sb_read_rp++; + sb_read_rp&=0xFF; + } +// pclog("SB read %02X\n",sbreaddat); + return sbreaddat; + case 0xC: /*Write data ready*/ + cycles-=100; + writebusy++; + if (writebusy&8) return 0xFF; + return 0x7F; + case 0xE: /*Read data ready*/ + picintc(1 << sb_irqnum); + sb_irq8=sb_irq16=0; + return (sb_read_rp==sb_read_wp)?0x7f:0xff; + case 0xF: /*16-bit ack*/ + sb_irq16=0; + if (!sb_irq8) picintc(1 << sb_irqnum); + return 0xff; + } + return 0; +} + +void sb_init() +{ + int c; + + sb_reset(); + + io_sethandler(0x0220, 0x0010, sb_read, NULL, NULL, sb_write, NULL, NULL); +} + + +int sbshift4[8]={-2,-1,0,0,1,1,1,1}; +void pollsb() +{ + int tempi,ref; +// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (sb_8_enable && !sb_8_pause && sb_pausetime<0 && sb_8_output) + { +// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); + switch (sb_8_format) + { + case 0x00: /*Mono unsigned*/ + sbdat=(sb_8_read_dma()^0x80)<<8; + if (sbtype>=SBPRO && sbtype=SBPRO && sbtype>4)+sbstep; + if (tempi<0) tempi=0; + if (tempi>63) tempi=63; + + ref = sbref + scaleMap4[tempi]; + if (ref > 0xff) sbref = 0xff; + else if (ref < 0x00) sbref = 0x00; + else sbref = ref; + + sbstep = (sbstep + adjustMap4[tempi]) & 0xff; + + sbdat=(sbref^0x80)<<8; + + sbdacpos++; + if (sbdacpos>=2) + { + sbdacpos=0; + sbdat2=sb_8_read_dma(); + sb_8_length--; + } + + if (sbtype>=SBPRO && sbtype>5)+sbstep; + else if (sbdacpos==1) tempi=((sbdat2>>2)&7)+sbstep; + else tempi=((sbdat2<<1)&7)+sbstep; + + if (tempi<0) tempi=0; + if (tempi>39) tempi=39; + + ref = sbref + scaleMap26[tempi]; + if (ref > 0xff) sbref = 0xff; + else if (ref < 0x00) sbref = 0x00; + else sbref = ref; + sbstep = (sbstep + adjustMap26[tempi]) & 0xff; + + sbdat=(sbref^0x80)<<8; + + sbdacpos++; + if (sbdacpos>=3) + { + sbdacpos=0; + sbdat2=readdma1(); + sb_8_length--; + } + + if (sbtype>=SBPRO && sbtype>((3-sbdacpos)*2))&3)+sbstep; + if (tempi<0) tempi=0; + if (tempi>23) tempi=23; + + ref = sbref + scaleMap2[tempi]; + if (ref > 0xff) sbref = 0xff; + else if (ref < 0x00) sbref = 0x00; + else sbref = ref; + sbstep = (sbstep + adjustMap2[tempi]) & 0xff; + + sbdat=(sbref^0x80)<<8; + + sbdacpos++; + if (sbdacpos>=4) + { + sbdacpos=0; + sbdat2=readdma1(); + } + + if (sbtype>=SBPRO && sbtype-1) + { + sb_pausetime--; + if (sb_pausetime<0) + { + sb_irq(1); + sbenable=sb_8_enable; + pclog("SB pause over\n"); + } + } +} + +void sb_poll_i() +{ +// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (sb_8_enable && !sb_8_pause && sb_pausetime<0 && !sb_8_output) + { + switch (sb_8_format) + { + case 0x00: /*Mono unsigned*/ + sb_8_write_dma(0x80); + sb_8_length--; + break; + case 0x10: /*Mono signed*/ + sb_8_write_dma(0x00); + sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + sb_8_write_dma(0x80); + sb_8_write_dma(0x80); + sb_8_length-=2; + break; + case 0x30: /*Stereo signed*/ + sb_8_write_dma(0x00); + sb_8_write_dma(0x00); + sb_8_length-=2; + break; + +// default: +// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); + } + + if (sb_8_length<0) + { +// pclog("Input DMA over %i\n",sb_8_autoinit); + if (sb_8_autoinit) sb_8_length=sb_8_autolen; + else sb_8_enable=sbenable=0; + sb_irq(1); + } + } + if (sb_16_enable && !sb_16_pause && sb_pausetime<0 && !sb_16_output) + { + switch (sb_16_format) + { + case 0x00: /*Unsigned mono*/ + sb_16_write_dma(0x8000); + sb_16_length--; + break; + case 0x10: /*Signed mono*/ + sb_16_write_dma(0); + sb_16_length--; + break; + case 0x20: /*Unsigned stereo*/ + sb_16_write_dma(0x8000); + sb_16_write_dma(0x8000); + sb_16_length-=2; + break; + case 0x30: /*Signed stereo*/ + sb_16_write_dma(0); + sb_16_write_dma(0); + sb_16_length-=2; + break; + +// default: +// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); + } + + if (sb_16_length<0) + { +// pclog("16iDMA over %i\n",sb_16_autoinit); + if (sb_16_autoinit) sb_16_length=sb_16_autolen; + else sb_16_enable=sbenable=0; + sb_irq(0); + } + } +} + +int16_t sbbuffer[2][SOUNDBUFLEN+20]; +int sbbufferpos=0; +int _sampcnt=0; +int16_t sb_filtbuf[4]={0,0,0,0}; +void getsbsamp() +{ + int vocl=sbpmixer.vocl*sbpmixer.masl; + int vocr=sbpmixer.vocr*sbpmixer.masr; + int16_t sbdat[2]; + double t; + + vocl=256-vocl; + vocr=256-vocr; + if (!vocl) vocl=1; + if (!vocr) vocr=1; + if (sbbufferpos>=(SOUNDBUFLEN+20)) return; + + sbdat[0]=sbdatl; + sbdat[1]=sbdatr; + + if (mixer.filter) + { + /*3.2kHz output filter*/ + sbdat[0]=(int16_t)(sb_iir(0,(float)sbdat[0])/1.3); + sbdat[1]=(int16_t)(sb_iir(1,(float)sbdat[1])/1.3); + } + + sbbuffer[0][sbbufferpos]=sbdat[0]; + sbbuffer[1][sbbufferpos]=sbdat[1]; + sbbufferpos++; +} + +void addsb(int16_t *p) +{ + int c; + if (sbbufferpos>SOUNDBUFLEN) sbbufferpos=SOUNDBUFLEN; +// printf("Addsb - %i %04X\n",sbbufferpos,p[0]); + for (c=0;c>16); + p[(c<<1)+1]+=(((sbbuffer[1][c]/3)*mixer.voice_r)>>16); +// if (!c) pclog("V %04X %04X %04X\n",sbbuffer[0][c],p[c<<1],mixer.voice_l); + } + for (;c>16); + p[(c<<1)+1]+=(((sbbuffer[0][sbbufferpos-1]/3)*mixer.voice_l)>>16); + } + sbbufferpos=0; +} + diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 00000000..294b5361 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,210 @@ +#include "ibm.h" +#include "io.h" +#include "mouse.h" +#include "serial.h" + +SERIAL serial,serial2; + +int mousepos=-1; +int mousedelay; +uint8_t serial_fifo[256]; +int serial_fifo_read, serial_fifo_write; + +void (*serial_rcr)(); + +void serial_reset() +{ + serial.iir=serial.ier=serial.lcr=0; + serial2.iir=serial2.ier=serial2.lcr=0; + mousedelay=0; + serial_fifo_read = serial_fifo_write = 0; +} + +void serial_write_fifo(uint8_t dat) +{ + serial_fifo[serial_fifo_write] = dat; + serial_fifo_write = (serial_fifo_write + 1) & 0xFF; + if (!(serial.linestat & 1)) + { + serial.linestat|=1; + if (serial.mctrl&8) picint(0x10); + serial.iir=4; + } +} + +uint8_t serial_read_fifo() +{ + uint8_t temp = serial_fifo[serial_fifo_read]; + if (serial_fifo_read != serial_fifo_write) + serial_fifo_read = (serial_fifo_read + 1) & 0xFF; + return temp; +} + +void sendserial(uint8_t dat) +{ + serial.rcr=dat; + serial.linestat|=1; + if (serial.mctrl&8) picint(0x10); + serial.iir=4; +} + +void serial_write(uint16_t addr, uint8_t val) +{ +// printf("Write serial %03X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr&7) + { + case 0: + if (serial.lcr&0x80 && !AMSTRADIO) + { + serial.dlab1=val; + return; + } + serial.thr=val; + serial.linestat|=0x20; + if (serial.mctrl&0x10) + { + serial_write_fifo(val); +// serial.rcr=val; +// serial.linestat|=1; + } + break; + case 1: + if (serial.lcr&0x80 && !AMSTRADIO) + { + serial.dlab2=val; + return; + } + serial.ier=val; + break; + case 3: serial.lcr=val; break; + case 4: + if ((val&2) && !(serial.mctrl&2)) + { + if (serial_rcr) + serial_rcr(); +// printf("RCR raised! sending M\n"); + } + serial.mctrl=val; + break; + } +} + +uint8_t serial_read(uint16_t addr) +{ + uint8_t temp; +// printf("Read serial %03X %04X(%08X):%04X %i %i ", addr, CS, cs, pc, mousedelay, ins); + switch (addr&7) + { + case 0: + if (serial.lcr&0x80 && !AMSTRADIO) return serial.dlab1; +// picintc(0x10); + serial.iir=1; + serial.linestat&=~1; + temp=serial_read_fifo(); + if (serial_fifo_read != serial_fifo_write) + { + mousepos = 0; + mousedelay = 1000; +// pclog("Next FIFO\n"); + } + break; + case 1: + if (serial.lcr&0x80 && !AMSTRADIO) temp = serial.dlab2; + else temp = 0; + break; + case 2: temp=serial.iir; break; + case 3: temp=serial.lcr; break; + case 4: temp=serial.mctrl; break; + case 5: temp=serial.linestat; serial.linestat|=0x60; break; + default: temp=0; + } +// printf("%02X\n",temp); + return temp; +} + +void serial2_write(uint16_t addr, uint8_t val) +{ +// printf("Write serial2 %03X %02X %04X:%04X\n",addr,val,cs>>4,pc); + switch (addr&7) + { + case 0: + if (serial2.lcr&0x80 && !AMSTRADIO) + { + serial2.dlab1=val; + return; + } + serial2.thr=val; + serial2.linestat|=0x20; + if (serial2.mctrl&0x10) + { + serial2.rcr=val; + serial2.linestat|=1; + } + break; + case 1: + if (serial2.lcr&0x80 && !AMSTRADIO) + { + serial2.dlab2=val; + return; + } + serial2.ier=val; + break; + case 3: serial2.lcr=val; break; + case 4: + serial2.mctrl=val; + break; + } +} + +uint8_t serial2_read(uint16_t addr) +{ + uint8_t temp; +// printf("Read serial2 %03X %04X:%04X\n",addr,cs>>4,pc); + switch (addr&7) + { + case 0: + if (serial2.lcr&0x80 && !AMSTRADIO) return serial2.dlab1; + serial2.iir=1; + serial2.linestat&=~1; + temp=serial2.rcr; + break; + case 1: + if (serial2.lcr&0x80 && !AMSTRADIO) return serial2.dlab2; + temp=0; + break; + case 2: temp=serial2.iir; break; + case 3: temp=serial2.lcr; break; + case 4: temp=serial2.mctrl; break; + case 5: temp=serial2.linestat; break; + default: temp=0; + } +// printf("%02X\n",temp); + return temp; +} + + +/*Tandy might need COM1 at 2f8*/ +void serial1_init(uint16_t addr) +{ + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL); + serial_rcr = NULL; +} +void serial1_remove() +{ + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL); +} + +void serial2_init(uint16_t addr) +{ + io_sethandler(addr, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL); +} +void serial2_remove() +{ + io_removehandler(0x2e8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL); + io_removehandler(0x2f8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL); + io_removehandler(0x3e8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL); + io_removehandler(0x3f8, 0x0008, serial2_read, NULL, NULL, serial2_write, NULL, NULL); +} diff --git a/src/serial.h b/src/serial.h new file mode 100644 index 00000000..bf0397d6 --- /dev/null +++ b/src/serial.h @@ -0,0 +1,17 @@ +void serial1_init(uint16_t addr); +void serial2_init(uint16_t addr); +void serial1_remove(); +void serial2_remove(); +void serial_reset(); + +typedef struct +{ + uint8_t linestat,thr,mctrl,rcr,iir,ier,lcr; + uint8_t dlab1,dlab2; +} SERIAL; + +extern SERIAL serial,serial2; + +extern int serial_fifo_read, serial_fifo_write; + +extern void (*serial_rcr)(); diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 00000000..f1963717 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,180 @@ +#include +#include "ibm.h" +#include "filters.h" + +int soundon = 1; +int16_t *adbuffer,*adbuffer2; +int16_t *psgbuffer; +uint16_t *cmsbuffer; +int16_t *spkbuffer; +int16_t *outbuffer; +uint16_t *gusbuffer; + +void initsound() +{ + initalmain(0,NULL); + inital(); +// install_sound(DIGI_AUTODETECT,MIDI_NONE,0); +// as=play_audio_stream(SOUNDBUFLEN,16,1,48000,255,128); + adbuffer=malloc((SOUNDBUFLEN)*2); + adbuffer2=malloc((SOUNDBUFLEN)*2); + psgbuffer=malloc((SOUNDBUFLEN)*2); + cmsbuffer=malloc((SOUNDBUFLEN)*2*2); + gusbuffer=malloc((SOUNDBUFLEN)*2*2); + spkbuffer=malloc(((SOUNDBUFLEN)*2)+32); + outbuffer=malloc((SOUNDBUFLEN)*2*2); +} + +int adpoll=0; +void pollad() +{ +/* if (adpoll>=20) return; + getadlibl(adbuffer+(adpoll*(48000/200)),48000/200); + getadlibr(adbuffer2+(adpoll*(48000/200)),48000/200); + adpoll++;*/ +// printf("ADPOLL %i\n",adpoll); +} + +void polladlib() +{ + getadlib(adbuffer+(adpoll),adbuffer2+(adpoll),1); + adpoll++; +} + +int psgpoll=0; +void pollpsg() +{ + if (psgpoll>=20) return; + getpsg(psgbuffer+(psgpoll*(48000/200)),48000/200); + psgpoll++; +} + +int cmspoll=0; +void pollcms() +{ + if (cmspoll>=20) return; + getcms(cmsbuffer+(cmspoll*(48000/200)*2),48000/200); + cmspoll++; +} + +int guspoll=0; +void pollgussnd() +{ + if (guspoll>=20) return; + getgus(gusbuffer+(guspoll*(48000/200)*2),48000/200); + guspoll++; +} + +int spkpos=0; +int wasgated = 0; +void pollspk() +{ + if (spkpos>=SOUNDBUFLEN) return; +// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]); + if (gated) + { + if (!pit.m[2] || pit.m[2]==4) + spkbuffer[spkpos]=speakval; + else + spkbuffer[spkpos]=(speakon)?0x1400:0; + } + else + spkbuffer[spkpos]=(wasgated)?0x1400:0; + spkpos++; + wasgated=0; +} + +FILE *soundf; + +static int16_t cd_buffer[(SOUNDBUFLEN) * 2]; +void pollsound() +{ + int c; + int16_t t[4]; + uint32_t pos; +// printf("Pollsound! %i\n",soundon); +// if (soundon) +// { + for (c=0;c<(SOUNDBUFLEN);c++) outbuffer[c<<1]=outbuffer[(c<<1)+1]=0; + for (c=0;c<(SOUNDBUFLEN);c++) + { + outbuffer[c<<1]+=((adbuffer[c]*mixer.fm_l)>>16); + outbuffer[(c<<1)+1]+=((adbuffer[c]*mixer.fm_r)>>16); +// if (!c) pclog("F %04X %04X %04X\n",adbuffer[c],outbuffer[c<<1],mixer.fm_l); + } + addsb(outbuffer); + for (c=0;c<(SOUNDBUFLEN);c++) + { +// if (!c) pclog("M %04X ",outbuffer[c<<1]); + outbuffer[c<<1]=(outbuffer[c<<1]*mixer.master_l)>>16; + outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]*mixer.master_r)>>16; +// if (!c) pclog("%04X %04X\n",outbuffer[c<<1],mixer.master_l); + } + if (mixer.bass_l!=8 || mixer.bass_r!=8 || mixer.treble_l!=8 || mixer.treble_r!=8) + { + for (c=0;c<(SOUNDBUFLEN);c++) + { + if (mixer.bass_l>8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)low_iir(0,(float)outbuffer[c<<1]) *(mixer.bass_l-8))>>1))*((15-mixer.bass_l)+16)>>5; + if (mixer.bass_r>8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)low_iir(1,(float)outbuffer[(c<<1)+1]) *(mixer.bass_r-8))>>1))*((15-mixer.bass_r)+16)>>5; + if (mixer.treble_l>8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)high_iir(0,(float)outbuffer[c<<1]) *(mixer.treble_l-8))>>1))*((15-mixer.treble_l)+16)>>5; + if (mixer.treble_r>8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)high_iir(1,(float)outbuffer[(c<<1)+1]) *(mixer.treble_r-8))>>1))*((15-mixer.treble_r)+16)>>5; + if (mixer.bass_l<8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)low_cut_iir(0,(float)outbuffer[c<<1]) *(8-mixer.bass_l))>>1))*(mixer.bass_l+16)>>5; + if (mixer.bass_r<8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)low_cut_iir(1,(float)outbuffer[(c<<1)+1]) *(8-mixer.bass_r))>>1))*(mixer.bass_r+16)>>5; + if (mixer.treble_l<8) outbuffer[c<<1] =(outbuffer[c<<1] +(((int16_t)high_cut_iir(0,(float)outbuffer[c<<1]) *(8-mixer.treble_l))>>1))*(mixer.treble_l+16)>>5; + if (mixer.treble_r<8) outbuffer[(c<<1)+1]=(outbuffer[(c<<1)+1]+(((int16_t)high_cut_iir(1,(float)outbuffer[(c<<1)+1])*(8-mixer.treble_r))>>1))*(mixer.treble_r+16)>>5; + } + } + for (c=0;c<(SOUNDBUFLEN);c++) + { + outbuffer[c<<1]+=(spkbuffer[c]/2); + outbuffer[(c<<1)+1]+=(spkbuffer[c]/2); + } + for (c=0;c<(SOUNDBUFLEN);c++) + { + outbuffer[c<<1]+=(psgbuffer[c]/2); + outbuffer[(c<<1)+1]+=(psgbuffer[c]/2); + } + for (c=0;c<((SOUNDBUFLEN)*2);c++) + outbuffer[c]+=(cmsbuffer[c]/2); + for (c=0;c<((SOUNDBUFLEN)*2);c++) + outbuffer[c]+=(gusbuffer[c]); + adddac(outbuffer); + ioctl_audio_callback(cd_buffer, ((SOUNDBUFLEN) * 2 * 441) / 480); + pos = 0; + for (c = 0; c < (SOUNDBUFLEN) * 2; c+=2) + { + outbuffer[c] += cd_buffer[((pos >> 16) << 1)] / 2; + outbuffer[c + 1] += cd_buffer[((pos >> 16) << 1) + 1] / 2; +// outbuffer[c] += (int16_t)((int32_t)cd_buffer[pos >> 16] * (65536 - (pos & 0xffff))) / 65536; +// outbuffer[c] += (int16_t)((int32_t)cd_buffer[(pos >> 16) + 1] * (pos & 0xffff)) / 65536; + pos += 60211; //(44100 * 65536) / 48000; + } + +// if (!soundf) soundf=fopen("sound.pcm","wb"); +// fwrite(outbuffer,(SOUNDBUFLEN)*2*2,1,soundf); + if (soundon) givealbuffer(outbuffer); +// } +// addsb(outbuffer); +// adddac(outbuffer); + adpoll=0; + psgpoll=0; + cmspoll=0; + spkpos=0; + guspoll=0; +} + +int sndcount; +void pollsound60hz() +{ +// printf("Poll sound %i\n",sndcount); +// pollad(); + pollpsg(); + pollcms(); + pollgussnd(); + sndcount++; + if (sndcount==20) + { + sndcount=0; + pollsound(); + } +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 00000000..2bdff7cb --- /dev/null +++ b/src/sound.h @@ -0,0 +1 @@ +extern int wasgated; diff --git a/src/soundopenal.c b/src/soundopenal.c new file mode 100644 index 00000000..6bd8d6d9 --- /dev/null +++ b/src/soundopenal.c @@ -0,0 +1,143 @@ +#define USE_OPENAL +#include +#include +#ifdef USE_OPENAL +#include +#include +#endif +#include "ibm.h" + +FILE *allog; +#ifdef USE_OPENAL +ALuint buffers[4]; // front and back buffers +ALuint source; // audio source +ALenum format; // internal format +#endif +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + +void closeal(); + +void initalmain(int argc, char *argv[]) +{ +#ifdef USE_OPENAL + alutInit(0,0); +// printf("AlutInit\n"); + atexit(closeal); +// printf("AlutInit\n"); +#endif +} + +void closeal() +{ +#ifdef USE_OPENAL + alutExit(); +#endif +} + +void check() +{ +#ifdef USE_OPENAL + ALenum error; + if ((error = alGetError()) != AL_NO_ERROR) + { +// printf("Error : %08X\n", error); +// exit(-1); + } +#endif +} + +void inital() +{ +#ifdef USE_OPENAL + int c; + int16_t buf[BUFLEN*2]; + format = AL_FORMAT_STEREO16; +// printf("1\n"); + check(); + +// printf("2\n"); + alGenBuffers(4, buffers); + check(); + +// printf("3\n"); + alGenSources(1, &source); + check(); + +// printf("4\n"); + alSource3f(source, AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source, AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source, AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source, AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source, AL_SOURCE_RELATIVE, AL_TRUE ); + check(); + + memset(buf,0,BUFLEN*4); + +// printf("5\n"); + for (c=0;c<4;c++) + alBufferData(buffers[c], AL_FORMAT_STEREO16, buf, BUFLEN*2*2, FREQ); + alSourceQueueBuffers(source, 4, buffers); + check(); +// printf("6 %08X\n",source); + alSourcePlay(source); + check(); +// printf("InitAL!!! %08X\n",source); +#endif +} + +void givealbuffer(int16_t *buf) +{ +#ifdef USE_OPENAL + int processed; + int state; + int c; + + //return; + +// printf("Start\n"); + check(); + +// printf("GiveALBuffer %08X\n",source); + + alGetSourcei(source, AL_SOURCE_STATE, &state); + + check(); + + if (state==0x1014) + { + alSourcePlay(source); +// printf("Resetting sound\n"); + } +// printf("State - %i %08X\n",state,state); + alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); + +// printf("P "); + check(); +// printf("Processed - %i\n",processed); + + if (processed>=1) + { + ALuint buffer; + + alSourceUnqueueBuffers(source, 1, &buffer); +// printf("U "); + check(); + +// for (c=0;c= 4) + card_16[addr] = val; +} + +uint8_t um8881f_read(int func, int addr) +{ + return card_16[addr]; +} + +void um8886f_write(int func, int addr, uint8_t val) +{ + if (addr >= 4) + card_18[addr] = val; +} + +uint8_t um8886f_read(int func, int addr) +{ + return card_18[addr]; +} + + + +void um8881f_init() +{ + pci_add_specific(16, um8881f_read, um8881f_write); + pci_add_specific(18, um8886f_read, um8886f_write); + + card_16[0] = card_18[0] = 0x60; /*UMC*/ + card_16[1] = card_18[1] = 0x10; + card_16[2] = 0x81; card_16[3] = 0x88; /*UM8881 Host - PCI bridge*/ + card_18[2] = 0x86; card_18[3] = 0x88; /*UM8886 PCI - ISA bridge*/ +} diff --git a/src/um8881f.h b/src/um8881f.h new file mode 100644 index 00000000..a21a24f3 --- /dev/null +++ b/src/um8881f.h @@ -0,0 +1 @@ +void um8881f_init(); diff --git a/src/vid_cga.c b/src/vid_cga.c new file mode 100644 index 00000000..054894f0 --- /dev/null +++ b/src/vid_cga.c @@ -0,0 +1,494 @@ +/*CGA emulation*/ +#include "ibm.h" +#include "video.h" + +void cga_out(uint16_t addr, uint8_t val) +{ + uint8_t old; +// pclog("CGA_OUT %04X %02X\n", addr, val); + switch (addr) + { + case 0x3D4: + crtcreg=val&31; + return; + case 0x3D5: + old=crtc[crtcreg]; + crtc[crtcreg]=val&crtcmask[crtcreg]; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + cga_recalctimings(); + } + } + return; + case 0x3D8: + cgamode=val; + return; + case 0x3D9: + cgacol=val; + return; + } +} + +uint8_t cga_in(uint16_t addr) +{ +// pclog("CGA_IN %04X\n", addr); + switch (addr) + { + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + case 0x3DA: + return cgastat; + } + return 0xFF; +} + +extern uint8_t charbuffer[256]; + +void cga_write(uint32_t addr, uint8_t val) +{ +// pclog("CGA_WRITE %04X %02X\n", addr, val); + vram[addr&0x3FFF]=val; + charbuffer[ ((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc] = val; + charbuffer[(((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + cycles -= 4; +} + +uint8_t cga_read(uint32_t addr) +{ + cycles -= 4; + charbuffer[ ((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc] = vram[addr&0x3FFF]; + charbuffer[(((int)(((dispontime - vidtime) * 2) / CGACONST)) & 0xfc) | 1] = vram[addr&0x3FFF]; +// pclog("CGA_READ %04X\n", addr); + return vram[addr&0x3FFF]; +} + +void cga_recalctimings() +{ + pclog("Recalc - %i %i %i\n", crtc[0], crtc[1], cgamode & 1); + if (cgamode&1) + { + disptime=crtc[0]+1; + dispontime=crtc[1]; + } + else + { + disptime=(crtc[0]+1)<<1; + dispontime=crtc[1]<<1; + } + dispofftime=disptime-dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + dispontime*=CGACONST; + dispofftime*=CGACONST; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); +} + +static int linepos,displine; +static int sc,vc; +static int cgadispon; +static int con,coff,cursoron,cgablink; +static int vsynctime,vadj; +static uint16_t ma,maback,ca; +static int oddeven = 0; + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +int i_filt[8],q_filt[8]; + + +void cga_poll() +{ + uint16_t ca=(crtc[15]|(crtc[14]<<8))&0x3FFF; + int drawcursor; + int x,c; + int oldvc; + uint8_t chr,attr; + uint16_t dat,dat2,dat3,dat4; + int cols[4]; + int col; + int oldsc; + int y_buf[8]={0,0,0,0,0,0,0,0},y_val,y_tot; + int i_buf[8]={0,0,0,0,0,0,0,0},i_val,i_tot; + int q_buf[8]={0,0,0,0,0,0,0,0},q_val,q_tot; + int r,g,b; + if (!linepos) + { + vidtime+=dispofftime; + cgastat|=1; + linepos=1; + oldsc=sc; + if ((crtc[8] & 3) == 3) + sc = ((sc << 1) + oddeven) & 7; + if (cgadispon) + { + if (displineline[displine][c]=0; + if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=0; + else buffer->line[displine][c+(crtc[1]<<4)+8]=0; + } + else + { + buffer->line[displine][c]=(cgacol&15)+16; + if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=(cgacol&15)+16; + else buffer->line[displine][c+(crtc[1]<<4)+8]=(cgacol&15)+16; + } + } + if (cgamode&1) + { + for (x=0;x>4)&7)+16; + if ((cgablink&8) && (attr&0x80) && !drawcursor) cols[1]=cols[0]; + } + else + { + cols[1]=(attr&15)+16; + cols[0]=(attr>>4)+16; + } + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]^15; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]; + } + ma++; + } + } + else if (!(cgamode&2)) + { + for (x=0;x>4)&7)+16; + if ((cgablink&8) && (attr&0x80)) cols[1]=cols[0]; + } + else + { + cols[1]=(attr&15)+16; + cols[0]=(attr>>4)+16; + } + ma++; + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]^15; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]; + } + } + } + else if (!(cgamode&16)) + { + cols[0]=(cgacol&15)|16; + col=(cgacol&16)?24:16; + if (cgamode&4) + { + cols[1]=col|3; + cols[2]=col|4; + cols[3]=col|7; + } + else if (cgacol&32) + { + cols[1]=col|3; + cols[2]=col|5; + cols[3]=col|7; + } + else + { + cols[1]=col|2; + cols[2]=col|4; + cols[3]=col|6; + } + for (x=0;xline[displine][(x<<4)+(c<<1)+8]= + buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[dat>>14]; + dat<<=2; + } + } + } + else + { + cols[0]=0; cols[1]=(cgacol&15)+16; + for (x=0;xline[displine][(x<<4)+c+8]=cols[dat>>15]; + dat<<=1; + } + } + } + } + else + { + cols[0]=((cgamode&0x12)==0x12)?0:(cgacol&15)+16; + if (cgamode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,cols[0]); + else hline(buffer,0,displine,(crtc[1]<<4)+16,cols[0]); + } + + if (cgamode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + if (cga_comp) + { + for (c=0;cline[displine][c]&7][(c<<1)&6]?0x6000:0; + y_buf[(c<<1)&6]+=(buffer->line[displine][c]&8)?0x3000:0; + i_buf[(c<<1)&6]=y_buf[(c<<1)&6]*i_filt[(c<<1)&6]; + q_buf[(c<<1)&6]=y_buf[(c<<1)&6]*q_filt[(c<<1)&6]; + y_tot=y_buf[0]+y_buf[1]+y_buf[2]+y_buf[3]+y_buf[4]+y_buf[5]+y_buf[6]+y_buf[7]; + i_tot=i_buf[0]+i_buf[1]+i_buf[2]+i_buf[3]+i_buf[4]+i_buf[5]+i_buf[6]+i_buf[7]; + q_tot=q_buf[0]+q_buf[1]+q_buf[2]+q_buf[3]+q_buf[4]+q_buf[5]+q_buf[6]+q_buf[7]; + + y_val=y_tot>>10; + if (y_val>255) y_val=255; + y_val<<=16; + i_val=i_tot>>12; + if (i_val>39041) i_val=39041; + if (i_val<-39041) i_val=-39041; + q_val=q_tot>>12; + if (q_val>34249) q_val=34249; + if (q_val<-34249) q_val=-34249; + + r=(y_val+249*i_val+159*q_val)>>16; + g=(y_val-70*i_val-166*q_val)>>16; + b=(y_val-283*i_val+436*q_val)>>16; + + y_buf[((c<<1)&6)+1]=ntsc_col[buffer->line[displine][c]&7][((c<<1)&6)+1]?0x6000:0; + y_buf[((c<<1)&6)+1]+=(buffer->line[displine][c]&8)?0x3000:0; + i_buf[((c<<1)&6)+1]=y_buf[((c<<1)&6)+1]*i_filt[((c<<1)&6)+1]; + q_buf[((c<<1)&6)+1]=y_buf[((c<<1)&6)+1]*q_filt[((c<<1)&6)+1]; + y_tot=y_buf[0]+y_buf[1]+y_buf[2]+y_buf[3]+y_buf[4]+y_buf[5]+y_buf[6]+y_buf[7]; + i_tot=i_buf[0]+i_buf[1]+i_buf[2]+i_buf[3]+i_buf[4]+i_buf[5]+i_buf[6]+i_buf[7]; + q_tot=q_buf[0]+q_buf[1]+q_buf[2]+q_buf[3]+q_buf[4]+q_buf[5]+q_buf[6]+q_buf[7]; + + y_val=y_tot>>10; + if (y_val>255) y_val=255; + y_val<<=16; + i_val=i_tot>>12; + if (i_val>39041) i_val=39041; + if (i_val<-39041) i_val=-39041; + q_val=q_tot>>12; + if (q_val>34249) q_val=34249; + if (q_val<-34249) q_val=-34249; + + r+=(y_val+249*i_val+159*q_val)>>16; + g+=(y_val-70*i_val-166*q_val)>>16; + b+=(y_val-283*i_val+436*q_val)>>16; + if (r>511) r=511; + if (g>511) g=511; + if (b>511) b=511; + + ((uint32_t *)buffer32->line[displine])[c]=makecol32(r/2,g/2,b/2); + } + } + + sc=oldsc; + if (vc==crtc[7] && !sc) + cgastat|=8; + displine++; + if (displine>=360) displine=0; + } + else + { + vidtime+=dispontime; + if (cgadispon) cgastat&=~1; + linepos=0; + if (vsynctime) + { + vsynctime--; + if (!vsynctime) + cgastat&=~8; + } + if (sc==(crtc[11]&31) || ((crtc[8]&3)==3 && sc==((crtc[11]&31)>>1))) { con=0; coff=1; } + if ((crtc[8] & 3) == 3 && sc == (crtc[9] >> 1)) + maback = ma; + if (vadj) + { + sc++; + sc&=31; + ma=maback; + vadj--; + if (!vadj) + { + cgadispon=1; + ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + sc=0; + } + } + else if (sc==crtc[9]) + { + maback=ma; + sc=0; + oldvc=vc; + vc++; + vc&=127; + + if (vc==crtc[6]) cgadispon=0; + + if (oldvc==crtc[4]) + { + vc=0; + vadj=crtc[5]; + if (!vadj) cgadispon=1; + if (!vadj) ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + if ((crtc[10]&0x60)==0x20) cursoron=0; + else cursoron=cgablink&8; + } + + if (vc==crtc[7]) + { + cgadispon=0; + displine=0; + vsynctime=(crtc[3]>>4)+1; + if (crtc[7]) + { + if (cgamode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + lastline++; + if (x!=xsize || (lastline-firstline)!=ysize) + { + xsize=x; + ysize=lastline-firstline; + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + updatewindowsize(xsize,(ysize<<1)+16); + } + +startblit(); + if (cga_comp) + video_blit_memtoscreen(0, firstline-4, 0, (lastline-firstline)+8, xsize, (lastline-firstline)+8); + else + video_blit_memtoscreen_8(0, firstline-4, xsize, (lastline-firstline)+8); + if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); + readflash=0; + frames++; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (cgamode & 1) + { + video_res_x /= 8; + video_res_y /= crtc[9] + 1; + video_bpp = 0; + } + else if (!(cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= crtc[9] + 1; + video_bpp = 0; + } + else if (!(cgamode&16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + firstline=1000; + lastline=0; + cgablink++; + oddeven ^= 1; + } + } + else + { + sc++; + sc&=31; + ma=maback; + } + if ((sc==(crtc[10]&31) || ((crtc[8]&3)==3 && sc==((crtc[10]&31)>>1)))) con=1; + if (cgadispon && (cgamode&1)) + { + for (x=0;x<(crtc[1]<<1);x++) + charbuffer[x]=vram[(((ma<<1)+x)&0x3FFF)]; + } + } +} + + +int cga_init() +{ + int c; + int cga_tint = -2; + for (c=0;c<8;c++) + { + i_filt[c]=512.0*cos((3.14*(cga_tint+c*4)/16.0) - 33.0/180.0); + q_filt[c]=512.0*sin((3.14*(cga_tint+c*4)/16.0) - 33.0/180.0); + } + mem_sethandler(0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL); + return 0; +} + +GFXCARD vid_cga = +{ + cga_init, + /*IO at 3Cx/3Dx*/ + cga_out, + cga_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + cga_poll, + cga_recalctimings, + + video_write_null, + video_write_null, + cga_write, + + video_read_null, + video_read_null, + cga_read +}; diff --git a/src/vid_cga.h b/src/vid_cga.h new file mode 100644 index 00000000..f8474003 --- /dev/null +++ b/src/vid_cga.h @@ -0,0 +1,7 @@ +int cga_init(); +void cga_out(uint16_t addr, uint8_t val); +uint8_t cga_in(uint16_t addr); +void cga_poll(); +void cga_write(uint32_t addr, uint8_t val); +uint8_t cga_read(uint32_t addr); +void cga_recalctimings(); diff --git a/src/vid_ega.c b/src/vid_ega.c new file mode 100644 index 00000000..2afe346f --- /dev/null +++ b/src/vid_ega.c @@ -0,0 +1,720 @@ +/*EGA emulation*/ +#include "ibm.h" +#include "video.h" + +void ega_recalctimings(); +void ega_write(uint32_t addr, uint8_t val); +uint8_t ega_read(uint32_t addr); + +extern uint8_t edatlookup[4][4]; + +uint8_t ega_3c2; + +static uint8_t la, lb, lc, ld; +static uint8_t ega_rotate[8][256]; + +/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ +int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ + +void ega_out(uint16_t addr, uint8_t val) +{ + int c; + uint8_t o,old; + if ((addr&0xFFF0) == 0x3B0) addr |= 0x20; + switch (addr) + { + case 0x3C0: + if (!attrff) + attraddr=val&31; + else + { + attrregs[attraddr&31]=val; + if (attraddr<16) fullchange=changeframecount; + if (attraddr==0x10 || attraddr==0x14 || attraddr<0x10) + { + for (c=0;c<16;c++) + { + if (attrregs[0x10]&0x80) egapal[c]=(attrregs[c]&0xF)|((attrregs[0x14]&0xF)<<4); + else egapal[c]=(attrregs[c]&0x3F)|((attrregs[0x14]&0xC)<<4); + } + } + } + attrff^=1; + break; + case 0x3C2: + egaswitchread=val&0xC; + vres=!(val&0x80); + pallook=(vres)?pallook16:pallook64; + vidclock=val&4; /*printf("3C2 write %02X\n",val);*/ + ega_3c2=val; + break; + case 0x3C4: seqaddr=val; break; + case 0x3C5: + o=seqregs[seqaddr&0xF]; + seqregs[seqaddr&0xF]=val; + if (o!=val && (seqaddr&0xF)==1) ega_recalctimings(); + switch (seqaddr&0xF) + { + case 1: if (scrblank && !(val&0x20)) fullchange=3; scrblank=(scrblank&~0x20)|(val&0x20); break; + case 2: writemask=val&0xF; break; + case 3: + charset=val&0xF; + charseta=((charset>>2)*0x10000)+2; + charsetb=((charset&3) *0x10000)+2; + break; + } + break; + case 0x3CE: gdcaddr=val; break; + case 0x3CF: + gdcreg[gdcaddr&15]=val; + switch (gdcaddr&15) + { + case 2: colourcompare=val; break; + case 4: readplane=val&3; break; + case 5: writemode=val&3; readmode=val&8; break; + case 6: + mem_removehandler(0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL); +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + } + + break; + case 7: colournocare=val; break; + } + break; + case 0x3D4: + crtcreg=val; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + ega_recalctimings(); + } + } + break; + } +} + +uint8_t ega_in(uint16_t addr) +{ + uint8_t temp; + if ((addr&0xFFF0) == 0x3B0) addr |= 0x20; + switch (addr) + { + case 0x3C0: return attraddr; + case 0x3C1: return attrregs[attraddr]; + case 0x3C2: +// printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA); + switch (egaswitchread) + { + case 0xC: return (egaswitches&1)?0x10:0; + case 0x8: return (egaswitches&2)?0x10:0; + case 0x4: return (egaswitches&4)?0x10:0; + case 0x0: return (egaswitches&8)?0x10:0; + } + break; + case 0x3C4: return seqaddr; + case 0x3C5: + return seqregs[seqaddr&0xF]; + case 0x3CE: return gdcaddr; + case 0x3CF: + return gdcreg[gdcaddr&0xF]; + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + case 0x3DA: + attrff=0; + cgastat^=0x30; /*Fools IBM EGA video BIOS self-test*/ + return cgastat; + } +// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc); + return 0xFF; +} + +static int linepos,displine,vslines; +static int egadispon; +static uint32_t ma,ca,maback; +static int vc,sc; +static int con,cursoron,cgablink; +static int scrollcache; +#define vrammask 0x3FFFF + +void ega_recalctimings() +{ + float crtcconst; + int temp; + ega_vtotal=crtc[6]; + ega_dispend=crtc[0x12]; + ega_vsyncstart=crtc[0x10]; + ega_split=crtc[0x18]; + + if (crtc[7]&1) ega_vtotal|=0x100; + if (crtc[7]&32) ega_vtotal|=0x200; + ega_vtotal++; + + if (crtc[7]&2) ega_dispend|=0x100; + if (crtc[7]&64) ega_dispend|=0x200; + ega_dispend++; + + if (crtc[7]&4) ega_vsyncstart|=0x100; + if (crtc[7]&128) ega_vsyncstart|=0x200; + ega_vsyncstart++; + + if (crtc[7]&0x10) ega_split|=0x100; + if (crtc[9]&0x40) ega_split|=0x200; + ega_split+=2; + + ega_hdisp=crtc[1]; + ega_hdisp++; + + ega_rowoffset=crtc[0x13]; + + printf("Recalc! %i %i %i %i %i %02X\n",ega_vtotal,ega_dispend,ega_vsyncstart,ega_split,ega_hdisp,attrregs[0x16]); + + if (vidclock) crtcconst=(seqregs[1]&1)?(MDACONST*(8.0/9.0)):MDACONST; + else crtcconst=(seqregs[1]&1)?(CGACONST*(8.0/9.0)):CGACONST; + + disptime=crtc[0]+2; + dispontime=crtc[1]+1; + + printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); + if (seqregs[1]&8) { disptime*=2; dispontime*=2; } + dispofftime=disptime-dispontime; + dispontime*=crtcconst; + dispofftime*=crtcconst; + + +// printf("EGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4)); +// printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart); +// printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*ega_vtotal,(dispontime+dispofftime)*ega_vtotal*70,seqregs[1]); +} + +void ega_poll() +{ + uint8_t chr,dat,attr; + uint32_t charaddr; + int x,xx; + uint32_t fg,bg; + int offset; + uint8_t edat[4]; + int drawcursor=0; + + if (!linepos) + { + vidtime+=dispofftime; + + cgastat|=1; + linepos=1; + + if (egadispon) + { + if (firstline==2000) firstline=displine; + + if (scrblank) + { + for (x=0;xline[displine])[(x*9)+xx+32]=0; + break; + case 1: + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[(x*8)+xx+32]=0; + break; + case 8: + for (xx=0;xx<18;xx++) ((uint32_t *)buffer32->line[displine])[(x*18)+xx+32]=0; + break; + case 9: + for (xx=0;xx<16;xx++) ((uint32_t *)buffer32->line[displine])[(x*16)+xx+32]=0; + break; + } + } + } + else if (!(gdcreg[6]&1)) + { + if (fullchange) + { + for (x=0;x>4]]; } + else + { + fg=pallook[egapal[attr&15]]; + bg=pallook[egapal[attr>>4]]; + if (attr&0x80 && attrregs[0x10]&8) + { + bg=pallook[egapal[(attr>>4)&7]]; + if (cgablink&16) fg=bg; + } + } + + dat=vram[charaddr+(sc<<2)]; + if (seqregs[1]&8) + { + if (seqregs[1]&1) { for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x<<4)+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[((x<<4)+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; } + else + { + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x*18)+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; + if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) ((uint32_t *)buffer32->line[displine])[((x*18)+32+16)&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+32+17)&2047]=bg; + else ((uint32_t *)buffer32->line[displine])[((x*18)+32+16)&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+32+17)&2047]=(dat&1)?fg:bg; + } + } + else + { + if (seqregs[1]&1) { for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x<<3)+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; } + else + { + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x*9)+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; + if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) ((uint32_t *)buffer32->line[displine])[((x*9)+32+8)&2047]=bg; + else ((uint32_t *)buffer32->line[displine])[((x*9)+32+8)&2047]=(dat&1)?fg:bg; + } + } + ma+=4; ma&=vrammask; + } + } + } + else + { + switch (gdcreg[5]&0x20) + { + case 0x00: + if (seqregs[1]&8) + { + offset=((8-scrollcache)<<1)+16; + for (x=0;x<=ega_hdisp;x++) + { + if (sc&1 && !(crtc[0x17]&1)) + { + edat[0] = vram[ma | 0x8000]; + edat[1] = vram[ma | 0x8001]; + edat[2] = vram[ma | 0x8002]; + edat[3] = vram[ma | 0x8003]; + } + else + { + edat[0] = vram[ma]; + edat[1] = vram[ma | 0x1]; + edat[2] = vram[ma | 0x2]; + edat[3] = vram[ma | 0x3]; + } + ma+=4; ma&=vrammask; + + dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+14+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+15+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+12+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+13+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+10+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+11+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+8+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+9+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+7+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+5+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+3+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+1+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + } + } + else + { + offset=(8-scrollcache)+24; + for (x=0;x<=ega_hdisp;x++) + { + if (sc&1 && !(crtc[0x17]&1)) + { + edat[0] = vram[ma | 0x8000]; + edat[1] = vram[ma | 0x8001]; + edat[2] = vram[ma | 0x8002]; + edat[3] = vram[ma | 0x8003]; + } + else + { + edat[0] = vram[ma]; + edat[1] = vram[ma | 0x1]; + edat[2] = vram[ma | 0x2]; + edat[3] = vram[ma | 0x3]; + } + ma+=4; ma&=vrammask; + + dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+7+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+6+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+5+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+4+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+3+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+2+offset]=pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+1+offset]=pallook[egapal[(dat & 0xF) & attrregs[0x12]]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+offset]= pallook[egapal[(dat >> 4) & attrregs[0x12]]]; + } + } + break; + case 0x20: + offset=((8-scrollcache)<<1)+16; + for (x=0;x<=ega_hdisp;x++) + { + if (sc&1 && !(crtc[0x17]&1)) + { + edat[0]=vram[(ma<<1)+0x8000]; + edat[1]=vram[(ma<<1)+0x8004]; + } + else + { + edat[0]=vram[(ma<<1)]; + edat[1]=vram[(ma<<1)+4]; + } + ma+=4; ma&=vrammask; + + ((uint32_t *)buffer32->line[displine])[(x<<4)+14+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+15+offset]=pallook[egapal[edat[1]&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+12+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+13+offset]=pallook[egapal[(edat[1]>>2)&3]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+10+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+11+offset]=pallook[egapal[(edat[1]>>4)&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+8+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+9+offset]=pallook[egapal[(edat[1]>>6)&3]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+7+offset]=pallook[egapal[(edat[0]>>0)&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+5+offset]=pallook[egapal[(edat[0]>>2)&3]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+3+offset]=pallook[egapal[(edat[0]>>4)&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+1+offset]=pallook[egapal[(edat[0]>>6)&3]]; + } + break; + } + } + if (lastline500) displine=0; + } + else + { + vidtime+=dispontime; +// if (output) printf("Display on %f\n",vidtime); + if (egadispon) cgastat&=~1; + linepos=0; + if (sc==(crtc[11]&31)) + con=0; + if (egadispon) + { + if (sc==(crtc[9]&31)) + { + sc=0; + + maback+=(ega_rowoffset<<3); + maback&=vrammask; + ma=maback; + } + else + { + sc++; + sc&=31; + ma=maback; + } + } + vc++; + vc&=1023; +// printf("Line now %i %i ma %05X\n",vc,displine,ma); + if (vc==ega_split) + { +// printf("Split at line %i %i\n",displine,vc); + ma=maback=0; + if (attrregs[0x10]&0x20) scrollcache=0; + } + if (vc==ega_dispend) + { +// printf("Display over at line %i %i\n",displine,vc); + egadispon=0; + if (crtc[10] & 0x20) cursoron=0; + else cursoron=cgablink&16; + if (!(gdcreg[6]&1) && !(cgablink&15)) fullchange=2; + cgablink++; + + for (x=0;x<2048;x++) if (changedvram[x]) changedvram[x]--; +// memset(changedvram,0,2048); + if (fullchange) fullchange--; + } + if (vc==ega_vsyncstart) + { + egadispon=0; +// printf("Vsync on at line %i %i\n",displine,vc); + cgastat|=8; + if (seqregs[1]&8) x=ega_hdisp*((seqregs[1]&1)?8:9)*2; + else x=ega_hdisp*((seqregs[1]&1)?8:9); + wx=x; + wy=lastline-firstline; +// pclog("Cursor %02X %02X\n",crtc[10],crtc[11]); +// pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven); +// doblit(); + svga_doblit(firstline, lastline + 1); + + video_res_x = wx; + video_res_y = wy + 1; + if (!(gdcreg[6]&1)) /*Text mode*/ + { + video_res_x /= (seqregs[1] & 1) ? 8 : 9; + video_res_y /= (crtc[9] & 31) + 1; + video_bpp = 0; + } + else + { + if (crtc[9] & 0x80) + video_res_y /= 2; + if (!(crtc[0x17] & 1)) + video_res_y *= 2; + video_res_y /= (crtc[9] & 31) + 1; + if (seqregs[1] & 8) + video_res_x /= 2; + video_bpp = (gdcreg[5] & 0x20) ? 2 : 4; + } + +// wakeupblit(); + readflash=0; + //framecount++; + firstline=2000; + lastline=0; + + maback=ma=(crtc[0xC]<<8)|crtc[0xD]; + ca=(crtc[0xE]<<8)|crtc[0xF]; + ma<<=2; + maback<<=2; + ca<<=2; + changeframecount=2; + vslines=0; + } + if (vc==ega_vtotal) + { + vc=0; + sc=0; + egadispon=1; + displine=0; + scrollcache=attrregs[0x13]&7; + } + if (sc == (crtc[10] & 31)) con=1; + } +} + + +void ega_write(uint32_t addr, uint8_t val) +{ + int x,y; + char s[2]={0,0}; + uint8_t vala,valb,valc,vald,wm=writemask; + + egawrites++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + if (addr>=0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (!(gdcreg[6]&1)) fullchange=2; + addr <<= 2; + +// pclog("%i %08X %i %i %02X %02X %02X %02X %02X\n",chain4,addr,writemode,writemask,gdcreg[8],vram[0],vram[1],vram[2],vram[3]); + switch (writemode) + { + case 1: + if (writemask&1) vram[addr]=la; + if (writemask&2) vram[addr|0x1]=lb; + if (writemask&4) vram[addr|0x2]=lc; + if (writemask&8) vram[addr|0x3]=ld; + break; + case 0: + if (gdcreg[3]&7) val=ega_rotate[gdcreg[3]&7][val]; + if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1]) + { +// pclog("Easy write %05X %02X\n",addr,val); + if (writemask&1) vram[addr]=val; + if (writemask&2) vram[addr|0x1]=val; + if (writemask&4) vram[addr|0x2]=val; + if (writemask&8) vram[addr|0x3]=val; + } + else + { + if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0; + else vala=val; + if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0; + else valb=val; + if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0; + else valc=val; + if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0; + else vald=val; +// pclog("Write %02X %01X %02X %02X %02X %02X %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]); + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]); + if (writemask&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]); + } + else + { + vala=((val&1)?0xFF:0); + valb=((val&2)?0xFF:0); + valc=((val&4)?0xFF:0); + vald=((val&8)?0xFF:0); + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + } + break; + } +} + +uint8_t ega_read(uint32_t addr) +{ + uint8_t temp,temp2,temp3,temp4; + uint32_t addr2; + egareads++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; +// pclog("Readega %06X ",addr); + if (addr>=0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + addr<<=2; + la=vram[addr]; + lb=vram[addr|0x1]; + lc=vram[addr|0x2]; + ld=vram[addr|0x3]; + if (readmode) + { + temp= (colournocare&1) ?0xFF:0; + temp&=la; + temp^=(colourcompare&1)?0xFF:0; + temp2= (colournocare&2) ?0xFF:0; + temp2&=lb; + temp2^=(colourcompare&2)?0xFF:0; + temp3= (colournocare&4) ?0xFF:0; + temp3&=lc; + temp3^=(colourcompare&4)?0xFF:0; + temp4= (colournocare&8) ?0xFF:0; + temp4&=ld; + temp4^=(colourcompare&8)?0xFF:0; + return ~(temp|temp2|temp3|temp4); + } + return vram[addr|readplane]; +} + +int ega_init() +{ + int c, d, e; + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + return 0; +} + +GFXCARD vid_ega = +{ + ega_init, + /*IO at 3Cx/3Dx*/ + ega_out, + ega_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + ega_poll, + ega_recalctimings, + + ega_write, + video_write_null, + video_write_null, + + ega_read, + video_read_null, + video_read_null +}; + diff --git a/src/vid_ega.h b/src/vid_ega.h new file mode 100644 index 00000000..6258e7c6 --- /dev/null +++ b/src/vid_ega.h @@ -0,0 +1,7 @@ +int ega_init(); +void ega_out(uint16_t addr, uint8_t val); +uint8_t ega_in(uint16_t addr); +void ega_poll(); +void ega_recalctimings(); +void ega_write(uint32_t addr, uint8_t val); +uint8_t ega_read(uint32_t addr); diff --git a/src/vid_et4000.c b/src/vid_et4000.c new file mode 100644 index 00000000..e4259a6b --- /dev/null +++ b/src/vid_et4000.c @@ -0,0 +1,141 @@ +/*ET4000 emulation*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +int et4k_b8000; + + +void et4000_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + pclog("ET4000 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + unk_ramdac_out(addr,val); + return; + + case 0x3CD: /*Banking*/ + svgawbank=(val&0xF)*65536; + svgarbank=((val>>4)&0xF)*65536; + svgaseg=val; + pclog("Banking write %08X %08X %02X\n", svgawbank, svgarbank, val); + return; + case 0x3CF: + switch (gdcaddr&15) + { + case 6: + et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); + break; + } + break; + case 0x3D4: + crtcreg = val & 0x3f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + case 0x3D8: + if (val==0xA0) svgaon=1; + if (val==0x29) svgaon=0; + break; + } + svga_out(addr,val); +} + +uint8_t et4000_in(uint16_t addr) +{ + uint8_t temp; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); + + switch (addr) + { + case 0x3C5: + if ((seqaddr&0xF)==7) return seqregs[seqaddr&0xF]|4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return unk_ramdac_in(addr); + + case 0x3CD: /*Banking*/ + return svgaseg; + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + } + return svga_in(addr); +} + +void et4000_recalctimings() +{ + svga_ma|=(crtc[0x33]&3)<<16; + if (crtc[0x35]&2) svga_vtotal+=0x400; + if (crtc[0x35]&4) svga_dispend+=0x400; + if (crtc[0x35]&8) svga_vsyncstart+=0x400; + if (crtc[0x35]&0x10) svga_split+=0x400; + if (!svga_rowoffset) svga_rowoffset=0x100; +// if (crtc[0x3F]&0x80) svga_rowoffset+=0x100; + if (crtc[0x3F]&1) svga_htotal+=256; + if (attrregs[0x16]&0x20) svga_hdisp<<=1; +// pclog("Rowoffset %i\n",svga_rowoffset); + + switch (((svga_miscout >> 2) & 3) | ((crtc[0x34] << 1) & 4)) + { + case 0: case 1: break; + case 3: svga_clock = cpuclock/40000000.0; break; + case 5: svga_clock = cpuclock/65000000.0; break; + default: svga_clock = cpuclock/36000000.0; break; + } + +} + +int et4000_init() +{ + svga_recalctimings_ex = et4000_recalctimings; + svga_vram_limit = 1 << 20; /*1mb*/ + vrammask = 0xfffff; + return svga_init(); +} + +GFXCARD vid_et4000 = +{ + et4000_init, + /*IO at 3Cx/3Dx*/ + et4000_out, + et4000_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_et4000w32.c b/src/vid_et4000w32.c new file mode 100644 index 00000000..7e40ebd7 --- /dev/null +++ b/src/vid_et4000w32.c @@ -0,0 +1,936 @@ +/*ET4000/W32p emulation (Diamond Stealth 32)*/ +/*Known bugs : + + - Accelerator doesn't work in planar modes +*/ + +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_icd2061.h" +#include "vid_stg_ramdac.h" +#include "mem.h" + +int et4k_b8000; + +void et4000w32p_recalcmapping(); + +uint8_t et4000w32p_mmu_read(uint32_t addr); +void et4000w32p_mmu_write(uint32_t addr, uint8_t val); + +static int et4000w32p_index; +static uint8_t et4000w32p_regs[256]; +static uint32_t et4000w32p_linearbase, et4000w32p_linearbase_old; + +void et4000w32p_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + +// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("ET4000W32p out %04X %02X %04X:%04X ",addr,val,CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("%04X\n",addr); + + switch (addr) + { + case 0x3c2: + icd2061_write((val >> 2) & 3); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + stg_ramdac_out(addr,val); + return; + + case 0x3CB: /*Banking extension*/ + svgawbank=(svgawbank&0xFFFFF)|((val&1)<<20); + svgarbank=(svgarbank&0xFFFFF)|((val&0x10)<<16); + svgaseg2=val; + return; + case 0x3CD: /*Banking*/ + svgawbank=(svgawbank&0x100000)|((val&0xF)*65536); + svgarbank=(svgarbank&0x100000)|(((val>>4)&0xF)*65536); + svgaseg=val; + return; + case 0x3CF: + switch (gdcaddr&15) + { + case 6: + gdcreg[gdcaddr&15]=val; + //et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); + et4000w32p_recalcmapping(); + return; + } + break; + case 0x3D4: + crtcreg=val&63; + return; + case 0x3D5: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); +// if (crtcreg!=0xE && crtcreg!=0xF) pclog("CRTC R%02X = %02X\n",crtcreg,val); + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + if (crtcreg == 0x30) + { + et4000w32p_linearbase = val * 0x400000; +// pclog("Linear base now at %08X %02X\n", et4000w32p_linearbase, val); + et4000w32p_recalcmapping(); + } + if (crtcreg == 0x36) et4000w32p_recalcmapping(); + break; + case 0x3D8: + if (val==0xA0) svgaon=1; + if (val==0x29) svgaon=0; + break; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + et4000w32p_index=val; + return; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + et4000w32p_regs[et4000w32p_index] = val; + svga_hwcursor.x = et4000w32p_regs[0xE0] | ((et4000w32p_regs[0xE1] & 7) << 8); + svga_hwcursor.y = et4000w32p_regs[0xE4] | ((et4000w32p_regs[0xE5] & 7) << 8); + svga_hwcursor.addr = (et4000w32p_regs[0xE8] | (et4000w32p_regs[0xE9] << 8) | ((et4000w32p_regs[0xEA] & 7) << 16)) << 2; + svga_hwcursor.addr += (et4000w32p_regs[0xE6] & 63) * 16; + svga_hwcursor.ena = et4000w32p_regs[0xF7] & 0x80; + svga_hwcursor.xoff = et4000w32p_regs[0xE2] & 63; + svga_hwcursor.yoff = et4000w32p_regs[0xE6] & 63; +// pclog("HWCURSOR X %i Y %i\n",svga_hwcursor_x,svga_hwcursor_y); + return; + + } + svga_out(addr,val); +} + +uint8_t et4000w32p_in(uint16_t addr) +{ + uint8_t temp; +// if (addr==0x3DA) pclog("In 3DA %04X(%06X):%04X\n",CS,cs,pc); + +// pclog("ET4000W32p in %04X %04X:%04X ",addr,CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// pclog("%04X\n",addr); + + switch (addr) + { + case 0x3C5: + if ((seqaddr&0xF)==7) return seqregs[seqaddr&0xF]|4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return stg_ramdac_in(addr); + + case 0x3CB: + return svgaseg2; + case 0x3CD: + return svgaseg; + case 0x3D4: + return crtcreg; + case 0x3D5: +// pclog("Read CRTC R%02X %02X\n", crtcreg, crtc[crtcreg]); + return crtc[crtcreg]; + + case 0x3DA: + attrff=0; + cgastat^=0x30; + temp = cgastat & 0x39; + if (svga_hdisp_on) temp |= 2; + if (!(cgastat & 8)) temp |= 0x80; +// pclog("3DA in %02X\n",temp); + return temp; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + return et4000w32p_index; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000w32p_index==0xEC) return (et4000w32p_regs[0xEC]&0xF)|0x60; /*ET4000/W32p rev D*/ + if (et4000w32p_index == 0xEF) + { + if (PCI) return et4000w32p_regs[0xEF] | 0xe0; /*PCI*/ + else return et4000w32p_regs[0xEF] | 0x60; /*VESA local bus*/ + } + return et4000w32p_regs[et4000w32p_index]; + } + return svga_in(addr); +} + +void et4000w32p_recalctimings() +{ + double clk; +// pclog("Recalc %08X ",svga_ma); + svga_ma|=(crtc[0x33]&0x7)<<16; + pclog("SVGA_MA %08X %i\n", svga_ma, (svga_miscout >> 2) & 3); + if (crtc[0x35]&2) svga_vtotal+=0x400; + if (crtc[0x35]&4) svga_dispend+=0x400; + if (crtc[0x35]&8) svga_vsyncstart+=0x400; + if (crtc[0x35]&0x10) svga_split+=0x400; + if (crtc[0x3F]&0x80) svga_rowoffset+=0x100; + if (crtc[0x3F]&1) svga_htotal+=256; + if (attrregs[0x16]&0x20) svga_hdisp<<=1; + + switch ((svga_miscout >> 2) & 3) + { + case 0: case 1: break; + case 2: case 3: svga_clock = cpuclock/icd2061_getfreq(2); break; +/* default: + pclog("Unknown clock %i\n", ((svga_miscout >> 2) & 3) | ((crtc[0x34] << 1) & 4) | ((crtc[0x31] & 0xc0) >> 3)); + svga_clock = cpuclock/36000000.0; break;*/ + } + +// pclog("Recalctimings - %02X %02X %02X\n", crtc[6], crtc[7], crtc[0x35]); +} + +int et4000w32p_getclock() +{ + return ((svga_miscout >> 2) & 3) | ((crtc[0x34] << 1) & 4) | ((crtc[0x31] & 0xc0) >> 3); +} + + +void et4000w32p_recalcmapping() +{ + int map; + + mem_removehandler(et4000w32p_linearbase_old, 0x200000, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_removehandler(0xb0000, 0x10000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL); + if (crtc[0x36] & 0x10) /*Linear frame buffer*/ + { + mem_sethandler(et4000w32p_linearbase, 0x200000, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + } + else + { + map = (gdcreg[6] & 0xC) >> 2; + if (crtc[0x36] & 0x20) map |= 4; + if (crtc[0x36] & 0x08) map |= 8; + switch (map) + { + case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x1: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x2: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x3: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/ + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_sethandler(0xb8000, 0x08000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL); + break; + case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/ + mem_sethandler(0xa8000, 0x08000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL); + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/ + mem_sethandler(0xa8000, 0x08000, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL); + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + } +// pclog("ET4K map %02X\n", map); + } + et4000w32p_linearbase_old = et4000w32p_linearbase; +} + +/*Accelerator*/ +struct +{ + struct + { + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint16_t pattern_off,source_off,dest_off,mix_off; + uint8_t pixel_depth,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + uint16_t error; + uint16_t dmin,dmaj; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint32_t pattern_back,source_back,dest_back,mix_back; + int pattern_x,source_x; + int pattern_x_back,source_x_back; + int pattern_y,source_y; + uint8_t status; + uint64_t cpu_dat; + int cpu_dat_pos; + int pix_pos; +} acl; + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +struct +{ + uint32_t base[3]; + uint8_t ctrl; +} mmu; + +void et4000w32_reset() +{ + acl.status=0; +} + +void et4000w32_blit_start(); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); + +void et4000w32p_mmu_write(uint32_t addr, uint8_t val) +{ + int bank; +// pclog("ET4K write %08X %02X %02X %04X(%08X):%08X\n",addr,val,acl.status,acl.internal.ctrl_routing,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>(acl.mix_addr&7), 0, 1); + else + et4000w32_blit(8, val, 0, 1); + } + else if ((acl.internal.ctrl_routing&3)==1) + et4000w32_blit(1, ~0, val, 2); +// else +// pclog("Bad ET4K routing %i\n",acl.internal.ctrl_routing&7); + } + } + else + { + vram[(addr&0x1FFF)+mmu.base[bank]]=val; + changedvram[((addr&0x1FFF)+mmu.base[bank])>>10]=changeframecount; + } + break; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; + case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; + case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; + case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; + case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; + case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; + case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; + case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; + case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; + case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; + case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; + case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; + case 0x7F13: mmu.ctrl=val; break; + + case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; + case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; + case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; + case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; + case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; + case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; + case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; + case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; + case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; + case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; + case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; + case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; + case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; + case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; + case 0x7F8E: acl.queued.pixel_depth=val; break; + case 0x7F8F: acl.queued.xy_dir=val; break; + case 0x7F90: acl.queued.pattern_wrap=val; break; + case 0x7F92: acl.queued.source_wrap=val; break; + case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; + case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; + case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; + case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; + case 0x7F9C: acl.queued.ctrl_routing=val; break; + case 0x7F9D: acl.queued.ctrl_reload =val; break; + case 0x7F9E: acl.queued.rop_bg =val; break; + case 0x7F9F: acl.queued.rop_fg =val; break; + case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; + case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; + case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; + case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); + acl.internal=acl.queued; + et4000w32_blit_start(); + if (!(acl.queued.ctrl_routing&0x43)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0); + } + if ((acl.queued.ctrl_routing&0x40) && !(acl.internal.ctrl_routing&3)) + et4000w32_blit(4, ~0, 0, 0); + break; + case 0x7FA4: acl.queued.mix_addr=(acl.queued.mix_addr&0xFFFFFF00)|val; break; + case 0x7FA5: acl.queued.mix_addr=(acl.queued.mix_addr&0xFFFF00FF)|(val<<8); break; + case 0x7FA6: acl.queued.mix_addr=(acl.queued.mix_addr&0xFF00FFFF)|(val<<16); break; + case 0x7FA7: acl.queued.mix_addr=(acl.queued.mix_addr&0x00FFFFFF)|(val<<24); break; + case 0x7FA8: acl.queued.mix_off =(acl.queued.mix_off &0xFF00)|val; break; + case 0x7FA9: acl.queued.mix_off =(acl.queued.mix_off &0x00FF)|(val<<8); break; + case 0x7FAA: acl.queued.error =(acl.queued.error &0xFF00)|val; break; + case 0x7FAB: acl.queued.error =(acl.queued.error &0x00FF)|(val<<8); break; + case 0x7FAC: acl.queued.dmin =(acl.queued.dmin &0xFF00)|val; break; + case 0x7FAD: acl.queued.dmin =(acl.queued.dmin &0x00FF)|(val<<8); break; + case 0x7FAE: acl.queued.dmaj =(acl.queued.dmaj &0xFF00)|val; break; + case 0x7FAF: acl.queued.dmaj =(acl.queued.dmaj &0x00FF)|(val<<8); break; + } + break; + } +} + +uint8_t et4000w32p_mmu_read(uint32_t addr) +{ + int bank; + uint8_t temp; +// pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>=8; + } + if ((acl.queued.ctrl_routing&0x40) && !acl.cpu_dat_pos && !(acl.internal.ctrl_routing&3)) + et4000w32_blit(4, ~0, 0, 0); + /*???*/ + return temp; + } + return vram[(addr&0x1FFF)+mmu.base[bank]]; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: return mmu.base[0]; + case 0x7F01: return mmu.base[0]>>8; + case 0x7F02: return mmu.base[0]>>16; + case 0x7F03: return mmu.base[0]>>24; + case 0x7F04: return mmu.base[1]; + case 0x7F05: return mmu.base[1]>>8; + case 0x7F06: return mmu.base[1]>>16; + case 0x7F07: return mmu.base[1]>>24; + case 0x7F08: return mmu.base[2]; + case 0x7F09: return mmu.base[2]>>8; + case 0x7F0A: return mmu.base[2]>>16; + case 0x7F0B: return mmu.base[2]>>24; + case 0x7F13: return mmu.ctrl; + + case 0x7F36: +// pclog("Read ACL status %02X\n",acl.status); +// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; + return acl.status; + case 0x7F80: return acl.internal.pattern_addr; + case 0x7F81: return acl.internal.pattern_addr>>8; + case 0x7F82: return acl.internal.pattern_addr>>16; + case 0x7F83: return acl.internal.pattern_addr>>24; + case 0x7F84: return acl.internal.source_addr; + case 0x7F85: return acl.internal.source_addr>>8; + case 0x7F86: return acl.internal.source_addr>>16; + case 0x7F87: return acl.internal.source_addr>>24; + case 0x7F88: return acl.internal.pattern_off; + case 0x7F89: return acl.internal.pattern_off>>8; + case 0x7F8A: return acl.internal.source_off; + case 0x7F8B: return acl.internal.source_off>>8; + case 0x7F8C: return acl.internal.dest_off; + case 0x7F8D: return acl.internal.dest_off>>8; + case 0x7F8E: return acl.internal.pixel_depth; + case 0x7F8F: return acl.internal.xy_dir; + case 0x7F90: return acl.internal.pattern_wrap; + case 0x7F92: return acl.internal.source_wrap; + case 0x7F98: return acl.internal.count_x; + case 0x7F99: return acl.internal.count_x>>8; + case 0x7F9A: return acl.internal.count_y; + case 0x7F9B: return acl.internal.count_y>>8; + case 0x7F9C: return acl.internal.ctrl_routing; + case 0x7F9D: return acl.internal.ctrl_reload; + case 0x7F9E: return acl.internal.rop_bg; + case 0x7F9F: return acl.internal.rop_fg; + case 0x7FA0: return acl.internal.dest_addr; + case 0x7FA1: return acl.internal.dest_addr>>8; + case 0x7FA2: return acl.internal.dest_addr>>16; + case 0x7FA3: return acl.internal.dest_addr>>24; + } + return 0xFF; + } +} + +int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000}; +int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +int bltout=0; +void et4000w32_blit_start() +{ +// if (acl.queued.xy_dir&0x80) +// pclog("Blit - %02X %08X (%i,%i) %08X (%i,%i) %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.queued.xy_dir,acl.internal.pattern_addr,(acl.internal.pattern_addr/3)%640,(acl.internal.pattern_addr/3)/640,acl.internal.source_addr,(acl.internal.source_addr/3)%640,(acl.internal.source_addr/3)/640,acl.internal.dest_addr,(acl.internal.dest_addr/3)%640,(acl.internal.dest_addr/3)/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); +// bltout=1; +// bltout=(acl.internal.count_x==1541); + if (!(acl.queued.xy_dir&0x20)) + acl.internal.error = acl.internal.dmaj/2; + acl.pattern_addr=acl.internal.pattern_addr; + acl.source_addr =acl.internal.source_addr; + acl.mix_addr =acl.internal.mix_addr; + acl.mix_back =acl.mix_addr; + acl.dest_addr =acl.internal.dest_addr; + acl.dest_back =acl.dest_addr; + acl.internal.pos_x=acl.internal.pos_y=0; + acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; + acl.status = ACL_XYST; + if ((!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) && !(acl.internal.ctrl_routing&0x40)) acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) + { + acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + } + acl.pattern_back=acl.pattern_addr; + if (!(acl.internal.pattern_wrap&0x40)) + { + acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); + acl.pattern_back&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); + } + acl.pattern_x_back=acl.pattern_x; + + if (et4000w32_wrap_x[acl.internal.source_wrap&7]) + { + acl.source_x=acl.source_addr&et4000w32_wrap_x[acl.internal.source_wrap&7]; + acl.source_addr&=~et4000w32_wrap_x[acl.internal.source_wrap&7]; + } + acl.source_back=acl.source_addr; + if (!(acl.internal.source_wrap&0x40)) + { + acl.source_y=(acl.source_addr/(et4000w32_wrap_x[acl.internal.source_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.source_wrap>>4)&7]-1); + acl.source_back&=~(((et4000w32_wrap_x[acl.internal.source_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.source_wrap>>4)&7])-1); + } + acl.source_x_back=acl.source_x; + + et4000w32_max_x[2]=((acl.internal.pixel_depth&0x30)==0x20)?3:4; + + acl.internal.count_x += (acl.internal.pixel_depth>>4)&3; + acl.cpu_dat_pos=0; + acl.cpu_dat=0; + + acl.pix_pos=0; +} + +void et4000w32_incx(int c) +{ + acl.dest_addr+=c; + acl.pattern_x+=c; + acl.source_x +=c; + acl.mix_addr +=c; + if (acl.pattern_x>=et4000w32_max_x[acl.internal.pattern_wrap&7]) + acl.pattern_x -=et4000w32_max_x[acl.internal.pattern_wrap&7]; + if (acl.source_x >=et4000w32_max_x[acl.internal.source_wrap &7]) + acl.source_x -=et4000w32_max_x[acl.internal.source_wrap &7]; +} +void et4000w32_decx(int c) +{ + acl.dest_addr-=c; + acl.pattern_x-=c; + acl.source_x -=c; + acl.mix_addr -=c; + if (acl.pattern_x<0) + acl.pattern_x +=et4000w32_max_x[acl.internal.pattern_wrap&7]; + if (acl.source_x <0) + acl.source_x +=et4000w32_max_x[acl.internal.source_wrap &7]; +} +void et4000w32_incy() +{ + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off +1; + acl.mix_addr +=acl.internal.mix_off +1; + acl.dest_addr +=acl.internal.dest_off +1; + acl.pattern_y++; + if (acl.pattern_y == et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + acl.pattern_y = 0; + acl.pattern_addr = acl.pattern_back; + } + acl.source_y++; + if (acl.source_y == et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + acl.source_y = 0; + acl.source_addr = acl.source_back; + } +} +void et4000w32_decy() +{ + acl.pattern_addr-=acl.internal.pattern_off+1; + acl.source_addr -=acl.internal.source_off +1; + acl.mix_addr -=acl.internal.mix_off +1; + acl.dest_addr -=acl.internal.dest_off +1; + acl.pattern_y--; + if (acl.pattern_y<0 && !(acl.internal.pattern_wrap&0x40)) + { + acl.pattern_y=et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1; + acl.pattern_addr=acl.pattern_back+(et4000w32_wrap_x[acl.internal.pattern_wrap&7]*(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1)); + } + acl.source_y--; + if (acl.source_y<0 && !(acl.internal.source_wrap&0x40)) + { + acl.source_y =et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]-1; + acl.source_addr =acl.source_back +(et4000w32_wrap_x[acl.internal.source_wrap&7] *(et4000w32_wrap_y[(acl.internal.source_wrap>>4)&7]-1));; + } +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) +{ + int c,d; + uint8_t pattern,source,dest,out; + uint8_t rop; + int mixdat; + + if (!(acl.status & ACL_XYST)) return; +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); + //pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); + if (acl.internal.xy_dir&0x80) /*Line draw*/ + { + while (count--) + { + if (bltout) pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + if (bltout) pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + if (bltout) pclog("%06X ",acl.dest_addr); + if ((acl.internal.ctrl_routing&0xA)==8) + { + mixdat = vram[(acl.mix_addr>>3)&0x1FFFFF] & (1<<(acl.mix_addr&7)); + if (bltout) pclog("%06X %02X ",acl.mix_addr,vram[(acl.mix_addr>>3)&0x1FFFFF]); + } + else + { + mixdat = mix & 1; + mix>>=1; mix|=0x80000000; + } + acl.mix_addr++; + rop = (mixdat) ? acl.internal.rop_fg:acl.internal.rop_bg; + for (c=0;c<8;c++) + { + d=(dest & (1<>10]=changeframecount; + } + else + { + acl.cpu_dat|=((uint64_t)out<<(acl.cpu_dat_pos*8)); + acl.cpu_dat_pos++; + } + +// pclog("%i %i\n",acl.pix_pos,(acl.internal.pixel_depth>>4)&3); + acl.pix_pos++; + acl.internal.pos_x++; + if (acl.pix_pos<=((acl.internal.pixel_depth>>4)&3)) + { + if (acl.internal.xy_dir&1) et4000w32_decx(1); + else et4000w32_incx(1); + } + else + { + if (acl.internal.xy_dir&1) et4000w32_incx((acl.internal.pixel_depth>>4)&3); + else et4000w32_decx((acl.internal.pixel_depth>>4)&3); + acl.pix_pos=0; + /*Next pixel*/ + switch (acl.internal.xy_dir&7) + { + case 0: case 1: /*Y+*/ + et4000w32_incy(); + acl.internal.pos_y++; + acl.internal.pos_x-=((acl.internal.pixel_depth>>4)&3)+1; + break; + case 2: case 3: /*Y-*/ + et4000w32_decy(); + acl.internal.pos_y++; + acl.internal.pos_x-=((acl.internal.pixel_depth>>4)&3)+1; + break; + case 4: case 6: /*X+*/ + et4000w32_incx(((acl.internal.pixel_depth>>4)&3)+1); + //acl.internal.pos_x++; + break; + case 5: case 7: /*X-*/ + et4000w32_decx(((acl.internal.pixel_depth>>4)&3)+1); + //acl.internal.pos_x++; + break; + } + acl.internal.error+=acl.internal.dmin; + if (acl.internal.error > acl.internal.dmaj) + { + acl.internal.error-=acl.internal.dmaj; + switch (acl.internal.xy_dir&7) + { + case 0: case 2: /*X+*/ + et4000w32_incx(((acl.internal.pixel_depth>>4)&3)+1); + acl.internal.pos_x++; + break; + case 1: case 3: /*X-*/ + et4000w32_decx(((acl.internal.pixel_depth>>4)&3)+1); + acl.internal.pos_x++; + break; + case 4: case 5: /*Y+*/ + et4000w32_incy(); + acl.internal.pos_y++; + break; + case 6: case 7: /*Y-*/ + et4000w32_decy(); + acl.internal.pos_y++; + break; + } + } + if (acl.internal.pos_x > acl.internal.count_x || + acl.internal.pos_y > acl.internal.count_y) + { + acl.status = 0; +// pclog("Blit line over\n"); + return; + } + } + } + } + else + { + while (count--) + { + if (bltout) pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + if (bltout) pclog("%i %06X %06X %02X %02X ",acl.pattern_y,(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF,pattern,source); + + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + if (bltout) pclog("%06X %02X %i %08X %08X ",dest,acl.dest_addr,mix&1,mix,acl.mix_addr); + if ((acl.internal.ctrl_routing&0xA)==8) + { + mixdat = vram[(acl.mix_addr>>3)&0x1FFFFF] & (1<<(acl.mix_addr&7)); + if (bltout) pclog("%06X %02X ",acl.mix_addr,vram[(acl.mix_addr>>3)&0x1FFFFF]); + } + else + { + mixdat = mix & 1; + mix>>=1; mix|=0x80000000; + } + + rop = (mixdat) ? acl.internal.rop_fg:acl.internal.rop_bg; + for (c=0;c<8;c++) + { + d=(dest & (1<>10]=changeframecount; + } + else + { + acl.cpu_dat|=((uint64_t)out<<(acl.cpu_dat_pos*8)); + acl.cpu_dat_pos++; + } + + if (acl.internal.xy_dir&1) et4000w32_decx(1); + else et4000w32_incx(1); + + acl.internal.pos_x++; + if (acl.internal.pos_x>acl.internal.count_x) + { + if (acl.internal.xy_dir&2) + { + et4000w32_decy(); + acl.mix_back =acl.mix_addr =acl.mix_back -(acl.internal.mix_off +1); + acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); + } + else + { + et4000w32_incy(); + acl.mix_back =acl.mix_addr =acl.mix_back +acl.internal.mix_off +1; + acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; + } + + acl.pattern_x = acl.pattern_x_back; + acl.source_x = acl.source_x_back; + + acl.internal.pos_y++; + acl.internal.pos_x=0; + if (acl.internal.pos_y>acl.internal.count_y) + { + acl.status = 0; +// pclog("Blit over\n"); + return; + } + if (cpu_input) return; + if (acl.internal.ctrl_routing&0x40) + { + if (acl.cpu_dat_pos&3) acl.cpu_dat_pos+=4-(acl.cpu_dat_pos&3); + return; + } + } + } + } +} + + +void et4000w32p_cursor_draw(int displine) +{ + int x, offset; + uint8_t dat; + offset = svga_hwcursor_latch.xoff; + for (x = 0; x < 64 - svga_hwcursor_latch.xoff; x += 4) + { + dat = vram[svga_hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 32] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 32] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 33] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 33] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 34] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 34] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 35] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine])[svga_hwcursor_latch.x + x + 35] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga_hwcursor_latch.addr += 16; +} + +uint8_t et4000w32p_pci_read(int func, int addr) +{ + pclog("ET4000 PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x0c; /*Tseng Labs*/ + case 0x01: return 0x10; + + case 0x02: return 0x06; /*ET4000W32p Rev D*/ + case 0x03: return 0x32; + + case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return crtc[0x5a] & 0x80; + case 0x13: return crtc[0x59]; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + } + return 0; +} + +void et4000w32p_pci_write(int func, int addr, uint8_t val) +{ + switch (addr) + { + case 0x13: et4000w32p_linearbase = val << 24; et4000w32p_recalcmapping(); break; + } +} + +int et4000w32p_init() +{ + svga_recalctimings_ex = et4000w32p_recalctimings; + svga_hwcursor_draw = et4000w32p_cursor_draw; + + io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL); + + pci_add(et4000w32p_pci_read, et4000w32p_pci_write); + + svga_vram_limit = 2 << 20; /*2mb - chip supports 4mb but can't map both 4mb linear frame buffer and accelerator registers*/ + + vrammask = 0x1fffff; + + return svga_init(); +} + +GFXCARD vid_et4000w32p = +{ + et4000w32p_init, + /*IO at 3Cx/3Dx*/ + et4000w32p_out, + et4000w32p_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; + + diff --git a/src/vid_et4000w32i.c b/src/vid_et4000w32i.c new file mode 100644 index 00000000..3570b4ce --- /dev/null +++ b/src/vid_et4000w32i.c @@ -0,0 +1,407 @@ +/*The below is (with some removals) a reasonable emulation of the ET4000/W32i blitter. + Unfortunately the Diamond Stealth 32 is actually an ET4000/W32p! Which has a different + blitter. If only I'd dug out and looked at the card before trying to emulate it. + + This might be of use for an attempt at emulating an ET4000/W32i. + */ +#if 0 + +#include "ibm.h" + +int et4k_b8000; + +struct +{ + struct + { + uint32_t pattern_addr,source_addr,dest_addr; + uint16_t pattern_off,source_off,dest_off; + uint8_t vbus,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr; + uint32_t pattern_back,dest_back; + int pattern_x,source_x; + int pattern_x_back; + int pattern_y,source_y; + uint8_t status; + uint32_t cpu_input; + int cpu_input_num; +} acl; + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +struct +{ + uint32_t base[3]; + uint8_t ctrl; +} mmu; + +void et4000w32_reset() +{ + acl.status=0; + acl.cpu_input_num=0; +} + +void et4000w32_blit_start(); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); + +int et4000w32_vbus[4]={1,2,4,4}; + +void et4000w32_mmu_write(uint32_t addr, uint8_t val) +{ + int bank; + pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>10]=changeframecount; + } + break; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; + case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; + case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; + case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; + case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; + case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; + case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; + case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; + case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; + case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; + case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; + case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; + case 0x7F13: mmu.ctrl=val; break; + + case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; + case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; + case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; + case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; + case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; + case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; + case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; + case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; + case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; + case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; + case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; + case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; + case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; + case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; + case 0x7F8E: acl.queued.vbus=val; break; + case 0x7F8F: acl.queued.xy_dir=val; break; + case 0x7F90: acl.queued.pattern_wrap=val; break; + case 0x7F92: acl.queued.source_wrap=val; break; + case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; + case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; + case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; + case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; + case 0x7F9C: acl.queued.ctrl_routing=val; break; + case 0x7F9D: acl.queued.ctrl_reload =val; break; + case 0x7F9E: acl.queued.rop_bg =val; break; + case 0x7F9F: acl.queued.rop_fg =val; break; + case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; + case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; + case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; + case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); + acl.internal=acl.queued; + et4000w32_blit_start(); + acl.cpu_input_num=0; + if (!(acl.queued.ctrl_routing&0x37)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0); + } + break; + } + break; + } +} + +uint8_t et4000w32_mmu_read(uint32_t addr) +{ + int bank; + pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>8; + case 0x7F02: return mmu.base[0]>>16; + case 0x7F03: return mmu.base[0]>>24; + case 0x7F04: return mmu.base[1]; + case 0x7F05: return mmu.base[1]>>8; + case 0x7F06: return mmu.base[1]>>16; + case 0x7F07: return mmu.base[1]>>24; + case 0x7F08: return mmu.base[2]; + case 0x7F09: return mmu.base[2]>>8; + case 0x7F0A: return mmu.base[2]>>16; + case 0x7F0B: return mmu.base[2]>>24; + case 0x7F13: return mmu.ctrl; + + case 0x7F36: +// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; + return acl.status & ~(ACL_XYST | ACL_SSO); + case 0x7F80: return acl.internal.pattern_addr; + case 0x7F81: return acl.internal.pattern_addr>>8; + case 0x7F82: return acl.internal.pattern_addr>>16; + case 0x7F83: return acl.internal.pattern_addr>>24; + case 0x7F84: return acl.internal.source_addr; + case 0x7F85: return acl.internal.source_addr>>8; + case 0x7F86: return acl.internal.source_addr>>16; + case 0x7F87: return acl.internal.source_addr>>24; + case 0x7F88: return acl.internal.pattern_off; + case 0x7F89: return acl.internal.pattern_off>>8; + case 0x7F8A: return acl.internal.source_off; + case 0x7F8B: return acl.internal.source_off>>8; + case 0x7F8C: return acl.internal.dest_off; + case 0x7F8D: return acl.internal.dest_off>>8; + case 0x7F8E: return acl.internal.vbus; + case 0x7F8F: return acl.internal.xy_dir; + case 0x7F90: return acl.internal.pattern_wrap; + case 0x7F92: return acl.internal.source_wrap; + case 0x7F98: return acl.internal.count_x; + case 0x7F99: return acl.internal.count_x>>8; + case 0x7F9A: return acl.internal.count_y; + case 0x7F9B: return acl.internal.count_y>>8; + case 0x7F9C: return acl.internal.ctrl_routing; + case 0x7F9D: return acl.internal.ctrl_reload; + case 0x7F9E: return acl.internal.rop_bg; + case 0x7F9F: return acl.internal.rop_fg; + case 0x7FA0: return acl.internal.dest_addr; + case 0x7FA1: return acl.internal.dest_addr>>8; + case 0x7FA2: return acl.internal.dest_addr>>16; + case 0x7FA3: return acl.internal.dest_addr>>24; + } + return 0xFF; + } +} + +int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +void et4000w32_blit_start() +{ + pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); + acl.pattern_addr=acl.internal.pattern_addr; + acl.source_addr =acl.internal.source_addr; + acl.dest_addr =acl.internal.dest_addr; + acl.dest_back =acl.dest_addr; + acl.internal.pos_x=acl.internal.pos_y=0; + acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; + acl.status = ACL_XYST; + if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; + if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) + { + acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + } + if (!(acl.internal.pattern_wrap&0x80)) + { + acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); + acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); + } + acl.pattern_x_back=acl.pattern_x; + acl.pattern_back=acl.pattern_addr; +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) +{ + int c,d; + uint8_t pattern,source,dest,out; + uint8_t rop; + +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); +// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); + while (count--) + { + pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); + } + else + { + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); + } + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); + rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; + mix>>=1; mix|=0x80000000; + for (c=0;c<8;c++) + { + d=(dest & (1<>10]=changeframecount; + + acl.pattern_x++; + acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.source_x++; + acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + + acl.internal.pos_x++; + if (acl.internal.pos_x>acl.internal.count_x) + { + if (acl.internal.xy_dir&2) + { + acl.pattern_addr-=(acl.internal.pattern_off+1); + acl.source_addr -=(acl.internal.source_off +1); + acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); + } + else + { + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off +1; + acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; + } + acl.pattern_x = acl.pattern_x_back; + acl.source_x = 0; + acl.pattern_y++; + if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + acl.pattern_y=0; + acl.pattern_addr=acl.pattern_back; + } + acl.source_y++; + if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + acl.source_y=0; + acl.source_addr=acl.internal.source_addr; + } + + acl.internal.pos_y++; + if (acl.internal.pos_y>acl.internal.count_y) + { + acl.status = 0; + return; + } + acl.internal.pos_x=0; + if (cpu_input) return; + } + } +} + +/* for (y=0;y<=acl.internal.count_y;y++) + { + dest_back=acl.dest_addr; + for (x=0;x<=acl.internal.count_x;x++) + { + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -source_x) &0x1FFFFF]; + } + else + { + pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +source_x) &0x1FFFFF]; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + for (c=0;c<8;c++) + { + d=(dest&(1<>10]=changeframecount; + + pattern_x++; + pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + source_x++; + source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + } + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off+1; + acl.dest_addr=dest_back+acl.internal.dest_off+1; + pattern_y++; + if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + pattern_y=0; + acl.pattern_addr=acl.internal.pattern_addr; + } + source_y++; + if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + source_y=0; + acl.source_addr=acl.internal.source_addr; + } + }*/ + +#endif diff --git a/src/vid_hercules.c b/src/vid_hercules.c new file mode 100644 index 00000000..86a0414d --- /dev/null +++ b/src/vid_hercules.c @@ -0,0 +1,291 @@ +/*Hercules emulation*/ +#include "ibm.h" +#include "video.h" + +void hercules_recalctimings(); +void hercules_write(uint32_t addr, uint8_t val); +uint8_t hercules_read(uint32_t addr); + +static uint8_t hercules_ctrl, hercules_ctrl2, hercules_stat; +uint8_t crtcm[32],crtcmreg; + +void hercules_out(uint16_t addr, uint8_t val) +{ +// pclog("Herc out %04X %02X\n",addr,val); + switch (addr) + { + case 0x3B0: case 0x3B2: case 0x3B4: case 0x3B6: + crtcmreg = val & 31; + return; + case 0x3B1: case 0x3B3: case 0x3B5: case 0x3B7: + crtcm[crtcmreg] = val; + if (crtcm[10]==6 && crtcm[11]==7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + crtcm[10]=0xB; + crtcm[11]=0xC; + } + hercules_recalctimings(); + return; + case 0x3B8: + hercules_ctrl = val; + return; + case 0x3BF: + hercules_ctrl2 = val; + video_write_b800 = (val&2) ? hercules_write : video_write_null; + video_read_b800 = (val&2) ? hercules_read : video_read_null; + return; + } +} + +uint8_t hercules_in(uint16_t addr) +{ + // pclog("Herc in %04X %02X %04X:%04X %04X\n",addr,(hercules_stat & 0xF) | ((hercules_stat & 8) << 4),CS,pc,CX); + switch (addr) + { + case 0x3B0: case 0x3B2: case 0x3B4: case 0x3B6: + return crtcmreg; + case 0x3B1: case 0x3B3: case 0x3B5: case 0x3B7: + return crtcm[crtcmreg]; + case 0x3BA: + return (hercules_stat & 0xF) | ((hercules_stat & 8) << 4); + } +} + +void hercules_write(uint32_t addr, uint8_t val) +{ +// pclog("Herc write %08X %02X\n",addr,val); + vram[addr&0xFFFF]=val; +} + +uint8_t hercules_read(uint32_t addr) +{ + return vram[addr&0xFFFF]; +} + +void hercules_recalctimings() +{ + disptime=crtc[0]+1; + dispontime=crtc[1]; + dispofftime=disptime-dispontime; + dispontime*=MDACONST; + dispofftime*=MDACONST; +} + +int mdacols[256][2][2]; + +static int linepos,displine; +static int vc,sc; +static uint16_t ma,maback,ca; +static int con,coff,cursoron; +static int cgadispon,cgablink; +static int vsynctime,vadj; + +void hercules_poll() +{ + uint16_t ca=(crtcm[15]|(crtcm[14]<<8))&0x3FFF; + int drawcursor; + int x,c; + int oldvc; + uint8_t chr,attr; + uint16_t dat,dat2,dat3,dat4; + int cols[4]; + int col; + int oldsc; + int blink; + if (!linepos) + { + //pclog("Poll %i %i\n",vc,sc); + vidtime+=dispofftime; + hercules_stat|=1; + linepos=1; + oldsc=sc; + if ((crtcm[8]&3)==3) sc=(sc<<1)&7; + if (cgadispon) + { + if (displineline[displine][(x<<4)+c]=(dat&(32768>>c))?7:0; + } + } + else + { + for (x=0;xline[displine][(x*9)+c]=mdacols[attr][blink][1]; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x*9)+c]=mdacols[attr][blink][(fontdatm[chr][sc]&(1<<(c^7)))?1:0]; + if ((chr&~0x1F)==0xC0) buffer->line[displine][(x*9)+8]=mdacols[attr][blink][fontdatm[chr][sc]&1]; + else buffer->line[displine][(x*9)+8]=mdacols[attr][blink][0]; + } + ma++; + if (drawcursor) + { + for (c=0;c<9;c++) + buffer->line[displine][(x*9)+c]^=mdacols[attr][0][1]; + } + } + } + } + sc=oldsc; + if (vc==crtcm[7] && !sc) + { + hercules_stat|=8; +// printf("VSYNC on %i %i\n",vc,sc); + } + displine++; + if (displine>=500) displine=0; + } + else + { + vidtime+=dispontime; + if (cgadispon) hercules_stat&=~1; + linepos=0; + if (vsynctime) + { + vsynctime--; + if (!vsynctime) + { + hercules_stat&=~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (sc==(crtcm[11]&31) || ((crtcm[8]&3)==3 && sc==((crtcm[11]&31)>>1))) { con=0; coff=1; } + if (vadj) + { + sc++; + sc&=31; + ma=maback; + vadj--; + if (!vadj) + { + cgadispon=1; + ma=maback=(crtcm[13]|(crtcm[12]<<8))&0x3FFF; + sc=0; + } + } + else if (sc==crtcm[9] || ((crtcm[8]&3)==3 && sc==(crtcm[9]>>1))) + { + maback=ma; + sc=0; + oldvc=vc; + vc++; + vc&=127; + if (vc==crtcm[6]) cgadispon=0; + if (oldvc==crtcm[4]) + { +// printf("Display over at %i\n",displine); + vc=0; + vadj=crtcm[5]; + if (!vadj) cgadispon=1; + if (!vadj) ma=maback=(crtcm[13]|(crtcm[12]<<8))&0x3FFF; + if ((crtcm[10]&0x60)==0x20) cursoron=0; + else cursoron=cgablink&16; + } + if (vc==crtcm[7]) + { + cgadispon=0; + displine=0; + vsynctime=16;//(crtcm[3]>>4)+1; + if (crtcm[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((hercules_ctrl & 2) && (hercules_ctrl2 & 1)) x = crtcm[1] << 4; + else x = crtcm[1] * 9; + lastline++; + if (x!=xsize || (lastline-firstline)!=ysize) + { + xsize=x; + ysize=lastline-firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + updatewindowsize(xsize,ysize); + } + startblit(); + video_blit_memtoscreen_8(0, firstline, xsize, ysize); + endblit(); + frames++; + if ((hercules_ctrl & 2) && (hercules_ctrl2 & 1)) + { + video_res_x = crtcm[1] * 16; + video_res_y = crtcm[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = crtcm[1]; + video_res_y = crtcm[6]; + video_bpp = 0; + } + } + firstline=1000; + lastline=0; + cgablink++; + } + } + else + { + sc++; + sc&=31; + ma=maback; + } + if ((sc==(crtcm[10]&31) || ((crtcm[8]&3)==3 && sc==((crtcm[10]&31)>>1)))) + { + con=1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +int hercules_init() +{ + mem_sethandler(0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL); + return 0; +} + +GFXCARD vid_hercules = +{ + hercules_init, + /*IO at 3Cx/3Dx*/ + video_out_null, + video_in_null, + /*IO at 3Ax/3Bx*/ + hercules_out, + hercules_in, + + hercules_poll, + hercules_recalctimings, + + video_write_null, + hercules_write, + video_write_null, + + video_read_null, + hercules_read, + video_read_null +}; diff --git a/src/vid_icd2061.c b/src/vid_icd2061.c new file mode 100644 index 00000000..f43f668a --- /dev/null +++ b/src/vid_icd2061.c @@ -0,0 +1,74 @@ +/*PCem v0.7 by Tom Walker + + ICD2061 clock generator emulation + Used by ET4000w32/p (Diamond Stealth 32)*/ +#include "ibm.h" +#include "vid_icd2061.h" + +static int icd2061_state; +static int icd2061_status = 0; +static int icd2061_pos = 0; +static int icd2061_unlock = 0; +static uint32_t icd2061_data; + +static double icd2061_freq[4]; +static uint32_t icd2061_ctrl; + +void icd2061_write(int val) +{ + int q, p, m, i, a; + if ((val & 1) && !(icd2061_state & 1)) + { + pclog("ICD2061 write %02X %i %08X %i\n", val, icd2061_unlock, icd2061_data, icd2061_pos); + if (!icd2061_status) + { + if (val & 2) icd2061_unlock++; + else + { + if (icd2061_unlock >= 5) + { + icd2061_status = 1; + icd2061_pos = 0; + } + else + icd2061_unlock = 0; + } + } + else if (val & 1) + { + icd2061_data = (icd2061_data >> 1) | (((val & 2) ? 1 : 0) << 24); + icd2061_pos++; + if (icd2061_pos == 26) + { + pclog("ICD2061 data - %08X\n", icd2061_data); + a = (icd2061_data >> 21) & 0x7; + if (!(a & 4)) + { + q = (icd2061_data & 0x7f) - 2; + m = 1 << ((icd2061_data >> 7) & 0x7); + p = ((icd2061_data >> 10) & 0x7f) - 3; + i = (icd2061_data >> 17) & 0xf; + pclog("p %i q %i m %i\n", p, q, m); + if (icd2061_ctrl & (1 << a)) + p <<= 1; + icd2061_freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; + pclog("ICD2061 freq %i = %f\n", a, icd2061_freq[a]); + } + else if (a == 6) + { + icd2061_ctrl = val; + pclog("ICD2061 ctrl = %08X\n", val); + } + icd2061_unlock = icd2061_data = 0; + icd2061_status = 0; + } + } + } + icd2061_state = val; +} + +double icd2061_getfreq(int i) +{ + pclog("Return freq %f\n", icd2061_freq[i]); + return icd2061_freq[i]; +} diff --git a/src/vid_icd2061.h b/src/vid_icd2061.h new file mode 100644 index 00000000..3d8b3fe1 --- /dev/null +++ b/src/vid_icd2061.h @@ -0,0 +1,2 @@ +void icd2061_write(int val); +double icd2061_getfreq(int i); diff --git a/src/vid_mda.c b/src/vid_mda.c new file mode 100644 index 00000000..2fb6aa0e --- /dev/null +++ b/src/vid_mda.c @@ -0,0 +1,254 @@ +/*MDA emulation*/ +#include "ibm.h" +#include "video.h" + +void mda_recalctimings(); + +static uint8_t mda_ctrl,mda_stat; +uint8_t crtcm[32],crtcmreg; + +void mda_out(uint16_t addr, uint8_t val) +{ + switch (addr) + { + case 0x3B0: case 0x3B2: case 0x3B4: case 0x3B6: + crtcmreg = val & 31; + return; + case 0x3B1: case 0x3B3: case 0x3B5: case 0x3B7: + crtcm[crtcmreg] = val; + if (crtcm[10]==6 && crtcm[11]==7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + crtcm[10]=0xB; + crtcm[11]=0xC; + } + mda_recalctimings(); + return; + case 0x3B8: + mda_ctrl = val; + return; + } +} + +uint8_t mda_in(uint16_t addr) +{ + switch (addr) + { + case 0x3B0: case 0x3B2: case 0x3B4: case 0x3B6: + return crtcmreg; + case 0x3B1: case 0x3B3: case 0x3B5: case 0x3B7: + return crtcm[crtcmreg]; + case 0x3BA: + return mda_stat | 0xF0; + } +} + +void mda_write(uint32_t addr, uint8_t val) +{ + vram[addr&0xFFF]=val; +} + +uint8_t mda_read(uint32_t addr) +{ + return vram[addr&0xFFF]; +} + +void mda_recalctimings() +{ + disptime=crtc[0]+1; + dispontime=crtc[1]; + dispofftime=disptime-dispontime; + dispontime*=MDACONST; + dispofftime*=MDACONST; +} + +int mdacols[256][2][2]; + +static int linepos,displine; +static int vc,sc; +static uint16_t ma,maback,ca; +static int con,coff,cursoron; +static int cgadispon,cgablink; +static int vsynctime,vadj; + +void mda_poll() +{ + uint16_t ca=(crtcm[15]|(crtcm[14]<<8))&0x3FFF; + int drawcursor; + int x,c; + int oldvc; + uint8_t chr,attr; + uint16_t dat,dat2,dat3,dat4; + int cols[4]; + int col; + int oldsc; + int blink; + if (!linepos) + { + vidtime+=dispofftime; + mda_stat|=1; + linepos=1; + oldsc=sc; + if ((crtcm[8]&3)==3) sc=(sc<<1)&7; + if (cgadispon) + { + if (displineline[displine][(x*9)+c]=mdacols[attr][blink][1]; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x*9)+c]=mdacols[attr][blink][(fontdatm[chr][sc]&(1<<(c^7)))?1:0]; + if ((chr&~0x1F)==0xC0) buffer->line[displine][(x*9)+8]=mdacols[attr][blink][fontdatm[chr][sc]&1]; + else buffer->line[displine][(x*9)+8]=mdacols[attr][blink][0]; + } + ma++; + if (drawcursor) + { + for (c=0;c<9;c++) + buffer->line[displine][(x*9)+c]^=mdacols[attr][0][1]; + } + } + } + sc=oldsc; + if (vc==crtcm[7] && !sc) + { + mda_stat|=8; +// printf("VSYNC on %i %i\n",vc,sc); + } + displine++; + if (displine>=500) displine=0; + } + else + { + vidtime+=dispontime; + if (cgadispon) mda_stat&=~1; + linepos=0; + if (vsynctime) + { + vsynctime--; + if (!vsynctime) + { + mda_stat&=~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (sc==(crtcm[11]&31) || ((crtcm[8]&3)==3 && sc==((crtcm[11]&31)>>1))) { con=0; coff=1; } + if (vadj) + { + sc++; + sc&=31; + ma=maback; + vadj--; + if (!vadj) + { + cgadispon=1; + ma=maback=(crtcm[13]|(crtcm[12]<<8))&0x3FFF; + sc=0; + } + } + else if (sc==crtcm[9] || ((crtcm[8]&3)==3 && sc==(crtcm[9]>>1))) + { + maback=ma; + sc=0; + oldvc=vc; + vc++; + vc&=127; + if (vc==crtcm[6]) cgadispon=0; + if (oldvc==crtcm[4]) + { +// printf("Display over at %i\n",displine); + vc=0; + vadj=crtcm[5]; + if (!vadj) cgadispon=1; + if (!vadj) ma=maback=(crtcm[13]|(crtcm[12]<<8))&0x3FFF; + if ((crtcm[10]&0x60)==0x20) cursoron=0; + else cursoron=cgablink&16; + } + if (vc==crtcm[7]) + { + cgadispon=0; + displine=0; + vsynctime=16;//(crtcm[3]>>4)+1; + if (crtcm[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + x=crtcm[1]*9; + lastline++; + if (x!=xsize || (lastline-firstline)!=ysize) + { + xsize=x; + ysize=lastline-firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + updatewindowsize(xsize,ysize); + } + startblit(); + video_blit_memtoscreen_8(0, firstline, xsize, lastline - firstline); + endblit(); + frames++; + video_res_x = crtcm[1]; + video_res_y = crtcm[6]; + video_bpp = 0; + } + firstline=1000; + lastline=0; + cgablink++; + } + } + else + { + sc++; + sc&=31; + ma=maback; + } + if ((sc==(crtcm[10]&31) || ((crtcm[8]&3)==3 && sc==((crtcm[10]&31)>>1)))) + { + con=1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +int mda_init() +{ + mem_sethandler(0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL); + return 0; +} + +GFXCARD vid_mda = +{ + mda_init, + /*IO at 3Cx/3Dx*/ + video_out_null, + video_in_null, + /*IO at 3Ax/3Bx*/ + mda_out, + mda_in, + + mda_poll, + mda_recalctimings, + + video_write_null, + mda_write, + video_write_null, + + video_read_null, + mda_read, + video_read_null +}; diff --git a/src/vid_olivetti_m24.c b/src/vid_olivetti_m24.c new file mode 100644 index 00000000..9b63ba45 --- /dev/null +++ b/src/vid_olivetti_m24.c @@ -0,0 +1,428 @@ +/*Olivetti M24 video emulation + Essentially double-res CGA*/ +#include "ibm.h" +#include "video.h" + +static uint8_t m24_ctrl; +static uint32_t m24_base; + +void m24_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + switch (addr) + { + case 0x3D4: + crtcreg = val & 31; + return; + case 0x3D5: + old = crtc[crtcreg]; + crtc[crtcreg] = val & crtcmask[crtcreg]; + if (old != val) + { + if (crtcreg < 0xE || crtcreg > 0x10) + { + fullchange = changeframecount; + m24_recalctimings(); + } + } + return; + case 0x3D8: + cgamode = val; + return; + case 0x3D9: + cgacol = val; + return; + case 0x3de: + m24_ctrl = val; + m24_base = (val & 0x08) ? 0x4000 : 0; + return; + } +} + +uint8_t m24_in(uint16_t addr) +{ + switch (addr) + { + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + case 0x3DA: + return cgastat; + } + return 0xFF; +} + +static uint8_t charbuffer[256]; + +void m24_write(uint32_t addr, uint8_t val) +{ + vram[addr & 0x7FFF]=val; + charbuffer[ ((int)(((dispontime - vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val; + charbuffer[(((int)(((dispontime - vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val; +} + +uint8_t m24_read(uint32_t addr) +{ + return vram[addr & 0x7FFF]; +} + +void m24_recalctimings() +{ + if (cgamode & 1) + { + disptime = crtc[0] + 1; + dispontime = crtc[1]; + } + else + { + disptime = (crtc[0] + 1) << 1; + dispontime = crtc[1] << 1; + } + dispofftime = disptime - dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + dispontime *= CGACONST / 2; + dispofftime *= CGACONST / 2; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); +} + +static int linepos,displine; +static int sc,vc; +static int cgadispon; +static int con,coff,cursoron,cgablink; +static int vsynctime,vadj; +static int m24_lineff = 0; +static uint16_t ma,maback,ca; + +void m24_poll() +{ + uint16_t ca=(crtc[15]|(crtc[14]<<8))&0x3FFF; + int drawcursor; + int x,c; + int oldvc; + uint8_t chr,attr; + uint16_t dat,dat2,dat3,dat4; + int cols[4]; + int col; + int oldsc; + if (!linepos) + { +// pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine); + vidtime+=dispofftime; + cgastat|=1; + linepos=1; + oldsc=sc; + if ((crtc[8]&3)==3) sc=(sc<<1)&7; + if (cgadispon) + { + if (displineline[displine][c]=0; + if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=0; + else buffer->line[displine][c+(crtc[1]<<4)+8]=0; + } + else + { + buffer->line[displine][c]=(cgacol&15)+16; + if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=(cgacol&15)+16; + else buffer->line[displine][c+(crtc[1]<<4)+8]=(cgacol&15)+16; + } + } + if (cgamode&1) + { + for (x=0;x>4)&7)+16; + if ((cgablink&16) && (attr&0x80) && !drawcursor) cols[1]=cols[0]; + } + else + { + cols[1]=(attr&15)+16; + cols[0]=(attr>>4)+16; + } + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]^15; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]; + } + ma++; + } + } + else if (!(cgamode&2)) + { + for (x=0;x>4)&7)+16; + if ((cgablink&16) && (attr&0x80)) cols[1]=cols[0]; + } + else + { + cols[1]=(attr&15)+16; + cols[0]=(attr>>4)+16; + } + ma++; + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]^15; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdatm[chr][((sc & 7) << 1) | m24_lineff]&(1<<(c^7)))?1:0]; + } + } + } + else if (!(cgamode&16)) + { + cols[0]=(cgacol&15)|16; + col=(cgacol&16)?24:16; + if (cgamode&4) + { + cols[1]=col|3; + cols[2]=col|4; + cols[3]=col|7; + } + else if (cgacol&32) + { + cols[1]=col|3; + cols[2]=col|5; + cols[3]=col|7; + } + else + { + cols[1]=col|2; + cols[2]=col|4; + cols[3]=col|6; + } + for (x=0;xline[displine][(x<<4)+(c<<1)+8]= + buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[dat>>14]; + dat<<=2; + } + } + } + else + { + + if (m24_ctrl & 1) + { + dat2 = ((sc & 1) * 0x4000) | (m24_lineff * 0x2000); + cols[0]=0; cols[1]=/*(cgacol&15)*/15+16; + } + else + { + dat2 = (sc & 1) * 0x2000; + cols[0]=0; cols[1]=(cgacol&15)+16; + } + for (x=0;xline[displine][(x<<4)+c+8]=cols[dat>>15]; + dat<<=1; + } + } + } + } + else + { + cols[0]=((cgamode&0x12)==0x12)?0:(cgacol&15)+16; + if (cgamode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,cols[0]); + else hline(buffer,0,displine,(crtc[1]<<4)+16,cols[0]); + } + + if (cgamode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + + sc=oldsc; + if (vc==crtc[7] && !sc) + cgastat|=8; + displine++; + if (displine>=720) displine=0; + } + else + { +// pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj); + vidtime+=dispontime; + if (cgadispon) cgastat&=~1; + linepos=0; + m24_lineff ^= 1; + if (m24_lineff) + { + ma = maback; + } + else + { + if (vsynctime) + { + vsynctime--; + if (!vsynctime) + cgastat&=~8; + } + if (sc==(crtc[11]&31) || ((crtc[8]&3)==3 && sc==((crtc[11]&31)>>1))) { con=0; coff=1; } + if (vadj) + { + sc++; + sc&=31; + ma=maback; + vadj--; + if (!vadj) + { + cgadispon=1; + ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + sc=0; + } + } + else if (sc==crtc[9] || ((crtc[8]&3)==3 && sc==(crtc[9]>>1))) + { + maback=ma; + sc=0; + oldvc=vc; + vc++; + vc&=127; + + if (vc==crtc[6]) + cgadispon=0; + + if (oldvc==crtc[4]) + { + vc=0; + vadj=crtc[5]; + if (!vadj) cgadispon=1; + if (!vadj) ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + if ((crtc[10]&0x60)==0x20) cursoron=0; + else cursoron=cgablink&16; + } + + if (vc==crtc[7]) + { + cgadispon=0; + displine=0; + vsynctime=(crtc[3]>>4)+1; + if (crtc[7]) + { + if (cgamode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + lastline++; + if (x!=xsize || (lastline-firstline)!=ysize) + { + xsize=x; + ysize=lastline-firstline; + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + updatewindowsize(xsize, ysize + 16); + } +startblit(); + video_blit_memtoscreen_8(0, firstline - 8, xsize, (lastline - firstline) + 16); + if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); + readflash=0; + frames++; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (cgamode & 1) + { + video_res_x /= 8; + video_res_y /= (crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (!(cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= (crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (!(cgamode&16)) + { + video_res_x /= 2; + video_res_y /= 2; + video_bpp = 2; + } + else if (!(m24_ctrl & 1)) + { + video_res_y /= 2; + video_bpp = 1; + } + } + firstline=1000; + lastline=0; + cgablink++; + } + } + else + { + sc++; + sc&=31; + ma=maback; + } + if ((sc==(crtc[10]&31) || ((crtc[8]&3)==3 && sc==((crtc[10]&31)>>1)))) con=1; + } + if (cgadispon && (cgamode&1)) + { + for (x=0;x<(crtc[1]<<1);x++) + charbuffer[x]=vram[(((ma<<1)+x)&0x3FFF) + m24_base]; + } + } +} + + +int m24_init() +{ + mem_sethandler(0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL); + return 0; +} + +GFXCARD vid_m24 = +{ + m24_init, + /*IO at 3Cx/3Dx*/ + m24_out, + m24_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + m24_poll, + m24_recalctimings, + + video_write_null, + video_write_null, + m24_write, + + video_read_null, + video_read_null, + m24_read +}; diff --git a/src/vid_olivetti_m24.h b/src/vid_olivetti_m24.h new file mode 100644 index 00000000..e69de29b diff --git a/src/vid_oti067.c b/src/vid_oti067.c new file mode 100644 index 00000000..06688cf1 --- /dev/null +++ b/src/vid_oti067.c @@ -0,0 +1,108 @@ +/*Oak OTI067 emulation*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" + +static int oti067_index; +static uint8_t oti067_regs[32]; + +void oti067_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + + if ((addr&0xFFF0) == 0x3B0) addr |= 0x20; + + switch (addr) + { + case 0x3D4: + crtcreg=val&31; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + + case 0x3DE: oti067_index=val&0x1F; return; + case 0x3DF: + oti067_regs[oti067_index]=val; + switch (oti067_index) + { + case 0xD: + vrammask=(val&0xC)?0x7FFFF:0x3FFFF; + break; + case 0x11: + svgarbank=(val&0xF)*65536; + svgawbank=(val>>4)*65536; + break; + } + return; + } + svga_out(addr,val); +} + +uint8_t oti067_in(uint16_t addr) +{ + uint8_t temp; + + if ((addr&0xFFF0) == 0x3B0) addr |= 0x20; + + switch (addr) + { + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + case 0x3DE: return oti067_index|(2<<5); + case 0x3DF: + if (oti067_index==0x10) return 0x40; + if (oti067_index==0xD) return oti067_regs[oti067_index]|0xC0; + return oti067_regs[oti067_index]; + } + return svga_in(addr); +} + +void oti067_recalctimings() +{ + if (oti067_regs[0x14]&0x08) svga_ma|=0x10000; + if (oti067_regs[0x0D]&0x0C) svga_rowoffset<<=1; + svga_interlace = oti067_regs[0x14]&0x80; +} + +int oti067_init() +{ + svga_recalctimings_ex = oti067_recalctimings; + svga_vram_limit = 1 << 19; /*512kb*/ + vrammask = 0x7ffff; + return svga_init(); +} + +GFXCARD vid_oti067 = +{ + oti067_init, + /*IO at 3Cx/3Dx*/ + oti067_out, + oti067_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_paradise.c b/src/vid_paradise.c new file mode 100644 index 00000000..c3cc8130 --- /dev/null +++ b/src/vid_paradise.c @@ -0,0 +1,273 @@ +/*Paradise VGA emulation + + PC2086, PC3086 use PVGA1A + MegaPC uses W90C11A + */ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +void paradise_write(uint32_t addr, uint8_t val); +uint8_t paradise_read(uint32_t addr); + +enum +{ + PVGA1A = 0, + WD90C11 +}; + +static int paradise_type; + +static uint32_t paradise_bank_r[4], paradise_bank_w[4]; + +void paradise_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; +// output = 3; + pclog("Paradise out %04X %02X %04X:%04X\n", addr, val, CS, pc); + switch (addr) + { + case 0x3c5: + if (seqaddr > 7) + { + if (paradise_type < WD90C11 || seqregs[6] != 0x48) + return; + seqregs[seqaddr & 0x1f] = val; + if (seqaddr == 0x11) + paradise_remap(); + return; + } + break; + + case 0x3cf: + if (gdcaddr >= 0x9 && gdcaddr < 0xf) + { + if ((gdcreg[0xf] & 7) != 5) + return; + } + if (gdcaddr == 6) + { + if ((gdcreg[6] & 0xc) != (val & 0xc)) + { + mem_removehandler(0xa0000, 0x20000, paradise_read, NULL, NULL, svga_write, NULL, NULL); +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + break; + } + } + gdcreg[6] = val; + paradise_remap(); + return; + } + if (gdcaddr == 0x9 || gdcaddr == 0xa) + { + gdcreg[gdcaddr] = val; + paradise_remap(); + return; + } + if (gdcaddr == 0xe) + { + gdcreg[0xe] = val; + paradise_remap(); + return; + } + break; + + case 0x3D4: + if (paradise_type == PVGA1A) + crtcreg = val & 0x1f; + else + crtcreg = val & 0x3f; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) + return; + if (crtcreg > 0x29 && (crtc[0x29] & 7) != 5) + return; + if (crtcreg >= 0x31 && crtcreg <= 0x37) + return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr,val); +} + +uint8_t paradise_in(uint16_t addr) +{ + uint8_t temp; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// if (addr != 0x3da) pclog("Paradise in %04X\n", addr); + switch (addr) + { + case 0x3c5: + if (seqaddr > 7) + { + if (paradise_type < WD90C11 || seqregs[6] != 0x48) + return 0xff; + if (seqaddr > 0x12) + return 0xff; + return seqregs[seqaddr & 0x1f]; + } + break; + + case 0x3cf: + if (gdcaddr >= 0x9 && gdcaddr < 0xf) + { + if (gdcreg[0xf] & 0x10) + return 0xff; + switch (gdcaddr) + { + case 0xf: + return (gdcreg[0xf] & 0x17) | 0x80; + } + } + break; + + case 0x3D4: + return crtcreg; + case 0x3D5: + if (crtcreg > 0x29 && crtcreg < 0x30 && (crtc[0x29] & 0x88) != 0x80) + return 0xff; + return crtc[crtcreg]; + } + return svga_in(addr); +} + +void paradise_remap() +{ + if (seqregs[0x11] & 0x80) + { +// pclog("Remap 1\n"); + paradise_bank_r[0] = paradise_bank_r[2] = (gdcreg[0x9] & 0x7f) << 12; + paradise_bank_r[1] = paradise_bank_r[3] = ((gdcreg[0x9] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise_bank_w[0] = paradise_bank_w[2] = (gdcreg[0xa] & 0x7f) << 12; + paradise_bank_w[1] = paradise_bank_w[3] = ((gdcreg[0xa] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else if (gdcreg[0xe] & 0x08) + { + if (gdcreg[0x6] & 0xc) + { +// pclog("Remap 2\n"); + paradise_bank_r[0] = paradise_bank_r[2] = (gdcreg[0xa] & 0x7f) << 12; + paradise_bank_w[0] = paradise_bank_w[2] = (gdcreg[0xa] & 0x7f) << 12; + paradise_bank_r[1] = paradise_bank_r[3] = ((gdcreg[0x9] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise_bank_w[1] = paradise_bank_w[3] = ((gdcreg[0x9] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else + { +// pclog("Remap 3\n"); + paradise_bank_r[0] = paradise_bank_w[0] = (gdcreg[0xa] & 0x7f) << 12; + paradise_bank_r[1] = paradise_bank_w[1] = ((gdcreg[0xa] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise_bank_w[2] = paradise_bank_w[2] = (gdcreg[0x9] & 0x7f) << 12; + paradise_bank_w[3] = paradise_bank_w[3] = ((gdcreg[0x9] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + } + } + else + { + // pclog("Remap 4\n"); + paradise_bank_r[0] = paradise_bank_r[2] = (gdcreg[0x9] & 0x7f) << 12; + paradise_bank_r[1] = paradise_bank_r[3] = ((gdcreg[0x9] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise_bank_w[0] = paradise_bank_w[2] = (gdcreg[0x9] & 0x7f) << 12; + paradise_bank_w[1] = paradise_bank_w[3] = ((gdcreg[0x9] & 0x7f) << 12) + ((gdcreg[6] & 0x08) ? 0 : 0x8000); + } +// pclog("Remap - %04X %04X\n", paradise_bank_r[0], paradise_bank_w[0]); +} + +void paradise_recalctimings() +{ + svga_lowres = !(gdcreg[0xe] & 0x01); +} + +#define egacycles 1 +#define egacycles2 1 +void paradise_write(uint32_t addr, uint8_t val) +{ +// pclog("paradise_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + paradise_bank_w[(addr >> 15) & 3]; +// pclog("%08X\n", addr); + svga_write_linear(addr, val); +} + +uint8_t paradise_read(uint32_t addr) +{ +// pclog("paradise_read : %05X ", addr); + addr = (addr & 0x7fff) + paradise_bank_r[(addr >> 15) & 3]; +// pclog("%08X\n", addr); + return svga_read_linear(addr); +} + +int paradise_init() +{ + if (romset == ROM_PC2086 || romset == ROM_PC3086) + { + paradise_type = PVGA1A; + vrammask = 0x3ffff; + pclog("Init PVGA1A\n"); + svga_vram_limit = 1 << 18; /*256kb*/ + } + if (romset == ROM_MEGAPC) + { + paradise_type = WD90C11; + vrammask = 0x7ffff; + crtc[0x36] = '1'; + crtc[0x37] = '1'; + pclog("Init WD90C11\n"); + svga_vram_limit = 1 << 19; /*512kb*/ + } + crtc[0x31] = 'W'; + crtc[0x32] = 'D'; + crtc[0x33] = '9'; + crtc[0x34] = '0'; + crtc[0x35] = 'C'; + svga_recalctimings_ex = paradise_recalctimings; + return svga_init(); +} + +GFXCARD vid_paradise = +{ + paradise_init, + /*IO at 3Cx/3Dx*/ + paradise_out, + paradise_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + paradise_write, + video_write_null, + video_write_null, + + paradise_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_pc1512.c b/src/vid_pc1512.c new file mode 100644 index 00000000..e03cf210 --- /dev/null +++ b/src/vid_pc1512.c @@ -0,0 +1,444 @@ +/*PC1512 CGA emulation + + The PC1512 extends CGA with a bit-planar 640x200x16 mode. + + Most CRTC registers are fixed. + + The Technical Reference Manual lists the video waitstate time as between 12 + and 46 cycles. PCem currently always uses the lower number.*/ + +#include "ibm.h" +#include "video.h" +#include "vid_cga.h" + +static uint8_t pc1512_plane_write,pc1512_plane_read,pc1512_border; + +void pc1512_recalctimings(); + +void pc1512_out(uint16_t addr, uint8_t val) +{ + uint8_t old; +// pclog("PC1512 out %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3D4: + crtcreg=val&31; + return; + case 0x3D5: + old=crtc[crtcreg]; + crtc[crtcreg]=val&crtcmask[crtcreg]; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + pc1512_recalctimings(); + } + } + return; + case 0x3D8: + if ((val&0x12)==0x12 && (cgamode&0x12)!=0x12) + { + pc1512_plane_write=0xF; + pc1512_plane_read =0; + } + cgamode=val; + return; + case 0x3D9: + cgacol=val; + return; + case 0x3DD: + pc1512_plane_write=val; + return; + case 0x3DE: + pc1512_plane_read=val&3; + return; + case 0x3DF: + pc1512_border=val; + return; + } +} + +uint8_t pc1512_in(uint16_t addr) +{ +// pclog("PC1512 in %04X %02X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + case 0x3DA: + return cgastat; + } + return 0xFF; +} + +void pc1512_write(uint32_t addr, uint8_t val) +{ +/* if (CS==0x023E && pc==0x524E) + { + dumpregs(); + exit(-1); + } + pclog("PC1512 write %08X %02X %02X %01X %04X:%04X\n",addr,val,cgamode&0x12,pc1512_plane_write,CS,pc);*/ + cycles-=12; + addr&=0x7FFF; + if ((cgamode&0x12)==0x12) + { + if (pc1512_plane_write&1) vram[addr]=val; + if (pc1512_plane_write&2) vram[addr|0x10000]=val; + if (pc1512_plane_write&4) vram[addr|0x20000]=val; + if (pc1512_plane_write&8) vram[addr|0x30000]=val; + } + else + vram[addr]=val; +} + +uint8_t pc1512_read(uint32_t addr) +{ +// pclog("PC1512 read %08X %02X %01X\n",addr,cgamode&0x12,pc1512_plane_read); + cycles-=12; + addr&=0x7FFF; + if ((cgamode&0x12)==0x12) + return vram[addr|(pc1512_plane_read<<16)]; + return vram[addr]; +} + + +static int linepos,displine; +static int sc,vc; +static int cgadispon; +static int con,coff,cursoron,cgablink; +static int vsynctime,vadj; +static uint16_t ma,maback,ca; + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +int i_filt[8],q_filt[8]; + + +void pc1512_recalctimings() +{ + disptime = 128; /*Fixed on PC1512*/ + dispontime = 80; + dispofftime=disptime-dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + dispontime*=CGACONST; + dispofftime*=CGACONST; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); +} + +void pc1512_poll() +{ + uint16_t ca=(crtc[15]|(crtc[14]<<8))&0x3FFF; + int drawcursor; + int x,c; + int oldvc; + uint8_t chr,attr; + uint16_t dat,dat2,dat3,dat4; + int cols[4]; + int col; + int oldsc; + + if (!linepos) + { + vidtime+=dispofftime; + cgastat|=1; + linepos=1; + oldsc=sc; + if (cgadispon) + { + if (displineline[displine][c]=(pc1512_border&15)+16; + if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=0; + else buffer->line[displine][c+(crtc[1]<<4)+8]=0; + } + else + { + buffer->line[displine][c]=(cgacol&15)+16; + if (cgamode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=(cgacol&15)+16; + else buffer->line[displine][c+(crtc[1]<<4)+8]=(cgacol&15)+16; + } + } + if (cgamode&1) + { + for (x = 0; x < 80; x++) + { + chr=vram[((ma<<1)&0x3FFF)]; + attr=vram[(((ma<<1)+1)&0x3FFF)]; + drawcursor=((ma==ca) && con && cursoron); + if (cgamode&0x20) + { + cols[1]=(attr&15)+16; + cols[0]=((attr>>4)&7)+16; + if ((cgablink&16) && (attr&0x80) && !drawcursor) cols[1]=cols[0]; + } + else + { + cols[1]=(attr&15)+16; + cols[0]=(attr>>4)+16; + } + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]^15; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]; + } + ma++; + } + } + else if (!(cgamode&2)) + { + for (x = 0; x < 40; x++) + { + chr=vram[((ma<<1)&0x3FFF)]; + attr=vram[(((ma<<1)+1)&0x3FFF)]; + drawcursor=((ma==ca) && con && cursoron); + if (cgamode&0x20) + { + cols[1]=(attr&15)+16; + cols[0]=((attr>>4)&7)+16; + if ((cgablink&16) && (attr&0x80)) cols[1]=cols[0]; + } + else + { + cols[1]=(attr&15)+16; + cols[0]=(attr>>4)+16; + } + ma++; + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]^15; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]; + } + } + } + else if (!(cgamode&16)) + { + cols[0]=(cgacol&15)|16; + col=(cgacol&16)?24:16; + if (cgamode&4) + { + cols[1]=col|3; + cols[2]=col|4; + cols[3]=col|7; + } + else if (cgacol&32) + { + cols[1]=col|3; + cols[2]=col|5; + cols[3]=col|7; + } + else + { + cols[1]=col|2; + cols[2]=col|4; + cols[3]=col|6; + } + for (x = 0; x < 40; x++) + { + dat=(vram[((ma<<1)&0x1FFF)+((sc&1)*0x2000)]<<8)|vram[((ma<<1)&0x1FFF)+((sc&1)*0x2000)+1]; + ma++; + for (c=0;c<8;c++) + { + buffer->line[displine][(x<<4)+(c<<1)+8]= + buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[dat>>14]; + dat<<=2; + } + } + } + else + { + for (x = 0; x < 40; x++) + { + ca=((ma<<1)&0x1FFF)+((sc&1)*0x2000); + dat=(vram[ca]<<8)|vram[ca+1]; + dat2=(vram[ca+0x10000]<<8)|vram[ca+0x10001]; + dat3=(vram[ca+0x20000]<<8)|vram[ca+0x20001]; + dat4=(vram[ca+0x30000]<<8)|vram[ca+0x30001]; + + ma++; + for (c=0;c<16;c++) + { + buffer->line[displine][(x<<4)+c+8]=(((dat>>15)|((dat2>>15)<<1)|((dat3>>15)<<2)|((dat4>>15)<<3))&(cgacol&15))+16; + dat<<=1; + dat2<<=1; + dat3<<=1; + dat4<<=1; + } + } + } + } + else + { + cols[0]=((cgamode&0x12)==0x12)?0:(cgacol&15)+16; + if (cgamode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,cols[0]); + else hline(buffer,0,displine,(crtc[1]<<4)+16,cols[0]); + } + + sc=oldsc; + if (vsynctime) + cgastat|=8; + displine++; + if (displine>=360) displine=0; +// pclog("Line %i %i %i %i %i %i\n",displine,cgadispon,firstline,lastline,vc,sc); + } + else + { + vidtime+=dispontime; + if ((lastline-firstline)==199) cgadispon=0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ + if (cgadispon) cgastat&=~1; + linepos=0; + if (vsynctime) + { + vsynctime--; + if (!vsynctime) + cgastat&=~8; + } + if (sc==(crtc[11]&31)) { con=0; coff=1; } + if (vadj) + { + sc++; + sc&=31; + ma=maback; + vadj--; + if (!vadj) + { + cgadispon=1; + ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + sc=0; + } + } + else if (sc==crtc[9]) + { + maback=ma; + sc=0; + oldvc=vc; + vc++; + vc&=127; + + if (displine == 32)//oldvc == (cgamode & 2) ? 127 : 31) + { + vc=0; + vadj=6; + if ((crtc[10]&0x60)==0x20) cursoron=0; + else cursoron=cgablink&16; + } + + if (displine >= 262)//vc == (cgamode & 2) ? 111 : 27) + { + cgadispon=0; + displine=0; + vsynctime=46; + + if (cgamode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + x = 640 + 16; + lastline++; + if (x!=xsize || (lastline-firstline)!=ysize) + { + xsize=x; + ysize=lastline-firstline; + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + updatewindowsize(xsize,(ysize<<1)+16); + } +startblit(); + video_blit_memtoscreen_8(0, firstline - 4, xsize, (lastline - firstline) + 8); +// blit(buffer,vbuf,0,firstline-4,0,0,xsize,(lastline-firstline)+8+1); +// if (vid_resize) stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,winsizex,winsizey); +// else stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,xsize,((lastline-firstline)<<1)+16+2); +// if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); +// readflash=0; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (cgamode & 1) + { + video_res_x /= 8; + video_res_y /= crtc[9] + 1; + video_bpp = 0; + } + else if (!(cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= crtc[9] + 1; + video_bpp = 0; + } + else if (!(cgamode&16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 4; + } + + firstline=1000; + lastline=0; + cgablink++; + } + } + else + { + sc++; + sc&=31; + ma=maback; + } + if (sc==(crtc[10]&31)) con=1; + } +} + +int pc1512_init() +{ + mem_sethandler(0xb8000, 0x08000, pc1512_read, NULL, NULL, pc1512_write, NULL, NULL); + return 0; +} + +GFXCARD vid_pc1512 = +{ + pc1512_init, + /*IO at 3Cx/3Dx*/ + pc1512_out, + pc1512_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + pc1512_poll, + pc1512_recalctimings, + + video_write_null, + video_write_null, + pc1512_write, + + video_read_null, + video_read_null, + pc1512_read +}; diff --git a/src/vid_pc1640.c b/src/vid_pc1640.c new file mode 100644 index 00000000..8aff1ea4 --- /dev/null +++ b/src/vid_pc1640.c @@ -0,0 +1,97 @@ +/*PC1640 video emulation. + Mostly standard EGA, but with CGA & Hercules emulation*/ +#include "ibm.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_ega.h" + +static int pc1640_cga=1; + +void pc1640_out(uint16_t addr, uint8_t val) +{ + switch (addr) + { + case 0x3DB: + pc1640_cga=val&0x40; + mem_removehandler(0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL); + mem_removehandler(0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL); + if (pc1640_cga) + mem_sethandler(0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL); + else + { + switch (gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, ega_read, NULL, NULL, ega_write, NULL, NULL); + break; + } + } + pclog("3DB write %02X\n", val); + return; + } + if (pc1640_cga) cga_out(addr,val); + else ega_out(addr,val); +} + +uint8_t pc1640_in(uint16_t addr) +{ + switch (addr) + { + } + if (pc1640_cga) return cga_in(addr); + else return ega_in(addr); +} + +void pc1640_recalctimings() +{ + if (pc1640_cga) cga_recalctimings(); + else ega_recalctimings(); +} + +void pc1640_poll() +{ + if (pc1640_cga) cga_poll(); + else ega_poll(); +} + +int pc1640_init() +{ + int r = ega_init(); + + pc1640_cga = 1; + + mem_sethandler(0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL); + + return r; +} + +GFXCARD vid_pc1640 = +{ + pc1640_init, + /*IO at 3Cx/3Dx*/ + pc1640_out, + pc1640_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + pc1640_poll, + pc1640_recalctimings, + + ega_write, + video_write_null, + video_write_null, + + ega_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_pc200.c b/src/vid_pc200.c new file mode 100644 index 00000000..bf29121c --- /dev/null +++ b/src/vid_pc200.c @@ -0,0 +1,102 @@ +/*PC200 video emulation. + CGA with some NMI stuff. But we don't need that as it's only used for TV and + LCD displays, and we're emulating a CRT*/ +#include "ibm.h" +#include "video.h" +#include "vid_cga.h" + +uint8_t pc200_3dd, pc200_3de, pc200_3df; + +void pc200_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + switch (addr) + { + case 0x3D5: + if (!(pc200_3de&0x40) && crtcreg<=11) + { + if (pc200_3de&0x80) nmi=1; + pc200_3dd=0x20|(crtcreg&0x1F); + pc200_3df=val; + return; + } + old=crtc[crtcreg]; + crtc[crtcreg]=val&crtcmask[crtcreg]; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + cga_recalctimings(); + } + } + return; + + case 0x3D8: + old = cgamode; + cgamode=val; + if ((cgamode ^ old) & 3) + cga_recalctimings(); + pc200_3dd|=0x80; + if (pc200_3de&0x80) + nmi=1; + return; + + case 0x3DE: + pc200_3de=val; + pc200_3dd=0x1F; + if (val&0x80) pc200_3dd|=0x40; + return; + } + cga_out(addr,val); +} + +uint8_t pc200_in(uint16_t addr) +{ + uint8_t temp; + switch (addr) + { + case 0x3D8: + return cgamode; + + case 0x3DD: + temp = pc200_3dd; + pc200_3dd &= 0x1F; + return temp; + + case 0x3DE: + return (pc200_3de&0xC7)| 0x18; /*External CGA*/ + + case 0x3DF: + return pc200_3df; + } + return cga_in(addr); +} + +int pc200_init() +{ + mem_sethandler(0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL); + return cga_init(); +} + +GFXCARD vid_pc200 = +{ + pc200_init, + /*IO at 3Cx/3Dx*/ + pc200_out, + pc200_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + cga_poll, + cga_recalctimings, + + video_write_null, + video_write_null, + cga_write, + + video_read_null, + video_read_null, + cga_read +}; diff --git a/src/vid_s3.c b/src/vid_s3.c new file mode 100644 index 00000000..cd3ae4dd --- /dev/null +++ b/src/vid_s3.c @@ -0,0 +1,1533 @@ +/*S3 emulation*/ +#include "ibm.h" +#include "mem.h" +#include "pci.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +void s3_updatemapping(); + +void s3_accel_write(uint32_t addr, uint8_t val); +void s3_accel_write_w(uint32_t addr, uint16_t val); +void s3_accel_write_l(uint32_t addr, uint32_t val); +uint8_t s3_accel_read(uint32_t addr); + +static uint8_t s3_bank; +static uint8_t s3_ma_ext; +static int s3_width = 1024; +static int s3_bpp = 0; + +static uint8_t s3_id, s3_id_ext; + +void s3_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// pclog("S3 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3c5: + if (seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); + sdac_ramdac_out(addr,val); + return; + + case 0x3D4: + crtcreg=val&0x7f; + return; + case 0x3D5: +// if (crtcreg == 0x67) pclog("Write CRTC R%02X %02X\n", crtcreg, val); + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + if (crtcreg >= 0x20 && crtcreg != 0x38 && (crtc[0x38] & 0xcc) != 0x48) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + switch (crtcreg) + { + case 0x31: + s3_ma_ext = (s3_ma_ext & 0x1c) | ((val & 0x30) >> 4); + vrammask = (val & 8) ? 0x3fffff : 0x3ffff; + break; + + case 0x50: + switch (crtc[0x50] & 0xc1) + { + case 0x00: s3_width = (crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3_width = 1152; break; + case 0x40: s3_width = 640; break; + case 0x80: s3_width = 800; break; + case 0x81: s3_width = 1600; break; + case 0xc0: s3_width = 1280; break; + } + s3_bpp = (crtc[0x50] >> 4) & 3; + break; + case 0x69: + s3_ma_ext = val & 0x1f; + break; + + case 0x35: + s3_bank = (s3_bank & 0x70) | (val & 0xf); +// pclog("CRTC write R35 %02X\n", val); + if (chain4) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + break; + case 0x51: + s3_bank = (s3_bank & 0x4f) | ((val & 0xc) << 2); + if (chain4) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + s3_ma_ext = (s3_ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + s3_bank = val; +// pclog("CRTC write R6a %02X\n", val); + if (chain4) svgawbank = svgarbank = s3_bank << 16; + else svgawbank = svgarbank = s3_bank << 14; + break; + + case 0x3a: + if (val & 0x10) gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga_hwcursor.ena = val & 1; + break; + case 0x48: + svga_hwcursor.x = ((crtc[0x46] << 8) | crtc[0x47]) & 0x7ff; + if (bpp == 32) svga_hwcursor.x >>= 1; + svga_hwcursor.y = ((crtc[0x48] << 8) | crtc[0x49]) & 0x7ff; + svga_hwcursor.xoff = crtc[0x4e] & 63; + svga_hwcursor.yoff = crtc[0x4f] & 63; + svga_hwcursor.addr = ((((crtc[0x4c] << 8) | crtc[0x4d]) & 0xfff) * 1024) + (svga_hwcursor.yoff * 16); + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_updatemapping(); + break; + + case 0x67: + if (gfxcard == GFX_N9_9FX) /*Trio64*/ + { + switch (val >> 4) + { + case 3: bpp = 15; break; + case 5: bpp = 16; break; + case 7: bpp = 24; break; + case 13: bpp = 32; break; + default: bpp = 8; break; + } + } + break; + //case 0x55: case 0x43: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + } + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + break; + } + svga_out(addr,val); +} + +uint8_t s3_in(uint16_t addr) +{ + uint8_t temp; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + +// if (addr != 0x3da) pclog("S3 in %04X\n", addr); + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); + return sdac_ramdac_in(addr); + + case 0x3D4: + return crtcreg; + case 0x3D5: +// pclog("Read CRTC R%02X %04X:%04X\n", crtcreg, CS, pc); + switch (crtcreg) + { + case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2e: return s3_id_ext; /*New chip ID*/ + case 0x30: return s3_id; /*Chip ID*/ + case 0x31: return (crtc[0x31] & 0xcf) | ((s3_ma_ext & 3) << 4); + case 0x35: return (crtc[0x35] & 0xf0) | (s3_bank & 0xf); + case 0x51: return (crtc[0x51] & 0xf0) | ((s3_bank >> 2) & 0xc) | ((s3_ma_ext >> 2) & 3); + case 0x69: return s3_ma_ext; + case 0x6a: return s3_bank; + } + return crtc[crtcreg]; + } + return svga_in(addr); +} + +void s3_recalctimings() +{ +// pclog("recalctimings\n"); + svga_ma |= (s3_ma_ext << 16); +// pclog("SVGA_MA %08X\n", svga_ma); + if (gdcreg[5] & 0x40) svga_lowres = !(crtc[0x3a] & 0x10); + if (crtc[0x5d] & 0x01) svga_htotal += 0x100; + if (crtc[0x5d] & 0x02) svga_hdisp += 0x100; + if (crtc[0x5e] & 0x01) svga_vtotal += 0x400; + if (crtc[0x5e] & 0x02) svga_dispend += 0x400; + if (crtc[0x5e] & 0x10) svga_vsyncstart += 0x400; + if (crtc[0x5e] & 0x40) svga_split += 0x400; + if (crtc[0x51] & 0x30) svga_rowoffset += (crtc[0x51] & 0x30) << 4; + else if (crtc[0x43] & 0x04) svga_rowoffset += 0x100; + if (!svga_rowoffset) svga_rowoffset = 256; + svga_interlace = crtc[0x42] & 0x20; + svga_clock = cpuclock / sdac_getclock((svga_miscout >> 2) & 3); +// pclog("SVGA_CLOCK = %f %02X %f\n", svga_clock, svga_miscout, cpuclock); + if (bpp > 8) svga_clock /= 2; +} + +static uint32_t s3_linear_base = 0, s3_linear_size = 0; +void s3_updatemapping() +{ + mem_removehandler(s3_linear_base, s3_linear_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + +// video_write_a000_w = video_write_a000_l = NULL; + + mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); +// pclog("Update mapping - bank %02X ", gdcreg[6] & 0xc); + switch (gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + } + +// pclog("Linear framebuffer %02X ", crtc[0x58] & 0x10); + if (crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + s3_linear_base = (crtc[0x5a] << 16) | (crtc[0x59] << 24); + switch (crtc[0x58] & 3) + { + case 0: /*64k*/ + s3_linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3_linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3_linear_size = 0x200000; + break; + case 3: /*8mb*/ + s3_linear_size = 0x800000; + break; + } + s3_linear_base &= ~(s3_linear_size - 1); +// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); +// pclog("Linear framebuffer at %08X size %08X\n", linear_base, linear_size); + if (s3_linear_base == 0xa0000) + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + else + mem_sethandler(s3_linear_base, s3_linear_size, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + } + +// pclog("Memory mapped IO %02X\n", crtc[0x53] & 0x10); + if (crtc[0x53] & 0x10) /*Memory mapped IO*/ + { + mem_sethandler(0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l); +/* video_write_a000 = s3_accel_write; + video_write_a000_w = s3_accel_write_w; + video_write_a000_l = s3_accel_write_l; + video_read_a000 = s3_accel_read;*/ + } +} + + +struct +{ + uint8_t subsys_cntl; + uint8_t setup_md; + uint8_t advfunc_cntl; + uint16_t cur_y; + uint16_t cur_x; + int16_t desty_axstp; + int16_t destx_distp; + int16_t err_term; + int16_t maj_axis_pcnt; + uint16_t cmd; + uint16_t short_stroke; + uint32_t bkgd_color; + uint32_t frgd_color; + uint32_t wrt_mask; + uint32_t rd_mask; + uint32_t color_cmp; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + uint8_t pix_trans[4]; + + int cx, cy; + int sx, sy; + int dx, dy; + uint32_t src, dest, pattern; + int pix_trans_count; + + uint32_t dat_buf; + int dat_count; +} s3_accel; + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat); + +void s3_accel_out(uint16_t port, uint8_t val) +{ +// pclog("Accel out %04X %02X\n", port, val); + switch (port) + { + case 0x42e8: + break; + case 0x42e9: + s3_accel.subsys_cntl = val; + break; + case 0x46e8: + s3_accel.setup_md = val; + break; + case 0x4ae8: + s3_accel.advfunc_cntl = val; + break; + + case 0x82e8: + s3_accel.cur_y = (s3_accel.cur_y & 0xf00) | val; + break; + case 0x82e9: + s3_accel.cur_y = (s3_accel.cur_y & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x86e8: + s3_accel.cur_x = (s3_accel.cur_x & 0xf00) | val; + break; + case 0x86e9: + s3_accel.cur_x = (s3_accel.cur_x & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x8ae8: + s3_accel.desty_axstp = (s3_accel.desty_axstp & 0x3f00) | val; + break; + case 0x8ae9: + s3_accel.desty_axstp = (s3_accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3_accel.desty_axstp |= ~0x3fff; + break; + + case 0x8ee8: + s3_accel.destx_distp = (s3_accel.destx_distp & 0x3f00) | val; + break; + case 0x8ee9: + s3_accel.destx_distp = (s3_accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3_accel.destx_distp |= ~0x3fff; + break; + + case 0x92e8: + s3_accel.err_term = (s3_accel.err_term & 0x3f00) | val; + break; + case 0x92e9: + s3_accel.err_term = (s3_accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3_accel.err_term |= ~0x3fff; + break; + + case 0x96e8: + s3_accel.maj_axis_pcnt = (s3_accel.maj_axis_pcnt & 0x3f00) | val; + break; + case 0x96e9: + s3_accel.maj_axis_pcnt = (s3_accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3_accel.maj_axis_pcnt |= ~0x0fff; + break; + + case 0x9ae8: + s3_accel.cmd = (s3_accel.cmd & 0xff00) | val; + break; + case 0x9ae9: + s3_accel.cmd = (s3_accel.cmd & 0xff) | (val << 8); + s3_accel_start(-1, 0, 0xffffffff, 0); + s3_accel.pix_trans_count = 0; + break; + + case 0x9ee8: + s3_accel.short_stroke = (s3_accel.short_stroke & 0xff00) | val; + break; + case 0x9ee9: + s3_accel.short_stroke = (s3_accel.short_stroke & 0xff) | (val << 8); + break; + + case 0xa2e8: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.bkgd_color = (s3_accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3_accel.bkgd_color = (s3_accel.bkgd_color & ~0x000000ff) | val; + break; + case 0xa2e9: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.bkgd_color = (s3_accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3_accel.bkgd_color = (s3_accel.bkgd_color & ~0x0000ff00) | (val << 8); + s3_accel.multifunc[0xe] ^= 0x10; + break; + + case 0xa6e8: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.frgd_color = (s3_accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3_accel.frgd_color = (s3_accel.frgd_color & ~0x000000ff) | val; +// pclog("Foreground colour now %08X %i\n", s3_accel.frgd_color, s3_bpp); + break; + case 0xa6e9: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.frgd_color = (s3_accel.frgd_color & ~0xff000000) | (val << 24); + else + s3_accel.frgd_color = (s3_accel.frgd_color & ~0x0000ff00) | (val << 8); + s3_accel.multifunc[0xe] ^= 0x10; +// pclog("Foreground colour now %08X\n", s3_accel.frgd_color); + break; + + case 0xaae8: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.wrt_mask = (s3_accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3_accel.wrt_mask = (s3_accel.wrt_mask & ~0x000000ff) | val; + break; + case 0xaae9: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.wrt_mask = (s3_accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3_accel.wrt_mask = (s3_accel.wrt_mask & ~0x0000ff00) | (val << 8); + s3_accel.multifunc[0xe] ^= 0x10; + break; + + case 0xaee8: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.rd_mask = (s3_accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3_accel.rd_mask = (s3_accel.rd_mask & ~0x000000ff) | val; + break; + case 0xaee9: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.rd_mask = (s3_accel.rd_mask & ~0xff000000) | (val << 24); + else + s3_accel.rd_mask = (s3_accel.rd_mask & ~0x0000ff00) | (val << 8); + s3_accel.multifunc[0xe] ^= 0x10; + break; + + case 0xb2e8: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.color_cmp = (s3_accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3_accel.color_cmp = (s3_accel.color_cmp & ~0x000000ff) | val; + break; + case 0xb2e9: + if (s3_bpp == 3 && s3_accel.multifunc[0xe] & 0x10) + s3_accel.color_cmp = (s3_accel.color_cmp & ~0xff000000) | (val << 24); + else + s3_accel.color_cmp = (s3_accel.color_cmp & ~0x0000ff00) | (val << 8); + s3_accel.multifunc[0xe] ^= 0x10; + break; + + case 0xb6e8: + s3_accel.bkgd_mix = val; + break; + + case 0xbae8: + s3_accel.frgd_mix = val; + break; + + case 0xbee8: + s3_accel.multifunc_cntl = (s3_accel.multifunc_cntl & 0xff00) | val; + break; + case 0xbee9: + s3_accel.multifunc_cntl = (s3_accel.multifunc_cntl & 0xff) | (val << 8); + s3_accel.multifunc[s3_accel.multifunc_cntl >> 12] = s3_accel.multifunc_cntl & 0xfff; + break; + + case 0xe2e8: + s3_accel.pix_trans[0] = val; + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3_accel.cmd & 0x600) && (s3_accel.cmd & 0x100)) + s3_accel_start(8, 1, s3_accel.pix_trans[0], 0); + else if (!(s3_accel.cmd & 0x600) && (s3_accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, s3_accel.pix_trans[0]); + break; + case 0xe2e9: + s3_accel.pix_trans[1] = val; + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80 && (s3_accel.cmd & 0x600) == 0x200 && (s3_accel.cmd & 0x100)) + { + if (s3_accel.cmd & 0x1000) s3_accel_start(16, 1, s3_accel.pix_trans[1] | (s3_accel.pix_trans[0] << 8), 0); + else s3_accel_start(16, 1, s3_accel.pix_trans[0] | (s3_accel.pix_trans[1] << 8), 0); + } + else if ((s3_accel.cmd & 0x600) == 0x200 && (s3_accel.cmd & 0x100)) + { + if (s3_accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3_accel.pix_trans[1] | (s3_accel.pix_trans[0] << 8)); + else s3_accel_start(2, 1, 0xffffffff, s3_accel.pix_trans[0] | (s3_accel.pix_trans[1] << 8)); + } + break; + case 0xe2ea: + s3_accel.pix_trans[2] = val; + break; + case 0xe2eb: + s3_accel.pix_trans[3] = val; + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80 && (s3_accel.cmd & 0x600) == 0x400 && (s3_accel.cmd & 0x100)) + s3_accel_start(32, 1, s3_accel.pix_trans[0] | (s3_accel.pix_trans[1] << 8) | (s3_accel.pix_trans[2] << 16) | (s3_accel.pix_trans[3] << 24), 0); + else if ((s3_accel.cmd & 0x600) == 0x400 && (s3_accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, s3_accel.pix_trans[0] | (s3_accel.pix_trans[1] << 8) | (s3_accel.pix_trans[2] << 16) | (s3_accel.pix_trans[3] << 24)); + break; + } +} + +void s3_accel_out_w(uint16_t port, uint16_t val) +{ +// pclog("Accel out w %04X %04X\n", port, val); + if (s3_accel.cmd & 0x100) + { + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3_accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0); + } + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16)); + } +} + +void s3_accel_out_l(uint16_t port, uint32_t val) +{ +// pclog("Accel out l %04X %08X\n", port, val); + if (s3_accel.cmd & 0x100) + { + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3_accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + if ((s3_accel.cmd & 0x600) == 0x400) + s3_accel_start(32, 1, val, 0); + else if ((s3_accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, val >> 16, 0); + s3_accel_start(16, 1, val, 0); + } + else if (!(s3_accel.cmd & 0x600)) + { + s3_accel_start(8, 1, val >> 24, 0); + s3_accel_start(8, 1, val >> 16, 0); + s3_accel_start(8, 1, val >> 8, 0); + s3_accel_start(8, 1, val, 0); + } + } + else + { + if ((s3_accel.cmd & 0x600) == 0x400) + s3_accel_start(4, 1, 0xffffffff, val); + else if ((s3_accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val >> 16); + s3_accel_start(2, 1, 0xffffffff, val); + } + else if (!(s3_accel.cmd & 0x600)) + { + s3_accel_start(1, 1, 0xffffffff, val >> 24); + s3_accel_start(1, 1, 0xffffffff, val >> 16); + s3_accel_start(1, 1, 0xffffffff, val >> 8); + s3_accel_start(1, 1, 0xffffffff, val); + } + } + } +} + +uint8_t s3_accel_in(uint16_t port) +{ + int temp; +// pclog("Accel in %04X\n", port); + switch (port) + { + case 0x42e8: + return 0; + case 0x42e9: + return 0; + + case 0x82e8: + return s3_accel.cur_y & 0xff; + case 0x82e9: + return s3_accel.cur_y >> 8; + + case 0x86e8: + return s3_accel.cur_x & 0xff; + case 0x86e9: + return s3_accel.cur_x >> 8; + + case 0x8ae8: + return s3_accel.desty_axstp & 0xff; + case 0x8ae9: + return s3_accel.desty_axstp >> 8; + + case 0x8ee8: + return s3_accel.destx_distp & 0xff; + case 0x8ee9: + return s3_accel.destx_distp >> 8; + + case 0x92e8: + return s3_accel.err_term & 0xff; + case 0x92e9: + return s3_accel.err_term >> 8; + + case 0x96e8: + return s3_accel.maj_axis_pcnt & 0xff; + case 0x96e9: + return s3_accel.maj_axis_pcnt >> 8; + + case 0x9ae8: + return 0; + case 0x9ae9: + return 0; + + case 0xa2e8: + return s3_accel.bkgd_color & 0xff; + case 0xa2e9: + return s3_accel.bkgd_color >> 8; + + case 0xa6e8: + return s3_accel.frgd_color & 0xff; + case 0xa6e9: + return s3_accel.frgd_color >> 8; + + case 0xaae8: + return s3_accel.wrt_mask & 0xff; + case 0xaae9: + return s3_accel.wrt_mask >> 8; + + case 0xaee8: + return s3_accel.rd_mask & 0xff; + case 0xaee9: + return s3_accel.rd_mask >> 8; + + case 0xb2e8: + return s3_accel.color_cmp & 0xff; + case 0xb2e9: + return s3_accel.color_cmp >> 8; + + case 0xb6e8: + return s3_accel.bkgd_mix; + + case 0xbae8: + return s3_accel.frgd_mix; + + case 0xbee8: + temp = s3_accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3_accel.multifunc[0x0] & 0xff; + case 0x1: return s3_accel.multifunc[0x1] & 0xff; + case 0x2: return s3_accel.multifunc[0x2] & 0xff; + case 0x3: return s3_accel.multifunc[0x3] & 0xff; + case 0x4: return s3_accel.multifunc[0x4] & 0xff; + case 0x5: return s3_accel.multifunc[0xa] & 0xff; + case 0x6: return s3_accel.multifunc[0xe] & 0xff; + case 0x7: return s3_accel.cmd & 0xff; + case 0x8: return s3_accel.subsys_cntl & 0xff; + case 0x9: return s3_accel.setup_md & 0xff; + case 0xa: return s3_accel.multifunc[0xd] & 0xff; + } + return 0xff; + case 0xbee9: + temp = s3_accel.multifunc[0xf] & 0xf; + s3_accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3_accel.multifunc[0x0] >> 8; + case 0x1: return s3_accel.multifunc[0x1] >> 8; + case 0x2: return s3_accel.multifunc[0x2] >> 8; + case 0x3: return s3_accel.multifunc[0x3] >> 8; + case 0x4: return s3_accel.multifunc[0x4] >> 8; + case 0x5: return s3_accel.multifunc[0xa] >> 8; + case 0x6: return s3_accel.multifunc[0xe] >> 8; + case 0x7: return s3_accel.cmd >> 8; + case 0x8: return (s3_accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3_accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3_accel.multifunc[0xd] >> 8; + } + return 0xff; + + case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ + break; + } + return 0; +} + +void s3_accel_write(uint32_t addr, uint8_t val) +{ +// pclog("Write S3 accel %08X %02X\n", addr, val); + if (addr & 0x8000) + s3_accel_out(addr & 0xffff, val); + else + { + if (s3_accel.cmd & 0x100) + { + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24)); + } + } +} + +void s3_accel_write_w(uint32_t addr, uint16_t val) +{ +// pclog("Write S3 accel w %08X %04X\n", addr, val); + if (addr & 0x8000) + { + s3_accel_out( addr & 0xffff, val); + s3_accel_out((addr & 0xffff) + 1, val >> 8); + } + else + { + if (s3_accel.cmd & 0x100) + { + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3_accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0); + } + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16)); + } + } +} + +void s3_accel_write_l(uint32_t addr, uint32_t val) +{ +// pclog("Write S3 accel l %08X %08X\n", addr, val); + if (addr & 0x8000) + { + s3_accel_out( addr & 0xffff, val); + s3_accel_out((addr & 0xffff) + 1, val >> 8); + s3_accel_out((addr & 0xffff) + 2, val >> 16); + s3_accel_out((addr & 0xffff) + 3, val >> 24); + } + else + { + if (s3_accel.cmd & 0x100) + { + if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3_accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + if ((s3_accel.cmd & 0x600) == 0x400) + s3_accel_start(32, 1, val, 0); + else if ((s3_accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, val >> 16, 0); + s3_accel_start(16, 1, val, 0); + } + else if (!(s3_accel.cmd & 0x600)) + { + s3_accel_start(8, 1, val >> 24, 0); + s3_accel_start(8, 1, val >> 16, 0); + s3_accel_start(8, 1, val >> 8, 0); + s3_accel_start(8, 1, val, 0); + } + } + else + { + if ((s3_accel.cmd & 0x600) == 0x400) + s3_accel_start(4, 1, 0xffffffff, val); + else if ((s3_accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val >> 16); + s3_accel_start(2, 1, 0xffffffff, val); + } + else if (!(s3_accel.cmd & 0x600)) + { + s3_accel_start(1, 1, 0xffffffff, val >> 24); + s3_accel_start(1, 1, 0xffffffff, val >> 16); + s3_accel_start(1, 1, 0xffffffff, val >> 8); + s3_accel_start(1, 1, 0xffffffff, val); + } + } + } + } +} + +uint8_t s3_accel_read(uint32_t addr) +{ +// pclog("Read S3 accel %08X\n", addr); + if (addr & 0x8000) + return s3_accel_in(addr & 0xffff); + return 0; +} + +#define READ(addr, dat) if (s3_bpp == 0) dat = vram[ (addr) & 0x3fffff]; \ + else if (s3_bpp == 1) dat = vram_w[(addr) & 0x1fffff]; \ + else dat = vram_l[(addr) & 0x0fffff]; + +#define MIX switch ((mix_dat & mix_mask) ? (s3_accel.frgd_mix & 0xf) : (s3_accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = 1; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + + +#define WRITE(addr) if (s3_bpp == 0) \ + { \ + vram[(addr) & 0x3fffff] = dest_dat; \ + changedvram[((addr) & 0x3fffff) >> 10] = changeframecount; \ + } \ + else if (s3_bpp == 1) \ + { \ + vram_w[(addr) & 0x1fffff] = dest_dat; \ + changedvram[((addr) & 0x1fffff) >> 9] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & 0xfffff] = dest_dat; \ + changedvram[((addr) & 0xfffff) >> 8] = changeframecount; \ + } + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat) +{ + uint32_t dest, destbak; + int sx, sy, cx, cy; + int x, y; + uint32_t src_dat, dest_dat; + int frgd_mix, bkgd_mix; + int mix; + int clip_t = s3_accel.multifunc[1] & 0xfff; + int clip_l = s3_accel.multifunc[2] & 0xfff; + int clip_b = s3_accel.multifunc[3] & 0xfff; + int clip_r = s3_accel.multifunc[4] & 0xfff; + int vram_mask = (s3_accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask; + uint16_t *vram_w = (uint16_t *)vram; + uint32_t *vram_l = (uint32_t *)vram; + uint32_t compare = s3_accel.color_cmp; + int compare_mode = (s3_accel.multifunc[0xe] >> 7) & 3; +//return; +// if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3_accel.cmd >> 13, s3_accel.cur_x, s3_accel.cur_y, s3_accel.maj_axis_pcnt & 0xfff, s3_accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3_accel.multifunc[0xe] & 0x20); +// else pclog(" S3 command %i, %i, %08x %08x\n", s3_accel.cmd >> 13, count, mix_dat, cpu_dat); + + if (!cpu_input) s3_accel.dat_count = 0; + if (cpu_input && (s3_accel.multifunc[0xa] & 0xc0) != 0x80) + { + if (s3_bpp == 3 && count == 2) + { + if (s3_accel.dat_count) + { + cpu_dat = (cpu_dat & 0xffff) | (s3_accel.dat_buf << 16); + count = 4; + s3_accel.dat_count = 0; + } + else + { + s3_accel.dat_buf = cpu_dat & 0xffff; + s3_accel.dat_count = 1; + } + } + if (s3_bpp == 1) count >>= 1; + if (s3_bpp == 3) count >>= 2; + } + + switch (s3_accel.cmd & 0x600) + { + case 0x000: mix_mask = 0x80; break; + case 0x200: mix_mask = 0x8000; break; + case 0x400: mix_mask = 0x80000000; break; + case 0x600: mix_mask = 0x80000000; break; + } + + if (s3_bpp == 0) compare &= 0xff; + if (s3_bpp == 1) compare &= 0xffff; + switch (s3_accel.cmd >> 13) + { + case 1: /*Draw line*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3_accel.cx = s3_accel.cur_x; + if (s3_accel.cur_x & 0x1000) s3_accel.cx |= ~0xfff; + s3_accel.cy = s3_accel.cur_y; + if (s3_accel.cur_y & 0x1000) s3_accel.cy |= ~0xfff; + + s3_accel.sy = s3_accel.maj_axis_pcnt; + } + if ((s3_accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + if (s3_accel.cmd & 8) /*Radial*/ + { + while (count-- && s3_accel.sy >= 0) + { + if (s3_accel.cx >= clip_l && s3_accel.cx <= clip_r && + s3_accel.cy >= clip_t && s3_accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3_accel.bkgd_color; break; + case 1: src_dat = s3_accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3_accel.cy * s3_width) + s3_accel.cx, dest_dat); + + MIX + + WRITE((s3_accel.cy * s3_width) + s3_accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3_bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + switch (s3_accel.cmd & 0xe0) + { + case 0x00: s3_accel.cx++; break; + case 0x20: s3_accel.cx++; s3_accel.cy--; break; + case 0x40: s3_accel.cy--; break; + case 0x60: s3_accel.cx--; s3_accel.cy--; break; + case 0x80: s3_accel.cx--; break; + case 0xa0: s3_accel.cx--; s3_accel.cy++; break; + case 0xc0: s3_accel.cy++; break; + case 0xe0: s3_accel.cx++; s3_accel.cy++; break; + } + s3_accel.sy--; + } + } + else /*Bresenham*/ + { + while (count-- && s3_accel.sy >= 0) + { + if (s3_accel.cx >= clip_l && s3_accel.cx <= clip_r && + s3_accel.cy >= clip_t && s3_accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3_accel.bkgd_color; break; + case 1: src_dat = s3_accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3_accel.cy * s3_width) + s3_accel.cx, dest_dat); + +// pclog("Line : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X (%02X %02X) ", s3_accel.cx, s3_accel.cy, s3_accel.dest + s3_accel.cx, src_dat, vram[s3_accel.src + s3_accel.cx], mix_dat & mix_mask, s3_accel.src + s3_accel.cx, dest_dat, s3_accel.frgd_color, s3_accel.bkgd_color); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE((s3_accel.cy * s3_width) + s3_accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3_bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + +// pclog("%i, %i - %i %i %i %i\n", s3_accel.cx, s3_accel.cy, s3_accel.err_term, s3_accel.maj_axis_pcnt, s3_accel.desty_axstp, s3_accel.destx_distp); + + if (s3_accel.err_term >= s3_accel.maj_axis_pcnt) + { + s3_accel.err_term += s3_accel.destx_distp; + /*Step minor axis*/ + switch (s3_accel.cmd & 0xe0) + { + case 0x00: s3_accel.cy--; break; + case 0x20: s3_accel.cy--; break; + case 0x40: s3_accel.cx--; break; + case 0x60: s3_accel.cx++; break; + case 0x80: s3_accel.cy++; break; + case 0xa0: s3_accel.cy++; break; + case 0xc0: s3_accel.cx--; break; + case 0xe0: s3_accel.cx++; break; + } + } + else + s3_accel.err_term += s3_accel.desty_axstp; + + /*Step major axis*/ + switch (s3_accel.cmd & 0xe0) + { + case 0x00: s3_accel.cx--; break; + case 0x20: s3_accel.cx++; break; + case 0x40: s3_accel.cy--; break; + case 0x60: s3_accel.cy--; break; + case 0x80: s3_accel.cx--; break; + case 0xa0: s3_accel.cx++; break; + case 0xc0: s3_accel.cy++; break; + case 0xe0: s3_accel.cy++; break; + } + s3_accel.sy--; + } + } + break; + + case 2: /*Rectangle fill*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + s3_accel.sy = s3_accel.multifunc[0] & 0xfff; + s3_accel.cx = s3_accel.cur_x; + if (s3_accel.cur_x & 0x1000) s3_accel.cx |= ~0xfff; + s3_accel.cy = s3_accel.cur_y; + if (s3_accel.cur_y & 0x1000) s3_accel.cy |= ~0xfff; + + s3_accel.dest = s3_accel.cy * s3_width; + +// pclog("Dest %08X (%i, %i) %04X %04X\n", s3_accel.dest, s3_accel.cx, s3_accel.cy, s3_accel.cur_x, s3_accel.cur_x & 0x1000); + } + if ((s3_accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + frgd_mix = (s3_accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3_accel.bkgd_mix >> 5) & 3; + + while (count-- && s3_accel.sy >= 0) + { + if (s3_accel.cx >= clip_l && s3_accel.cx <= clip_r && + s3_accel.cy >= clip_t && s3_accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3_accel.bkgd_color; break; + case 1: src_dat = s3_accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3_accel.dest + s3_accel.cx, dest_dat); + +// if (CS != 0xc000) pclog("Write %05X %02X %02X %04X (%02X %02X) ", s3_accel.dest + s3_accel.cx, src_dat, dest_dat, mix_dat, s3_accel.frgd_mix, s3_accel.bkgd_mix); + + MIX + +// if (CS != 0xc000) pclog("%02X\n", dest_dat); + + WRITE(s3_accel.dest + s3_accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3_bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3_accel.cmd & 0x20) s3_accel.cx++; + else s3_accel.cx--; + s3_accel.sx--; + if (s3_accel.sx < 0) + { + if (s3_accel.cmd & 0x20) s3_accel.cx -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + else s3_accel.cx += (s3_accel.maj_axis_pcnt & 0xfff) + 1; +// s3_accel.dest -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + +// s3_accel.dest += s3_width; + if (s3_accel.cmd & 0x80) s3_accel.cy++; + else s3_accel.cy--; + + s3_accel.dest = s3_accel.cy * s3_width; + s3_accel.sy--; + + if (cpu_input/* && (s3_accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3_accel.sy < 0) + { + return; + } + } + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + s3_accel.sy = s3_accel.multifunc[0] & 0xfff; + + s3_accel.dx = s3_accel.destx_distp & 0xfff; + if (s3_accel.destx_distp & 0x1000) s3_accel.dx |= ~0xfff; + s3_accel.dy = s3_accel.desty_axstp & 0xfff; + if (s3_accel.desty_axstp & 0x1000) s3_accel.dy |= ~0xfff; + + s3_accel.cx = s3_accel.cur_x & 0xfff; + if (s3_accel.cur_x & 0x1000) s3_accel.cx |= ~0xfff; + s3_accel.cy = s3_accel.cur_y & 0xfff; + if (s3_accel.cur_y & 0x1000) s3_accel.cy |= ~0xfff; + + s3_accel.src = s3_accel.cy * s3_width; + s3_accel.dest = s3_accel.dy * s3_width; + +// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3_accel.src, s3_accel.dest, s3_accel.cx, s3_accel.cy, s3_accel.dx, s3_accel.dy); + } + if ((s3_accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + if (s3_accel.sy < 0) + return; + + frgd_mix = (s3_accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3_accel.bkgd_mix >> 5) & 3; + + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && + (s3_accel.cmd & 0xa0) == 0xa0 && (s3_accel.frgd_mix & 0xf) == 7) + { + while (1) + { + if (s3_accel.dx >= clip_l && s3_accel.dx <= clip_r && + s3_accel.dy >= clip_t && s3_accel.dy <= clip_b) + { + READ(s3_accel.src + s3_accel.cx, src_dat); + + dest_dat = src_dat; + + WRITE(s3_accel.dest + s3_accel.dx); + } + + s3_accel.cx++; + s3_accel.dx++; + s3_accel.sx--; + if (s3_accel.sx < 0) + { + s3_accel.cx -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + s3_accel.dx -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + + s3_accel.cy++; + s3_accel.dy++; + + s3_accel.src = s3_accel.cy * s3_width; + s3_accel.dest = s3_accel.dy * s3_width; + + s3_accel.sy--; + + if (s3_accel.sy < 0) + return; + } + } + } + else + { + while (count-- && s3_accel.sy >= 0) + { + if (s3_accel.dx >= clip_l && s3_accel.dx <= clip_r && + s3_accel.dy >= clip_t && s3_accel.dy <= clip_b) + { + if (vram_mask) + { + READ(s3_accel.src + s3_accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3_accel.bkgd_color; break; + case 1: src_dat = s3_accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3_accel.src + s3_accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3_accel.dest + s3_accel.dx, dest_dat); + +// pclog("BitBlt : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3_accel.dx, s3_accel.dy, s3_accel.dest + s3_accel.dx, src_dat, vram[s3_accel.src + s3_accel.cx], mix_dat, s3_accel.src + s3_accel.cx, dest_dat); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE(s3_accel.dest + s3_accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3_bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3_accel.cmd & 0x20) + { + s3_accel.cx++; + s3_accel.dx++; + } + else + { + s3_accel.cx--; + s3_accel.dx--; + } + s3_accel.sx--; + if (s3_accel.sx < 0) + { + if (s3_accel.cmd & 0x20) + { + s3_accel.cx -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + s3_accel.dx -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3_accel.cx += (s3_accel.maj_axis_pcnt & 0xfff) + 1; + s3_accel.dx += (s3_accel.maj_axis_pcnt & 0xfff) + 1; + } + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + + if (s3_accel.cmd & 0x80) + { + s3_accel.cy++; + s3_accel.dy++; + } + else + { + s3_accel.cy--; + s3_accel.dy--; + } + + s3_accel.src = s3_accel.cy * s3_width; + s3_accel.dest = s3_accel.dy * s3_width; + + s3_accel.sy--; + + if (cpu_input/* && (s3_accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3_accel.sy < 0) + { + return; + } + } + } + } + break; + + case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + s3_accel.sy = s3_accel.multifunc[0] & 0xfff; + + s3_accel.dx = s3_accel.destx_distp & 0xfff; + if (s3_accel.destx_distp & 0x1000) s3_accel.dx |= ~0xfff; + s3_accel.dy = s3_accel.desty_axstp & 0xfff; + if (s3_accel.desty_axstp & 0x1000) s3_accel.dy |= ~0xfff; + + s3_accel.cx = s3_accel.cur_x & 0xfff; + if (s3_accel.cur_x & 0x1000) s3_accel.cx |= ~0xfff; + s3_accel.cy = s3_accel.cur_y & 0xfff; + if (s3_accel.cur_y & 0x1000) s3_accel.cy |= ~0xfff; + + /*Align source with destination*/ +// s3_accel.cx = (s3_accel.cx & ~7) | (s3_accel.dx & 7); +// s3_accel.cy = (s3_accel.cy & ~7) | (s3_accel.dy & 7); + + s3_accel.pattern = (s3_accel.cy * s3_width) + s3_accel.cx; + s3_accel.dest = s3_accel.dy * s3_width; + + s3_accel.cx = s3_accel.dx & 7; + s3_accel.cy = s3_accel.dy & 7; + + s3_accel.src = s3_accel.pattern + (s3_accel.cy * s3_width); + +// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3_accel.src, s3_accel.dest, s3_accel.cx, s3_accel.cy, s3_accel.dx, s3_accel.dy); +// dumpregs(); +// exit(-1); + } + if ((s3_accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3_accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + frgd_mix = (s3_accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3_accel.bkgd_mix >> 5) & 3; + + while (count-- && s3_accel.sy >= 0) + { + if (s3_accel.dx >= clip_l && s3_accel.dx <= clip_r && + s3_accel.dy >= clip_t && s3_accel.dy <= clip_b) + { + if (vram_mask) + { + READ(s3_accel.src + s3_accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3_accel.bkgd_color; break; + case 1: src_dat = s3_accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3_accel.src + s3_accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3_accel.dest + s3_accel.dx, dest_dat); + +// pclog("Pattern fill : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3_accel.dx, s3_accel.dy, s3_accel.dest + s3_accel.dx, src_dat, vram[s3_accel.src + s3_accel.cx], mix_dat, s3_accel.src + s3_accel.cx, dest_dat); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE(s3_accel.dest + s3_accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3_bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3_accel.cmd & 0x20) + { + s3_accel.cx = ((s3_accel.cx + 1) & 7) | (s3_accel.cx & ~7); + s3_accel.dx++; + } + else + { + s3_accel.cx = ((s3_accel.cx - 1) & 7) | (s3_accel.cx & ~7); + s3_accel.dx--; + } + s3_accel.sx--; + if (s3_accel.sx < 0) + { + if (s3_accel.cmd & 0x20) + { + s3_accel.cx = ((s3_accel.cx - ((s3_accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3_accel.cx & ~7); + s3_accel.dx -= (s3_accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3_accel.cx = ((s3_accel.cx + ((s3_accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3_accel.cx & ~7); + s3_accel.dx += (s3_accel.maj_axis_pcnt & 0xfff) + 1; + } + s3_accel.sx = s3_accel.maj_axis_pcnt & 0xfff; + + if (s3_accel.cmd & 0x80) + { + s3_accel.cy = ((s3_accel.cy + 1) & 7) | (s3_accel.cy & ~7); + s3_accel.dy++; + } + else + { + s3_accel.cy = ((s3_accel.cy - 1) & 7) | (s3_accel.cy & ~7); + s3_accel.dy--; + } + + s3_accel.src = s3_accel.pattern + (s3_accel.cy * s3_width); + s3_accel.dest = s3_accel.dy * s3_width; + + s3_accel.sy--; + + if (cpu_input/* && (s3_accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3_accel.sy < 0) + { + return; + } + } + } + break; + } +} + +void s3_hwcursor_draw(int displine) +{ + int x; + uint16_t dat[2]; + int xx; + int offset = svga_hwcursor_latch.x - svga_hwcursor_latch.xoff; + + for (x = 0; x < 64; x += 16) + { + dat[0] = (vram[svga_hwcursor_latch.addr] << 8) | vram[svga_hwcursor_latch.addr + 1]; + dat[1] = (vram[svga_hwcursor_latch.addr + 2] << 8) | vram[svga_hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga_hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga_hwcursor_latch.addr += 4; + } +} + + +uint8_t s3_pci_read(int func, int addr) +{ + pclog("S3 PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3_id_ext; + case 0x03: return 0x88; + + case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return crtc[0x5a] & 0x80; + case 0x13: return crtc[0x59]; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + } + return 0; +} + +void s3_pci_write(int func, int addr, uint8_t val) +{ + switch (addr) + { + case 0x12: crtc[0x5a] = val & 0x80; s3_updatemapping(); break; + case 0x13: crtc[0x59] = val; s3_updatemapping(); break; + } +} + +int s3_init() +{ + if (gfxcard == GFX_BAHAMAS64) + { + s3_id = 0xc1; /*Vision864P*/ + s3_id_ext = 0xc1; /*Trio64*/ + } + if (gfxcard == GFX_N9_9FX) + { + s3_id = 0xe1; + s3_id_ext = 0x11; /*Trio64*/ + } + if (gfxcard == GFX_STEALTH64) + { + s3_id = 0xe1; /*Trio64*/ + s3_id_ext = 0x11; + } + svga_recalctimings_ex = s3_recalctimings; + svga_hwcursor_draw = s3_hwcursor_draw; + + crtc[0x36] = 1 | (2 << 2) | (1 << 4) | (4 << 5); + crtc[0x37] = 1 | (7 << 5); + + vrammask = 0x3fffff; + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xa2e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xa6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xaae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xaee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xb2e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l); + + pci_add(s3_pci_read, s3_pci_write); + + svga_vram_limit = 4 << 20; /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ + return svga_init(); +} + +GFXCARD vid_s3 = +{ + s3_init, + /*IO at 3Cx/3Dx*/ + s3_out, + s3_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; + diff --git a/src/vid_sdac_ramdac.c b/src/vid_sdac_ramdac.c new file mode 100644 index 00000000..b92f60aa --- /dev/null +++ b/src/vid_sdac_ramdac.c @@ -0,0 +1,148 @@ +/*87C716 'SDAC' true colour RAMDAC emulation*/ +/*Misidentifies as AT&T 21C504*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +struct +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; +} sdac_ramdac; + +void sdac_ramdac_out(uint16_t addr, uint8_t val) +{ + int didwrite; +// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); + switch (addr) + { + case 0x3C6: + if (val == 0xff) + { + sdac_ramdac.rs2 = 0; + sdac_ramdac.magic_count = 0; + break; + } + if (sdac_ramdac.magic_count < 4) break; + if (sdac_ramdac.magic_count == 4) + { + sdac_ramdac.command = val; +// pclog("RAMDAC command reg now %02X\n", val); + switch (val >> 4) + { + case 2: case 3: case 0xa: bpp = 15; break; + case 4: case 0xe: bpp = 24; break; + case 5: case 6: case 0xc: bpp = 16; break; + case 7: bpp = 32; break; + + case 0: case 1: default: bpp = 8; break; + } + } + //sdac_ramdac.magic_count = 0; + break; + + case 0x3C7: + sdac_ramdac.magic_count = 0; + if (sdac_ramdac.rs2) + sdac_ramdac.rindex = val; + break; + case 0x3C8: + sdac_ramdac.magic_count = 0; + if (sdac_ramdac.rs2) + sdac_ramdac.windex = val; + break; + case 0x3C9: + sdac_ramdac.magic_count = 0; + if (sdac_ramdac.rs2) + { + if (!sdac_ramdac.reg_ff) sdac_ramdac.regs[sdac_ramdac.windex] = (sdac_ramdac.regs[sdac_ramdac.windex] & 0xff00) | val; + else sdac_ramdac.regs[sdac_ramdac.windex] = (sdac_ramdac.regs[sdac_ramdac.windex] & 0x00ff) | (val << 8); + sdac_ramdac.reg_ff = !sdac_ramdac.reg_ff; +// pclog("RAMDAC reg %02X now %04X\n", sdac_ramdac.windex, sdac_ramdac.regs[sdac_ramdac.windex]); + if (!sdac_ramdac.reg_ff) sdac_ramdac.windex++; + } + break; + } + svga_out(addr,val); +} + +uint8_t sdac_ramdac_in(uint16_t addr) +{ + uint8_t temp; +// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i\n",addr,CS,pc, sdac_ramdac.rs2); + switch (addr) + { + case 0x3C6: + sdac_ramdac.reg_ff = 0; + if (sdac_ramdac.magic_count < 5) + sdac_ramdac.magic_count++; + if (sdac_ramdac.magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + sdac_ramdac.rs2 = 1; + } + if (sdac_ramdac.magic_count == 5) + { + temp = sdac_ramdac.command; + sdac_ramdac.magic_count = 0; + } + return temp; + case 0x3C7: +// if (sdac_ramdac.magic_count < 4) +// { + sdac_ramdac.magic_count=0; +// break; +// } + if (sdac_ramdac.rs2) return sdac_ramdac.rindex; + break; + case 0x3C8: +// if (sdac_ramdac.magic_count < 4) +// { + sdac_ramdac.magic_count=0; +// break; +// } + if (sdac_ramdac.rs2) return sdac_ramdac.windex; + break; + case 0x3C9: +// if (sdac_ramdac.magic_count < 4) +// { + sdac_ramdac.magic_count=0; +// break; +// } + if (sdac_ramdac.rs2) + { + if (!sdac_ramdac.reg_ff) temp = sdac_ramdac.regs[sdac_ramdac.rindex] & 0xff; + else temp = sdac_ramdac.regs[sdac_ramdac.rindex] >> 8; + sdac_ramdac.reg_ff = !sdac_ramdac.reg_ff; + if (!sdac_ramdac.reg_ff) + { + sdac_ramdac.rindex++; + sdac_ramdac.magic_count = 0; + } + return temp; + } + break; + } + return svga_in(addr); +} + +float sdac_getclock(int clock) +{ + float t; + int m, n1, n2; +// pclog("SDAC_Getclock %i %04X\n", clock, sdac_ramdac.regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (sdac_ramdac.regs[clock] & 0x7f) + 2; + n1 = ((sdac_ramdac.regs[clock] >> 8) & 0x1f) + 2; + n2 = ((sdac_ramdac.regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("SDAC clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, sdac_ramdac.regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/src/vid_sdac_ramdac.h b/src/vid_sdac_ramdac.h new file mode 100644 index 00000000..391b6fa2 --- /dev/null +++ b/src/vid_sdac_ramdac.h @@ -0,0 +1,4 @@ +void sdac_ramdac_out(uint16_t addr, uint8_t val); +uint8_t sdac_ramdac_in(uint16_t addr); + +float sdac_getclock(int clock); diff --git a/src/vid_stg_ramdac.c b/src/vid_stg_ramdac.c new file mode 100644 index 00000000..f47ec76c --- /dev/null +++ b/src/vid_stg_ramdac.c @@ -0,0 +1,104 @@ +/*STG1702 true colour RAMDAC emulation*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_stg_ramdac.h" + +struct +{ + int magic_count; + uint8_t command; + int index; + uint8_t regs[256]; +} stg_ramdac; + +int stg_state_read[2][8]={{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; +int stg_state_write[8]={0,0,0,0,0,6,7,7}; + +void stg_ramdac_out(uint16_t addr, uint8_t val) +{ + int didwrite; + //if (CS!=0xC000) pclog("OUT RAMDAC %04X %02X %i %04X:%04X\n",addr,val,stg_ramdac.magic_count,CS,pc); + switch (addr) + { + case 0x3C6: + switch (stg_ramdac.magic_count) + { + case 0: case 1: case 2: case 3: break; + case 4: stg_ramdac.command=val; /*pclog("Write RAMDAC command %02X\n",val);*/ break; + case 5: stg_ramdac.index=(stg_ramdac.index&0xFF00)|val; break; + case 6: stg_ramdac.index=(stg_ramdac.index&0xFF)|(val<<8); break; + case 7: + pclog("Write RAMDAC reg %02X %02X\n", stg_ramdac.index, val); + if (stg_ramdac.index<0x100) stg_ramdac.regs[stg_ramdac.index]=val; + stg_ramdac.index++; + break; + } + didwrite = (stg_ramdac.magic_count>=4); + stg_ramdac.magic_count=stg_state_write[stg_ramdac.magic_count&7]; + if (stg_ramdac.command&8) + { + switch (stg_ramdac.regs[3]) + { + case 0: case 5: case 7: bpp=8; break; + case 1: case 2: case 8: bpp=15; break; + case 3: case 6: bpp=16; break; + case 4: case 9: bpp=24; break; + default: bpp=8; break; + } + } + else + { + switch (stg_ramdac.command>>5) + { + case 0: bpp=8; break; + case 5: bpp=15; break; + case 6: bpp=16; break; + case 7: bpp=24; break; + default: bpp=8; break; + } + } + if (didwrite) return; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + stg_ramdac.magic_count=0; + break; + } + svga_out(addr,val); +} + +uint8_t stg_ramdac_in(uint16_t addr) +{ + uint8_t temp; + //if (CS!=0xC000) pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3C6: + switch (stg_ramdac.magic_count) + { + case 0: case 1: case 2: case 3: temp=0xFF; break; + case 4: temp=stg_ramdac.command; break; + case 5: temp=stg_ramdac.index&0xFF; break; + case 6: temp=stg_ramdac.index>>8; break; + case 7: +// pclog("Read RAMDAC index %04X\n",stg_ramdac.index); + switch (stg_ramdac.index) + { + case 0: temp=0x44; break; + case 1: temp=0x02; break; + default: + if (stg_ramdac.index<0x100) temp=stg_ramdac.regs[stg_ramdac.index]; + else temp=0xFF; + break; + } + stg_ramdac.index++; + break; + } + stg_ramdac.magic_count=stg_state_read[(stg_ramdac.command&0x10)?1:0][stg_ramdac.magic_count&7]; + return temp; + case 0x3C8: case 0x3C9: + stg_ramdac.magic_count=0; + break; + } + return svga_in(addr); +} diff --git a/src/vid_stg_ramdac.h b/src/vid_stg_ramdac.h new file mode 100644 index 00000000..84d9cf77 --- /dev/null +++ b/src/vid_stg_ramdac.h @@ -0,0 +1,2 @@ +void stg_ramdac_out(uint16_t addr, uint8_t val); +uint8_t stg_ramdac_in(uint16_t addr); diff --git a/src/vid_svga.c b/src/vid_svga.c new file mode 100644 index 00000000..4571c2e6 --- /dev/null +++ b/src/vid_svga.c @@ -0,0 +1,1392 @@ +/*Generic SVGA handling*/ +/*This is intended to be used by another SVGA driver, and not as a card in it's own right*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "io.h" + +uint32_t svga_vram_limit; + +extern uint8_t edatlookup[4][4]; +uint8_t svga_miscout; + +static uint8_t la, lb, lc, ld; +static uint8_t svga_rotate[8][256]; + +static int svga_fast; + +void svga_out(uint16_t addr, uint8_t val) +{ + int c; + uint8_t o; + //printf("OUT SVGA %03X %02X %04X:%04X %i %08X\n",addr,val,CS,pc,TRIDENT,svgawbank); + switch (addr) + { + case 0x3C0: + if (!attrff) + attraddr=val&31; + else + { + attrregs[attraddr&31]=val; + if (attraddr<16) fullchange=changeframecount; + if (attraddr==0x10 || attraddr==0x14 || attraddr<0x10) + { + for (c=0;c<16;c++) + { + if (attrregs[0x10]&0x80) egapal[c]=(attrregs[c]&0xF)|((attrregs[0x14]&0xF)<<4); + else egapal[c]=(attrregs[c]&0x3F)|((attrregs[0x14]&0xC)<<4); + } + } + if (attraddr == 0x10) svga_recalctimings(); + } + attrff^=1; + break; + case 0x3C2: + svga_miscout = val; + vres = 0; pallook = pallook256; + vidclock = val & 4; printf("3C2 write %02X\n",val); + if (val&1) + io_sethandler(0x03a0, 0x0020, video_in, NULL, NULL, video_out, NULL, NULL); + else + io_sethandler(0x03a0, 0x0020, video_in_null, NULL, NULL, video_out_null, NULL, NULL); + break; + case 0x3C4: seqaddr=val; break; + case 0x3C5: + if (seqaddr > 0xf) return; + o=seqregs[seqaddr&0xF]; + seqregs[seqaddr&0xF]=val; + if (o!=val && (seqaddr&0xF)==1) svga_recalctimings(); + switch (seqaddr&0xF) + { + case 1: if (scrblank && !(val&0x20)) fullchange=3; scrblank=(scrblank&~0x20)|(val&0x20); break; + case 2: writemask=val&0xF; break; + case 3: + charset=val&0xF; + charseta=((charset>>2)*0x10000)+2; + charsetb=((charset&3) *0x10000)+2; + break; + case 4: + chain4=val&8; /*printf("Chain4 %i %02X\n",val&8,gdcreg[5]&0x60); */ + svga_fast = (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1]) && chain4; + break; + } + break; + case 0x3C7: dacread=val; dacpos=0; break; + case 0x3C8: dacwrite=val; dacpos=0; break; + case 0x3C9: + palchange=1; + fullchange=changeframecount; + switch (dacpos) + { + case 0: vgapal[dacwrite].r=val&63; pallook256[dacwrite]=makecol32(vgapal[dacwrite].r*4,vgapal[dacwrite].g*4,vgapal[dacwrite].b*4); dacpos++; break; + case 1: vgapal[dacwrite].g=val&63; pallook256[dacwrite]=makecol32(vgapal[dacwrite].r*4,vgapal[dacwrite].g*4,vgapal[dacwrite].b*4); dacpos++; break; + case 2: vgapal[dacwrite].b=val&63; pallook256[dacwrite]=makecol32(vgapal[dacwrite].r*4,vgapal[dacwrite].g*4,vgapal[dacwrite].b*4); dacpos=0; dacwrite=(dacwrite+1)&255; break; + } + break; + case 0x3CE: gdcaddr=val; break; + case 0x3CF: + switch (gdcaddr&15) + { + case 2: colourcompare=val; break; + case 4: readplane=val&3; break; + case 5: writemode=val&3; readmode=val&8; break; + case 6: + if ((gdcreg[6] & 0xc) != (val & 0xc)) + { + mem_removehandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_sethandler(0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x4: /*64k at A0000*/ + mem_sethandler(0xa0000, 0x10000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0x8: /*32k at B0000*/ + mem_sethandler(0xb0000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + case 0xC: /*32k at B8000*/ + mem_sethandler(0xb8000, 0x08000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + break; + } + } + break; + case 7: colournocare=val; break; + } + gdcreg[gdcaddr&15]=val; + svga_fast = (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1]) && chain4; + break; + } +} + +uint8_t svga_in(uint16_t addr) +{ + uint8_t temp; +// if (addr!=0x3da) pclog("Read port %04X\n",addr); + switch (addr) + { + case 0x3C0: return attraddr; + case 0x3C1: return attrregs[attraddr]; + case 0x3C2: return 0x10; + case 0x3C4: return seqaddr; + case 0x3C5: + return seqregs[seqaddr&0xF]; + case 0x3C8: return dacwrite; + case 0x3C9: + palchange=1; + switch (dacpos) + { + case 0: dacpos++; return vgapal[dacread].r; + case 1: dacpos++; return vgapal[dacread].g; + case 2: dacpos=0; dacread=(dacread+1)&255; return vgapal[(dacread-1)&255].b; + } + break; + case 0x3CC: return svga_miscout; + case 0x3CE: return gdcaddr; + case 0x3CF: + return gdcreg[gdcaddr&0xF]; + case 0x3DA: + attrff=0; + cgastat^=0x30; + return cgastat; + } +// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc); + return 0xFF; +} + +int svga_vtotal, svga_dispend, svga_vsyncstart, svga_split; +int svga_hdisp, svga_htotal, svga_rowoffset; +int svga_lowres, svga_interlace; +double svga_clock; +uint32_t svga_ma; +void (*svga_recalctimings_ex)() = NULL; +void (*svga_hwcursor_draw)(int displine) = NULL; + +void svga_recalctimings() +{ + double crtcconst; + int temp; + svga_vtotal=crtc[6]; + svga_dispend=crtc[0x12]; + svga_vsyncstart=crtc[0x10]; + svga_split=crtc[0x18]; + + if (crtc[7]&1) svga_vtotal|=0x100; + if (crtc[7]&32) svga_vtotal|=0x200; + svga_vtotal+=2; + + + if (crtc[7]&2) svga_dispend|=0x100; + if (crtc[7]&64) svga_dispend|=0x200; + svga_dispend++; + + if (crtc[7]&4) svga_vsyncstart|=0x100; + if (crtc[7]&128) svga_vsyncstart|=0x200; + svga_vsyncstart++; + + if (crtc[7]&0x10) svga_split|=0x100; + if (crtc[9]&0x40) svga_split|=0x200; + svga_split++; + + svga_hdisp=crtc[1]; + svga_hdisp++; + + svga_htotal=crtc[0]; + svga_htotal+=6; /*+6 is required for Tyrian*/ + + svga_rowoffset=crtc[0x13]; + + svga_clock = (vidclock) ? VGACONST2 : VGACONST1; + + svga_lowres = attrregs[0x10]&0x40; + + svga_interlace = 0; + + svga_ma = (crtc[0xC]<<8)|crtc[0xD]; + + if (svga_recalctimings_ex) svga_recalctimings_ex(); + + crtcconst=(seqregs[1]&1)?(svga_clock*8.0):(svga_clock*9.0); + + disptime =svga_htotal; + dispontime=svga_hdisp; + +// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); + if (seqregs[1]&8) { disptime*=2; dispontime*=2; } + dispofftime=disptime-dispontime; + dispontime*=crtcconst; + dispofftime*=crtcconst; + +// printf("SVGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4)); +// printf("SVGA vert total %i display end %i max row %i vsync %i\n",svga_vtotal,svga_dispend,(crtc[9]&31)+1,svga_vsyncstart); +// printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*svga_vtotal,(dispontime+dispofftime)*svga_vtotal*70,seqregs[1]); +} + + +static uint32_t ma,maback,ca; +static int vc,sc; +static int linepos, displine, vslines, linecountff, oddeven; +static int svga_dispon; +static int con, coff, cursoron, cgablink; +static int scrollcache; + +int svga_hwcursor_on; + +SVGA_HWCURSOR svga_hwcursor, svga_hwcursor_latch; + +int svga_hdisp_on; + +static int firstline_draw = 2000, lastline_draw = 0; + +void svga_poll() +{ + uint8_t chr,dat,attr; + uint32_t charaddr; + int x,xx; + uint32_t fg,bg; + int offset; + uint8_t edat[4]; + int drawcursor=0; + if (!linepos) + { +// if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount()); + if (displine == svga_hwcursor_latch.y && svga_hwcursor_latch.ena) + svga_hwcursor_on = 64 - svga_hwcursor_latch.yoff; + vidtime+=dispofftime; +// if (output) printf("Display off %f\n",vidtime); + cgastat|=1; + linepos=1; + + if (svga_dispon) + { + svga_hdisp_on=1; + + ma&=vrammask; + if (firstline==2000) firstline=displine; + if (scrblank) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + for (x=0;xline[displine])[(x*9)+xx+32]=0; + break; + case 1: + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[(x*8)+xx+32]=0; + break; + case 8: + for (xx=0;xx<18;xx++) ((uint32_t *)buffer32->line[displine])[(x*18)+xx+32]=0; + break; + case 9: + for (xx=0;xx<16;xx++) ((uint32_t *)buffer32->line[displine])[(x*16)+xx+32]=0; + break; + } + } + } + else if (!(gdcreg[6]&1)) /*Text mode*/ + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + if (fullchange) + { + for (x=0;x>4]]; } + else + { + fg=pallook[egapal[attr&15]]; + bg=pallook[egapal[attr>>4]]; + if (attr&0x80 && attrregs[0x10]&8) + { + bg=pallook[egapal[(attr>>4)&7]]; + if (cgablink&16) fg=bg; + } + } + + dat=vram[charaddr+(sc<<2)]; + if (seqregs[1]&8) /*40 column*/ + { + if (seqregs[1]&1) { for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x<<4)+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[((x<<4)+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; } + else + { + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x*18)+32+(xx<<1))&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+33+(xx<<1))&2047]=(dat&(0x80>>xx))?fg:bg; + if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) ((uint32_t *)buffer32->line[displine])[((x*18)+32+16)&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+32+17)&2047]=bg; + else ((uint32_t *)buffer32->line[displine])[((x*18)+32+16)&2047]=((uint32_t *)buffer32->line[displine])[((x*18)+32+17)&2047]=(dat&1)?fg:bg; + } + } + else /*80 column*/ + { + if (seqregs[1]&1) { for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x<<3)+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; } + else + { + for (xx=0;xx<8;xx++) ((uint32_t *)buffer32->line[displine])[((x*9)+32+xx)&2047]=(dat&(0x80>>xx))?fg:bg; + if ((chr&~0x1F)!=0xC0 || !(attrregs[0x10]&4)) ((uint32_t *)buffer32->line[displine])[((x*9)+32+8)&2047]=bg; + else ((uint32_t *)buffer32->line[displine])[((x*9)+32+8)&2047]=(dat&1)?fg:bg; + } + } + ma+=4; ma&=vrammask; + } + } + } + else + { +// if (hwcursor_on) changedvram[ma>>10]=changedvram[(ma>>10)+1]=2; + switch (gdcreg[5]&0x60) + { + case 0x00: /*16 colours*/ + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + if (seqregs[1]&8) /*Low res (320)*/ + { + offset=((8-scrollcache)<<1)+16; + for (x=0;x<=svga_hdisp;x++) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + + dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+14+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+15+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+12+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+13+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+10+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+11+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+8+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+9+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+7+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+5+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+3+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+1+offset]=pallook[egapal[dat>>4]]; + } + } + else /*High res (640)*/ + { + offset=(8-scrollcache)+24; + for (x=0;x<=svga_hdisp;x++) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + + dat=edatlookup[edat[0]&3][edat[1]&3]|(edatlookup[edat[2]&3][edat[3]&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+7+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+6+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+5+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+4+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+3+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+2+offset]=pallook[egapal[dat>>4]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<3)+1+offset]=pallook[egapal[dat&0xF]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+offset]= pallook[egapal[dat>>4]]; + } + } + break; + case 0x20: /*4 colours*/ + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + offset=((8-scrollcache)<<1)+16; + /*Low res (320) only, though high res (640) should be possible*/ + for (x=0;x<=svga_hdisp;x++) + { + if (sc&1 && !(crtc[0x17]&1)) + { + edat[0]=vram[(ma<<1)+0x8000]; + edat[1]=vram[(ma<<1)+0x8004]; + } + else + { + edat[0]=vram[(ma<<1)]; + edat[1]=vram[(ma<<1)+4]; + } + ma+=4; ma&=vrammask; + + ((uint32_t *)buffer32->line[displine])[(x<<4)+14+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+15+offset]=pallook[egapal[edat[1]&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+12+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+13+offset]=pallook[egapal[(edat[1]>>2)&3]]; + dat=edatlookup[(edat[0]>>2)&3][(edat[1]>>2)&3]|(edatlookup[(edat[2]>>2)&3][(edat[3]>>2)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+10+offset]=((uint32_t *)buffer32->line[displine])[(x<<4)+11+offset]=pallook[egapal[(edat[1]>>4)&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+8+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+9+offset]=pallook[egapal[(edat[1]>>6)&3]]; + dat=edatlookup[(edat[0]>>4)&3][(edat[1]>>4)&3]|(edatlookup[(edat[2]>>4)&3][(edat[3]>>4)&3]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+7+offset]=pallook[egapal[(edat[0]>>0)&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+5+offset]=pallook[egapal[(edat[0]>>2)&3]]; + dat=edatlookup[edat[0]>>6][edat[1]>>6]|(edatlookup[edat[2]>>6][edat[3]>>6]<<2); + ((uint32_t *)buffer32->line[displine])[(x<<4)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+3+offset]=pallook[egapal[(edat[0]>>4)&3]]; + ((uint32_t *)buffer32->line[displine])[(x<<4)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<4)+1+offset]=pallook[egapal[(edat[0]>>6)&3]]; + } + break; + case 0x40: case 0x60: /*256 colours (and more, with high/true colour RAMDAC)*/ + if (changedvram[ma>>10] || changedvram[(ma>>10)+1] || changedvram[(ma>>10)+2] || fullchange) + { + if (firstline_draw == 2000) firstline_draw = displine; + lastline_draw = displine; + if (svga_lowres) /*Low res (320)*/ + { +// if (!displine) pclog("Lo res %i %i %i\n",bpp,svga_hdisp,(svga_hdisp<<3)/3); + offset=(8-(scrollcache&6))+24; + if (bpp==8) /*Regular 8 bpp palette mode*/ + { + for (x=0;x<=svga_hdisp;x++) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<3)+6+offset]= ((uint32_t *)buffer32->line[displine])[(x<<3)+7+offset]=pallook[edat[3]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+4+offset]= ((uint32_t *)buffer32->line[displine])[(x<<3)+5+offset]=pallook[edat[2]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+2+offset]= ((uint32_t *)buffer32->line[displine])[(x<<3)+3+offset]=pallook[edat[1]]; + ((uint32_t *)buffer32->line[displine])[(x<<3)+offset]= ((uint32_t *)buffer32->line[displine])[(x<<3)+1+offset]=pallook[edat[0]]; + } + } + else if (bpp==16) /*16 bpp 565 mode*/ + { + for (x=0;x<=svga_hdisp;x++) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<2)+2+offset]=((uint32_t *)buffer32->line[displine])[(x<<2)+3+offset]=((bg&31)<<3)|(((bg>>5)&63)<<10)|(((bg>>11)&31)<<19); + ((uint32_t *)buffer32->line[displine])[(x<<2)+0+offset]=((uint32_t *)buffer32->line[displine])[(x<<2)+1+offset]=((fg&31)<<3)|(((fg>>5)&63)<<10)|(((fg>>11)&31)<<19); + } + } + else if (bpp==15) /*15 bpp 555 mode*/ + { + for (x=0;x<=svga_hdisp;x++) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<1)+2+offset]=((uint32_t *)buffer32->line[displine])[(x<<2)+3+offset]=((bg&31)<<3)|(((bg>>5)&31)<<11)|(((bg>>10)&31)<<19); + ((uint32_t *)buffer32->line[displine])[(x<<1)+0+offset]=((uint32_t *)buffer32->line[displine])[(x<<2)+1+offset]=((fg&31)<<3)|(((fg>>5)&31)<<11)|(((fg>>10)&31)<<19); + } + } + else if (bpp==24) /*24 bpp 888 mode*/ + { + for (x=0;x<=((svga_hdisp<<3)/3);x++) + { + fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16); + ma+=3; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<1)+offset]=((uint32_t *)buffer32->line[displine])[(x<<1)+1+offset]=fg; + } + } + else if (bpp==32) /*32 bpp 8888 mode*/ + { + for (x = 0; x <= svga_hdisp; x++) + { + fg = vram[ma] | (vram[ma + 1] << 8) | (vram[ma + 2] << 16); + ma += 4; ma &= vrammask; + ((uint32_t *)buffer32->line[displine])[(x << 1) + offset] = ((uint32_t *)buffer32->line[displine])[(x << 1) + 1 + offset] = fg; + } + } + } + else /*High res (SVGA only)*/ + { +// if (!displine) pclog("Hi res %i %i %i\n",bpp,svga_hdisp,(svga_hdisp<<3)/3); + offset=(8-((scrollcache&6)>>1))+24; + if (bpp==8) + { + for (x=0;x<=(svga_hdisp<<1);x++) + { + edat[0]=vram[ma]; + edat[1]=vram[ma|0x1]; + edat[2]=vram[ma|0x2]; + edat[3]=vram[ma|0x3]; + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<2)+3+offset]=pallook[edat[3]]; + ((uint32_t *)buffer32->line[displine])[(x<<2)+2+offset]=pallook[edat[2]]; + ((uint32_t *)buffer32->line[displine])[(x<<2)+1+offset]=pallook[edat[1]]; + ((uint32_t *)buffer32->line[displine])[(x<<2)+offset]= pallook[edat[0]]; + } + } + else if (bpp==16) + { + for (x=0;x<=(svga_hdisp<<1);x++) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<1)+1+offset]=((bg&31)<<3)|(((bg>>5)&63)<<10)|(((bg>>11)&31)<<19); + ((uint32_t *)buffer32->line[displine])[(x<<1)+0+offset]=((fg&31)<<3)|(((fg>>5)&63)<<10)|(((fg>>11)&31)<<19); + } + } + else if (bpp==15) + { + for (x=0;x<=(svga_hdisp<<1);x++) + { + fg=vram[ma]|(vram[ma|0x1]<<8); + bg=vram[ma|0x2]|(vram[ma|0x3]<<8); + ma+=4; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[(x<<1)+1+offset]=((bg&31)<<3)|(((bg>>5)&31)<<11)|(((bg>>10)&31)<<19); + ((uint32_t *)buffer32->line[displine])[(x<<1)+0+offset]=((fg&31)<<3)|(((fg>>5)&31)<<11)|(((fg>>10)&31)<<19); + } + } + else if (bpp==24) + { + for (x=0;x<=((svga_hdisp<<3)/3);x++) + { + fg=vram[ma]|(vram[ma+1]<<8)|(vram[ma+2]<<16); + ma+=3; ma&=vrammask; + ((uint32_t *)buffer32->line[displine])[x+offset]=fg; + } + } + else if (bpp==32) + { + for (x = 0; x <= (svga_hdisp<<2); x++) + { + fg = vram[ma] | (vram[ma + 1] << 8) | (vram[ma + 2] << 16); + ma += 4; ma &= vrammask; + ((uint32_t *)buffer32->line[displine])[x + offset] = fg; + } + } + } + } + break; + } + if (svga_hwcursor_on) + { + svga_hwcursor_draw(displine); + svga_hwcursor_on--; + } + } + if (lastline1500) displine=0; +// pclog("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], +// displine, vc, ma); + } + else + { +// pclog("VC %i ma %05X\n", vc, ma); + vidtime+=dispontime; + +// if (output) printf("Display on %f\n",vidtime); + if (svga_dispon) cgastat&=~1; + svga_hdisp_on=0; + + linepos=0; + if (sc==(crtc[11]&31)) con = 0; + if (svga_dispon) + { + if ((crtc[9]&0x80) && !linecountff) + { + linecountff=1; + ma=maback; + } + else if (sc==(crtc[9]&31)) + { + linecountff=0; + sc=0; + + maback += (svga_rowoffset<<3); + if (svga_interlace) maback += (svga_rowoffset<<3); + maback&=vrammask; + ma=maback; + } + else + { + linecountff=0; + sc++; + sc&=31; + ma=maback; + } + } + vc++; + vc&=2047; + + if (vc==svga_split) + { +// pclog("VC split\n"); + ma=maback=0; + if (attrregs[0x10]&0x20) scrollcache=0; + } + if (vc==svga_dispend) + { +// pclog("VC dispend\n"); + svga_dispon=0; + if (crtc[10] & 0x20) cursoron=0; + else cursoron=cgablink&16; + if (!(gdcreg[6]&1) && !(cgablink&15)) fullchange=2; + cgablink++; + + for (x=0;x<2048;x++) if (changedvram[x]) changedvram[x]--; +// memset(changedvram,0,2048); + if (fullchange) fullchange--; + } + if (vc==svga_vsyncstart) + { +// pclog("VC vsync %i %i\n", firstline_draw, lastline_draw); + svga_dispon=0; + cgastat|=8; + if (seqregs[1]&8) x=svga_hdisp*((seqregs[1]&1)?8:9)*2; + else x=svga_hdisp*((seqregs[1]&1)?8:9); + + if (bpp == 16 || bpp == 15) x /= 2; + if (bpp == 24) x /= 3; + if (bpp == 32) x /= 4; + if (svga_interlace && !oddeven) lastline++; + if (svga_interlace && oddeven) firstline--; + + wx=x; + wy=lastline-firstline; + + + svga_doblit(firstline_draw, lastline_draw + 1); + + readflash=0; + + firstline=2000; + lastline=0; + + firstline_draw = 2000; + lastline_draw = 0; + + oddeven^=1; + + changeframecount=(svga_interlace)?3:2; + vslines=0; + + if (svga_interlace && oddeven) ma = maback = svga_ma + (svga_rowoffset << 1); + else ma = maback = svga_ma; + ca=(crtc[0xE]<<8)|crtc[0xF]; + + ma <<= 2; + maback <<= 2; + ca <<= 2; + + + video_res_x = wx; + video_res_y = wy + 1; + + if (!(gdcreg[6]&1)) /*Text mode*/ + { + video_res_x /= (seqregs[1] & 1) ? 8 : 9; + video_res_y /= (crtc[9] & 31) + 1; + video_bpp = 0; + } + else + { + if (crtc[9] & 0x80) + video_res_y /= 2; + if (!(crtc[0x17] & 1)) + video_res_y *= 2; + video_res_y /= (crtc[9] & 31) + 1; + if ((seqregs[1] & 8) || svga_lowres) + video_res_x /= 2; + switch (gdcreg[5]&0x60) + { + case 0x00: video_bpp = 4; break; + case 0x20: video_bpp = 2; break; + case 0x40: case 0x60: video_bpp = bpp; break; + } + } + +// if (svga_interlace && oddeven) ma=maback=ma+(svga_rowoffset<<2); + +// pclog("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,svga_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], svga_interlace, oddeven); + } + if (vc==svga_vtotal) + { +// pclog("VC vtotal\n"); + + +// printf("Frame over at line %i %i %i %i\n",displine,vc,svga_vsyncstart,svga_dispend); + vc=0; + sc=0; + svga_dispon=1; + displine=(svga_interlace && oddeven) ? 1 : 0; //(TRIDENT && (crtc[0x1E]&4) && oddeven)?1:0; + scrollcache=attrregs[0x13]&7; + linecountff=0; + + svga_hwcursor_on=0; + svga_hwcursor_latch = svga_hwcursor; +// pclog("Latch HWcursor addr %08X\n", svga_hwcursor_latch.addr); + +// pclog("ADDR %08X\n",hwcursor_addr); + } + if (sc==(crtc[10]&31)) con=1; + } +// printf("2 %i\n",svga_vsyncstart); +} + +int svga_init() +{ + int c, d, e; + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + readmode = 0; + return 0; +} + +#define egacycles 1 +#define egacycles2 1 +void svga_write(uint32_t addr, uint8_t val) +{ + int x,y; + char s[2]={0,0}; + uint8_t vala,valb,valc,vald,wm=writemask; + int writemask2 = writemask; + int bankaddr; + + egawrites++; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + +// pclog("Writeega %06X ",addr); + if (addr>=0xB0000) addr&=0x7FFF; + else + { + //if (gdcreg[6]&8) return; + addr &= 0xFFFF; + addr += svgawbank; + } + + if (!(gdcreg[6]&1)) fullchange=2; + if (chain4) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else + { + addr<<=2; + } +// pclog("%08X %02X %i %i %i\n", addr, val, writemask2, writemode, chain4); + addr&=0x7FFFFF; + changedvram[addr>>10]=changeframecount; + + switch (writemode) + { + case 1: + if (writemask2&1) vram[addr]=la; + if (writemask2&2) vram[addr|0x1]=lb; + if (writemask2&4) vram[addr|0x2]=lc; + if (writemask2&8) vram[addr|0x3]=ld; + break; + case 0: + if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val]; + if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask2&1) vram[addr]=val; + if (writemask2&2) vram[addr|0x1]=val; + if (writemask2&4) vram[addr|0x2]=val; + if (writemask2&8) vram[addr|0x3]=val; + } + else + { + if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0; + else vala=val; + if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0; + else valb=val; + if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0; + else valc=val; + if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0; + else vald=val; + + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask2&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]); + } + else + { + vala=((val&1)?0xFF:0); + valb=((val&2)?0xFF:0); + valc=((val&4)?0xFF:0); + vald=((val&8)?0xFF:0); + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + } + break; + case 3: + if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val]; + wm=gdcreg[8]; + gdcreg[8]&=val; + + vala=(gdcreg[0]&1)?0xFF:0; + valb=(gdcreg[0]&2)?0xFF:0; + valc=(gdcreg[0]&4)?0xFF:0; + vald=(gdcreg[0]&8)?0xFF:0; + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + gdcreg[8]=wm; + break; + } +} + +uint8_t svga_read(uint32_t addr) +{ + uint8_t temp,temp2,temp3,temp4; + uint32_t addr2; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; +// pclog("Readega %06X ",addr); + if (addr>=0xB0000) addr&=0x7FFF; + else + { + addr &= 0xFFFF; + addr += svgarbank; + } +// pclog("%05X %i %04X:%04X %02X %02X %i\n",addr,chain4,CS,pc, vram[addr & 0x7fffff], vram[(addr << 2) & 0x7fffff], readmode); +// pclog("%i\n", readmode); + if (chain4) + { + addr &= 0x7fffff; + if (addr >= svga_vram_limit) + return 0xff; + return vram[addr]; + } + else addr<<=2; + + addr &= 0x7fffff; + + if (addr >= svga_vram_limit) + return 0xff; + + la=vram[addr]; + lb=vram[addr|0x1]; + lc=vram[addr|0x2]; + ld=vram[addr|0x3]; + if (readmode) + { + temp= (colournocare&1) ?0xFF:0; + temp&=la; + temp^=(colourcompare&1)?0xFF:0; + temp2= (colournocare&2) ?0xFF:0; + temp2&=lb; + temp2^=(colourcompare&2)?0xFF:0; + temp3= (colournocare&4) ?0xFF:0; + temp3&=lc; + temp3^=(colourcompare&4)?0xFF:0; + temp4= (colournocare&8) ?0xFF:0; + temp4&=ld; + temp4^=(colourcompare&8)?0xFF:0; + return ~(temp|temp2|temp3|temp4); + } +//pclog("Read %02X %04X %04X\n",vram[addr|readplane],addr,readplane); + return vram[addr|readplane]; +} + +void svga_write_linear(uint32_t addr, uint8_t val) +{ + int x,y; + char s[2]={0,0}; + uint8_t vala,valb,valc,vald,wm=writemask; + int writemask2 = writemask; + int bankaddr; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egawrites++; + +// pclog("Write LFB %08X %02X ", addr, val); + if (!(gdcreg[6]&1)) fullchange=2; + if (chain4) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else + { + addr<<=2; + } + addr &= 0x7fffff; +// pclog("%08X\n", addr); + changedvram[addr>>10]=changeframecount; + + switch (writemode) + { + case 1: + if (writemask2&1) vram[addr]=la; + if (writemask2&2) vram[addr|0x1]=lb; + if (writemask2&4) vram[addr|0x2]=lc; + if (writemask2&8) vram[addr|0x3]=ld; + break; + case 0: + if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val]; + if (gdcreg[8]==0xFF && !(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask2&1) vram[addr]=val; + if (writemask2&2) vram[addr|0x1]=val; + if (writemask2&4) vram[addr|0x2]=val; + if (writemask2&8) vram[addr|0x3]=val; + } + else + { + if (gdcreg[1]&1) vala=(gdcreg[0]&1)?0xFF:0; + else vala=val; + if (gdcreg[1]&2) valb=(gdcreg[0]&2)?0xFF:0; + else valb=val; + if (gdcreg[1]&4) valc=(gdcreg[0]&4)?0xFF:0; + else valc=val; + if (gdcreg[1]&8) vald=(gdcreg[0]&8)?0xFF:0; + else vald=val; + + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(gdcreg[3]&0x18) && !gdcreg[1]) + { + if (writemask2&1) vram[addr]=(((val&1)?0xFF:0)&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(((val&2)?0xFF:0)&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(((val&4)?0xFF:0)&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(((val&8)?0xFF:0)&gdcreg[8])|(ld&~gdcreg[8]); + } + else + { + vala=((val&1)?0xFF:0); + valb=((val&2)?0xFF:0); + valc=((val&4)?0xFF:0); + vald=((val&8)?0xFF:0); + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + } + break; + case 3: + if (gdcreg[3]&7) val=svga_rotate[gdcreg[3]&7][val]; + wm=gdcreg[8]; + gdcreg[8]&=val; + + vala=(gdcreg[0]&1)?0xFF:0; + valb=(gdcreg[0]&2)?0xFF:0; + valc=(gdcreg[0]&4)?0xFF:0; + vald=(gdcreg[0]&8)?0xFF:0; + switch (gdcreg[3]&0x18) + { + case 0: /*Set*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|(la&~gdcreg[8]); + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|(lb&~gdcreg[8]); + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|(lc&~gdcreg[8]); + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|(ld&~gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2&1) vram[addr]=(vala|~gdcreg[8])&la; + if (writemask2&2) vram[addr|0x1]=(valb|~gdcreg[8])&lb; + if (writemask2&4) vram[addr|0x2]=(valc|~gdcreg[8])&lc; + if (writemask2&8) vram[addr|0x3]=(vald|~gdcreg[8])&ld; + break; + case 0x10: /*OR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])|la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])|lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])|lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])|ld; + break; + case 0x18: /*XOR*/ + if (writemask2&1) vram[addr]=(vala&gdcreg[8])^la; + if (writemask2&2) vram[addr|0x1]=(valb&gdcreg[8])^lb; + if (writemask2&4) vram[addr|0x2]=(valc&gdcreg[8])^lc; + if (writemask2&8) vram[addr|0x3]=(vald&gdcreg[8])^ld; + break; + } + gdcreg[8]=wm; + break; + } +} + +uint8_t svga_read_linear(uint32_t addr) +{ + uint8_t temp,temp2,temp3,temp4; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; + + if (chain4) + { + addr &= 0x7fffff; + if (addr >= svga_vram_limit) + return 0xff; + return vram[addr & 0x7fffff]; + } + else addr<<=2; + + addr &= 0x7fffff; + + if (addr >= svga_vram_limit) + return 0xff; + + la=vram[addr]; + lb=vram[addr|0x1]; + lc=vram[addr|0x2]; + ld=vram[addr|0x3]; + if (readmode) + { + temp= (colournocare&1) ?0xFF:0; + temp&=la; + temp^=(colourcompare&1)?0xFF:0; + temp2= (colournocare&2) ?0xFF:0; + temp2&=lb; + temp2^=(colourcompare&2)?0xFF:0; + temp3= (colournocare&4) ?0xFF:0; + temp3&=lc; + temp3^=(colourcompare&4)?0xFF:0; + temp4= (colournocare&8) ?0xFF:0; + temp4&=ld; + temp4^=(colourcompare&8)?0xFF:0; + return ~(temp|temp2|temp3|temp4); + } +//printf("Read %02X %04X %04X\n",vram[addr|readplane],addr,readplane); + return vram[addr|readplane]; +} + +void svga_doblit(int y1, int y2) +{ + frames++; +// pclog("doblit %i %i\n", y1, y2); + if (y1 > y2) + { + startblit(); + video_blit_memtoscreen(32, 0, 0, 0, xsize, ysize); + endblit(); + return; + } + startblit(); + if ((wx!=xsize || wy!=ysize) && !vid_resize) + { + xsize=wx; + ysize=wy+1; + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + if (vres) updatewindowsize(xsize,ysize<<1); + else updatewindowsize(xsize,ysize); + } + if (vid_resize) + { + xsize = wx; + ysize = wy + 1; + } + video_blit_memtoscreen(32, 0, y1, y2, xsize, ysize); + if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); + endblit(); + +} + +void svga_writew(uint32_t addr, uint16_t val) +{ + if (!svga_fast) + { + svga_write(addr, val); + svga_write(addr + 1, val >> 8); + return; + } + + egawrites += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + +// pclog("Writew %05X ", addr); + addr = (addr & 0xffff) + svgawbank; + addr &= 0x7FFFFF; +// pclog("%08X %04X\n", addr, val); + changedvram[addr >> 10] = changeframecount; + *(uint16_t *)&vram[addr] = val; +} + +void svga_writel(uint32_t addr, uint32_t val) +{ + if (!svga_fast) + { + svga_write(addr, val); + svga_write(addr + 1, val >> 8); + svga_write(addr + 2, val >> 16); + svga_write(addr + 3, val >> 24); + return; + } + + egawrites += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + +// pclog("Writel %05X ", addr); + addr = (addr & 0xffff) + svgawbank; + addr &= 0x7FFFFF; +// pclog("%08X %08X\n", addr, val); + + changedvram[addr >> 10] = changeframecount; + *(uint32_t *)&vram[addr] = val; +} + +uint16_t svga_readw(uint32_t addr) +{ + if (!svga_fast) + return svga_read(addr) | (svga_read(addr + 1) << 8); + + egareads += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + +// pclog("Readw %05X ", addr); + addr = (addr & 0xffff) + svgarbank; + addr &= 0x7FFFFF; +// pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]); + if (addr >= svga_vram_limit) return 0xffff; + + return *(uint16_t *)&vram[addr]; +} + +uint32_t svga_readl(uint32_t addr) +{ + if (!svga_fast) + return svga_read(addr) | (svga_read(addr + 1) << 8) | (svga_read(addr + 2) << 16) | (svga_read(addr + 3) << 24); + + egareads += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + +// pclog("Readl %05X ", addr); + addr = (addr & 0xffff) + svgarbank; + addr &= 0x7FFFFF; +// pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]); + if (addr >= svga_vram_limit) return 0xffffffff; + + return *(uint32_t *)&vram[addr]; +} + +void svga_writew_linear(uint32_t addr, uint16_t val) +{ + if (!svga_fast) + { + svga_write_linear(addr, val); + svga_write_linear(addr + 1, val >> 8); + return; + } + + egawrites += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + addr &= 0x7FFFFF; + changedvram[addr >> 10] = changeframecount; + *(uint16_t *)&vram[addr] = val; +} + +void svga_writel_linear(uint32_t addr, uint32_t val) +{ + if (!svga_fast) + { + svga_write_linear(addr, val); + svga_write_linear(addr + 1, val >> 8); + svga_write_linear(addr + 2, val >> 16); + svga_write_linear(addr + 3, val >> 24); + return; + } + + egawrites += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + addr &= 0x7fffff; + changedvram[addr >> 10] = changeframecount; + *(uint32_t *)&vram[addr] = val; +} + +uint16_t svga_readw_linear(uint32_t addr) +{ + if (!svga_fast) + return svga_read_linear(addr) | (svga_read_linear(addr + 1) << 8); + + egareads += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + addr &= 0x7FFFFF; + if (addr >= svga_vram_limit) return 0xffff; + + return *(uint16_t *)&vram[addr]; +} + +uint32_t svga_readl_linear(uint32_t addr) +{ + if (!svga_fast) + return svga_read_linear(addr) | (svga_read_linear(addr + 1) << 8) | (svga_read_linear(addr + 2) << 16) | (svga_read_linear(addr + 3) << 24); + + egareads += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + addr &= 0x7FFFFF; + if (addr >= svga_vram_limit) return 0xffffffff; + + return *(uint32_t *)&vram[addr]; +} diff --git a/src/vid_svga.h b/src/vid_svga.h new file mode 100644 index 00000000..60384090 --- /dev/null +++ b/src/vid_svga.h @@ -0,0 +1,53 @@ +/*Vertical timings*/ +extern int svga_vtotal, svga_dispend, svga_vsyncstart, svga_split; +/*Horizontal timings*/ +extern int svga_hdisp, svga_htotal, svga_rowoffset; +/*Flags - svga_lowres = 1/2 clock in 256+ colour modes, svga_interlace = interlace mode enabled*/ +extern int svga_lowres, svga_interlace; + +/*Status of display on*/ +extern int svga_hdisp_on; + +extern double svga_clock; +extern uint32_t svga_ma; +extern void (*svga_recalctimings_ex)(); + +extern uint8_t svga_miscout; + +extern int svga_init(); +extern void svga_poll(); +extern void svga_recalctimings(); + +typedef struct +{ + int ena; + int x, y; + int xoff, yoff; + uint32_t addr; +} SVGA_HWCURSOR; + +extern SVGA_HWCURSOR svga_hwcursor, svga_hwcursor_latch; + +//extern int svga_hwcursor_x, svga_hwcursor_y; +//extern int svga_hwcursor_xoff, svga_hwcursor_yoff; +//extern uint32_t /*svga_hwcursor_addr, */svga_hwcursor_addr_cur; +//extern int svga_hwcursor_ena; +extern int svga_hwcursor_on; +extern void (*svga_hwcursor_draw)(int displine); + +uint8_t svga_read(uint32_t addr); +uint16_t svga_readw(uint32_t addr); +uint32_t svga_readl(uint32_t addr); +void svga_write(uint32_t addr, uint8_t val); +void svga_writew(uint32_t addr, uint16_t val); +void svga_writel(uint32_t addr, uint32_t val); +uint8_t svga_read_linear(uint32_t addr); +uint16_t svga_readw_linear(uint32_t addr); +uint32_t svga_readl_linear(uint32_t addr); +void svga_write_linear(uint32_t addr, uint8_t val); +void svga_writew_linear(uint32_t addr, uint16_t val); +void svga_writel_linear(uint32_t addr, uint32_t val); + +void svga_doblit(int y1, int y2); + +extern uint32_t svga_vram_limit; diff --git a/src/vid_tandy.c b/src/vid_tandy.c new file mode 100644 index 00000000..4e53a714 --- /dev/null +++ b/src/vid_tandy.c @@ -0,0 +1,611 @@ +#include "ibm.h" +#include "video.h" +#include "io.h" +#include "mem.h" + +static int tandy_array_index; +static uint8_t tandy_array[32]; +static int tandy_memctrl=-1; +static uint32_t tandy_base; +static uint8_t tandy_mode,tandy_col; + +static uint8_t *tandy_vram, *tandy_b8000; + +void tandy_recalcaddress(); +void tandy_recalctimings(); + +void tandy_out(uint16_t addr, uint8_t val) +{ + uint8_t old; +// pclog("Tandy OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3D4: + crtcreg=val&31; + return; + case 0x3D5: + old=crtc[crtcreg]; + crtc[crtcreg]=val&crtcmask[crtcreg]; + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + tandy_recalctimings(); + } + } + return; + case 0x3D8: + tandy_mode=val; + return; + case 0x3D9: + tandy_col=val; + return; + case 0x3DA: + tandy_array_index = val & 31; + break; + case 0x3DE: + if (tandy_array_index & 16) val &= 0xF; + tandy_array[tandy_array_index & 31] = val; + break; + case 0x3DF: + tandy_memctrl=val; + tandy_recalcaddress(); + break; + case 0xA0: + tandy_base=((val>>1)&7)*128*1024; + tandy_recalcaddress(); + break; + } +} + +uint8_t tandy_in(uint16_t addr) +{ +// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr); + switch (addr) + { + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + case 0x3DA: + return cgastat; + } + return 0xFF; +} + +void tandy_recalcaddress() +{ + if ((tandy_memctrl&0xC0)==0xC0) + { + tandy_vram =&ram[((tandy_memctrl&0x6)<<14) +tandy_base]; + tandy_b8000=&ram[((tandy_memctrl&0x30)<<11)+tandy_base]; +// printf("VRAM at %05X B8000 at %05X\n",((tandy_memctrl&0x6)<<14)+tandy_base,((tandy_memctrl&0x30)<<11)+tandy_base); + } + else + { + tandy_vram =&ram[((tandy_memctrl&0x7)<<14) +tandy_base]; + tandy_b8000=&ram[((tandy_memctrl&0x38)<<11)+tandy_base]; +// printf("VRAM at %05X B8000 at %05X\n",((tandy_memctrl&0x7)<<14)+tandy_base,((tandy_memctrl&0x38)<<11)+tandy_base); + } +} + +void tandy_write(uint32_t addr, uint8_t val) +{ + if (tandy_memctrl==-1) return; +// pclog("Tandy VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); + tandy_b8000[addr&0x7FFF]=val; +} + +uint8_t tandy_read(uint32_t addr) +{ + if (tandy_memctrl==-1) return 0xFF; +// pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy_b8000[addr&0x7FFF],CS,pc); + return tandy_b8000[addr&0x7FFF]; +} + +void tandy_recalctimings() +{ + if (tandy_mode&1) + { + disptime=crtc[0]+1; + dispontime=crtc[1]; + } + else + { + disptime=(crtc[0]+1)<<1; + dispontime=crtc[1]<<1; + } + dispofftime=disptime-dispontime; + dispontime*=CGACONST; + dispofftime*=CGACONST; +} + + +static int linepos,displine; +static int sc,vc; +static int cgadispon; +static int con,coff,cursoron,cgablink; +static int vsynctime,vadj; +static uint16_t ma,maback,ca; + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +int i_filt[8],q_filt[8]; + +/*static int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +};*/ + +void tandy_poll() +{ +// int *cgapal=cga4pal[((tandy_col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; + uint16_t ca=(crtc[15]|(crtc[14]<<8))&0x3FFF; + int drawcursor; + int x,c; + int oldvc; + uint8_t chr,attr; + uint16_t dat,dat2,dat3,dat4; + int cols[4]; + int col; + int oldsc; + int y_buf[8]={0,0,0,0,0,0,0,0},y_val,y_tot; + int i_buf[8]={0,0,0,0,0,0,0,0},i_val,i_tot; + int q_buf[8]={0,0,0,0,0,0,0,0},q_val,q_tot; + int r,g,b; + if (!linepos) + { +// cgapal[0]=tandy_col&15; +// printf("Firstline %i Lastline %i Displine %i\n",firstline,lastline,displine); + vidtime+=dispofftime; + cgastat|=1; + linepos=1; + oldsc=sc; + if ((crtc[8]&3)==3) sc=(sc<<1)&7; + if (cgadispon) + { + if (displineline[displine][c]=cols[0]; + if (tandy_mode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=cols[0]; + else buffer->line[displine][c+(crtc[1]<<4)+8]=cols[0]; + } + else if ((tandy_mode&0x12)==0x12) + { + buffer->line[displine][c]=0; + if (tandy_mode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=0; + else buffer->line[displine][c+(crtc[1]<<4)+8]=0; + } + else + { + buffer->line[displine][c]=(tandy_col&15)+16; + if (tandy_mode&1) buffer->line[displine][c+(crtc[1]<<3)+8]=(tandy_col&15)+16; + else buffer->line[displine][c+(crtc[1]<<4)+8]=(tandy_col&15)+16; + } + } +// printf("X %i %i\n",c+(crtc[1]<<4)+8,c+(crtc[1]<<3)+8); +// printf("Drawing %i %i %i\n",displine,vc,sc); + if ((tandy_array[3]&0x10) && (tandy_mode&1)) /*320x200x16*/ + { + for (x=0;xline[displine][(x<<3)+8]=buffer->line[displine][(x<<3)+9] =tandy_array[((dat>>12)&tandy_array[1])+16]+16; + buffer->line[displine][(x<<3)+10]=buffer->line[displine][(x<<3)+11]=tandy_array[((dat>>8)&tandy_array[1])+16]+16; + buffer->line[displine][(x<<3)+12]=buffer->line[displine][(x<<3)+13]=tandy_array[((dat>>4)&tandy_array[1])+16]+16; + buffer->line[displine][(x<<3)+14]=buffer->line[displine][(x<<3)+15]=tandy_array[(dat&tandy_array[1])+16]+16; + } + } + else if (tandy_array[3]&0x10) /*160x200x16*/ + { + for (x=0;xline[displine][(x<<4)+8]= buffer->line[displine][(x<<4)+9]= buffer->line[displine][(x<<4)+10]=buffer->line[displine][(x<<4)+11]=tandy_array[((dat>>12)&tandy_array[1])+16]+16; + buffer->line[displine][(x<<4)+12]=buffer->line[displine][(x<<4)+13]=buffer->line[displine][(x<<4)+14]=buffer->line[displine][(x<<4)+15]=tandy_array[((dat>>8)&tandy_array[1])+16]+16; + buffer->line[displine][(x<<4)+16]=buffer->line[displine][(x<<4)+17]=buffer->line[displine][(x<<4)+18]=buffer->line[displine][(x<<4)+19]=tandy_array[((dat>>4)&tandy_array[1])+16]+16; + buffer->line[displine][(x<<4)+20]=buffer->line[displine][(x<<4)+21]=buffer->line[displine][(x<<4)+22]=buffer->line[displine][(x<<4)+23]=tandy_array[(dat&tandy_array[1])+16]+16; + } + } + else if (tandy_array[3]&0x08) /*640x200x4 - this implementation is a complete guess!*/ + { + for (x=0;x>7)&1; + chr|=((dat>>14)&2); + buffer->line[displine][(x<<3)+8+c]=tandy_array[(chr&tandy_array[1])+16]+16; + dat<<=1; + } + } + } + else if (tandy_mode&1) + { + for (x=0;x>4)&7)&tandy_array[1])+16]+16; + if ((cgablink&16) && (attr&0x80) && !drawcursor) cols[1]=cols[0]; + } + else + { + cols[1]=tandy_array[((attr&15)&tandy_array[1])+16]+16; + cols[0]=tandy_array[((attr>>4)&tandy_array[1])+16]+16; + } + if (sc&8) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[0]; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<3)+c+8]^=15; + } + ma++; + } + } + else if (!(tandy_mode&2)) + { + for (x=0;x>4)&7)&tandy_array[1])+16]+16; + if ((cgablink&16) && (attr&0x80) && !drawcursor) cols[1]=cols[0]; + } + else + { + cols[1]=tandy_array[((attr&15)&tandy_array[1])+16]+16; + cols[0]=tandy_array[((attr>>4)&tandy_array[1])+16]+16; + } + ma++; + if (sc&8) + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[0]; + } + else + { + for (c=0;c<8;c++) + buffer->line[displine][(x<<4)+(c<<1)+8]=buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[(fontdat[chr][sc&7]&(1<<(c^7)))?1:0]; + } + if (drawcursor) + { + for (c=0;c<16;c++) + buffer->line[displine][(x<<4)+c+8]^=15; + } + } + } + else if (!(tandy_mode&16)) + { + cols[0]=(tandy_col&15)|16; + col=(tandy_col&16)?24:16; + if (tandy_mode&4) + { + cols[1]=col|3; + cols[2]=col|4; + cols[3]=col|7; + } + else if (tandy_col&32) + { + cols[1]=col|3; + cols[2]=col|5; + cols[3]=col|7; + } + else + { + cols[1]=col|2; + cols[2]=col|4; + cols[3]=col|6; + } + for (x=0;xline[displine][(x<<4)+(c<<1)+8]= + buffer->line[displine][(x<<4)+(c<<1)+1+8]=cols[dat>>14]; + dat<<=2; + } + } + } + else + { + cols[0]=0; cols[1]=tandy_array[(tandy_col&tandy_array[1])+16]+16; + for (x=0;xline[displine][(x<<4)+c+8]=cols[dat>>15]; + dat<<=1; + } + } + } + } + else + { + if (tandy_array[3]&4) + { + if (tandy_mode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,(tandy_array[2]&0xF)+16); + else hline(buffer,0,displine,(crtc[1]<<4)+16,(tandy_array[2]&0xF)+16); + } + else + { + cols[0]=((tandy_mode&0x12)==0x12)?0:(tandy_col&15)+16; + if (tandy_mode&1) hline(buffer,0,displine,(crtc[1]<<3)+16,cols[0]); + else hline(buffer,0,displine,(crtc[1]<<4)+16,cols[0]); + } + } + if (tandy_mode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + if (cga_comp) + { + for (c=0;cline[displine][c]&7][(c<<1)&6]?0x6000:0; + y_buf[(c<<1)&6]+=(buffer->line[displine][c]&8)?0x3000:0; + i_buf[(c<<1)&6]=y_buf[(c<<1)&6]*i_filt[(c<<1)&6]; + q_buf[(c<<1)&6]=y_buf[(c<<1)&6]*q_filt[(c<<1)&6]; + y_tot=y_buf[0]+y_buf[1]+y_buf[2]+y_buf[3]+y_buf[4]+y_buf[5]+y_buf[6]+y_buf[7]; + i_tot=i_buf[0]+i_buf[1]+i_buf[2]+i_buf[3]+i_buf[4]+i_buf[5]+i_buf[6]+i_buf[7]; + q_tot=q_buf[0]+q_buf[1]+q_buf[2]+q_buf[3]+q_buf[4]+q_buf[5]+q_buf[6]+q_buf[7]; + + y_val=y_tot>>10; + if (y_val>255) y_val=255; + y_val<<=16; + i_val=i_tot>>12; + if (i_val>39041) i_val=39041; + if (i_val<-39041) i_val=-39041; + q_val=q_tot>>12; + if (q_val>34249) q_val=34249; + if (q_val<-34249) q_val=-34249; + + r=(y_val+249*i_val+159*q_val)>>16; + g=(y_val-70*i_val-166*q_val)>>16; + b=(y_val-283*i_val+436*q_val)>>16; +// if (r>255) r=255; +// if (g>255) g=255; +// if (b>255) b=255; + + y_buf[((c<<1)&6)+1]=ntsc_col[buffer->line[displine][c]&7][((c<<1)&6)+1]?0x6000:0; + y_buf[((c<<1)&6)+1]+=(buffer->line[displine][c]&8)?0x3000:0; + i_buf[((c<<1)&6)+1]=y_buf[((c<<1)&6)+1]*i_filt[((c<<1)&6)+1]; + q_buf[((c<<1)&6)+1]=y_buf[((c<<1)&6)+1]*q_filt[((c<<1)&6)+1]; + y_tot=y_buf[0]+y_buf[1]+y_buf[2]+y_buf[3]+y_buf[4]+y_buf[5]+y_buf[6]+y_buf[7]; + i_tot=i_buf[0]+i_buf[1]+i_buf[2]+i_buf[3]+i_buf[4]+i_buf[5]+i_buf[6]+i_buf[7]; + q_tot=q_buf[0]+q_buf[1]+q_buf[2]+q_buf[3]+q_buf[4]+q_buf[5]+q_buf[6]+q_buf[7]; + + y_val=y_tot>>10; + if (y_val>255) y_val=255; + y_val<<=16; + i_val=i_tot>>12; + if (i_val>39041) i_val=39041; + if (i_val<-39041) i_val=-39041; + q_val=q_tot>>12; + if (q_val>34249) q_val=34249; + if (q_val<-34249) q_val=-34249; + + r+=(y_val+249*i_val+159*q_val)>>16; + g+=(y_val-70*i_val-166*q_val)>>16; + b+=(y_val-283*i_val+436*q_val)>>16; + if (r>511) r=511; + if (g>511) g=511; + if (b>511) b=511; + + ((uint32_t *)buffer32->line[displine])[c]=makecol32(r/2,g/2,b/2); + } + } + sc=oldsc; + if (vc==crtc[7] && !sc) + { + cgastat|=8; +// printf("VSYNC on %i %i\n",vc,sc); + } + displine++; + if (displine>=360) displine=0; + } + else + { + vidtime+=dispontime; + if (cgadispon) cgastat&=~1; + linepos=0; + if (vsynctime) + { + vsynctime--; + if (!vsynctime) + { + cgastat&=~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (sc==(crtc[11]&31) || ((crtc[8]&3)==3 && sc==((crtc[11]&31)>>1))) { con=0; coff=1; } + if (vadj) + { + sc++; + sc&=31; + ma=maback; + vadj--; + if (!vadj) + { + cgadispon=1; + ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + sc=0; +// printf("Display on!\n"); + } + } + else if (sc==crtc[9] || ((crtc[8]&3)==3 && sc==(crtc[9]>>1))) + { + maback=ma; +// con=0; +// coff=0; + sc=0; + oldvc=vc; + vc++; + vc&=127; +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],cgadispon); + if (vc==crtc[6]) cgadispon=0; + if (oldvc==crtc[4]) + { +// printf("Display over at %i\n",displine); + vc=0; + vadj=crtc[5]; + if (!vadj) cgadispon=1; + if (!vadj) ma=maback=(crtc[13]|(crtc[12]<<8))&0x3FFF; + if ((crtc[10]&0x60)==0x20) cursoron=0; + else cursoron=cgablink&16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (vc==crtc[7]) + { + cgadispon=0; + displine=0; + vsynctime=16;//(crtc[3]>>4)+1; +// printf("Vsynctime %i %02X\n",vsynctime,crtc[3]); +// cgastat|=8; + if (crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (tandy_mode&1) x=(crtc[1]<<3)+16; + else x=(crtc[1]<<4)+16; + lastline++; + if (x!=xsize || (lastline-firstline)!=ysize) + { + xsize=x; + ysize=lastline-firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize<64) xsize=656; + if (ysize<32) ysize=200; + updatewindowsize(xsize,(ysize<<1)+16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + if (cga_comp) + video_blit_memtoscreen(0, firstline-4, 0, (lastline-firstline)+8, xsize, (lastline-firstline)+8); + else + video_blit_memtoscreen_8(0, firstline-4, xsize, (lastline-firstline)+8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + if ((tandy_array[3]&0x10) && (tandy_mode&1)) /*320x200x16*/ + { + video_res_x /= 2; + video_bpp = 4; + } + else if (tandy_array[3]&0x10) /*160x200x16*/ + { + video_res_x /= 4; + video_bpp = 4; + } + else if (tandy_array[3]&0x08) /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + else if (tandy_mode&1) + { + video_res_x /= 8; + video_res_y /= crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy_mode&2)) + { + video_res_x /= 16; + video_res_y /= crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy_mode&16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + video_bpp = 1; + } + firstline=1000; + lastline=0; + cgablink++; + } + } + else + { + sc++; + sc&=31; + ma=maback; + } + if ((sc==(crtc[10]&31) || ((crtc[8]&3)==3 && sc==((crtc[10]&31)>>1)))) con=1; + } +} + +int tandy_init() +{ + mem_sethandler(0xb8000, 0x8000, tandy_read, NULL, NULL, tandy_write, NULL, NULL); + io_sethandler(0x00a0, 0x0002, tandy_in, NULL, NULL, tandy_out, NULL, NULL); + tandy_memctrl = -1; + return 0; +} + +GFXCARD vid_tandy = +{ + tandy_init, + /*IO at 3Cx/3Dx*/ + tandy_out, + tandy_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + tandy_poll, + tandy_recalctimings, + + video_write_null, + video_write_null, + tandy_write, + + video_read_null, + video_read_null, + tandy_read +}; diff --git a/src/vid_tkd8001_ramdac.c b/src/vid_tkd8001_ramdac.c new file mode 100644 index 00000000..4c013eae --- /dev/null +++ b/src/vid_tkd8001_ramdac.c @@ -0,0 +1,64 @@ +/*Trident TKD8001 RAMDAC emulation*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_tkd8001_ramdac.h" + +static int tkd8001_state=0; +static uint8_t tkd8001_ctrl; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val) +{ +// pclog("OUT RAMDAC %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3C6: + if (tkd8001_state == 4) + { + tkd8001_state = 0; + tkd8001_ctrl = val; + switch (val>>5) + { + case 0: case 1: case 2: case 3: + bpp = 8; + break; + case 5: + bpp = 15; + break; + case 6: + bpp = 24; + break; + case 7: + bpp = 16; + break; + } + return; + } + // tkd8001_state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_state = 0; + break; + } + svga_out(addr,val); +} + +uint8_t tkd8001_ramdac_in(uint16_t addr) +{ +// pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3C6: + if (tkd8001_state == 4) + { + //tkd8001_state = 0; + return tkd8001_ctrl; + } + tkd8001_state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_state = 0; + break; + } + return svga_in(addr); +} diff --git a/src/vid_tkd8001_ramdac.h b/src/vid_tkd8001_ramdac.h new file mode 100644 index 00000000..60a4626c --- /dev/null +++ b/src/vid_tkd8001_ramdac.h @@ -0,0 +1,2 @@ +void tkd8001_ramdac_out(uint16_t addr, uint8_t val); +uint8_t tkd8001_ramdac_in(uint16_t addr); diff --git a/src/vid_tvga.c b/src/vid_tvga.c new file mode 100644 index 00000000..eb43e1ff --- /dev/null +++ b/src/vid_tvga.c @@ -0,0 +1,199 @@ +/*Trident TVGA (8900D) emulation*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_tkd8001_ramdac.h" + +uint8_t trident3d8,trident3d9; +int tridentoldmode; +uint8_t tridentoldctrl2,tridentnewctrl2; +uint8_t tridentdac; + +void tvga_out(uint16_t addr, uint8_t val) +{ + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (seqaddr&0xF) + { + case 0xB: tridentoldmode=1; break; + case 0xC: if (seqregs[0xE]&0x80) seqregs[0xC]=val; break; + case 0xD: if (tridentoldmode) { tridentoldctrl2=val; rowdbl=val&0x10; } else tridentnewctrl2=val; break; + case 0xE: + seqregs[0xE]=val^2; + svgawbank=(seqregs[0xE]&0xF)*65536; + if (!(gdcreg[0xF]&1)) svgarbank=svgawbank; + return; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_ramdac_out(addr,val); + return; + + case 0x3CF: + switch (gdcaddr&15) + { + case 0xE: + gdcreg[0xE]=val^2; + if ((gdcreg[0xF]&1)==1) + svgarbank=(gdcreg[0xE]&0xF)*65536; + break; + case 0xF: + if (val&1) svgarbank=(gdcreg[0xE] &0xF)*65536; + else svgarbank=(seqregs[0xE]&0xF)*65536; + svgawbank=(seqregs[0xE]&0xF)*65536; + break; + } + break; + case 0x3D4: + crtcreg=val&63; + return; + case 0x3D5: + if (crtcreg <= 7 && crtc[0x11] & 0x80) return; + old=crtc[crtcreg]; + crtc[crtcreg]=val; + //if (crtcreg!=0xE && crtcreg!=0xF) pclog("CRTC R%02X = %02X\n",crtcreg,val); + if (old!=val) + { + if (crtcreg<0xE || crtcreg>0x10) + { + fullchange=changeframecount; + svga_recalctimings(); + } + } + return; + case 0x3D8: + trident3d8=val; + if (gdcreg[0xF]&4) + { + svgawbank=(val&0x1F)*65536; +// pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc); + if (!(gdcreg[0xF]&1)) + { + svgarbank=(val&0x1F)*65536; +// pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc); + } + } + return; + case 0x3D9: + trident3d9=val; + if ((gdcreg[0xF]&5)==5) + { + svgarbank=(val&0x1F)*65536; +// pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc); + } + return; + } + svga_out(addr,val); +} + +uint8_t tvga_in(uint16_t addr) +{ + uint8_t temp; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga_miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((seqaddr&0xF)==0xB) + { +// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); + tridentoldmode=0; + return 0x33; /*TVGA8900D*/ + } + if ((seqaddr&0xF)==0xC) + { +// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); +// return 0x20; /*2 DRAM banks*/ + } + if ((seqaddr&0xF)==0xD) + { + if (tridentoldmode) return tridentoldctrl2; + return tridentnewctrl2; + } + break; + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return tkd8001_ramdac_in(addr); + case 0x3CD: /*Banking*/ + return svgaseg; + case 0x3D4: + return crtcreg; + case 0x3D5: + return crtc[crtcreg]; + } + return svga_in(addr); +} + +void tvga_recalctimings() +{ + if (!svga_rowoffset) svga_rowoffset=0x100; /*This is the only sensible way I can see this being handled, + given that TVGA8900D has no overflow bits. + Some sort of overflow is required for 320x200x24 and 1024x768x16*/ + + if ((crtc[0x1E]&0xA0)==0xA0) svga_ma|=0x10000; + if ((crtc[0x27]&0x01)==0x01) svga_ma|=0x20000; + if ((crtc[0x27]&0x02)==0x02) svga_ma|=0x40000; + + if (tridentoldctrl2 & 0x10) + { + svga_rowoffset<<=1; + svga_ma<<=1; + } + if (tridentoldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/ + svga_lowres=0; + + if (gdcreg[0xF] & 8) + { + svga_htotal<<=1; + svga_hdisp<<=1; + } + svga_interlace = crtc[0x1E] & 4; + if (svga_interlace) + svga_rowoffset >>= 1; + + switch (((svga_miscout>>2)&3) | ((tridentnewctrl2<<2)&4)) + { + case 2: svga_clock = cpuclock/44900000.0; break; + case 3: svga_clock = cpuclock/36000000.0; break; + case 4: svga_clock = cpuclock/57272000.0; break; + case 5: svga_clock = cpuclock/65000000.0; break; + case 6: svga_clock = cpuclock/50350000.0; break; + case 7: svga_clock = cpuclock/40000000.0; break; + } +} + +int tvga_init() +{ + svga_recalctimings_ex = tvga_recalctimings; + svga_vram_limit = 1 << 20; /*1mb - chip supports 2mb, but drivers are buggy*/ + vrammask = 0xfffff; + return svga_init(); +} + +GFXCARD vid_tvga = +{ + tvga_init, + /*IO at 3Cx/3Dx*/ + tvga_out, + tvga_in, + /*IO at 3Ax/3Bx*/ + video_out_null, + video_in_null, + + svga_poll, + svga_recalctimings, + + svga_write, + video_write_null, + video_write_null, + + svga_read, + video_read_null, + video_read_null +}; diff --git a/src/vid_unk_ramdac.c b/src/vid_unk_ramdac.c new file mode 100644 index 00000000..d70d9aa3 --- /dev/null +++ b/src/vid_unk_ramdac.c @@ -0,0 +1,66 @@ +/*It is unknown exactly what RAMDAC this is + It is possibly a Sierra 1502x + It's addressed by the TLIVESA1 driver for ET4000*/ +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +static int unk_state=0; +static uint8_t unk_ctrl; + +void unk_ramdac_out(uint16_t addr, uint8_t val) +{ + //pclog("OUT RAMDAC %04X %02X\n",addr,val); + switch (addr) + { + case 0x3C6: + if (unk_state == 4) + { + unk_state = 0; + unk_ctrl = val; + switch ((val&1)|((val&0xE0)>>4)) + { + case 0: case 1: case 2: case 3: + bpp = 8; + break; + case 6: case 7: + bpp = 24; + break; + case 8: case 9: case 0xA: case 0xB: + bpp = 15; + break; + case 0xC: case 0xD: case 0xE: case 0xF: + bpp = 16; + break; + } + return; + } + unk_state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + unk_state = 0; + break; + } + svga_out(addr,val); +} + +uint8_t unk_ramdac_in(uint16_t addr) +{ + //pclog("IN RAMDAC %04X\n",addr); + switch (addr) + { + case 0x3C6: + if (unk_state == 4) + { + unk_state = 0; + return unk_ctrl; + } + unk_state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + unk_state = 0; + break; + } + return svga_in(addr); +} diff --git a/src/vid_unk_ramdac.h b/src/vid_unk_ramdac.h new file mode 100644 index 00000000..1f05aac4 --- /dev/null +++ b/src/vid_unk_ramdac.h @@ -0,0 +1,2 @@ +void unk_ramdac_out(uint16_t addr, uint8_t val); +uint8_t unk_ramdac_in(uint16_t addr); diff --git a/src/video.c b/src/video.c new file mode 100644 index 00000000..f9ee7deb --- /dev/null +++ b/src/video.c @@ -0,0 +1,494 @@ +#include +#include +#include "ibm.h" +#include "video.h" +#include "vid_svga.h" +#include "io.h" +#include "cpu.h" + +/*Video timing settings - + +8-bit - 1mb/sec + B = 8 ISA clocks + W = 16 ISA clocks + L = 32 ISA clocks + +Slow 16-bit - 2mb/sec + B = 6 ISA clocks + W = 8 ISA clocks + L = 16 ISA clocks + +Fast 16-bit - 4mb/sec + B = 3 ISA clocks + W = 3 ISA clocks + L = 6 ISA clocks + +Slow VLB/PCI - 8mb/sec (ish) + B = 4 bus clocks + W = 8 bus clocks + L = 16 bus clocks + +Mid VLB/PCI - + B = 4 bus clocks + W = 5 bus clocks + L = 10 bus clocks + +Fast VLB/PCI - + B = 3 bus clocks + W = 3 bus clocks + L = 4 bus clocks +*/ + +enum +{ + VIDEO_ISA = 0, + VIDEO_BUS +}; + +int video_speed = 0; +int video_timing[6][4] = +{ + {VIDEO_ISA, 8, 16, 32}, + {VIDEO_ISA, 6, 8, 16}, + {VIDEO_ISA, 3, 3, 6}, + {VIDEO_BUS, 4, 8, 16}, + {VIDEO_BUS, 4, 5, 10}, + {VIDEO_BUS, 3, 3, 4} +}; + +void video_updatetiming() +{ + if (video_timing[video_speed][0] == VIDEO_ISA) + { + video_timing_b = (int)(isa_timing * video_timing[video_speed][1]); + video_timing_w = (int)(isa_timing * video_timing[video_speed][2]); + video_timing_l = (int)(isa_timing * video_timing[video_speed][3]); + } + else + { + video_timing_b = (int)(bus_timing * video_timing[video_speed][1]); + video_timing_w = (int)(bus_timing * video_timing[video_speed][2]); + video_timing_l = (int)(bus_timing * video_timing[video_speed][3]); + } + if (cpu_16bitbus) + video_timing_l = video_timing_w * 2; +} + +int video_timing_b, video_timing_w, video_timing_l; + +int video_res_x, video_res_y, video_bpp; + +void (*video_blit_memtoscreen)(int x, int y, int y1, int y2, int w, int h); +void (*video_blit_memtoscreen_8)(int x, int y, int w, int h); + +void (*video_out) (uint16_t addr, uint8_t val); +void (*video_mono_out)(uint16_t addr, uint8_t val); +uint8_t (*video_in) (uint16_t addr); +uint8_t (*video_mono_in)(uint16_t addr); + +void (*video_write_a000)(uint32_t addr, uint8_t val); +void (*video_write_b000)(uint32_t addr, uint8_t val); +void (*video_write_b800)(uint32_t addr, uint8_t val); + +void (*video_write_a000_w)(uint32_t addr, uint16_t val); +void (*video_write_a000_l)(uint32_t addr, uint32_t val); + +uint8_t (*video_read_a000)(uint32_t addr); +uint8_t (*video_read_b000)(uint32_t addr); +uint8_t (*video_read_b800)(uint32_t addr); + +void (*video_recalctimings)(); + +void video_out_null(uint16_t addr, uint8_t val) +{ +} + +uint8_t video_in_null(uint16_t addr) +{ + return 0xFF; +} + +void video_write_null(uint32_t addr, uint8_t val) +{ +} + +uint8_t video_read_null(uint32_t addr) +{ + return 0xff; +} + +void video_load(GFXCARD g) +{ + io_sethandler(0x03a0, 0x0020, g.mono_in, NULL, NULL, g.mono_out, NULL, NULL); + io_sethandler(0x03c0, 0x0020, g.in, NULL, NULL, g.out, NULL, NULL); + + video_out = g.out; + video_in = g.in; + video_mono_out = g.mono_out; + video_mono_in = g.mono_in; + + pollvideo = g.poll; + video_recalctimings = g.recalctimings; + + video_write_a000 = g.write_a000; + video_write_b000 = g.write_b000; + video_write_b800 = g.write_b800; + + video_read_a000 = g.read_a000; + video_read_b000 = g.read_b000; + video_read_b800 = g.read_b800; + + video_write_a000_w = video_write_a000_l = NULL; + + g.init(); +} + +void video_init() +{ + pclog("Video_init %i %i\n",romset,gfxcard); + + switch (romset) + { + case ROM_TANDY: + video_load(vid_tandy); + return; + + case ROM_PC1512: + video_load(vid_pc1512); + return; + + case ROM_PC1640: + video_load(vid_pc1640); + return; + + case ROM_PC200: + video_load(vid_pc200); + return; + + case ROM_OLIM24: + video_load(vid_m24); + return; + + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + video_load(vid_paradise); + return; + + case ROM_ACER386: + video_load(vid_oti067); + return; + } + switch (gfxcard) + { + case GFX_MDA: + video_load(vid_mda); + break; + + case GFX_HERCULES: + video_load(vid_hercules); + break; + + case GFX_CGA: + video_load(vid_cga); + break; + + case GFX_EGA: + video_load(vid_ega); + break; + + case GFX_TVGA: + video_load(vid_tvga); + break; + + case GFX_ET4000: + video_load(vid_et4000); + break; + + case GFX_ET4000W32: + video_load(vid_et4000w32p); + break; + + case GFX_BAHAMAS64: + video_load(vid_s3); + break; + + case GFX_N9_9FX: + video_load(vid_s3); + break; + + case GFX_STEALTH64: + video_load(vid_s3); + break; + + default: + fatal("Bad gfx card %i\n",gfxcard); + } +} + +uint32_t cga32[256]; + +BITMAP *buffer,*vbuf;//,*vbuf2; +BITMAP *buffer32; +int speshul=0; + +uint8_t fontdat[256][8]; +uint8_t fontdatm[256][16]; + +float dispontime,dispofftime,disptime; +int svgaon; +uint8_t cgamode=1,cgastat,cgacol=7,ocgamode; +int linepos=0; +int output; +uint8_t *vram,*ram; + +int cgadispon=0; +int cgablink; + +uint8_t port3de,port3dd,port3df; + +uint8_t crtc[128],crtcreg; +uint8_t crtcmask[128]={0xFF,0xFF,0xFF,0xFF,0x7F,0x1F,0x7F,0x7F,0xF3,0x1F,0x7F,0x1F,0x3F,0xFF,0x3F,0xFF,0xFF,0xFF}; +uint8_t charbuffer[256]; +int crtcams[64]={0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1}; +int nmi=0; + + +int xsize=1,ysize=1; +int firstline=1000,lastline=0; + +int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + + +extern int fullchange; + +extern uint32_t vrammask; + + +int mdacols[256][2][2]; +uint8_t gdcreg[16]; + + +int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +}; + + +PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +void loadfont(char *s, int format) +{ + FILE *f=romfopen(s,"rb"); + int c,d; + if (!f) + return; + + if (!format) + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d]=getc(f); + } + } + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d+8]=getc(f); + } + } + fseek(f,4096+2048,SEEK_SET); + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + } + } + else if (format == 1) + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d]=getc(f); + } + } + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d+8]=getc(f); + } + } + fseek(f, 4096, SEEK_SET); + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + for (d=0;d<8;d++) getc(f); + } + } + else + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + } + } + fclose(f); +} + + +void drawscreen() +{ +// printf("Drawscreen %i %i %i %i\n",gfxcard,MDA,EGA,TANDY); +// if (EGA) drawscreenega(buffer,vbuf); +/* else if (MDA) {}//drawscreenmda(); + else if (TANDY) + { + if ((cgamode&3)==3 || array[3]&0x10) drawscreentandy(tandyvram); + else drawscreencga(tandyvram); + }*/ +// else drawscreencga(&vram[0x8000]); +} + +PALETTE comppal= +{ + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,31}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41} +}; + +void initvideo() +{ + int c,d; +// set_color_depth(desktop_color_depth()); +// if (set_gfx_mode(GFX_AUTODETECT_WINDOWED,2048,2048,0,0)) +// set_gfx_mode(GFX_AUTODETECT_WINDOWED,1024,768,0,0); +// vbuf=create_video_bitmap(1280+32,1024+32); +// set_color_depth(32); + buffer32=create_bitmap(2048,2048); +// set_color_depth(8); + buffer=create_bitmap(2048,2048); +// set_color_depth(32); + for (c=0;c<64;c++) + { + cgapal[c+64].r=(((c&4)?2:0)|((c&0x10)?1:0))*21; + cgapal[c+64].g=(((c&2)?2:0)|((c&0x10)?1:0))*21; + cgapal[c+64].b=(((c&1)?2:0)|((c&0x10)?1:0))*21; + if ((c&0x17)==6) cgapal[c+64].g>>=1; + } + for (c=0;c<64;c++) + { + cgapal[c+128].r=(((c&4)?2:0)|((c&0x20)?1:0))*21; + cgapal[c+128].g=(((c&2)?2:0)|((c&0x10)?1:0))*21; + cgapal[c+128].b=(((c&1)?2:0)|((c&0x08)?1:0))*21; + } + for (c=0;c<256;c++) cga32[c]=makecol(cgapal[c].r<<2,cgapal[c].g<<2,cgapal[c].b<<2); +// for (c=0;c<16;c++) cgapal[c+192]=comppal[c]; +// set_palette(cgapal); + if (MDA && !TANDY && !AMSTRAD && romset!=ROM_PC200) updatewindowsize(720,350); + else updatewindowsize(656,416); + for (c=17;c<64;c++) crtcmask[c]=0xFF; +} + +void resetvideo() +{ + int c; + if (MDA && !TANDY && !AMSTRAD && romset!=ROM_PC200) updatewindowsize(720,350); + else updatewindowsize(656,416); + cgastat=0; + set_palette(cgapal); + + for (c=18;c<64;c++) crtcmask[c]=0xFF; + crtc[0]=0x38; + crtc[1]=0x28; +// crtc[3]=0xFA; + crtc[4]=0x7F; + crtc[5]=0x06; + crtc[6]=0x64; + crtc[7]=0x70; + crtc[8]=0x02; + crtc[9]=1; + + cgacol=7; + for (c=0;c<256;c++) + { + mdacols[c][0][0]=mdacols[c][1][0]=mdacols[c][1][1]=16; + if (c&8) mdacols[c][0][1]=15+16; + else mdacols[c][0][1]=7+16; + } + mdacols[0x70][0][1]=16; + mdacols[0x70][0][0]=mdacols[0x70][1][0]=mdacols[0x70][1][1]=16+15; + mdacols[0xF0][0][1]=16; + mdacols[0xF0][0][0]=mdacols[0xF0][1][0]=mdacols[0xF0][1][1]=16+15; + mdacols[0x78][0][1]=16+7; + mdacols[0x78][0][0]=mdacols[0x78][1][0]=mdacols[0x78][1][1]=16+15; + mdacols[0xF8][0][1]=16+7; + mdacols[0xF8][0][0]=mdacols[0xF8][1][0]=mdacols[0xF8][1][1]=16+15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; +/* switch (gfxcard) + { + case GFX_CGA: pollvideo=pollcga; break; + case GFX_MDA: + case GFX_HERCULES: pollvideo=pollmda; break; + } + if (TANDY) pollvideo=polltandy; + if (EGA) pollvideo=pollega; + if (romset==ROM_PC1512 || romset==ROM_PC200) pollvideo=pollcga;*/ +// tandyvram=&ram[0x9C000]; +// printf("Tandy VRAM %08X\n",tandyvram); +// tandyb8000=&ram[0x9C000]; +} + +void closevideo() +{ + destroy_bitmap(buffer); + destroy_bitmap(vbuf); +} diff --git a/src/video.h b/src/video.h new file mode 100644 index 00000000..5f3d3a02 --- /dev/null +++ b/src/video.h @@ -0,0 +1,150 @@ +extern int egareads,egawrites; + +extern int bpp; +extern uint8_t svgaseg,svgaseg2; + +extern uint8_t crtcreg; +extern uint8_t crtc[128]; +extern uint8_t crtcmask[128]; +extern uint8_t gdcreg[16]; +extern int gdcaddr; +extern uint8_t attrregs[32]; +extern int attraddr,attrff; +extern uint8_t seqregs[32]; +extern int seqaddr; +extern int svgaon; + +extern uint8_t cgamode,cgacol,cgastat; +extern int egapal[16]; + +extern int scrblank; + +extern uint8_t writemask,charset; +extern int charseta,charsetb; +extern uint8_t colourcompare,colournocare; +extern int readplane,readmode,writemode; + +extern int vidclock; +extern int vres; + +extern uint32_t *pallook,pallook16[256],pallook64[256],pallook256[256]; + +extern int fullchange; +extern int changeframecount; + +extern int firstline,lastline; +extern int ega_hdisp,ega_rowoffset,ega_split,ega_dispend,ega_vsyncstart,ega_vtotal; +extern float dispontime,dispofftime,disptime; + +extern void (*video_out) (uint16_t addr, uint8_t val); +extern void (*video_mono_out)(uint16_t addr, uint8_t val); +extern uint8_t (*video_in) (uint16_t addr); +extern uint8_t (*video_mono_in)(uint16_t addr); + +extern void (*video_write_a000)(uint32_t addr, uint8_t val); +extern void (*video_write_b000)(uint32_t addr, uint8_t val); +extern void (*video_write_b800)(uint32_t addr, uint8_t val); + +extern uint8_t (*video_read_a000)(uint32_t addr); +extern uint8_t (*video_read_b000)(uint32_t addr); +extern uint8_t (*video_read_b800)(uint32_t addr); + +extern void (*video_write_a000_w)(uint32_t addr, uint16_t val); +extern void (*video_write_a000_l)(uint32_t addr, uint32_t val); + +extern void video_out_null(uint16_t addr, uint8_t val); +extern uint8_t video_in_null(uint16_t addr); + +extern void video_write_null(uint32_t addr, uint8_t val); +extern uint8_t video_read_null (uint32_t addr); + + +extern uint8_t tridentoldctrl2,tridentnewctrl2; +extern int rowdbl; + +typedef struct +{ + int w, h; + uint8_t *dat; + uint8_t *line[0]; +} BITMAP; + +extern BITMAP *buffer,*buffer32,*vbuf; + +extern BITMAP *screen; + +extern int wx,wy; + +extern uint8_t fontdat[256][8]; +extern uint8_t fontdatm[256][16]; + + +extern int xsize,ysize; + +extern int dacread,dacwrite,dacpos; + +typedef struct +{ + uint8_t r, g, b; +} RGB; + +typedef RGB PALETTE[256]; +extern PALETTE vgapal; +extern int palchange; + + +extern uint32_t vrammask; + +typedef struct +{ + int (*init)(); + void (*out)(uint16_t addr, uint8_t val); + uint8_t (*in)(uint16_t addr); + void (*mono_out)(uint16_t addr, uint8_t val); + uint8_t (*mono_in)(uint16_t addr); + void (*poll)(); + void (*recalctimings)(); + void (*write_a000)(uint32_t addr, uint8_t val); + void (*write_b000)(uint32_t addr, uint8_t val); + void (*write_b800)(uint32_t addr, uint8_t val); + uint8_t (*read_a000)(uint32_t addr); + uint8_t (*read_b000)(uint32_t addr); + uint8_t (*read_b800)(uint32_t addr); +} GFXCARD; + +extern GFXCARD vid_cga; +extern GFXCARD vid_mda; +extern GFXCARD vid_hercules; +extern GFXCARD vid_pc1512; +extern GFXCARD vid_pc1640; +extern GFXCARD vid_pc200; +extern GFXCARD vid_m24; +extern GFXCARD vid_paradise; +extern GFXCARD vid_tandy; +extern GFXCARD vid_ega; +extern GFXCARD vid_oti067; +extern GFXCARD vid_tvga; +extern GFXCARD vid_et4000; +extern GFXCARD vid_et4000w32p; +extern GFXCARD vid_s3; + + +extern float cpuclock; + +extern int emu_fps, frames; + +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +extern int readflash; + +extern void (*video_recalctimings)(); + +extern void (*video_blit_memtoscreen)(int x, int y, int y1, int y2, int w, int h); +extern void (*video_blit_memtoscreen_8)(int x, int y, int w, int h); + + +extern int video_timing_b, video_timing_w, video_timing_l; +extern int video_speed; + +extern int video_res_x, video_res_y, video_bpp; diff --git a/src/wd76c10.c b/src/wd76c10.c new file mode 100644 index 00000000..a5b96b07 --- /dev/null +++ b/src/wd76c10.c @@ -0,0 +1,102 @@ +#include "ibm.h" +#include "fdc.h" +#include "io.h" +#include "mem.h" +#include "serial.h" +#include "wd76c10.h" + +static uint16_t wd76c10_0092; +static uint16_t wd76c10_2072; +static uint16_t wd76c10_2872; +static uint16_t wd76c10_5872; + +uint16_t wd76c10_read(uint16_t port) +{ + switch (port) + { + case 0x0092: + return wd76c10_0092; + + case 0x2072: + return wd76c10_2072; + + case 0x2872: + return wd76c10_2872; + + case 0x5872: + return wd76c10_5872; + } + return 0; +} + +void wd76c10_write(uint16_t port, uint16_t val) +{ + pclog("WD76C10 write %04X %04X\n", port, val); + switch (port) + { + case 0x0092: + wd76c10_0092 = val; + + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + + case 0x2072: + wd76c10_2072 = val; + + serial1_remove(); + serial2_remove(); + + switch ((val >> 5) & 7) + { + case 1: serial1_init(0x3f8); break; + case 2: serial1_init(0x2f8); break; + case 3: serial1_init(0x3e8); break; + case 4: serial1_init(0x2e8); break; + } + switch ((val >> 1) & 7) + { + case 1: serial2_init(0x3f8); break; + case 2: serial2_init(0x2f8); break; + case 3: serial2_init(0x3e8); break; + case 4: serial2_init(0x2e8); break; + } + break; + + case 0x2872: + wd76c10_2872 = val; + + fdc_remove(); + if (!(val & 1)) + fdc_init(); + break; + + case 0x5872: + wd76c10_5872 = val; + break; + } +} + +uint8_t wd76c10_readb(uint16_t port) +{ + if (port & 1) + return wd76c10_read(port & ~1) >> 8; + return wd76c10_read(port) & 0xff; +} + +void wd76c10_writeb(uint16_t port, uint8_t val) +{ + uint16_t temp = wd76c10_read(port); + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8)); + else + wd76c10_write(port , (temp & 0xff00) | val); +} + +void wd76c10_init() +{ + io_sethandler(0x0092, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL); + io_sethandler(0x2072, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL); + io_sethandler(0x2872, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL); + io_sethandler(0x5872, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL); +} diff --git a/src/wd76c10.h b/src/wd76c10.h new file mode 100644 index 00000000..70ed1c96 --- /dev/null +++ b/src/wd76c10.h @@ -0,0 +1 @@ +void wd76c10_init(); diff --git a/src/win-d3d.cc b/src/win-d3d.cc new file mode 100644 index 00000000..77be9fa4 --- /dev/null +++ b/src/win-d3d.cc @@ -0,0 +1,225 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-d3d.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +void d3d_blit_memtoscreen_8(int x, int y, int w, int h); + +LPDIRECT3D9 d3d = NULL; +LPDIRECT3DDEVICE9 d3ddev = NULL; +LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +LPDIRECT3DTEXTURE9 d3dTexture = NULL; +D3DPRESENT_PARAMETERS d3dpp; + +HWND d3d_hwnd; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + DWORD color; // from the D3DFVF_DIFFUSE flag + FLOAT tu, tv; +}; + +CUSTOMVERTEX OurVertices[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 255), 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(0, 255, 0), 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, D3DCOLOR_XRGB(255, 0, 0), 1.0f, 1.0f}, +}; + +void d3d_init(HWND h) +{ + VOID* pVoid; // the void pointer + D3DLOCKED_RECT dr; + RECT r; + int x, y; + uint32_t *p; + + d3d_hwnd = h; + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = D3DPRESENTFLAG_VIDEO; + d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP; + d3dpp.hDeviceWindow = h; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0,D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0,D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + // create the vertex and store the pointer into v_buffer, which is created globally + d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + + v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy the vertices to the locked buffer + v_buffer->Unlock(); // unlock the vertex buffer + + d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + r.top = r.left = 0; + r.bottom = r.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (y = 0; y < 2048; y++) + { + p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + for (x = 0; x < 2048; x++) + { + p[x] = x + (y << 11); + } + } + + d3dTexture->UnlockRect(0); + +// atexit(d3d_close); + + video_blit_memtoscreen = d3d_blit_memtoscreen; + video_blit_memtoscreen_8 = d3d_blit_memtoscreen_8; +} + +void d3d_resize(int x, int y) +{ +// d3d_close(); +// d3d_init(d3d_hwnd); + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + d3ddev->Reset(&d3dpp); +} + +void d3d_close() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } +} + +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + VOID* pVoid; + float xmax, ymax; + D3DLOCKED_RECT dr; + RECT r; + uint32_t *p, *src; + int yy; + + xmax = (float)w / 2048.0; + ymax = (float)h / 2048.0; + + OurVertices[1].tu = OurVertices[4].tu = OurVertices[5].tu = xmax; + OurVertices[1].tv = OurVertices[2].tv = OurVertices[5].tv = ymax; + + GetClientRect(d3d_hwnd, &r); + OurVertices[1].x = OurVertices[4].x = OurVertices[5].x = r.right - r.left; + OurVertices[1].y = OurVertices[2].y = OurVertices[5].y = r.bottom - r.top; + + //pclog("Window %i, %i\n", + + v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy the vertices to the locked buffer + v_buffer->Unlock(); // unlock the vertex buffer + // clear the window to a deep blue + //d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0); + + r.top = y1; + r.left = 0; + r.bottom = y2; + r.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy(dr.pBits + (yy * dr.Pitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + + d3dTexture->UnlockRect(0); + + +// d3dpp.BackBufferWidth = r.right - r.left; +// d3dpp.BackBufferHeight = r.bottom - r.top; + +// d3ddev->Reset(&d3dpp); + + d3ddev->BeginScene(); // begins the 3D scene + + d3ddev->SetTexture( 0, d3dTexture ); + // select which vertex format we are using + d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + + // select the vertex buffer to display + d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + // copy the vertex buffer to the back buffer + d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + d3ddev->SetTexture( 0, NULL ); + + d3ddev->EndScene(); // ends the 3D scene + + d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); // displays the created frame +} + +void d3d_blit_memtoscreen_8(int x, int y, int w, int h) +{ + // clear the window to a deep blue + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 40, 100), 1.0f, 0); + + d3ddev->BeginScene(); // begins the 3D scene + + // do 3D rendering on the back buffer here + + d3ddev->EndScene(); // ends the 3D scene + + d3ddev->Present(NULL, NULL, NULL, NULL); // displays the created frame +} diff --git a/src/win-d3d.h b/src/win-d3d.h new file mode 100644 index 00000000..a7c17876 --- /dev/null +++ b/src/win-d3d.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + void d3d_init(HWND h); + void d3d_close(); + void d3d_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/win-ddraw.cc b/src/win-ddraw.cc new file mode 100644 index 00000000..3790c3f3 --- /dev/null +++ b/src/win-ddraw.cc @@ -0,0 +1,291 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void ddraw_init(HWND h); +extern "C" void ddraw_close(); +extern "C" void ddraw_draw(); + +LPDIRECTDRAW lpdd = NULL; +LPDIRECTDRAW4 lpdd4 = NULL; +LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; +LPDIRECTDRAWSURFACE4 lpdds_back = NULL; +LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; +LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +DDSURFACEDESC2 ddsd; + +HWND ddraw_hwnd; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +void ddraw_init(HWND h) +{ + int c; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + fatal("DirectDrawCreate failed\n"); + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) + fatal("QueryInterface failed\n"); + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_NORMAL))) + fatal("SetCooperativeLevel failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) + fatal("CreateSurface failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) + fatal("CreateSurface back failed\n"); + + if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) + fatal("CreateClipper failed\n"); + if (FAILED(lpdd_clipper->SetHWnd(0, h))) + fatal("SetHWnd failed\n"); + if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) + fatal("SetClipper failed\n"); + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen = ddraw_blit_memtoscreen; + video_blit_memtoscreen_8 = ddraw_blit_memtoscreen_8; +} + +void ddraw_close() +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd4) + { + lpdd4->Release(); + lpdd4 = NULL; + } +} + +void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + +// pclog("Blit memtoscreen %i,%i %i %i %i,%i\n", x, y, y1, y2, w, h); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + fullchange = changeframecount; + } + if (!ddsd.lpSurface) return; + for (yy = y1; yy < y2; yy++) + memcpy(ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + fullchange = changeframecount; + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + } + lpdds_back2->Unlock(NULL); + +// pclog("Blit from %i,%i %i,%i to %i,%i %i,%i\n", r_src.left, r_src.top, r_src.right, r_src.bottom, r_dest.left, r_dest.top, r_dest.right, r_dest.bottom); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + fullchange = changeframecount; + } + if (!ddsd.lpSurface) return; + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + p = (uint32_t *)(ddsd.lpSurface + (4 * ddsd.lPitch)); + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + fullchange = changeframecount; + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + lpdds_back2->Unlock(NULL); + } + + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} diff --git a/src/win-ddraw.h b/src/win-ddraw.h new file mode 100644 index 00000000..22a8c13f --- /dev/null +++ b/src/win-ddraw.h @@ -0,0 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + void ddraw_init(HWND h); + void ddraw_close(); + + void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); + void ddraw_blit_memtoscreen_8(int x, int y, int w, int h); +#ifdef __cplusplus +} +#endif + diff --git a/src/win-keyboard.cc b/src/win-keyboard.cc new file mode 100644 index 00000000..ec35bb31 --- /dev/null +++ b/src/win-keyboard.cc @@ -0,0 +1,109 @@ +#include +#include +#include +#define DIRECTINPUT_VERSION 0x0700 +#include +#include "plat-keyboard.h" +#include "win.h" + +extern "C" int key[256]; +uint8_t dinput_key[256]; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void keyboard_init(); +extern "C" void keyboard_close(); +extern "C" void keyboard_poll(); + +LPDIRECTINPUT lpdi = NULL; +LPDIRECTINPUTDEVICE lpdi_key = NULL; + +static int keyboard_lookup[256] = +{ + -1, DIK_ESCAPE, DIK_1, DIK_2, DIK_3, DIK_4, DIK_5, DIK_6, /*00*/ + DIK_7, DIK_8, DIK_9, DIK_0, DIK_MINUS, DIK_EQUALS, DIK_BACKSPACE, DIK_TAB, /*08*/ + DIK_Q, DIK_W, DIK_E, DIK_R, DIK_T, DIK_Y, DIK_U, DIK_I, /*10*/ + DIK_O, DIK_P, DIK_LBRACKET, DIK_RBRACKET, DIK_RETURN, DIK_LCONTROL, DIK_A, DIK_S, /*18*/ + DIK_D, DIK_F, DIK_G, DIK_H, DIK_J, DIK_K, DIK_L, DIK_SEMICOLON,/*20*/ + DIK_APOSTROPHE, DIK_GRAVE, DIK_LSHIFT, DIK_BACKSLASH, DIK_Z, DIK_X, DIK_C, DIK_V, /*28*/ + DIK_B, DIK_N, DIK_M, DIK_COMMA, DIK_PERIOD, DIK_SLASH, DIK_RSHIFT, DIK_MULTIPLY, /*30*/ + DIK_LMENU, DIK_SPACE, DIK_CAPSLOCK, DIK_F1, DIK_F2, DIK_F3, DIK_F4, DIK_F5, /*38*/ + DIK_F6, DIK_F7, DIK_F8, DIK_F9, DIK_F10, DIK_NUMLOCK, DIK_SCROLL, DIK_NUMPAD7, /*40*/ + DIK_NUMPAD8, DIK_NUMPAD9, DIK_NUMPADMINUS, DIK_NUMPAD4, DIK_NUMPAD5, DIK_NUMPAD6, DIK_NUMPADPLUS, DIK_NUMPAD1, /*48*/ + DIK_NUMPAD2, DIK_NUMPAD3, DIK_NUMPAD0, DIK_DECIMAL, DIK_SYSRQ, -1, DIK_OEM_102, DIK_F11, /*50*/ + DIK_F12, -1, -1, DIK_LWIN, DIK_RWIN, DIK_LMENU, -1, -1, /*58*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*60*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*68*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*70*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*78*/ + + -1, -1, -1, -1, -1, -1, -1, -1, /*80*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*88*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*90*/ + -1, -1, -1, -1, DIK_NUMPADENTER, DIK_RCONTROL, -1, -1, /*98*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*a0*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*a8*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*b0*/ + DIK_RMENU, -1, -1, -1, -1, -1, -1, -1, /*b8*/ + -1, -1, -1, -1, -1, -1, -1, DIK_HOME, /*c0*/ + DIK_UP, DIK_PRIOR, -1, DIK_LEFT, -1, DIK_RIGHT, -1, DIK_END, /*c8*/ + DIK_DOWN, DIK_NEXT, DIK_INSERT, DIK_DELETE, -1, -1, -1, -1, /*d0*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*d8*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*e0*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*e8*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*f0*/ + -1, -1, -1, -1, -1, -1, -1, DIK_PAUSE, /*f8*/ + +}; + +void keyboard_init() +{ + atexit(keyboard_close); + + if (FAILED(DirectInputCreate(hinstance, DIRECTINPUT_VERSION, &lpdi, NULL))) + fatal("install_keyboard : DirectInputCreate failed\n"); + if (FAILED(lpdi->CreateDevice(GUID_SysKeyboard, &lpdi_key, NULL))) + fatal("install_keyboard : CreateDevice failed\n"); + if (FAILED(lpdi_key->SetCooperativeLevel(ghwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE))) + fatal("install_keyboard : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_key->SetDataFormat(&c_dfDIKeyboard))) + fatal("install_keyboard : SetDataFormat failed\n"); + if (FAILED(lpdi_key->Acquire())) + fatal("install_keyboard : Acquire failed\n"); + + memset(key, 0, sizeof(key)); +} + +void keyboard_close() +{ + if (lpdi_key) + { + lpdi_key->Release(); + lpdi_key = NULL; + } + if (lpdi) + { + lpdi->Release(); + lpdi = NULL; + } +} + +void keyboard_poll_host() +{ + int c; + if (FAILED(lpdi_key->GetDeviceState(256, (LPVOID)dinput_key))) + { + lpdi_key->Acquire(); + lpdi_key->GetDeviceState(256, (LPVOID)dinput_key); + } + for (c = 0; c < 256; c++) + { + if (dinput_key[c] & 0x80) pclog("Dinput key down %i %02X\n", c, c); + if (keyboard_lookup[c] != -1) + { + key[c] = dinput_key[keyboard_lookup[c]] & 0x80; + if (key[c]) pclog("Key down %i %02X %i %02X\n", c, c, keyboard_lookup[c], keyboard_lookup[c]); + } + } +} diff --git a/src/win-mouse.cc b/src/win-mouse.cc new file mode 100644 index 00000000..08f493fc --- /dev/null +++ b/src/win-mouse.cc @@ -0,0 +1,72 @@ +#include +#include "plat-mouse.h" +#include "plat-dinput.h" +#include "win.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void mouse_init(); +extern "C" void mouse_close(); +extern "C" void poll_mouse(); +extern "C" void position_mouse(int x, int y); +extern "C" void get_mouse_mickeys(int *x, int *y); + +static LPDIRECTINPUTDEVICE lpdi_mouse = NULL; +static DIMOUSESTATE mousestate; +static int mouse_x = 0, mouse_y = 0; +int mouse_b = 0; + +void mouse_init() +{ + atexit(mouse_close); + + if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) + fatal("mouse_init : CreateDevice failed\n"); + if (FAILED(lpdi_mouse->SetCooperativeLevel(ghwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE))) + fatal("mouse_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) + fatal("mouse_init : SetDataFormat failed\n"); + if (FAILED(lpdi_mouse->Acquire())) + fatal("mouse_init : Acquire failed\n"); +} + +void mouse_close() +{ + if (lpdi_mouse) + { + lpdi_mouse->Release(); + lpdi_mouse = NULL; + } +} + +void poll_mouse() +{ + if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate))) + { + lpdi_mouse->Acquire(); + lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); + } + mouse_b = 0; + if (mousestate.rgbButtons[0] & 0x80) + mouse_b |= 1; + if (mousestate.rgbButtons[1] & 0x80) + mouse_b |= 2; + if (mousestate.rgbButtons[2] & 0x80) + mouse_b |= 4; + mouse_x += mousestate.lX; + mouse_y += mousestate.lY; + if (!mousecapture) + mouse_x = mouse_y = mouse_b = 0; +} + +void position_mouse(int x, int y) +{ +} + +void get_mouse_mickeys(int *x, int *y) +{ + *x = mouse_x; + *y = mouse_y; + mouse_x = mouse_y = 0; +} diff --git a/src/win-opengl.c b/src/win-opengl.c new file mode 100644 index 00000000..3f1cc902 --- /dev/null +++ b/src/win-opengl.c @@ -0,0 +1,148 @@ +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include +#include "ibm.h" +#include "video.h" +#include "win-opengl.h" + +HDC hDC=NULL; // Private GDI Device Context +HGLRC hRC=NULL; // Permanent Rendering Context +HWND opengl_hwnd; + + +void opengl_init(HWND h) +{ + GLuint PixelFormat; + PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 16, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // No Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 16, // 16Bit Z-Buffer (Depth Buffer) + 0, // No Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + if (!(hDC = GetDC(h))) + fatal("Couldn't get DC\n"); + if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) + fatal("Couldn't choose pixel format\n"); + if (!SetPixelFormat(hDC, PixelFormat, &pfd)) + fatal("Couldn't set pixel format\n"); + if (!(hRC = wglCreateContext(hDC))) + fatal("Couldn't create rendering context\n"); + if (!wglMakeCurrent(hDC, hRC)) + fatal("Couldn't set rendering context\n"); + + ShowWindow(h, SW_SHOW); + + glViewport(0, 0, 200, 200); // Reset The Current Viewport + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + glLoadIdentity(); // Reset The Projection Matrix + + // Calculate The Aspect Ratio Of The Window + gluPerspective(45.0f, (GLfloat)200/(GLfloat)200, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + glLoadIdentity(); // Reset The Modelview Matrix + + glShadeModel(GL_SMOOTH); // Enable Smooth Shading + glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background + glClearDepth(1.0f); // Depth Buffer Setup + glEnable(GL_DEPTH_TEST); // Enables Depth Testing + glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations + + glDisable(GL_ALPHA_TEST); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDisable(GL_POLYGON_SMOOTH); + glDisable(GL_STENCIL_TEST); + glEnable(GL_DITHER); + glDisable(GL_TEXTURE_2D); + glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glClearColor(0.0, 0.0, 0.0, 0.0); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + + opengl_hwnd = h; + atexit(opengl_close); + pclog("opengl_init\n"); +} + +void opengl_close() +{ + pclog("opengl_close\n"); + if (hRC) + { + wglMakeCurrent(NULL, NULL); + wglDeleteContext(hRC); + hRC = NULL; + } + if (hDC) + { + ReleaseDC(opengl_hwnd, hDC); + hDC = NULL; + } +} + +void opengl_resize(int x, int y) +{ + x = y = 200; + glViewport(0, 0, x, y); // Reset The Current Viewport + + glMatrixMode(GL_PROJECTION); // Select The Projection Matrix + glLoadIdentity(); // Reset The Projection Matrix + + // Calculate The Aspect Ratio Of The Window + gluPerspective(45.0f, (GLfloat)x/(GLfloat)y, 0.1f, 100.0f); + + glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix + glLoadIdentity(); // Reset The Modelview Matrix +} + +void opengl_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + pclog("blit memtoscreen\n"); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer + glLoadIdentity(); // Reset The Current Modelview Matrix + glColor3f(1.0f, 1.0f, 0.0f); + glTranslatef(-1.5f,0.0f,-6.0f); // Move Left 1.5 Units And Into The Screen 6.0 + glBegin(GL_TRIANGLES); // Drawing Using Triangles + glVertex3f( 0.0f, 1.0f, 0.0f); // Top + glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left + glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right + glEnd(); // Finished Drawing The Triangle + glTranslatef(3.0f,0.0f,0.0f); // Move Right 3 Units + glBegin(GL_QUADS); // Draw A Quad + glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left + glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right + glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right + glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left + glEnd(); // Done Drawing The Quad + + SwapBuffers(hDC); +} + +void opengl_blit_memtoscreen_8(int x, int y, int w, int h) +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + SwapBuffers(hDC); +} diff --git a/src/win-opengl.h b/src/win-opengl.h new file mode 100644 index 00000000..fac97675 --- /dev/null +++ b/src/win-opengl.h @@ -0,0 +1,3 @@ +void opengl_init(HWND h); +void opengl_close(); +void opengl_resize(int x, int y); diff --git a/src/win-timer.c b/src/win-timer.c new file mode 100644 index 00000000..71bfeffc --- /dev/null +++ b/src/win-timer.c @@ -0,0 +1,8 @@ +int BPS_TO_TIMER(int a) +{ + return a; +} + +void install_int_ex(void (*rout)(), int a) +{ +} diff --git a/src/win-video.c b/src/win-video.c new file mode 100644 index 00000000..1df1a894 --- /dev/null +++ b/src/win-video.c @@ -0,0 +1,49 @@ +#include +#include "video.h" + +BITMAP *screen; + +void hline(BITMAP *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + +void blit(BITMAP *src, BITMAP *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + +void stretch_blit(BITMAP *src, BITMAP *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + +void rectfill(BITMAP *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + +void set_palette(PALETTE p) +{ +} + +void destroy_bitmap(BITMAP *b) +{ +} + +BITMAP *create_bitmap(int x, int y) +{ + BITMAP *b = malloc(sizeof(BITMAP) + (y * sizeof(uint8_t *))); + int c; + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + { + b->line[c] = b->dat + (c * x * 4); + } + b->w = x; + b->h = y; + return b; +} diff --git a/src/win.c b/src/win.c new file mode 100644 index 00000000..898ddfdf --- /dev/null +++ b/src/win.c @@ -0,0 +1,1644 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include + +#include + +#include +#include +#include +#include +#include "ibm.h" +#include "video.h" +#include "resources.h" +#include "ide.h" + +#include "plat-keyboard.h" + +#include "win-ddraw.h" +//#include "win-d3d.h" +//#include "win-opengl.h" + +#define TIMER_1SEC 1 + +int winsizex=640,winsizey=480; +int svgapresent, et4000w32_present, bahamas64_present, n9_9fx_present; +int wakeups,wokeups; +#undef cs +CRITICAL_SECTION cs; +void waitmain(); +void vsyncint(); +int vgapresent; + +int cursoron = 1; + +HANDLE soundthreadh; +HANDLE blitthreadh; +HANDLE mainthreadh; + +void soundthread(LPVOID param); +void endmainthread(); +void endsoundthread(); +void silencesound(); +void restoresound(); +static HANDLE soundobject; + +static HANDLE frameobject; + +int infocus=1; + +int drawits=0; +void vsyncint() +{ +// if (infocus) +// { + drawits++; + wakeups++; + SetEvent(frameobject); +// } +} + +int romspresent[25]; +int quited=0; + +RECT oldclip,pcclip; +int mousecapture=0; +int drawit; +/* Declare Windows procedure */ +LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); + +/* Make the class name into a global variable */ +char szClassName[ ] = "WindowsApp"; + +HWND ghwnd; +void updatewindowsize(int x, int y) +{ + RECT r; + if (vid_resize) return; + winsizex=x; winsizey=y; + GetWindowRect(ghwnd,&r); + MoveWindow(ghwnd,r.left,r.top, + x+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), + y+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, + TRUE); +// startblit(); +// d3d_resize(x, y); +// endblit(); +} + +void releasemouse() +{ + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture = 0; + } +} + +static LARGE_INTEGER counter_base; +static LARGE_INTEGER counter_freq; +static LARGE_INTEGER counter_pos; +static LARGE_INTEGER counter_posold; + +void setrefresh(int rate) +{ + return; + remove_int(vsyncint); + drawit=0; + install_int_ex(vsyncint,BPS_TO_TIMER(rate)); +/* printf("Vsyncint at %i hz\n",rate); + counter_freq.QuadPart=counter_base.QuadPart/rate;*/ +// DeleteTimerQueueTimer( &hTimer, hTimerQueue, NULL); +// CreateTimerQueueTimer( &hTimer, hTimerQueue, +// mainroutine, NULL , 100, 1000/rate, 0); +} + +void startblit() +{ + EnterCriticalSection(&cs); +} + +void endblit() +{ + LeaveCriticalSection(&cs); +} + +int mainthreadon=0; + +/*static HANDLE blitobject; +void blitthread(LPVOID param) +{ + while (!quited) + { + WaitForSingleObject(blitobject,100); + if (quited) break; + doblit(); + } +} + +void wakeupblit() +{ + SetEvent(blitobject); +}*/ + +HWND statushwnd; +int statusopen=0; +extern int updatestatus; +extern int sreadlnum, swritelnum, segareads, segawrites, scycles_lost; + +int pause=0; + +void mainthread(LPVOID param) +{ + int t = 0; + DWORD old_time, new_time; + mainthreadon=1; +// Sleep(500); + drawits=0; + old_time = GetTickCount(); + while (!quited) + { +// if (infocus) +// { +/* if (!drawits) + { + while (!drawits) + { + ResetEvent(frameobject); + WaitForSingleObject(frameobject,10); + } + }*/ + if (updatestatus) + { + updatestatus=0; + if (statusopen) SendMessage(statushwnd,WM_USER,0,0); + } + new_time = GetTickCount(); + drawits += new_time - old_time; + old_time = new_time; + if (drawits > 0 && !pause) + { +// printf("Drawits %i\n",drawits); + drawits-=10; + if (drawits>50) drawits=0; + wokeups++; + startblit(); + runpc(); +// ddraw_draw(); + endblit(); +//#if 0 +//#endif + } + else + { +// Sleep(1); + } +// } + } + mainthreadon=0; +} + +HMENU menu; + +static void initmenu(void) +{ + int c; + HMENU m; + char s[32]; + m=GetSubMenu(menu,2); /*Settings*/ + m=GetSubMenu(m,1); /*CD-ROM*/ + + /* Loop through each Windows drive letter and test to see if + it's a CDROM */ + for (c='A';c<='Z';c++) + { + sprintf(s,"%c:\\",c); + if (GetDriveType(s)==DRIVE_CDROM) + { + sprintf(s, "Host CD/DVD Drive (%c:)", c); + AppendMenu(m,MF_STRING,IDM_CDROM_REAL+c,s); + } + } +} + +HINSTANCE hinstance; + +void get_executable_name(char *s, int size) +{ + GetModuleFileName(hinstance, s, size); +} + +void set_window_title(char *s) +{ + SetWindowText(ghwnd, s); +} + +int WINAPI WinMain (HINSTANCE hThisInstance, + HINSTANCE hPrevInstance, + LPSTR lpszArgument, + int nFunsterStil) + +{ + HWND hwnd; /* This is the handle for our window */ + MSG messages; /* Here messages to the application are saved */ + WNDCLASSEX wincl; /* Data structure for the windowclass */ + int c,d; + FILE *f; + int oldinfocus=0; + + hinstance=hThisInstance; + /* The Window structure */ + wincl.hInstance = hThisInstance; + wincl.lpszClassName = szClassName; + wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof (WNDCLASSEX); + + /* Use default icon and mouse-pointer */ + wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); + wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW); + wincl.lpszMenuName = NULL; /* No menu */ + wincl.cbClsExtra = 0; /* No extra bytes after the window class */ + wincl.cbWndExtra = 0; /* structure or the window instance */ + /* Use Windows's default color as the background of the window */ + wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; + + /* Register the window class, and if it fails quit the program */ + if (!RegisterClassEx (&wincl)) + return 0; + + menu=LoadMenu(hThisInstance,TEXT("MainMenu")); + initmenu(); + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + "PCem v0.7", /* Title Text */ + WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */ + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where the window ends up on the screen */ + 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ + 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* The window is a child-window to desktop */ + menu, /* Menu */ + hThisInstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + /* Make the window visible on the screen */ + ShowWindow (hwnd, nFunsterStil); + +// win_set_window(hwnd); + + ghwnd=hwnd; + + ddraw_init(hwnd); +// d3d_init(hwnd); +// opengl_init(hwnd); + + initpc(); + + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + + if (!cdrom_enabled) + CheckMenuItem(menu, IDM_CDROM_DISABLED, MF_CHECKED); + else + CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); + CheckMenuItem(menu, IDM_KEY_ALLEGRO + kb_win, MF_CHECKED); + if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); + +// set_display_switch_mode(SWITCH_BACKGROUND); + + d=romset; + for (c=0;c<25;c++) + { + romset=c; + romspresent[c]=loadbios(); + pclog("romset %i - %i\n", c, romspresent[c]); + } + + for (c = 0; c < 25; c++) + { + if (romspresent[c]) + break; + } + if (c == 25) + { + MessageBox(hwnd,"No ROMs present!\nYou must have at least one romset to use PCem.","PCem fatal error",MB_OK); + return 0; + } + + romset=d; + c=loadbios(); + + if (!c) + { + if (romset!=-1) MessageBox(hwnd,"Configured romset not available.\nDefaulting to available romset.","PCemu error",MB_OK); + for (c=0;c<25;c++) + { + if (romspresent[c]) + { + romset=c; + loadbios(); + break; + } + } + } + + f=romfopen("roms/trident.bin","rb"); + if (f) + { + fclose(f); + vgapresent=1; + } + else + { + vgapresent=0; + if (gfxcard==GFX_TVGA) gfxcard=GFX_CGA; + } + f=romfopen("roms/et4000.bin","rb"); + if (f) + { + fclose(f); + svgapresent=1; + } + else + { + svgapresent=0; + if (gfxcard==GFX_ET4000) gfxcard=(svgapresent)?GFX_TVGA:GFX_CGA; + } + f=romfopen("roms/et4000w32.bin","rb"); + if (f) + { + fclose(f); + et4000w32_present=1; + } + else + { + et4000w32_present=0; + if (gfxcard==GFX_ET4000W32) gfxcard=(svgapresent)?GFX_TVGA:GFX_CGA; + } + f=romfopen("roms/bahamas64.bin","rb"); + if (f) + { + fclose(f); + bahamas64_present=1; + } + else + { + bahamas64_present=0; + if (gfxcard==GFX_BAHAMAS64) gfxcard=(svgapresent)?GFX_TVGA:GFX_CGA; + } + f=romfopen("roms/s3_764.bin","rb"); + if (f) + { + fclose(f); + n9_9fx_present=1; + } + else + { + n9_9fx_present=0; + if (gfxcard==GFX_N9_9FX) gfxcard=(svgapresent)?GFX_TVGA:GFX_CGA; + } + timeBeginPeriod(1); +// soundobject=CreateEvent(NULL, FALSE, FALSE, NULL); +// soundthreadh=CreateThread(NULL,0,soundthread,NULL,NULL,NULL); + + + atexit(releasemouse); +// atexit(endsoundthread); + drawit=0; +// QueryPerformanceFrequency(&counter_base); +/// QueryPerformanceCounter(&counter_posold); +// counter_posold.QuadPart*=100; + +InitializeCriticalSection(&cs); + frameobject=CreateEvent(NULL, FALSE, FALSE, NULL); + mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); +// atexit(endmainthread); +// soundthreadh=(HANDLE)_beginthread(soundthread,0,NULL); +// atexit(endsoundthread); + SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); + +// blitobject=CreateEvent(NULL, FALSE, FALSE, NULL); +// blitthreadh=(HANDLE)_beginthread(blitthread,0,NULL); + +// SetThreadPriority(soundthreadh, THREAD_PRIORITY_HIGHEST); + + drawit=0; + install_int_ex(vsyncint,BPS_TO_TIMER(100)); + + updatewindowsize(640, 480); +// focus=1; +// setrefresh(100); + +// ShowCursor(TRUE); + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (!quited) + { +/* if (infocus) + { + if (drawits) + { + drawits--; + if (drawits>10) drawits=0; + runpc(); + } +//; else +// sleep(0); + if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END] && mousecapture) + { + ClipCursor(&oldclip); + mousecapture=0; + } + }*/ + + while (GetMessage(&messages,NULL,0,0) && !quited) + { + if (messages.message==WM_QUIT) quited=1; + TranslateMessage(&messages); + DispatchMessage(&messages); + if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END] && mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + } + + quited=1; +// else +// sleep(10); + } + + startblit(); +// pclog("Sleep 1000\n"); + Sleep(200); +// pclog("TerminateThread\n"); + TerminateThread(blitthreadh,0); + TerminateThread(mainthreadh,0); +// pclog("Quited? %i\n",quited); +// pclog("Closepc\n"); + closepc(); +// pclog("dumpregs\n"); + timeEndPeriod(1); +// endsoundthread(); +// dumpregs(); + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + } +// pclog("Ending! %i %i\n",messages.wParam,quited); + return messages.wParam; +} + +char openfilestring[260]; +int getfile(HWND hwnd, char *f, char *fn) +{ + OPENFILENAME ofn; // common dialog box structure + char szFile[260]; // buffer for file name + BOOL r; + DWORD err; + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = openfilestring; + // + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + // +// ofn.lpstrFile[0] = '\0'; + strcpy(ofn.lpstrFile,fn); + ofn.nMaxFile = sizeof(openfilestring); + ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + + pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetOpenFileName(&ofn); + if (r) + { + pclog("GetOpenFileName return true\n"); + return 0; + } + pclog("GetOpenFileName return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + +int getsfile(HWND hwnd, char *f, char *fn) +{ + OPENFILENAME ofn; // common dialog box structure + char szFile[260]; // buffer for file name + BOOL r; + DWORD err; + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = openfilestring; + // + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + // +// ofn.lpstrFile[0] = '\0'; + strcpy(ofn.lpstrFile,fn); + ofn.nMaxFile = sizeof(openfilestring); + ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + + pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetSaveFileName(&ofn); + if (r) + { + pclog("GetSaveFileName return true\n"); + return 0; + } + pclog("GetSaveFileName return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + +extern int is486; +int romstolist[25], listtomodel[23], romstomodel[25], modeltolist[23]; +int vidtolist[10],listtovid[10]; + +int mem_list_to_size[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,32,48,64}; +int mem_size_to_list[]={0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12,13,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18}; + +#include "cpu.h" +#include "model.h" + +BOOL CALLBACK configdlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d; + int rom,gfx,mem,fpu; + int temp_cpu, temp_cpu_m, temp_model; +// pclog("Dialog msg %i %08X\n",message,message); + switch (message) + { + case WM_INITDIALOG: + pause=1; + h=GetDlgItem(hdlg,IDC_COMBO1); + for (c=0;c<25;c++) romstolist[c]=0; + c = d = 0; + while (models[c].id != -1) + { + pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); + if (romspresent[models[c].id]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[c].name); + modeltolist[c] = d; + listtomodel[d] = c; + romstolist[models[c].id] = d; + romstomodel[models[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, modeltolist[model], 0); + + h=GetDlgItem(hdlg,IDC_COMBO2); + for (c=0;c<6;c++) vidtolist[c]=0; + c=4; + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"CGA"); vidtolist[GFX_CGA]=0; listtovid[0]=0; + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"MDA"); vidtolist[GFX_MDA]=1; listtovid[1]=1; + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Hercules"); vidtolist[GFX_HERCULES]=2; listtovid[2]=2; + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"EGA"); vidtolist[GFX_EGA]=3; listtovid[3]=3; + if (vgapresent) { SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Trident 8900D"); vidtolist[GFX_TVGA]=c; listtovid[c]=GFX_TVGA; c++; } + if (svgapresent) { SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Tseng ET4000AX"); vidtolist[GFX_ET4000]=c; listtovid[c]=GFX_ET4000; c++; } + if (et4000w32_present) { SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Diamond Stealth 32"); vidtolist[GFX_ET4000W32]=c; listtovid[c]=GFX_ET4000W32; c++; } + if (bahamas64_present) { SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Paradise Bahamas 64"); vidtolist[GFX_BAHAMAS64]=c; listtovid[c]=GFX_BAHAMAS64; c++; } + if (n9_9fx_present) { SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Number Nine 9FX"); vidtolist[GFX_N9_9FX]=c; listtovid[c]=GFX_N9_9FX; c++; } + SendMessage(h,CB_SETCURSEL,vidtolist[gfxcard],0); + if (models[model].fixed_gfxcard) EnableWindow(h,FALSE); + + h=GetDlgItem(hdlg,IDC_COMBOCPUM); + c = 0; + while (models[romstomodel[romset]].cpu[c].cpus != NULL && c < 3) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[c].name); + c++; + } + EnableWindow(h,TRUE); + SendMessage(h, CB_SETCURSEL, cpu_manufacturer, 0); + if (c == 1) EnableWindow(h, FALSE); + else EnableWindow(h, TRUE); + + h=GetDlgItem(hdlg,IDC_COMBO3); + c = 0; + while (models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].cpu_type != -1) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].name); + c++; + } + EnableWindow(h,TRUE); + SendMessage(h, CB_SETCURSEL, cpu, 0); + + h=GetDlgItem(hdlg,IDC_COMBOSND); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"None"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"AdLib"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"SoundBlaster v1.0"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"SoundBlaster v1.5"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"SoundBlaster v2.0"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"SB Pro v1"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"SB Pro v2"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"SoundBlaster 16"); + SendMessage(h,CB_SETCURSEL,sbtype,0); + +// h=GetDlgItem(hdlg,IDC_CHECK2); +// SendMessage(h,BM_SETCHECK,ADLIB,0); + + h=GetDlgItem(hdlg,IDC_CHECK3); + SendMessage(h,BM_SETCHECK,GAMEBLASTER,0); + + h=GetDlgItem(hdlg,IDC_CHECK1); + SendMessage(h,BM_SETCHECK,FASTDISC,0); + + h=GetDlgItem(hdlg,IDC_CHECK2); + SendMessage(h,BM_SETCHECK,slowega,0); + + h=GetDlgItem(hdlg,IDC_CHECK4); + SendMessage(h,BM_SETCHECK,cga_comp,0); + + h=GetDlgItem(hdlg,IDC_COMBOCHC); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"A little"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"A bit"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Some"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"A lot"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Infinite"); + SendMessage(h,CB_SETCURSEL,cache,0); + + h=GetDlgItem(hdlg,IDC_COMBOSPD); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"8-bit"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Slow 16-bit"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Fast 16-bit"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Slow VLB/PCI"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Mid VLB/PCI"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"Fast VLB/PCI"); + SendMessage(h,CB_SETCURSEL,video_speed,0); + + h=GetDlgItem(hdlg,IDC_COMBOMEM); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"1 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"2 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"3 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"4 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"5 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"6 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"7 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"8 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"9 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"10 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"11 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"12 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"13 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"14 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"15 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"16 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"32 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"48 MB"); + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)"64 MB"); + SendMessage(h,CB_SETCURSEL,mem_size_to_list[mem_size-1],0); + + pclog("Init cpuspeed %i\n",cpuspeed); + + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h=GetDlgItem(hdlg,IDC_COMBO1); + temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; + + h=GetDlgItem(hdlg,IDC_COMBO2); + gfx=listtovid[SendMessage(h,CB_GETCURSEL,0,0)]; + + h=GetDlgItem(hdlg,IDC_COMBOMEM); + mem=mem_list_to_size[SendMessage(h,CB_GETCURSEL,0,0)]; + + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + fpu = (models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; + pclog("newcpu - %i %i %i %i\n",temp_cpu_m,temp_cpu,fpu,models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type); + + if (temp_model != model || gfx!=gfxcard || mem!=mem_size || fpu!=hasfpu) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK) + { + model = temp_model; + romset = model_getromset(); + gfxcard=gfx; + mem_size=mem; + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + + mem_resize(); + loadbios(); + resetpchard(); + } + else + { + EndDialog(hdlg,0); + pause=0; + return TRUE; + } + } + + h=GetDlgItem(hdlg,IDC_COMBOSPD); + video_speed = SendMessage(h,CB_GETCURSEL,0,0); + + h=GetDlgItem(hdlg,IDC_CHECK3); + GAMEBLASTER=SendMessage(h,BM_GETCHECK,0,0); + + h=GetDlgItem(hdlg,IDC_CHECK1); + FASTDISC=SendMessage(h,BM_GETCHECK,0,0); + + h=GetDlgItem(hdlg,IDC_CHECK4); + cga_comp=SendMessage(h,BM_GETCHECK,0,0); + + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + cpu_set(); + + h=GetDlgItem(hdlg,IDC_COMBOSND); + sbtype=SendMessage(h,CB_GETCURSEL,0,0); + + h=GetDlgItem(hdlg,IDC_COMBOCHC); + cache=SendMessage(h,CB_GETCURSEL,0,0); + mem_updatecache(); + + saveconfig(); + + speedchanged(); +// if (romset>2) cpuspeed=1; +// setpitclock(clocks[AT?1:0][cpuspeed][0]); +// if (cpuspeed) setpitclock(8000000.0); +// else setpitclock(4772728.0); + + case IDCANCEL: + EndDialog(hdlg,0); + pause=0; + return TRUE; + case IDC_COMBO1: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg,IDC_COMBO1); + temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; + + /*Enable/disable gfxcard list*/ + h = GetDlgItem(hdlg, IDC_COMBO2); + if (!models[temp_model].fixed_gfxcard) + { + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, gfxcard, 0); + } + else + EnableWindow(h, FALSE); + + /*Rebuild manufacturer list*/ + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[c].cpus != NULL && c < 3) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[c].name); + c++; + } + if (temp_cpu_m >= c) temp_cpu_m = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + if (c == 1) EnableWindow(h, FALSE); + else EnableWindow(h, TRUE); + + /*Rebuild CPU list*/ + h = GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) temp_cpu = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + } + break; + case IDC_COMBOCPUM: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + /*Rebuild CPU list*/ + h=GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) temp_cpu = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + } + break; + } + break; + + } + return FALSE; +} +static char hd_new_name[512]; +static int hd_new_spt, hd_new_hpc, hd_new_cyl; + +BOOL CALLBACK hdnewdlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + int c; + PcemHDC hd[2]; + int changeddrv=0; + FILE *f; + uint8_t buf[512]; + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_EDIT1); + sprintf(s, "%i", 63); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT2); + sprintf(s, "%i", 16); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT3); + sprintf(s, "%i", 511); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)""); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((511*16*63)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)hd_new_name); + if (!hd_new_name[0]) + { + MessageBox(ghwnd,"Please enter a valid filename","PCem error",MB_OK); + return TRUE; + } + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + MessageBox(ghwnd,"Drive has too many sectors (maximum is 63)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_hpc > 128) + { + MessageBox(ghwnd,"Drive has too many heads (maximum is 128)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_cyl > 16383) + { + MessageBox(ghwnd,"Drive has too many cylinders (maximum is 16383)","PCem error",MB_OK); + return TRUE; + } + + f = fopen64(hd_new_name, "wb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for write","PCem error",MB_OK); + return TRUE; + } + memset(buf, 0, 512); + for (c = 0; c < (hd_new_cyl * hd_new_hpc * hd_new_spt); c++) + fwrite(buf, 512, 1, f); + fclose(f); + + MessageBox(ghwnd,"Remember to partition and format the new drive","PCem",MB_OK); + + EndDialog(hdlg,1); + return TRUE; + case IDCANCEL: + EndDialog(hdlg,0); + return TRUE; + + case IDC_CFILE: + if (!getsfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + } + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h=GetDlgItem(hdlg,IDC_EDIT1); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].spt); + h=GetDlgItem(hdlg,IDC_EDIT2); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].hpc); + h=GetDlgItem(hdlg,IDC_EDIT3); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].tracks); + + h=GetDlgItem(hdlg,IDC_TEXT1); + sprintf(s,"Size : %imb",(((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +BOOL CALLBACK hdsizedlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + int c; + PcemHDC hd[2]; + int changeddrv=0; + FILE *f; + uint8_t buf[512]; + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_EDIT1); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT2); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT3); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", ((((uint64_t)hd_new_spt*(uint64_t)hd_new_hpc*(uint64_t)hd_new_cyl)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + MessageBox(ghwnd,"Drive has too many sectors (maximum is 63)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_hpc > 128) + { + MessageBox(ghwnd,"Drive has too many heads (maximum is 128)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_cyl > 16383) + { + MessageBox(ghwnd,"Drive has too many cylinders (maximum is 16383)","PCem error",MB_OK); + return TRUE; + } + + EndDialog(hdlg,1); + return TRUE; + case IDCANCEL: + EndDialog(hdlg,0); + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h=GetDlgItem(hdlg,IDC_EDIT1); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].spt); + h=GetDlgItem(hdlg,IDC_EDIT2); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].hpc); + h=GetDlgItem(hdlg,IDC_EDIT3); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].tracks); + + h=GetDlgItem(hdlg,IDC_TEXT1); + sprintf(s,"Size : %imb",(((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +static int hd_changed = 0; +BOOL CALLBACK hdconfdlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + int c; + PcemHDC hd[2]; + int changeddrv=0; + FILE *f; + off64_t sz; + switch (message) + { + case WM_INITDIALOG: + pause=1; + hd[0]=hdc[0]; + hd[1]=hdc[1]; + hd_changed = 0; + + h=GetDlgItem(hdlg,IDC_EDIT1); + sprintf(s,"%i",hdc[0].spt); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT2); + sprintf(s,"%i",hdc[0].hpc); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT3); + sprintf(s,"%i",hdc[0].tracks); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDITC); + SendMessage(h,WM_SETTEXT,0,(LPARAM)ide_fn[0]); + + h=GetDlgItem(hdlg,IDC_EDIT4); + sprintf(s,"%i",hdc[1].spt); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT5); + sprintf(s,"%i",hdc[1].hpc); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT6); + sprintf(s,"%i",hdc[1].tracks); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDITD); + SendMessage(h,WM_SETTEXT,0,(LPARAM)ide_fn[1]); + + h=GetDlgItem(hdlg,IDC_TEXT1); + sprintf(s,"Size : %imb",(((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + + h=GetDlgItem(hdlg,IDC_TEXT2); + sprintf(s,"Size : %imb",(((((uint64_t)hd[1].tracks*(uint64_t)hd[1].hpc)*(uint64_t)hd[1].spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + if (hd_changed) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK) + { + h=GetDlgItem(hdlg,IDC_EDIT1); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].spt); + h=GetDlgItem(hdlg,IDC_EDIT2); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].hpc); + h=GetDlgItem(hdlg,IDC_EDIT3); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].tracks); + h=GetDlgItem(hdlg,IDC_EDITC); + SendMessage(h,WM_GETTEXT,511,(LPARAM)ide_fn[0]); + + h=GetDlgItem(hdlg,IDC_EDIT4); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[1].spt); + h=GetDlgItem(hdlg,IDC_EDIT5); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[1].hpc); + h=GetDlgItem(hdlg,IDC_EDIT6); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[1].tracks); + h=GetDlgItem(hdlg,IDC_EDITD); + SendMessage(h,WM_GETTEXT,511,(LPARAM)ide_fn[1]); + + hdc[0] = hd[0]; + hdc[1] = hd[1]; + + saveconfig(); + + resetpchard(); + } + } + case IDCANCEL: + EndDialog(hdlg,0); + pause=0; + return TRUE; + + case IDC_CNEW: + if (DialogBox(hinstance,TEXT("HdNewDlg"),hdlg,hdnewdlgproc) == 1) + { + h=GetDlgItem(hdlg,IDC_EDIT1); + sprintf(s,"%i",hd_new_spt); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT2); + sprintf(s,"%i",hd_new_hpc); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT3); + sprintf(s,"%i",hd_new_cyl); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDITC); + SendMessage(h,WM_SETTEXT,0,(LPARAM)hd_new_name); + + h=GetDlgItem(hdlg,IDC_TEXT1); + sprintf(s,"Size : %imb",(((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_CFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance,TEXT("HdSizeDlg"),hdlg,hdsizedlgproc) == 1) + { + h=GetDlgItem(hdlg,IDC_EDIT1); + sprintf(s,"%i",hd_new_spt); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT2); + sprintf(s,"%i",hd_new_hpc); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT3); + sprintf(s,"%i",hd_new_cyl); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDITC); + SendMessage(h,WM_SETTEXT,0,(LPARAM)openfilestring); + + h=GetDlgItem(hdlg,IDC_TEXT1); + sprintf(s,"Size : %imb",(((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_DNEW: + if (DialogBox(hinstance,TEXT("HdNewDlg"),hdlg,hdnewdlgproc) == 1) + { + h=GetDlgItem(hdlg,IDC_EDIT4); + sprintf(s,"%i",hd_new_spt); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT5); + sprintf(s,"%i",hd_new_hpc); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT6); + sprintf(s,"%i",hd_new_cyl); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDITD); + SendMessage(h,WM_SETTEXT,0,(LPARAM)hd_new_name); + + h=GetDlgItem(hdlg,IDC_TEXT2); + sprintf(s,"Size : %imb",(((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_DFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance,TEXT("HdSizeDlg"),hdlg,hdsizedlgproc) == 1) + { + h=GetDlgItem(hdlg,IDC_EDIT4); + sprintf(s,"%i",hd_new_spt); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT5); + sprintf(s,"%i",hd_new_hpc); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDIT6); + sprintf(s,"%i",hd_new_cyl); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + h=GetDlgItem(hdlg,IDC_EDITD); + SendMessage(h,WM_SETTEXT,0,(LPARAM)openfilestring); + + h=GetDlgItem(hdlg,IDC_TEXT2); + sprintf(s,"Size : %imb",(((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h=GetDlgItem(hdlg,IDC_EDIT1); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].spt); + h=GetDlgItem(hdlg,IDC_EDIT2); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].hpc); + h=GetDlgItem(hdlg,IDC_EDIT3); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[0].tracks); + + h=GetDlgItem(hdlg,IDC_TEXT1); + sprintf(s,"Size : %imb",((((hd[0].tracks*hd[0].hpc)*hd[0].spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + return TRUE; + + case IDC_EDIT4: case IDC_EDIT5: case IDC_EDIT6: + h=GetDlgItem(hdlg,IDC_EDIT4); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[1].spt); + h=GetDlgItem(hdlg,IDC_EDIT5); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[1].hpc); + h=GetDlgItem(hdlg,IDC_EDIT6); + SendMessage(h,WM_GETTEXT,255,(LPARAM)s); + sscanf(s,"%i",&hd[1].tracks); + + h=GetDlgItem(hdlg,IDC_TEXT2); + sprintf(s,"Size : %imb",((((hd[1].tracks*hd[1].hpc)*hd[1].spt)*512)/1024)/1024); + SendMessage(h,WM_SETTEXT,0,(LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +BOOL CALLBACK statusdlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c; + int egasp; + char s[256]; + switch (message) + { + case WM_INITDIALOG: + statusopen=1; + case WM_USER: + sprintf(s,"CPU speed : %f MIPS",mips); + SendDlgItemMessage(hdlg,IDC_STEXT1,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"FPU speed : %f MFLOPS",flops); + SendDlgItemMessage(hdlg,IDC_STEXT2,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"Cache misses (read) : %i/sec",sreadlnum); + SendDlgItemMessage(hdlg,IDC_STEXT3,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"Cache misses (write) : %i/sec",swritelnum); + SendDlgItemMessage(hdlg,IDC_STEXT4,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"Video throughput (read) : %i bytes/sec",segareads); + SendDlgItemMessage(hdlg,IDC_STEXT5,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"Video throughput (write) : %i bytes/sec",segawrites); + SendDlgItemMessage(hdlg,IDC_STEXT6,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + egasp=(slowega)?egacycles:egacycles2; + sprintf(s,"Effective clockspeed : %iHz",clockrate-(sreadlnum*memwaitstate)-(swritelnum*memwaitstate)- scycles_lost); +// pclog("%i : %i %i %i %i : %i %i\n",clockrate,sreadlnum*memwaitstate,swritelnum*memwaitstate,segareads*egasp,segawrites*egasp,segawrites,egasp); + SendDlgItemMessage(hdlg,IDC_STEXT7,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"Timer 0 frequency : %fHz",pit_timer0_freq()); + SendDlgItemMessage(hdlg,IDC_STEXT8,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + if (chain4) sprintf(s,"VGA chained (possibly mode 13h)"); + else sprintf(s,"VGA unchained (possibly mode-X)"); + SendDlgItemMessage(hdlg,IDC_STEXT9,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + if (!video_bpp) sprintf(s,"VGA in text mode"); + else sprintf(s,"VGA colour depth : %i bpp", video_bpp); + SendDlgItemMessage(hdlg,IDC_STEXT10,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"VGA resolution : %i x %i", video_res_x, video_res_y); + SendDlgItemMessage(hdlg,IDC_STEXT11,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"SB frequency : %i Hz",sb_freq); + SendDlgItemMessage(hdlg,IDC_STEXT12,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + sprintf(s,"Video refresh rate : %i Hz", emu_fps); + SendDlgItemMessage(hdlg,IDC_STEXT13,WM_SETTEXT,(WPARAM)NULL,(LPARAM)s); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + statusopen=0; + EndDialog(hdlg,0); + return TRUE; + } + break; + } + return FALSE; +} + + +HHOOK hKeyboardHook; + +LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + if (nCode < 0 || nCode != HC_ACTION || !mousecapture) return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); + + KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam; + + if(p->vkCode==VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab + if(p->vkCode==VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab + if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys + if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape + BOOL bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed + if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape + + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); +} + +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HMENU hmenu; + RECT rect; + int c; + int x, y; + POINT po; +// pclog("Message %i %08X\n",message,message); + switch (message) + { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + break; + + case WM_COMMAND: +// pclog("WM_COMMAND %i\n",LOWORD(wParam)); + hmenu=GetMenu(hwnd); + switch (LOWORD(wParam)) + { + case IDM_FILE_RESET: + pause=1; + Sleep(100); + resetpc(); + pause=0; + drawit=1; + break; + case IDM_FILE_HRESET: + pause=1; + Sleep(100); + resetpchard(); + pause=0; + drawit=1; + break; + case IDM_FILE_EXIT: + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + case IDM_DISC_A: + if (!getfile(hwnd,"Disc image (*.IMG;*.IMA)\0*.IMG;*.IMA\0All files (*.*)\0*.*\0",discfns[0])) + { + savedisc(0); + loaddisc(0,openfilestring); + saveconfig(); + } + break; + case IDM_DISC_B: + if (!getfile(hwnd,"Disc image (*.IMG;*.IMA)\0*.IMG;*.IMA\0All files (*.*)\0*.*\0",discfns[1])) + { + savedisc(1); + loaddisc(1,openfilestring); + saveconfig(); + } + break; + case IDM_EJECT_A: + savedisc(0); + ejectdisc(0); + saveconfig(); + break; + case IDM_EJECT_B: + savedisc(1); + ejectdisc(1); + saveconfig(); + break; + case IDM_HDCONF: + DialogBox(hinstance,TEXT("HdConfDlg"),hwnd,hdconfdlgproc); + break; + case IDM_CONFIG: + DialogBox(hinstance,TEXT("ConfigureDlg"),hwnd,configdlgproc); + break; + case IDM_STATUS: + statushwnd=CreateDialog(hinstance,TEXT("StatusDlg"),hwnd,statusdlgproc); + ShowWindow(statushwnd,SW_SHOW); + break; + + case IDM_VID_RESIZE: + vid_resize=!vid_resize; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED); + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + GetWindowRect(hwnd,&rect); + SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + saveconfig(); + break; + case IDM_KEY_ALLEGRO: case IDM_KEY_WINDOWS: + CheckMenuItem(hmenu,LOWORD(wParam),MF_CHECKED); + CheckMenuItem(hmenu,LOWORD(wParam)^1,MF_UNCHECKED); +// if (kb_win && LOWORD(wParam)==IDM_KEY_ALLEGRO) install_keyboard(); +// if (!kb_win && LOWORD(wParam)==IDM_KEY_WINDOWS) remove_keyboard(); + kb_win=LOWORD(wParam)-IDM_KEY_ALLEGRO; + break; + + case IDM_CDROM_DISABLED: + if (cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED); + CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_UNCHECKED); + if (cdrom_enabled) + { + cdrom_enabled = 0; + saveconfig(); + resetpchard(); + } + break; + + case IDM_CDROM_EMPTY: + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + atapi->exit(); + ioctl_open(0); + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + cdrom_drive=0; + CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + } + break; + default: + if (LOWORD(wParam)>=IDM_CDROM_REAL && LOWORD(wParam)<(IDM_CDROM_REAL+100)) + { + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + atapi->exit(); + ioctl_open(LOWORD(wParam)-IDM_CDROM_REAL); + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + cdrom_drive = LOWORD(wParam) - IDM_CDROM_REAL; + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + } + } + break; + } + return 0; + + case WM_SETFOCUS: + infocus=1; + drawit=0; + // QueryPerformanceCounter(&counter_posold); +// ResetEvent(frameobject); +// restoresound(); +// pclog("Set focus!\n"); + break; + case WM_KILLFOCUS: + infocus=0; + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } +// silencesound(); +// pclog("Lost focus!\n"); + break; + + case WM_LBUTTONUP: + if (!mousecapture) + { + GetClipCursor(&oldclip); + GetWindowRect(hwnd,&pcclip); + pcclip.left+=GetSystemMetrics(SM_CXFIXEDFRAME)+10; + pcclip.right-=GetSystemMetrics(SM_CXFIXEDFRAME)+10; + pcclip.top+=GetSystemMetrics(SM_CXFIXEDFRAME)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+10; + pcclip.bottom-=GetSystemMetrics(SM_CXFIXEDFRAME)+10; + ClipCursor(&pcclip); + mousecapture=1; + ShowCursor(FALSE); + } + break; + + case WM_ENTERMENULOOP: +// if (key[KEY_ALT] || key[KEY_ALTGR]) return 0; + break; + + case WM_SIZE: + winsizex=lParam&0xFFFF; + winsizey=lParam>>16; +// startblit(); +// d3d_resize(winsizex, winsizey); +// endblit(); + break; + + case WM_TIMER: + if (wParam == TIMER_1SEC) + onesec(); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: +// if (mousecapture) + return 0; +// return DefWindowProc (hwnd, message, wParam, lParam); + + case WM_DESTROY: + UnhookWindowsHookEx( hKeyboardHook ); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + default: +// pclog("Def %08X %i\n",message,message); + return DefWindowProc (hwnd, message, wParam, lParam); + } + return 0; +} diff --git a/src/win.h b/src/win.h new file mode 100644 index 00000000..4506d168 --- /dev/null +++ b/src/win.h @@ -0,0 +1,3 @@ +extern HINSTANCE hinstance; +extern HWND ghwnd; +extern int mousecapture; diff --git a/src/x86.c b/src/x86.c new file mode 100644 index 00000000..aa32effa --- /dev/null +++ b/src/x86.c @@ -0,0 +1,3686 @@ +//1B64 - Vid_SetMode (Vid_Vesa.c) +//6689c - CONS_Printf +/*SHR AX,1 + + 4 clocks - fetch opcode + 4 clocks - fetch mod/rm + 2 clocks - execute 2 clocks - fetch opcode 1 + 2 clocks - fetch opcode 2 + 4 clocks - fetch mod/rm + 2 clocks - fetch opcode 1 2 clocks - execute + 2 clocks - fetch opcode 2 etc*/ +#include +#include "ibm.h" +#include "x86.h" +#include "mem.h" +#include "keyboard.h" + +int nextcyc=0; +int cycdiff; +int is8086=0; + +int memcycs; +int nopageerrors=0; +float cassettetime; + +void FETCHCOMPLETE(); + +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + +#undef readmemb +#undef readmemw +uint8_t readmemb(uint32_t a) +{ + if (a!=(cs+pc)) memcycs+=4; + if (readlookup2[(a)>>12]==0xFFFFFFFF) return readmembl(a); + else return ram[readlookup2[(a)>>12]+((a)&0xFFF)]; +} + +uint8_t readmembf(uint32_t a) +{ + if (readlookup2[(a)>>12]==0xFFFFFFFF) return readmembl(a); + else return ram[readlookup2[(a)>>12]+((a)&0xFFF)]; +} + +uint16_t readmemw(uint32_t s, uint16_t a) +{ + if (a!=(cs+pc)) memcycs+=(8>>is8086); + if ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF)) return readmemwl(s,a); + else return *((uint16_t *)(&ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)])); +} + +void refreshread() { /*pclog("Refreshread\n"); */FETCHCOMPLETE(); memcycs+=4; } + +#undef fetchea +#define fetchea() { rmdat=FETCH(); \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + +void writemembl(uint32_t addr, uint8_t val); +void writememb(uint32_t a, uint8_t v) +{ + memcycs+=4; + if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); + else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v; +} +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +void writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs+=(8>>is8086); + if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); + else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v; +} +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +void writememl(uint32_t s, uint32_t a, uint32_t v) +{ + if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); + else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v; +} + +int lldt=0; +int notpresent; +uint16_t oldflags; +void dumpregs(); +int incga; +uint32_t old8,old82,old83; +uint16_t oldcs; +int oldcpl; + +int dlE=0; +/*#define CS (cs>>4) +#define DS (ds>>4) +#define ES (es>>4) +#define SS (ss>>4)*/ + +//#define loadseg(a) ((a)<<4) + +int keyboardtimer; +int tempc; +int bxcheck=0,spcheck=0; +uint16_t getword(); +int count40=0; +int dosfunc; +uint8_t opcode; +int times=0; +uint16_t pc2,pc3; +int pit0=1; +int noint=0; + +int output=0; + +int shadowbios=0; + +int inint=0; +int ins=0; +//#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a)) + +int ssegs; + +int fetchcycles=0,memcycs,fetchclocks; + +uint8_t prefetchqueue[6]; +uint16_t prefetchpc; +int prefetchw=0; +inline uint8_t FETCH() +{ + uint8_t temp; +/* temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + if (prefetchw<=((is8086)?4:3)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + if (is8086 && (prefetchpc&1)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + } + }*/ + +// uint8_t temp=readmemb(cs+pc); +// if (output) printf("FETCH %04X %i\n",pc,fetchcycles); + if (prefetchw==0) //(fetchcycles<4) + { + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + fetchcycles=4; + temp=readmembf(cs+pc); + prefetchpc=pc=pc+1; +// if (output) printf(" FETCH %04X:%04X %02X %04X %04X %i\n",CS,pc-1,temp,pc,prefetchpc,prefetchw); + if (is8086 && (pc&1)) + { + prefetchqueue[0]=readmembf(cs+pc); +// if (output) printf(" PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + } + else + { + temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + prefetchw--; +// if (output) printf("PREFETCH %04X:%04X %02X %04X %04X %i\n",CS,pc,temp,pc,prefetchpc,prefetchw); + fetchcycles-=4; +// fetchclocks+=4; + pc++; + } +// if (output) printf("%i\n",fetchcycles); + return temp; +} + +inline void FETCHADD(int c) +{ + int d; +// if (output) printf("FETCHADD %i\n",c); + if (c<0) return; + if (prefetchw>((is8086)?4:3)) return; + d=c+(fetchcycles&3); + while (d>3 && prefetchw<((is8086)?6:4)) + { + d-=4; + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHED from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + } + fetchcycles+=c; + if (fetchcycles>16) fetchcycles=16; +// if (fetchcycles>24) fetchcycles=24; +} + +void FETCHCOMPLETE() +{ +// pclog("Fetchcomplete %i %i %i\n",fetchcycles&3,fetchcycles,prefetchw); + if (!(fetchcycles&3)) return; + if (prefetchw>((is8086)?4:3)) return; + if (!prefetchw) nextcyc=(4-(fetchcycles&3)); + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHEDc from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHEDc from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + fetchcycles+=(4-(fetchcycles&3)); +} + +inline void FETCHCLEAR() +{ +/* int c; + fetchcycles=0; + prefetchpc=pc; + if (is8086 && (prefetchpc&1)) cycles-=4; + for (c=0;c<((is8086)?6:4);c++) + { + prefetchqueue[c]=readmembf(cs+prefetchpc); + if (!is8086 || !(prefetchpc&1)) cycles-=4; + prefetchpc++; + } + prefetchw=(is8086)?6:4;*/ +// fetchcycles=0; + prefetchpc=pc; + prefetchw=0; + memcycs=cycdiff-cycles; + fetchclocks=0; +// memcycs=cycles; +/* prefetchqueue[0]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw=1; + if (is8086 && prefetchpc&1) + { + prefetchqueue[1]=readmembf(cs+prefetchpc); + prefetchpc++; + }*/ +} + +/*EA calculation*/ + +/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod + From 386 programmers manual : +r8(/r) AL CL DL BL AH CH DH BH +r16(/r) AX CX DX BX SP BP SI DI +r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI +/digit (Opcode) 0 1 2 3 4 5 6 7 +REG = 000 001 010 011 100 101 110 111 + ÚÄÄÄAddress +disp8 denotes an 8-bit displacement following the ModR/M byte, to be +sign-extended and added to the index. disp16 denotes a 16-bit displacement +following the ModR/M byte, to be added to the index. Default segment +register is SS for the effective addresses containing a BP index, DS for +other effective addresses. + ÄÄ¿ ÚMod R/M¿ ÚÄÄÄÄÄÄÄÄModR/M Values in HexadecimalÄÄÄÄÄÄÄÄ¿ + +[BX + SI] 000 00 08 10 18 20 28 30 38 +[BX + DI] 001 01 09 11 19 21 29 31 39 +[BP + SI] 010 02 0A 12 1A 22 2A 32 3A +[BP + DI] 011 03 0B 13 1B 23 2B 33 3B +[SI] 00 100 04 0C 14 1C 24 2C 34 3C +[DI] 101 05 0D 15 1D 25 2D 35 3D +disp16 110 06 0E 16 1E 26 2E 36 3E +[BX] 111 07 0F 17 1F 27 2F 37 3F + +[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 +[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 +[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A +[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B +[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C +[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D +[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E +[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F + +[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 +[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 +[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA +[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB +[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC +[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD +[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE +[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF + +EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 +ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 +EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA +EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB +ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC +EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD +ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE +EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF + +mod = 11 - register + 10 - address + 16 bit displacement + 01 - address + 8 bit displacement + 00 - address + +reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) + 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL + 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH + + Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB + selects whether BX/BP are used at all (0=used). + + mod=00 is an exception though + 6=16 bit displacement only + 7=[BX] + + Usage varies with instructions. + + MOV AL,BL has ModR/M as C3, for example. + mod=11, reg=0, r/m=3 + MOV uses reg as dest, and r/m as src. + reg 0 is AL, reg 3 is BL + + If BP or SP are in address calc, seg is SS, else DS +*/ + +int cycles=0; +uint32_t easeg,eaaddr; +int rm,reg,mod,rmdat; + +uint16_t zero=0; +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +int slowrm[8]; + +void makemod1table() +{ + mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; + mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; + mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; + mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; + slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; + mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; + mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; +} + +void fetcheal() +{ + if (!mod && rm==6) { eaaddr=getword(); easeg=ds; FETCHADD(6); } + else + { + switch (mod) + { + case 0: + eaaddr=0; + if (rm&4) FETCHADD(5); + else FETCHADD(7+slowrm[rm]); + break; + case 1: + eaaddr=(uint16_t)(int8_t)FETCH(); + if (rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[rm]); + break; + case 2: + eaaddr=getword(); + if (rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[rm]); + break; + } + eaaddr+=(*mod1add[0][rm])+(*mod1add[1][rm]); + easeg=*mod1seg[rm]; + eaaddr&=0xFFFF; + } +} + +/*void fetchea() +{ + rmdat=readmemb(cs+pc); pc++; + reg=(rmdat>>3)&7; + mod=rmdat>>6; + rm=rmdat&7; + switch (mod) + { + case 0: + switch (rm) + { + case 0: eaaddr=BX+SI; easeg=ds; if (!AT) cycles-=7; break; + case 1: eaaddr=BX+DI; easeg=ds; if (!AT) cycles-=8; break; + case 2: eaaddr=BP+SI; easeg=ss; if (!AT) cycles-=8; break; + case 3: eaaddr=BP+DI; easeg=ss; if (!AT) cycles-=7; break; + case 4: eaaddr=SI; easeg=ds; if (!AT) cycles-=5; break; + case 5: eaaddr=DI; easeg=ds; if (!AT) cycles-=5; break; + case 6: eaaddr=getword(); easeg=ds; if (!AT) cycles-=6; break; + case 7: eaaddr=BX; easeg=ds; if (!AT) cycles-=5; break; + } + if (AT && !(rm&4)) cycles--; + break; + + case 1: + eaaddr=readmemb(cs+pc); pc++; + if (eaaddr&0x80) eaaddr|=0xFF00; +// if (output) printf("EAADDR %04X ",eaaddr); + switch (rm) + { + case 0: eaaddr+=BX+SI; easeg=ds; if (!AT) cycles-=11; break; + case 1: eaaddr+=BX+DI; easeg=ds; if (!AT) cycles-=12; break; + case 2: eaaddr+=BP+SI; easeg=ss; if (!AT) cycles-=12; break; + case 3: eaaddr+=BP+DI; easeg=ss; if (!AT) cycles-=11; break; + case 4: eaaddr+=SI; easeg=ds; if (!AT) cycles-=9; break; + case 5: eaaddr+=DI; easeg=ds; if (!AT) cycles-=9; break; + case 6: eaaddr+=BP; easeg=ss; if (!AT) cycles-=9; break; + case 7: eaaddr+=BX; easeg=ds; if (!AT) cycles-=9; break; + } + if (AT && !(rm&4)) cycles--; +// if (output) printf("%04X %04X",eaaddr,BX); + break; + + case 2: + eaaddr=getword(); + switch (rm) + { + case 0: eaaddr+=BX+SI; easeg=ds; if (!AT) cycles-=11; break; + case 1: eaaddr+=BX+DI; easeg=ds; if (!AT) cycles-=12; break; + case 2: eaaddr+=BP+SI; easeg=ss; if (!AT) cycles-=12; break; + case 3: eaaddr+=BP+DI; easeg=ss; if (!AT) cycles-=11; break; + case 4: eaaddr+=SI; easeg=ds; if (!AT) cycles-=9; break; + case 5: eaaddr+=DI; easeg=ds; if (!AT) cycles-=9; break; + case 6: eaaddr+=BP; easeg=ss; if (!AT) cycles-=9; break; + case 7: eaaddr+=BX; easeg=ds; if (!AT) cycles-=9; break; + } + if (AT && !(rm&4)) cycles--; + break; + } + eaaddr&=0xFFFF; +}*/ + +static inline uint8_t geteab() +{ + if (mod==3) + return (rm&4)?regs[rm&3].b.h:regs[rm&3].b.l; + return readmemb(easeg+eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod==3) + return regs[rm].w; +// if (output==3) printf("GETEAW %04X:%08X\n",easeg,eaaddr); + return readmemw(easeg,eaaddr); +} + +static inline uint16_t geteaw2() +{ + if (mod==3) + return regs[rm].w; +// printf("Getting addr from %04X:%04X %05X\n",easeg,eaaddr+2,easeg+eaaddr+2); + return readmemw(easeg,(eaaddr+2)&0xFFFF); +} + +static inline void seteab(uint8_t val) +{ + if (mod==3) + { + if (rm&4) regs[rm&3].b.h=val; + else regs[rm&3].b.l=val; + } + else + { + writememb(easeg+eaaddr,val); + } +} + +static inline void seteaw(uint16_t val) +{ + if (mod==3) + regs[rm].w=val; + else + { + writememw(easeg,eaaddr,val); +// writememb(easeg+eaaddr+1,val>>8); + } +} + +#define getr8(r) ((r&4)?regs[r&3].b.h:regs[r&3].b.l) + +#define setr8(r,v) if (r&4) regs[r&3].b.h=v; \ + else regs[r&3].b.l=v; + + +/*Flags*/ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +void makeznptable() +{ + int c,d; + for (c=0;c<256;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable8[c]=0; + else + znptable8[c]=P_FLAG; + if (c == 0xb1) pclog("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) znptable8[c]|=Z_FLAG; + if (c&0x80) znptable8[c]|=N_FLAG; + } + for (c=0;c<65536;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable16[c]=0; + else + znptable16[c]=P_FLAG; + if (c == 0xb1) pclog("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) pclog("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) znptable16[c]|=Z_FLAG; + if (c&0x8000) znptable16[c]|=N_FLAG; + } +// isram[0xF]=1; +// printf("isram 0 = %i\n",isram[0]); + +// makemod1table(); +} +int timetolive=0; + +uint8_t cpu_readop(uint32_t addr) { return readmemb(addr); } +uint8_t cpu_readmem20(uint32_t addr) { return readmemb(addr); } + +void cpu_writemem20(uint32_t addr, uint8_t val) { writememb(addr,val); } + +uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +// pc+=2; +// return readmemw(cs,(pc-2)); +} + +uint16_t getword286() +{ + uint16_t temp=readmemw(cs,pc); pc+=2; + return temp; +} + +int ratio1=0,ratio2=0; + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +void dumpregs() +{ + FILE *f; + int c,d=0,e=0; +// return; + output=0; +// return; +// savenvr(); +/* printf("The ratio is %i %i\n",ratio1,ratio2); + for (c=0;c<256;c++) + { + printf("ISRAM : %06X %i\n",c<<16,isram[c]); + }*/ +// return; +chdir(pcempath); + nopageerrors=1; +/* f=fopen("rram3.dmp","wb"); + for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f); + fclose(f);*/ +/* f=fopen("ram.dmp","wb"); + fwrite(ram,mem_size*1024*1024,1,f); + fclose(f);*/ +/* f=fopen("rram.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c),f); + fclose(f); + f=fopen("rram2.dmp","wb"); + for (c=0;c<0x100000;c++) putc(readmemb(c+0xbff00000),f); + fclose(f); + f = fopen("stack.dmp","wb"); + for (c = 0; c < 0x6000; c++) putc(readmemb(c+0xFFDFA000), f); + fclose(f); + f = fopen("tempx.dmp","wb"); + for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFC816000), f); + fclose(f); + f = fopen("tempx2.dmp","wb"); + for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFDEF5000), f); + fclose(f);*/ +/* f=fopen("rram4.dmp","wb"); + for (c=0;c<0x3000000;c++) putc(readmemb(c+0x80000000),f); + fclose(f);*/ +/* f=fopen("rram5.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10000000),f); + fclose(f);*/ +/* f=fopen("rram6.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f); + fclose(f);*/ +/* f=fopen("ram6.bin","wb"); + fwrite(ram+0x10100,0xA000,1,f); + fclose(f); + f=fopen("boot.bin","wb"); + fwrite(ram+0x7C00,0x200,1,f); + fclose(f); + f=fopen("ram7.bin","wb"); + fwrite(ram+0x11100,0x2000,1,f); + fclose(f); + f=fopen("ram8.bin","wb"); + fwrite(ram+0x3D210,0x200,1,f); + fclose(f); */ +/* f=fopen("vram.dmp","wb"); + fwrite(vram,0x400000,1,f); + fclose(f); + f=fopen("bios.dmp","wb"); + fwrite(rom,0x20000,1,f); + fclose(f); + f=fopen("vbios.dmp","wb"); + fwrite(vrom,0x8000,1,f); + fclose(f);*/ +/* f=fopen("kernel.dmp","wb"); + for (c=0;c<0x200000;c++) putc(readmemb(c+0xC0000000),f); + fclose(f);*/ +/* f=fopen("rram.dmp","wb"); + for (c=0;c<0x1500000;c++) putc(readmemb(c),f); + fclose(f); + if (!times) + { + f=fopen("thing.dmp","wb"); + fwrite(ram+0x11E50,0x1000,1,f); + fclose(f); + }*/ + if (is386) + printf("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); + else + printf("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); + printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",pc,CS,DS,ES,SS,flags); + printf("%04X:%04X %04X:%04X %08X %08X %08X\n",oldcs,oldpc, oldcs2, oldpc2, old8,old82,old83); + printf("%i ins\n",ins); + if (is386) + printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + else + printf("In %s mode\n",(msw&1)?"protected":"real"); + printf("CS : base=%06X limit=%04X access=%02X\n",cs,_cs.limit,_cs.access); + printf("DS : base=%06X limit=%04X access=%02X\n",ds,_ds.limit,_ds.access); + printf("ES : base=%06X limit=%04X access=%02X\n",es,_es.limit,_es.access); + if (is386) + { + printf("FS : base=%06X limit=%04X access=%02X\n",fs,_fs.limit,_fs.access); + printf("GS : base=%06X limit=%04X access=%02X\n",gs,_gs.limit,_gs.access); + } + printf("SS : base=%06X limit=%04X access=%02X\n",ss,_ss.limit,_ss.access); + printf("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); + printf("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); + printf("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); + printf("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + if (is386) + { + printf("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); + printf("CR0=%08X CR2=%08X CR3=%08X\n",cr0,cr2,cr3); + } + printf("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); + for (c=0;c<1024*1024;c++) + { + if (readlookup2[c]!=0xFFFFFFFF) d++; + if (writelookup2[c]!=0xFFFFFFFF) e++; + } + printf("Entries in readlookup : %i writelookup : %i\n",d,e); + d=0; + x87_dumpregs(); +/* for (c=0;c<1024*1024;c++) + { + if (mmucache[c]!=0xFFFFFFFF) d++; + } + printf("Entries in MMU cache : %i\n",d);*/ +} + +int isAT; +int resets = 0; +void resetx86() +{ + pclog("x86 reset\n"); + resets++; + ins = 0; + use32=0; + stack32=0; +// i86_Reset(); +// cs=0xFFFF0; + pc=0; + msw=0; + cr0=0; + eflags=0; + cgate32=0; + loadcs(0xFFFF); + rammask=0xFFFFFFFF; + flags=2; + initmmucache(); + resetreadlookup(); + makemod1table(); + resetmcr(); + isAT=AT; + FETCHCLEAR(); + x87_reset(); + cpu_set_edx(); + ESP=0; + mmu_perm=4; +} + +void softresetx86() +{ +// dumpregs(); +// exit(-1); + use32=0; + stack32=0; +// i86_Reset(); +// cs=0xFFFF0; + pc=0; + msw=0; + cr0=0; + eflags=0; + cgate32=0; + loadcs(0xFFFF); + //rammask=0xFFFFFFFF; + flags=2; +} + +#undef AT +#define AT isAT + +extern int is486; +void setznp8(uint8_t val) +{ + flags&=~0xC4; + flags|=znptable8[val]; +} + +#define setznp168 setznp16 +void setznp16(uint16_t val) +{ + flags&=~0xC4; +// flags|=((val&0x8000)?N_FLAG:((!val)?Z_FLAG:0)); +// flags|=(((znptable8[val&0xFF]&P_FLAG)==(znptable8[val>>8]&P_FLAG))?P_FLAG:0); + flags|=znptable16[val]; +} + +/*void setznp168(uint16_t val) +{ + flags&=~0xC4; + flags|=(znptable16[val]&0xC0)|(znptable8[val&0xFF]&4); +}*/ + +void setadd8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +void setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +void setadd16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +void setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D4; + flags|=znptable16[c&0xFFFF]; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +void setsub8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsub16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; +// if (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG); + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + + +void clockhardware() +{ + cycdiff-=cycles; + + keybsenddelay--; + if (keybsenddelay<1) + { + keybsenddelay = 1000;//2500; + keyboard_poll(); + } + + pit.c[0]-=cycdiff; + pit.c[1]-=cycdiff; + if (ppi.pb&1) pit.c[2]-=cycdiff; + + if ((pit.c[0]<1)||(pit.c[1]<1)||(pit.c[2]<1)) pit_poll(); + + spktime-=cycdiff; + if (spktime<=0.0) + { + spktime+=SPKCONST; + pollspk(); + pollgussamp(); + getsbsamp(); + getdacsamp(); + polladlib(); + } + soundtime-=cycdiff; + if (soundtime<=0.0) + { + soundtime+=SOUNDCONST; + pollsound60hz(); + } + gustime-=cycdiff; + while (gustime<=0.0) + { + gustime+=GUSCONST; +// printf("1Poll GUS %f %f\n",gustime,GUSCONST); + pollgus(); +// printf("2Poll GUS\n"); + } + vidtime-=cycdiff; + if (vidtime<=0.0) + { + pollvideo(); +// polltandy(); +// pollmda(); +// pollcga(); + } + if (disctime) + { + disctime-=(cycdiff/2); + if (disctime<=0) + { + disctime=0; + fdc_poll(); + } + } + if (mousedelay) + { + mousedelay--; + if (!mousedelay) + mousecallback(); + } + if (sbenable) + { + sbcount-=cycdiff; + if (sbcount<0) + { + sbcount+=sblatcho; + pollsb(); + } + } + rtctime-=cycdiff; + if (rtctime<0) + { + nvr_rtc(); + } + cycdiff=cycles; + if (idecallback[0]) + { + idecallback[0]--; + if (idecallback[0]<=0) + { +// pclog("IDE time over\n"); + idecallback[0]=0; + callbackide(0); + } + } +} + + + int firstrepcycle=1; +void cpu_writeport(uint32_t port, uint8_t val) { outb(port,val); } +void rep(int fv) +{ + uint8_t temp; + int c=CX; + uint8_t temp2; + uint16_t tempw,tempw2,tempw3; + uint16_t ipc=oldpc;//pc-1; + int changeds=0; + uint32_t oldds; + startrep: + temp=FETCH(); +// if (firstrepcycle && temp==0xA5) printf("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (output) printf("REP %02X %04X\n",temp,ipc); + switch (temp) + { + case 0x08: + pc=ipc+1; + cycles-=2; + FETCHCLEAR(); + break; + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + while (c>0 && !IRQTEST) + { + temp2=readmemb(ds+SI); + writememb(es+DI,temp2); +// if (output) printf("Moved %02X from %04X:%04X to %04X:%04X\n",temp2,ds>>4,SI,es>>4,DI); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=((AT)?4:17); + clockhardware(); + FETCHADD(((AT)?4:17)-memcycs); + } + if (IRQTEST && c>0) pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// } + break; + case 0xA5: /*REP MOVSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=((AT)?4:17); + clockhardware(); + FETCHADD(((AT)?4:17)-memcycs); + } + if (IRQTEST && c>0) pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// } + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + temp=readmemb(ds+SI); + temp2=readmemb(es+DI); +// printf("CMPSB %c %c %i %05X %05X %04X:%04X\n",temp,temp2,c,ds+SI,es+DI,cs>>4,pc); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + if (!AT) cycles-=30; + else cycles-=9; + setsub8(temp,temp2); + clockhardware(); + FETCHADD(((AT)?9:30)-memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) pc=ipc; +// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + if (!AT) cycles-=30; + else cycles-=9; + setsub16(tempw,tempw2); + clockhardware(); + FETCHADD(((AT)?9:30)-memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) pc=ipc; +// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// if (firstrepcycle) printf("REP CMPSW %06X:%04X %06X:%04X %04X %04X\n",ds,SI,es,DI,tempw,tempw2); + break; + case 0xAA: /*REP STOSB*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=((AT)?3:10); + clockhardware(); + FETCHADD(((AT)?3:10)-memcycs); + } + if (IRQTEST && c>0) pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=((AT)?3:10); + clockhardware(); + FETCHADD(((AT)?3:10)-memcycs); + } + if (IRQTEST && c>0) pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// printf("REP STOSW %04X:%04X %04X:%04X %04X %04X\n",CS,pc,ES,DI,AX,CX); } + break; + case 0xAC: /*REP LODSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ + if (c>0) + { + tempw2=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es+DI); +// if (output) printf("SCASB %02X %c %02X %05X ",temp2,temp2,AL,es+DI); + setsub8(AL,temp2); +// if (output && flags&Z_FLAG) printf("Match %02X %02X\n",AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=((AT)?8:15); + } +//if (output) printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0)))); + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; +// cycles-=120; + break; + case 0xAF: /*REP SCASW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=((AT)?8:15); + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + default: + pc=ipc; + cycles-=20; + FETCHCLEAR(); +// printf("Bad REP %02X\n",temp); +// dumpregs(); +// exit(-1); + } + CX=c; + if (changeds) ds=oldds; +// if (pc==ipc) FETCHCLEAR(); +} + + +int inhlt=0; +uint16_t lastpc,lastcs; +int firstrepcycle; +int skipnextprint=0; + + +int instime=0,instimer=0; +//#if 0 +void execx86(int cycs) +{ + uint8_t temp,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + int tempws; + uint32_t templ; + int c; + int tempi; + int trap; + FILE *f; +// printf("Run x86! %i %i\n",cycles,cycs); + cycles+=cycs; +// i86_Execute(cycs); +// return; + while (cycles>0) + { +// old83=old82; +// old82=old8; +// old8=oldpc|(oldcs<<16); +// if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; } +// if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime); + cycdiff=cycles; + cycles-=nextcyc; +// if (instime) pclog("Cycles %i %i\n",cycles,cycdiff); + nextcyc=0; +// if (output) printf("CLOCK %i %i\n",cycdiff,cycles); + fetchclocks=0; + oldcs=CS; + oldpc=pc; + opcodestart: + opcode=FETCH(); + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + pc--; +// output=1; +// if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat); +//#if 0 + if (output && /*cs<0xF0000 && */!ssegs && (pc<0x43A || pc>0x44A))//opcode!=0x26 && opcode!=0x36 && opcode!=0x2E && opcode!=0x3E) + { + if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) + { + if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %02X %02X %02X %02X\n",cs,pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ram[0x413], ram[0x414], ram[0x415], ram[0x416]); + skipnextprint=0; +// ins++; + } + } +//#endif + pc++; + inhlt=0; +// if (ins==500000) { dumpregs(); exit(0); }*/ + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); +/* if (!rmdat) pc--; + if (!rmdat) + { + fatal("Crashed\n"); +// clear_keybuf(); +// readkey(); + }*/ + temp=geteab(); + setadd8(temp,getr8(reg)); + temp+=getr8(reg); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw=geteaw(); + setadd16(tempw,regs[reg].w); + tempw+=regs[reg].w; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x02: /*ADD reg,8*/ + fetchea(); + temp=geteab(); + setadd8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp); + cycles-=((mod==3)?3:13); + break; + case 0x03: /*ADD reg,16*/ + fetchea(); + tempw=geteaw(); + setadd16(regs[reg].w,tempw); + regs[reg].w+=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x04: /*ADD AL,#8*/ + temp=FETCH(); + setadd8(AL,temp); + AL+=temp; + cycles-=4; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getword(); + setadd16(AX,tempw); + AX+=tempw; + cycles-=4; + break; + + case 0x06: /*PUSH ES*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); + SP-=2; + cycles-=14; + break; + case 0x07: /*POP ES*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_es); + SP+=2; + cycles-=12; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp=geteab(); + temp|=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw|=regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x0A: /*OR reg,8*/ + fetchea(); + temp=geteab(); + temp|=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw|=regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x0C: /*OR AL,#8*/ + AL|=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x0E: /*PUSH CS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); + SP-=2; + cycles-=14; + break; + case 0x0F: /*POP CS - 8088/8086 only*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_cs); + SP+=2; + cycles-=12; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setadc8(temp,temp2); + temp+=temp2+tempc; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=regs[reg].w; + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x12: /*ADC reg,8*/ + fetchea(); + temp=geteab(); + setadc8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp+tempc); + cycles-=((mod==3)?3:13); + break; + case 0x13: /*ADC reg,16*/ + fetchea(); + tempw=geteaw(); + setadc16(regs[reg].w,tempw); + regs[reg].w+=tempw+tempc; + cycles-=((mod==3)?3:13); + break; + case 0x14: /*ADC AL,#8*/ + tempw=FETCH(); + setadc8(AL,tempw); + AL+=tempw+tempc; + cycles-=4; + break; + case 0x15: /*ADC AX,#16*/ + tempw=getword(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles-=4; + break; + + case 0x16: /*PUSH SS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),SS); + SP-=2; + cycles-=14; + break; + case 0x17: /*POP SS*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ss); + SP+=2; + noint=1; + cycles-=12; +// output=1; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setsbc8(temp,temp2); + temp-=(temp2+tempc); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=regs[reg].w; +// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x1A: /*SBB reg,8*/ + fetchea(); + temp=geteab(); + setsbc8(getr8(reg),temp); + setr8(reg,getr8(reg)-(temp+tempc)); + cycles-=((mod==3)?3:13); + break; + case 0x1B: /*SBB reg,16*/ + fetchea(); + tempw=geteaw(); + tempw2=regs[reg].w; +// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + regs[reg].w=tempw2; + cycles-=((mod==3)?3:13); + break; + case 0x1C: /*SBB AL,#8*/ + temp=FETCH(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=4; + break; + case 0x1D: /*SBB AX,#16*/ + tempw=getword(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=4; + break; + + case 0x1E: /*PUSH DS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),DS); + SP-=2; + cycles-=14; + break; + case 0x1F: /*POP DS*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + SP+=2; + cycles-=12; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp=geteab(); + temp&=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw&=regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x22: /*AND reg,8*/ + fetchea(); + temp=geteab(); + temp&=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x23: /*AND reg,16*/ + fetchea(); + tempw=geteaw(); + tempw&=regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x24: /*AND AL,#8*/ + AL&=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x25: /*AND AX,#16*/ + AX&=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x26: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x27: /*DAA*/ + if ((flags&A_FLAG) || ((AL&0xF)>9)) + { + tempi=((uint16_t)AL)+6; + AL+=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + setznp8(AL); + cycles-=4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(reg)); + temp-=getr8(reg); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw=geteaw(); +// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,tempw,regs[reg].w); + setsub16(tempw,regs[reg].w); + tempw-=regs[reg].w; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x2A: /*SUB reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(reg),temp); + setr8(reg,getr8(reg)-temp); + cycles-=((mod==3)?3:13); + break; + case 0x2B: /*SUB reg,16*/ + fetchea(); + tempw=geteaw(); +// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,regs[reg].w,tempw); + setsub16(regs[reg].w,tempw); + regs[reg].w-=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x2C: /*SUB AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + AL-=temp; + cycles-=4; + break; + case 0x2D: /*SUB AX,#16*/ +// printf("INS %i\n",ins); +// output=1; + tempw=getword(); + setsub16(AX,tempw); + AX-=tempw; + cycles-=4; + break; + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + setznp8(AL); + cycles-=4; + break; + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp=geteab(); + temp^=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw^=regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x32: /*XOR reg,8*/ + fetchea(); + temp=geteab(); + temp^=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x33: /*XOR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw^=regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x34: /*XOR AL,#8*/ + AL^=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); +// if (output) printf("CMP %02X-%02X\n",temp,getr8(reg)); + setsub8(temp,getr8(reg)); + cycles-=((mod==3)?3:13); + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); +// if (output) printf("CMP %04X-%04X\n",tempw,regs[reg].w); + setsub16(tempw,regs[reg].w); + cycles-=((mod==3)?3:13); + break; + case 0x3A: /*CMP reg,8*/ + fetchea(); + temp=geteab(); +// if (output) printf("CMP %02X-%02X\n",getr8(reg),temp); + setsub8(getr8(reg),temp); + cycles-=((mod==3)?3:13); + break; + case 0x3B: /*CMP reg,16*/ + fetchea(); + tempw=geteaw(); +// printf("CMP %04X-%04X\n",regs[reg].w,tempw); + setsub16(regs[reg].w,tempw); + cycles-=((mod==3)?3:13); + break; + case 0x3C: /*CMP AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + cycles-=4; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + cycles-=4; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(regs[opcode&7].w,1); + regs[opcode&7].w++; + cycles-=3; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(regs[opcode&7].w,1); + regs[opcode&7].w--; + cycles-=3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (ssegs) ss=oldss; + SP-=2; + writememw(ss,SP,regs[opcode&7].w); + cycles-=15; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (ssegs) ss=oldss; + SP+=2; + regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cycles-=12; + break; + + + case 0x70: /*JO*/ + offset=(int8_t)FETCH(); + if (flags&V_FLAG) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x71: /*JNO*/ + offset=(int8_t)FETCH(); + if (!(flags&V_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x72: /*JB*/ + offset=(int8_t)FETCH(); + if (flags&C_FLAG) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x73: /*JNB*/ + offset=(int8_t)FETCH(); + if (!(flags&C_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x74: /*JE*/ + offset=(int8_t)FETCH(); + if (flags&Z_FLAG) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x75: /*JNE*/ + offset=(int8_t)FETCH(); + cycles-=4; + if (!(flags&Z_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + break; + case 0x76: /*JBE*/ + offset=(int8_t)FETCH(); + if (flags&(C_FLAG|Z_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x77: /*JNBE*/ + offset=(int8_t)FETCH(); + if (!(flags&(C_FLAG|Z_FLAG))) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x78: /*JS*/ + offset=(int8_t)FETCH(); + if (flags&N_FLAG) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x79: /*JNS*/ + offset=(int8_t)FETCH(); + if (!(flags&N_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x7A: /*JP*/ + offset=(int8_t)FETCH(); + if (flags&P_FLAG) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x7B: /*JNP*/ + offset=(int8_t)FETCH(); + if (!(flags&P_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x7C: /*JL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x7D: /*JNL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x7E: /*JLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x7F: /*JNLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + + case 0x80: case 0x82: + fetchea(); + temp=geteab(); + temp2=FETCH(); + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + setadd8(temp,temp2); + seteab(temp+temp2); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC b,#8*/ +// temp2+=(flags&C_FLAG); + setadc8(temp,temp2); + seteab(temp+temp2+tempc); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB b,#8*/ +// temp2+=(flags&C_FLAG); + setsbc8(temp,temp2); + seteab(temp-(temp2+tempc)); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x28: /*SUB b,#8*/ + setsub8(temp,temp2); + seteab(temp-temp2); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 80 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); + tempw2=getword(); + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC w,#16*/ +// tempw2+=(flags&C_FLAG); + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB w,#16*/ +// tempw2+=(flags&C_FLAG); + setsbc16(tempw,tempw2); + seteaw(tempw-(tempw2+tempc)); + cycles-=((mod==3)?4:23); + break; + case 0x28: /*SUB w,#16*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x38: /*CMP w,#16*/ +// printf("CMP %04X %04X\n",tempw,tempw2); + setsub16(tempw,tempw2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 81 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); + tempw2=FETCH(); + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + setznp16(tempw); + seteaw(tempw); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC w,#8*/ +// tempw2+=(flags&C_FLAG); + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB w,#8*/ +// tempw2+=(flags&C_FLAG); + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x28: /*SUB w,#8*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 83 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setznp8(temp&temp2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?3:13); + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=regs[reg].w; + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?3:13); + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); + seteab(getr8(reg)); + setr8(reg,temp); + cycles-=((mod==3)?4:25); + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); + seteaw(regs[reg].w); + regs[reg].w=tempw; + cycles-=((mod==3)?4:25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(reg)); + cycles-=((mod==3)?2:13); + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(regs[reg].w); + cycles-=((mod==3)?2:13); + break; + case 0x8A: /*MOV reg,b*/ + fetchea(); + temp=geteab(); + setr8(reg,temp); + cycles-=((mod==3)?2:12); + break; + case 0x8B: /*MOV reg,w*/ + fetchea(); + tempw=geteaw(); + regs[reg].w=tempw; + cycles-=((mod==3)?2:12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles-=((mod==3)?2:13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + regs[reg].w=eaaddr; + cycles-=2; + break; + + case 0x8E: /*MOV sreg,w*/ +// if (output) printf("MOV %04X ",pc); + fetchea(); +// if (output) printf("%04X %02X\n",pc,rmdat); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); + loadseg(tempw,&_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + tempw=geteaw(); + loadseg(tempw,&_cs); + break; + case 0x18: /*DS*/ + tempw=geteaw(); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + break; + case 0x10: /*SS*/ + tempw=geteaw(); + loadseg(tempw,&_ss); + if (ssegs) oldss=ss; +// printf("LOAD SS %04X %04X\n",tempw,SS); +// printf("SS loaded with %04X %04X:%04X %04X %04X %04X\n",ss>>4,cs>>4,pc,CX,DX,es>>4); + break; + } + cycles-=((mod==3)?2:12); + skipnextprint=1; + noint=1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + SP+=2; + seteaw(tempw); + cycles-=25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=regs[opcode&7].w; + regs[opcode&7].w=tempw; + cycles-=3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=5; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); + tempw3=CS; + tempw4=pc; + if (ssegs) ss=oldss; + pc=tempw; +// printf("0x9a"); + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,tempw4); + SP-=4; + cycles-=36; + FETCHCLEAR(); + break; + case 0x9B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: /*PUSHF*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + SP-=2; + cycles-=14; + break; + case 0x9D: /*POPF*/ + if (ssegs) ss=oldss; + flags=readmemw(ss,SP)&0xFFF; + SP+=2; + cycles-=12; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|AH; + cycles-=4; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles-=4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); + AL=readmemb(ds+addr); + cycles-=14; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); +// printf("Reading AX from %05X %04X:%04X\n",ds+addr,ds>>4,addr); + AX=readmemw(ds,addr); + cycles-=!4; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); + writememb(ds+addr,AL); + cycles-=14; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); +// if (!addr) printf("Write !addr %04X:%04X\n",cs>>4,pc); + writememw(ds,addr,AX); + cycles-=14; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds+SI); + writememb(es+DI,temp); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=18; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=18; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds+SI); + temp2=readmemb(es+DI); + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=30; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); +// printf("CMPSW %04X %04X\n",tempw,tempw2); + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=30; + break; + case 0xA8: /*TEST AL,#8*/ + temp=FETCH(); + setznp8(AL&temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getword(); + setznp16(AX&tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xAA: /*STOSB*/ + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=11; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=11; + break; + case 0xAC: /*LODSB*/ + AL=readmemb(ds+SI); +// printf("LODSB %04X:%04X %02X %04X:%04X\n",cs>>4,pc,AL,ds>>4,SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=16; + break; + case 0xAD: /*LODSW*/ +// if (times) printf("LODSW %04X:%04X\n",cs>>4,pc); + AX=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=16; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es+DI); + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=19; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=19; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=FETCH(); + cycles-=4; + break; + case 0xB1: /*MOV CL,#8*/ + CL=FETCH(); + cycles-=4; + break; + case 0xB2: /*MOV DL,#8*/ + DL=FETCH(); + cycles-=4; + break; + case 0xB3: /*MOV BL,#8*/ + BL=FETCH(); + cycles-=4; + break; + case 0xB4: /*MOV AH,#8*/ + AH=FETCH(); + cycles-=4; + break; + case 0xB5: /*MOV CH,#8*/ + CH=FETCH(); + cycles-=4; + break; + case 0xB6: /*MOV DH,#8*/ + DH=FETCH(); + cycles-=4; + break; + case 0xB7: /*MOV BH,#8*/ + BH=FETCH(); + cycles-=4; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + regs[opcode&7].w=getword(); + cycles-=4; + break; + + case 0xC2: /*RET*/ + tempw=getword(); + if (ssegs) ss=oldss; + pc=readmemw(ss,SP); +// printf("C2\n"); +// printf("RET to %04X\n",pc); + SP+=2+tempw; + cycles-=24; + FETCHCLEAR(); + break; + case 0xC3: /*RET*/ + if (ssegs) ss=oldss; + pc=readmemw(ss,SP); +// printf("C3\n"); +// if (output) printf("RET to %04X %05X\n",pc,ss+SP); + SP+=2; + cycles-=20; + FETCHCLEAR(); + break; + case 0xC4: /*LES*/ + fetchea(); + regs[reg].w=readmemw(easeg,eaaddr); //geteaw(); + tempw=readmemw(easeg,(eaaddr+2)&0xFFFF); //geteaw2(); + loadseg(tempw,&_es); + cycles-=24; + break; + case 0xC5: /*LDS*/ + fetchea(); + regs[reg].w=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+2)&0xFFFF); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + cycles-=24; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=FETCH(); + seteab(temp); + cycles-=((mod==3)?4:14); + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); + seteaw(tempw); + cycles-=((mod==3)?4:14); + break; + + case 0xCA: /*RETF*/ + tempw=getword(); + if (ssegs) ss=oldss; + pc=readmemw(ss,SP); +// printf("CA\n"); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + break; + case 0xCB: /*RETF*/ + if (ssegs) ss=oldss; + pc=readmemw(ss,SP); +// printf("CB\n"); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + break; + case 0xCC: /*INT 3*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + SP-=6; + addr=3<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; +// printf("CC %04X:%04X ",CS,pc); + pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); +// printf("%04X:%04X\n",CS,pc); + cycles-=72; + break; + case 0xCD: /*INT*/ + lastpc=pc; + lastcs=CS; + temp=FETCH(); + +// if (temp == 0x13 && AX == 0x0201 && ES == 0x0BF5 && CX == 0x1D06) output = 3; +// if (temp==0x10 && !AH) printf("Entering mode %02X\n",AL); +// if (temp==0x18 || temp==0x19) { printf("INT %02X\n",temp); output=1; } +// /*if (temp==0x13) */printf("INT %02X %04X %04X:%04X %04X %04X:%04X %04X:%04X\n",temp,AX,ES,BX,CX,DS,DX,CS,pc); + //if (temp == 0x13 && AH == 2) output = 3; +/* if (CS==0xC800 && temp==0x13) + { + output=3; + timetolive=100000; + }*/ +/* if (temp==0x10) printf("INT 10 %04X %04X %04X %04X %04X:%04X %06X %06X %c\n",AX,BX,CX,DX,cs>>4,pc,ds,ds+DX, (AL > 31) ? AL : '.'); + if (temp == 0x10 && AX == 0xe35) + { + dumpregs(); + + }*/ +/* if (temp==0x21 && AH==9) + { + addr=0; + while (ram[ds+DX+addr]!='$') + { + printf("%c",ram[ds+DX+addr]); + addr++; + } + printf("\n"); + printf("Called from %04X\n",readmemw(ss,SP)); + }*/ +// output=0; +// if (temp==0x13 && AH==3) printf("Write sector %04X:%04X %05X\n",es>>4,BX,es+BX); +/* if (temp==0x13 && (DL==0x80 || DL==0x81) && AH>0) + { + int13hdc(); + } + else *//*if (temp==0x13 && AH==2 && DL<2)// && FASTDISC) + { + int13read(); + //output=1; + } + else if (temp==0x13 && AH==3 && DL<2)// && FASTDISC) + { + int13write(); + } + else if (temp==0x13 && AH==4 && DL<2)// && FASTDISC) + { + AH=0; + flags&=~C_FLAG; + } + else + {*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + pc=readmemw(0,addr); +// printf("CD\n"); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); +// } + cycles-=71; + break; + case 0xCF: /*IRET*/ + if (ssegs) ss=oldss; + tempw=CS; + tempw2=pc; + inint=0; + pc=readmemw(ss,SP); +// printf("CF\n"); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + SP+=6; + cycles-=44; + FETCHCLEAR(); + break; + case 0xD0: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x08: /*ROR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + seteab(temp); +// setznp8(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + seteab(temp); +// setznp8(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp<<=1; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (temp&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp>>=1; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp&0x40) temp|=0x80; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + +// default: +// printf("Bad D0 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD1: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + seteaw(tempw); +// setznp16(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x08: /*ROR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + seteaw(tempw); +// setznp16(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + seteaw(tempw); +// setznp16(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw<<=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw>>=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (tempw&0x4000) tempw|=0x8000; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + +// default: +// printf("Bad D1 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); + c=CL; +// cycles-=c; + if (!c) break; +// if (c>7) printf("Shiftb %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x10: /*RCL b,CL*/ +// printf("RCL %i %02X %02X\n",c,CL,temp); + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&0x80; + temp<<=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=1; + c--; + cycles-=4; + } +// printf("Now %02X\n",temp); + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x18: /*RCR b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&1; + temp>>=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=0x80; + c--; + cycles-=4; + } +// if (temp2) flags|=C_FLAG; +// else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + if ((temp<<(c-1))&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=c; + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=c; + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + +// default: +// printf("Bad D2 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); + c=CL; +// cycles-=c; + if (!c) break; +// if (c>15) printf("Shiftw %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x10: /*RCL w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw<<1)|templ; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x18: /*RCR w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + if (c>16) + { + tempw=0; + flags&=~C_FLAG; + } + else + { + if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x28: /*SHR w,CL*/ + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=c; + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + +// default: +// printf("Bad D3 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD4: /*AAM*/ + tempws=FETCH(); + AH=AL/tempws; + AL%=tempws; + setznp168(AX); + cycles-=83; + break; + case 0xD5: /*AAD*/ + tempws=FETCH(); + AL=(AH*tempws)+AL; + AH=0; + setznp168(AX); + cycles-=60; + break; + case 0xD7: /*XLAT*/ + addr=BX+AL; + AL=readmemb(ds+addr); + cycles-=11; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xDC: case 0xDE: case 0xDF: case 0xD8: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && !(flags&Z_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && (flags&Z_FLAG)) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE2: /*LOOP*/ +// printf("LOOP start\n"); + offset=(int8_t)FETCH(); + CX--; + if (CX) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=5; +// printf("LOOP end!\n"); + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)FETCH(); + if (!CX) { pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + + case 0xE4: /*IN AL*/ + temp=FETCH(); + AL=inb(temp); + cycles-=14; + break; + case 0xE5: /*IN AX*/ + temp=FETCH(); + AL=inb(temp); + AH=inb(temp+1); + cycles-=14; + break; + case 0xE6: /*OUT AL*/ + temp=FETCH(); + outb(temp,AL); + cycles-=14; + break; + case 0xE7: /*OUT AX*/ + temp=FETCH(); + outb(temp,AL); + outb(temp+1,AH); + cycles-=14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); + if (ssegs) ss=oldss; +// writememb(ss+((SP-1)&0xFFFF),pc>>8); + writememw(ss,((SP-2)&0xFFFF),pc); + SP-=2; + pc+=tempw; + cycles-=23; + FETCHCLEAR(); + break; + case 0xE9: /*JMP rel 16*/ +// printf("PC was %04X\n",pc); + pc+=getword(); +// printf("PC now %04X\n",pc); + cycles-=15; + FETCHCLEAR(); + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); + pc=addr; +// printf("EA\n"); + loadcs(tempw); +// cs=loadcs(CS); +// cs=CS<<4; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)FETCH(); + pc+=offset; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEC: /*IN AL,DX*/ + AL=inb(DX); + cycles-=12; + break; + case 0xED: /*IN AX,DX*/ + AL=inb(DX); + AH=inb(DX+1); + cycles-=12; + break; + case 0xEE: /*OUT DX,AL*/ + outb(DX,AL); + cycles-=12; + break; + case 0xEF: /*OUT DX,AX*/ + outb(DX,AL); + outb(DX+1,AH); + cycles-=12; + break; + + case 0xF0: /*LOCK*/ + cycles-=4; + break; + + case 0xF2: /*REPNE*/ + rep(0); + break; + case 0xF3: /*REPE*/ + rep(1); + break; + + case 0xF4: /*HLT*/ +// printf("IN HLT!!!! %04X:%04X %08X %08X %08X\n",oldcs,oldpc,old8,old82,old83); +/* if (!(flags & I_FLAG)) + { + pclog("HLT\n"); + dumpregs(); + exit(-1); + }*/ + inhlt=1; + pc--; + FETCHCLEAR(); + cycles-=2; + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + temp2=FETCH(); + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?5:11); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX=AL*temp; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=70; + break; + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=80; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) + { + tempw2=tempw%temp; +/* if (!tempw) + { + writememw((ss+SP)-2,flags|0xF000); + writememw((ss+SP)-4,cs>>4); + writememw((ss+SP)-6,pc); + SP-=6; + flags&=~I_FLAG; + pc=readmemw(0); + cs=readmemw(2)<<4; + printf("Div by zero %04X:%04X\n",cs>>4,pc); +// dumpregs(); +// exit(-1); + } + else + {*/ + AH=tempw2; + tempw/=temp; + AL=tempw&0xFF; +// } + } + else + { + printf("DIVb BY 0 %04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,0); +// printf("F6 30\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); +// cs=loadcs(CS); +// cs=CS<<4; +// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x30); +// dumpregs(); +// exit(-1); + } + cycles-=80; + break; + case 0x38: /*IDIV AL,b*/ + tempws=(int)AX; + if (temp) + { + tempw2=tempws%(int)((int8_t)temp); +/* if (!tempw) + { + writememw((ss+SP)-2,flags|0xF000); + writememw((ss+SP)-4,cs>>4); + writememw((ss+SP)-6,pc); + SP-=6; + flags&=~I_FLAG; + pc=readmemw(0); + cs=readmemw(2)<<4; + printf("Div by zero %04X:%04X\n",cs>>4,pc); + } + else + {*/ + AH=tempw2&0xFF; + tempws/=(int)((int8_t)temp); + AL=tempws&0xFF; +// } + } + else + { + printf("IDIVb BY 0 %04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,0); +// printf("F6 38\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); +// cs=loadcs(CS); +// cs=CS<<4; +// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); + } + cycles-=101; + break; + +// default: +// printf("Bad F6 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + tempw2=getword(); + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?5:11); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles-=((mod==3)?3:24); + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ=AX*tempw; +// if (output) printf("%04X*%04X=%08X\n",AX,tempw,templ); + AX=templ&0xFFFF; + DX=templ>>16; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=118; + break; + case 0x28: /*IMUL AX,w*/ + setznp16(AX); +// printf("IMUL %i %i ",(int)((int16_t)AX),(int)((int16_t)tempw)); + tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); + if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); +// printf("%i ",tempws); + AX=tempws&0xFFFF; + tempws=(uint16_t)(tempws>>16); + DX=tempws&0xFFFF; +// printf("%04X %04X\n",AX,DX); +// dumpregs(); +// exit(-1); + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + cycles-=128; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; +// printf("DIV %08X/%04X\n",templ,tempw); + if (tempw) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + } + else + { + printf("DIVw BY 0 %04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,0); +// printf("F7 30\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=144; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); +// printf("IDIV %i %i ",tempws,tempw); + if (tempw) + { + tempw2=tempws%(int)((int16_t)tempw); +// printf("%04X ",tempw2); + DX=tempw2; + tempws/=(int)((int16_t)tempw); + AX=tempws&0xFFFF; + } + else + { + printf("IDIVw BY 0 %04X:%04X\n",cs>>4,pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + pc=readmemw(0,0); +// printf("F7 38\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=165; + break; + +// default: +// printf("Bad F7 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: /*STC*/ +// printf("STC %04X\n",pc); + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: /*CLI*/ + flags&=~I_FLAG; +// printf("CLI at %04X:%04X\n",cs>>4,pc); + cycles-=3; + break; + case 0xFB: /*STI*/ + flags|=I_FLAG; +// printf("STI at %04X:%04X\n",cs>>4,pc); + cycles-=2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); + flags&=~V_FLAG; + if (rmdat&0x38) + { + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } +// setznp8(temp2); + seteab(temp2); + cycles-=((mod==3)?3:23); + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); + setadd16nc(tempw,1); +// setznp16(tempw+1); + seteaw(tempw+1); + cycles-=((mod==3)?3:23); + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); +// setsub16(tempw,1); + setsub16nc(tempw,1); +// setznp16(tempw-1); + seteaw(tempw-1); +// if (output) printf("DEC - %04X\n",tempw); + cycles-=((mod==3)?3:23); + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,pc); + SP-=2; + pc=tempw; +// printf("FF 10\n"); + cycles-=((mod==3)?20:29); + FETCHCLEAR(); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,(eaaddr+2)&0xFFFF); //geteaw2(); + tempw3=CS; + tempw4=pc; + if (ssegs) ss=oldss; + pc=tempw; +// printf("FF 18\n"); + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + SP-=4; + cycles-=53; + FETCHCLEAR(); + break; + case 0x20: /*JMP*/ + pc=geteaw(); +// printf("FF 20\n"); + cycles-=((mod==3)?11:18); + FETCHCLEAR(); + break; + case 0x28: /*JMP far*/ + pc=readmemw(easeg,eaaddr); //geteaw(); +// printf("FF 28\n"); + loadcs(readmemw(easeg,(eaaddr+2)&0xFFFF)); //geteaw2(); +// cs=loadcs(CS); +// cs=CS<<4; + cycles-=24; + FETCHCLEAR(); + break; + case 0x30: /*PUSH w*/ + tempw=geteaw(); +// if (output) printf("PUSH %04X %i %02X %04X %04X %02X %02X\n",tempw,rm,rmdat,easeg,eaaddr,ram[0x22340+0x5638],ram[0x22340+0x5639]); + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); + SP-=2; + cycles-=((mod==3)?15:24); + break; + +// default: +// printf("Bad FF opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + default: + FETCH(); + cycles-=8; + break; + +/* printf("Bad opcode %02X at %04X:%04X from %04X:%04X %08X\n",opcode,cs>>4,pc,old8>>16,old8&0xFFFF,old82); + dumpregs(); + exit(-1);*/ + } + pc&=0xFFFF; + +/* if ((CS & 0xf000) == 0xa000) + { + dumpregs(); + exit(-1); + }*/ +// output = 3; +/* if (CS == 0xf000) + { + dumpregs(); + exit(-1); + } + output = 3;*/ + if (ssegs) + { + ds=oldds; + ss=oldss; + ssegs=0; + } + +// output = 3; + // if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks); + FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); + if ((cycdiff-cycles)>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + + +int optype; +#define JMP 1 +#define CALL 2 +#define IRET 3 +#define INT 4 + +uint32_t oxpc; + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + + +#define IRQTEST ((flags&I_FLAG) && (pic.pend&~pic.mask) && !ssegs && !noint) + +extern int cgate32; + + +extern uint32_t *eal_r, *eal_w; + + +extern uint32_t flags_zn; +extern uint8_t flags_p; +#define FLAG_N (flags_zn>>31) +#define FLAG_Z (flags_zn) +#define FLAG_P (znptable8[flags_p]&P_FLAG) + +extern int gpf; + + +enum +{ + ABRT_NONE = 0, + ABRT_GEN, + ABRT_TS = 0xA, + ABRT_NP = 0xB, + ABRT_SS = 0xC, + ABRT_GPF = 0xD, + ABRT_PF = 0xE +}; + +extern int abrt; +extern uint32_t abrt_error; + +void x86_doabrt(int x86_abrt); + +extern uint8_t opcode2; + +extern uint16_t rds; +extern uint32_t rmdat32; diff --git a/src/x86_flags.h b/src/x86_flags.h new file mode 100644 index 00000000..9dc8eea7 --- /dev/null +++ b/src/x86_flags.h @@ -0,0 +1,17 @@ +static inline void setznp8(uint8_t val) +{ + flags&=~0x8d5; + flags|=znptable8[val]; +} + +static inline void setznp16(uint16_t val) +{ + flags&=~0x8d5; + flags|=znptable16[val]; +} +static inline void setznp32(uint32_t val) +{ + flags&=~0x8d5; + flags|=((val&0x80000000)?N_FLAG:((!val)?Z_FLAG:0)); + flags|=znptable8[val&0xFF]&P_FLAG; +} diff --git a/src/x86seg.c b/src/x86seg.c new file mode 100644 index 00000000..5d6c1b49 --- /dev/null +++ b/src/x86seg.c @@ -0,0 +1,2543 @@ +//#if 0 +#include +#include +#include "ibm.h" +#include "x86.h" + +/*Controls whether the accessed bit in a descriptor is set when CS is loaded. The + 386 PRM is ambiguous on this subject, but BOCHS doesn't set it and Windows 98 + setup crashes if it is. + The accessed bit is always set for data and stack selectors though.*/ +//#define CS_ACCESSED + +/*Controls whether the accessed bit in a descriptor is set when a data or stack + selector is loaded. This SHOULD be set, however Windows 98 setup crashes if it + is.*/ +//#define SEL_ACCESSED +int stimes = 0; +int dtimes = 0; +int btimes = 0; +int is486=1; + +uint32_t abrt_error; +int cgate16,cgate32; + +#define breaknullsegs 0 + +int intgatesize; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); +void taskswitch386(uint16_t seg, uint16_t *segdat); + +int notpresent=0; +int output; +void pmodeint(int num, int soft); +/*NOT PRESENT is INT 0B + GPF is INT 0D*/ + +FILE *pclogf; +void x86abort(const char *format, ...) +{ + char buf[256]; +// return; + if (!pclogf) + pclogf=fopen("pclog.txt","wt"); +//return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); + fflush(pclogf); + dumpregs(); + exit(-1); +} + +uint8_t opcode2; + +void x86_doabrt(int x86_abrt) +{ +// ingpf = 1; + CS = oldcs; + pc = oldpc; + _cs.access = oldcpl << 5; +// pclog("x86_doabrt - %02X %08X %04X:%08X %i\n", x86_abrt, abrt_error, CS, pc, ins); + +/* if (CS == 0x3433 && pc == 0x000006B0) + { + pclog("Quit it\n"); + dumpregs(); + exit(-1); + }*/ +// pclog("GPF! - error %04X %04X(%08X):%08X %02X %02X %i %04X %i %i\n",error,CS,cs,pc,opcode,opcode2,ins,flags&I_FLAG,IOPL, dtimes); + + pmodeint(x86_abrt, 0); + + if (abrt) return; + + if (intgatesize == 16) + { + if (stack32) + { + writememw(ss, ESP-2, abrt_error); + ESP-=2; + } + else + { + writememw(ss, ((SP-2)&0xFFFF), abrt_error); + SP-=2; + } + } + else + { + if (stack32) + { + writememl(ss, ESP-4, abrt_error); + ESP-=4; + } + else + { + writememl(ss, ((SP-4)&0xFFFF), abrt_error); + SP-=4; + } + } +// ingpf = 0; +// abrt = gpf = 1; +} +void x86gpf(char *s, uint16_t error) +{ +// pclog("GPF %04X\n", error); + abrt = ABRT_GPF; + abrt_error = error; +} +void x86ss(char *s, uint16_t error) +{ +// pclog("SS %04X\n", error); + abrt = ABRT_SS; + abrt_error = error; +} +void x86ts(char *s, uint16_t error) +{ +// pclog("TS %04X\n", error); + abrt = ABRT_TS; + abrt_error = error; +} +void x86np(char *s, uint16_t error) +{ +// pclog("NP %04X : %s\n", error, s); +// dumpregs(); +// exit(-1); + abrt = ABRT_NP; + abrt_error = error; +} + + +void loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr; + int dpl; + if (output) pclog("Load seg %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { +// intcount++; + if (!(seg&~3)) + { + if (s==&_ss) + { + pclog("SS selector = NULL!\n"); + x86ss(NULL,0); + return; +// dumpregs(); +// exit(-1); + } +// if (s->base!=-1) pclog("NEW! "); + s->seg=0; + s->base=-1; +// pclog("NULL selector %s%s%s%s %04X(%06X):%06X\n",(s==&_ds)?"DS":"",(s==&_es)?"ES":"",(s==&_fs)?"FS":"",(s==&_gs)?"GS":"",CS,cs,pc); + return; + } +// if (s==&_ss) pclog("Load SS %04X\n",seg); +// pclog("Protected mode seg load!\n"); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n",seg,ldt.limit, opcode, opcode2, rmdat); +// dumppic(); +// dumpregs(); +// exit(-1); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X 1\n",seg,gdt.limit); +// dumpregs(); +// exit(-1); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + dpl=(segdat[2]>>13)&3; + if (s==&_ss) + { + if (!(seg&~3)) + { + pclog("Load SS null selector\n"); + x86gpf(NULL,seg&~3); + return; + } + if ((seg&3)!=CPL || dpl!=CPL) + { + pclog("Invalid SS permiss\n"); + x86gpf(NULL,seg&~3); +// x86abort("Invalid SS permiss for %04X!\n",seg&0xFFFC); + return; + } + switch ((segdat[2]>>8)&0x1F) + { + case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ + break; + default: + pclog("Invalid SS type\n"); + x86gpf(NULL,seg&~3); +// x86abort("Invalid SS segment type for %04X!\n",seg&0xFFFC); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("Load SS not present!\n"); + x86ss(NULL,seg&~3); + return; + } + if (segdat[3]&0x40) stack32=1; + else stack32=0; +// pclog("Load SS\n"); + } + else if (s!=&_cs) + { + if (output) pclog("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + if (output) pclog("Seg type %03X\n",segdat[2]&0x1F00); + switch ((segdat[2]>>8)&0x1F) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ +// pclog("Load seg %04X %i %i %04X:%08X\n",seg,dpl,CS&3,CS,pc); + if ((seg&3)>dpl || (CPL)>dpl) + { + pclog("Data seg fail - %04X:%08X %04X %i %04X\n",CS,pc,seg,dpl,segdat[2]); + x86gpf(NULL,seg&~3); +// x86abort("Data segment load - level too low!\n",seg&0xFFFC); + return; + } + break; + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + default: + pclog("Invalid segment type for %04X! %04X\n",seg&0xFFFC,segdat[2]); +// if ((seg & ~3) == 0x1508) btimes++; +// if (btimes == 2) output = 3; +// dumpregs(); +// exit(-1); + x86gpf(NULL,seg&~3); +// x86abort("Invalid segment type for %04X!\n",seg&0xFFFC); + return; + } + } +// #endif +// } +// if (!(segdat[2]&0x8000)) x86abort("Data segment not present!\n"); +// if (!(segdat[2]&0x800) || !(segdat[2]&0x400)) +// { + if (!(segdat[2]&0x8000)) + { + x86np("Load data seg not present", seg & 0xfffc); + return; + } + s->seg=seg; + s->limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) s->limit=(s->limit<<12)|0xFFF; + s->limitw=(segdat[2]&0x200)?1:0; + s->base=segdat[1]; + s->base|=((segdat[2]&0xFF)<<16); + if (is386) s->base|=((segdat[3]>>8)<<24); + s->access=segdat[2]>>8; + + if ((segdat[2]>>8) & 4) + s->limit = 0xffffffff; + +// if (output) pclog("SS limit %08X\n", s->limit); + +// pclog("Seg Write %04X to %08X\n",segdat[2]|0x100,addr+4); +#ifndef CS_ACCESSED + if (s != &_cs) + { +#endif +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +#ifndef CS_ACCESSED + } +#endif +// pclog("Access=%02X Limit=%04X Limitw=%04X %08X %i %04X:%04X\n",s->access,s->limit,s->limitw, _ss.limit, ins, CS, pc); +// if (s==&_es && s->base>0x180000) s->base=0x180000; +// } +// pclog("base=%06X limit=%04X access=%02X %06X %04X %04X %04X %04X\n",s->base,s->limit,s->access,addr,segdat[0],segdat[1],segdat[2],seg); +// dumpregs(); +// exit(-1); + } + else + { + s->base=seg<<4; + s->limit=0xFFFF; + s->seg=seg; + if (eflags&VM_FLAG) s->access=3<<5; + else s->access=0<<5; + use32=0; + if (s==&_ss) stack32=0; +/* if (s==&_ds) + { + pclog("DS! %04X %06X %04X:%04X\n",DS,ds,CS,pc); + }*/ + } +} + +#define DPL ((segdat[2]>>13)&3) +#define DPL2 ((segdat2[2]>>13)&3) +#define DPL3 ((segdat3[2]>>13)&3) + +void loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr; + int count; + uint16_t oldss,oldsp; + if (output) pclog("Load CS %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { +// intcount++; +// flushmmucache(); +// pclog("Load CS %04X\n",seg); + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcs\n"); +// dumpregs(); +// exit(-1); + x86gpf(NULL,0); + return; + } +// pclog("Protected mode CS load! %04X\n",seg); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (optype==JMP) pclog("Code seg - %04X - %04X %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2],segdat[3]); +// if (!(segdat[2]&0x8000)) x86abort("Code segment not present!\n"); +// if (output) pclog("Segdat2 %04X\n",segdat[2]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + pclog("loadcs RPL > CPL %04X %04X %i %02X\n",segdat[2],seg,CPL,opcode); + return; + } + if (CPL != DPL) + { + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS not present", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + CS=(seg&~3)|CPL; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + use32=(segdat[3]&0x40)?0x300:0; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +// if (output) pclog("Load CS %08X\n",_cs.base); +// CS=(CS&0xFFFC)|((_cs.access>>5)&3); + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS system seg not present\n", seg & 0xfffc); + return; + } + switch (segdat[2]&0xF00) + { + default: + pclog("Bad CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); + x86gpf(NULL,seg&~3); + return; + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + CS=seg; + if (eflags&VM_FLAG) _cs.access=3<<5; + else _cs.access=0<<5; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void loadcsjmp(uint16_t seg, uint32_t oxpc) +{ + uint16_t segdat[4]; + uint32_t addr; + int count; + uint16_t oldss,oldsp; + uint16_t type,seg2; + uint32_t newpc; + if (output) pclog("Load CS JMP %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcsjmp\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (output) pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP not present\n", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << 5+8)) | (CPL << 5+8); + + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP system selector not present\n", seg & 0xfffc); + return; + } + type=segdat[2]&0xF00; + if (type==0x400) newpc=segdat[0]; + else newpc=segdat[0]|(segdat[3]<<16); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + oldpc=pc; + count=segdat[2]&31; + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (!(seg2&~3)) + { + pclog("Trying to load CS with NULL selector! lcsjmpcg\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSJ\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSJ\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + + if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP from call gate not present\n", seg & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL > CPL) + { + pclog("Call gate DPL > CPL"); + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + pclog("JMP Call gate bad segment type\n"); + x86gpf(NULL,seg2&~3); + return; + } + break; + + + case 0x900: /*386 Task gate*/ + pc=oxpc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpl_override=0; +// case 0xB00: /*386 Busy task gate*/ +// if (optype==JMP) pclog("Task switch!\n"); +// taskswitch386(seg,segdat); + return; + + default: + pclog("Bad JMP CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + CS=seg; + if (eflags&VM_FLAG) _cs.access=3<<5; + else _cs.access=0<<5; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void PUSHW(uint16_t v) +{ +// if (output==3) pclog("PUSHW %04X to %08X\n",v,ESP-4); + if (stack32) + { + writememw(ss,ESP-2,v); + if (abrt) return; + ESP-=2; + } + else + { +// pclog("Write %04X to %08X\n", v, ss+((SP-2)&0xFFFF)); + writememw(ss,((SP-2)&0xFFFF),v); + if (abrt) return; + SP-=2; + } +} +void PUSHL(uint32_t v) +{ +// if (output==3) pclog("PUSHL %08X to %08X\n",v,ESP-4); + if (stack32) + { + writememl(ss,ESP-4,v); + if (abrt) return; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),v); + if (abrt) return; + SP-=4; + } +} +uint16_t POPW() +{ + uint16_t tempw; + if (stack32) + { + tempw=readmemw(ss,ESP); + if (abrt) return 0; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); + if (abrt) return 0; + SP+=2; + } + return tempw; +} +uint32_t POPL() +{ + uint32_t templ; + if (stack32) + { + templ=readmeml(ss,ESP); + if (abrt) return 0; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); + if (abrt) return 0; + SP+=4; + } + return templ; +} + +void loadcscall(uint16_t seg) +{ + uint16_t seg2; + uint16_t segdat[4],segdat2[4],newss; + uint32_t addr,oldssbase=ss, oaddr; + uint32_t newpc; + int count; + uint16_t oldcs=CPL; + uint32_t oldss,oldsp,newsp,oldpc, oldsp2; + int type; + uint16_t tempw; + + int csout = output; + + if (msw&1 && !(eflags&VM_FLAG)) + { + //flushmmucache(); + if (csout) pclog("Protected mode CS load! %04X\n",seg); + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcscall\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSC\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + type=segdat[2]&0xF00; + if (type==0x400) newpc=segdat[0]; + else newpc=segdat[0]|(segdat[3]<<16); + + if (csout) pclog("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); + if (segdat[2]&0x1000) + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + if (csout) pclog("Not conforming, RPL > CPL\n"); + x86gpf(NULL,seg&~3); + return; + } + if (CPL != DPL) + { + if (csout) pclog("Not conforming, CPL != DPL (%i %i)\n",CPL,DPL); + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + if (csout) pclog("CPL < DPL\n"); + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (csout) pclog("Not present\n"); + x86np("Load CS call not present", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + /*Conforming segments don't change CPL, so preserve existing CPL*/ + if (segdat[2]&0x400) + { + seg = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << 5+8)) | (CPL << 5+8); + } + else /*On non-conforming segments, set RPL = CPL*/ + seg = (seg & ~3) | CPL; + CS=seg; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + if (csout) pclog("Complete\n"); + } + else + { + type=segdat[2]&0xF00; + if (csout) pclog("Type %03X\n",type); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: /*386 Call gate*/ + if (output) pclog("Callgate %08X\n", pc); + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + oldpc=pc; + count=segdat[2]&31; + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (output) pclog("Call gate not present %04X\n",seg); + x86np("Call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (output) pclog("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2&~3)) + { + pclog("Trying to load CS with NULL selector! lcscallcg\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSC\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + + if (output) pclog("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); + + if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (output) pclog("Call gate CS not present %04X\n",seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL < CPL) + { + oaddr = addr; + /*Load new stack*/ + oldss=SS; + oldsp=oldsp2=ESP; + cpl_override=1; + if (tr.access&8) + { + addr = 4 + tr.base + (DPL * 8); + newss=readmemw(0,addr+4); + newsp=readmeml(0,addr); + } + else + { + addr = 2 + tr.base + (DPL * 4); + newss=readmemw(0,addr+2); + newsp=readmemw(0,addr); + } + cpl_override=0; + if (abrt) return; + if (output) pclog("New stack %04X:%08X\n",newss,newsp); + if (!(newss&~3)) + { + pclog("Call gate loading null SS\n"); + x86ts(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + if (output) pclog("Read stack seg\n"); + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (output) pclog("Read stack seg done!\n"); + if (((newss & 3) != DPL) || (DPL2 != DPL)) + { + pclog("Call gate loading SS with wrong permissions %04X %04X %i %i %04X %04X\n", newss, seg2, DPL, DPL2, segdat[2], segdat2[2]); +// dumpregs(); +// exit(-1); + x86ts(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("Call gate loading SS wrong type\n"); + x86ts(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("Call gate loading SS not present\n"); + x86np("Call gate loading SS not present\n", newss & 0xfffc); + return; + } + if (!stack32) oldsp &= 0xFFFF; + SS=newss; + stack32=segdat2[3]&0x40; + if (stack32) ESP=newsp; + else SP=newsp; + _ss.limit=segdat2[0]|((segdat2[3]&0xF)<<16); + if (segdat2[3]&0x80) _ss.limit=(_ss.limit<<12)|0xFFF; + if ((segdat2[2]>>8) & 4) + _ss.limit = 0xffffffff; + + _ss.limitw=(segdat2[2]&0x200)?1:0; + _ss.base=segdat2[1]; + _ss.base|=((segdat2[2]&0xFF)<<16); + if (is386) _ss.base|=((segdat2[3]>>8)<<24); + _ss.access=segdat2[2]>>8; + + if (output) pclog("Set access 1\n"); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS=seg2; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + pc=newpc; + + if (output) pclog("Set access 2\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + if (output) pclog("Type %04X\n",type); + if (type==0xC00) + { + PUSHL(oldss); + PUSHL(oldsp2); + if (abrt) + { + pclog("ABRT PUSHL\n"); + SS = oldss; + ESP = oldsp2; + return; + } +// if (output) pclog("Stack now %04X:%08X\n",SS,ESP); + if (count) + { + while (count) + { + count--; + PUSHL(readmeml(oldssbase,oldsp+(count*4))); + if (abrt) + { + pclog("ABRT COPYL\n"); + SS = oldss; + ESP = oldsp2; + return; + } + } + } +// x86abort("Call gate with count %i\n",count); +// PUSHL(oldcs); +// PUSHL(oldpc); if (abrt) return; + } + else + { + if (output) pclog("Stack %04X\n",SP); + PUSHW(oldss); + if (output) pclog("Write SS to %04X:%04X\n",SS,SP); + PUSHW(oldsp2); + if (abrt) + { + pclog("ABRT PUSHW\n"); + SS = oldss; + ESP = oldsp2; + return; + } + if (output) pclog("Write SP to %04X:%04X\n",SS,SP); +// if (output) pclog("Stack %04X %i %04X:%04X\n",SP,count,oldssbase,oldsp); +// if (output) pclog("PUSH %04X %04X %i %i now %04X:%08X\n",oldss,oldsp,count,stack32,SS,ESP); + if (count) + { + while (count) + { + count--; + tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); + if (output) pclog("PUSH %04X\n",tempw); + PUSHW(tempw); + if (abrt) + { + pclog("ABRT COPYW\n"); + SS = oldss; + ESP = oldsp2; + return; + } + } + } +// if (output) pclog("Stack %04X\n",SP); +// if (count) x86abort("Call gate with count\n"); +// PUSHW(oldcs); +// PUSHW(oldpc); if (abrt) return; + } + break; + } + else if (DPL > CPL) + { + pclog("Call gate DPL > CPL"); + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ +/* if (type==0xC00) + { + PUSHL(oldcs); + PUSHL(oldpc); if (abrt) return; + } + else + { + PUSHW(oldcs); + PUSHW(oldpc); if (abrt) return; + }*/ + CS=seg2; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + pclog("Call gate bad segment type\n"); + x86gpf(NULL,seg2&~3); + return; + } + break; + +// case 0x900: /*386 Task gate*/ +// case 0xB00: /*386 Busy task gate*/ +// if (optype==JMP) pclog("Task switch!\n"); +// taskswitch386(seg,segdat); +// return; + + + default: + pclog("Bad CALL special descriptor %03X\n",segdat[2]&0xF00); + x86gpf(NULL,seg&~3); + return; +// dumpregs(); +// exit(-1); + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + CS=seg; + if (eflags&VM_FLAG) _cs.access=3<<5; + else _cs.access=0<<5; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void pmoderetf(int is32, uint16_t off) +{ + uint32_t newpc; + uint32_t newsp; + uint32_t addr, oaddr; + uint16_t segdat[4],segdat2[4],seg,newss; + uint32_t oldsp=ESP; + if (output) pclog("RETF %i %04X:%04X %08X %04X\n",is32,CS,pc,cr0,eflags); + if (is32) + { + newpc=POPL(); + seg=POPL(); if (abrt) return; + } + else + { + if (output) pclog("PC read from %04X:%04X\n",SS,SP); + newpc=POPW(); + if (output) pclog("CS read from %04X:%04X\n",SS,SP); + seg=POPW(); if (abrt) return; + } + if (output) pclog("Return to %04X:%08X\n",seg,newpc); + if ((seg&3)=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X RETF\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X RETF\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); +// dumpregs(); +// exit(-1); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } + oaddr = addr; + + if (output) pclog("CPL %i RPL %i %i\n",CPL,seg&3,is32); + + if (stack32) ESP+=off; + else SP+=off; + + if (CPL==(seg&3)) + { + if (output) pclog("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (CPL != DPL) + { + pclog("RETF non-conforming CPL != DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (CPL < DPL) + { + pclog("RETF non-conforming CPL < DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + pclog("RETF CS not code segment\n"); + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("RETF CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + pc=newpc; + if (segdat[2] & 0x400) + segdat[2] = (segdat[2] & ~(3 << 5+8)) | ((seg & 3) << 5+8); + CS = seg; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + +// pclog("CPL=RPL return to %04X:%08X\n",CS,pc); + } + else + { + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((seg&3) != DPL) + { + pclog("RETF non-conforming RPL != DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (output) pclog("RETF non-conforming, %i %i\n",seg&3, DPL); + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((seg&3) < DPL) + { + pclog("RETF non-conforming RPL < DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (output) pclog("RETF conforming, %i %i\n",seg&3, DPL); + break; + default: + pclog("RETF CS not code segment\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("RETF CS not present! %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + if (is32) + { + newsp=POPL(); + newss=POPL(); if (abrt) return; +// pclog("is32 new stack %04X:%04X\n",newss,newsp); + } + else + { + if (output) pclog("SP read from %04X:%04X\n",SS,SP); + newsp=POPW(); + if (output) pclog("SS read from %04X:%04X\n",SS,SP); + newss=POPW(); if (abrt) return; +// pclog("!is32 new stack %04X:%04X\n",newss,newsp); + } + if (output) pclog("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss&~3)) + { + pclog("RETF loading null SS\n"); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X RETF SS\n",newss,gdt.limit); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X RETF SS\n",newss,gdt.limit); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } + if (output) pclog("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); +// if (((newss & 3) != DPL) || (DPL2 != DPL)) + if ((newss & 3) != (seg & 3)) + { + pclog("RETF loading SS with wrong permissions %i %i %04X %04X\n", newss & 3, seg & 3, newss, seg); + ESP=oldsp; +// output = 3; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("RETF loading SS wrong type\n"); + ESP=oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("RETF loading SS not present\n"); + ESP=oldsp; + x86np("RETF loading SS not present\n", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) + { + pclog("RETF loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + SS=newss; + stack32=segdat2[3]&0x40; + if (stack32) ESP=newsp; + else SP=newsp; + _ss.limit=segdat2[0]|((segdat2[3]&0xF)<<16); + if (segdat2[3]&0x80) _ss.limit=(_ss.limit<<12)|0xFFF; + if ((segdat2[2]>>8) & 4) + _ss.limit = 0xffffffff; + _ss.limitw=(segdat2[2]&0x200)?1:0; + _ss.base=segdat2[1]; + _ss.base|=((segdat2[2]&0xFF)<<16); + if (is386) _ss.base|=((segdat2[3]>>8)<<24); + _ss.access=segdat2[2]>>8; + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << 5+8)) | ((seg & 3) << 5+8); + + pc=newpc; + CS=seg; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + + if (stack32) ESP+=off; + else SP+=off; +// pclog("CPL=idt.limit) + { + if (num==8) + { + /*Triple fault - reset!*/ + pclog("Triple fault!\n"); +// output=1; + softresetx86(); + } + else if (num==0xD) + { + pclog("Double fault!\n"); + pmodeint(8,0); + } + else + { + pclog("INT out of range\n"); + x86gpf(NULL,(num*8)+2+(soft)?0:1); + } + if (output) pclog("addr >= IDT.limit\n"); + return; + } + addr+=idt.base; + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(2,addr); + segdat[2]=readmemw(4,addr); + segdat[3]=readmemw(6,addr); cpl_override=0; if (abrt) { pclog("Abrt reading from %08X\n",addr); return; } + oaddr = addr; + + if (output) pclog("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); + if (!(segdat[2]&0x1F00)) + { + //pclog("No seg\n"); + x86gpf(NULL,(num*8)+2); + return; + } + if (DPL=0x800)?32:16; +// if (output) pclog("Int gate %04X %i oldpc %04X pc %04X\n",type,intgatesize,oldpc,pc); + if (!(segdat[2]&0x8000)) + { + pclog("Int gate not present\n"); + x86np("Int gate not present\n", (num << 3) | 2); + return; + } + seg=segdat[1]; +// pclog("Interrupt gate : %04X:%04X%04X\n",seg,segdat[3],segdat[0]); + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } +/* if ((seg&3) < CPL) + { + pclog("INT to higher level\n"); + x86gpf(NULL,seg&~3); + return; + }*/ + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + oaddr = addr; + + if (DPL2 > CPL) + { + pclog("INT to higher level 2\n"); + x86gpf(NULL,seg&~3); + return; + } + //pclog("Type %04X\n",segdat2[2]); + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (DPL2=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X PMODEINT SS\n",newss,gdt.limit); + x86ss(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ss(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat3[0]=readmemw(0,addr); + segdat3[1]=readmemw(0,addr+2); + segdat3[2]=readmemw(0,addr+4); + segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (((newss & 3) != DPL2) || (DPL3 != DPL2)) + { + pclog("Int gate loading SS with wrong permissions\n"); + x86ss(NULL,newss&~3); + return; + } + if ((segdat3[2]&0x1A00)!=0x1200) + { + pclog("Int gate loading SS wrong type\n"); + x86ss(NULL,newss&~3); + return; + } + if (!(segdat3[2]&0x8000)) + { + pclog("Int gate loading SS not present\n"); + x86np("Int gate loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + stack32=segdat3[3]&0x40; + if (stack32) ESP=newsp; + else SP=newsp; + _ss.limit=segdat3[0]|((segdat3[3]&0xF)<<16); + if (segdat3[3]&0x80) _ss.limit=(_ss.limit<<12)|0xFFF; + if ((segdat3[2]>>8) & 4) + _ss.limit = 0xffffffff; + _ss.limitw=(segdat3[2]&0x200)?1:0; + _ss.base=segdat3[1]; + _ss.base|=((segdat3[2]&0xFF)<<16); + if (is386) _ss.base|=((segdat3[3]>>8)<<24); + _ss.access=segdat3[2]>>8; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + if (output) pclog("New stack %04X:%08X\n",SS,ESP); + cpl_override=1; + if (type>=0x800) + { +// if (output) pclog("Push 32 %i\n",eflags&VM_FLAG); + if (eflags & VM_FLAG) + { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); if (abrt) return; + loadseg(0,&_ds); + loadseg(0,&_es); + loadseg(0,&_fs); + loadseg(0,&_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(flags|(eflags<<16)); +// if (soft) pclog("Pushl CS %08X\n", CS); + PUSHL(CS); +// if (soft) pclog("Pushl PC %08X\n", pc); + PUSHL(pc); if (abrt) return; +// if (output) pclog("32Stack %04X:%08X\n",SS,ESP); + } + else + { +// if (output) pclog("Push 16\n"); + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(flags); +// if (soft) pclog("Pushw CS %04X\n", CS); + PUSHW(CS); +// if (soft) pclog("Pushw pc %04X\n", pc); + PUSHW(pc); if (abrt) return; +// if (output) pclog("16Stack %04X:%08X\n",SS,ESP); + } + cpl_override=0; + _cs.access=0; +// pclog("Non-confirming int gate, CS = %04X\n"); + break; + } + else if (DPL2!=CPL) + { + pclog("Non-conforming int gate DPL != CPL\n"); + x86gpf(NULL,seg&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (!(segdat2[2]&0x8000)) + { + pclog("Int gate CS not present\n"); + x86np("Int gate CS not present\n", segdat[1] & 0xfffc); + return; + } + if ((eflags & VM_FLAG) && DPL20x800) + { + PUSHL(flags|(eflags<<16)); +// if (soft) pclog("Pushlc CS %08X\n", CS); + PUSHL(CS); +// if (soft) pclog("Pushlc PC %08X\n", pc); + PUSHL(pc); if (abrt) return; + } + else + { + PUSHW(flags); +// if (soft) pclog("Pushwc CS %04X\n", CS); + PUSHW(CS); +// if (soft) pclog("Pushwc PC %04X\n", pc); + PUSHW(pc); if (abrt) return; + } + break; + default: + pclog("Int gate CS not code segment - %04X %04X %04X %04X\n",segdat2[0],segdat2[1],segdat2[2],segdat2[3]); + x86gpf(NULL,seg&~3); + return; + } + CS=(seg&~3)|CPL; +// pclog("New CS = %04X\n",CS); + _cs.limit=segdat2[0]|((segdat2[3]&0xF)<<16); + if (segdat2[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat2[1]; + _cs.base|=((segdat2[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat2[3]>>8)<<24); + _cs.access=segdat2[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + if (type>0x800) pc=segdat[0]|(segdat[3]<<16); + else pc=segdat[0]; + use32=(segdat2[3]&0x40)?0x300:0; +// pclog("Int gate done!\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + eflags&=~VM_FLAG; + if (!(type&0x100)) + { + flags&=~I_FLAG; +// pclog("INT %02X disabling interrupts %i\n",num,soft); + } + flags&=~(T_FLAG|NT_FLAG); +// if (output) pclog("Final Stack %04X:%08X\n",SS,ESP); + break; + + case 0x500: /*Task gate*/ +// pclog("Task gate\n"); + seg=segdat[1]; + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + cpl_override=0; if (abrt) return; + if (!(segdat2[2]&0x8000)) + { + pclog("Int task gate not present\n"); + x86np("Int task gate not present\n", segdat[1] & 0xfffc); + return; + } + optype=INT; + cpl_override=1; + taskswitch286(seg,segdat2,segdat2[2]&0x800); + cpl_override=0; + break; + + default: + pclog("Bad int gate type %04X %04X %04X %04X %04X\n",segdat[2]&0x1F00,segdat[0],segdat[1],segdat[2],segdat[3]); + x86gpf(NULL,seg&~3); + return; + } +} + +int inint; +void pmodeiret(int is32) +{ + uint32_t newsp; + uint16_t oldcs=CPL,newss; + uint16_t tempw,tempw2; + uint32_t tempflags,flagmask; + uint32_t newpc; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint16_t seg; + uint32_t addr, oaddr; + uint32_t oldsp=ESP; + if (is386 && (eflags&VM_FLAG)) + { +// if (output) pclog("V86 IRET\n"); + if (IOPL!=3) + { + pclog("V86 IRET! IOPL!=3\n"); + x86gpf(NULL,0); + return; + } + oxpc=pc; + if (is32) + { + newpc=POPL(); + seg=POPL(); + tempflags=POPL(); if (abrt) return; + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (abrt) return; + } + pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + CS=seg; + flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + return; + } + +// pclog("IRET %i\n",is32); + //flushmmucache(); +// if (output) pclog("Pmode IRET %04X:%04X ",CS,pc); + + if (flags&NT_FLAG) + { +// pclog("NT IRET\n"); + seg=readmemw(tr.base,0); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("TS Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("TS Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); + taskswitch286(seg,segdat,0); + cpl_override=0; + return; + } + inint=0; + oxpc=pc; + flagmask=0xFFFF; + if (CPL) flagmask&=~0x3000; + if (IOPL>16)&VM_FLAG)) + { +// pclog("IRETD to V86\n"); + + newsp=POPL(); + newss=POPL(); + segs[0]=POPL(); + segs[1]=POPL(); + segs[2]=POPL(); + segs[3]=POPL(); if (abrt) return; +// pclog("Pop stack %04X:%04X\n",newss,newsp); + eflags=tempflags>>16; + loadseg(segs[0],&_es); + loadseg(segs[1],&_ds); + loadseg(segs[2],&_fs); + loadseg(segs[3],&_gs); + +// pclog("V86 IRET %04X:%08X\n",SS,ESP); +// output=3; + + pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + CS=seg; + _cs.access=3<<5; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + ESP=newsp; + loadseg(newss,&_ss); + use32=0; + flags=(tempflags&0xFFD5)|2; + +// pclog("V86 IRET to %04X:%04X %04X:%04X %04X %04X %04X %04X %i\n",CS,pc,SS,SP,DS,ES,FS,GS,abrt); + // if (CS==0xFFFF && pc==0xFFFFFFFF) timetolive=12; +/* { + dumpregs(); + exit(-1); + }*/ + return; + } + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (abrt) return; + } +// if (!is386) tempflags&=0xFFF; +// pclog("Returned to %04X:%08X %04X %04X %i\n",seg,newpc,flags,tempflags, ins); + if (!(seg&~3)) + { + pclog("IRET CS=0\n"); +// dumpregs(); +// exit(-1); + x86gpf(NULL,0); + return; + } + +// if (output) pclog("IRET %04X:%08X\n",seg,newpc); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + if ((seg&3) < CPL) + { + pclog("IRET to lower level\n"); + x86gpf(NULL,seg&~3); + return; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } +// pclog("Seg type %04X %04X\n",segdat[2]&0x1F00,segdat[2]); + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if ((seg&3) != DPL) + { + pclog("IRET NC DPL %04X %04X %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2], segdat[3]); +// dumpregs(); +// exit(-1); + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ + if ((seg&3) < DPL) + { + pclog("IRET C DPL\n"); + x86gpf(NULL,seg&~3); + return; + } + break; + default: + pclog("IRET CS != code seg\n"); + x86gpf(NULL,seg&~3); +// dumpregs(); +// exit(-1); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("IRET CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + ESP=oldsp; + x86np("IRET CS not present\n", seg & 0xfffc); + return; + } +// pclog("Seg %04X CPL %04X\n",seg,CPL); + if ((seg&3) == CPL) + { +// pclog("Same level\n"); + CS=seg; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + } + else /*Return to outer level*/ + { + oaddr = addr; + if (output) pclog("Outer level\n"); + if (is32) + { + newsp=POPL(); + newss=POPL(); if (abrt) return; + } + else + { + newsp=POPW(); + newss=POPW(); if (abrt) return; + } + + if (output) pclog("IRET load stack %04X:%04X\n",newss,newsp); + + if (!(newss&~3)) + { + pclog("IRET loading null SS\n"); + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X PMODEIRET SS\n",newss,gdt.limit); + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X PMODEIRET\n",newss,gdt.limit); + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } +// pclog("IRET SS sd2 %04X\n",segdat2[2]); +// if (((newss & 3) != DPL) || (DPL2 != DPL)) + if ((newss & 3) != (seg & 3)) + { + pclog("IRET loading SS with wrong permissions %04X %04X\n", newss, seg); +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("IRET loading SS wrong type\n"); + x86gpf(NULL,newss&~3); + return; + } + if (DPL2 != (seg & 3)) + { + pclog("IRET loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("IRET loading SS not present\n"); + x86np("IRET loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + stack32=segdat2[3]&0x40; + if (stack32) ESP=newsp; + else SP=newsp; + _ss.limit=segdat2[0]|((segdat2[3]&0xF)<<16); + if (segdat2[3]&0x80) _ss.limit=(_ss.limit<<12)|0xFFF; + if ((segdat2[2]>>8) & 4) + _ss.limit = 0xffffffff; + _ss.limitw=(segdat2[2]&0x200)?1:0; + _ss.base=segdat2[1]; + _ss.base|=((segdat2[2]&0xFF)<<16); + if (is386) _ss.base|=((segdat2[3]>>8)<<24); + _ss.access=segdat2[2]>>8; + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << 5+8)) | ((seg & 3) << 5+8); + + CS=seg; + _cs.limit=segdat[0]|((segdat[3]&0xF)<<16); + if (segdat[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat[1]; + _cs.base|=((segdat[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat[3]>>8)<<24); + _cs.access=segdat[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + + if (CPL>((_ds.access>>5)&3)) + { + _ds.seg=0; + _ds.base=-1; + } + if (CPL>((_es.access>>5)&3)) + { + _es.seg=0; + _es.base=-1; + } + if (CPL>((_fs.access>>5)&3)) + { + _fs.seg=0; + _fs.base=-1; + } + if (CPL>((_gs.access>>5)&3)) + { + _gs.seg=0; + _gs.base=-1; + } + } + pc=newpc; + flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; + if (is32) eflags=tempflags>>16; +// pclog("done\n"); +} + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint32_t base,obase=tr.base; + uint32_t limit; + int x386; + uint32_t templ; + uint16_t tempw; + int c; + + uint32_t new_cr3=0; + uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + uint16_t new_ldt; + + uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + + uint32_t addr; + + uint16_t oldflags; + + uint16_t segdat2[4]; + +//output=3; + base=segdat[1]|((segdat[2]&0xFF)<<16)|((segdat[3]>>8)<<24); + limit=segdat[0]|((segdat[3]&0xF)<<16); +// pclog("286 Task switch! %04X:%04X\n",CS,pc); +/// pclog("TSS %04X base %08X limit %04X old TSS %04X %08X %i\n",seg,base,limit,tr.seg,tr.base,ins); +// / pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + + if (is386) + { +// if (output) pclog("32-bit TSS\n"); + + new_cr3=readmeml(base,0x1C); + new_pc=readmeml(base,0x20); + new_flags=readmeml(base,0x24); + + new_eax=readmeml(base,0x28); + new_ecx=readmeml(base,0x2C); + new_edx=readmeml(base,0x30); + new_ebx=readmeml(base,0x34); + new_esp=readmeml(base,0x38); + new_ebp=readmeml(base,0x3C); + new_esi=readmeml(base,0x40); + new_edi=readmeml(base,0x44); + + new_es=readmemw(base,0x48); +// if (output) pclog("Read CS from %08X\n",base+0x4C); + new_cs=readmemw(base,0x4C); + new_ss=readmemw(base,0x50); + new_ds=readmemw(base,0x54); + new_fs=readmemw(base,0x58); + new_gs=readmemw(base,0x5C); + new_ldt=readmemw(base,0x60); + + if (abrt) return; + if (optype==JMP || optype==INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + + if (optype==IRET) flags&=~NT_FLAG; + +// if (output) pclog("Write PC %08X %08X\n",tr.base,pc); + writememl(tr.base,0x1C,cr3); + writememl(tr.base,0x20,pc); + writememl(tr.base,0x24,flags|(eflags<<16)); + + writememl(tr.base,0x28,EAX); + writememl(tr.base,0x2C,ECX); + writememl(tr.base,0x30,EDX); + writememl(tr.base,0x34,EBX); + writememl(tr.base,0x38,ESP); + writememl(tr.base,0x3C,EBP); + writememl(tr.base,0x40,ESI); + writememl(tr.base,0x44,EDI); + + writememl(tr.base,0x48,ES); +// if (output) pclog("Write CS %04X to %08X\n",CS,tr.base+0x4C); + writememl(tr.base,0x4C,CS); + writememl(tr.base,0x50,SS); + writememl(tr.base,0x54,DS); + writememl(tr.base,0x58,FS); + writememl(tr.base,0x5C,GS); + writememl(tr.base,0x60,ldt.seg); + + if (optype==INT) + { + writememl(base,0,tr.seg); + new_flags|=NT_FLAG; + } + if (abrt) return; + if (optype==JMP || optype==INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + + + + cr3=new_cr3; +// pclog("New CR3 %08X\n",cr3); + flushmmucache(); + + + + pc=new_pc; +// if (output) pclog("New pc %08X\n",new_pc); + flags=new_flags; + eflags=new_flags>>16; + +// if (output) pclog("Load LDT %04X\n",new_ldt); + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; +// if (output) pclog("Load from %08X %08X\n",templ,gdt.base); + ldt.limit=readmemw(0,templ); + if (readmemb(templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=(readmemw(0,templ+2))|(readmemb(templ+4)<<16)|(readmemb(templ+7)<<24); +// if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base); + + + if (eflags&VM_FLAG) + { + pclog("Task switch V86!\n"); + x86gpf(NULL,0); + return; + } + + if (!(new_cs&~3)) + { + pclog("TS loading null CS\n"); + x86gpf(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr); + x86gpf(NULL,0); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); + x86gpf(NULL,0); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + pclog("TS loading CS not present\n"); + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + pclog("TS load CS non-conforming RPL != DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + pclog("TS load CS non-conforming RPL < DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + default: + pclog("TS load CS not code segment\n"); + x86gpf(NULL,new_cs&~3); + return; + } + +// if (output) pclog("new_cs %04X\n",new_cs); + CS=new_cs; + _cs.limit=segdat2[0]|((segdat2[3]&0xF)<<16); + if (segdat2[3]&0x80) _cs.limit=(_cs.limit<<12)|0xFFF; + _cs.base=segdat2[1]; + _cs.base|=((segdat2[2]&0xFF)<<16); + if (is386) _cs.base|=((segdat2[3]>>8)<<24); + _cs.access=segdat2[2]>>8; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat2[3]&0x40)?0x300:0; + + EAX=new_eax; + ECX=new_ecx; + EDX=new_edx; + EBX=new_ebx; + ESP=new_esp; + EBP=new_ebp; + ESI=new_esi; + EDI=new_edi; + + if (output) pclog("Load ES %04X\n",new_es); + loadseg(new_es,&_es); + if (output) pclog("Load SS %04X\n",new_ss); + loadseg(new_ss,&_ss); + if (output) pclog("Load DS %04X\n",new_ds); + loadseg(new_ds,&_ds); + if (output) pclog("Load FS %04X\n",new_fs); + loadseg(new_fs,&_fs); + if (output) pclog("Load GS %04X\n",new_gs); + loadseg(new_gs,&_gs); + + if (output) pclog("Resuming at %04X:%08X\n",CS,pc); + } + else + { + pclog("16-bit TSS\n"); + resetx86(); + //exit(-1); + } + + + tr.seg=seg; + tr.base=base; + tr.limit=limit; + tr.access=segdat[2]>>8; +} + diff --git a/src/x87.c b/src/x87.c new file mode 100644 index 00000000..420c1cee --- /dev/null +++ b/src/x87.c @@ -0,0 +1,1106 @@ +//Quake timedemo demo1 - 8.1FPS + +//11A00 - D_SCAlloc +//11C1C - D_CacheSurface + +//36174 - SCR_CalcRefdef + +//SCR_CalcRefdef +//Calls R_SetVrect and R_ViewChanged + +#include +#include "ibm.h" +#include "x86.h" +#include "x87.h" + +#undef readmemb +#undef writememb + +#define readmemb(s,a) ((readlookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF)?readmemb386l(s,a):ram[readlookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]) +#define writememb(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememb386l(s,a,v); else ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]=v + +#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v + +static inline uint8_t geteab() +{ + if (mod==3) + return (rm&4)?regs[rm&3].b.h:regs[rm&3].b.l; +// cycles-=3; + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod==3) + return regs[rm].w; +// cycles-=3; + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,eaaddr); +} + +static inline uint32_t geteal() +{ + if (mod==3) + return regs[rm].l; +// cycles-=3; + if (eal_r) return *eal_r; + return readmeml(easeg,eaaddr); +} + + +#define seteab(v) if (mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); } else if (rm&4) regs[rm&3].b.h=v; else regs[rm].b.l=v +#define seteaw(v) if (mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); } else regs[rm].w=v +#define seteal(v) if (mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); } else regs[rm].l=v + + + +double ST[8]; +uint16_t npxs,npxc,tag; + +int TOP; +#define ST(x) ST[((TOP+(x))&7)] + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +void x87_reset() +{ +} + +void x87_dumpregs() +{ + pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]); + pclog("Status = %04X Control = %04X Tag = %04X\n",npxs,npxc,tag); +} + +void x87_print() +{ + pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]); +} + +void x87_push(double i) +{ + TOP=(TOP-1)&7; + ST[TOP]=i; + tag&=~(3<<((TOP&7)<<1)); + if (i==0.0) tag|=(1<<((TOP&7)<<1)); +} + +double x87_pop() +{ + double t=ST[TOP]; + tag|=(3<<((TOP&7)<<1)); + TOP=(TOP+1)&7; + return t; +} + +int64_t x87_fround(double b) +{ + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + return (int64_t)(b+0.5); + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +#define BIAS80 16383 +#define BIAS64 1023 + +double x87_ld80() +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,eaaddr+4)<<32; + test.begin = readmemw(easeg,eaaddr+8); + + int64_t exp64 = (((test.begin&0x7fff) - BIAS80)); + int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff); + int64_t sign = (test.begin&0x8000)?1:0; + + if (test.eind.ll&0x400) mant64++; +// pclog("LD80 %08X %08X\n",test.eind.ll,mant64); + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + return test.eind.d; +} + +void x87_st80(double d) +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.d=d; + int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0; + int64_t exp80 = test.eind.ll&(0x7ff0000000000000); + int64_t exp80final = (exp80>>52); + int64_t mant80 = test.eind.ll&(0x000fffffffffffff); + int64_t mant80final = (mant80 << 11); + if(d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= (0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + writememl(easeg,eaaddr,test.eind.ll); + writememl(easeg,eaaddr+4,test.eind.ll>>32); + writememw(easeg,eaaddr+8,test.begin); +} + +void x87_d8() +{ + union + { + float s; + uint32_t i; + } ts; + if (mod==3) + { + switch (rmdat32&0xFF) + { + case 0xC0: case 0xC1: case 0xC2: case 0xC3: /*FADD*/ + case 0xC4: case 0xC5: case 0xC6: case 0xC7: + ST(0)=ST(0)+ST(rmdat32&7); + cycles-=8; + return; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: /*FMUL*/ + case 0xCC: case 0xCD: case 0xCE: case 0xCF: + ST(0)=ST(0)*ST(rmdat32&7); + cycles-=16; + return; + case 0xD0: case 0xD1: case 0xD2: case 0xD3: /*FCOM*/ + case 0xD4: case 0xD5: case 0xD6: case 0xD7: + npxs&=~(C0|C2|C3); + if (ST(0)==ST(rmdat32&7)) npxs|=C3; + else if (ST(0)>((TOP&1)<<1))&3); + npxs&=~(C0|C2|C3); + if (((tag>>((TOP&1)<<1))&3)==3) npxs|=(C0|C3); + else if (ST(0)==0.0) npxs|=C3; + else npxs|=C2; + if (ST(0)<0.0) npxs|=C1; + cycles-=8; + return; + case 0xE8: /*FLD1*/ + x87_push(1.0); + cycles-=4; + return; + case 0xE9: /*FLDL2T*/ + x87_push(3.3219280948873623); + cycles-=8; + return; + case 0xEA: /*FLDL2E*/ + x87_push(1.4426950408889634); + cycles-=8; + return; + case 0xEB: /*FLDPI*/ + x87_push(3.141592653589793); + cycles-=8; + return; + case 0xEC: /*FLDEG2*/ + x87_push(0.3010299956639812); + cycles-=8; + return; + case 0xED: /*FLDLN2*/ + x87_push(0.693147180559945); + cycles-=8; + return; + case 0xEE: /*FLDZ*/ +// pclog("FLDZ %04X:%08X\n",CS,pc); + x87_push(0.0); + tag|=(1<<((TOP&7)<<1)); + cycles-=4; + return; + case 0xF0: /*F2XM1*/ + ST(0)=pow(2.0,ST(0))-1.0; + cycles-=200; + return; + case 0xF1: /*FYL2X*/ + ST(1)=ST(1)*(log(ST(0))/log(2.0)); + x87_pop(); + cycles-=250; + return; + case 0xF2: /*FPTAN*/ +// pclog("Tan of %f = ",ST(0)); + ST(0)=tan(ST(0)); +// pclog("%f\n",ST(0)); + x87_push(1.0); + npxs&=~C2; + cycles-=235; + return; + case 0xF3: /*FPATAN*/ +// pclog("FPATAN %08X\n",pc); + ST(1)=atan2(ST(1),ST(0)); + x87_pop(); + cycles-=250; + return; + case 0xF6: /*FDECSTP*/ + TOP=(TOP-1)&7; + return; + case 0xF7: /*FINCSTP*/ + TOP=(TOP+1)&7; + return; + case 0xF8: /*FPREM*/ + temp64=(int64_t)(ST(0)/ST(1)); + ST(0)=ST(0)-(ST(1)*(double)temp64); + npxs&=~(C0|C1|C2|C3); + if (temp64&4) npxs|=C0; + if (temp64&2) npxs|=C3; + if (temp64&1) npxs|=C1; + cycles-=100; + return; + case 0xFA: /*FSQRT*/ + ST(0)=sqrt(ST(0)); + cycles-=83; + return; + case 0xFB: /*FSINCOS*/ + td=ST(0); + ST(0)=sin(td); + x87_push(cos(td)); + npxs&=~C2; + cycles-=330; + return; + case 0xFC: /*FRNDINT*/ +// pclog("FRNDINT %f %i ",ST(0),(npxc>>10)&3); + ST(0)=(double)x87_fround(ST(0)); +// pclog("%f\n",ST(0)); + cycles-=21; + return; + case 0xFD: /*FSCALE*/ + temp64=(int64_t)ST(1); + ST(0)=ST(0)*pow(2.0,(double)temp64); + cycles-=30; + return; + case 0xFE: /*FSIN*/ + ST(0)=sin(ST(0)); + npxs&=~C2; + cycles-=300; + return; + case 0xFF: /*FCOS*/ + ST(0)=cos(ST(0)); + npxs&=~C2; + cycles-=300; + return; + } + } + else + { + switch (reg) + { + case 0: /*FLD single-precision*/ +// if ((rmdat32&0xFFFF)==0xD445) { pclog("FLDS\n"); output=3; dumpregs(); exit(-1); } + ts.i=(float)geteal(); if (abrt) return; + x87_push((double)ts.s); + cycles-=3; + return; + case 2: /*FST single-precision*/ + ts.s=(float)ST(0); + seteal(ts.i); + cycles-=7; + return; + case 3: /*FSTP single-precision*/ + ts.s=(float)ST(0); + seteal(ts.i); if (abrt) return; + // if (pc==0x3f50c) pclog("FSTP %f %f %08X\n",ST(0),ts.s,ts.i); + x87_pop(); + cycles-=7; + return; + case 4: /*FLDENV*/ + switch ((cr0&1)|(op32&0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + npxc=readmemw(easeg,eaaddr); + npxs=readmemw(easeg,eaaddr+2); + tag=readmemw(easeg,eaaddr+4); + TOP=(npxs>>11)&7; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + npxc=readmemw(easeg,eaaddr); + npxs=readmemw(easeg,eaaddr+4); + tag=readmemw(easeg,eaaddr+8); + TOP=(npxs>>11)&7; + break; + } + cycles-=(cr0&1)?34:44; + return; + case 5: /*FLDCW*/ + tempw=geteaw(); + if (abrt) return; + npxc=tempw; + cycles-=4; + return; + case 6: /*FSTENV*/ + switch ((cr0&1)|(op32&0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,tag); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+10,x87_op_off); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,tag); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+8,x87_pc_seg); + writememw(easeg,eaaddr+10,x87_op_off); + writememw(easeg,eaaddr+12,x87_op_seg); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,tag); + writememw(easeg,eaaddr+12,x87_pc_off); + writememw(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,tag); + writememl(easeg,eaaddr+12,x87_pc_off); + writememl(easeg,eaaddr+16,x87_pc_seg); + writememl(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,x87_op_seg); + break; + } + cycles-=(cr0&1)?56:67; + return; + case 7: /*FSTCW*/ + seteaw(npxc); + cycles-=3; + return; + } + } +// fatal("Bad x87 D9 opcode %i %02X\n",reg,rmdat32&0xFF); + x86illegal(); +} +void x87_da() +{ + int32_t templ; + if (mod==3) + { + switch (rmdat32&0xFF) + { + case 0xE9: /*FUCOMPP*/ + npxs&=~(C0|C2|C3); + if (ST(0)==ST(1)) npxs|=C3; + else if (ST(0)>((TOP&7)<<1))&3; + tag&=~(3<<((rmdat32&7)<<1)); + tag|=(temp<<((rmdat32&7)<<1)); + cycles-=3; + return; + case 3: /*FSTP*/ + ST(rmdat32&7)=ST(0); + temp=(tag>>((TOP&7)<<1))&3; + tag&=~(3<<((rmdat32&7)<<1)); + tag|=(temp<<((rmdat32&7)<<1)); + x87_pop(); + cycles-=3; + return; + case 4: /*FUCOM*/ + npxs&=~(C0|C2|C3); + if (ST(0)==ST(rmdat32&7)) npxs|=C3; + else if (ST(0)>32)); + cycles-=8; + return; + case 3: /*FSTP double-precision*/ + t.d=ST(0); + writememl(easeg,eaaddr,t.i); + writememl(easeg,eaaddr+4,(t.i>>32)); if (abrt) return; + x87_pop(); + cycles-=8; + return; + case 4: /*FRSTOR*/ + switch ((cr0&1)|(op32&0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + npxc=readmemw(easeg,eaaddr); + npxs=readmemw(easeg,eaaddr+2); + tag=readmemw(easeg,eaaddr+4); + TOP=(npxs>>11)&7; + eaaddr+=14; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + npxc=readmemw(easeg,eaaddr); + npxs=readmemw(easeg,eaaddr+4); + tag=readmemw(easeg,eaaddr+8); + TOP=(npxs>>11)&7; + eaaddr+=28; + break; + } + ST(0)=x87_ld80(); eaaddr+=10; + ST(1)=x87_ld80(); eaaddr+=10; + ST(2)=x87_ld80(); eaaddr+=10; + ST(3)=x87_ld80(); eaaddr+=10; + ST(4)=x87_ld80(); eaaddr+=10; + ST(5)=x87_ld80(); eaaddr+=10; + ST(6)=x87_ld80(); eaaddr+=10; + ST(7)=x87_ld80(); + cycles-=(cr0&1)?34:44; + return; + case 6: /*FSAVE*/ + switch ((cr0&1)|(op32&0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,tag); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+10,x87_op_off); + eaaddr+=14; + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,tag); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+8,x87_pc_seg); + writememw(easeg,eaaddr+10,x87_op_off); + writememw(easeg,eaaddr+12,x87_op_seg); + eaaddr+=14; + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,tag); + writememw(easeg,eaaddr+12,x87_pc_off); + writememw(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); + eaaddr+=28; + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,tag); + writememl(easeg,eaaddr+12,x87_pc_off); + writememl(easeg,eaaddr+16,x87_pc_seg); + writememl(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,x87_op_seg); + eaaddr+=28; + x87_st80(ST(0)); eaaddr+=10; + x87_st80(ST(1)); eaaddr+=10; + x87_st80(ST(2)); eaaddr+=10; + x87_st80(ST(3)); eaaddr+=10; + x87_st80(ST(4)); eaaddr+=10; + x87_st80(ST(5)); eaaddr+=10; + x87_st80(ST(6)); eaaddr+=10; + x87_st80(ST(7)); + break; + } + cycles-=(cr0&1)?56:67; + return; + case 7: /*FSTSW*/ + seteaw((npxs&0xC7FF)|(TOP<<11)); + cycles-=3; + return; + } + } +// fatal("Bad x87 DD opcode %i %02X\n",reg,rmdat32&0xFF); + x86illegal(); +} +void x87_de() +{ + double t; + int32_t templ; + if (mod==3) + { + switch (rmdat32&0xFF) + { + case 0xC0: case 0xC1: case 0xC2: case 0xC3: /*FADDP*/ + case 0xC4: case 0xC5: case 0xC6: case 0xC7: + ST(rmdat32&7)=ST(rmdat32&7)+ST[TOP]; + x87_pop(); + cycles-=8; + return; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: /*FMULP*/ + case 0xCC: case 0xCD: case 0xCE: case 0xCF: + ST(rmdat32&7)=ST(rmdat32&7)*ST[TOP]; + x87_pop(); + cycles-=16; + return; + case 0xD9: /*FCOMPP*/ + npxs&=~(C0|C2|C3); + if (ST(0)==ST(1)) npxs|=C3; + else if (ST(0)>32); if (abrt) return; + x87_pop(); + cycles-=29; + return; + } + } +// fatal("Bad x87 DF opcode %i %02X\n",reg,rmdat32&0xFF); + x86illegal(); +} diff --git a/src/x87.h b/src/x87.h new file mode 100644 index 00000000..00842cdb --- /dev/null +++ b/src/x87.h @@ -0,0 +1,3 @@ +uint32_t x87_pc_off,x87_op_off; +uint16_t x87_pc_seg,x87_op_seg; +extern uint32_t op32; diff --git a/src/xtide.c b/src/xtide.c new file mode 100644 index 00000000..0dbe2d99 --- /dev/null +++ b/src/xtide.c @@ -0,0 +1,55 @@ +#include "ibm.h" +#include "xtide.h" +#include "ide.h" + +uint8_t xtide_high; + +void xtide_write(uint16_t port, uint8_t val) +{ + switch (port & 0xf) + { + case 0x0: + writeidew(0, val | (xtide_high << 8)); + return; + + case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + writeide(0, (port & 0xf) | 0x1f0, val); + return; + + case 0x8: + xtide_high = val; + return; + + case 0xe: + writeide(0, 0x3f6, val); + return; + } +} + +uint8_t xtide_read(uint16_t port) +{ + uint16_t tempw; + switch (port & 0xf) + { + case 0x0: + tempw = readidew(0); + xtide_high = tempw >> 8; + return tempw & 0xff; + + case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + return readide(0, (port & 0xf) | 0x1f0); + + case 0x8: + return xtide_high; + + case 0xe: + return readide(0, 0x3f6); + } +} + +void xtide_init() +{ + io_sethandler(0x0300, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL); +} diff --git a/src/xtide.h b/src/xtide.h new file mode 100644 index 00000000..ac5413d4 --- /dev/null +++ b/src/xtide.h @@ -0,0 +1 @@ +void xtide_init(); diff --git a/win486.nvr b/win486.nvr new file mode 100644 index 00000000..97221385 Binary files /dev/null and b/win486.nvr differ