From 3c253c2cf85556aa9c2232198c841dff63f20a39 Mon Sep 17 00:00:00 2001 From: TomW Date: Sun, 21 Apr 2013 14:54:35 +0100 Subject: [PATCH] Add v0.7 source --- COPYING | 339 ++ acer386.nvr | Bin 0 -> 128 bytes ami286.nvr | Bin 0 -> 128 bytes ami386.nvr | Bin 0 -> 128 bytes ami486.nvr | Bin 0 -> 128 bytes at.nvr | Bin 0 -> 128 bytes cmdpc30.nvr | Bin 0 -> 128 bytes dell200.nvr | Bin 0 -> 128 bytes europc.nvr | Bin 0 -> 16 bytes hot-433.nvr | Bin 0 -> 128 bytes mda.rom | Bin 0 -> 8192 bytes megapc.nvr | Bin 0 -> 128 bytes pc1512.nvr | Bin 0 -> 128 bytes pc1640.nvr | Bin 0 -> 128 bytes pc2086.nvr | Bin 0 -> 128 bytes pc3086.nvr | Bin 0 -> 128 bytes readme.txt | 483 +++ roms/acer386/roms.txt | 1 + roms/ami286/roms.txt | 1 + roms/ami386/roms.txt | 1 + roms/ami486/roms.txt | 1 + roms/cmdpc30/roms.txt | 1 + roms/dells200/roms.txt | 1 + roms/dtk/roms.txt | 1 + roms/europc/roms.txt | 1 + roms/genxt/roms.txt | 1 + roms/hot-433/roms.txt | 1 + roms/ibmat/roms.txt | 1 + roms/ibmpc/roms.txt | 1 + roms/ibmxt/roms.txt | 1 + roms/megapc/roms.txt | 1 + roms/olivetti_m24/roms.txt | 1 + roms/pc1512/roms.txt | 1 + roms/pc1640/roms.txt | 1 + roms/pc200/roms.txt | 1 + roms/pc2086/roms.txt | 1 + roms/pc3086/roms.txt | 1 + roms/tandy/roms.txt | 1 + roms/win486/roms.txt | 1 + src/286.c | 3787 ++++++++++++++++ src/386.c | 8377 ++++++++++++++++++++++++++++++++++++ src/Makefile.mingw | 43 + src/acer386sx.c | 33 + src/acer386sx.h | 1 + src/adlib.c | 187 + src/ali1429.c | 76 + src/ali1429.h | 1 + src/amstrad.c | 84 + src/amstrad.h | 2 + src/cdrom-ioctl.c | 475 ++ src/cdrom-ioctl.h | 9 + src/cms.c | 141 + src/config.c | 166 + src/config.h | 5 + src/cpu.c | 411 ++ src/cpu.h | 71 + src/dac.c | 68 + src/dma.c | 490 +++ src/dma.h | 3 + src/ega.c | 298 ++ src/fdc.c | 806 ++++ src/fdc.h | 4 + src/filters.h | 178 + src/gus.c | 625 +++ src/harddisk.c | 155 + src/headland.c | 45 + src/headland.h | 1 + src/ibm.h | 468 ++ src/ide.c | 1757 ++++++++ src/ide.h | 42 + src/io.c | 196 + src/io.h | 17 + src/jim.c | 78 + src/jim.h | 1 + src/keyboard.c | 280 ++ src/keyboard.h | 3 + src/keyboard_amstrad.c | 168 + src/keyboard_amstrad.h | 3 + src/keyboard_at.c | 436 ++ src/keyboard_at.h | 6 + src/keyboard_olim24.c | 285 ++ src/keyboard_olim24.h | 3 + src/keyboard_xt.c | 163 + src/keyboard_xt.h | 3 + src/lpt.c | 66 + src/lpt.h | 2 + src/mame/fmopl.c | 2613 +++++++++++ src/mame/fmopl.h | 126 + src/mame/ymf262.c | 2730 ++++++++++++ src/mame/ymf262.h | 62 + src/mcr.c | 37 + src/mem.c | 1358 ++++++ src/mem.h | 40 + src/model.c | 200 + src/model.h | 16 + src/mouse.c | 4 + src/mouse.h | 5 + src/mouse_ps2.c | 152 + src/mouse_ps2.h | 1 + src/mouse_serial.c | 66 + src/mouse_serial.h | 1 + src/neat.c | 68 + src/neat.h | 1 + src/nvr.c | 204 + src/nvr.h | 1 + src/olivetti_m24.c | 20 + src/olivetti_m24.h | 1 + src/opti.c | 284 ++ src/pc.c | 491 +++ src/pc.rc | 158 + src/pci.c | 99 + src/pci.h | 3 + src/pic.c | 313 ++ src/pic.h | 3 + src/pit.c | 305 ++ src/pit.h | 3 + src/plat-dinput.h | 1 + src/plat-keyboard.h | 15 + src/plat-mouse.h | 13 + src/ppi.c | 19 + src/ppi.h | 1 + src/psg.c | 206 + src/psg.h | 1 + src/resources.h | 62 + src/sblaster.c | 1104 +++++ src/serial.c | 210 + src/serial.h | 17 + src/sound.c | 180 + src/sound.h | 1 + src/soundopenal.c | 143 + src/um8881f.c | 70 + src/um8881f.h | 1 + src/vid_cga.c | 494 +++ src/vid_cga.h | 7 + src/vid_ega.c | 720 ++++ src/vid_ega.h | 7 + src/vid_et4000.c | 141 + src/vid_et4000w32.c | 936 ++++ src/vid_et4000w32i.c | 407 ++ src/vid_hercules.c | 291 ++ src/vid_icd2061.c | 74 + src/vid_icd2061.h | 2 + src/vid_mda.c | 254 ++ src/vid_olivetti_m24.c | 428 ++ src/vid_olivetti_m24.h | 0 src/vid_oti067.c | 108 + src/vid_paradise.c | 273 ++ src/vid_pc1512.c | 444 ++ src/vid_pc1640.c | 97 + src/vid_pc200.c | 102 + src/vid_s3.c | 1533 +++++++ src/vid_sdac_ramdac.c | 148 + src/vid_sdac_ramdac.h | 4 + src/vid_stg_ramdac.c | 104 + src/vid_stg_ramdac.h | 2 + src/vid_svga.c | 1392 ++++++ src/vid_svga.h | 53 + src/vid_tandy.c | 611 +++ src/vid_tkd8001_ramdac.c | 64 + src/vid_tkd8001_ramdac.h | 2 + src/vid_tvga.c | 199 + src/vid_unk_ramdac.c | 66 + src/vid_unk_ramdac.h | 2 + src/video.c | 494 +++ src/video.h | 150 + src/wd76c10.c | 102 + src/wd76c10.h | 1 + src/win-d3d.cc | 225 + src/win-d3d.h | 9 + src/win-ddraw.cc | 291 ++ src/win-ddraw.h | 12 + src/win-keyboard.cc | 109 + src/win-mouse.cc | 72 + src/win-opengl.c | 148 + src/win-opengl.h | 3 + src/win-timer.c | 8 + src/win-video.c | 49 + src/win.c | 1644 +++++++ src/win.h | 3 + src/x86.c | 3686 ++++++++++++++++ src/x86.h | 98 + src/x86_flags.h | 17 + src/x86seg.c | 2543 +++++++++++ src/x87.c | 1106 +++++ src/x87.h | 3 + src/xtide.c | 55 + src/xtide.h | 1 + win486.nvr | Bin 0 -> 128 bytes 188 files changed, 52566 insertions(+) create mode 100644 COPYING create mode 100644 acer386.nvr create mode 100644 ami286.nvr create mode 100644 ami386.nvr create mode 100644 ami486.nvr create mode 100644 at.nvr create mode 100644 cmdpc30.nvr create mode 100644 dell200.nvr create mode 100644 europc.nvr create mode 100644 hot-433.nvr create mode 100644 mda.rom create mode 100644 megapc.nvr create mode 100644 pc1512.nvr create mode 100644 pc1640.nvr create mode 100644 pc2086.nvr create mode 100644 pc3086.nvr create mode 100644 readme.txt create mode 100644 roms/acer386/roms.txt create mode 100644 roms/ami286/roms.txt create mode 100644 roms/ami386/roms.txt create mode 100644 roms/ami486/roms.txt create mode 100644 roms/cmdpc30/roms.txt create mode 100644 roms/dells200/roms.txt create mode 100644 roms/dtk/roms.txt create mode 100644 roms/europc/roms.txt create mode 100644 roms/genxt/roms.txt create mode 100644 roms/hot-433/roms.txt create mode 100644 roms/ibmat/roms.txt create mode 100644 roms/ibmpc/roms.txt create mode 100644 roms/ibmxt/roms.txt create mode 100644 roms/megapc/roms.txt create mode 100644 roms/olivetti_m24/roms.txt create mode 100644 roms/pc1512/roms.txt create mode 100644 roms/pc1640/roms.txt create mode 100644 roms/pc200/roms.txt create mode 100644 roms/pc2086/roms.txt create mode 100644 roms/pc3086/roms.txt create mode 100644 roms/tandy/roms.txt create mode 100644 roms/win486/roms.txt create mode 100644 src/286.c create mode 100644 src/386.c create mode 100644 src/Makefile.mingw create mode 100644 src/acer386sx.c create mode 100644 src/acer386sx.h create mode 100644 src/adlib.c create mode 100644 src/ali1429.c create mode 100644 src/ali1429.h create mode 100644 src/amstrad.c create mode 100644 src/amstrad.h create mode 100644 src/cdrom-ioctl.c create mode 100644 src/cdrom-ioctl.h create mode 100644 src/cms.c create mode 100644 src/config.c create mode 100644 src/config.h create mode 100644 src/cpu.c create mode 100644 src/cpu.h create mode 100644 src/dac.c create mode 100644 src/dma.c create mode 100644 src/dma.h create mode 100644 src/ega.c create mode 100644 src/fdc.c create mode 100644 src/fdc.h create mode 100644 src/filters.h create mode 100644 src/gus.c create mode 100644 src/harddisk.c create mode 100644 src/headland.c create mode 100644 src/headland.h create mode 100644 src/ibm.h create mode 100644 src/ide.c create mode 100644 src/ide.h create mode 100644 src/io.c create mode 100644 src/io.h create mode 100644 src/jim.c create mode 100644 src/jim.h create mode 100644 src/keyboard.c create mode 100644 src/keyboard.h create mode 100644 src/keyboard_amstrad.c create mode 100644 src/keyboard_amstrad.h create mode 100644 src/keyboard_at.c create mode 100644 src/keyboard_at.h create mode 100644 src/keyboard_olim24.c create mode 100644 src/keyboard_olim24.h create mode 100644 src/keyboard_xt.c create mode 100644 src/keyboard_xt.h create mode 100644 src/lpt.c create mode 100644 src/lpt.h create mode 100644 src/mame/fmopl.c create mode 100644 src/mame/fmopl.h create mode 100644 src/mame/ymf262.c create mode 100644 src/mame/ymf262.h create mode 100644 src/mcr.c create mode 100644 src/mem.c create mode 100644 src/mem.h create mode 100644 src/model.c create mode 100644 src/model.h create mode 100644 src/mouse.c create mode 100644 src/mouse.h create mode 100644 src/mouse_ps2.c create mode 100644 src/mouse_ps2.h create mode 100644 src/mouse_serial.c create mode 100644 src/mouse_serial.h create mode 100644 src/neat.c create mode 100644 src/neat.h create mode 100644 src/nvr.c create mode 100644 src/nvr.h create mode 100644 src/olivetti_m24.c create mode 100644 src/olivetti_m24.h create mode 100644 src/opti.c create mode 100644 src/pc.c create mode 100644 src/pc.rc create mode 100644 src/pci.c create mode 100644 src/pci.h create mode 100644 src/pic.c create mode 100644 src/pic.h create mode 100644 src/pit.c create mode 100644 src/pit.h create mode 100644 src/plat-dinput.h create mode 100644 src/plat-keyboard.h create mode 100644 src/plat-mouse.h create mode 100644 src/ppi.c create mode 100644 src/ppi.h create mode 100644 src/psg.c create mode 100644 src/psg.h create mode 100644 src/resources.h create mode 100644 src/sblaster.c create mode 100644 src/serial.c create mode 100644 src/serial.h create mode 100644 src/sound.c create mode 100644 src/sound.h create mode 100644 src/soundopenal.c create mode 100644 src/um8881f.c create mode 100644 src/um8881f.h create mode 100644 src/vid_cga.c create mode 100644 src/vid_cga.h create mode 100644 src/vid_ega.c create mode 100644 src/vid_ega.h create mode 100644 src/vid_et4000.c create mode 100644 src/vid_et4000w32.c create mode 100644 src/vid_et4000w32i.c create mode 100644 src/vid_hercules.c create mode 100644 src/vid_icd2061.c create mode 100644 src/vid_icd2061.h create mode 100644 src/vid_mda.c create mode 100644 src/vid_olivetti_m24.c create mode 100644 src/vid_olivetti_m24.h create mode 100644 src/vid_oti067.c create mode 100644 src/vid_paradise.c create mode 100644 src/vid_pc1512.c create mode 100644 src/vid_pc1640.c create mode 100644 src/vid_pc200.c create mode 100644 src/vid_s3.c create mode 100644 src/vid_sdac_ramdac.c create mode 100644 src/vid_sdac_ramdac.h create mode 100644 src/vid_stg_ramdac.c create mode 100644 src/vid_stg_ramdac.h create mode 100644 src/vid_svga.c create mode 100644 src/vid_svga.h create mode 100644 src/vid_tandy.c create mode 100644 src/vid_tkd8001_ramdac.c create mode 100644 src/vid_tkd8001_ramdac.h create mode 100644 src/vid_tvga.c create mode 100644 src/vid_unk_ramdac.c create mode 100644 src/vid_unk_ramdac.h create mode 100644 src/video.c create mode 100644 src/video.h create mode 100644 src/wd76c10.c create mode 100644 src/wd76c10.h create mode 100644 src/win-d3d.cc create mode 100644 src/win-d3d.h create mode 100644 src/win-ddraw.cc create mode 100644 src/win-ddraw.h create mode 100644 src/win-keyboard.cc create mode 100644 src/win-mouse.cc create mode 100644 src/win-opengl.c create mode 100644 src/win-opengl.h create mode 100644 src/win-timer.c create mode 100644 src/win-video.c create mode 100644 src/win.c create mode 100644 src/win.h create mode 100644 src/x86.c create mode 100644 src/x86.h create mode 100644 src/x86_flags.h create mode 100644 src/x86seg.c create mode 100644 src/x87.c create mode 100644 src/x87.h create mode 100644 src/xtide.c create mode 100644 src/xtide.h create mode 100644 win486.nvr 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 0000000000000000000000000000000000000000..cc5a06d93de56bf544b0c9ff0546c2615983b796 GIT binary patch literal 128 ycmZQ)5MmH#U=tS-RAc)8pMk-Jfq}uXfr)_yNMiy%rLqC6aoMZOGJMF literal 0 HcmV?d00001 diff --git a/ami286.nvr b/ami286.nvr new file mode 100644 index 0000000000000000000000000000000000000000..bfb993f2fa0827b2f71ea0e4676c9047e6ecc60e GIT binary patch literal 128 zcmWe+@MI8YU}P2&Vq*JApl2K B1|R?c literal 0 HcmV?d00001 diff --git a/ami486.nvr b/ami486.nvr new file mode 100644 index 0000000000000000000000000000000000000000..7055279865cf2ad0e11ef6bfb457ae57b6d1cfe9 GIT binary patch literal 128 zcmXqDFlSI;U}feIQe$vvVBieh{eO>t0~14yzW#q^f&c$G{xjSEXLf)vM-#9-~S&08WBwLSODpi BQ@H>D literal 0 HcmV?d00001 diff --git a/dell200.nvr b/dell200.nvr new file mode 100644 index 0000000000000000000000000000000000000000..b16f18490881a1fcf6115c6dfe6d788aa8d1237a GIT binary patch literal 128 xcmZ=|;9wAEU=tS-WMgt@Fko=`&+y-|fr)|VKQI!r6vt5pVP#$h138BO4gc|he~b$h7#Nt~N&ufnL literal 0 HcmV?d00001 diff --git a/mda.rom b/mda.rom new file mode 100644 index 0000000000000000000000000000000000000000..1b92f042a036027dba033e622a3b2fe05b4c26be GIT binary patch literal 8192 zcmb_h-)m#}bw80^jUI088)L{VRxPa}f*V4(GaBxS%&n|d)Tw6}lCo_26w*7^awkwR zV=~~qbZ?~DWhq<8!x9K||A4;qxvvWX2X!CB?%Oh;$>1mZWmybeydnrGpU?SzzvCHC zhW4SywvNvEp6~hfJ>Q=eaWHuAKi+%q6OqAkx?CQC8w~-#rE+W75((n?^z@W?uv`wb z7g$Te=@I26PCFfvM<0IzJ?mHg@~`5Q+%$~?k=@2_7=|Ll-mur}K~FG^Ph*jGa*z*m zk#DVBsSGQsKL{Y-P=Ne&I(>IbTD`Cwv7ZC@p>oeKDE1Taio+st5DsAvkR%CFJzc^d z#8Yk|9vKc>tupxr5KN5z@U5ndC>lml$-K4cb*4?r+EPR&z43%#1odGXF2^?$Cc8QKTUwYoh^_4Rr4BKyQr^bc@6#{ zyPn4=pBn@u3n_3A7f}}nVHih<7trb@B5TDW27n}JI3IK^#NMFCdMTQQ0PiyCMia!78`xN$kegs z2Q9-C_STTK1N7st2=D>$8Zc_tg2{!B<6Ts3ir-XNdyEr}qWJ)i7*(UV3|q?Q%uZ63 z)4V{Am~xJ8(lXWnVw9cYUQY{+YFGgrs$nDKd_>q=sL)E3rbDL}`9Y4DC!@Eg`sgQV z%?H{Tcdw@fMRBbYWbJ4)I?~}n38Fqw9hi^vG|l(Z2eP(>d<+7i1B{25eiG9jvFb;@ zFh2Oy!j-t+ZwcIN_WMoA;WcA~timv{ctw)qUfKuWV2r2Ap&mrGqCVoc#d{{dD~E;<>is!?arZytuIZh0~+$B1UfzRFsbe z%kr0&u3VxGzY2Ks4)$iyia`Faa(p&wz zDhGSo-(hSfw%z!%#K0PuS$`|shX|Hlo>^G8U|MbSjr)DdwR&b^bZeRUI^a6BQUv-Rv}66w6KF$~q0V4He>qPP zg|M)7{YL?E&Y)0PsSeEYZu~|~-Y|6tEeh;!zR0>RJ73DYma-UCnJ8DT2~K}Hc7d% z@-4*!9u)|7iQL-SQZgzRdvw|yNs#q8P=}EhZFl`JAPO!KNUlQNVm;B|yNk=ROMi#%Ia#P?Kt{r1q61Su-7Z!)d|i5 zO1lqRX42R$uCM}}eix^sUxj1O6r7X4jNN!##yI<{3l4|Y-^WkhQGS}@Xb5omxr{IS z| zy$ZhG`@Eto+%2@htY+BzjhL9-U&QSGB4+nj|8(f^@d7sc9xi7J7jllijIEiMkkfm) z!SNk-?T&WX*>UZ!qF=>#{TzOk-dD9dy{_M7IkUfGolp=l+dpol3Qij1aNn%wy+M*x z!M0mJ^Q%H`J?3eTfa#hLyCc2bhQ!rh6uCM!>y4>C>{rQ%-Ea&pD|YK3cYi`)k4z!Y zmH^LU7vE#8RtlOrdUl9c>6btHv9WWx<>j5!;}D>if2@dl`Ntt(edRBH{lNzxWO1j{L5_mm*LJJbz)HZZt)pzS}YZ3~7M-8zEo0h+S5y1I&ilKuKlxKr=RK^1_0 zy`SBB10efv-o8nB+UwKA+C>h*uw=;Rf=vNDpQB5fmf2aGt9TlRbuessZxX|kCN>Z)<@aokc zlJ2x&uUIJj=;lqX5pidLJb4>B2SEQVGoB~aA6%=|_E9;Z#$R9$IGR+MfbS`nc@a5; zzqf#YzK=juALGFabnV&?kN}D9+_}DrO}l@sMp9ZxKyJ!tgQr^by7?nu6F;!VkAmAl zOr{~-i%ilM72`$~hz_ZSeDpq=@lVqi=$#o!|mN-IV?$04R())Ps#mrAX6yHzR$_3A;jlOs#H zPRQAvtozgM-<^~0LVdBoL7;5M>bWt{*9 z?KY7N3I(|R`@QqO`SEWmo!{R+|NcL{U!WkzLN@Aq^$kejv%V)%`_TNj`~UQv=~w)t zu!A%Ga^@3n0=~u{4b2rh{@1JIJ3y`J?c`Gn^=xk9@(-HU486H&?1FaowBP1tMeV{K zF!eisDz<%T^jN793SjNqWt2H>v$7OjA+2GtG* zTv~g3dm*M%k2X5y~NddAeh8hnFd&IHV}=4k3LE;Z?O4cKSE)0E{E!rMq*C} z*aAVW)4NZ1f(-t0bqM$TYNld%=GJmm;@QXl`~H7r{nwMpBr~u7*#G(Zk4FG~{lE9W z@BesG!3{6v>;Joa1Hk@|BiPIPzj^)V6Pz9!{>=VA8jThR)9wH0pszysABKBsU=qTN zkA$J=y zhT)vAjtb_?$mwSQ4R|jIlhGr|$DchtKglJ;GcvkJHu0Lt#9$BMmgD|pfxG2=H1kL| zlhF)mmH7k;peF-C8XvjGJ06W*{3W!a&qxCE_{DcxrX9Qxgs}hg>C;h$_$QP3WTMZb zX*$Po4tc|QZq~;*^k=fz|7G^e{e{8FnYMqHwgh90ZWH^;pUE~3#`NbT?PvY;M9z?& z{d6JYuW)=Ek7ayv{`528W`8^$<4n!x*aZ4ue)1$ME6sk{1fDX^|6*P;+5yZB&O$-& zFBV@xACy2B`53@V7USOp*I+M$-6Y9`!FxsQ|16LI`#*&*U>Wj>O(FAgjO#HT=hE~E zIN4+b`*^+2C*YHwBTvnKf{@NYA2Q>!!rzep2Y`K#Hv{-`oG<|=$~AZT2@`;R zGX|pim?x1Z%m5UszHQKlsp{9l!?`dI!|U{s-RK7p;zvP#u~_tp`z9pt;SUD+-@~`( zcx4QaL)s)vK7$tg zGCvMeF=+7BPbf5)G~zzuD=a3oHbV}p!Dxi5M6>_)S#rX<$>yAq$o?P4pO60=&;R&` z)#C%itMN3gf0_W=EnEFF9WYFt$(Qpdlb4?VF^3Y?31B`N5y_lSYe(bB(?&X32cEwE z;PVwT3;~Wg=_GAH3ZE&;;8puSlJ*Q{`VEi#z`XaK+si2*_4$Nv_|HB5D}QnE_z!bn zMO+30NY8)?>__1KO1xAq_Dd3g3jW9>LS$?N&_C|^1k%K>-v1AueEJ0QDx1tEGmPMTf`xB{ z`=NO^pJN^3dW?#qpu& z5ho+A-=n0-VkV$k^at|+#fh(2uCO}KxvyYln!ot^4+m6;>pLbg=d%7A3RVDSu=oXk YeE$Cuj{uo@{l|a*Lac^_7x(`^0WqZB8vpFxUez1PEScInTf#`H|s2 X149GT|NjgP4F3rMA)q?k;0q%FUiD5M literal 0 HcmV?d00001 diff --git a/pc1512.nvr b/pc1512.nvr new file mode 100644 index 0000000000000000000000000000000000000000..b1f758b3eb1e48c42a9253b22710a853d1f9c5b0 GIT binary patch literal 128 rcmXqIP-0MKU=tS-WMg1xP*Mi5Qh8>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 0000000000000000000000000000000000000000..97221385ab82839e593ef6bcf2ddce0ccd9d2137 GIT binary patch literal 128 zcmZQ$@L&*UU}feIQe$vvVBieh&G5j#fr){K0TUeNVxGmoBiYDcz|a7Z<