diff --git a/CHANGES b/CHANGES.txt similarity index 87% rename from CHANGES rename to CHANGES.txt index 56bedb5..9a884b9 100644 --- a/CHANGES +++ b/CHANGES.txt @@ -1,4 +1,61 @@ +Changes in KEGS v0.91 since v0.90 (12/06/04) +- Fixed serious bug in engine_c.c that could cause Finder file copies to + silently corrupt data. +- Virtual Modem support--modem appears on serial port, allows outgoing + and incoming connections. +- Sockets (and Virtual Modem) supported on Windows. +- Fixed various reset bugs (where pressing Ctrl-Reset would cause infinite + beeps, etc). +- Allow user to select ROM file from config panel if not found. +- Improved Mac OS X interface: Full Screen support and error dialogs. +- Better floppy support by always having 5.25" read nearest track regardless + of head position (supports Last Gladiator game bad crack by + emulating other emulators). + +Changes in KEGS v0.90 since v0.89 (10/19/04) +- Make Keypad Joystick the default joystick emulation +- Fix timezone calculation on Mac OS X for central time zone. +- Fix handling of long paths in config panel, reported by David Scruffham. +- Always call joystick_init at startup. +- Fix F2 keymappings for X Windows, to fix some issue reported by + David Wilson. +- Fixed some documentation issues reported by David Wilson. +- Fixed a bug in joystick_driver.c reported by Doug Mitton. +- Add README.a2.compatibility to discuss known issues with programs. + +Changes in KEGS v0.89 since v0.88 (10/17/04) +- Make old mouse button presses disappear after .5 seconds. +- Add Keypad Joystick, along with configuration menu choices to enable it. + The keypad numbers move the joystick to the indicated direction, + with chording allowing in-between values. + The keypad '0' is button 0 and keypad '1' is button 1. +- Also add jostick scaling factor and trim adjustment. +- Allow user to increase keyboard and mouse scan rate to 240Hz from 60Hz + for some better game response. + +Changes in KEGS v0.88 since v0.87 (10/13/04) +- Add configuration setting to debug halt on code red halts. Also add + configuration mode (on by default) to shadow text page 2 on ROM 01, + which is an enhancement over a real IIgs. +- Handle mac binary header on images. Handle compressed .po images. +- Fix refresh rate to 59.923Hz from 60Hz so that exactly 17030 1MHz cycles + pass in one screen refresh period. +- Enhance trace-to-file function to also write out data values stored using + the Data_log info. +- Debugger adds memory move and memory compare functions. +- Support "floating bus" where reading certain $C0xx locations returns the + current video data. This allows Bob Bishop's split-screen demos to + run and enables Drol's between-level animations to work fully. + +Changes in KEGS v0.87 since v0.86 (10/05/04) +- Remove all of Jonathan Kalbfeld's and Gilles Tschopp's contributions. + All of Solaris audio is removed. +- Fix config screen not drawing correctly if emulator was currently displaying + video page 2. +- Fix STP instruction. +- Fix mouse-joystick which was halving the Y dimension. + Changes in KEGS v0.86 since v0.85 (03/23/04) - Add patch for Solaris sound by Jonathan Kalbfeld. - Fix so that F4 enters config panel even while running Prosel-16 diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..960fe74 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/KEGSMAC.app/Contents/Info.plist b/KEGSMAC.app/Contents/Info.plist index 15a616a..d810c7d 100644 --- a/KEGSMAC.app/Contents/Info.plist +++ b/KEGSMAC.app/Contents/Info.plist @@ -4,8 +4,46 @@ CFBundleDevelopmentRegion English + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + 2mg + 2MG + + CFBundleTypeIconFile + 2mg.icns + CFBundleTypeName + Apple II 2MG Disk Image + CFBundleTypeOSTypes + + a2mg + + CFBundleTypeRole + None + + + CFBundleTypeExtensions + + kegs + + CFBundleTypeIconFile + 525.icns + CFBundleTypeName + KEGS Configuration File + CFBundleTypeOSTypes + + kegs + + CFBundleTypeRole + None + + CFBundleExecutable KEGSMAC + CFBundleName + KEGSMAC CFBundleIconFile kegsicon.icns CFBundleInfoDictionaryVersion @@ -13,10 +51,14 @@ CFBundlePackageType APPL CFBundleSignature - ???? + KEGS CFBundleVersion - 0.1 - CSResourcesFileMapped - + 0.91 + CFBundleShortVersionString + KEGSMAC version 0.91 + CFBundleGetInfoString + KEGSMAC v0.91, Copyright 2004 Kent Dickey, http://kegs.sourceforge.net + NSHumanReadableCopyright + Copyright 2004 Kent Dickey diff --git a/KEGSMAC.app/Contents/MacOS/KEGSMAC b/KEGSMAC.app/Contents/MacOS/KEGSMAC index 81fafe8..2255037 100755 Binary files a/KEGSMAC.app/Contents/MacOS/KEGSMAC and b/KEGSMAC.app/Contents/MacOS/KEGSMAC differ diff --git a/KEGSMAC.app/Contents/Resources/2mg.icns b/KEGSMAC.app/Contents/Resources/2mg.icns new file mode 100644 index 0000000..1e612e0 Binary files /dev/null and b/KEGSMAC.app/Contents/Resources/2mg.icns differ diff --git a/KEGSMAC.app/Contents/Resources/525.icns b/KEGSMAC.app/Contents/Resources/525.icns new file mode 100644 index 0000000..94e5a90 Binary files /dev/null and b/KEGSMAC.app/Contents/Resources/525.icns differ diff --git a/KEGSMAC.app/Contents/Resources/English.lproj/InfoPlist.strings b/KEGSMAC.app/Contents/Resources/English.lproj/InfoPlist.strings deleted file mode 100644 index 036ca1e..0000000 Binary files a/KEGSMAC.app/Contents/Resources/English.lproj/InfoPlist.strings and /dev/null differ diff --git a/README.a2.compatibility.txt b/README.a2.compatibility.txt new file mode 100644 index 0000000..3b667c8 --- /dev/null +++ b/README.a2.compatibility.txt @@ -0,0 +1,123 @@ +# $Id: README.a2.compatibility,v 1.2 2004/10/18 18:17:21 kentd Exp $ + +Flobynoid: Must disable Fast Disk Emul (hit F7 to toggle it off) since + game's loader relies on the sector order on the disk (reads 8 + sectors from the start without checking headers, assumes every other + physical sector is skipped due to decode delays). + +Bard's Tale II GS: Doesn't recognize any save disk as a ProDOS disk. + It's detecting a "ProDOS" disk by checking for a string on block + 0 at offset 0x15e. GSOS on system 6 has moved the string to 0x162, + so disks inited under GSOS will be detected as "Not a PRODOS disk". + Just make a copy of the Bard's Tale disk image to another file and + then mount that new image and remove all the files using the Finder. + Then rename the volume and you have a working save disk. + +Robotron 2084: +Robot Battle: + These cracks use a "Fastloader" which is buggy. + It tries to JMP $F3D4 and expects to hit an RTS soon. + But on a IIgs it will access some illegal memory causing a code + yellow. You can just ignore the code yellow. + +Beyond Castle Wolfenstein: Make sure your disk is writeable (not compressed!) + +Breakout: Has trouble loading from the cracked copy. + From the BASIC prompt, do: "CALL -151" then "C083 N C083" then + "BLOAD INTBASIC" then run breakout. Then it runs fine. + +Burgertime: This is a bad crack. Loader starts the game by writing + the game entry point into $0036/$0037, and then executing a BRK + instruction. The BRK handler on an old Apple II will try to write + out a message by calling through $0036/$0037, and this will start + the game. But on a IIgs, the ROM sets the $0036/$0037 vectors + back to the default, and so we crash into the monitor instead. + Here's a memory fix and a disk-image fix: From the crack screen, + press Shift-F6 (or middle mouse button) and in the KEGS debugger + window enter: "1d0a:ea 6c 36 0" and then "g". You can make + this fix to the disk image using a sector editor and change + Track $1E sector $09 offset $0A from "60 78 A9 03" to "EA 6C 36 00" + and write it back. + +Caverns of Callisto: Requires old C600 ROM in slot 6 (Slot 6==Your Card). + +Championship Loderunner: Requires disk to be writeable or else it starts + the level and then jumps immediately back to the title page. + +Jeopardy: Disk must be writeable or else it displays "DISK ERROR" and + then crashes into the monitor. + + +Drol: Needs slot 6 set to "Your Card" from the IIgs control panel + (Ctrl-Cmd-ESC, then choose "Slots"). + I found Drol hard, so here are some cheats. First, the standard cheat + for Drol is to have infinite lives, this cheat is to edit the disk + image: + Track $0B, Sector $0A, byte $22 to EA EA + Track $11, Sector $0A, byte $10 to EA EA + Track $17, Sector $09, byte $B2 to EA EA + I didn't create those cheats, I got it from textfiles.com. + My cheats are for the monsters to never kill you--just run right + through them. + While playing Drol, press Shift-F6 (or middle mouse button) to + enter the KEGS debugger, and then: + 0/f28:18 18 # Monsters' missiles won't kill you + 0/e05:90 0c # Monsters won't kill you + Continue emulation by type "g" and then enter. + Other things, like the bird, axes, swords still kill you. + To easily solve the third screen, move your man to the far right + side on the top level, so that you are directly above the woman + on the bottom row. Fly into the air "A" and then get to the KEGS + debugger, and type: + 0/c:4 + and then continue with "g". Now press "Z" and you will go all + the way down and land on the woman and end the level. It's + useful to have made the two above patches so that touching monsters + won't kill you. + Two more patches that only apply to level 3, and so most be made + in memory each time you enter level 3: + 6cf3:18 18 18 # Axes won't kill you + 6f70:38 38 # Swords/arrows won't kill you + The bird and the guy you can't kill will still kill you. These + cheats were enough to make the game easily playable. + In the game, your death is indicated by setting location $001E to + $FF. Setting breakpoints there can let you find other cheats. + +Moon Patrol: Crashes into the monitor after completing checkpoint E. + To fix the Moon Patrol/Dung beetles version, from within KEGS: + BLOAD MOON PATROL + CALL -151 + 1E15:EA + 919G + and it will work fine. + If you have the booting version that just has Moon Patrol on it, + then from any point after the crack screen is shown, enter the + KEGS debugger (Shift-F6 or middle moust button) and then enter: + 0/1e15:ea + g + and then it will play fine. + The bug is that the code executes an instruction with opcode $02, + which is a NOP on 6502, but is a COP instruction to 65816. The + COP instruction acts like BRK and will crash. The patch just + makes it a real NOP. + +Microbe: Crashes upon booting. + Code at $599E tries to pull a return address off of a location + beneath the stack pointer and jump to it, but it doesn't add 1 + correctly so it jumps to $5917 when it meant to jump to $5918. + On a IIgs, this causes a BRK to be executed and the game to crash. + This can be patched in memory in two places: + 0/599e:ba ca 9a 7d 00 01 48 98 7d 01 01 9d 01 01 60 + 0/6f1d:ba ca 9a 7d 00 01 48 98 7d 01 01 9d 01 01 60 + The original byte sequence for both locations is: + 00/599e: ba TSX + 00/599f: 7d ff 00 ADC $00ff,X + 00/59a2: 85 94 STA $94 + 00/59a4: 98 TYA + 00/59a5: 7d 00 01 ADC $0100,X + 00/59a8: 85 95 STA $95 + 00/59aa: 6c 94 00 JMP ($0094) + You can also patch the code onto the disk image. I found + the $599E version on Track $05, Sector $06, Byte $9E. + I found the $6F1D version on the image at Track $0C, Sector $00, + at byte $1D. diff --git a/README.compile b/README.compile.txt similarity index 63% rename from README.compile rename to README.compile.txt index 1563e6f..098b164 100644 --- a/README.compile +++ b/README.compile.txt @@ -1,5 +1,4 @@ - -NOTE: The build process changed as of KEGS v0.70! +# $Id: README.compile,v 1.20 2004/10/18 04:05:14 kentd Exp $ General build instructions: -------------------------- @@ -39,8 +38,11 @@ Use the vars_x86linux file with: rm vars; ln -s vars_x86linux vars make -KEGS assumes perl is in your path. If it is somewhere else, you need to edit -the "PERL = perl" line in the vars file and make it point to the correct place. +The resulting executable is called "xkegs". + +The build scripts assume perl is in your path. If it is somewhere else, +you need to edit the "PERL = perl" line in the vars file and make it point +to the correct place. For audio, KEGS needs access to /dev/dsp. If the permissions do not allow KEGS to access /dev/dsp, it can fail with a cryptic error message. As root, @@ -55,11 +57,12 @@ Use the vars_linuxppc vars file by: rm vars; ln -s vars_linuxppc vars make -KEGS assumes perl is in your path. If it is somewhere else, you need to edit -the "PERL = perl" line in the vars file and make it point to the correct place. +The build scripts assume perl is in your path. If it is somewhere else, +you need to edit the "PERL = perl" line in the vars file and make it point +to the correct place. Audio is currently disabled by default, but you can try turning it on -by runnning "kegs -audio 1". It sounds horrible to me, but sounds do +by runnning "xkegs -audio 1". It sounds horrible to me, but sounds do come out. Solaris SPARC build instructions: @@ -70,11 +73,12 @@ Use the vars_solaris vars file by: rm vars; ln -s vars_solaris vars make -KEGS assumes perl is in your path. If it is somewhere else, you need to edit -the "PERL = perl" line in the vars file and make it point to the correct place. +The build scripts assume perl is in your path. If it is somewhere else, +you need to edit the "PERL = perl" line in the vars file and make it point +to the correct place. Audio is currently disabled by default, but you can try turning it on -by runnning "kegs -audio 1". +by runnning "xkegs -audio 1". Solaris x86 build instructions: -------------------------------- @@ -84,11 +88,12 @@ Use the vars_x86solaris vars file by: rm vars; ln -s vars_x86solaris vars make -KEGS assumes perl is in your path. If it is somewhere else, you need to edit -the "PERL = perl" line in the vars file and make it point to the correct place. +The build scripts assume perl is in your path. If it is somewhere else, +you need to edit the "PERL = perl" line in the vars file and make it point +to the correct place. Audio is currently disabled by default, but you can try turning it on -by runnning "kegs -audio 1". +by runnning "xkegs -audio 1". HP-UX assembly-emulation instructions: ------------------------------------- @@ -100,14 +105,14 @@ rm vars; ln -s vars_hp vars Edit the Makefile, and remove "engine_c.o" from the "OBJECTS1=" line at the top. Then just type "make". +This version is quite out of date and most likely does not compile any more. Other platform "C" build instructions: ------------------------------------- -I don't know--you tell me. If you are porting to an X-windows and -Unix-based machine, it should be easy. Start with vars_x86linux if -you are a little-endian machine, or vars_linuxppc if you are big -endian. Don't define -DKEGS_LITTLE_ENDIAN unless your processor is -little-endian (x86, Alpha). Mac, Sun, MIPS, HP, Motorola, and IBM are -big-endian. +If you are porting to an X-windows and Unix-based machine, it should be +easy. Start with vars_x86linux if you are a little-endian machine, or +vars_linuxppc if you are big endian. Don't define -DKEGS_LITTLE_ENDIAN +unless your processor is little-endian (x86, Alpha). Mac, Sun, MIPS, +HP, Motorola, and IBM are big-endian. diff --git a/README.kegs b/README.kegs.txt similarity index 73% rename from README.kegs rename to README.kegs.txt index 379968b..d850a10 100644 --- a/README.kegs +++ b/README.kegs.txt @@ -1,18 +1,19 @@ -KEGS: Kent's Emulated GS version 0.86 +KEGS: Kent's Emulated GS version 0.91 http://kegs.sourceforge.net/ What is this? ------------- KEGS is an Apple IIgs emulator for Mac OS X, Linux, and Win32. -The Apple IIgs was the last released computer in the Apple II line. -It first was sold in 1986. +The Apple IIgs was the most powerful computer in the Apple II line. +It first was sold in 1986. An Apple IIgs has the capability to run almost all +Apple II, Apple IIe, and Apple IIc programs. KEGS supports all Apple IIgs graphics modes (which include all Apple //e modes), plus plays all Apple IIgs sounds accurately. It supports -limited serial port emulation through sockets, or can use real serial ports -on Windows and Mac OS X. +serial port emulation through TCP/IP connections, or can use real +serial ports on Windows and Mac OS X. The ROMs and GS/OS (the Apple IIgs operating system) are not included with KEGS since they are not freely distributable. KEGS is a little @@ -20,49 +21,53 @@ user-hostile now, so if something doesn't work, let me know what went wrong, and I'll try to help you out. See my email address at the end of this file. +I'd like to thank Chea Chee Keong who created KEGS32, the first Windows +port of KEGS. That version, which has a better Windows-interface but which +is based on older core code, is at http://www.geocities.com/akilgard/kegs2. + KEGS features: ------------- Fast 65816 emulation: - About 80MHz on a P4 1.7GHz or a G4 1GHz. + About 80MHz on a Pentium 4 1.7GHz or a Mac G4 1GHz. Emulates low-level 5.25" and 3.5" drive accesses (even nibble-copiers work!). Emulates classic Apple II sound and 32-voice Ensoniq sound. All sound is played in 16-bit stereo at 48KHz (44100 on a Mac). -Emulates all Apple IIgs graphics modes, including border effects. - Can handle mixed-displays (superhires at the top, lores at the bottom). - Always does 60 full screen video updates per second. - Even supports 3200-color pictures. +Emulates all Apple IIgs and Apple II graphics modes, including border effects. + Can handle display changes at any time (superhires at the top, lores + at the bottom). Always does 60 full screen video updates per second. + Supports 3200-color pictures. Mouse and joystick support. -Emulates all Apple IIgs memory "tricks" for full compatibility. -Low-level ADB keyboard and mouse emulation enables Wolfenstein 3D to run. -Clock chip emulation makes the host time available to the Apple IIgs. Emulated battery RAM remembers control panel settings. -Limited SCC (serial port) emulation to enable PR#1/2 IN#1/2 and other - serial programs to work. +Limited SCC (serial port) emulation to enable PR#1/2 IN#1/2 and Virtual + Modem enables standard Apple terminal programs to telnet to any + internet address (or receive connections from another telnet). -KEGS by default emulates a 8MB Apple IIgs, but you can change this with -the "-mem" command line option. +KEGS by default emulates a 8MB Apple IIgs, but you can change this from +the Configuration Panel. KEGS is so accurate, even the built-in ROM selftests pass (you must be in -2.8MHz speed mode to pass the self-tests). +2.8MHz speed mode to pass the self-tests and you must set the Configuration +Panel entry "Enable Text Page 2 shadow" to "Disabled on ROM 01" for ROM 01). Release info: ------------ Included files: CHANGES - Description of changes since last release - README.kegs - you're here - README.compile - Describes how to build KEGS - README.linux.rpm - Describes how to install KEGS's RPM for Linux - README.win32 - Win32 special directions - README.mac - Mac OS X special directions - INTERNALS.overview - description of how KEGS code works - INTERNALS.xdriver - Describes the xdriver.c routines for porting - INTERNALS.iwm - Describes the internal 3.5" and 5.25" disk + README.kegs.txt - you're here + README.compile.txt - Describes how to build KEGS + README.linux.rpm.txt - Describes how to install KEGS's RPM for Linux + README.win32.txt - Win32 special directions + README.mac.txt - Mac OS X special directions + README.a2.compatibility.txt - List of programs which need tweaking + src/INTERNALS.overview - description of how KEGS code works + src/INTERNALS.xdriver - Describes the xdriver.c routines for porting + src/INTERNALS.iwm - Describes the internal 3.5" and 5.25" disk handling routines - kegs - the executable, for HP-UX 10.20+ - kegs.spec - The Linux spec file for making an RPM - kegs_conf - disk image configuration info + KEGSMAC - the Mac OS X executable + kegswin.exe - the Windows executable + config.kegs - disk image configuration info to_pro - Hard-to-use ProDOS volume creator partls - Lists partitions on Apple-partitioned hard drives or CD-ROMs @@ -71,9 +76,10 @@ Included files: You need to provide: 1) Patience. - 2) a ROM file called "ROM", "ROM.01" or "ROM.03" in the KEGS directory. - It can be either from a ROM 01 (131072 bytes long) or from a - ROM 03 machine (262144 bytes long.) + 2) a ROM file called "ROM", "ROM.01" or "ROM.03" in the KEGS directory + (or in your home directory). It can be either from a ROM 01 + (131072 bytes long) or from a ROM 03 machine (262144 bytes + long.) 3) A disk image to boot. This can be either "raw" format or 2IMG. See discussion below. GS/OS would be best. @@ -87,10 +93,11 @@ or fc/0000 - ff/ffff from a ROM 03 GS, and put that in a file called Running KEGS: ------------ -The distribution comes in 3 parts: a source-only distribution (kegs.xxx.tar.gz), -along with two binary distributions for Mac and Windows. +The distribution comes with the full source code for all platforms in +the src/ directory, the Windows executable as kegswin.exe, and the Mac OS X +executable as KEGSMAC. -See the README.compile file for more info about compiling for Linux. +See the README.compile.txt file for more info about compiling for Linux. On all platforms except the Mac, you must start KEGS from a terminal window. KEGS will open a new window and use the window you started it from @@ -98,50 +105,68 @@ as a "debug" window. On a MAC, you need to place the "config.kegs" file someplace where KEGS can find it. The simplest place is in your home directory, so copy it there -with the Finder (or using the Terminal). +with the Finder (or using the Terminal). You can also make the directory +Library/KEGS from your home directory, and then place config.kegs there +along with the ROM file. You do not need a starting config.kegs file +on a Mac--KEGS will offer to make it for you if it cannot find one. Start kegs by Double-clicking the KEGSMAC icon on a MAC, or by running the executable (kegswin on Windows, and kegs on Linux). KEGSMAC can -be run by the Terminal window as well (which enables access to more debug -information) by typing: "./KEGSMAC.app/Contents/MacOS/KEGSMAC". +be run by the Terminal window on a Mac as well (which enables access to +more debug information) by typing: "./KEGSMAC.app/Contents/MacOS/KEGSMAC". Assuming all goes well, KEGS will then boot up but probably not find any disk images. See below for how to tell KEGS what disk images to use. Tip: Hitting "F8" locks the mouse in the window (and hides the host cursor) until you hit "F8" again. -Disk Images: +Configuration Panel: +------------------- + +You enter the Configuration panel by pressing F4 at any time. You tell +KEGS what disk images to use through the Configuration panel. (If KEGS +couldn't find a ROM file, you will be forced into the Configuration +Panel mode until you select a valid ROM file). + +To select a ROM file, select "ROM File Selection" and then select your +ROM file. If you were not forced into the panel at startup, the KEGS +found one and you can skip this step. + +Disk Images ----------- -You tell KEGS what disk images to use through the Configuration panel. +The primary use of the Configuration Panel is to select disk images. To +change disk images being used, select "Disk Configuration". Each slot +and drive that can be loaded with an image is listed. "s5d1" means slot +5, drive 1. Slot 5 devices are 3.5" 800K disks, and slot 6 devices are +5.25" 140K disks. Slot 7 devices are virtual hard drives, and can be +any size at all (although ProDOS-formatted images should be less than +32MB). -You enter the Configuration panel by pressing F4 at any time. Then select, -"Disk Configuration". Each slot and drive that can be loaded with an image -is listed. "s5d1" means slot 5, drive 1. Slot 5 devices are 3.5" 800K disks, -and slot 6 devices are 5.25" 140K disks. Slot 7 devices are virtual hard -drives, and can be any size at all (although ProDOS-formatted drives -should be less than 32MB). - -Just use the arrow keys to navigate to the device entry to change, -and then select it by pressing Return. A scrollable file selection -interface is presented, letting you located your image files. To -save navigation, you can press Tab to toggle between entering a path -manually, and using the selector. Press Return on ".." entries to go up -a directory level. When you find the image you want, just press Return. +Just use the arrow keys to navigate to the device entry to change, and +then select it by pressing Return. A scrollable file selection +interface is presented, letting you locate your image files. To quickly +jump to a particular path, you can press Tab to toggle between entering +a path manually, and using the file selector. Press Return on ".." +entries to go up a directory level. When you find the image you want, +just press Return. If the image has partitions that KEGS supports, another selection dialog will have you select which partition to mount. You will probably -only have partitions on direct devices you mount. For instance, on a -Mac, /dev/disk1 is usually the CDROM drive. +only have partitions on direct devices you mount (or on a Mac, of .dmg +images of CDs). For instance, on a Mac, /dev/disk1 can sometimes be the +CDROM drive. -KEGS can handle "raw", .dsk, .po, 2IMG, 5.25" ".nib" images, some Mac +KEGS can handle "raw", .dsk, .po, 2IMG, 5.25" ".nib" images, most Mac Diskcopy images and partitioned images. The .dsk and .po formats you often find on the web are really "raw" formats, and so they work fine. KEGS uses the host file permissions to encode the read/write status of the image. +KEGS can open any image file compressed with gzip (with the extension ".gz") +automatically as a read-only disk image. An image is the representation of an Apple IIgs disk, but in a file on your computer. For 3.5" disks, for example, a raw image would be exactly -800K bytes long (819200 bytes). KEGS intercepts the emulated GS accesses to +800K bytes long (819200 bytes). KEGS directs the emulated GS accesses to the image, and does the correct reads and writes of the Unix file instead. To do "useful" things with KEGS, you need to get a bootable disk image. @@ -150,21 +175,36 @@ get Apple IIgs System 6. Unfortunately, Apple now only has .sea files which are executable files for Macintosh only. You need a macintosh to execute those programs, which creates Disk Copy image files with no special extensions (and with spaces in the names). Once you get those files back to your -host machine, you can use them by listing them in kegs_conf. +host machine, you can use them by selecting them from the Configuration Panel. + +You can also get Apple II programs in ".dsk" format from a variety of +sites on the internet, and these should all work on KEGS as well. KEGS also supports partitioned devices. For instance, if you have a CD-ROM on your computer, just pop an Apple II CD in, and KEGS can mount it, if -you have a Unix-base system (Linux, any Unix, and Mac OS X). +you have a Unix-based system (Linux, any Unix, and Mac OS X). If you're on a Mac, be careful letting KEGS use your HFS partitions-- -GSOS has many HFS bugs when it is writing. +GSOS has many HFS bugs when it is writing. Also avoid having KEGS access +an image which have mounted on your Mac at the same time (always unmount +it from your Mac before letting KEGS access it)! -If you do not have any disk mounted in s7d1, KEGS will jump into BASIC. +If you do not have any disk mounted in s7d1, KEGS will jump into the monitor. +To boot slot 6 (or slot 5), use the Apple IIgs Control Panel by pressing +Ctrl-Command-ESC. Support for 5.25" nibblized images is read-only for now (since the -format is kinda simplistic, it's tricky for KEGS to write to it). -Just mount your image, like "disk.nib" in the kegs_conf file like -any .dsk or .po image. +format is kinda simplistic, it's tricky for KEGS to write to it since KEGS +has more information than fits in that format). Just select your image, +like "disk.nib" in the kegs_conf file like any .dsk or .po image. + +In addition to changing disks, you can also just "eject" and image by +moving the cursor to select that slot/drive and then press "E". The +emulated IIgs will immediately detect changes to s5d1 and s5d2. + +Care should be taken when changing images in slot 7--KEGS does not notify +GSOS that images have changed (or been ejected), and so it's best to make +changes when GSOS is not running. Key summary: @@ -180,8 +220,8 @@ F7: Toggle fast_disk_emul on/off F8: Toggle pointer hiding on/off. F9: Invert the sense of the joystick. Shift-F9: Swap x and y joystick/paddle axes. -F10: Attempt to change the a2vid_palette (only useful on 8-bit color display) -F11: Full screen mode (does not do anything yet). +F10: Attempt to change the a2vid_palette (only useful on 256-color displays) +F11: Full screen mode (only on Mac OS X). F12: Alias of Pause/Break which is treated as Reset F2, Alt_R, Meta_r, Menu, Print, Mode_switch, Option: Option key @@ -202,35 +242,15 @@ KEGS hides the host cursor automatically and enables special tracking which forces the emulated cursor to follow the host cursor. If this doesn't work right under some program, just press F8 for better compatibility. -The default joystick is the mouse position. Upper left is 0,0. Lower right -is 255,255. Press Shift-F9 to swap the X and Y axes. Press F9 to reverse -the sense of both paddles (so 0 becomes 255, etc). Swapping and -reversing are convenient with paddle-based games like "Little Brick Out" -so that the mouse will be moving like the paddle on the screen. "Little -Brick Out" is on the DOS 3.3 master disk. The joystick does not work -properly if the pointer is constrained in the window. - -If you have a real joystick on Linux, start KEGS with "-joystick" and -you should be able to use it. Real joysticks should also work on Windows. - -The left mouse button is the mouse button for KEGS. The right mouse -button (if you have it) or F6 toggles between four speed modes. Mode 0 -(the default) means run as fast as possible. Mode 1 means run at 1MHz. -Mode 2 means run at 2.8MHz. Mode 3 means run at 8.0MHz (about the speed -of a ZipGS accelerator). Most Apple //e (or earlier) games need to be -run at 1MHz. Many Apple IIgs demos must run at 2.8MHz or they crash. Try -running ornery programs at 2.8MHz. 3200 pictures generally only display -correctly at 2.8MHz or sometimes 8.0MHz. - The middle mouse button or Shift-F6 causes KEGS to stop emulation, and enter the debugger. You can continue with "g" then return in the debug window. You can also disassemble memory, etc. The section "Debugging KEGS" above describes the debugger interface a little more. KEGS has no pop-up menus or other interactive interfaces (other than -the debug window). Input to the debug window is only acted upon when -the emulation is stopped by hitting a breakpoint or pressing the right-most -mouse button. +the debug window, and the occasional error dialogs on Mac OS X). Input to +the debug window is only acted upon when the emulation is stopped +(Shift-F6, middle mouse button, or hitting a breakpoint). Quitting KEGS: ------------- @@ -240,6 +260,86 @@ can select Quit from the menu. Or enter ctrl-c in the debugger window. Or press the middle-mouse button in the emulation window, and then type "q" return in the debug window. +Command/Option keys: +------------------- + +If you have a keyboard with the special Windows keys, you can +use them as the command/option keys. For those without those keys, +there are several alternatives. + +The following keys are Option (closed-apple) (not all keyboards have all +keys): F2, Meta_R, Alt_R, Cancel, Print_screen, Mode_switch, Option, +or the Windows key just to the right of the spacebar. The following keys are +Command (open-apple): F1, Meta_L, Alt_L, Menu, Scroll_lock, Command, +the Windows key left of the spacebar, and the Windows key on the far right +that looks like a pull-down menu. You can use F1 and F2 if you cannot make +anything else work (especially useful if your OS is intercepting some +Alt or Command key sequences). + +If you can't get any of these to work on your machine, let me know. +Note that X Windows often has other things mapped to Meta- and Alt- +key sequences, so they often don't get passed through to KEGS. So it's +best to use another key instead of Alt or Meta. + +The joystick/paddle buttons are just the Command and Option keys. + + +Reset: +----- + +The reset key is Pause/Break or F12. You must hit it with Ctrl to get it to +take effect (just like a real Apple IIgs). Ctrl-Command-Reset +forces a reboot. Ctrl-Command-Option-Reset enters selftests. +Selftests will pass if you force speed to 2.8MHz using the middle +button or F6 (and also set Enable Text Page 2 shadow = Disabled for ROM 01). +Watch out for ctrl-shift-Break--it will likely kill an X Windows session. +Also note that the Unix olvwm X window manager interprets ctrl-F12 and will +not pass it on to KEGS--you'll need to use Break for reset in that case. + +Full Screen mode (MAC OS X ONLY): +---------------- + +KEGS can run in full screen mode--which is especially useful when letting +small kids use KEGS (but it is not really a lock, so do not let a 2 year +old bang on the keyboard while running KEGS). + +Full Screen mode is toggled with F11 (or Ctrl-F11, since Expose on a Mac +is intercepting F11). If KEGS stops in the debugger for any reason, +full screen mode is toggled off automatically. + + +Joystick Emulation (Mouse, Keypad, or real native joystick): +------------------ + +The default joystick is the mouse position. Upper left is 0,0. Lower right +is 255,255. Press Shift-F9 to swap the X and Y axes. Press F9 to reverse +the sense of both paddles (so 0 becomes 255, etc). Swapping and +reversing are convenient with paddle-based games like "Little Brick Out" +so that the mouse will be moving like the paddle on the screen. "Little +Brick Out" is on the DOS 3.3 master disk. The joystick does not work +properly if the pointer is constrained in the window. + +You can also select from a "Keypad Joystick" or a real joystick from +the Configuration panel. Press return on the "Joystick Configuration" +entry, and then select between Mouse Joystick, Keypad Joystick, or one +of two native joysticks. The Keypad Joystick uses your keypad number +keys as a joystick, where keypad 7 means move to the upper left, and +keypad 3 means move to the lower right. Pressing multiple keys together +averages the results, allowing finer control than just 8 directions. +Also, joystick scaling is selectable here for games which require +a greater range of motion to work correctly, along with trim adjustment +which moves the centering point. Adjusting scaling usually means you +will need to adjust the trim as well. + +The left mouse button is the mouse button for KEGS. The right mouse +button (if you have it) or F6 toggles between four speed modes. Mode 0 +(the default) means run as fast as possible. Mode 1 means run at 1MHz. +Mode 2 means run at 2.8MHz. Mode 3 means run at 8.0MHz (about the speed +of a ZipGS accelerator). Most Apple //e (or earlier) games need to be +run at 1MHz. Many Apple IIgs demos must run at 2.8MHz or they will not +operate correctly. Try running ornery programs at 2.8MHz. 3200 pictures +generally only display correctly at 2.8MHz or sometimes 8.0MHz. + Debugging KEGS: -------------- @@ -272,6 +372,10 @@ type: e1/0010B +The format is "bank/address" then "B", where the B must be in caps and +the address must use lower-case hex. For Apple IIe programs, just use a +bank of 0. + To list all breakpoints, just type 'B' with no number in front of it. To delete a breakpoint, enter its address followed by 'D', so @@ -296,27 +400,17 @@ watchpoints). Frederic Devernay has written a nice help screen available in the debugger when you type "h". +Useful locations for setting breakpoints: +0/3f0B - Break handler +0/c000B - Keyboard latch, programs read keys from this address + + + KEGS command-line option summary: -------------------------------- --mem {mem_amt}: KEGS will use mem_amt as the amount of expansion RAM in - the IIgs. This memory is in addition to the 256KB on a ROM 01 - motherboard, or 1MB on a ROM 03. The memory is in bytes, - and it will be rounded down to the nearest 64KB. "-mem 0x800000" - will use 8MB of expansion RAM (the default). --badrd: Causes KEGS to halt on any access to invalid memory addresses. - Useful for debugging. By default, KEGS allows reads to invalid - memory since the Finder does some (especially when you open the - About window, and then close it). But KEGS warns you about these - accesses in the debug window. In general, these warnings - indicate buggy programs. If the warnings get severe, it's - a good sign you should quit KEGS and start over before the - emulated program crashes. -badrd would be the default for KEGS - if it wasn't for the Finder's About window's problem. --ignbadacc: Causes KEGS to allow reads & writes to invalid memory - addresses without printing any warnings. Useful for running - extremely buggy programs so you don't have to see all the warning - messages scroll by. +There are others, but the Configuration panel provides a better way to +set them so they are no longer listed here. -skip: KEGS will "skip" that many screen redraws between refreshes. -skip 0 will do 60 frames per second, -skip 1 will do 30 fps, -skip 5 will do 10 fps. @@ -340,7 +434,6 @@ X-Windows/Linux options -24: KEGS will only look for a 24-bit X-Window display. -display {machine:0.0}: Same as setting the environment variable DISPLAY. Sends X display to {machine:0.0}. --joystick: Will use /dev/js0 as the joystick. -noshm: KEGS will not try to used shared memory for the X graphics display. This will make KEGS much slower on graphics-intensive tasks, by as much as a factor of 10! By default, -noshm causes an @@ -348,40 +441,9 @@ X-Windows/Linux options default by specifying a -skip explicitly. -Command/Option keys: -------------------- -If you have a workstation keyboard with the new Windows keys, you can -use them as the command/option keys. This is what I use. Since many people -don't have the PC keyboard, there are several alternatives. - -The following keys are Option (closed-apple) (not all keyboards have all -keys): F2, Meta_R, Alt_R, Cancel, Print_screen, Mode_switch, Option, -or the Windows key just to the right of the spacebar. The following keys are -Command (open-apple): F1, Meta_L, Alt_L, Menu, Scroll_lock, Command, -the Windows key left of the spacebar, and the Windows key on the far right -that looks like a pull-down menu. You can use F1 and F2 if you cannot make -anything else work. - -If you can't get any of these to work on your machine, let me know. -Note that X Windows often has other things mapped to Meta- and Alt- -key sequences, so they often don't get passed through to KEGS. So it's -best to use another key instead of Alt or Meta. - -The joystick/paddle buttons are just the Command and Option keys. - -Reset: ------ - -The reset key is Pause/Break or F12. You must hit it with Ctrl to get it to -take effect (just like a real Apple IIgs). Ctrl-Command-Reset -forces a reboot. Ctrl-Command-Option-Reset enters selftests. -Selftests will pass if you force speed to 2.8MHz using the middle -button. Watch out for ctrl-shift-Break--it will likely kill your -X Windows session. - -Control Panel: -------------- +Apple IIgs Control Panel: +------------------------ You can get to the Apple IIgs control panel (unless some application has locked it out) using Ctrl-Command-ESC. @@ -453,18 +515,12 @@ to $E0. Details on config.kegs and disk images -------------------------------------- -The file "config.kegs" describes the images KEGS will use. The sample -file has all the lines commented out with '#' to show sample uses. -Remember, KEGS will boot s7d1 (unless you've changed that using the -Apple IIgs control panel), so you must put an image in that slot. +The file "config.kegs" describes the images KEGS will use. Although you +can edit the file manually, in general you can use the Configuration Panel +to make all the changes you need. This information is for reference. -Changing disks in slot 7 does not work, but you can move around -disks in slots 5 and 6. This allows you to "eject" disks and change them. -This is especially useful for multi-disk 5.25" programs. - -KEGS uses the Unix permissions on raw disk images to decide how to load -it into the emulator. If the file is unreadable, it cannot load the -image (duh). +KEGS by default will boot s7d1 (unless you've changed that using the +Apple IIgs control panel), so you should put an image in that slot. KEGS, by default, runs the IWM (3.5" and 5.25" disks) emulation in an "approximate" mode, called "fast_disk_emul". In this mode, KEGS @@ -544,14 +600,14 @@ equivalent speed. Many games will be unplayable at the unlimited setting. Setting the IIgs control panel speed to "slow" will slow down to 1MHz. -Sound output has an interesting relationship to KEGS timing. KEGS must +Sound output has an important relationship to KEGS timing. KEGS must play one second of sound per second of emulated time. Normally, this works out exactly right. But as noted above, if KEGS can't maintain the needed speed, it extends the emulated second. If it extends the second to 1.4 real seconds, that means KEGS only produces 1.0 second of sound data every 1.4 seconds--the sound breaks up! -In all cases, 1MHz to KEGS is 1.024MHz. And 2.8MHz to KEGS is 2.52MHz +In all cases, 1MHz to KEGS is 1.024MHz. And 2.8MHz to KEGS is 2.56MHz (trying to approximate the slowdown causes by memory refresh on a real Apple IIgs). It's just easier to say 1MHz and 2.8MHz. @@ -673,7 +729,9 @@ useful for some games. KEGS: What works: ----------------- -Basically, just about every Apple II program works. +Basically, just about every Apple II program works. See the file +README.a2.compatibility for directions on how to make certain games/programs +work. KEGS is EXTREMELY compatible. But, I haven't tested everything. Let me know if you find a program which is not working correctly. @@ -696,9 +754,6 @@ the above lets it work fine. This seems to be a bug in the demo. KEGS bugs: --------- -KEGS's serial port emulation is very limited now, and only for -adventurous souls. - On a ROM03, KEGS makes a patch to the ROM image (inside emulation, not to the Unix file) to fix a bug in the ROM code. Both ROM01 and ROM03 are patched to enable use of more than 8MB of memory. I then patch the ROM @@ -726,39 +781,70 @@ in the debug window. However, when sound restarts, it sometimes If your display is not using shared memory, audio defaults to off unless you override it with "-audio 1". -SCC emulation: -------------- +SCC (Serial Port) emulation: +--------------------------- KEGS emulates the two serial ports on a IIgs as being two Unix sockets. Port 1 (printer port) is at socket address 6501, and port 2 (modem) is at socket address 6502. -In KEGS, from APPLESOFT, if you PR#1, all output will then be sent to -socket port 6501. You can see it by connecting to the port using -any method you like, but a simple, easy way is to use telnet. In -another Unix window, do: "telnet localhost 6501" and then you -will see all the output going to the "printer". +By default, slot 1 is emulated using a simple receive socket, and slot 2 +emulates a Virtual Modem. + +A Virtual Modem means KEGS acts as if a modem is on the serial port +allowing Apple II communcation programs to fully work, but connected to +internet-enabled sockets. KEGS emulates a "Hayes- Compatible" modem, +meaning it accepts "AT" commands. You can use KEGS to connect to free +telnet-BBSs, or run a BBS program on KEGS and become a telnet BBS yourself. + +The two main AT commands are: ATDT for dialing out, and ATA for receiving +calls. To dial out, enter "ATDThostname", or for example, +"ATDTboycot.no-ip.com" (which is down at the moment, unfortunately). +You can also enter an IP address, like "ATDT127.0.0.1". On a Mac, to +create a telnet server to allow telnet connections (do not use over the +internet, but on a private network behind a firewall, this should be +fine), in a Terminal window type: "sudo /usr/libexec/telnetd -debug". +You must then enable telnet on port 23 through your Mac OS X Firewall in +the System Preferences->Sharing->Firewall page (just add port 23 as +open--you'll need to use the "New..." button and then select Other for +Port Name, and enter Port Number as 23). Then from KEGS in a +communications program, do "ATDT127.0.0.1", and then log-in to your Mac. + +KEGS also accepts incoming "calls". Start KEGS, and initialize the +Virtual Modem with some AT command (ATZ resets all state, and is a useful +start). KEGS now has a socket port open, 6502 for slot 2, which you +can connect to using any telnet program. In a Terminal window, then +type "telnet 127.0.0.1 6502" and you will connect to KEGS. The Virtual +Modem then starts printing "RING" every 2 seconds until you answer with +"ATA". You are now connected. I have not tried BBS programs, but have +made connections with ProTERM. + +On Windows XP SP2, when KEGS tries to open this incoming socket, you'll +need to enable it and click Unblock to the dialog that Windows pops up. +If you do not want incoming connections, you can block it instead. + +Once connected, you can go back to talking to the Virtual Modem by +pressing + three times quickly (+++), and then not type anything for a second. +This goes back to the AT-command mode. You can now "ATH" to hang up, or +"ATO" to go back online. + +On Windows, the socket code is very preliminary and there are problems +receiving connections. + +KEGS also supports an older, simpler socket interface, which it defaults +to using on slot 1. In KEGS, from APPLESOFT, if you PR#1, all output will +then be sent to socket port 6501. You can see it by connecting to the +port using telnet. In another terminal window, do: "telnet localhost 6501" +and then you will see all the output going to the "printer". Under APPLESOFT, you can PR#1 and IN#1. This gets input from the socket also. You can type in the telnet window, it will be sent on -to the emulated IIgs. Telnet on Unix defaults to "line mode" which -buffers keys you type until you hit return. This can be a bit distracting, -and can be disabled by hitting Ctrl-] and then "mode char". This -causes a few {{ chars to show up in KEGS--just ignore this for now. -You may want to go to the F4 Config Panel and set "mask off high bit" -for serial port accesses to make PR#2 work a little nicer. +to the emulated IIgs. You may want to go to the F4 Config Panel and set +"mask off high bit" for serial port accesses to make PR#1 work a little nicer. -That's about it. Proterm and Appleworks GS can talk to the modem port -fine, but it's limited in its usefulness. I have printed from -Printshop, but it's a bit pointless since it's sending out Imagewriter -printer codes which doesn't look like anything. You can "print" from -BASIC by using something like PR#1 in KEGS and +You can "print" from BASIC by using something like PR#1 in KEGS and "telnet localhost 6501 | tee file.out" in another window. -Feel free to let me know what doesn't work, but a lot is known not -to work. GNO's tty interface may work, but I'm having problems -testing it. - KEGS status area: ---------------- @@ -875,7 +961,7 @@ Fix the Ensoniq bugs to make sound more accurate. If you have any problems/questions/etc., just let me know. Special thanks to Jeff Smoot of climbingwashington.com for letting me use -the picture of a keg in the Mac icon. +the picture of a keg for the Mac icon. Kent Dickey kadickey@alumni.princeton.edu @@ -956,21 +1042,9 @@ KEGS boots s7d1 by default. You can change this using the emulated IIgs control panel, just like a real Apple IIgs. KEGS emulates a IIgs with two 5.25" drives in slot 6, two 3.5" drives in slot 5, and up to 32 "hard drives" in slot 7. However, the current Configuration Panel only -lets you set through s7d11. - -Config.kegs file ----------------- - -KEGS saves your preferences and disk image names in the file config.kegs. -KEGS searches for this file in the directory KEGS was started in, in -your home directory, or in the Resources directory (on a Mac) of the app. -It needs to find one someplace, so putting it in your home directory is -usually the easiest. - -The config.kegs file is a simple text file. You need to quit KEGS before -editing the file. The BRAM data is also kept in this file, with separate -BRAM contents for ROM 01 and ROM 03 (so if you switch ROM versions, you -don't lose all your BRAM preferences). +lets you set through s7d11. ProDOS 8 can access disks up to s7d8, but GSOS +has no limit, so it's best to put HFS images past s7d8 in order to leave +more slots for ProDOS images. If you're trying to use a real host device (CD-ROM, or hard drive, or floppy), you should make the permissions on the /dev/disk* files something @@ -982,8 +1056,6 @@ You can do this on a Mac with: sudo chmod 644 /dev/disk2 -Running KEGS as root is NOT recommended. - -The s6d* and s5d* drives support disk swapping and disk ejecting, but -the s7d* drives do not. +DO NOT RUN KEGS AS ROOT. It is not designed for this and it's almost certain +problems will ensue. diff --git a/README.linux.partitions b/README.linux.partitions.txt similarity index 100% rename from README.linux.partitions rename to README.linux.partitions.txt diff --git a/README.mac b/README.mac.txt similarity index 100% rename from README.mac rename to README.mac.txt diff --git a/README.md b/README.md new file mode 100644 index 0000000..c9317db --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +KEGS - Kent's Emulated GS +========================= + +Kegs is an Apple //gs emulator for Mac OS X, Win32, Linux and Unix/X11 + +The latest version on the main KEGS home page is v0.91 which doesn't work on Intel Macs. In fact, only +small build changes are required, so I have forked the code to Github with my changes. + +Original homepage with useful info on how to get it running is here: (http://kegs.sourceforge.net/)[http://kegs.sourceforge.net/] diff --git a/README.win32 b/README.win32.txt similarity index 83% rename from README.win32 rename to README.win32.txt index 182958a..d3d0617 100644 --- a/README.win32 +++ b/README.win32.txt @@ -2,13 +2,13 @@ WIN32 port of KEGS (KEGSWIN) ---------------------------- -There is a different port of KEGS by akilgard called KEGS32. -You can get it from http://www.geocities.com/akilgard/kegs32. -This port is leveraged from KEGS32, but mostly a rewrite (perhaps -for the worse). The joystick code was taken without too many -modifications. +There is a different port of KEGS by Chea Chee Keong (akilgard) called +KEGS32. You can get it from http://www.geocities.com/akilgard/kegs32. +This port is leveraged from KEGS32, but mostly a rewrite (perhaps for +the worse). I am grateful for Chea for doing the windows port since I +did not know any Windows programming. -This port is alpha quality. Seriously. Don't expect much. +This port is alpha quality. Don't expect much. This is a bare-bones Win32 port. It was compiled with Mingw2.0, which you can download at: http://www.mingw.org/. I also had @@ -49,3 +49,4 @@ In order to compile, You can contact me at kadickey@alumni.princeton.edu + diff --git a/kegswin.exe b/kegswin.exe index b6c6563..5d2277e 100755 Binary files a/kegswin.exe and b/kegswin.exe differ diff --git a/src/2mg.icns b/src/2mg.icns new file mode 100644 index 0000000..1e612e0 Binary files /dev/null and b/src/2mg.icns differ diff --git a/src/525.icns b/src/525.icns new file mode 100644 index 0000000..94e5a90 Binary files /dev/null and b/src/525.icns differ diff --git a/src/Info.plist b/src/Info.plist index 15a616a..d810c7d 100644 --- a/src/Info.plist +++ b/src/Info.plist @@ -4,8 +4,46 @@ CFBundleDevelopmentRegion English + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + 2mg + 2MG + + CFBundleTypeIconFile + 2mg.icns + CFBundleTypeName + Apple II 2MG Disk Image + CFBundleTypeOSTypes + + a2mg + + CFBundleTypeRole + None + + + CFBundleTypeExtensions + + kegs + + CFBundleTypeIconFile + 525.icns + CFBundleTypeName + KEGS Configuration File + CFBundleTypeOSTypes + + kegs + + CFBundleTypeRole + None + + CFBundleExecutable KEGSMAC + CFBundleName + KEGSMAC CFBundleIconFile kegsicon.icns CFBundleInfoDictionaryVersion @@ -13,10 +51,14 @@ CFBundlePackageType APPL CFBundleSignature - ???? + KEGS CFBundleVersion - 0.1 - CSResourcesFileMapped - + 0.91 + CFBundleShortVersionString + KEGSMAC version 0.91 + CFBundleGetInfoString + KEGSMAC v0.91, Copyright 2004 Kent Dickey, http://kegs.sourceforge.net + NSHumanReadableCopyright + Copyright 2004 Kent Dickey diff --git a/src/InfoPlist.strings b/src/InfoPlist.strings deleted file mode 100644 index 036ca1e..0000000 Binary files a/src/InfoPlist.strings and /dev/null differ diff --git a/src/Makefile b/src/Makefile index 158f58b..8af41f0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,4 +1,4 @@ -# $Id: release_makefile_base,v 1.15 2003/11/21 20:00:42 kentd Exp $ +# $Id: release_makefile_base,v 1.15 2003/11/21 20:00:42 kentd Exp kentd $ OBJECTS1 = adb.o clock.o config.o dis.o engine_c.o scc.o iwm.o \ joystick_driver.o moremem.o paddles.o sim65816.o smartport.o \ @@ -24,17 +24,18 @@ specials_clean: # Mac builds: kegsmac: $(OBJECTS) compile_time.o - $(CC) $(CCOPTS) $(LDOPTS) -arch ppc $(OBJECTS) compile_time.o $(LDFLAGS) -o kegsmac $(EXTRA_LIBS) -prebind -framework Carbon + $(CC) $(CCOPTS) $(LDOPTS) -arch ppc $(OBJECTS) compile_time.o $(LDFLAGS) -o kegsmac $(EXTRA_LIBS) -prebind -framework Carbon -framework Quicktime mkdir -p ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib mkdir -p ../KEGSMAC.app/Contents/MacOS mv kegsmac ../KEGSMAC.app/Contents/MacOS/KEGSMAC echo "APPL????" > ../KEGSMAC.app/Contents/PkgInfo cp -f Info.plist ../KEGSMAC.app/Contents/ - cp -f InfoPlist.strings ../KEGSMAC.app/Contents/Resources/English.lproj/ cp -f info.nib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib cp -f classes.nib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib cp -f objects.xib ../KEGSMAC.app/Contents/Resources/English.lproj/main.nib cp -f kegsicon.icns ../KEGSMAC.app/Contents/Resources/ + cp -f 525.icns ../KEGSMAC.app/Contents/Resources/ + cp -f 2mg.icns ../KEGSMAC.app/Contents/Resources/ touch '../KEGSMAC.app/Icon?' # Linux for X builds: @@ -49,7 +50,7 @@ kegs.exe: $(OBJECTS) compile_time.o # Mingw32 (native windows) builds: kegswin.exe: $(OBJECTS) compile_time.o - $(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 + $(CC) $(CCOPTS) $(LDOPTS) $(OBJECTS) compile_time.o $(LDFLAGS) -o $(NAME)$(SUFFIX) $(EXTRA_LIBS) -lwinmm -lgdi32 -ldsound -lcomctl32 -lws2_32 mv $(NAME)$(SUFFIX) .. diff --git a/src/adb.c b/src/adb.c index 0ebb103..86c2d13 100644 --- a/src/adb.c +++ b/src/adb.c @@ -8,12 +8,14 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_adb_c[] = "@(#)$KmKId: adb.c,v 1.63 2004-03-23 18:46:25-05 kentd Exp $"; +const char rcsid_adb_c[] = "@(#)$KmKId: adb.c,v 1.73 2004-11-14 14:05:33-05 kentd Exp $"; /* adb_mode bit 3 and bit 2 (faster repeats for arrows and space/del) not done*/ #include "adb.h" +int g_fullscreen = 0; + extern int Verbose; extern word32 g_vbl_count; extern int g_num_lines_prev_superhires640; @@ -21,11 +23,14 @@ extern int g_num_lines_prev_superhires; extern int g_rom_version; extern int g_fast_disk_emul; extern int g_limit_speed; +extern int g_irq_pending; extern int g_swap_paddles; extern int g_invert_paddles; +extern int g_joystick_type; extern int g_a2vid_palette; extern int g_config_control_panel; extern word32 g_cfg_vbl_count; +extern double g_cur_dcycs; extern byte *g_slow_memory_ptr; extern byte *g_memory_ptr; @@ -84,17 +89,23 @@ int g_warp_pointer = 0; int g_hide_pointer = 0; int g_unhide_pointer = 0; - int g_mouse_a2_x = 0; int g_mouse_a2_y = 0; int g_mouse_a2_button = 0; int g_mouse_fifo_pos = 0; +int g_mouse_raw_x = 0; +int g_mouse_raw_y = 0; #define ADB_MOUSE_FIFO 8 -int g_mouse_fifo_x[ADB_MOUSE_FIFO] = { 0 }; -int g_mouse_fifo_y[ADB_MOUSE_FIFO] = { 0 }; -int g_mouse_fifo_buttons[ADB_MOUSE_FIFO] = { 0 }; +STRUCT(Mouse_fifo) { + double dcycs; + int x; + int y; + int buttons; +}; + +Mouse_fifo g_mouse_fifo[ADB_MOUSE_FIFO] = { { 0, 0, 0, 0 } }; int g_mouse_warp_x = 0; int g_mouse_warp_y = 0; @@ -102,11 +113,6 @@ int g_mouse_warp_y = 0; int g_adb_mouse_valid_data = 0; int g_adb_mouse_coord = 0; -int g_adb_data_int_sent = 0; -int g_adb_mouse_int_sent = 0; -int g_adb_kbd_srq_sent = 0; - - #define MAX_KBD_BUF 8 int g_key_down = 0; @@ -129,6 +135,10 @@ int g_mouse_ctl_addr = 3; /* ADB ucontroller's mouse addr*/ word32 g_virtual_key_up[4]; /* bitmask of all possible 128 a2codes */ /* indicates which keys are up=1 by bit */ +int g_keypad_key_is_down[10] = { 0 };/* List from 0-9 of which keypad */ + /* keys are currently pressed */ + + #define SHIFT_DOWN ( (g_c025_val & 0x01) ) #define CTRL_DOWN ( (g_c025_val & 0x02) ) #define CAPS_LOCK_DOWN ( (g_c025_val & 0x04) ) @@ -171,6 +181,10 @@ adb_init() g_virtual_key_up[i] = -1; } + for(i = 0; i < 10; i++) { + g_keypad_key_is_down[i] = 0; + } + adb_reset(); } @@ -189,9 +203,9 @@ adb_reset() g_kbd_ctl_addr = 2; g_mouse_ctl_addr = 3; - g_adb_data_int_sent = 0; - g_adb_mouse_int_sent = 0; - g_adb_kbd_srq_sent = 0; + adb_clear_data_int(); + adb_clear_mouse_int(); + adb_clear_kbd_srq(); g_adb_data_pending = 0; g_adb_interrupt_byte = 0; @@ -201,6 +215,7 @@ adb_reset() g_kbd_reg0_pos = 0; g_kbd_reg3_16bit = 0x602; + } @@ -250,8 +265,6 @@ show_adb_log(void) printf("kbd: dev: %x, ctl: %x; mouse: dev: %x, ctl: %x\n", g_kbd_dev_addr, g_kbd_ctl_addr, g_mouse_dev_addr, g_mouse_ctl_addr); - printf("adb_data_int_sent: %d, adb_kbd_srq_sent: %d, mouse_int: %d\n", - g_adb_data_int_sent, g_adb_kbd_srq_sent, g_adb_mouse_int_sent); printf("g_adb_state: %d, g_adb_interrupt_byte: %02x\n", g_adb_state, g_adb_interrupt_byte); } @@ -271,11 +284,8 @@ adb_add_kbd_srq() { if(g_kbd_reg3_16bit & 0x200) { /* generate SRQ */ - g_adb_interrupt_byte |= 0x08;; - if(!g_adb_kbd_srq_sent) { - g_adb_kbd_srq_sent = 1; - add_irq(); - } + g_adb_interrupt_byte |= 0x08; + add_irq(IRQ_PENDING_ADB_KBD_SRQ); } else { printf("Got keycode but no kbd SRQ!\n"); } @@ -284,10 +294,7 @@ adb_add_kbd_srq() void adb_clear_kbd_srq() { - if(g_adb_kbd_srq_sent) { - remove_irq(); - g_adb_kbd_srq_sent = 0; - } + remove_irq(IRQ_PENDING_ADB_KBD_SRQ); /* kbd SRQ's are the only ones to handle now, so just clean it out */ g_adb_interrupt_byte &= (~(0x08)); @@ -297,10 +304,7 @@ void adb_add_data_int() { if(g_c027_val & ADB_C027_DATA_INT) { - if(!g_adb_data_int_sent) { - g_adb_data_int_sent = 1; - add_irq(); - } + add_irq(IRQ_PENDING_ADB_DATA); } } @@ -308,31 +312,20 @@ void adb_add_mouse_int() { if(g_c027_val & ADB_C027_MOUSE_INT) { - if(!g_adb_mouse_int_sent) { - /* printf("Mouse int sent\n"); */ - g_adb_mouse_int_sent = 1; - add_irq(); - } + add_irq(IRQ_PENDING_ADB_MOUSE); } } void adb_clear_data_int() { - if(g_adb_data_int_sent) { - remove_irq(); - g_adb_data_int_sent = 0; - } + remove_irq(IRQ_PENDING_ADB_DATA); } void adb_clear_mouse_int() { - if(g_adb_mouse_int_sent) { - remove_irq(); - g_adb_mouse_int_sent = 0; - /* printf("Mouse int clear, button: %d\n", g_mouse_a2_button);*/ - } + remove_irq(IRQ_PENDING_ADB_MOUSE); } @@ -580,7 +573,7 @@ adb_read_c026() case ADB_IDLE: ret = g_adb_interrupt_byte; g_adb_interrupt_byte = 0; - if(g_adb_kbd_srq_sent) { + if(g_irq_pending & IRQ_PENDING_ADB_KBD_SRQ) { g_adb_interrupt_byte |= 0x08; } if(g_adb_data_pending == 0) { @@ -1087,15 +1080,57 @@ write_adb_ram(word32 addr, int val) } } +int +adb_get_keypad_xy(int get_y) +{ + int x, y; + int key; + int num_keys; + int i, j; + + key = 1; + num_keys = 0; + x = 0; + y = 0; + for(i = 0; i < 3; i++) { + for(j = 0; j < 3; j++) { + if(g_keypad_key_is_down[key]) { + num_keys++; + x = x + (j - 1)*32768; + y = y + (1 - i)*32768; + } + key++; + } + } + if(num_keys == 0) { + num_keys = 1; + } + + adb_printf("get_xy=%d, num_keys: %d, x:%d, y:%d\n", get_y, + num_keys, x, y); + + if(get_y) { + return y / num_keys; + } else { + return x / num_keys; + } +} + int update_mouse(int x, int y, int button_states, int buttons_valid) { + double dcycs; int button1_changed; int mouse_moved; int unhide; int pos; int i; + dcycs = g_cur_dcycs; + + g_mouse_raw_x = x; + g_mouse_raw_y = y; + unhide = 0; if(x < 0) { x = 0; @@ -1132,47 +1167,50 @@ update_mouse(int x, int y, int button_states, int buttons_valid) y = y >> 1; } + mouse_compress_fifo(dcycs); + #if 0 printf("Update Mouse called with buttons:%d x,y:%d,%d, fifo:%d,%d, " " a2: %d,%d\n", buttons_valid, x, y, - g_mouse_fifo_x[0], g_mouse_fifo_y[0], + g_mouse_fifo[0].x, g_mouse_fifo[0].y, g_mouse_a2_x, g_mouse_a2_y); #endif if((buttons_valid < 0) && g_warp_pointer) { /* Warping the pointer causes it to jump here...this is not */ /* real motion, just update info and get out */ - g_mouse_a2_x += (x - g_mouse_fifo_x[0]); - g_mouse_a2_y += (y - g_mouse_fifo_y[0]); - g_mouse_fifo_x[0] = x; - g_mouse_fifo_y[0] = y; + g_mouse_a2_x += (x - g_mouse_fifo[0].x); + g_mouse_a2_y += (y - g_mouse_fifo[0].y); + g_mouse_fifo[0].x = x; + g_mouse_fifo[0].y = y; return 0; } #if 0 printf("...real move, warp: %d, %d, new x: %d, %d, a2:%d,%d\n", - g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo_x[0], - g_mouse_fifo_y[0], g_mouse_a2_x, g_mouse_a2_y); + g_mouse_warp_x, g_mouse_warp_y, g_mouse_fifo[0].x, + g_mouse_fifo[0].y, g_mouse_a2_x, g_mouse_a2_y); #endif - mouse_moved = (g_mouse_fifo_x[0] != x) || (g_mouse_fifo_y[0] != y); + mouse_moved = (g_mouse_fifo[0].x != x) || (g_mouse_fifo[0].y != y); g_mouse_a2_x += g_mouse_warp_x; g_mouse_a2_y += g_mouse_warp_y; - g_mouse_fifo_x[0] = x; - g_mouse_fifo_y[0] = y; + g_mouse_fifo[0].x = x; + g_mouse_fifo[0].y = y; + g_mouse_fifo[0].dcycs = dcycs; g_mouse_warp_x = 0; g_mouse_warp_y = 0; button1_changed = (buttons_valid & 1) && - ((button_states & 1) != (g_mouse_fifo_buttons[0] & 1)); + ((button_states & 1) != (g_mouse_fifo[0].buttons & 1)); - if((button_states & 4) && !(g_mouse_fifo_buttons[0] & 4) && + if((button_states & 4) && !(g_mouse_fifo[0].buttons & 4) && (buttons_valid & 4)) { /* right button pressed */ adb_increment_speed(); } - if((button_states & 2) && !(g_mouse_fifo_buttons[0] & 2) && + if((button_states & 2) && !(g_mouse_fifo[0].buttons & 2) && (buttons_valid & 2)) { /* middle button pressed */ halt2_printf("Middle button pressed\n"); @@ -1185,15 +1223,13 @@ update_mouse(int x, int y, int button_states, int buttons_valid) /* button up/down times. Using a mouse event list where */ /* deltas accumulate until a button change would work, too */ for(i = pos; i >= 0; i--) { - g_mouse_fifo_x[i + 1] = g_mouse_fifo_x[i]; - g_mouse_fifo_y[i + 1] = g_mouse_fifo_y[i]; - g_mouse_fifo_buttons[i + 1] = g_mouse_fifo_buttons[i]&1; + g_mouse_fifo[i + 1] = g_mouse_fifo[i]; /* copy struct*/ } g_mouse_fifo_pos = pos + 1; } - g_mouse_fifo_buttons[0] = (button_states & buttons_valid) | - (g_mouse_fifo_buttons[0] & ~buttons_valid); + g_mouse_fifo[0].buttons = (button_states & buttons_valid) | + (g_mouse_fifo[0].buttons & ~buttons_valid); if(mouse_moved || button1_changed) { if( (g_mouse_ctl_addr == g_mouse_dev_addr) && @@ -1226,10 +1262,12 @@ mouse_read_c024(double dcycs) return 0; } + mouse_compress_fifo(dcycs); + pos = g_mouse_fifo_pos; - target_x = g_mouse_fifo_x[pos]; - target_y = g_mouse_fifo_y[pos]; - mouse_button = (g_mouse_fifo_buttons[pos] & 1); + target_x = g_mouse_fifo[pos].x; + target_y = g_mouse_fifo[pos].y; + mouse_button = (g_mouse_fifo[pos].buttons & 1); delta_x = target_x - g_mouse_a2_x; delta_y = target_y - g_mouse_a2_y; @@ -1253,7 +1291,7 @@ mouse_read_c024(double dcycs) /* peek into next entry's button info if we are not clamped */ /* and we're returning the y-coord */ if(!clamped && g_adb_mouse_coord) { - mouse_button = g_mouse_fifo_buttons[pos - 1] & 1; + mouse_button = g_mouse_fifo[pos - 1].buttons & 1; } } @@ -1351,9 +1389,9 @@ mouse_read_c024(double dcycs) g_slow_memory_ptr[0x10190], g_slow_memory_ptr[0x10192], g_slow_memory_ptr[0x10191], g_slow_memory_ptr[0x10193]); - if((g_mouse_fifo_pos == 0) && (g_mouse_fifo_x[0] == a2_x) && - (g_mouse_fifo_y[0] == a2_y) && - ((g_mouse_fifo_buttons[0] & 1) == g_mouse_a2_button)) { + if((g_mouse_fifo_pos == 0) && (g_mouse_fifo[0].x == a2_x) && + (g_mouse_fifo[0].y == a2_y) && + ((g_mouse_fifo[0].buttons & 1) == g_mouse_a2_button)) { g_adb_mouse_valid_data = 0; adb_clear_mouse_int(); } @@ -1362,6 +1400,29 @@ mouse_read_c024(double dcycs) return ret; } +void +mouse_compress_fifo(double dcycs) +{ + int pos; + + /* The mouse fifo exists so that fast button changes don't get lost */ + /* if the emulator lags behind the mouse events */ + /* But the FIFO means really old mouse events are saved if */ + /* the emulated code isn't looking at the mouse registers */ + /* This routine compresses all mouse events > 0.5 seconds old */ + + for(pos = g_mouse_fifo_pos; pos >= 1; pos--) { + if(g_mouse_fifo[pos].dcycs < (dcycs - 500*1000.0)) { + /* Remove this entry */ + adb_printf("Old mouse FIFO pos %d removed\n", pos); + g_mouse_fifo_pos = pos - 1; + continue; + } + /* Else, stop searching the FIFO */ + break; + } +} + void adb_key_event(int a2code, int is_up) { @@ -1489,7 +1550,8 @@ adb_read_c000() /* got one */ if((g_kbd_read_no_update++ > 5) && (g_kbd_chars_buffered > 1)) { /* read 5 times, keys pending, let's move it along */ - printf("Read %02x 3 times, tossing\n", g_kbd_buf[0]); + printf("Read %02x %d times, tossing\n", g_kbd_buf[0], + g_kbd_read_no_update); adb_access_c010(); } } else { @@ -1583,7 +1645,8 @@ adb_physical_key_update(int a2code, int is_up) { int autopoll; int special; - int tmp; + int ascii_and_type; + int ascii; /* this routine called by xdriver to pass raw codes--handle */ /* ucontroller and ADB bus protocol issues here */ @@ -1599,17 +1662,17 @@ adb_physical_key_update(int a2code, int is_up) return; } - /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards */ + /* Remap 0x7b-0x7e to 0x3b-0x3e (arrow keys on new mac keyboards) */ if(a2code >= 0x7b && a2code <= 0x7e) { a2code = a2code - 0x40; } /* Now check for special keys (function keys, etc) */ - tmp = a2_key_to_ascii[a2code][1]; + ascii_and_type = a2_key_to_ascii[a2code][1]; special = 0; - if((tmp & 0xf000) == 0x8000) { + if((ascii_and_type & 0xf000) == 0x8000) { /* special function key */ - special = tmp & 0xff; + special = ascii_and_type & 0xff; switch(special) { case 0x01: /* F1 - remap to cmd */ a2code = 0x37; @@ -1643,7 +1706,7 @@ adb_physical_key_update(int a2code, int is_up) if(special && !is_up) { switch(special) { case 0x04: /* F4 - Emulator config panel */ - g_config_control_panel = !g_config_control_panel; + cfg_toggle_config_panel(); break; case 0x06: /* F6 - emulator speed */ if(SHIFT_DOWN) { @@ -1679,13 +1742,38 @@ adb_physical_key_update(int a2code, int is_up) change_a2vid_palette((g_a2vid_palette + 1) & 0xf); break; case 0x0b: /* F11 - full screen */ - /* g_fullscreen = !g_fullscreen; */ - /* x_full_screen(g_full_screen); */ + g_fullscreen = !g_fullscreen; + x_full_screen(g_fullscreen); break; } return; } + /* Handle Keypad Joystick here partly...if keypad key pressed */ + /* while in Keypad Joystick mode, do not pass it on as a key press */ + if((ascii_and_type & 0xff00) == 0x1000) { + /* Keep track of keypad number keys being up or down even */ + /* if joystick mode isn't keypad. This avoid funny cases */ + /* if joystick mode is changed while a key is pressed */ + ascii = ascii_and_type & 0xff; + if(ascii > 0x30 && ascii <= 0x39) { + g_keypad_key_is_down[ascii - 0x30] = !is_up; + } + if(g_joystick_type == 0) { + /* If Joystick type is keypad, then do not let these */ + /* keypress pass on further, except for cmd/opt */ + if(ascii == 0x30) { + /* remap '0' to cmd */ + a2code = 0x37; + } else if(ascii == 0x2e || ascii == 0x2c) { + /* remap '.' and ',' to option */ + a2code = 0x3a; + } else { + /* Just ignore it in this mode */ + return; + } + } + } autopoll = 1; if(g_adb_mode & 1) { @@ -1753,6 +1841,23 @@ adb_virtual_key_update(int a2code, int is_up) } } +void +adb_all_keys_up() +{ + word32 mask; + int i, j; + + for(i = 0; i < 4; i++) { + for(j = 0; j < 32; j++) { + mask = 1 << j; + if((g_virtual_key_up[i] & mask) == 0) { + /* create key-up event */ + adb_physical_key_update(i*32 + j, 1); + } + } + } +} + void adb_kbd_repeat_off() { diff --git a/src/adb.h b/src/adb.h index 857aa33..7f4b4e8 100644 --- a/src/adb.h +++ b/src/adb.h @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_adb_h[] = "@(#)$KmKId: adb.h,v 1.9 2002-11-19 03:10:38-05 kadickey Exp $"; +const char rcsid_adb_h[] = "@(#)$KmKId: adb.h,v 1.11 2004-10-13 23:30:33-04 kentd Exp $"; #include "defc.h" @@ -87,7 +87,7 @@ const int a2_key_to_ascii[][4] = { { 0x3f, -1, -1, -1 }, { 0x40, -1, -1, -1 }, - { 0x41, 0x102e, 0x102e, -1 }, /* keypad . */ + { 0x41, 0x102e, 0x102c, -1 }, /* keypad . */ { 0x42, -1, -1, -1 }, { 0x43, 0x102a, 0x102a, -1 }, /* keypad * */ { 0x44, -1, -1, -1 }, @@ -115,7 +115,7 @@ const int a2_key_to_ascii[][4] = { { 0x58, 0x1036, 0x1036, -1 }, /* keypad 6 */ { 0x59, 0x1037, 0x1037, -1 }, /* keypad 7 */ - { 0x5a, -1, -1, -1 }, + { 0x5a, 'a', 'A', 0x01 }, /* probably not necessary */ { 0x5b, 0x1038, 0x1038, -1 }, /* keypad 8 */ { 0x5c, 0x1039, 0x1039, -1 }, /* keypad 9 */ { 0x5d, -1, -1, -1 }, @@ -137,7 +137,7 @@ const int a2_key_to_ascii[][4] = { { 0x6b, 0x800e, 0x106b, -1 }, /* F14 */ { 0x6c, -1, -1, -1 }, { 0x6d, 0x800a, 0x106d, -1 }, /* F10 */ - { 0x6e, -1, -1, -1 }, + { 0x6e, 0x4000, 0x4000, -1 }, /* windows key alias to option */ { 0x6f, 0x800c, 0x106f, -1 }, /* F12 */ { 0x70, -1, -1, -1 }, diff --git a/src/clock.c b/src/clock.c index 442ed70..27c1f49 100644 --- a/src/clock.c +++ b/src/clock.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_clock_c[] = "@(#)$KmKId: clock.c,v 1.29 2003-10-17 15:07:35-04 kentd Exp $"; +const char rcsid_clock_c[] = "@(#)$KmKId: clock.c,v 1.31 2004-10-19 17:32:07-04 kentd Exp $"; #include "defc.h" #include @@ -34,8 +34,8 @@ int g_clk_mode = CLK_IDLE; int g_clk_read = 0; int g_clk_reg1 = 0; -word32 c033_data = 0; -word32 c034_val = 0; +extern int g_c033_data; +extern int g_c034_val; byte g_bram[2][256]; byte *g_bram_ptr = &(g_bram[0][0]); @@ -173,12 +173,19 @@ update_cur_time() tm_ptr = localtime(&cur_time); secs = mktime(tm_ptr); +#ifdef MAC + /* Mac OS X's mktime function modifies the tm_ptr passed in for */ + /* the CDT timezone and breaks this algorithm. So on a Mac, we */ + /* will use the tm_ptr->gmtoff member to correct the time */ + secs = secs + tm_ptr->tm_gmtoff; +#else secs = (unsigned int)cur_time - (secs2 - secs); if(tm_ptr->tm_isdst) { /* adjust for daylight savings time */ secs += 3600; } +#endif /* add in secs to make date based on Apple Jan 1, 1904 instead of */ /* Unix's Jan 1, 1970 */ @@ -210,28 +217,10 @@ clock_update_if_needed() } } -word32 -clock_read_c033() -{ - return c033_data; -} - -word32 -clock_read_c034() -{ - return c034_val; -} - -void -clock_write_c033(word32 val) -{ - c033_data = val; -} - void clock_write_c034(word32 val) { - c034_val = val & 0x7f; + g_c034_val = val & 0x7f; if((val & 0x80) != 0) { if((val & 0x20) == 0) { printf("c034 write not last = 1\n"); @@ -251,12 +240,12 @@ do_clock_data() clk_printf("In do_clock_data, g_clk_mode: %02x\n", g_clk_mode); - read = c034_val & 0x40; + read = g_c034_val & 0x40; switch(g_clk_mode) { case CLK_IDLE: - g_clk_read = (c033_data >> 7) & 1; - g_clk_reg1 = (c033_data >> 2) & 3; - op = (c033_data >> 4) & 7; + g_clk_read = (g_c033_data >> 7) & 1; + g_clk_reg1 = (g_c033_data >> 2) & 3; + op = (g_c033_data >> 4) & 7; if(!read) { /* write */ switch(op) { @@ -269,7 +258,7 @@ do_clock_data() if(g_clk_reg1 & 0x2) { /* extend BRAM read */ g_clk_mode = CLK_BRAM2; - g_clk_reg1 = (c033_data & 7) << 5; + g_clk_reg1 = (g_c033_data & 7) << 5; } break; case 0x2: /* read/write ram 0x10-0x13 */ @@ -279,11 +268,11 @@ do_clock_data() case 0x4: /* read/write ram 0x00-0x0f */ case 0x5: case 0x6: case 0x7: g_clk_mode = CLK_BRAM1; - g_clk_reg1 = (c033_data >> 2) & 0xf; + g_clk_reg1 = (g_c033_data >> 2) & 0xf; break; default: halt_printf("Bad c033_data in CLK_IDLE: %02x\n", - c033_data); + g_c033_data); } } else { printf("clk read from IDLE mode!\n"); @@ -294,13 +283,13 @@ do_clock_data() case CLK_BRAM2: if(!read) { /* get more bits of bram addr */ - if((c033_data & 0x83) == 0x00) { + if((g_c033_data & 0x83) == 0x00) { /* more address bits */ - g_clk_reg1 |= ((c033_data >> 2) & 0x1f); + g_clk_reg1 |= ((g_c033_data >> 2) & 0x1f); g_clk_mode = CLK_BRAM1; } else { halt_printf("CLK_BRAM2: c033_data: %02x!\n", - c033_data); + g_c033_data); g_clk_mode = CLK_IDLE; } } else { @@ -313,9 +302,9 @@ do_clock_data() if(read) { if(g_clk_read) { /* Yup, read */ - c033_data = g_bram_ptr[g_clk_reg1]; + g_c033_data = g_bram_ptr[g_clk_reg1]; clk_printf("Reading BRAM loc %02x: %02x\n", - g_clk_reg1, c033_data); + g_clk_reg1, g_c033_data); } else { halt_printf("CLK_BRAM1: said wr, now read\n"); } @@ -325,8 +314,8 @@ do_clock_data() } else { /* Yup, write */ clk_printf("Writing BRAM loc %02x with %02x\n", - g_clk_reg1, c033_data); - g_bram_ptr[g_clk_reg1] = c033_data; + g_clk_reg1, g_c033_data); + g_bram_ptr[g_clk_reg1] = g_c033_data; g_config_kegs_update_needed = 1; } } @@ -337,20 +326,21 @@ do_clock_data() if(g_clk_read == 0) { halt_printf("Reading time, but in set mode!\n"); } - c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) & 0xff; + g_c033_data = (g_clk_cur_time >> (g_clk_reg1 * 8)) & + 0xff; clk_printf("Returning time byte %d: %02x\n", - g_clk_reg1, c033_data); + g_clk_reg1, g_c033_data); } else { /* Write */ if(g_clk_read) { halt_printf("Write time, but in read mode!\n"); } clk_printf("Writing TIME loc %d with %02x\n", - g_clk_reg1, c033_data); + g_clk_reg1, g_c033_data); mask = 0xff << (8 * g_clk_reg1); g_clk_cur_time = (g_clk_cur_time & (~mask)) | - ((c033_data & 0xff) << (8 *g_clk_reg1)); + ((g_c033_data & 0xff) << (8 * g_clk_reg1)); } g_clk_mode = CLK_IDLE; break; @@ -361,24 +351,24 @@ do_clock_data() } else { switch(g_clk_reg1) { case 0x0: /* test register */ - if(c033_data & 0xc0) { + if(g_c033_data & 0xc0) { printf("Writing test reg: %02x!\n", - c033_data); + g_c033_data); /* set_halt(1); */ } break; case 0x1: /* write protect reg */ clk_printf("Writing clk wr_protect: %02x\n", - c033_data); - if(c033_data & 0x80) { + g_c033_data); + if(g_c033_data & 0x80) { printf("Stop, wr clk wr_prot: %02x\n", - c033_data); + g_c033_data); /* set_halt(1); */ } break; default: halt_printf("Writing int reg: %02x with %02x\n", - g_clk_reg1, c033_data); + g_clk_reg1, g_c033_data); } } g_clk_mode = CLK_IDLE; diff --git a/src/config.c b/src/config.c index b9987b1..b311c59 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_config_c[] = "@(#)$KmKId: config.c,v 1.30 2003-11-21 16:38:53-05 kentd Exp $"; +const char rcsid_config_c[] = "@(#)$KmKId: config.c,v 1.50 2004-12-04 02:05:25-05 kentd Exp $"; #include "defc.h" #include @@ -21,11 +21,15 @@ extern Iwm iwm; extern int g_track_bytes_35[]; extern int g_track_nibs_35[]; -extern int g_apple35_sel; +extern int g_c031_disk35; extern int g_cur_a2_stat; extern byte *g_slow_memory_ptr; +extern byte *g_rom_fc_ff_ptr; +extern byte *g_rom_cards_ptr; extern double g_cur_dcycs; +extern int g_rom_version; +extern int g_fatal_log; extern word32 g_adb_repeat_vbl; @@ -33,8 +37,19 @@ extern int g_limit_speed; extern int g_force_depth; extern int g_raw_serial; extern int g_serial_out_masking; +extern int g_serial_modem[]; +extern word32 g_mem_size_base; extern word32 g_mem_size_exp; extern int g_video_line_update_interval; +extern int g_video_extra_check_inputs; +extern int g_user_halt_bad; +extern int g_joystick_type; +extern int g_joystick_scale_factor_x; +extern int g_joystick_scale_factor_y; +extern int g_joystick_trim_amount_x; +extern int g_joystick_trim_amount_y; +extern int g_swap_paddles; +extern int g_invert_paddles; extern int g_screen_index[]; extern word32 g_full_refresh_needed; @@ -46,7 +61,7 @@ extern int g_key_down; extern const char g_kegs_version_str[]; int g_config_control_panel = 0; -char g_config_kegs_name[256]; +char g_config_kegs_name[1024]; char g_cfg_cwd_str[CFG_PATH_MAX] = { 0 }; int g_config_kegs_auto_update = 1; @@ -58,10 +73,11 @@ const char *g_config_kegs_name_list[] = { int g_highest_smartport_unit = -1; int g_reparse_delay = 0; +int g_user_page2_shadow = 1; -byte g_save_text_screen_bytes[0x800]; -word32 g_save_cur_a2_stat = 0; -char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; +byte g_save_text_screen_bytes[0x800]; +int g_save_cur_a2_stat = 0; +char g_cfg_printf_buf[CFG_PRINTF_BUFSIZE]; char g_config_kegs_buf[CONF_BUF_LEN]; word32 g_cfg_vbl_count = 0; @@ -78,6 +94,12 @@ int g_cfg_opts_vals[CFG_MAX_OPTS]; char g_cfg_opts_strs[CFG_MAX_OPTS][CFG_OPT_MAXSTR]; char g_cfg_opt_buf[CFG_OPT_MAXSTR]; +char *g_cfg_rom_path = "ROM"; +char *g_cfg_file_def_name = "Undefined"; +char **g_cfg_file_strptr = 0; +int g_cfg_file_min_size = 1024; +int g_cfg_file_max_size = 2047*1024*1024; + #define MAX_PARTITION_BLK_SIZE 65536 extern Cfg_menu g_cfg_main_menu[]; @@ -108,9 +130,58 @@ Cfg_menu g_cfg_disk_menu[] = { { 0, 0, 0, 0, 0 }, }; +Cfg_menu g_cfg_joystick_menu[] = { +{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, +{ "Joystick Emulation,0,Keypad Joystick,1,Mouse Joystick,2,Native Joystick 1," + "3,Native Joystick 2", KNMP(g_joystick_type), CFGTYPE_INT }, +{ "Joystick Scale X,0x100,Standard,0x119,+10%,0x133,+20%," + "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", + KNMP(g_joystick_scale_factor_x), CFGTYPE_INT }, +{ "Joystick Scale Y,0x100,Standard,0x119,+10%,0x133,+20%," + "0x150,+30%,0xb0,-30%,0xcd,-20%,0xe7,-10%", + KNMP(g_joystick_scale_factor_y), CFGTYPE_INT }, +{ "Joystick Trim X", KNMP(g_joystick_trim_amount_x), CFGTYPE_INT }, +{ "Joystick Trim Y", KNMP(g_joystick_trim_amount_y), CFGTYPE_INT }, +{ "Swap Joystick X and Y,0,Normal operation,1,Paddle 1 and Paddle 0 swapped", + KNMP(g_swap_paddles), CFGTYPE_INT }, +{ "Invert Joystick,0,Normal operation,1,Left becomes right and up becomes down", + KNMP(g_invert_paddles), CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_rom_menu[] = { +{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, +{ "ROM File", KNMP(g_cfg_rom_path), CFGTYPE_FILE }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + +Cfg_menu g_cfg_serial_menu[] = { +{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, +{ "Serial Ports,0,Only use sockets 6501-6502,1,Use real ports if avail", + KNMP(g_raw_serial), CFGTYPE_INT }, +{ "Serial Output,0,Send full 8-bit data,1,Mask off high bit", + KNMP(g_serial_out_masking), CFGTYPE_INT }, +{ "Modem on port 0 (slot 1),0,Simple socket emulation mode,1,Modem with " + "incoming and outgoing emulation", KNMP(g_serial_modem[0]), + CFGTYPE_INT }, +{ "Modem on port 1 (slot 2),0,Simple socket emulation mode,1,Modem with " + "incoming and outgoing emulation", KNMP(g_serial_modem[1]), + CFGTYPE_INT }, +{ "", 0, 0, 0, 0 }, +{ "Back to Main Config", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, +{ 0, 0, 0, 0, 0 }, +}; + Cfg_menu g_cfg_main_menu[] = { { "KEGS Configuration", g_cfg_main_menu, 0, 0, CFGTYPE_MENU }, { "Disk Configuration", g_cfg_disk_menu, 0, 0, CFGTYPE_MENU }, +{ "Joystick Configuration", g_cfg_joystick_menu, 0, 0, CFGTYPE_MENU }, +{ "ROM File Selection", g_cfg_rom_menu, 0, 0, CFGTYPE_MENU }, +{ "Serial Port Configuration", g_cfg_serial_menu, 0, 0, CFGTYPE_MENU }, { "Force X-windows display depth", KNMP(g_force_depth), CFGTYPE_INT }, { "Auto-update config.kegs,0,Manual,1,Immediately", KNMP(g_config_kegs_auto_update), CFGTYPE_INT }, @@ -119,13 +190,16 @@ Cfg_menu g_cfg_main_menu[] = { { "Expansion Mem Size,0,0MB,0x100000,1MB,0x200000,2MB,0x300000,3MB," "0x400000,4MB,0x600000,6MB,0x800000,8MB,0xa00000,10MB,0xc00000,12MB," "0xe00000,14MB", KNMP(g_mem_size_exp), CFGTYPE_INT }, -{ "Serial Ports,0,Only use sockets 6501-6502,1,Use real ports if avail", - KNMP(g_raw_serial), CFGTYPE_INT }, -{ "Serial Output,0,Send full 8-bit data,1,Mask off high bit", - KNMP(g_serial_out_masking), CFGTYPE_INT }, { "3200 Color Enable,0,Auto (Full if fast enough),1,Full (Update every line)," "8,Off (Update video every 8 lines)", KNMP(g_video_line_update_interval), CFGTYPE_INT }, +{ "Keyboard and mouse poll rate,0,60 times per second,1,240 times per second", + KNMP(g_video_extra_check_inputs), CFGTYPE_INT }, +{ "Code Red Halts,0,Do not stop on bad accesses,1,Enter debugger on bad " + "accesses", KNMP(g_user_halt_bad), CFGTYPE_INT }, +{ "Enable Text Page 2 Shadow,0,Disabled on ROM 01 (matches real hardware)," + "1,Enabled on ROM 01 and 03", + KNMP(g_user_page2_shadow), CFGTYPE_INT }, { "Dump text screen to file", (void *)cfg_text_screen_dump, 0, 0, CFGTYPE_FUNC}, { "", 0, 0, 0, 0 }, { "Save changes to config.kegs", (void *)config_write_config_kegs_file, 0, 0, @@ -155,12 +229,68 @@ Cfg_listhdr g_cfg_partitionlist = { 0 }; int g_cfg_file_pathfield = 0; +const char *g_kegs_rom_names[] = { "ROM", "ROM", "ROM.01", "ROM.03", 0 }; + /* First entry is special--it will be overwritten by g_cfg_rom_path */ + +const char *g_kegs_c1rom_names[] = { 0 }; +const char *g_kegs_c2rom_names[] = { 0 }; +const char *g_kegs_c3rom_names[] = { 0 }; +const char *g_kegs_c4rom_names[] = { 0 }; +const char *g_kegs_c5rom_names[] = { 0 }; +const char *g_kegs_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", + "DISK.ROM", "diskII.prom", 0 }; +const char *g_kegs_c7rom_names[] = { 0 }; + +const char **g_kegs_rom_card_list[8] = { + 0, g_kegs_c1rom_names, + g_kegs_c2rom_names, g_kegs_c3rom_names, + g_kegs_c4rom_names, g_kegs_c5rom_names, + g_kegs_c6rom_names, g_kegs_c7rom_names }; + +byte g_rom_c600_rom01_diffs[256] = { + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, + 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, + 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, + 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, + 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, + 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, + 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, + 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, + 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, + 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, + 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, + 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 +}; + + void config_init_menus(Cfg_menu *menuptr) { void *voidptr; const char *name_str; Cfg_defval *defptr; + char **str_ptr; + char *str; int type; int pos; int val; @@ -180,20 +310,30 @@ config_init_menus(Cfg_menu *menuptr) if(name_str != 0) { defptr = &(g_cfg_defvals[g_cfg_defval_index++]); if(g_cfg_defval_index >= CFG_MAX_DEFVALS) { - printf("CFG_MAX_DEFVAL overflow\n"); + fatal_printf("CFG_MAX_DEFVAL overflow\n"); my_exit(5); } defptr->menuptr = menuptr; defptr->intval = 0; + defptr->strval = 0; switch(type) { case CFGTYPE_INT: val = *((int *)voidptr); defptr->intval = val; menuptr->defptr = &(defptr->intval); break; + case CFGTYPE_FILE: + str_ptr = (char **)menuptr->ptr; + str = *str_ptr; + // We need to malloc this string since all + // string values must be dynamically alloced + defptr->strval = str; // this can have a copy + *str_ptr = kegs_malloc_str(str); + menuptr->defptr = &(defptr->strval); + break; default: - printf("name_str is %p = %s, but type: %d\n", - name_str, name_str, type); + fatal_printf("name_str is %p = %s, but type: " + "%d\n", name_str, name_str, type); my_exit(5); } } @@ -208,11 +348,15 @@ config_init_menus(Cfg_menu *menuptr) void config_init() { + int can_create; + config_init_menus(g_cfg_main_menu); // Find the config.kegs file + g_config_kegs_name[0] = 0; + can_create = 1; setup_kegs_file(&g_config_kegs_name[0], sizeof(g_config_kegs_name), 0, - &g_config_kegs_name_list[0]); + can_create, &g_config_kegs_name_list[0]); config_parse_config_kegs_file(); } @@ -221,7 +365,18 @@ void cfg_exit() { /* printf("In cfg exit\n"); */ - g_config_control_panel = 0; + if(g_rom_version >= 1) { + g_config_control_panel = 0; + } +} + +void +cfg_toggle_config_panel() +{ + g_config_control_panel = !g_config_control_panel; + if(g_rom_version < 0) { + g_config_control_panel = 1; /* Stay in config mode */ + } } void @@ -239,7 +394,8 @@ cfg_text_screen_dump() printf("Writing text screen to the file %s\n", filename); ofile = fopen(filename, "w"); if(ofile == 0) { - printf("fopen ret 0, errno: %d\n", errno); + fatal_printf("Could not write to file %s, (%d)\n", filename, + errno); return; } @@ -289,6 +445,7 @@ config_parse_option(char *buf, int pos, int len, int line) Cfg_menu *menuptr; Cfg_defval *defptr; char *nameptr; + char **strptr; int *iptr; int num_equals; int type; @@ -357,6 +514,13 @@ config_parse_option(char *buf, int pos, int len, int line) iptr = (int *)menuptr->ptr; *iptr = val; break; + case CFGTYPE_FILE: + strptr = (char **)menuptr->ptr; + if(strptr && *strptr) { + free(*strptr); + } + *strptr = kegs_malloc_str(&buf[pos]); + break; default: printf("Config file variable %s is unknown type: %d\n", nameptr, type); @@ -372,12 +536,14 @@ config_parse_bram(char *buf, int pos, int len) int val; if((len < (pos+5)) || (buf[pos+1] != '[') || (buf[pos+4] != ']')) { - printf("Malformed bram statement: %s\n", buf); + fatal_printf("While reading config.kegs, found malformed bram " + "statement: %s\n", buf); return; } bram_num = buf[pos] - '0'; if(bram_num != 1 && bram_num != 3) { - printf("Malformed bram number: %s\n", buf); + fatal_printf("While reading config.kegs, found bad bram " + "num: %s\n", buf); return; } @@ -397,6 +563,210 @@ config_parse_bram(char *buf, int pos, int len) } } +void +config_load_roms() +{ + struct stat stat_buf; + const char **names_ptr; + int more_than_8mb; + int changed_rom; + int len; + int fd; + int ret; + int i; + + g_rom_version = -1; + + /* set first entry of g_kegs_rom_names[] to g_cfg_rom_path so that */ + /* it becomes the first place searched. */ + g_kegs_rom_names[0] = g_cfg_rom_path; + setup_kegs_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, -1, 0, + &g_kegs_rom_names[0]); + + if(g_cfg_tmp_path[0] == 0) { + // Just get out, let config interface select ROM + g_config_control_panel = 1; + return; + } + fd = open(&g_cfg_tmp_path[0], O_RDONLY | O_BINARY); + if(fd < 0) { + fatal_printf("Open ROM file %s failed:%d, errno:%d\n", + &g_cfg_tmp_path[0], fd, errno); + g_config_control_panel = 1; + return; + } + + ret = fstat(fd, &stat_buf); + if(ret != 0) { + fatal_printf("fstat returned %d on fd %d, errno: %d\n", + ret, fd, errno); + g_config_control_panel = 1; + return; + } + + len = stat_buf.st_size; + if(len == 128*1024) { + g_rom_version = 1; + g_mem_size_base = 256*1024; + memset(&g_rom_fc_ff_ptr[0], 0, 2*65536); + /* Clear banks fc and fd to 0 */ + ret = read(fd, &g_rom_fc_ff_ptr[2*65536], len); + } else if(len == 256*1024) { + g_rom_version = 3; + g_mem_size_base = 1024*1024; + ret = read(fd, &g_rom_fc_ff_ptr[0], len); + } else { + fatal_printf("The ROM size should be 128K or 256K, this file " + "is %d bytes\n", len); + g_config_control_panel = 1; + return; + } + + printf("Read: %d bytes of ROM\n", ret); + if(ret != len) { + fatal_printf("errno: %d\n", errno); + g_config_control_panel = 1; + return; + } + close(fd); + + memset(&g_rom_cards_ptr[0], 0, 256*16); + + /* initialize c600 rom to be diffs from the real ROM, to build-in */ + /* Apple II compatibility without distributing ROMs */ + for(i = 0; i < 256; i++) { + g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ + g_rom_c600_rom01_diffs[i]; + } + if(g_rom_version >= 3) { + /* some patches */ + g_rom_cards_ptr[0x61b] ^= 0x40; + g_rom_cards_ptr[0x61c] ^= 0x33; + g_rom_cards_ptr[0x632] ^= 0xc0; + g_rom_cards_ptr[0x633] ^= 0x33; + } + + for(i = 1; i < 8; i++) { + names_ptr = g_kegs_rom_card_list[i]; + if(names_ptr == 0) { + continue; + } + if(*names_ptr == 0) { + continue; + } + + setup_kegs_file(&g_cfg_tmp_path[0], CFG_PATH_MAX, 1, 0, + names_ptr); + + if(g_cfg_tmp_path[0] != 0) { + fd = open(&(g_cfg_tmp_path[0]), O_RDONLY | O_BINARY); + if(fd < 0) { + fatal_printf("Open card ROM file %s failed: %d " + "err:%d\n", &g_cfg_tmp_path[0], fd, + errno); + continue; + } + + len = 256; + ret = read(fd, &g_rom_cards_ptr[i*0x100], len); + + if(ret != len) { + fatal_printf("While reading card ROM %s, file " + "is too short. (%d) Expected %d bytes, " + "read %d bytes\n", errno, len, ret); + continue; + } + close(fd); + } + } + + more_than_8mb = (g_mem_size_exp > 0x800000); + /* Only do the patch if users wants more than 8MB of expansion mem */ + + changed_rom = 0; + if(g_rom_version == 1) { + /* make some patches to ROM 01 */ +#if 0 + /* 1: Patch ROM selftest to not do speed test */ + printf("Patching out speed test failures from ROM 01\n"); + g_rom_fc_ff_ptr[0x3785a] = 0x18; + changed_rom = 1; +#endif + +#if 0 + /* 2: Patch ROM selftests not to do tests 2,4 */ + /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ + g_rom_fc_ff_ptr[0x371e9] = 0xf5; + g_rom_fc_ff_ptr[0x371ea] = 0xff; + changed_rom = 1; +#endif + + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30302] = 0xdf; + g_rom_fc_ff_ptr[0x30314] = 0xdf; + g_rom_fc_ff_ptr[0x3031c] = 0x00; + changed_rom = 1; + } + + /* Patch ROM selftest to not do ROM cksum if any changes*/ + if(changed_rom) { + g_rom_fc_ff_ptr[0x37a06] = 0x18; + g_rom_fc_ff_ptr[0x37a07] = 0x18; + } + } else if(g_rom_version == 3) { + /* patch ROM 03 */ + printf("Patching ROM 03 smartport bug\n"); + /* 1: Patch Smartport code to fix a stupid bug */ + /* that causes it to write the IWM status reg into c036, */ + /* which is the system speed reg...it's "safe" since */ + /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ + /* it might have turned on shadowing in all banks! */ + g_rom_fc_ff_ptr[0x357c9] = 0x00; + changed_rom = 1; + +#if 0 + /* patch ROM 03 to not to speed test */ + /* skip fast speed test */ + g_rom_fc_ff_ptr[0x36ad7] = 0x18; + g_rom_fc_ff_ptr[0x36ad8] = 0x18; + changed_rom = 1; +#endif + +#if 0 + /* skip slow speed test */ + g_rom_fc_ff_ptr[0x36ae7] = 0x18; + g_rom_fc_ff_ptr[0x36ae8] = 0x6b; + changed_rom = 1; +#endif + +#if 0 + /* 4: Patch ROM 03 selftests not to do tests 1-4 */ + g_rom_fc_ff_ptr[0x364a9] = 0xf0; + g_rom_fc_ff_ptr[0x364aa] = 0xff; + changed_rom = 1; +#endif + + /* ROM tests are in ff/6403-642x, where 6403 = addr of */ + /* test 1, etc. */ + + if(more_than_8mb) { + /* Geoff Weiss patch to use up to 14MB of RAM */ + g_rom_fc_ff_ptr[0x30b] = 0xdf; + g_rom_fc_ff_ptr[0x31d] = 0xdf; + g_rom_fc_ff_ptr[0x325] = 0x00; + changed_rom = 1; + } + + if(changed_rom) { + /* patch ROM 03 selftest to not do ROM cksum */ + g_rom_fc_ff_ptr[0x36cb0] = 0x18; + g_rom_fc_ff_ptr[0x36cb1] = 0x18; + } + + } +} + void config_parse_config_kegs_file() { @@ -433,10 +803,11 @@ config_parse_config_kegs_file() /* In any case, copy the directory path to g_cfg_cwd_str */ (void)getcwd(&g_cfg_cwd_str[0], CFG_PATH_MAX); - fconf = fopen(g_config_kegs_name, "rt"); + fconf = fopen(g_config_kegs_name, "r"); if(fconf == 0) { - printf("cannot open disk_conf! Stopping!\n"); - exit(3); + fatal_printf("cannot open config.kegs at %s! Stopping!\n", + g_config_kegs_name); + my_exit(3); } line = 0; @@ -553,8 +924,9 @@ config_parse_config_kegs_file() ret = fclose(fconf); if(ret != 0) { - printf("Closing disk_conf ret: %d, errno: %d\n", ret, errno); - exit(4); + fatal_printf("Closing config.kegs ret: %d, errno: %d\n", ret, + errno); + my_exit(4); } iwm_printf("Done parsing disk_conf file\n"); @@ -623,6 +995,7 @@ config_write_config_kegs_file() Disk *dsk; Cfg_defval *defptr; Cfg_menu *menuptr; + char *curstr, *defstr; int defval, curval; int type; int slot, drive; @@ -673,13 +1046,20 @@ config_write_config_kegs_file() menuptr = defptr->menuptr; defval = defptr->intval; type = menuptr->cfgtype; - if(type != CFGTYPE_INT) { - /* skip it */ - continue; + if(type == CFGTYPE_INT) { + curval = *((int *)menuptr->ptr); + if(curval != defval) { + fprintf(fconf, "%s = %d\n", menuptr->name_str, + curval); + } } - curval = *((int *)menuptr->ptr); - if(curval != defval) { - fprintf(fconf, "%s = %d\n", menuptr->name_str, curval); + if(type == CFGTYPE_FILE) { + curstr = *((char **)menuptr->ptr); + defstr = *((char **)menuptr->defptr); + if(strcmp(curstr, defstr) != 0) { + fprintf(fconf, "%s = %s\n", menuptr->name_str, + curstr); + } } } @@ -721,13 +1101,13 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, g_config_kegs_update_needed = 1; if((slot < 5) || (slot > 7)) { - printf("insert_disk: Invalid slot: %d\n", slot); + fatal_printf("Invalid slot for insertiing disk: %d\n", slot); return; } if(drive < 0 || ((slot == 7) && (drive >= MAX_C7_DISKS)) || ((slot < 7) && (drive > 1))) { - printf("insert_disk: Invalid drive: %d\n", drive); - return; + fatal_printf("Invalid drive for inserting disk: %d\n", drive); + return; } dsk = cfg_get_dsk_from_slot_drive(slot, drive); @@ -761,9 +1141,9 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, free(dsk->name_ptr); } - name_len = strlen(name) + 1; - name_ptr = (char *)malloc(name_len); - strncpy(name_ptr, name, name_len); + name_len = strlen(name); + name_ptr = (char *)malloc(name_len + 1); + strncpy(name_ptr, name, name_len + 1); dsk->name_ptr = name_ptr; dsk->partition_name = 0; @@ -786,22 +1166,24 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, dsk->fd = -1; can_write = 1; - if((name_len > 4) && (strcmp(&name_ptr[name_len - 4], ".gz") == 0)) { + if((name_len > 3) && (strcmp(&name_ptr[name_len - 3], ".gz") == 0)) { /* it's gzip'ed, try to gunzip it, then unlink the */ /* uncompressed file */ can_write = 0; - uncomp_ptr = (char *)malloc(name_len); - strncpy(uncomp_ptr, name_ptr, name_len); - uncomp_ptr[name_len - 4] = 0; + uncomp_ptr = (char *)malloc(name_len + 1); + strncpy(uncomp_ptr, name_ptr, name_len + 1); + uncomp_ptr[name_len - 3] = 0; - system_len = name_len + 200; + system_len = 2*name_len + 100; system_str = (char *)malloc(system_len + 1); snprintf(system_str, system_len, - "set -o noclobber;gunzip -c %s > %s", name_ptr, - uncomp_ptr); + "set -o noclobber;gunzip -c %c%s%c > %c%s%c", + 0x22, name_ptr, 0x22, + 0x22, uncomp_ptr, 0x22); + /* 0x22 are " to allow spaces in filenames */ printf("I am uncompressing %s into %s for mounting\n", name_ptr, uncomp_ptr); ret = system(system_str); @@ -816,6 +1198,9 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, } free(system_str); free(uncomp_ptr); + /* Reduce name_len by 3 so that subsequent compares for .po */ + /* look at the correct chars */ + name_len -= 3; } if(dsk->fd < 0 && can_write) { @@ -832,7 +1217,7 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, iwm_printf("open returned: %d\n", dsk->fd); if(dsk->fd < 0) { - printf("Disk image %s does not exist!\n", name_ptr); + fatal_printf("Disk image %s does not exist!\n", name_ptr); return; } @@ -846,6 +1231,7 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, save_track = dsk->cur_qtr_track; /* save arm position */ dsk->image_type = DSK_TYPE_PRODOS; + dsk->image_start = 0; /* See if it is in 2IMG format */ ret = read(dsk->fd, (char *)&buf_2img[0], 512); @@ -853,6 +1239,13 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, if(size <= 0) { size = cfg_get_fd_size(dsk->fd); } + + /* Try to guess that there is a Mac Binary header of 128 bytes */ + /* See if image size & 0xfff = 0x080 which indicates extra 128 bytes */ + if((size & 0xfff) == 0x080) { + printf("Assuming Mac Binary header on %s\n", dsk->name_ptr); + dsk->image_start += 0x80; + } image_identified = 0; if(buf_2img[0] == '2' && buf_2img[1] == 'I' && buf_2img[2] == 'M' && buf_2img[3] == 'G') { @@ -883,16 +1276,6 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, // Byte reversed 0x0c8000 size = 0x0c8000; } - if(size == 0) { - /* From KEGS-OS-X: Gilles Tschopp: */ - /* deal with corrupted 2IMG files */ - printf("Bernie corrupted size to 0...working around\n"); - - /* Just get the full size, and subtract 64, and */ - /* then round down to lower 0x1000 boundary */ - size = cfg_get_fd_size(dsk->fd) - 64; - size = size & -0x1000; - } dsk->image_start = unix_pos; dsk->image_size = size; } @@ -909,32 +1292,31 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, printf("Image named %s is in Mac diskcopy format\n", dsk->name_ptr); image_identified = 1; - dsk->image_start = 0x54; + dsk->image_start += 0x54; dsk->image_size = exp_size; dsk->image_type = DSK_TYPE_PRODOS; /* ProDOS */ } } if(!image_identified) { /* Assume raw image */ - dsk->image_start = 0; dsk->image_size = size; dsk->image_type = DSK_TYPE_PRODOS; if(dsk->disk_525) { dsk->image_type = DSK_TYPE_DOS33; - if(name_len >= 5) { - cmp_o = dsk->name_ptr[name_len-2]; - cmp_p = dsk->name_ptr[name_len-3]; - cmp_dot = dsk->name_ptr[name_len-4]; + if(name_len >= 4) { + cmp_o = dsk->name_ptr[name_len-1]; + cmp_p = dsk->name_ptr[name_len-2]; + cmp_dot = dsk->name_ptr[name_len-3]; if(cmp_dot == '.' && (cmp_p == 'p' || cmp_p == 'P') && (cmp_o == 'o' || cmp_o == 'O')) { dsk->image_type = DSK_TYPE_PRODOS; } - cmp_b = dsk->name_ptr[name_len-2]; - cmp_i = dsk->name_ptr[name_len-3]; - cmp_n = dsk->name_ptr[name_len-4]; - cmp_dot = dsk->name_ptr[name_len-5]; + cmp_b = dsk->name_ptr[name_len-1]; + cmp_i = dsk->name_ptr[name_len-2]; + cmp_n = dsk->name_ptr[name_len-3]; + cmp_dot = dsk->name_ptr[name_len-4]; if(cmp_dot == '.' && (cmp_n == 'n' || cmp_n == 'N') && (cmp_i == 'i' || cmp_i == 'I') && @@ -949,6 +1331,7 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, dsk->disk_dirty = 0; dsk->nib_pos = 0; + dsk->trks = 0; if(dsk->smartport) { g_highest_smartport_unit = MAX(dsk->drive, @@ -967,12 +1350,12 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, } } iwm_printf("adding smartport device[%d], size:%08x, " - "img_sz:%08x\n", dsk->drive, dsk->tracks[0].unix_len, + "img_sz:%08x\n", dsk->drive, dsk->trks[0].unix_len, dsk->image_size); } else if(dsk->disk_525) { unix_pos = dsk->image_start; size = dsk->image_size; - dsk->num_tracks = 4*35; + disk_set_num_tracks(dsk, 4*35); len = 0x1000; nibs = NIB_LEN_525; if(dsk->image_type == DSK_TYPE_NIB) { @@ -980,8 +1363,8 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, nibs = len; } if(size != 35*len) { - printf("Disk 5.25 error: size is %d, not %d\n",size, - 35*len); + fatal_printf("Disk 5.25 error: size is %d, not 140K. " + "Will try to mount anyway\n", size, 35*len); } for(i = 0; i < 35; i++) { iwm_move_to_track(dsk, 4*i); @@ -993,9 +1376,10 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, unix_pos = dsk->image_start; size = dsk->image_size; if(size != 800*1024) { - printf("Disk 3.5 error: size is %d, not 800K\n", size); + fatal_printf("Disk 3.5 error: size is %d, not 800K. " + "Will try to mount anyway\n", size); } - dsk->num_tracks = 2*80; + disk_set_num_tracks(dsk, 2*80); for(i = 0; i < 2*80; i++) { iwm_move_to_track(dsk, i); len = g_track_bytes_35[i >> 5]; @@ -1005,7 +1389,7 @@ insert_disk(int slot, int drive, const char *name, int ejected, int force_size, disk_unix_to_nib(dsk, i, unix_pos, len, nibs); unix_pos += len; - iwm_printf(" trk_len:%05x\n",dsk->tracks[i].track_len); + iwm_printf(" trk_len:%05x\n", dsk->trks[i].track_len); } } @@ -1059,7 +1443,7 @@ eject_disk(Disk *dsk) g_config_kegs_update_needed = 1; motor_on = iwm.motor_on; - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { motor_on = iwm.motor_on35; } if(motor_on) { @@ -1073,14 +1457,18 @@ eject_disk(Disk *dsk) /* Free all memory, close file */ /* free the tracks first */ - for(i = 0; i < dsk->num_tracks; i++) { - if(dsk->tracks[i].nib_area) { - free(dsk->tracks[i].nib_area); + if(dsk->trks != 0) { + for(i = 0; i < dsk->num_tracks; i++) { + if(dsk->trks[i].nib_area) { + free(dsk->trks[i].nib_area); + } + dsk->trks[i].nib_area = 0; + dsk->trks[i].track_len = 0; } - dsk->tracks[i].nib_area = 0; - dsk->tracks[i].track_len = 0; + free(dsk->trks); } dsk->num_tracks = 0; + dsk->trks = 0; /* close file, clean up dsk struct */ close(dsk->fd); @@ -1232,7 +1620,8 @@ cfg_partition_make_list(int fd) GET_BE_WORD32(part_map_ptr->map_blk_cnt)); } if(sig != 0x504d) { - printf("Partition entry %d bad sig\n", cur_blk); + printf("Partition entry %d bad signature:%04x\n", + cur_blk, sig); free(blk_bufptr); return g_cfg_partitionlist.last; } @@ -1279,7 +1668,7 @@ cfg_maybe_insert_disk(int slot, int drive, const char *namestr) fd = open(namestr, O_RDONLY | O_BINARY, 0x1b6); if(fd < 0) { - printf("Cannot open: %s\n", namestr); + fatal_printf("Cannot open disk image: %s\n", namestr); return 0; } @@ -1485,10 +1874,12 @@ cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras) } void -cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change) +cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change) { char valbuf[CFG_OPT_MAXSTR]; + char **str_ptr; const char *menustr; + char *curstr, *defstr; char *str; char *outstr; int *iptr; @@ -1511,10 +1902,10 @@ cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change) opt_get_str = 0; separator = ','; - menu_ptr += menu_pos; /* move forward to entry menu_pos */ + menuptr += menu_pos; /* move forward to entry menu_pos */ - menustr = menu_ptr->str; - type = menu_ptr->cfgtype; + menustr = menuptr->str; + type = menuptr->cfgtype; type_ext = (type >> 4); type = type & 0xf; len = strlen(menustr) + 1; @@ -1594,21 +1985,40 @@ cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change) // Figure out if we should get a checkmark curval = -1; defval = -1; + curstr = 0; if(type == CFGTYPE_INT) { - iptr = menu_ptr->ptr; + iptr = menuptr->ptr; curval = *iptr; - iptr = menu_ptr->defptr; + iptr = menuptr->defptr; defval = *iptr; if(curval == defval) { g_cfg_opt_buf[3] = 'D'; /* checkmark */ g_cfg_opt_buf[4] = '\t'; } } + if(type == CFGTYPE_FILE) { + str_ptr = (char **)menuptr->ptr; + curstr = *str_ptr; + str_ptr = (char **)menuptr->defptr; + defstr = *str_ptr; + if(strcmp(curstr,defstr) == 0) { + g_cfg_opt_buf[3] = 'D'; /* checkmark */ + g_cfg_opt_buf[4] = '\t'; + } + } + + // If it's a menu, give it a special menu indicator + if(type == CFGTYPE_MENU) { + g_cfg_opt_buf[1] = '\t'; + g_cfg_opt_buf[2] = 'M'; /* return-like symbol */ + g_cfg_opt_buf[3] = '\t'; + g_cfg_opt_buf[4] = ' '; + } // Decide what to display on the "right" side str = 0; opt_num = -1; - if(type == CFGTYPE_INT) { + if(type == CFGTYPE_INT || type == CFGTYPE_FILE) { g_cfg_opt_buf[bufpos++] = ' '; g_cfg_opt_buf[bufpos++] = '='; g_cfg_opt_buf[bufpos++] = ' '; @@ -1636,7 +2046,7 @@ cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change) curval += change; /* HACK: min_val, max_val testing here */ } - iptr = (int *)menu_ptr->ptr; + iptr = (int *)menuptr->ptr; *iptr = curval; } g_config_kegs_update_needed = 1; @@ -1657,7 +2067,11 @@ cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change) } else if (type == CFGTYPE_DISK) { str = &(g_cfg_opts_strs[0][0]), cfg_get_disk_name(str, CFG_OPT_MAXSTR, type_ext, 1); - str = cfg_shorten_filename(str, 70); + str = cfg_shorten_filename(str, 68); + } else if (type == CFGTYPE_FILE) { + str = &(g_cfg_opts_strs[0][0]); + snprintf(str, CFG_OPT_MAXSTR, "%s", curstr); + str = cfg_shorten_filename(str, 68); } else { str = ""; } @@ -1776,25 +2190,32 @@ cfg_file_init() int slot, drive; int i; - cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, g_cfg_slotdrive, 0); - - slot = g_cfg_slotdrive >> 8; - drive = g_cfg_slotdrive & 1; - for(i = 0; i < 6; i++) { - if(g_cfg_tmp_path[0] != 0) { - break; - } - /* try to get a starting path from some mounted drive */ - drive = !drive; - if(i & 1) { - slot++; - if(slot >= 8) { - slot = 5; - } - } + if(g_cfg_slotdrive < 0xfff) { cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, + g_cfg_slotdrive, 0); + + slot = g_cfg_slotdrive >> 8; + drive = g_cfg_slotdrive & 1; + for(i = 0; i < 6; i++) { + if(g_cfg_tmp_path[0] != 0) { + break; + } + /* try to get a starting path from some mounted drive */ + drive = !drive; + if(i & 1) { + slot++; + if(slot >= 8) { + slot = 5; + } + } + cfg_get_disk_name(&g_cfg_tmp_path[0], CFG_PATH_MAX, (slot << 8) + drive, 0); + } + } else { + // Just use g_cfg_file_def_name + strncpy(&g_cfg_tmp_path[0], g_cfg_file_def_name, CFG_PATH_MAX); } + cfg_get_base_path(&g_cfg_file_curpath[0], &g_cfg_tmp_path[0], 0); g_cfg_dirlist.invalid = 1; } @@ -1861,11 +2282,17 @@ int cfg_dirent_sortfn(const void *obj1, const void *obj2) { const Cfg_dirent *direntptr1, *direntptr2; + int ret; /* Called by qsort to sort directory listings */ direntptr1 = (const Cfg_dirent *)obj1; direntptr2 = (const Cfg_dirent *)obj2; - return strcmp(direntptr1->name, direntptr2->name); +#if defined(MAC) || defined(_WIN32) + ret = strcasecmp(direntptr1->name, direntptr2->name); +#else + ret = strcmp(direntptr1->name, direntptr2->name); +#endif + return ret; } int @@ -1906,6 +2333,7 @@ cfg_file_readdir(const char *pathptr) mode_t fmt; char *str; const char *tmppathptr; + int size; int ret; int is_dir, is_gz; int len; @@ -1989,15 +2417,25 @@ cfg_file_readdir(const char *pathptr) printf("stat %s ret %d, errno:%d\n", &g_cfg_tmp_path[0], ret, errno); stat_buf.st_size = 0; + continue; /* skip it */ } else { fmt = stat_buf.st_mode & S_IFMT; + size = stat_buf.st_size; if(fmt == S_IFDIR) { /* it's a directory */ is_dir = 1; - } else if((fmt == S_IFREG) && (is_gz == 0) && - (stat_buf.st_size < 140*1024)) { - /* skip it */ - continue; + } else if((fmt == S_IFREG) && (is_gz == 0)) { + if(g_cfg_slotdrive < 0xfff) { + if(size < 140*1024) { + continue; /* skip it */ + } + } else { + /* see if there are size limits */ + if((size < g_cfg_file_min_size) || + (size > g_cfg_file_max_size)) { + continue; /* skip it */ + } + } } } cfg_file_add_dirent(&g_cfg_dirlist, direntptr->d_name, is_dir, @@ -2097,7 +2535,7 @@ cfg_file_draw() for(y = 0; y < 21; y++) { cfg_htab_vtab(0, y); cfg_printf("\tZ\t"); - for(x = 1; x < 72; x++) { + for(x = 1; x < 79; x++) { cfg_htab_vtab(x, y); cfg_putchar(' '); } @@ -2110,17 +2548,23 @@ cfg_file_draw() for(x = 1; x < 79; x++) { cfg_putchar(' '); } - cfg_htab_vtab(30, 0); - cfg_printf("\bSelect image for s%dd%d\b", (g_cfg_slotdrive >> 8), - (g_cfg_slotdrive & 0xff) + 1); + if(g_cfg_slotdrive < 0xfff) { + cfg_htab_vtab(30, 0); + cfg_printf("\bSelect image for s%dd%d\b", + (g_cfg_slotdrive >> 8), (g_cfg_slotdrive & 0xff) + 1); + } else { + cfg_htab_vtab(5, 0); + cfg_printf("\bSelect file to use as %-40s\b", + cfg_shorten_filename(g_cfg_file_def_name, 40)); + } cfg_htab_vtab(2, 1); - cfg_printf("Current KEGS directory: %-50s", - cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); + cfg_printf("config.kegs path: %-56s", + cfg_shorten_filename(&g_config_kegs_name[0], 56)); cfg_htab_vtab(2, 2); - cfg_printf("config.kegs path: %-50s", - cfg_shorten_filename(&g_config_kegs_name[0], 50)); + cfg_printf("Current KEGS directory: %-50s", + cfg_shorten_filename(&g_cfg_cwd_str[0], 50)); cfg_htab_vtab(2, 3); @@ -2129,7 +2573,7 @@ cfg_file_draw() str = "\b \b"; } cfg_printf("Path: %s%s", - cfg_shorten_filename(&g_cfg_file_curpath[0], 64), str); + cfg_shorten_filename(&g_cfg_file_curpath[0], 68), str); cfg_htab_vtab(0, 4); cfg_printf(" \t"); @@ -2184,7 +2628,7 @@ cfg_file_draw() } } - cfg_htab_vtab(1, 21); + cfg_htab_vtab(1, 5 + CFG_NUM_SHOWENTS); cfg_putchar('\t'); for(x = 1; x < 79; x++) { cfg_putchar('L'); @@ -2226,6 +2670,28 @@ cfg_partition_selected() g_cfg_select_partition = -1; } +void +cfg_file_update_ptr(char *str) +{ + char *newstr; + int len; + + len = strlen(str) + 1; + newstr = malloc(len); + memcpy(newstr, str, len); + if(g_cfg_file_strptr) { + if(*g_cfg_file_strptr) { + free(*g_cfg_file_strptr); + } + } + *g_cfg_file_strptr = newstr; + if(g_cfg_file_strptr == &(g_cfg_rom_path)) { + printf("Updated ROM file\n"); + load_roms_init_memory(); + } + g_config_kegs_update_needed = 1; +} + void cfg_file_selected() { @@ -2272,15 +2738,22 @@ cfg_file_selected() CFG_PATH_MAX); } else { /* select it */ - ret = cfg_maybe_insert_disk(g_cfg_slotdrive >> 8, - g_cfg_slotdrive & 0xff, &g_cfg_file_path[0]); - if(ret > 0) { + if(g_cfg_slotdrive < 0xfff) { + ret = cfg_maybe_insert_disk(g_cfg_slotdrive>>8, + g_cfg_slotdrive & 0xff, + &g_cfg_file_path[0]); + if(ret > 0) { + g_cfg_slotdrive = -1; + } + } else { + cfg_file_update_ptr(&g_cfg_file_path[0]); g_cfg_slotdrive = -1; } } } } + void cfg_file_handle_key(int key) { @@ -2312,7 +2785,10 @@ cfg_file_handle_key(int key) switch(key) { case 0x1b: - eject_disk_by_num(g_cfg_slotdrive >> 8, g_cfg_slotdrive & 0xff); + if(g_cfg_slotdrive < 0xfff) { + eject_disk_by_num(g_cfg_slotdrive >> 8, + g_cfg_slotdrive & 0xff); + } g_cfg_slotdrive = -1; g_cfg_select_partition = -1; g_cfg_dirlist.invalid = 1; @@ -2330,6 +2806,7 @@ cfg_file_handle_key(int key) } break; case 0x0d: /* return */ + printf("handling return press\n"); cfg_file_selected(); break; case 0x09: /* tab */ @@ -2359,7 +2836,7 @@ config_control_panel() { void (*fn_ptr)(); const char *str; - Cfg_menu *menu_ptr; + Cfg_menu *menuptr; void *ptr; int print_eject_help; int line; @@ -2371,7 +2848,7 @@ config_control_panel() int key; int i, j; - // First, save key text info + // First, save important text screen state g_save_cur_a2_stat = g_cur_a2_stat; for(i = 0; i < 0x400; i++) { g_save_text_screen_bytes[i] = g_slow_memory_ptr[0x400+i]; @@ -2386,6 +2863,7 @@ config_control_panel() cfg_printf("In config_control_panel\n"); for(i = 0; i < 20; i++) { + // Toss any queued-up keypresses if(adb_read_c000() & 0x80) { (void)adb_access_c010(); } @@ -2400,30 +2878,37 @@ config_control_panel() cfg_home(); j = 0; - menu_ptr = g_cfg_main_menu; + menuptr = g_cfg_main_menu; + if(g_rom_version < 0) { + /* Must select ROM file */ + menuptr = g_cfg_rom_menu; + } menu_line = 1; menu_inc = 1; g_cfg_slotdrive = -1; g_cfg_select_partition = -1; while(g_config_control_panel) { + if(g_fatal_log > 0) { + x_show_alert(0, 0); + } cfg_home(); line = 1; max_line = 1; match_found = 0; print_eject_help = 0; - cfg_printf("%s\n\n", menu_ptr[0].str); + cfg_printf("%s\n\n", menuptr[0].str); while(line < 24) { - str = menu_ptr[line].str; - type = menu_ptr[line].cfgtype; - ptr = menu_ptr[line].ptr; + str = menuptr[line].str; + type = menuptr[line].cfgtype; + ptr = menuptr[line].ptr; if(str == 0) { break; } if((type & 0xf) == CFGTYPE_DISK) { print_eject_help = 1; } - cfg_parse_menu(menu_ptr, line, menu_line, 0); + cfg_parse_menu(menuptr, line, menu_line, 0); if(line == menu_line) { if(type != 0) { match_found = 1; @@ -2447,6 +2932,11 @@ config_control_panel() menu_line = max_line; } + if(g_rom_version < 0) { + cfg_htab_vtab(0, 21); + cfg_printf("\bYOU MUST SELECT A VALID ROM FILE\b\n"); + } + cfg_htab_vtab(0, 23); cfg_printf("Move: \tJ\t \tK\t Change: \tH\t \tU\t \tM\t"); if(print_eject_help) { @@ -2501,17 +2991,17 @@ config_control_panel() } break; case 0x15: /* right arrow */ - cfg_parse_menu(menu_ptr, menu_line,menu_line,1); + cfg_parse_menu(menuptr, menu_line,menu_line,1); break; case 0x08: /* left arrow */ - cfg_parse_menu(menu_ptr,menu_line,menu_line,-1); + cfg_parse_menu(menuptr,menu_line,menu_line,-1); break; case 0x0d: - type = menu_ptr[menu_line].cfgtype; - ptr = menu_ptr[menu_line].ptr; + type = menuptr[menu_line].cfgtype; + ptr = menuptr[menu_line].ptr; switch(type & 0xf) { case CFGTYPE_MENU: - menu_ptr = (Cfg_menu *)ptr; + menuptr = (Cfg_menu *)ptr; menu_line = 1; break; case CFGTYPE_DISK: @@ -2522,6 +3012,11 @@ config_control_panel() fn_ptr = (void (*)())ptr; (*fn_ptr)(); break; + case CFGTYPE_FILE: + g_cfg_slotdrive = 0xfff; + g_cfg_file_def_name = *((char **)ptr); + g_cfg_file_strptr = (char **)ptr; + cfg_file_init(); } break; case 0x1b: @@ -2530,7 +3025,7 @@ config_control_panel() break; case 'e': case 'E': - type = menu_ptr[menu_line].cfgtype; + type = menuptr[menu_line].cfgtype; if((type & 0xf) == CFGTYPE_DISK) { eject_disk_by_num(type >> 12, (type >> 4) & 0xff); diff --git a/src/config.h b/src/config.h index 06106dc..9fa04fd 100644 --- a/src/config.h +++ b/src/config.h @@ -1,6 +1,6 @@ /************************************************************************/ /* KEGS: Apple //gs Emulator */ -/* Copyright 2003 by Kent Dickey */ +/* Copyright 2003-2004 by Kent Dickey */ /* */ /* This code is covered by the GNU GPL */ /* */ @@ -9,7 +9,7 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsid_config_h[] = "@(#)$KmKId: config.h,v 1.8 2003-10-17 15:09:58-04 kentd Exp $"; +const char rcsid_config_h[] = "@(#)$KmKId: config.h,v 1.9 2004-11-12 23:10:28-05 kentd Exp $"; #endif #define CONF_BUF_LEN 1024 @@ -24,6 +24,7 @@ const char rcsid_config_h[] = "@(#)$KmKId: config.h,v 1.8 2003-10-17 15:09:58-04 #define CFGTYPE_INT 2 #define CFGTYPE_DISK 3 #define CFGTYPE_FUNC 4 +#define CFGTYPE_FILE 5 /* CFGTYPE limited to just 4 bits: 0-15 */ /* Cfg_menu, Cfg_dirent and Cfg_listhdr are defined in defc.h */ @@ -31,4 +32,5 @@ const char rcsid_config_h[] = "@(#)$KmKId: config.h,v 1.8 2003-10-17 15:09:58-04 STRUCT(Cfg_defval) { Cfg_menu *menuptr; int intval; + char *strval; }; diff --git a/src/defc.h b/src/defc.h index 1596fe9..1afeb13 100644 --- a/src/defc.h +++ b/src/defc.h @@ -9,7 +9,7 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsid_defc_h[] = "@(#)$KmKId: defc.h,v 1.91 2003-11-03 01:29:38-05 kentd Exp $"; +const char rcsid_defc_h[] = "@(#)$KmKId: defc.h,v 1.100 2004-11-09 02:02:07-05 kentd Exp $"; #endif #include "defcomm.h" @@ -34,7 +34,10 @@ void U_STACK_TRACE(); #define DCYCS_1_MHZ ((DCYCS_28_MHZ/28.0)*(65.0*7/(65.0*7+1.0))) #define CYCS_1_MHZ ((int)DCYCS_1_MHZ) -#define DCYCS_IN_16MS_RAW (DCYCS_1_MHZ / 60.0) +/* #define DCYCS_IN_16MS_RAW (DCYCS_1_MHZ / 60.0) */ +#define DCYCS_IN_16MS_RAW (262.0 * 65.0) +/* Use precisely 17030 instead of forcing 60 Hz since this is the number of */ +/* 1MHz cycles per screen */ #define DCYCS_IN_16MS ((double)((int)DCYCS_IN_16MS_RAW)) #define DRECIP_DCYCS_IN_16MS (1.0 / (DCYCS_IN_16MS)) @@ -70,6 +73,7 @@ void U_STACK_TRACE(); #include #include #include +#include #ifdef HPUX # include /* for GET_ITIMER */ #endif @@ -93,6 +97,13 @@ STRUCT(Pc_log) { word32 pad; }; +STRUCT(Data_log) { + double dcycs; + word32 addr; + word32 val; + word32 size; +}; + STRUCT(Event) { double dcycs; int type; @@ -167,6 +178,21 @@ STRUCT(Cfg_listhdr) { int num_to_show; }; +STRUCT(Emustate_intlist) { + const char *str; + int *iptr; +}; + +STRUCT(Emustate_dbllist) { + const char *str; + double *dptr; +}; + +STRUCT(Emustate_word32list) { + const char *str; + word32 *wptr; +}; + #ifdef __LP64__ # define PTR2WORD(a) ((unsigned long)(a)) #else @@ -174,14 +200,38 @@ STRUCT(Cfg_listhdr) { #endif -#define ALTZP (statereg & 0x80) -#define PAGE2 (statereg & 0x40) -#define RAMRD (statereg & 0x20) -#define RAMWRT (statereg & 0x10) -#define RDROM (statereg & 0x08) -#define LCBANK2 (statereg & 0x04) -#define ROMB (statereg & 0x02) -#define INTCX (statereg & 0x01) +#define ALTZP (g_c068_statereg & 0x80) +/* #define PAGE2 (g_c068_statereg & 0x40) */ +#define RAMRD (g_c068_statereg & 0x20) +#define RAMWRT (g_c068_statereg & 0x10) +#define RDROM (g_c068_statereg & 0x08) +#define LCBANK2 (g_c068_statereg & 0x04) +#define ROMB (g_c068_statereg & 0x02) +#define INTCX (g_c068_statereg & 0x01) + +#define C041_EN_25SEC_INTS 0x10 +#define C041_EN_VBL_INTS 0x08 +#define C041_EN_SWITCH_INTS 0x04 +#define C041_EN_MOVE_INTS 0x02 +#define C041_EN_MOUSE 0x01 + +/* WARNING: SCC1 and SCC0 interrupts must be in this order for scc.c */ +/* This order matches the SCC hardware */ +#define IRQ_PENDING_SCC1_ZEROCNT 0x00001 +#define IRQ_PENDING_SCC1_TX 0x00002 +#define IRQ_PENDING_SCC1_RX 0x00004 +#define IRQ_PENDING_SCC0_ZEROCNT 0x00008 +#define IRQ_PENDING_SCC0_TX 0x00010 +#define IRQ_PENDING_SCC0_RX 0x00020 +#define IRQ_PENDING_C023_SCAN 0x00100 +#define IRQ_PENDING_C023_1SEC 0x00200 +#define IRQ_PENDING_C046_25SEC 0x00400 +#define IRQ_PENDING_C046_VBL 0x00800 +#define IRQ_PENDING_ADB_KBD_SRQ 0x01000 +#define IRQ_PENDING_ADB_DATA 0x02000 +#define IRQ_PENDING_ADB_MOUSE 0x04000 +#define IRQ_PENDING_DOC 0x08000 + #define EXTRU(val, pos, len) \ ( ( (len) >= (pos) + 1) ? ((val) >> (31-(pos))) : \ diff --git a/src/defcomm.h b/src/defcomm.h index 7de1042..68d8092 100644 --- a/src/defcomm.h +++ b/src/defcomm.h @@ -9,11 +9,9 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsdif_defcomm_h[] = "@(#)$KmKId: defcomm.h,v 1.93 2002-11-19 03:10:38-05 kadickey Exp $"; +const char rcsdif_defcomm_h[] = "@(#)$KmKId: defcomm.h,v 1.94 2004-10-13 21:53:44-04 kentd Exp $"; #endif -#define USE_XIMAGE_CHANGED - #if 0 # define CHECK_BREAKPOINTS #endif @@ -61,25 +59,6 @@ const char rcsdif_defcomm_h[] = "@(#)$KmKId: defcomm.h,v 1.93 2002-11-19 03:10:3 #define BANK_BAD_MEM (&g_dummy_memory1_ptr[0xff]) -#define LEN_FIFO_BUF 160 -#define LEN_KBD_BUF 160 - -#define FIFO_OK 0x1 -#define FIFO_INIT 0x2 -#define FIFO_END 0x3 -#define FIFO_40COLS 0x4 -#define FIFO_80COLS 0x5 -#define FIFO_SENDCHAR 0x6 -#define FIFO_SENDKEY 0x7 -#define FIFO_REFRESH 0x8 - -#define B_OP_SIZE 2 -#define B_OP_D_SIZE 5 -#define B_OP_DTYPE 12 -#define SIZE_OP_DTYPE 7 - - - #define ENGINE_FCYCLES 0x00 #define ENGINE_REG_KPC 0x08 #define ENGINE_REG_ACC 0x0c @@ -189,12 +168,3 @@ const char rcsdif_defcomm_h[] = "@(#)$KmKId: defcomm.h,v 1.93 2002-11-19 03:10:3 #define A2_BORDER_COLOR_NUM 0xfe -#if 0 -#define A2_TEXT_COLOR_ALT_NUM 0x01 -#define A2_BG_COLOR_ALT_NUM 0x00 -#define A2_TEXT_COLOR_PRIM_NUM 0x02 -#define A2_BG_COLOR_PRIM_NUM 0x00 -#define A2_TEXT_COLOR_FLASH_NUM 0x0c -#define A2_BG_COLOR_FLASH_NUM 0x08 -#endif - diff --git a/src/dis.c b/src/dis.c index 352f135..75b9a27 100644 --- a/src/dis.c +++ b/src/dis.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_dis_c[] = "@(#)$KmKId: dis.c,v 1.90 2003-11-18 17:35:30-05 kentd Exp $"; +const char rcsid_dis_c[] = "@(#)$KmKId: dis.c,v 1.103 2004-11-24 16:41:41-05 kentd Exp $"; #include #include "defc.h" @@ -20,19 +20,16 @@ const char rcsid_dis_c[] = "@(#)$KmKId: dis.c,v 1.90 2003-11-18 17:35:30-05 kent extern byte *g_memory_ptr; extern byte *g_slow_memory_ptr; -extern byte *g_rom_fc_ff_ptr; -extern byte *g_rom_cards_ptr; -extern word32 g_mem_size_base, g_mem_size_exp; extern int halt_sim; extern int enter_debug; -extern int statereg; +extern int g_c068_statereg; extern word32 stop_run_at; -extern int stop_on_c03x; extern int Verbose; extern int Halt_on; -extern int g_rom_version; extern int g_testing_enabled; +extern int g_fullscreen; +extern int g_config_control_panel; int g_num_breakpoints = 0; word32 g_breakpts[MAX_BREAK_POINTS]; @@ -48,8 +45,9 @@ int g_stepping = 0; word32 list_kpc; int hex_line_len; -word32 a1,a2,a3,a4; -int a1bank, a2bank, a3bank, a4bank; +word32 a1,a2,a3; +word32 g_a4, g_a4bank; +int a1bank, a2bank, a3bank; char *line_ptr; int mode,old_mode; int got_num; @@ -154,9 +152,11 @@ do_debug_intfc() int done; int ret_val; + g_config_control_panel = 1; + hex_line_len = 0x10; - a1 = 0; a2 = 0; a3 = 0; a4 = 0; - a1bank = 0; a2bank = 0; a3bank = 0; a4bank = 0; + a1 = 0; a2 = 0; a3 = 0; g_a4 = 0; + a1bank = 0; a2bank = 0; a3bank = 0; g_a4bank = 0; list_kpc = engine.kpc; g_stepping = 0; mode = 0; old_mode = 0; @@ -164,6 +164,8 @@ do_debug_intfc() stop_run_at = -1; x_auto_repeat_on(0); + g_fullscreen = 0; + x_full_screen(0); if(g_quit_sim_now) { printf("Exiting immediately\n"); @@ -229,10 +231,14 @@ do_debug_intfc() } break; case 'v': - video_show_debug_info(); + if(got_num) { + dis_do_compare(); + } else { + video_show_debug_info(); + } break; case 'V': - printf("g_irq_pending: %d\n", g_irq_pending); + printf("g_irq_pending: %05x\n", g_irq_pending); printf("Setting Verbose ^= %04x\n", a1); Verbose ^= a1; printf("Verbose is now: %04x\n", Verbose); @@ -256,8 +262,13 @@ do_debug_intfc() if(engine.psr & 0x100) { engine.psr |= 0x30; } + } else { + dis_do_memmove(); } break; + case 'p': + dis_do_pattern_search(); + break; case 'x': if(old_mode == '=') { if(!a1) { @@ -361,6 +372,10 @@ do_debug_intfc() } do_blank(); break; + case '<': + g_a4 = a2; + g_a4bank = a2bank; + break; case 0x05: /* ctrl-e */ show_regs(); break; @@ -383,10 +398,6 @@ do_debug_intfc() case 'w': read_line(w_buff, W_BUF_LEN); break; - case 'X': - stop_on_c03x = !stop_on_c03x; - printf("stop_on_c03x set to %d\n",stop_on_c03x); - break; default: printf("\nUnrecognized command: %s\n",linebuf); *line_ptr = 0; @@ -437,7 +448,7 @@ show_toolset_tables(word32 a2bank, word32 addr) addr = (a2bank << 16) + (addr & 0xffff); - toolfile = fopen("tool_set_info", "wt"); + toolfile = fopen("tool_set_info", "w"); if(toolfile == 0) { fprintf(stderr, "fopen of tool_set_info failed: %d\n", errno); exit(2); @@ -573,10 +584,14 @@ do_blank() void do_go() { + /* also called by do_step */ + + g_config_control_panel = 0; clear_halt(); run_prog(); show_regs(); + g_config_control_panel = 1; } void @@ -585,11 +600,8 @@ do_step() int size; int size_mem_imm, size_x_imm; - clear_halt(); + do_go(); - run_prog(); - - show_regs(); size_mem_imm = 2; if(engine.psr & 0x20) { size_mem_imm = 1; @@ -651,26 +663,59 @@ show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count) int read_line(char *buf, int len) { - int space_left; - int ret; + int space_left; + int ret; +#ifndef _WIN32 + int flags, flags_save; + /* Unix */ + flags = fcntl(0, F_GETFL, 0); + flags_save = flags; + if(flags == -1) { + return 0; + } + ret = fcntl(0, F_SETFL, flags | O_NONBLOCK); + if(ret == -1) { + return 0; + } +#endif space_left = len; - ret = 0; buf[0] = 0; + ret = 0; while(space_left > 0) { - ret = read(0,buf,1); +#ifdef _WIN32 + ret = win_nonblock_read_stdin(0, buf, 1); +#else + /* Unix */ + ret = read(0, buf, 1); +#endif if(ret <= 0) { - printf("read <= 0\n"); - return(len-space_left); + micro_sleep(15.0/60.0); + if(errno == EAGAIN) { + /* it would block, so no chars--do update */ + video_update(); + ret = 0; + continue; + } + printf("read ret %d, errno: %d\n", ret, errno); + if(errno == EAGAIN || errno == EINTR) { + ret = 0; + continue; + } + break; } space_left -= ret; if(buf[ret-1] == 0x0a) { - return(len-space_left); + break; } buf = &buf[ret]; } - return(len-space_left); +#ifndef _WIN32 + (void)fcntl(0, F_SETFL, flags_save); +#endif + + return (len-space_left); } void @@ -684,7 +729,7 @@ do_debug_list() list_kpc = (a2bank << 16) + (a2 & 0xffff); } printf("%d=m %d=x %d=LCBANK\n", (engine.psr >> 5)&1, - (engine.psr >> 4) & 1, (statereg & 0x4) >> 2); + (engine.psr >> 4) & 1, (g_c068_statereg & 0x4) >> 2); size_mem_imm = 2; if(engine.psr & 0x20) { @@ -701,242 +746,45 @@ do_debug_list() } } -const char *g_kegs_rom_names[] = { "ROM", "ROM.01", "ROM.03", 0 }; +void +dis_do_memmove() +{ + word32 val; -const char *g_kegs_c1rom_names[] = { 0 }; -const char *g_kegs_c2rom_names[] = { 0 }; -const char *g_kegs_c3rom_names[] = { 0 }; -const char *g_kegs_c4rom_names[] = { 0 }; -const char *g_kegs_c5rom_names[] = { 0 }; -const char *g_kegs_c6rom_names[] = { "c600.rom", "controller.rom", "disk.rom", - "DISK.ROM", "diskII.prom", 0 }; -const char *g_kegs_c7rom_names[] = { 0 }; - -const char **g_kegs_rom_card_list[8] = { - 0, g_kegs_c1rom_names, - g_kegs_c2rom_names, g_kegs_c3rom_names, - g_kegs_c4rom_names, g_kegs_c5rom_names, - g_kegs_c6rom_names, g_kegs_c7rom_names }; - -byte g_rom_c600_rom01_diffs[256] = { - 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xe2, 0x00, - 0xd0, 0x50, 0x0f, 0x77, 0x5b, 0xb9, 0xc3, 0xb1, - 0xb1, 0xf8, 0xcb, 0x4e, 0xb8, 0x60, 0xc7, 0x2e, - 0xfc, 0xe0, 0xbf, 0x1f, 0x66, 0x37, 0x4a, 0x70, - 0x55, 0x2c, 0x3c, 0xfc, 0xc2, 0xa5, 0x08, 0x29, - 0xac, 0x21, 0xcc, 0x09, 0x55, 0x03, 0x17, 0x35, - 0x4e, 0xe2, 0x0c, 0xe9, 0x3f, 0x9d, 0xc2, 0x06, - 0x18, 0x88, 0x0d, 0x58, 0x57, 0x6d, 0x83, 0x8c, - 0x22, 0xd3, 0x4f, 0x0a, 0xe5, 0xb7, 0x9f, 0x7d, - 0x2c, 0x3e, 0xae, 0x7f, 0x24, 0x78, 0xfd, 0xd0, - 0xb5, 0xd6, 0xe5, 0x26, 0x85, 0x3d, 0x8d, 0xc9, - 0x79, 0x0c, 0x75, 0xec, 0x98, 0xcc, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x39, 0x00, 0x35, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, - 0x6c, 0x44, 0xce, 0x4c, 0x01, 0x08, 0x00, 0x00 -}; + printf("Memory move from %02x/%04x.%04x to %02x/%04x\n", a1bank, a1, a2, g_a4bank, g_a4); + while(a1 <= (a2 & 0xffff)) { + val = get_memory_c((a1bank << 16) + a1, 0); + set_memory_c((g_a4bank << 16) + g_a4, val, 0); + a1++; + g_a4++; + } + a1 = a1 & 0xffff; + g_a4 = g_a4 & 0xffff; +} void -load_roms() +dis_do_pattern_search() { - char name_buf[256]; - struct stat stat_buf; - const char **names_ptr; - int more_than_8mb; - int changed_rom; - int len; - int fd; - int ret; - int i; + printf("Memory pattern search for %04x in %02x/%04x.%04x\n", g_a4, a1bank, a1, a2); +} - g_rom_version = 0; - setup_kegs_file(&name_buf[0], (int)sizeof(name_buf), 0, - &g_kegs_rom_names[0]); - fd = open(name_buf, O_RDONLY | O_BINARY); - if(fd < 0) { - printf("Open ROM file %s failed:%d, errno:%d\n", name_buf, fd, - errno); - my_exit(-3); - } +void +dis_do_compare() +{ + word32 val1, val2; - ret = fstat(fd, &stat_buf); - if(ret != 0) { - fprintf(stderr, "fstat returned %d on fd %d, errno: %d\n", - ret, fd, errno); - my_exit(2); - } - - len = stat_buf.st_size; - if(len == 128*1024) { - g_rom_version = 1; - g_mem_size_base = 256*1024; - ret = read(fd, &g_rom_fc_ff_ptr[2*65536], len); - } else if(len == 256*1024) { - g_rom_version = 3; - g_mem_size_base = 1024*1024; - ret = read(fd, &g_rom_fc_ff_ptr[0], len); - } else { - fprintf(stderr, "ROM size %d not 128K or 256K\n", len); - my_exit(4); - } - - printf("Read: %d bytes of ROM\n", ret); - if(ret != len) { - printf("errno: %d\n", errno); - my_exit(-3); - } - close(fd); - - memset(&g_rom_cards_ptr[0], 0, 256*16); - - /* initialize c600 rom to be diffs from the real ROM, to build-in */ - /* Apple II compatibility without distributing ROMs */ - for(i = 0; i < 256; i++) { - g_rom_cards_ptr[0x600 + i] = g_rom_fc_ff_ptr[0x3c600 + i] ^ - g_rom_c600_rom01_diffs[i]; - } - if(g_rom_version >= 3) { - /* some patches */ - g_rom_cards_ptr[0x61b] ^= 0x40; - g_rom_cards_ptr[0x61c] ^= 0x33; - g_rom_cards_ptr[0x632] ^= 0xc0; - g_rom_cards_ptr[0x633] ^= 0x33; - } - - for(i = 1; i < 8; i++) { - names_ptr = g_kegs_rom_card_list[i]; - if(names_ptr == 0) { - continue; - } - if(*names_ptr == 0) { - continue; - } - - setup_kegs_file(&name_buf[0], (int)sizeof(name_buf), 1, - names_ptr); - - if(name_buf[0] != 0) { - fd = open(name_buf, O_RDONLY | O_BINARY); - if(fd < 0) { - printf("Open card ROM file %s failed: %d " - "err:%d\n", name_buf, fd, errno); - my_exit(-3); - } - - len = 256; - ret = read(fd, &g_rom_cards_ptr[i*0x100], len); - - if(ret != len) { - printf("errno: %d, expected %d, got %d\n", - errno, len, ret); - my_exit(-3); - } - close(fd); + printf("Memory Compare from %02x/%04x.%04x with %02x/%04x\n", a1bank, a1, a2, g_a4bank, g_a4); + while(a1 <= (a2 & 0xffff)) { + val1 = get_memory_c((a1bank << 16) + a1, 0); + val2 = get_memory_c((g_a4bank << 16) + g_a4, 0); + if(val1 != val2) { + printf("%02x/%04x: %02x vs %02x\n", a1bank, a1, val1, val2); } + a1++; + g_a4++; } - - more_than_8mb = (g_mem_size_exp > 0x800000); - /* Only do the patch if users wants more than 8MB of expansion mem */ - - changed_rom = 0; - if(g_rom_version == 1) { - /* make some patches to ROM 01 */ -#if 0 - /* 1: Patch ROM selftest to not do speed test */ - printf("Patching out speed test failures from ROM 01\n"); - g_rom_fc_ff_ptr[0x3785a] = 0x18; - changed_rom = 1; -#endif - -#if 0 - /* 2: Patch ROM selftests not to do tests 2,4 */ - /* 0 = skip, 1 = do it, test 1 is bit 0 of LSByte */ - g_rom_fc_ff_ptr[0x371e9] = 0xf5; - g_rom_fc_ff_ptr[0x371ea] = 0xff; - changed_rom = 1; -#endif - - if(more_than_8mb) { - /* Geoff Weiss patch to use up to 14MB of RAM */ - g_rom_fc_ff_ptr[0x30302] = 0xdf; - g_rom_fc_ff_ptr[0x30314] = 0xdf; - g_rom_fc_ff_ptr[0x3031c] = 0x00; - changed_rom = 1; - } - - /* Patch ROM selftest to not do ROM cksum if any changes*/ - if(changed_rom) { - g_rom_fc_ff_ptr[0x37a06] = 0x18; - g_rom_fc_ff_ptr[0x37a07] = 0x18; - } - } else if(g_rom_version == 3) { - /* patch ROM 03 */ - printf("Patching ROM 03 smartport bug\n"); - /* 1: Patch Smartport code to fix a stupid bug */ - /* that causes it to write the IWM status reg into c036, */ - /* which is the system speed reg...it's "safe" since */ - /* IWM status reg bit 4 must be 0 (7MHz)..., otherwise */ - /* it might have turned on shadowing in all banks! */ - g_rom_fc_ff_ptr[0x357c9] = 0x00; - changed_rom = 1; - -#if 0 - /* patch ROM 03 to not to speed test */ - /* skip fast speed test */ - g_rom_fc_ff_ptr[0x36ad7] = 0x18; - g_rom_fc_ff_ptr[0x36ad8] = 0x18; - changed_rom = 1; -#endif - -#if 0 - /* skip slow speed test */ - g_rom_fc_ff_ptr[0x36ae7] = 0x18; - g_rom_fc_ff_ptr[0x36ae8] = 0x6b; - changed_rom = 1; -#endif - -#if 0 - /* 4: Patch ROM 03 selftests not to do tests 1-4 */ - g_rom_fc_ff_ptr[0x364a9] = 0xf0; - g_rom_fc_ff_ptr[0x364aa] = 0xff; - changed_rom = 1; -#endif - - /* ROM tests are in ff/6403-642x, where 6403 = addr of */ - /* test 1, etc. */ - - if(more_than_8mb) { - /* Geoff Weiss patch to use up to 14MB of RAM */ - g_rom_fc_ff_ptr[0x30b] = 0xdf; - g_rom_fc_ff_ptr[0x31d] = 0xdf; - g_rom_fc_ff_ptr[0x325] = 0x00; - changed_rom = 1; - } - - if(changed_rom) { - /* patch ROM 03 selftest to not do ROM cksum */ - g_rom_fc_ff_ptr[0x36cb0] = 0x18; - g_rom_fc_ff_ptr[0x36cb1] = 0x18; - } - - } + a1 = a1 & 0xffff; + g_a4 = g_a4 & 0xffff; } void diff --git a/src/engine_c.c b/src/engine_c.c index cbeedec..09a2f46 100644 --- a/src/engine_c.c +++ b/src/engine_c.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_engine_c_c[] = "@(#)$KmKId: engine_c.c,v 1.51 2004-01-10 15:50:15-05 kentd Exp $"; +const char rcsid_engine_c_c[] = "@(#)$KmKId: engine_c.c,v 1.57 2004-12-03 23:51:01-05 kentd Exp $"; #include "defc.h" #include "protos_engine_c.h" @@ -28,8 +28,10 @@ const char rcsid_engine_c_c[] = "@(#)$KmKId: engine_c.c,v 1.51 2004-01-10 15:50: extern int halt_sim; extern int g_code_red; extern int g_ignore_halts; +extern int g_user_halt_bad; extern double g_fcycles_stop; extern double g_last_vbl_dcycs; +extern double g_cur_dcycs; extern int g_wait_pending; extern int g_irq_pending; extern int g_testing; @@ -44,9 +46,13 @@ extern byte *g_dummy_memory1_ptr; extern int g_num_breakpoints; extern word32 g_breakpts[]; -extern Pc_log *log_pc_ptr; -extern Pc_log *log_pc_start_ptr; -extern Pc_log *log_pc_end_ptr; +extern Pc_log *g_log_pc_ptr; +extern Pc_log *g_log_pc_start_ptr; +extern Pc_log *g_log_pc_end_ptr; + +extern Data_log *g_log_data_ptr; +extern Data_log *g_log_data_start_ptr; +extern Data_log *g_log_data_end_ptr; int size_tab[] = { #include "size_c.h" @@ -75,8 +81,9 @@ int bogus[] = { #define FCYCLES_ROUND fcycles = (int)(fcycles + fplus_x_m1); -#define LOG_PC_MACRO() \ - tmp_pc_ptr = log_pc_ptr++; \ +#ifdef LOG_PC +# define LOG_PC_MACRO() \ + tmp_pc_ptr = g_log_pc_ptr++; \ tmp_pc_ptr->dbank_kpc = (dbank << 24) + kpc; \ tmp_pc_ptr->instr = (opcode << 24) + arg_ptr[1] + \ (arg_ptr[2] << 8) + (arg_ptr[3] << 16); \ @@ -85,11 +92,28 @@ int bogus[] = { tmp_pc_ptr->xreg_yreg = (xreg << 16) + yreg; \ tmp_pc_ptr->stack_direct = (stack << 16) + direct; \ tmp_pc_ptr->dcycs = fcycles + g_last_vbl_dcycs - fplus_2; \ - if(log_pc_ptr >= log_pc_end_ptr) { \ + if(g_log_pc_ptr >= g_log_pc_end_ptr) { \ /*halt2_printf("log_pc oflow %f\n", tmp_pc_ptr->dcycs);*/ \ - log_pc_ptr = log_pc_start_ptr; \ + g_log_pc_ptr = g_log_pc_start_ptr; \ } +# define LOG_DATA_MACRO(in_addr, in_val, in_size) \ + g_log_data_ptr->dcycs = fcycles + g_last_vbl_dcycs; \ + g_log_data_ptr->addr = in_addr; \ + g_log_data_ptr->val = in_val; \ + g_log_data_ptr->size = in_size; \ + g_log_data_ptr++; \ + if(g_log_data_ptr >= g_log_data_end_ptr) { \ + g_log_data_ptr = g_log_data_start_ptr; \ + } + +#else +# define LOG_PC_MACRO() +# define LOG_DATA_MACRO(addr, val, size) +/* Just do nothing */ +#endif + + #define GET_1BYTE_ARG arg = arg_ptr[1]; #define GET_2BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8); #define GET_3BYTE_ARG arg = arg_ptr[1] + (arg_ptr[2] << 8) + (arg_ptr[3]<<16); @@ -270,6 +294,7 @@ extern word32 slow_mem_changed[]; } #define SET_MEMORY8(addr, val) \ + LOG_DATA_MACRO(addr, val, 8); \ CYCLES_PLUS_1; \ stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ wstat = PTR2WORD(stat) & 0xff; \ @@ -284,17 +309,15 @@ extern word32 slow_mem_changed[]; } - - - #define SET_MEMORY16(addr, val, in_bank) \ + LOG_DATA_MACRO(addr, val, 16); \ stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ wstat = PTR2WORD(stat) & 0xff; \ ptr = stat - wstat + ((addr) & 0xff); \ - if((wstat) || (((addr) & 0xff) == 0xff)) { \ + if((wstat) || (((addr) & 0xff) == 0xff)) { \ fcycles_tmp1 = fcycles; \ set_memory16_pieces_stub((addr), (val), \ - &fcycles_tmp1, fplus_ptr, in_bank); \ + &fcycles_tmp1, fplus_1, fplus_x_m1, in_bank); \ fcycles = fcycles_tmp1; \ } else { \ CYCLES_PLUS_2; \ @@ -303,6 +326,7 @@ extern word32 slow_mem_changed[]; } #define SET_MEMORY24(addr, val, in_bank) \ + LOG_DATA_MACRO(addr, val, 24); \ stat = GET_PAGE_INFO_WR(((addr) >> 8) & 0xffff); \ wstat = PTR2WORD(stat) & 0xff; \ ptr = stat - wstat + ((addr) & 0xff); \ @@ -326,7 +350,7 @@ check_breakpoints(word32 addr) count = g_num_breakpoints; for(i = 0; i < count; i++) { - if(g_breakpts[i] == addr) { + if((g_breakpts[i] & 0xffffff) == addr) { halt2_printf("Hit breakpoint at %06x\n", addr); } } @@ -464,19 +488,15 @@ set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, void set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, - Fplus *fplus_ptr, int in_bank) + double fplus_1, double fplus_x_m1, int in_bank) { byte *ptr; byte *stat; double fcycles, fcycles_tmp1; - double fplus_1; - double fplus_x_m1; word32 addrp1; word32 wstat; fcycles = *fcycs_ptr; - fplus_1 = fplus_ptr->plus_1; - fplus_x_m1 = fplus_ptr->plus_x_minus_1; SET_MEMORY8(addr, val); addrp1 = addr + 1; if(in_bank) { @@ -536,14 +556,6 @@ get_memory_c(word32 addr, int cycs) GET_MEMORY8(addr, ret); return ret; } -#if 0 - stat = page_info[(addr>>8) & 0xffff].rd; - ptr = (byte *)((stat & 0xffffff00) | (addr & 0xff)); - if(stat & (1 << (31 -BANK_IO_BIT))) { - return get_memory_io(addr, &in_fcycles); - } - return *ptr; -#endif word32 get_memory16_c(word32 addr, int cycs) @@ -576,16 +588,27 @@ set_memory_c(word32 addr, word32 val, int cycs) double fplus_x_m1; word32 wstat; - fcycles = 0; + fcycles = g_cur_dcycs - g_last_vbl_dcycs; fplus_1 = 0; fplus_x_m1 = 0; SET_MEMORY8(addr, val); } + void set_memory16_c(word32 addr, word32 val, int cycs) { - set_memory_c(addr, val, 0); - set_memory_c(addr + 1, val >> 8, 0); + byte *stat; + byte *ptr; + double fcycles, fcycles_tmp1; + double fplus_1, fplus_2; + double fplus_x_m1; + word32 wstat; + + fcycles = g_cur_dcycs - g_last_vbl_dcycs; + fplus_1 = 0; + fplus_2 = 0; + fplus_x_m1 = 0; + SET_MEMORY16(addr, val, 0); } void @@ -706,10 +729,10 @@ fixed_memory_ptrs_init() /* set g_slow_memory_ptr, g_rom_fc_ff_ptr, g_dummy_memory1_ptr, */ /* and rom_cards_ptr */ - g_slow_memory_ptr = memalloc_align(128*1024, 0); - g_dummy_memory1_ptr = memalloc_align(256, 1024); - g_rom_fc_ff_ptr = memalloc_align(256*1024, 1024); - g_rom_cards_ptr = memalloc_align(16*256, 1024); + g_slow_memory_ptr = memalloc_align(128*1024, 0, 0); + g_dummy_memory1_ptr = memalloc_align(256, 1024, 0); + g_rom_fc_ff_ptr = memalloc_align(256*1024, 512, 0); + g_rom_cards_ptr = memalloc_align(16*256, 256, 0); #if 0 printf("g_memory_ptr: %08x, dummy_mem: %08x, slow_mem_ptr: %08x\n", @@ -757,7 +780,7 @@ get_itimer() void set_halt_act(int val) { - if(val == 1 && g_ignore_halts) { + if(val == 1 && g_ignore_halts && !g_user_halt_bad) { g_code_red++; } else { halt_sim |= val; @@ -938,9 +961,7 @@ recalc_accsize: FETCH_OPCODE; -#ifdef LOG_PC LOG_PC_MACRO(); -#endif switch(opcode) { default: @@ -957,9 +978,7 @@ recalc_accsize: } else { while(fcycles <= g_fcycles_stop) { FETCH_OPCODE; -#ifdef LOG_PC LOG_PC_MACRO(); -#endif switch(opcode) { default: diff --git a/src/instable.h b/src/instable.h index d350611..fbbd49e 100644 --- a/src/instable.h +++ b/src/instable.h @@ -10,7 +10,7 @@ #ifdef ASM # ifdef INCLUDE_RCSID_S - .stringz "@(#)$KmKId: instable.h,v 1.103 2004-01-10 15:50:50-05 kentd Exp $" + .stringz "@(#)$KmKId: instable.h,v 1.104 2004-10-05 20:12:08-04 kentd Exp $" # endif #endif @@ -2353,9 +2353,8 @@ instdb_SYM /* STP */ b dispatch_done depi RET_STP,3,4,ret0 #else - GET_1BYTE_ARG; - CYCLES_PLUS_1 - FINISH(RET_STP, arg); + CYCLES_FINISH + FINISH(RET_STP, 0); #endif instdc_SYM /* JML (Abs) */ diff --git a/src/iwm.c b/src/iwm.c index 0625d8a..8742978 100644 --- a/src/iwm.c +++ b/src/iwm.c @@ -8,14 +8,13 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_iwm_c[] = "@(#)$KmKId: iwm.c,v 1.111 2003-11-03 22:14:10-05 kentd Exp $"; +const char rcsid_iwm_c[] = "@(#)$KmKId: iwm.c,v 1.119 2004-11-21 17:44:14-05 kentd Exp $"; #include "defc.h" extern int Verbose; extern int g_vbl_count; -extern int speed_fast; -extern word32 g_slot_motor_detect; +extern int g_c036_val_speed; const byte phys_to_dos_sec[] = { 0x00, 0x07, 0x0e, 0x06, 0x0d, 0x05, 0x0c, 0x04, @@ -72,8 +71,8 @@ int from_disk_byte_valid = 0; Iwm iwm; -int g_apple35_sel = 0; -int head_35 = 0; +extern int g_c031_disk35; + int g_iwm_motor_on = 0; int g_check_nibblization = 0; @@ -87,11 +86,6 @@ void iwm_write_data_525(Disk *dsk, word32 val, int fast_disk_emul,double dcycs); void iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525) { - int num_tracks; - int i; - - num_tracks = MAX_TRACKS; - dsk->dcycs_last_read = 0.0; dsk->name_ptr = 0; dsk->partition_name = 0; @@ -113,15 +107,31 @@ iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525) dsk->last_phase = 0; dsk->nib_pos = 0; dsk->num_tracks = 0; + dsk->trks = 0; + +} + +void +disk_set_num_tracks(Disk *dsk, int num_tracks) +{ + int i; + + if(dsk->trks != 0) { + /* This should not be necessary! */ + free(dsk->trks); + halt_printf("Needed to free dsk->trks: %p\n", dsk->trks); + } + dsk->num_tracks = num_tracks; + dsk->trks = (Trk *)malloc(num_tracks * sizeof(Trk)); for(i = 0; i < num_tracks; i++) { - dsk->tracks[i].dsk = dsk; - dsk->tracks[i].nib_area = 0; - dsk->tracks[i].track_dirty = 0; - dsk->tracks[i].overflow_size = 0; - dsk->tracks[i].track_len = 0; - dsk->tracks[i].unix_pos = -1; - dsk->tracks[i].unix_len = -1; + dsk->trks[i].dsk = dsk; + dsk->trks[i].nib_area = 0; + dsk->trks[i].track_dirty = 0; + dsk->trks[i].overflow_size = 0; + dsk->trks[i].track_len = 0; + dsk->trks[i].unix_pos = -1; + dsk->trks[i].unix_len = -1; } } @@ -179,21 +189,23 @@ iwm_reset() iwm.previous_write_bits = 0; g_iwm_motor_on = 0; - g_apple35_sel = 0; + g_c031_disk35 = 0; } void draw_iwm_status(int line, char *buf) { char *flag[2][2]; + int apple35_sel; flag[0][0] = " "; flag[0][1] = " "; flag[1][0] = " "; flag[1][1] = " "; + apple35_sel = (g_c031_disk35 >> 6) & 1; if(g_iwm_motor_on) { - flag[g_apple35_sel][iwm.drive_select] = "*"; + flag[apple35_sel][iwm.drive_select] = "*"; } sprintf(buf, "s6d1:%2d%s s6d2:%2d%s s5d1:%2d/%d%s " @@ -204,12 +216,12 @@ draw_iwm_status(int line, char *buf) iwm.drive35[0].cur_qtr_track & 1, flag[1][0], iwm.drive35[1].cur_qtr_track >> 1, iwm.drive35[1].cur_qtr_track & 1, flag[1][1], - g_fast_disk_emul, g_slow_525_emul_wr, - (speed_fast << 7) + g_slot_motor_detect); + g_fast_disk_emul, g_slow_525_emul_wr, g_c036_val_speed); video_update_status_line(line, buf); } + void iwm_flush_disk_to_unix(Disk *dsk) { @@ -253,8 +265,8 @@ iwm_flush_disk_to_unix(Disk *dsk) num_dirty++; /* Write it out */ - unix_pos = dsk->tracks[j].unix_pos; - unix_len = dsk->tracks[j].unix_len; + unix_pos = dsk->trks[j].unix_pos; + unix_len = dsk->trks[j].unix_len; if(unix_pos < 0 || unix_len < 0x1000) { halt_printf("Disk:%s trk:%d, unix_pos:%08x, len:%08x\n", dsk->name_ptr, j, unix_pos, unix_len); @@ -303,7 +315,7 @@ iwm_vbl_update(int doit_3_persec) } motor_on = iwm.motor_on; - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { motor_on = iwm.motor_on35; } @@ -327,11 +339,11 @@ iwm_show_stats() { printf("IWM stats: q7,q6: %d, %d, reset,enable2: %d,%d, mode: %02x\n", iwm.q7, iwm.q6, iwm.reset, iwm.enable2, iwm.iwm_mode); - printf("motor: %d,%d, motor35:%d drive: %d, on: %d, head35: %d " + printf("motor: %d,%d, motor35:%d drive: %d, c031:%02x " "phs: %d %d %d %d\n", iwm.motor_on, iwm.motor_off, g_iwm_motor_on, - iwm.drive_select, g_apple35_sel, - head_35, iwm.iwm_phase[0], iwm.iwm_phase[1], iwm.iwm_phase[2], + iwm.drive_select, g_c031_disk35, + iwm.iwm_phase[0], iwm.iwm_phase[1], iwm.iwm_phase[2], iwm.iwm_phase[3]); printf("iwm.drive525[0].fd: %d, [1].fd: %d\n", iwm.drive525[0].fd, iwm.drive525[1].fd); @@ -355,7 +367,7 @@ iwm_touch_switches(int loc, double dcycs) on = loc & 1; drive = iwm.drive_select; phase = loc >> 1; - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { dsk = &(iwm.drive35[drive]); } else { dsk = &(iwm.drive525[drive]); @@ -366,9 +378,12 @@ iwm_touch_switches(int loc, double dcycs) /* phase adjustments. See if motor is on */ iwm.iwm_phase[phase] = on; + iwm_printf("Iwm phase %d=%d, all phases: %d %d %d %d (%f)\n", + phase, on, iwm.iwm_phase[0], iwm.iwm_phase[1], + iwm.iwm_phase[2], iwm.iwm_phase[3], dcycs); if(iwm.motor_on) { - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { if(phase == 3 && on) { iwm_do_action35(dcycs); } @@ -527,7 +542,7 @@ iwm525_phase_change(int drive, int phase) last_phase = 0; } if(qtr_track > 4*34) { - printf("Disk arm moved past track 0x21, moving it back\n"); + printf("Disk arm moved past track 34, moving it back\n"); qtr_track = 4*34; last_phase = 0; } @@ -536,9 +551,9 @@ iwm525_phase_change(int drive, int phase) dsk->last_phase = last_phase; - iwm_printf("Moving drive to qtr track: %04x, %d, %d, %d, " - "%d %d %d %d\n", - qtr_track, phase, delta, last_phase, iwm.iwm_phase[0], + iwm_printf("Moving drive to qtr track: %04x (trk:%d.%02d), %d, %d, %d, " + "%d %d %d %d\n", qtr_track, qtr_track>>2, 25*(qtr_track & 3), + phase, delta, last_phase, iwm.iwm_phase[0], iwm.iwm_phase[1], iwm.iwm_phase[2], iwm.iwm_phase[3]); /* sanity check stepping algorithm */ @@ -564,7 +579,7 @@ iwm_read_status35(double dcycs) if(iwm.motor_on) { /* Read status */ state = (iwm.iwm_phase[1] << 3) + (iwm.iwm_phase[0] << 2) + - (head_35 << 1) + iwm.iwm_phase[2]; + ((g_c031_disk35 >> 6) & 2) + iwm.iwm_phase[2]; iwm_printf("Iwm status read state: %02x\n", state); @@ -666,7 +681,7 @@ iwm_do_action35(double dcycs) if(iwm.motor_on) { /* Perform action */ state = (iwm.iwm_phase[1] << 3) + (iwm.iwm_phase[0] << 2) + - (head_35 << 1) + iwm.iwm_phase[2]; + ((g_c031_disk35 >> 6) & 2) + iwm.iwm_phase[2]; switch(state) { case 0x00: /* Set step direction inward */ /* towards higher tracks */ @@ -715,17 +730,6 @@ iwm_do_action35(double dcycs) } } -void -iwm_set_apple35_sel(int newval) -{ - if(g_apple35_sel != newval) { - /* Handle speed changes */ - set_halt(HALT_EVENT); - } - - g_apple35_sel = newval; -} - int iwm_read_c0ec(double dcycs) { @@ -736,7 +740,7 @@ iwm_read_c0ec(double dcycs) if(iwm.q7 == 0 && iwm.enable2 == 0 && iwm.motor_on) { drive = iwm.drive_select; - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { dsk = &(iwm.drive35[drive]); return iwm_read_data_35(dsk, g_fast_disk_emul, dcycs); } else { @@ -773,7 +777,7 @@ read_iwm(int loc, double dcycs) state = (iwm.q7 << 1) + iwm.q6; drive = iwm.drive_select; - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { dsk = &(iwm.drive35[drive]); } else { dsk = &(iwm.drive525[drive]); @@ -806,7 +810,7 @@ read_iwm(int loc, double dcycs) iwm_printf("Read status under enable2: 1\n"); status = 1; } else { - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { status = iwm_read_status35(dcycs); } else { status = dsk->write_prot; @@ -868,7 +872,7 @@ write_iwm(int loc, int val, double dcycs) state = (iwm.q7 << 1) + iwm.q6; drive = iwm.drive_select; fast_writes = g_fast_disk_emul; - if(g_apple35_sel) { + if(g_c031_disk35 & 0x40) { dsk = &(iwm.drive35[drive]); } else { dsk = &(iwm.drive525[drive]); @@ -899,8 +903,11 @@ write_iwm(int loc, int val, double dcycs) if(iwm.enable2) { iwm_write_enable2(val, dcycs); } else { +#if 0 +// Flobynoid writes to 0xc0e9 causing these messages... printf("Write iwm1, st: %02x, loc: %x: %02x\n", state, loc, val); +#endif } } return; @@ -915,10 +922,7 @@ write_iwm(int loc, int val, double dcycs) return; } - halt_printf("Got to end of write_iwm, loc:%02x, val: %02x\n", loc, val); - return; - } @@ -1064,7 +1068,7 @@ disk_unnib_4x4(Disk *dsk) } int -iwm_denib_track525(Disk *dsk, Track *trk, int qtr_track, byte *outbuf) +iwm_denib_track525(Disk *dsk, Trk *trk, int qtr_track, byte *outbuf) { byte aux_buf[0x80]; byte *buf; @@ -1274,7 +1278,7 @@ iwm_denib_track525(Disk *dsk, Track *trk, int qtr_track, byte *outbuf) } int -iwm_denib_track35(Disk *dsk, Track *trk, int qtr_track, byte *outbuf) +iwm_denib_track35(Disk *dsk, Trk *trk, int qtr_track, byte *outbuf) { word32 buf_c00[0x100]; word32 buf_d00[0x100]; @@ -1601,17 +1605,14 @@ iwm_denib_track35(Disk *dsk, Track *trk, int qtr_track, byte *outbuf) int disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf) { - Track *trk; + Trk *trk; int disk_525; disk_525 = dsk->disk_525; - trk = &(dsk->tracks[qtr_track]); + trk = &(dsk->trks[qtr_track]); if(trk->track_len == 0 || trk->track_dirty == 0) { -#if 0 - printf("disk_track_to_unix: dirty: %d\n", trk->track_dirty); -#endif return 0; } @@ -1652,7 +1653,7 @@ void disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size) { byte buffer[0x3000]; - Track *trk; + Trk *trk; int ret, ret2; int i; @@ -1665,7 +1666,7 @@ disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size) buffer[i] = 0; } - trk = &(dsk->tracks[qtr_track]); + trk = &(dsk->trks[qtr_track]); if(dsk->disk_525) { ret = iwm_denib_track525(dsk, trk, qtr_track, &(buffer[0])); @@ -1688,7 +1689,7 @@ disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size) ret, ret2, qtr_track); show_hex_data(buf, 0x1000); show_hex_data(buffer, 0x1000); - iwm_show_a_track(&(dsk->tracks[qtr_track])); + iwm_show_a_track(&(dsk->trks[qtr_track])); exit(2); } @@ -1702,7 +1703,7 @@ disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, int nib_len) { byte track_buf[TRACK_BUF_LEN]; - Track *trk; + Trk *trk; int must_clear_track; int ret; int len; @@ -1763,7 +1764,7 @@ disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, dsk->nib_pos = 0; /* for consistency */ - trk = &(dsk->tracks[qtr_track]); + trk = &(dsk->trks[qtr_track]); trk->track_dirty = 0; trk->overflow_size = 0; trk->track_len = 2*nib_len; @@ -1784,7 +1785,7 @@ disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, } void -iwm_nibblize_track_nib525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) +iwm_nibblize_track_nib525(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track) { byte *nib_ptr; byte *trk_ptr; @@ -1803,7 +1804,7 @@ iwm_nibblize_track_nib525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) } void -iwm_nibblize_track_525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) +iwm_nibblize_track_525(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track) { byte partial_nib_buf[0x300]; word32 *word_ptr; @@ -1895,7 +1896,7 @@ iwm_nibblize_track_525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) } void -iwm_nibblize_track_35(Disk *dsk, Track *trk, byte *track_buf, int qtr_track) +iwm_nibblize_track_35(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track) { int phys_to_log_sec[16]; word32 buf_c00[0x100]; @@ -2150,7 +2151,7 @@ disk_4x4_nib_out(Disk *dsk, word32 val) void disk_nib_out(Disk *dsk, byte val, int size) { - Track *trk; + Trk *trk; int pos; int old_size; int track_len; @@ -2160,9 +2161,12 @@ disk_nib_out(Disk *dsk, byte val, int size) qtr_track = dsk->cur_qtr_track; - trk = &(dsk->tracks[qtr_track]); - - track_len = trk->track_len; + track_len = 0; + trk = 0; + if(dsk->trks != 0) { + trk = &(dsk->trks[qtr_track]); + track_len = trk->track_len; + } if(track_len <= 10) { printf("Writing to an invalid qtr track: %02x!\n", qtr_track); @@ -2234,7 +2238,7 @@ disk_nib_end_track(Disk *dsk) dsk->nib_pos = 0; qtr_track = dsk->cur_qtr_track; - dsk->tracks[qtr_track].track_dirty = 0; + dsk->trks[qtr_track].track_dirty = 0; dsk->disk_dirty = 0; } @@ -2243,14 +2247,14 @@ void iwm_show_track(int slot_drive, int track) { Disk *dsk; - Track *trk; + Trk *trk; int drive; int sel35; int qtr_track; if(slot_drive < 0) { drive = iwm.drive_select; - sel35 = g_apple35_sel; + sel35 = (g_c031_disk35 >> 6) & 1; } else { drive = slot_drive & 1; sel35 = !((slot_drive >> 1) & 1); @@ -2267,22 +2271,25 @@ iwm_show_track(int slot_drive, int track) } else { qtr_track = track; } - trk = &(dsk->tracks[qtr_track]); + if(dsk->trks == 0) { + return; + } + trk = &(dsk->trks[qtr_track]); if(trk->track_len <= 0) { printf("Track_len: %d\n", trk->track_len); - printf("No track for type: %d, drive: %d, qtrk: %02x\n", - g_apple35_sel, drive, qtr_track); + printf("No track for type: %d, drive: %d, qtrk: 0x%02x\n", + sel35, drive, qtr_track); return; } - printf("Current drive: %d, q_track: %02x\n", drive, qtr_track); + printf("Current drive: %d, q_track: 0x%02x\n", drive, qtr_track); iwm_show_a_track(trk); } void -iwm_show_a_track(Track *trk) +iwm_show_a_track(Trk *trk) { int sum; int len; diff --git a/src/iwm.h b/src/iwm.h index e9a6587..1bff6bf 100644 --- a/src/iwm.h +++ b/src/iwm.h @@ -9,7 +9,7 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsid_iwm_h[] = "@(#)$KmKId: iwm.h,v 1.13 2003-07-08 23:29:48-04 kentd Exp $"; +const char rcsid_iwm_h[] = "@(#)$KmKId: iwm.h,v 1.14 2004-10-20 17:29:38-04 kentd Exp $"; #endif #define MAX_TRACKS (2*80) @@ -24,7 +24,7 @@ const char rcsid_iwm_h[] = "@(#)$KmKId: iwm.h,v 1.13 2003-07-08 23:29:48-04 kent typedef struct _Disk Disk; -STRUCT(Track) { +STRUCT(Trk) { Disk *dsk; byte *nib_area; int track_dirty; @@ -56,7 +56,7 @@ struct _Disk { int last_phase; int nib_pos; int num_tracks; - Track tracks[MAX_TRACKS]; + Trk *trks; }; diff --git a/src/iwm_35_525.h b/src/iwm_35_525.h index 2604c42..10b6fda 100644 --- a/src/iwm_35_525.h +++ b/src/iwm_35_525.h @@ -1,12 +1,12 @@ #ifdef INCLUDE_IWM_RCSID_C -const char rcsdif_iwm_35_525_h[] = "@(#)$KmKId: iwm_35_525.h,v 1.9 2002-11-14 01:03:16-05 kadickey Exp $"; +const char rcsdif_iwm_35_525_h[] = "@(#)$KmKId: iwm_35_525.h,v 1.14 2004-12-01 19:45:02-05 kentd Exp $"; #endif int IWM_READ_ROUT (Disk *dsk, int fast_disk_emul, double dcycs) { - Track *trk; + Trk *trk; double dcycs_last_read; int pos; int pos2; @@ -30,12 +30,28 @@ IWM_READ_ROUT (Disk *dsk, int fast_disk_emul, double dcycs) qtr_track = dsk->cur_qtr_track; - trk = &(dsk->tracks[qtr_track]); - track_len = trk->track_len; +#if IWM_DISK_525 + qtr_track = qtr_track & -4; /* round to nearest whole trk! */ +#endif + + trk = 0; + track_len = 0; + if(dsk->trks) { + trk = &(dsk->trks[qtr_track]); + track_len = trk->track_len; + } dcycs_last_read = dsk->dcycs_last_read; dcycs_passed = dcycs - dcycs_last_read; + cycs_passed = (int)dcycs_passed; + + if(track_len == 0) { + ret = (cycs_passed & 0x7f) + 0x80; + iwm_printf("Reading c0ec, track_len 0, returning %02x\n", ret); + return ret; + } + pos = dsk->nib_pos; if(pos >= track_len) { /* Arm may have moved from inner 3.5 track to outer one, */ @@ -43,11 +59,6 @@ IWM_READ_ROUT (Disk *dsk, int fast_disk_emul, double dcycs) pos = 0; } - cycs_passed = (int)dcycs_passed; - - if(track_len == 0) { - return (cycs_passed & 0x7f) + 0x80; - } size = trk->nib_area[pos]; while(size == 0) { @@ -207,9 +218,9 @@ IWM_WRITE_ROUT (Disk *dsk, word32 val, int fast_disk_emul, double dcycs) int sdiff; int prev_bits; - if(dsk->fd < 0) { + if(dsk->fd < 0 || dsk->trks == 0) { halt_printf("Tried to write to type: %d, drive: %d, fd: %d!\n", - IWM_DISK_525, dsk->drive, dsk->fd); + IWM_DISK_525, dsk->drive, dsk->fd, dsk->trks); return; } diff --git a/src/joystick_driver.c b/src/joystick_driver.c index 35c106f..53f64e2 100644 --- a/src/joystick_driver.c +++ b/src/joystick_driver.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_joystick_driver_c[] = "@(#)$KmKId: joystick_driver.c,v 1.7 2002-11-19 03:09:59-05 kadickey Exp $"; +const char rcsid_joystick_driver_c[] = "@(#)$KmKId: joystick_driver.c,v 1.12 2004-10-17 21:28:48-04 kentd Exp $"; #include "defc.h" #include @@ -22,20 +22,23 @@ const char rcsid_joystick_driver_c[] = "@(#)$KmKId: joystick_driver.c,v 1.7 2002 # include #endif -extern int g_joystick_type; /* in paddles.c */ -extern int g_paddle_button[]; +extern int g_joystick_native_type1; /* in paddles.c */ +extern int g_joystick_native_type2; /* in paddles.c */ +extern int g_joystick_native_type; /* in paddles.c */ +extern int g_paddle_buttons; extern int g_paddle_val[]; const char *g_joystick_dev = "/dev/js0"; /* default joystick dev file */ #define MAX_JOY_NAME 128 -int g_joystick_fd = -1; +int g_joystick_native_fd = -1; int g_joystick_num_axes = 0; int g_joystick_num_buttons = 0; #ifdef __linux__ +# define JOYSTICK_DEFINED void joystick_init() { @@ -64,22 +67,24 @@ joystick_init() joy_name, g_joystick_num_axes, g_joystick_num_buttons, version); - g_joystick_type = JOYSTICK_LINUX; - g_joystick_fd = fd; + g_joystick_native_type1 = 1; + g_joystick_native_type2 = -1; + g_joystick_native_fd = fd; for(i = 0; i < 4; i++) { - g_paddle_val[i] = 280; - g_paddle_button[i] = 1; + g_paddle_val[i] = 32767; } + g_paddle_buttons = 0xc; - joystick_update(); + joystick_update(0.0); } /* joystick_update_linux() called from paddles.c. Update g_paddle_val[] */ -/* and g_paddle_button[] arrays with current information */ +/* and g_paddle_buttons with current information */ void -joystick_update() +joystick_update(double dcycs) { struct js_event js; /* the linux joystick event record */ + int mask; int val; int num; int type; @@ -90,35 +95,42 @@ joystick_update() /* suck up to 20 events, then give up */ len = sizeof(struct js_event); for(i = 0; i < 20; i++) { - ret = read(g_joystick_fd, &js, len); + ret = read(g_joystick_native_fd, &js, len); if(ret != len) { /* just get out */ - return; + break; } type = js.type & ~JS_EVENT_INIT; val = js.value; num = js.number & 3; /* clamp to 0-3 */ switch(type) { case JS_EVENT_BUTTON: - g_paddle_button[num] = val; + mask = 1 << num; + if(val) { + val = mask; + } + g_paddle_buttons = (g_paddle_buttons & ~mask) | val; break; case JS_EVENT_AXIS: - /* val is -32767 to +32767, convert to 0->280 */ - /* want just 255, but go a little over for robustness*/ - g_paddle_val[num] = ((val + 32767) * 9) >> 11; + /* val is -32767 to +32767 */ + g_paddle_val[num] = val; break; } } + + if(i > 0) { + paddle_update_trigger_dcycs(dcycs); + } } void -joystick_update_button() +joystick_update_buttons() { } +#endif /* LINUX */ -#else /* !__linux__ */ - -# ifdef _WIN32 +#ifdef _WIN32 +# define JOYSTICK_DEFINED void joystick_init() { @@ -129,99 +141,120 @@ joystick_init() // Check that there is a joystick device if(joyGetNumDevs() <= 0) { - printf("--No joystick hardware detected\n"); + printf("No joystick hardware detected\n"); + g_joystick_native_type1 = -1; + g_joystick_native_type2 = -1; return; } + g_joystick_native_type1 = -1; + g_joystick_native_type2 = -1; + // Check that at least joystick 1 or joystick 2 is available ret1 = joyGetPos(JOYSTICKID1, &info); ret2 = joyGetDevCaps(JOYSTICKID1, &joycap, sizeof(joycap)); if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { - g_joystick_type = JOYSTICK_WIN32_1; - printf("--Joystick #1 = %s\n", joycap.szPname); - } else { - ret1 = joyGetPos(JOYSTICKID2, &info); - ret2 = joyGetDevCaps(JOYSTICKID2, &joycap, sizeof(joycap)); - if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { - g_joystick_type = JOYSTICK_WIN32_2; - printf("--Joystick #2 = %s\n", joycap.szPname); - } else { - printf("No joysticks found...\n"); - g_joystick_type = JOYSTICK_MOUSE; - return; + g_joystick_native_type1 = JOYSTICKID1; + printf("Joystick #1 = %s\n", joycap.szPname); + g_joystick_native_type = JOYSTICKID1; + } + ret1 = joyGetPos(JOYSTICKID2, &info); + ret2 = joyGetDevCaps(JOYSTICKID2, &joycap, sizeof(joycap)); + if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { + g_joystick_native_type2 = JOYSTICKID2; + printf("Joystick #2 = %s\n", joycap.szPname); + if(g_joystick_native_type < 0) { + g_joystick_native_type = JOYSTICKID2; } - } for(i = 0; i < 4; i++) { - g_paddle_val[i] = 280; - g_paddle_button[i] = 1; + g_paddle_val[i] = 32767; } + g_paddle_buttons = 0xc; - joystick_update(); + joystick_update(0.0); } void -joystick_update() +joystick_update(double dcycs) { JOYCAPS joycap; JOYINFO info; UINT id; MMRESULT ret1, ret2; - id = JOYSTICKID1; - if(g_joystick_type == JOYSTICK_WIN32_2) { - id = JOYSTICKID2; - } + id = g_joystick_native_type; ret1 = joyGetDevCaps(id, &joycap, sizeof(joycap)); ret2 = joyGetPos(id, &info); if(ret1 == JOYERR_NOERROR && ret2 == JOYERR_NOERROR) { - g_paddle_val[0] = (info.wXpos - joycap.wXmin) * 280 / + g_paddle_val[0] = (info.wXpos - joycap.wXmin) * 32768 / (joycap.wXmax - joycap.wXmin); - g_paddle_val[1] = (info.wYpos - joycap.wYmin) * 280 / + g_paddle_val[1] = (info.wYpos - joycap.wYmin) * 32768 / (joycap.wYmax - joycap.wYmin); - g_paddle_button[0] = ((info.wButtons & JOY_BUTTON1) ? 1 : 0); - g_paddle_button[1] = ((info.wButtons & JOY_BUTTON2) ? 1 : 0); + if(info.wButtons & JOY_BUTTON1) { + g_paddle_buttons = g_paddle_buttons | 1; + } else { + g_paddle_buttons = g_paddle_buttons & (~1); + } + if(info.wButtons & JOY_BUTTON2) { + g_paddle_buttons = g_paddle_buttons | 2; + } else { + g_paddle_buttons = g_paddle_buttons & (~2); + } + paddle_update_trigger_dcycs(dcycs); } } void -joystick_update_button() +joystick_update_buttons() { JOYINFOEX info; UINT id; - id = JOYSTICKID1; - if(g_joystick_type == JOYSTICK_WIN32_2) { - id = JOYSTICKID2; - } + id = g_joystick_native_type; info.dwSize = sizeof(JOYINFOEX); info.dwFlags = JOY_RETURNBUTTONS; if(joyGetPosEx(id, &info) == JOYERR_NOERROR) { - g_paddle_button[0] = ((info.dwButtons & JOY_BUTTON1) ? 1 : 0); - g_paddle_button[1] = ((info.dwButtons & JOY_BUTTON2) ? 1 : 0); + if(info.dwButtons & JOY_BUTTON1) { + g_paddle_buttons = g_paddle_buttons | 1; + } else { + g_paddle_buttons = g_paddle_buttons & (~1); + } + if(info.dwButtons & JOY_BUTTON2) { + g_paddle_buttons = g_paddle_buttons | 2; + } else { + g_paddle_buttons = g_paddle_buttons & (~2); + } } } -# else +#endif +#ifndef JOYSTICK_DEFINED /* stubs for the routines */ void joystick_init() { - printf("No joy with joystick\n"); + g_joystick_native_type1 = -1; + g_joystick_native_type2 = -1; + g_joystick_native_type = -1; } void -joystick_update() +joystick_update(double dcycs) { + int i; + + for(i = 0; i < 4; i++) { + g_paddle_val[i] = 32767; + } + g_paddle_buttons = 0xc; } void -joystick_update_button() +joystick_update_buttons() { } - -# endif /* !WIN32 */ #endif diff --git a/src/macdriver.c b/src/macdriver.c index bc113f4..6084a84 100644 --- a/src/macdriver.c +++ b/src/macdriver.c @@ -1,6 +1,6 @@ /************************************************************************/ /* KEGS: Apple //gs Emulator */ -/* Copyright 2002 by Kent Dickey */ +/* Copyright 2002-2004 by Kent Dickey */ /* */ /* This code is covered by the GNU GPL */ /* */ @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_macdriver_c[] = "@(#)$KmKId: macdriver.c,v 1.19 2004-03-23 17:27:56-05 kentd Exp $"; +const char rcsid_macdriver_c[] = "@(#)$KmKId: macdriver.c,v 1.24 2004-11-14 10:23:29-05 kentd Exp $"; // Quartz: CreateCGContextForPort vs QDBeginCGContext @@ -16,6 +16,7 @@ const char rcsid_macdriver_c[] = "@(#)$KmKId: macdriver.c,v 1.19 2004-03-23 17:2 // Use CGPointMake to get a point #include +#include #include "defc.h" #include "protos_macdriver.h" @@ -25,6 +26,9 @@ const char rcsid_macdriver_c[] = "@(#)$KmKId: macdriver.c,v 1.19 2004-03-23 17:2 #define MAX_MAC_ARGS 128 WindowRef g_main_window; +WindowRef g_main_window_saved; +Rect g_main_window_saved_rect; +Ptr g_mac_fullscreen_state = 0; int g_quit_seen = 0; EventHandlerUPP g_quit_handler_UPP; EventHandlerUPP g_dummy_event_handler_UPP; @@ -32,6 +36,7 @@ RgnHandle g_event_rgnhandle = 0; int g_ignore_next_click = 0; int g_mainwin_active = 0; GDHandle g_gdhandle = 0; + int g_mac_mouse_x = 0; int g_mac_mouse_y = 0; @@ -43,6 +48,8 @@ int g_mac_argc = 0; char *g_mac_argv[MAX_MAC_ARGS]; word32 g_mac_shift_control_state = 0; extern char g_argv0_path[]; +extern char *g_fatal_log_strs[]; +extern int g_fatal_log; extern word32 g_red_mask; extern word32 g_green_mask; @@ -68,6 +75,13 @@ extern int g_send_sound_to_file; extern int g_quit_sim_now; extern int g_config_control_panel; +extern int g_video_act_width; +extern int g_video_act_height; +extern int g_video_act_margin_left; +extern int g_video_act_margin_right; +extern int g_video_act_margin_top; +extern int g_video_act_margin_bottom; + int g_auto_repeat_on = -1; int g_x_shift_control_state = 0; @@ -99,8 +113,7 @@ extern char *g_status_ptrs[MAX_STATUS_LINES]; extern const char g_kegs_version_str[]; #if 0 -char g_printf_buf[4096]; -int g_debug_file_fd = -1; +extern int g_debug_file_fd; /* HACK to debug startup issues when launched from Finder */ int @@ -110,7 +123,6 @@ printf(const char *fmt, ...) int ret; va_start(ap, fmt); - ret = vsnprintf(g_printf_buf, 4090, fmt, ap); if(g_debug_file_fd < 0) { g_debug_file_fd = open("/tmp/kegs.out", @@ -118,8 +130,7 @@ printf(const char *fmt, ...) fprintf(stdout, "g_debug_file_fd = %d, %d\n", g_debug_file_fd, errno); } - write(1, g_printf_buf, strlen(g_printf_buf)); - write(g_debug_file_fd, g_printf_buf, strlen(g_printf_buf)); + ret = kegs_vprintf(fmt, ap); va_end(ap); @@ -140,27 +151,103 @@ quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore) } void -show_alert(const char *str1, const char *str2, const char *str3, int num) +show_simple_alert(char *str1, char *str2, char *str3, int num) { char buf[256]; - DialogRef alert; - DialogItemIndex out_item_hit; - CFStringRef cfstrref; + g_fatal_log_strs[0] = kegs_malloc_str(str1); + g_fatal_log_strs[1] = kegs_malloc_str(str2); + g_fatal_log_strs[2] = kegs_malloc_str(str3); + g_fatal_log = 3; if(num != 0) { - snprintf(buf, 250, "%s%s%s: %d", str1, str2, str3, num); - } else { - snprintf(buf, 250, "%s%s%s", str1, str2, str3); + snprintf(buf, 250, ": %d", num); + g_fatal_log_strs[g_fatal_log++] = kegs_malloc_str(buf); } - - cfstrref = CFStringCreateWithCString(NULL, buf, - kCFStringEncodingMacRoman); - - CreateStandardAlert(kAlertStopAlert, cfstrref, CFSTR("Click OK"), - NULL, &alert); - RunStandardAlert(alert, NULL, &out_item_hit); + x_show_alert(0, 0); } +void +x_dialog_create_kegs_conf(const char *str) +{ + char *path; + char tmp_buf[512]; + int ret; + + ret = x_show_alert(1, str); + if(ret) { + // Create empty file + path = "~/Library/KEGS"; + snprintf(tmp_buf, 500, "mkdir -p %s", path); + system(tmp_buf); + snprintf(tmp_buf, 500, "touch %s/%s", path, str); + system(tmp_buf); + } +} + +int +x_show_alert(int is_fatal, const char *str) +{ + DialogRef alert; + DialogItemIndex out_item_hit; + CFStringRef cfstrref, cfstrref2; + CFStringRef okstrref; + AlertStdCFStringAlertParamRec alert_param; + OSStatus osstat; + char *bufptr, *buf2ptr; + int sum, len; + int i; + + /* The dialog eats all events--including key-up events */ + /* Call adb_all_keys_up() to prevent annoying key-repeat problems */ + /* for instance, a key-down causes a dialog to appear--and the */ + /* eats the key-up event...then as soon as the dialog goes, adb.c */ + /* auto-repeat will repeat the key, and the dialog re-appears...*/ + adb_all_keys_up(); + + sum = 20; + for(i = 0; i < g_fatal_log; i++) { + sum += strlen(g_fatal_log_strs[i]); + } + bufptr = malloc(sum); + buf2ptr = bufptr; + for(i = 0; i < g_fatal_log; i++) { + len = strlen(g_fatal_log_strs[i]); + len = MIN(len, sum); + len = MAX(len, 0); + memcpy(bufptr, g_fatal_log_strs[i], MIN(len, sum)); + bufptr += len; + bufptr[0] = 0; + sum = sum - len; + } + + cfstrref = CFStringCreateWithCString(NULL, buf2ptr, + kCFStringEncodingMacRoman); + + printf("buf2ptr: :%s:\n", buf2ptr); + + osstat = GetStandardAlertDefaultParams(&alert_param, + kStdCFStringAlertVersionOne); + + if(str) { + // Provide an extra option--create a file + cfstrref2 = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, + CFSTR("Create ~/Library/KEGS/%s"), str); + alert_param.otherText = cfstrref2; + } + okstrref = CFSTR("Click OK to continue"); + if(is_fatal) { + okstrref = CFSTR("Clock OK to exit KEGS"); + } + CreateStandardAlert(kAlertStopAlert, cfstrref, okstrref, + &alert_param, &alert); + out_item_hit = -1; + RunStandardAlert(alert, NULL, &out_item_hit); + printf("out_item_hit: %d\n", out_item_hit); + free(buf2ptr); + + clear_fatal_logs(); /* free the fatal_log string memory */ + return (out_item_hit >= 3); +} pascal OSStatus @@ -182,13 +269,13 @@ my_cmd_handler( EventHandlerCallRef handlerRef, EventRef event, void *userdata) osresult = noErr; break; case 'abou': - show_alert("KEGSMAC v", g_kegs_version_str, + show_simple_alert("KEGSMAC v", (char *)g_kegs_version_str, ", Copyright 2004 Kent Dickey\n" "Latest version at http://kegs.sourceforge.net/\n", 0); osresult = noErr; break; case 'KCFG': - g_config_control_panel = !g_config_control_panel; + cfg_toggle_config_panel(); osresult = noErr; break; case 'quit': @@ -386,7 +473,7 @@ check_input_events() break; } if(err != noErr) { - printf("err: %d\n", (int)err); + printf("ReceiveNextEvent err: %d\n", (int)err); break; } @@ -488,8 +575,10 @@ check_input_events() } mac_warp_mouse(); } else { - g_mac_mouse_x = mouse_point.h -BASE_MARGIN_LEFT; - g_mac_mouse_y = mouse_point.v -BASE_MARGIN_TOP; + g_mac_mouse_x = mouse_point.h - + g_video_act_margin_left; + g_mac_mouse_y = mouse_point.v - + g_video_act_margin_top; } #if 0 @@ -723,6 +812,8 @@ main(int argc, char* argv[]) } // show_alert("About to show window", (int)g_main_window); + update_main_window_size(); + update_window(); // The window was created hidden so show it. @@ -742,7 +833,7 @@ main(int argc, char* argv[]) CantCreateWindow: CantSetMenuBar: CantGetNibRef: - show_alert("ending", "", "error code", err); + show_simple_alert("ending", "", "error code", err); return err; } @@ -773,6 +864,9 @@ xdriver_end() { printf("xdriver_end\n"); + if(g_fatal_log >= 0) { + x_show_alert(1, 0); + } } void @@ -932,6 +1026,12 @@ x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, void x_push_done() { + CGrafPtr window_port; + + SetPortWindowPort(g_main_window); + window_port = GetWindowPort(g_main_window); + + QDFlushPortBuffer(window_port, 0); } void @@ -953,3 +1053,73 @@ x_hide_pointer(int do_hide) ShowCursor(); } } + +void +x_full_screen(int do_full) +{ + WindowRef new_window; + short width, height; + OSErr ret; + + width = 640; + height = 480; + if(do_full && (g_mac_fullscreen_state == 0)) { + g_main_window_saved = g_main_window; + + GetWindowBounds(g_main_window, kWindowContentRgn, + &g_main_window_saved_rect); + ret = BeginFullScreen(&g_mac_fullscreen_state, 0, + &width, &height, &new_window, 0, 0); + printf("Ret beginfullscreen: %d\n", (int)ret); + printf("New width: %d, new height: %d\n", width, height); + if(ret == noErr) { + g_main_window = new_window; + } else { + g_mac_fullscreen_state = 0; + } + } else if(!do_full && (g_mac_fullscreen_state != 0)) { + ret = EndFullScreen(g_mac_fullscreen_state, 0); + printf("ret endfullscreen: %d\n", (int)ret); + g_main_window = g_main_window_saved; + g_mac_fullscreen_state = 0; + //InitCursor(); + SetWindowBounds(g_main_window, kWindowContentRgn, + &g_main_window_saved_rect); + } + + update_main_window_size(); + + ShowWindow(g_main_window); + BringToFront(g_main_window); + update_window(); +} + +void +update_main_window_size() +{ + Rect win_rect; + int width, height; + int left, excess_height; + int top, bottom; + + GetPortBounds(GetWindowPort(g_main_window), &win_rect); + width = win_rect.right - win_rect.left; + height = win_rect.bottom - win_rect.top; + g_video_act_width = width; + g_video_act_height = height; + + left = MAX(0, (width - A2_WINDOW_WIDTH) / 2); + left = MIN(left, BASE_MARGIN_LEFT); + g_video_act_margin_left = left; + g_video_act_margin_right = left; + + + excess_height = (height - A2_WINDOW_HEIGHT) / 2; + bottom = MAX(0, excess_height / 2); // No less than 0 + bottom = MIN(BASE_MARGIN_BOTTOM, bottom); // No more than 30 + g_video_act_margin_bottom = bottom; + excess_height -= bottom; + top = MAX(0, excess_height); + top = MIN(BASE_MARGIN_TOP, top); + g_video_act_margin_top = top; +} diff --git a/src/moremem.c b/src/moremem.c index 30425e7..d4235f8 100644 --- a/src/moremem.c +++ b/src/moremem.c @@ -8,12 +8,10 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_moremem_c[] = "@(#)$KmKId: moremem.c,v 1.233 2004-03-23 17:27:14-05 kentd Exp $"; +const char rcsid_moremem_c[] = "@(#)$KmKId: moremem.c,v 1.251 2004-11-19 01:55:50-05 kentd Exp $"; #include "defc.h" -extern int daylight; - extern char g_kegs_version_str[]; extern byte *g_memory_ptr; @@ -21,34 +19,46 @@ extern byte *g_dummy_memory1_ptr; extern byte *g_slow_memory_ptr; extern byte *g_rom_fc_ff_ptr; extern byte *g_rom_cards_ptr; -extern word32 g_mem_size_total; extern word32 slow_mem_changed[]; extern int g_num_breakpoints; extern word32 g_breakpts[]; -extern int halt_sim; -extern double g_last_vbl_dcycs; - extern Page_info page_info_rd_wr[]; -extern int scr_mode; - extern int Verbose; -extern int Halt_on; -extern double g_paddle_trig_dcycs; extern int g_rom_version; +extern int g_user_page2_shadow; -extern int g_paddle_button[4]; - -extern Fplus *g_cur_fplus_ptr; /* from iwm.c */ -extern int head_35; -extern int g_apple35_sel; -extern int cur_drive; +int g_num_shadow_all_banks = 0; +#define IOR(val) ( (val) ? 0x80 : 0x00 ) + + +extern int g_cur_a2_stat; + +int g_em_emubyte_cnt = 0; +int g_paddle_buttons = 0; +int g_irq_pending = 0; + +int g_c023_val = 0; +int g_c029_val_some = 0x41; +int g_c02b_val = 0x08; +int g_c02d_int_crom = 0; +int g_c031_disk35 = 0; +int g_c033_data = 0; +int g_c034_val = 0; +int g_c035_shadow_reg = 0x08; +int g_c036_val_speed = 0x80; +int g_c03ef_doc_ptr = 0; +int g_c041_val = 0; /* C041_EN_25SEC_INTS, C041_EN_MOVE_INTS */ +int g_c046_val = 0; +int g_c05x_annuncs = 0; +int g_c068_statereg = 0; +int g_c08x_wrdefram = 0; int g_zipgs_unlock = 0; int g_zipgs_reg_c059 = 0x5f; // 7=LC cache dis, 6==5ms paddle del en, 5==5ms ext del en, @@ -63,62 +73,52 @@ int g_zipgs_reg_c05b = 0x40; int g_zipgs_reg_c05c = 0x00; // 7:1==slot delay enable (for 52-54ms), 0==speaker 5ms delay -int g_emubyte_cnt = 0; +#define EMUSTATE(a) { #a, &a } -int statereg; -int halt_on_c02a = 0; -int g_shadow_all_banks = 0; -int g_num_shadow_all_banks = 0; +Emustate_intlist g_emustate_intlist[] = { + EMUSTATE(g_cur_a2_stat), + EMUSTATE(g_paddle_buttons), -extern Engine_reg engine; + EMUSTATE(g_em_emubyte_cnt), + EMUSTATE(g_irq_pending), + EMUSTATE(g_c023_val), + EMUSTATE(g_c029_val_some), + EMUSTATE(g_c02b_val), + EMUSTATE(g_c02d_int_crom), + EMUSTATE(g_c031_disk35), + EMUSTATE(g_c033_data), + EMUSTATE(g_c034_val), + EMUSTATE(g_c035_shadow_reg), + EMUSTATE(g_c036_val_speed), + EMUSTATE(g_c03ef_doc_ptr), + EMUSTATE(g_c041_val), + EMUSTATE(g_c046_val), + EMUSTATE(g_c05x_annuncs), + EMUSTATE(g_c068_statereg), + EMUSTATE(g_c08x_wrdefram), + EMUSTATE(g_zipgs_unlock), + EMUSTATE(g_zipgs_reg_c059), + EMUSTATE(g_zipgs_reg_c05a), + EMUSTATE(g_zipgs_reg_c05b), + EMUSTATE(g_zipgs_reg_c05c), + { 0, 0, } +}; -#define IOR(val) ( (val) ? 0x80 : 0x00 ) +extern double g_paddle_trig_dcycs; +extern double g_last_vbl_dcycs; -int linear_vid = 1; -int bank1latch = 0; +Emustate_dbllist g_emustate_dbllist[] = { + EMUSTATE(g_paddle_trig_dcycs), + EMUSTATE(g_last_vbl_dcycs), + { 0, 0, } +}; -int wrdefram = 0; -int int_crom[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +extern word32 g_mem_size_total; -extern int g_cur_a2_stat; - -int annunc_0 = 0; -int annunc_1 = 0; -int annunc_2 = 0; - -int shadow_reg = 0x08; - -int stop_on_c03x = 0; - -extern int doc_ptr; - -int shadow_text = 1; - -int g_border_color = 0; - -int speed_fast = 1; -word32 g_slot_motor_detect = 0; -int power_on_clear = 0; - - -int g_c023_val = 0; -int c023_scan_int_irq_pending = 0; -int c023_1sec_int_irq_pending = 0; - -int c02b_val = 0x08; - -int c039_write_val = 0; - -int c041_en_25sec_ints = 0; -int c041_en_vbl_ints = 0; -int c041_en_switch_ints = 0; -int c041_en_move_ints = 0; -int c041_en_mouse = 0; - -int g_c046_val = 0; - -int c046_25sec_irq_pend = 0; -int c046_vbl_irq_pending = 0; +Emustate_word32list g_emustate_word32list[] = { + EMUSTATE(g_mem_size_total), + { 0, 0, } +}; #define UNIMPL_READ \ @@ -135,15 +135,19 @@ fixup_brks() word32 page; word32 tmp, tmp2; Pg_info val; + int is_wr_only; int i, num; num = g_num_breakpoints; for(i = 0; i < num; i++) { page = (g_breakpts[i] >> 8) & 0xffff; - val = GET_PAGE_INFO_RD(page); - tmp = PTR2WORD(val) & 0xff; - tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; - SET_PAGE_INFO_RD(page, val - tmp + tmp2); + is_wr_only = (g_breakpts[i] >> 24) & 1; + if(!is_wr_only) { + val = GET_PAGE_INFO_RD(page); + tmp = PTR2WORD(val) & 0xff; + tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; + SET_PAGE_INFO_RD(page, val - tmp + tmp2); + } val = GET_PAGE_INFO_WR(page); tmp = PTR2WORD(val) & 0xff; tmp2 = tmp | BANK_IO_TMP | BANK_BREAK; @@ -171,13 +175,14 @@ fixup_bank0_2000_4000() mem0rd = &(g_memory_ptr[0x2000]); mem0wr = mem0rd; if((g_cur_a2_stat & ALL_STAT_ST80) && (g_cur_a2_stat & ALL_STAT_HIRES)){ - if(PAGE2) { + if(g_cur_a2_stat & ALL_STAT_PAGE2) { mem0rd += 0x10000; mem0wr += 0x10000; - if((shadow_reg & 0x12) == 0 || (shadow_reg & 0x8) == 0){ + if((g_c035_shadow_reg & 0x12) == 0 || + (g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } - } else if((shadow_reg & 0x02) == 0) { + } else if((g_c035_shadow_reg & 0x02) == 0) { mem0wr += BANK_SHADOW; } @@ -187,10 +192,11 @@ fixup_bank0_2000_4000() } if(RAMWRT) { mem0wr += 0x10000; - if((shadow_reg & 0x12) == 0 || (shadow_reg & 0x8) == 0){ + if((g_c035_shadow_reg & 0x12) == 0 || + (g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } - } else if((shadow_reg & 0x02) == 0) { + } else if((g_c035_shadow_reg & 0x02) == 0) { mem0wr += BANK_SHADOW; } } @@ -209,7 +215,7 @@ fixup_bank0_0400_0800() mem0wr = mem0rd; shadow = BANK_SHADOW; if(g_cur_a2_stat & ALL_STAT_ST80) { - if(PAGE2) { + if(g_cur_a2_stat & ALL_STAT_PAGE2) { shadow = BANK_SHADOW2; mem0rd += 0x10000; mem0wr += 0x10000; @@ -223,7 +229,7 @@ fixup_bank0_0400_0800() mem0rd += 0x10000; } } - if((shadow_reg & 0x01) == 0) { + if((g_c035_shadow_reg & 0x01) == 0) { mem0wr += shadow; } @@ -256,12 +262,12 @@ fixup_intcx() int no_io_shadow; int off; int start_k; - int indx; + word32 mask; int j, k; rom10000 = &(g_rom_fc_ff_ptr[0x30000]); - no_io_shadow = (shadow_reg & 0x40); + no_io_shadow = (g_c035_shadow_reg & 0x40); start_k = 0; if(no_io_shadow) { @@ -280,10 +286,10 @@ fixup_intcx() SET_PAGE_INFO_RD(0xc0 + off, SET_BANK_IO); for(j = 0xc1; j < 0xc8; j++) { - indx = j & 0xf; + mask = 1 << (j & 0xf); if(j < 0xc8) { rom_inc = SET_BANK_IO; - if((int_crom[indx] == 0) || INTCX) { + if(((g_c02d_int_crom & mask) == 0) || INTCX) { rom_inc = rom10000 + (j << 8); } else { // User-slot rom @@ -295,7 +301,7 @@ fixup_intcx() } for(j = 0xc8; j < 0xd0; j++) { /* c800 - cfff */ - if(int_crom[3] == 0 || INTCX) { + if(((g_c02d_int_crom & (1 << 3)) == 0) || INTCX) { rom_inc = rom10000 + (j << 8); } else { /* c800 space not necessarily mapped */ @@ -323,9 +329,9 @@ fixup_wrdefram(int new_wrdefram) byte *wrptr; int j; - wrdefram = new_wrdefram; + g_c08x_wrdefram = new_wrdefram; - if(shadow_reg & 0x40) { + if(g_c035_shadow_reg & 0x40) { /* do nothing */ return; } @@ -390,7 +396,7 @@ fixup_st80col(double dcycs) fixup_bank0_2000_4000(); } - if(PAGE2) { + if(cur_a2_stat & ALL_STAT_PAGE2) { change_display_mode(dcycs); } @@ -401,6 +407,7 @@ void fixup_altzp() { byte *mem0rd, *mem0wr; + int rdrom, c08x_wrdefram; int altzp; altzp = ALTZP; @@ -415,15 +422,19 @@ fixup_altzp() mem0rd = &(g_memory_ptr[0xd000]); mem0wr = mem0rd; + c08x_wrdefram = g_c08x_wrdefram; + rdrom = RDROM; - if(shadow_reg & 0x40) { + if(g_c035_shadow_reg & 0x40) { if(ALTZP) { mem0rd += 0x10000; } fixup_any_bank_any_page(0xd0, 0x10, mem0rd - 0x1000, mem0rd - 0x1000); + c08x_wrdefram = 1; + rdrom = 0; } else { - if(!wrdefram) { + if(!c08x_wrdefram) { mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); } if(ALTZP) { @@ -434,7 +445,7 @@ fixup_altzp() mem0rd -= 0x1000; mem0wr -= 0x1000; } - if(RDROM) { + if(rdrom) { mem0rd = &(g_rom_fc_ff_ptr[0x3d000]); } fixup_any_bank_any_page(0xd0, 0x10, mem0rd, mem0wr); @@ -442,17 +453,19 @@ fixup_altzp() mem0rd = &(g_memory_ptr[0xe000]); mem0wr = mem0rd; - if(!wrdefram) { + if(!c08x_wrdefram) { mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); } if(ALTZP) { mem0rd += 0x10000; mem0wr += 0x10000; } - if(RDROM) { + if(rdrom) { mem0rd = &(g_rom_fc_ff_ptr[0x3e000]); } fixup_any_bank_any_page(0xe0, 0x20, mem0rd, mem0wr); + + /* No need for fixup_brks since called from set_statereg() */ } void @@ -500,6 +513,8 @@ fixup_ramrd() for(j = 0x40; j < 0xc0; j++) { SET_PAGE_INFO_RD(j, mem0rd + j*0x100); } + + /* No need for fixup_brks since only called from set_statereg() */ } void @@ -534,7 +549,8 @@ fixup_ramwrt() if(ramwrt) { shadow = BANK_SHADOW2; } - if(((shadow_reg & 0x20) != 0) || g_rom_version < 3) { + if( ((g_c035_shadow_reg & 0x20) != 0) || + ((g_rom_version < 3) && !g_user_page2_shadow)) { shadow = 0; } for(j = 8; j < 0x0c; j++) { @@ -547,10 +563,11 @@ fixup_ramwrt() shadow = 0; if(ramwrt) { - if((shadow_reg & 0x14) == 0 || (shadow_reg & 0x08) == 0) { + if((g_c035_shadow_reg & 0x14) == 0 || + (g_c035_shadow_reg & 0x08) == 0) { shadow = BANK_SHADOW2; } - } else if((shadow_reg & 0x04) == 0) { + } else if((g_c035_shadow_reg & 0x04) == 0) { shadow = BANK_SHADOW; } for(j = 0x40; j < 0x60; j++) { @@ -558,7 +575,7 @@ fixup_ramwrt() } shadow = 0; - if(ramwrt && (shadow_reg & 0x08) == 0) { + if(ramwrt && (g_c035_shadow_reg & 0x08) == 0) { /* shr shadowing */ shadow = BANK_SHADOW2; } @@ -569,12 +586,15 @@ fixup_ramwrt() for(j = 0xa0; j < 0xc0; j++) { SET_PAGE_INFO_WR(j, mem0wr + j*0x100); } + + /* No need for fixup_brks() since only called from set_statereg() */ } void fixup_lcbank2() { byte *mem0rd, *mem0wr; + int lcbank2, c08x_wrdefram, rdrom; int off; int k; @@ -593,19 +613,30 @@ fixup_lcbank2() if((k == 0) && ALTZP) { mem0rd += 0x10000; } - if(! LCBANK2) { + lcbank2 = LCBANK2; + c08x_wrdefram = g_c08x_wrdefram; + rdrom = RDROM; + if((k < 2) && (g_c035_shadow_reg & 0x40)) { + lcbank2 = 0; + c08x_wrdefram = 1; + rdrom = 0; + } + if(! lcbank2) { mem0rd -= 0x1000; /* lcbank1, use 0xc000-cfff */ } mem0wr = mem0rd; - if((k < 2) && !wrdefram) { + if((k < 2) && !c08x_wrdefram) { mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); } - if((k < 2) && RDROM) { + if((k < 2) && rdrom) { mem0rd = &(g_rom_fc_ff_ptr[0x30000]); } fixup_any_bank_any_page(off*0x100 + 0xd0, 0x10, mem0rd + 0xd000, mem0wr + 0xd000); } + + /* No need for fixup_brks() since only called from set_statereg(), */ + /* or from other routines which will handle it */ } void @@ -623,7 +654,7 @@ fixup_rdrom() if((k == 0) && ALTZP) { mem0rd += 0x10000; } - if((shadow_reg & 0x40) == 0) { + if((g_c035_shadow_reg & 0x40) == 0) { if(RDROM) { mem0rd = &(g_rom_fc_ff_ptr[0x30000]); } @@ -633,6 +664,7 @@ fixup_rdrom() } } + /* No need for fixup_brks() since only called from set_statereg() */ } void @@ -640,8 +672,8 @@ set_statereg(double dcycs, int val) { int xor; - xor = val ^ statereg; - statereg = val; + xor = val ^ g_c068_statereg; + g_c068_statereg = val; if(xor == 0) { return; } @@ -652,6 +684,8 @@ set_statereg(double dcycs, int val) } if(xor & 0x40) { /* page2 */ + g_cur_a2_stat = (g_cur_a2_stat & ~ALL_STAT_PAGE2) | + (val & ALL_STAT_PAGE2); fixup_page2(dcycs); } @@ -698,7 +732,7 @@ fixup_shadow_txt1() fixup_bank0_0400_0800(); mem0wr = &(g_memory_ptr[0x10000]); - if((shadow_reg & 0x01) == 0) { + if((g_c035_shadow_reg & 0x01) == 0) { mem0wr += BANK_SHADOW2; } for(j = 4; j < 8; j++) { @@ -720,7 +754,8 @@ fixup_shadow_txt2() mem0wr += 0x10000; shadow = BANK_SHADOW2; } - if(((shadow_reg & 0x20) == 0) && (g_rom_version >= 3)) { + if(((g_c035_shadow_reg & 0x20) == 0) && + ((g_rom_version >= 3) || g_user_page2_shadow)) { mem0wr += shadow; } for(j = 8; j < 0xc; j++) { @@ -729,7 +764,8 @@ fixup_shadow_txt2() /* and bank 1 */ mem0wr = &(g_memory_ptr[0x10000]); - if(((shadow_reg & 0x20) == 0) && (g_rom_version >= 3)) { + if(((g_c035_shadow_reg & 0x20) == 0) && + ((g_rom_version >= 3) || g_user_page2_shadow)) { mem0wr += BANK_SHADOW2; } for(j = 8; j < 0xc; j++) { @@ -747,7 +783,7 @@ fixup_shadow_hires1() /* and bank 1 */ mem0wr = &(g_memory_ptr[0x10000]); - if((shadow_reg & 0x12) == 0 || (shadow_reg & 0x8) == 0) { + if((g_c035_shadow_reg & 0x12) == 0 || (g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } for(j = 0x20; j < 0x40; j++) { @@ -765,10 +801,11 @@ fixup_shadow_hires2() mem0wr = &(g_memory_ptr[0x00000]); if(RAMWRT) { mem0wr += 0x10000; - if((shadow_reg & 0x14) == 0 || (shadow_reg & 0x8) == 0) { + if((g_c035_shadow_reg & 0x14) == 0 || + (g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } - } else if((shadow_reg & 0x04) == 0) { + } else if((g_c035_shadow_reg & 0x04) == 0) { mem0wr += BANK_SHADOW; } for(j = 0x40; j < 0x60; j++) { @@ -777,7 +814,7 @@ fixup_shadow_hires2() /* and bank 1 */ mem0wr = &(g_memory_ptr[0x10000]); - if((shadow_reg & 0x14) == 0 || (shadow_reg & 0x8) == 0) { + if((g_c035_shadow_reg & 0x14) == 0 || (g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } for(j = 0x40; j < 0x60; j++) { @@ -795,7 +832,7 @@ fixup_shadow_shr() mem0wr = &(g_memory_ptr[0x00000]); if(RAMWRT) { mem0wr += 0x10000; - if((shadow_reg & 0x8) == 0) { + if((g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } } @@ -805,7 +842,7 @@ fixup_shadow_shr() /* and bank 1, only pages 0x60 - 0xa0 */ mem0wr = &(g_memory_ptr[0x10000]); - if((shadow_reg & 0x8) == 0) { + if((g_c035_shadow_reg & 0x8) == 0) { mem0wr += BANK_SHADOW2; } for(j = 0x60; j < 0xa0; j++) { @@ -816,12 +853,13 @@ fixup_shadow_shr() void fixup_shadow_iolc() { - byte *mem0rd, *mem0wr; + byte *mem0rd; int k; - for(k = 0; k < 2; k++) { - mem0rd = &(g_memory_ptr[k << 16]); - if(shadow_reg & 0x40) { + if(g_c035_shadow_reg & 0x40) { + /* Disable language card area */ + for(k = 0; k < 2; k++) { + mem0rd = &(g_memory_ptr[k << 16]); fixup_any_bank_any_page((k << 8) + 0xc0, 0x10, mem0rd + 0xd000, mem0rd + 0xd000); if(k == 0 && ALTZP) { @@ -831,26 +869,19 @@ fixup_shadow_iolc() mem0rd + 0xc000, mem0rd + 0xc000); fixup_any_bank_any_page((k << 8) + 0xe0, 0x20, mem0rd + 0xe000, mem0rd + 0xe000); - } else { - /* 0xc000 area */ - fixup_intcx(); - - /* 0xd000 area */ - fixup_lcbank2(); - - if(k == 0 && ALTZP) { - mem0rd += 0x10000; - } - mem0wr = mem0rd; - if(!wrdefram) { - mem0wr += (BANK_IO_TMP | BANK_IO2_TMP); - } - if(RDROM) { - mem0rd = &(g_rom_fc_ff_ptr[0x30000]); - } - fixup_any_bank_any_page((k << 8) + 0xe0, 0x20, - mem0rd + 0xe000, mem0wr + 0xe000); } + } else { + /* 0xc000 area */ + fixup_intcx(); + + /* 0xd000 area */ + /* fixup_lcbank2(); -- not needed since fixup_rdrom does it */ + + /* Fix 0xd000-0xffff for reads, banks 0 and 1 */ + fixup_rdrom(); /* which calls fixup_lcbank2 */ + + /* Fix 0xd000-0xffff for writes, banks 0 and 1 */ + fixup_wrdefram(g_c08x_wrdefram); } } @@ -859,12 +890,12 @@ update_shadow_reg(int val) { int xor; - if(shadow_reg == val) { + if(g_c035_shadow_reg == val) { return; } - xor = shadow_reg ^ val; - shadow_reg = val; + xor = g_c035_shadow_reg ^ val; + g_c035_shadow_reg = val; if(xor & 8) { fixup_shadow_hires1(); @@ -886,12 +917,15 @@ update_shadow_reg(int val) if(xor & 1) { fixup_shadow_txt1(); } - if((xor & 0x20) && g_rom_version >= 3) { + if((xor & 0x20) && ((g_rom_version >= 3) || g_user_page2_shadow)) { fixup_shadow_txt2(); } if(xor & 0x40) { fixup_shadow_iolc(); } + if(xor) { + fixup_brks(); + } } void @@ -906,7 +940,7 @@ fixup_shadow_all_banks() /* only do banks 3 - num_banks by 2, shadowing into e1 */ shadow = 0; - if(g_shadow_all_banks && ((shadow_reg & 0x08) == 0)) { + if((g_c036_val_speed & 0x10) && ((g_c035_shadow_reg & 0x08) == 0)) { shadow = BANK_SHADOW2; } num_banks = g_mem_size_total >> 16; @@ -917,6 +951,8 @@ fixup_shadow_all_banks() mem0rd += 0x100; } } + + fixup_brks(); } void @@ -966,7 +1002,7 @@ setup_pageinfo() fixup_bank0_2000_4000(); fixup_bank0_0400_0800(); - fixup_wrdefram(wrdefram); + fixup_wrdefram(g_c08x_wrdefram); fixup_altzp(); fixup_ramrd(); fixup_ramwrt(); @@ -987,7 +1023,7 @@ show_bankptrs_bank0rdwr() show_bankptrs(1); show_bankptrs(0xe0); show_bankptrs(0xe1); - printf("statereg: %02x\n", statereg); + printf("statereg: %02x\n", g_c068_statereg); } void @@ -1039,20 +1075,10 @@ show_addr(byte *ptr) } -#if 0 -#define CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc) \ - fcyc = *cyc_ptr; \ - new_fcyc = (int)(fcyc + g_cur_fplus_ptr->plus_x_minus_1); \ - *cyc_ptr = new_fcyc; \ - dcycs = g_last_vbl_dcycs + new_fcyc; -#endif - #define CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc) \ dcycs = g_last_vbl_dcycs + *cyc_ptr; -int dummy = 0; - int io_read(word32 loc, double *cyc_ptr) { @@ -1061,10 +1087,10 @@ io_read(word32 loc, double *cyc_ptr) #if 0 double fcyc, new_fcyc; #endif + word32 mask; int new_lcbank2; int new_wrdefram; int tmp; - int slot; int i; CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); @@ -1096,7 +1122,7 @@ io_read(word32 loc, double *cyc_ptr) case 0x16: /* c016: ALTZP */ return IOR(ALTZP); case 0x17: /* c017: rdc3rom */ - return IOR(int_crom[3]); + return IOR(g_c02d_int_crom & (1 << 3)); case 0x18: /* c018: rd80c0l */ return IOR((g_cur_a2_stat & ALL_STAT_ST80)); case 0x19: /* c019: rdvblbar */ @@ -1107,7 +1133,7 @@ io_read(word32 loc, double *cyc_ptr) case 0x1b: /* c01b: rdmix */ return IOR(g_cur_a2_stat & ALL_STAT_MIX_T_GR); case 0x1c: /* c01c: rdpage2 */ - return IOR(PAGE2); + return IOR(g_cur_a2_stat & ALL_STAT_PAGE2); case 0x1d: /* c01d: rdhires */ return IOR(g_cur_a2_stat & ALL_STAT_HIRES); case 0x1e: /* c01e: altcharset on? */ @@ -1120,7 +1146,8 @@ io_read(word32 loc, double *cyc_ptr) /* Click cassette port */ return 0x00; case 0x21: /* 0xc021 */ - UNIMPL_READ; + /* Not documented, but let's return COLOR_C021 */ + return IOR(g_cur_a2_stat & ALL_STAT_COLOR_C021); case 0x22: /* 0xc022 */ return (g_cur_a2_stat >> BIT_ALL_STAT_BG_COLOR) & 0xff; case 0x23: /* 0xc023 */ @@ -1136,23 +1163,19 @@ io_read(word32 loc, double *cyc_ptr) case 0x28: /* 0xc028 */ UNIMPL_READ; case 0x29: /* 0xc029 */ - return((g_cur_a2_stat & 0xa0) | (linear_vid<<6) | - (bank1latch)); + return((g_cur_a2_stat & 0xa0) | g_c029_val_some); case 0x2a: /* 0xc02a */ #if 0 printf("Reading c02a...returning 0\n"); #endif return 0; case 0x2b: /* 0xc02b */ - return c02b_val; + return g_c02b_val; case 0x2c: /* 0xc02c */ /* printf("reading c02c, returning 0\n"); */ return 0; case 0x2d: /* 0xc02d */ - tmp = 0; - for(i = 0; i < 8; i++) { - tmp = tmp | (int_crom[i] << i); - } + tmp = g_c02d_int_crom; return tmp; case 0x2e: /* 0xc02e */ case 0x2f: /* 0xc02f */ @@ -1164,20 +1187,18 @@ io_read(word32 loc, double *cyc_ptr) return doc_read_c030(dcycs); case 0x31: /* 0xc031 */ /* 3.5" control */ - return (head_35 << 7) | (g_apple35_sel << 6); + return g_c031_disk35; case 0x32: /* 0xc032 */ /* scan int */ return 0; case 0x33: /* 0xc033 = CLOCKDATA*/ - return clock_read_c033(); + return g_c033_data; case 0x34: /* 0xc034 = CLOCKCTL */ - return clock_read_c034(); + return g_c034_val; case 0x35: /* 0xc035 */ - return shadow_reg; + return g_c035_shadow_reg; case 0x36: /* 0xc036 = CYAREG */ - tmp = (speed_fast << 7) + (power_on_clear << 6) + - (g_shadow_all_banks << 4) + g_slot_motor_detect; - return tmp; + return g_c036_val_speed; case 0x37: /* 0xc037 */ return 0; case 0x38: /* 0xc038 */ @@ -1194,20 +1215,16 @@ io_read(word32 loc, double *cyc_ptr) case 0x3d: /* 0xc03d */ return doc_read_c03d(dcycs); case 0x3e: /* 0xc03e */ - return (doc_ptr & 0xff); + return (g_c03ef_doc_ptr & 0xff); case 0x3f: /* 0xc03f */ - return (doc_ptr >> 8); + return (g_c03ef_doc_ptr >> 8); /* 0xc040 - 0xc04f */ case 0x40: /* 0xc040 */ /* cassette */ return 0; case 0x41: /* 0xc041 */ - tmp = ((c041_en_25sec_ints << 4) + - (c041_en_vbl_ints << 3) + - (c041_en_switch_ints << 2) + - (c041_en_move_ints << 1) + (c041_en_mouse) ); - return tmp; + return g_c041_val; case 0x45: /* 0xc045 */ halt_printf("Mega II mouse read: c045\n"); return 0; @@ -1216,14 +1233,8 @@ io_read(word32 loc, double *cyc_ptr) g_c046_val = (tmp & 0xbf) + ((tmp & 0x80) >> 1); return tmp; case 0x47: /* 0xc047 */ - if(c046_vbl_irq_pending) { - remove_irq(); - c046_vbl_irq_pending = 0; - } - if(c046_25sec_irq_pend) { - remove_irq(); - c046_25sec_irq_pend = 0; - } + remove_irq(IRQ_PENDING_C046_25SEC | + IRQ_PENDING_C046_VBL); g_c046_val &= 0xe7; /* clear vbl_int, 1/4sec int*/ return 0; case 0x42: /* 0xc042 */ @@ -1235,17 +1246,17 @@ io_read(word32 loc, double *cyc_ptr) /* write to $c04f to start. Then read $c04f to get */ /* emulator ($16=sweet16, $fe=bernie II). */ /* Then read again to get version: $21 == 2.1 */ - switch(g_emubyte_cnt) { + switch(g_em_emubyte_cnt) { case 1: - g_emubyte_cnt = 2; + g_em_emubyte_cnt = 2; return 'K'; case 2: - g_emubyte_cnt = 0; + g_em_emubyte_cnt = 0; tmp = g_kegs_version_str[0] - '0'; i = g_kegs_version_str[2] - '0'; return ((tmp & 0xf) << 4) + (i & 0xf); default: - g_emubyte_cnt = 0; + g_em_emubyte_cnt = 0; return 0; } case 0x44: /* 0xc044 */ @@ -1264,62 +1275,62 @@ io_read(word32 loc, double *cyc_ptr) g_cur_a2_stat &= (~ALL_STAT_TEXT); change_display_mode(dcycs); } - return 0; + return float_bus(dcycs); case 0x51: /* 0xc051 */ if((g_cur_a2_stat & ALL_STAT_TEXT) == 0) { g_cur_a2_stat |= (ALL_STAT_TEXT); change_display_mode(dcycs); } - return 0; + return float_bus(dcycs); case 0x52: /* 0xc052 */ if(g_cur_a2_stat & ALL_STAT_MIX_T_GR) { g_cur_a2_stat &= (~ALL_STAT_MIX_T_GR); change_display_mode(dcycs); } - return 0; + return float_bus(dcycs); case 0x53: /* 0xc053 */ if((g_cur_a2_stat & ALL_STAT_MIX_T_GR) == 0) { g_cur_a2_stat |= (ALL_STAT_MIX_T_GR); change_display_mode(dcycs); } - return 0; + return float_bus(dcycs); case 0x54: /* 0xc054 */ - set_statereg(dcycs, statereg & (~0x40)); - return 0; + set_statereg(dcycs, g_c068_statereg & (~0x40)); + return float_bus(dcycs); case 0x55: /* 0xc055 */ - set_statereg(dcycs, statereg | 0x40); - return 0; + set_statereg(dcycs, g_c068_statereg | 0x40); + return float_bus(dcycs); case 0x56: /* 0xc056 */ if(g_cur_a2_stat & ALL_STAT_HIRES) { g_cur_a2_stat &= (~ALL_STAT_HIRES); fixup_hires_on(); change_display_mode(dcycs); } - return 0; + return float_bus(dcycs); case 0x57: /* 0xc057 */ if((g_cur_a2_stat & ALL_STAT_HIRES) == 0) { g_cur_a2_stat |= (ALL_STAT_HIRES); fixup_hires_on(); change_display_mode(dcycs); } - return 0; + return float_bus(dcycs); case 0x58: /* 0xc058 */ if(g_zipgs_unlock < 4) { - annunc_0 = 0; + g_c05x_annuncs &= (~1); } return 0; case 0x59: /* 0xc059 */ if(g_zipgs_unlock >= 4) { return g_zipgs_reg_c059; } else { - annunc_0 = 1; + g_c05x_annuncs |= 1; } return 0; case 0x5a: /* 0xc05a */ if(g_zipgs_unlock >= 4) { return g_zipgs_reg_c05a; } else { - annunc_1 = 0; + g_c05x_annuncs &= (~2); } return 0; case 0x5b: /* 0xc05b */ @@ -1328,21 +1339,21 @@ io_read(word32 loc, double *cyc_ptr) tmp = (word64_tmp >> 9) & 1; return (tmp << 7) + (g_zipgs_reg_c05b & 0x7f); } else { - annunc_1 = 1; + g_c05x_annuncs |= 2; } return 0; case 0x5c: /* 0xc05c */ if(g_zipgs_unlock >= 4) { return g_zipgs_reg_c05c; } else { - annunc_2 = 0; + g_c05x_annuncs &= (~4); } return 0; case 0x5d: /* 0xc05d */ if(g_zipgs_unlock >= 4) { halt_printf("Reading ZipGS $c05d!\n"); } else { - annunc_2 = 1; + g_c05x_annuncs |= 4; } return 0; case 0x5e: /* 0xc05e */ @@ -1365,24 +1376,25 @@ io_read(word32 loc, double *cyc_ptr) /* 0xc060 - 0xc06f */ case 0x60: /* 0xc060 */ - return IOR(g_paddle_button[3]); + return IOR(g_paddle_buttons & 8); case 0x61: /* 0xc061 */ - return IOR(adb_is_cmd_key_down() || g_paddle_button[0]); + return IOR(adb_is_cmd_key_down() || + g_paddle_buttons & 1); case 0x62: /* 0xc062 */ return IOR(adb_is_option_key_down() || - g_paddle_button[1]); + g_paddle_buttons & 2); case 0x63: /* 0xc063 */ - return IOR(g_paddle_button[2]); + return IOR(g_paddle_buttons & 4); case 0x64: /* 0xc064 */ - return read_paddles(0, dcycs); + return read_paddles(dcycs, 0); case 0x65: /* 0xc065 */ - return read_paddles(1, dcycs); + return read_paddles(dcycs, 1); case 0x66: /* 0xc066 */ - return read_paddles(2, dcycs); + return read_paddles(dcycs, 2); case 0x67: /* 0xc067 */ - return read_paddles(3, dcycs); + return read_paddles(dcycs, 3); case 0x68: /* 0xc068 = STATEREG */ - return statereg; + return g_c068_statereg; case 0x69: /* 0xc069 */ /* Reserved reg, return 0 */ return 0; @@ -1412,24 +1424,24 @@ io_read(word32 loc, double *cyc_ptr) case 0x8c: case 0x8d: case 0x8e: case 0x8f: new_lcbank2 = ((loc & 0x8) >> 1) ^ 0x4; new_wrdefram = (loc & 1); - if(new_wrdefram != wrdefram) { + if(new_wrdefram != g_c08x_wrdefram) { fixup_wrdefram(new_wrdefram); } switch(loc & 0x3) { case 0x1: /* 0xc081 */ case 0x2: /* 0xc082 */ /* Read rom, set lcbank2 */ - set_statereg(dcycs, (statereg & ~(0x04)) | + set_statereg(dcycs, (g_c068_statereg & ~(0x04))| (new_lcbank2 | 0x08)); break; case 0x0: /* 0xc080 */ case 0x3: /* 0xc083 */ /* Read ram (clear RDROM), set lcbank2 */ - set_statereg(dcycs, (statereg & ~(0x0c)) | + set_statereg(dcycs, (g_c068_statereg & ~(0x0c))| (new_lcbank2)); break; } - return 0xa0; + return float_bus(dcycs); /* 0xc090 - 0xc09f */ case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: @@ -1493,14 +1505,14 @@ io_read(word32 loc, double *cyc_ptr) } case 1: case 2: case 3: case 4: case 5: case 6: /* c100 - c6ff */ - slot = ((loc >> 8) & 7); - if(INTCX || (int_crom[slot] == 0)) { + mask = (1 << ((loc >> 8) & 7)); + if(INTCX || ((g_c02d_int_crom & mask) == 0)) { return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); } - return (dummy++) & 0xff; + return float_bus(dcycs); case 7: /* c700 */ - if(INTCX || (int_crom[7] == 0)) { + if(INTCX || ((g_c02d_int_crom & (1 << 7)) == 0)) { return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); } tmp = g_rom_fc_ff_ptr[0x3c500 + (loc & 0xff)]; @@ -1509,12 +1521,12 @@ io_read(word32 loc, double *cyc_ptr) } return tmp; case 8: case 9: case 0xa: case 0xb: case 0xc: case 0xd: case 0xe: - if(INTCX || (int_crom[3] == 0)) { + if(INTCX || ((g_c02d_int_crom & (1 << 3)) == 0)) { return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); } UNIMPL_READ; case 0xf: - if(INTCX || (int_crom[3] == 0)) { + if(INTCX || ((g_c02d_int_crom & (1 << 3)) == 0)) { return(g_rom_fc_ff_ptr[0x3c000 + (loc & 0xfff)]); } if((loc & 0xfff) == 0xfff) { @@ -1538,8 +1550,7 @@ io_write(word32 loc, int val, double *cyc_ptr) int new_tmp; int new_lcbank2; int new_wrdefram; - int i; - int tmp, tmp2; + int tmp; int fixup; CALC_DCYCS_FROM_CYC_PTR(dcycs, cyc_ptr, fcyc, new_fcyc); @@ -1562,38 +1573,40 @@ io_write(word32 loc, int val, double *cyc_ptr) } return; case 0x02: /* 0xc002 */ - set_statereg(dcycs, statereg & ~0x20); + set_statereg(dcycs, g_c068_statereg & ~0x20); return; case 0x03: /* 0xc003 */ - set_statereg(dcycs, statereg | 0x20); + set_statereg(dcycs, g_c068_statereg | 0x20); return; case 0x04: /* 0xc004 */ - set_statereg(dcycs, statereg & ~0x10); + set_statereg(dcycs, g_c068_statereg & ~0x10); return; case 0x05: /* 0xc005 */ - set_statereg(dcycs, statereg | 0x10); + set_statereg(dcycs, g_c068_statereg | 0x10); return; case 0x06: /* 0xc006 */ - set_statereg(dcycs, statereg & ~0x01); + set_statereg(dcycs, g_c068_statereg & ~0x01); return; case 0x07: /* 0xc007 */ - set_statereg(dcycs, statereg | 0x01); + set_statereg(dcycs, g_c068_statereg | 0x01); return; case 0x08: /* 0xc008 */ - set_statereg(dcycs, statereg & ~0x80); + set_statereg(dcycs, g_c068_statereg & ~0x80); return; case 0x09: /* 0xc009 */ - set_statereg(dcycs, statereg | 0x80); + set_statereg(dcycs, g_c068_statereg | 0x80); return; case 0x0a: /* 0xc00a */ - if(int_crom[3] != 0) { - int_crom[3] = 0; + tmp = 1 << 3; + if((g_c02d_int_crom & tmp) != 0) { + g_c02d_int_crom &= ~tmp; fixup_intcx(); } return; case 0x0b: /* 0xc00b */ - if(int_crom[3] == 0) { - int_crom[3] = 1; + tmp = 1 << 3; + if((g_c02d_int_crom & tmp) == 0) { + g_c02d_int_crom |= tmp; fixup_intcx(); } return; @@ -1653,28 +1666,24 @@ io_write(word32 loc, int val, double *cyc_ptr) return; case 0x23: /* 0xc023 */ if((val & 0x19) != 0) { - halt_printf("c023 write of %02x!!!\n",val); + halt_printf("c023 write of %02x!!!\n", val); } tmp = (g_c023_val & 0x70) | (val & 0x0f); - if(((tmp & 0x22)==0x22) && !c023_scan_int_irq_pending){ - c023_scan_int_irq_pending = 1; - add_irq(); + if((tmp & 0x22) == 0x22) { + add_irq(IRQ_PENDING_C023_SCAN); } - if(!(tmp & 2) && c023_scan_int_irq_pending) { - c023_scan_int_irq_pending = 0; - remove_irq(); + if(!(tmp & 2)) { + remove_irq(IRQ_PENDING_C023_SCAN); } - if(((tmp & 0x44)==0x44)&& !c023_1sec_int_irq_pending){ - c023_1sec_int_irq_pending = 1; - add_irq(); + if((tmp & 0x44) == 0x44) { + add_irq(IRQ_PENDING_C023_1SEC); } - if(!(tmp & 0x4) && c023_1sec_int_irq_pending) { - c023_1sec_int_irq_pending = 0; - remove_irq(); + if(!(tmp & 0x4)) { + remove_irq(IRQ_PENDING_C023_1SEC); } - if(c023_1sec_int_irq_pending || - c023_scan_int_irq_pending) { + if(g_irq_pending & (IRQ_PENDING_C023_SCAN | + IRQ_PENDING_C023_1SEC)) { tmp |= 0x80; } g_c023_val = tmp; @@ -1689,12 +1698,11 @@ io_write(word32 loc, int val, double *cyc_ptr) adb_write_c027(val); return; case 0x29: /* 0xc029 */ - bank1latch = val & 1; - linear_vid = (val >> 6) & 1; - new_tmp = val & 0xa0; - if(bank1latch == 0) { + g_c029_val_some = val & 0x41; + if((val & 1) == 0) { halt_printf("c029: %02x\n", val); } + new_tmp = val & 0xa0; if(new_tmp != (g_cur_a2_stat & 0xa0)) { g_cur_a2_stat = (g_cur_a2_stat & (~0xa0)) + new_tmp; @@ -1707,7 +1715,7 @@ io_write(word32 loc, int val, double *cyc_ptr) #endif return; case 0x2b: /* 0xc02b */ - c02b_val = val; + g_c02b_val = val; if(val != 0x08 && val != 0x00) { printf("Writing c02b with %02x\n", val); } @@ -1716,14 +1724,8 @@ io_write(word32 loc, int val, double *cyc_ptr) if((val & 0x9) != 0) { halt_printf("Illegal c02d write: %02x!\n", val); } - fixup = 0; - for(i = 0; i < 8; i++) { - tmp = ((val & (1 << i)) != 0); - if(int_crom[i] != tmp) { - fixup = 1; - int_crom[i] = tmp; - } - } + fixup = (val != g_c02d_int_crom); + g_c02d_int_crom = val; if(fixup) { vid_printf("Write c02d of %02x\n", val); fixup_intcx(); @@ -1748,37 +1750,29 @@ io_write(word32 loc, int val, double *cyc_ptr) (void)doc_read_c030(dcycs); return; case 0x31: /* 0xc031 */ - tmp = ((val & 0x80) != 0); - tmp2 = ((val & 0x40) != 0); - head_35 = tmp; - iwm_set_apple35_sel(tmp2); - iwm_printf("write c031: %02x, h: %d, 35: %d\n", - val, head_35, g_apple35_sel); + tmp = val ^ g_c031_disk35; + if(tmp & 0x40) { + /* apple35_sel changed, maybe speed change */ + set_halt(HALT_EVENT); + } + g_c031_disk35 = val & 0xc0; return; case 0x32: /* 0xc032 */ tmp = g_c023_val & 0x7f; if(((val & 0x40) == 0) && (tmp & 0x40)) { /* clear 1 sec int */ - irq_printf("Clear 1sec int\n"); - if(c023_1sec_int_irq_pending) { - remove_irq(); - } + remove_irq(IRQ_PENDING_C023_1SEC); tmp &= 0xbf; g_c023_val = tmp; - c023_1sec_int_irq_pending = 0; } if(((val & 0x20) == 0) && (tmp & 0x20)) { /* clear scan line int */ - irq_printf("Clear scn int1\n"); - if(c023_scan_int_irq_pending) { - remove_irq(); - } - c023_scan_int_irq_pending = 0; + remove_irq(IRQ_PENDING_C023_SCAN); g_c023_val = tmp & 0xdf; check_for_new_scan_int(dcycs); } - if(c023_1sec_int_irq_pending || - c023_scan_int_irq_pending) { + if(g_irq_pending & (IRQ_PENDING_C023_1SEC | + IRQ_PENDING_C023_SCAN)) { g_c023_val |= 0x80; } if((val & 0x9f) != 0x9f) { @@ -1786,12 +1780,12 @@ io_write(word32 loc, int val, double *cyc_ptr) } return; case 0x33: /* 0xc033 = CLOCKDATA*/ - clock_write_c033(val); + g_c033_data = val; return; case 0x34: /* 0xc034 = CLOCKCTL */ + tmp = val ^ g_c034_val; clock_write_c034(val); - if((val & 0xf) != g_border_color) { - g_border_color = val & 0xf; + if(tmp & 0xf) { change_border_color(dcycs, val & 0xf); } return; @@ -1799,28 +1793,31 @@ io_write(word32 loc, int val, double *cyc_ptr) update_shadow_reg(val); return; case 0x36: /* 0xc036 = CYAREG */ - tmp = (val>>7) & 1; - if(speed_fast != tmp) { - /* to recalculate times */ + tmp = val ^ g_c036_val_speed; + g_c036_val_speed = (val & ~0x20); /* clr bit 5 */ + if(tmp & 0x80) { + /* to recalculate times since speed changing */ set_halt(HALT_EVENT); } - speed_fast = tmp; - if((val & 0xf) != (int)g_slot_motor_detect) { + if(tmp & 0xf) { + /* slot_motor_detect changed */ set_halt(HALT_EVENT); } - g_slot_motor_detect = (val & 0xf); - power_on_clear = (val >> 6) & 1; if((val & 0x60) != 0) { - halt_printf("c036: %2x\n", val); + /* for ROM 03, 0x40 is the power-on status */ + /* and can be read/write */ + if(((val & 0x60) != 0x40) || + (g_rom_version < 3)) { + g_c036_val_speed &= (~0x60); + halt_printf("c036: %2x\n", val); + } } - tmp = (val >> 4) & 1; - if(tmp != g_shadow_all_banks) { + if(tmp & 0x10) { /* shadow in all banks! */ if(g_num_shadow_all_banks++ == 0) { printf("Shadowing all banks...This " "must be the NFC Megademo\n"); } - g_shadow_all_banks = tmp; fixup_shadow_all_banks(); } return; @@ -1848,46 +1845,33 @@ io_write(word32 loc, int val, double *cyc_ptr) doc_write_c03d(val, dcycs); return; case 0x3e: /* 0xc03e */ - doc_write_c03e(val); + g_c03ef_doc_ptr = (g_c03ef_doc_ptr & 0xff00) + val; return; case 0x3f: /* 0xc03f */ - doc_write_c03f(val); + g_c03ef_doc_ptr = (g_c03ef_doc_ptr & 0xff) + (val << 8); return; /* 0xc040 - 0xc04f */ case 0x41: /* c041 */ - c041_en_25sec_ints = ((val & 0x10) != 0); - c041_en_vbl_ints = ((val & 0x8) != 0); - c041_en_switch_ints = ((val & 0x4) != 0); - c041_en_move_ints = ((val & 0x2) != 0); - c041_en_mouse = ((val & 0x1) != 0); + g_c041_val = val & 0x1f; if((val & 0xe7) != 0) { halt_printf("write c041: %02x\n", val); } - if(!c041_en_vbl_ints && c046_vbl_irq_pending) { - /* there was an interrupt, but no more*/ - remove_irq(); - c046_vbl_irq_pending = 0; + if(!(val & C041_EN_VBL_INTS)) { + /* no more vbl interrupt */ + remove_irq(IRQ_PENDING_C046_VBL); } - if(!c041_en_25sec_ints && c046_25sec_irq_pend) { - /* there was an interrupt, but no more*/ - remove_irq(); - c046_25sec_irq_pend = 0; + if(!(val & C041_EN_25SEC_INTS)) { + remove_irq(IRQ_PENDING_C046_25SEC); } return; case 0x46: /* c046 */ /* ignore writes to c046 */ return; case 0x47: /* c047 */ - if(c046_vbl_irq_pending) { - remove_irq(); - c046_vbl_irq_pending = 0; - } - if(c046_25sec_irq_pend) { - remove_irq(); - c046_25sec_irq_pend = 0; - } + remove_irq(IRQ_PENDING_C046_VBL | + IRQ_PENDING_C046_25SEC); g_c046_val &= 0xe7; /* clear vblint, 1/4sec int*/ return; case 0x48: /* c048 */ @@ -1897,7 +1881,7 @@ io_write(word32 loc, int val, double *cyc_ptr) case 0x43: /* c043 */ return; case 0x4f: /* c04f */ - g_emubyte_cnt = 1; + g_em_emubyte_cnt = 1; return; case 0x40: /* c040 */ case 0x44: /* c044 */ @@ -1936,10 +1920,10 @@ io_write(word32 loc, int val, double *cyc_ptr) } return; case 0x54: /* 0xc054 */ - set_statereg(dcycs, statereg & (~0x40)); + set_statereg(dcycs, g_c068_statereg & (~0x40)); return; case 0x55: /* 0xc055 */ - set_statereg(dcycs, statereg | 0x40); + set_statereg(dcycs, g_c068_statereg | 0x40); return; case 0x56: /* 0xc056 */ if(g_cur_a2_stat & ALL_STAT_HIRES) { @@ -1959,7 +1943,7 @@ io_write(word32 loc, int val, double *cyc_ptr) if(g_zipgs_unlock >= 4) { g_zipgs_reg_c059 &= 0x4; /* last reset cold */ } else { - annunc_0 = 0; + g_c05x_annuncs &= (~1); } return; case 0x59: /* 0xc059 */ @@ -1967,11 +1951,11 @@ io_write(word32 loc, int val, double *cyc_ptr) g_zipgs_reg_c059 = (val & 0xf8) | (g_zipgs_reg_c059 & 0x7); } else { - annunc_0 = 1; + g_c05x_annuncs |= 1; } return; case 0x5a: /* 0xc05a */ - annunc_1 = 0; + g_c05x_annuncs &= (~2); if((val & 0xf0) == 0x50) { g_zipgs_unlock++; } else if((val & 0xf0) == 0xa0) { @@ -1992,14 +1976,14 @@ io_write(word32 loc, int val, double *cyc_ptr) } g_zipgs_reg_c05b &= (~0x10); // enable } else { - annunc_1 = 1; + g_c05x_annuncs |= 2; } return; case 0x5c: /* 0xc05c */ if(g_zipgs_unlock >= 4) { g_zipgs_reg_c05c = val; } else { - annunc_2 = 0; + g_c05x_annuncs &= (~4); } return; case 0x5d: /* 0xc05d */ @@ -2010,7 +1994,7 @@ io_write(word32 loc, int val, double *cyc_ptr) } g_zipgs_reg_c05a = val | 0xf; } else { - annunc_2 = 1; + g_c05x_annuncs |= 4; } return; case 0x5e: /* 0xc05e */ @@ -2084,9 +2068,9 @@ io_write(word32 loc, int val, double *cyc_ptr) case 0x84: case 0x85: case 0x86: case 0x87: case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: - new_lcbank2 = ((loc & 0x8) >> 1) ^ 0x4; + new_lcbank2 = ((loc >> 1) & 0x4) ^ 0x4; new_wrdefram = (loc & 1); - if(new_wrdefram != wrdefram) { + if(new_wrdefram != g_c08x_wrdefram) { fixup_wrdefram(new_wrdefram); } switch(loc & 0xf) { @@ -2099,7 +2083,7 @@ io_write(word32 loc, int val, double *cyc_ptr) case 0xd: /* 0xc08d */ case 0xe: /* 0xc08e */ /* Read rom, set lcbank2 */ - set_statereg(dcycs, (statereg & ~(0x04)) | + set_statereg(dcycs, (g_c068_statereg & ~(0x04))| (new_lcbank2 | 0x08)); break; case 0x0: /* 0xc080 */ @@ -2111,7 +2095,7 @@ io_write(word32 loc, int val, double *cyc_ptr) case 0xc: /* 0xc08c */ case 0xf: /* 0xc08f */ /* Read ram (clear RDROM), set lcbank2 */ - set_statereg(dcycs, (statereg & ~(0x0c)) | + set_statereg(dcycs, (g_c068_statereg & ~(0x0c))| (new_lcbank2)); break; } @@ -2125,11 +2109,12 @@ io_write(word32 loc, int val, double *cyc_ptr) UNIMPL_WRITE; /* 0xc0a0 - 0xc0af */ - case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa0: case 0xa1: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf: UNIMPL_WRITE; + case 0xa2: /* Burger Times writes here on error */ case 0xa8: /* Kurzweil SMP writes to 0xc0a8, ignore it */ return; @@ -2277,9 +2262,9 @@ get_lines_since_vbl(double dcycs) dcycs_since_last_vbl = dcycs - g_last_vbl_dcycs; - dlines_since_vbl = (262.0/DCYCS_IN_16MS) * dcycs_since_last_vbl; + dlines_since_vbl = dcycs_since_last_vbl * (1.0 / 65.0); lines_since_vbl = (int)dlines_since_vbl; - dcyc_line_start = (double)lines_since_vbl * (DCYCS_IN_16MS/262.0); + dcyc_line_start = (double)lines_since_vbl * 65.0; offset = ((int)(dcycs_since_last_vbl - dcyc_line_start)) & 0xff; diff --git a/src/paddles.c b/src/paddles.c index ec62a0e..0fcfe26 100644 --- a/src/paddles.c +++ b/src/paddles.c @@ -8,25 +8,52 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_paddles_c[] = "@(#)$KmKId: paddles.c,v 1.7 2004-03-23 17:28:06-05 kentd Exp $"; +const char rcsid_paddles_c[] = "@(#)$KmKId: paddles.c,v 1.14 2004-10-19 14:52:36-04 kentd Exp $"; #include "defc.h" -extern int g_mouse_fifo_x[]; /* from adb.c */ -extern int g_mouse_fifo_y[]; +extern int g_mouse_raw_x; /* from adb.c */ +extern int g_mouse_raw_y; double g_paddle_trig_dcycs = 0.0; int g_swap_paddles = 0; int g_invert_paddles = 0; +int g_joystick_scale_factor_x = 0x100; +int g_joystick_scale_factor_y = 0x100; +int g_joystick_trim_amount_x = 0; +int g_joystick_trim_amount_y = 0; -int g_joystick_type = JOYSTICK_MOUSE; +int g_joystick_type = 0; /* 0 = Keypad Joystick */ +int g_joystick_native_type1 = -1; +int g_joystick_native_type2 = -1; +int g_joystick_native_type = -1; -int g_paddle_button[4] = { 0, 0, 0, 0 }; - /* g_paddle_button[0] = button 0, etc */ +extern int g_paddle_buttons; int g_paddle_val[4] = { 0, 0, 0, 0 }; /* g_paddle_val[0]: Joystick X coord, [1]:Y coord */ +double g_paddle_dcycs[4] = { 0.0, 0.0, 0.0, 0.0 }; + /* g_paddle_dcycs are the dcycs the paddle goes to 0 */ + + +void +paddle_fixup_joystick_type() +{ + /* If g_joystick_type points to an illegal value, change it */ + if(g_joystick_type == 2) { + g_joystick_native_type = g_joystick_native_type1; + if(g_joystick_native_type1 < 0) { + g_joystick_type = 0; + } + } + if(g_joystick_type == 3) { + g_joystick_native_type = g_joystick_native_type2; + if(g_joystick_native_type2 < 0) { + g_joystick_type = 0; + } + } +} void paddle_trigger(double dcycs) @@ -35,75 +62,117 @@ paddle_trigger(double dcycs) g_paddle_trig_dcycs = dcycs; /* Determine what all the paddle values are right now */ + paddle_fixup_joystick_type(); switch(g_joystick_type) { - case JOYSTICK_MOUSE: + case 0: /* Keypad Joystick */ + paddle_trigger_keypad(dcycs); + break; + case 1: /* Mouse Joystick */ paddle_trigger_mouse(dcycs); break; - case JOYSTICK_LINUX: - case JOYSTICK_WIN32_1: - case JOYSTICK_WIN32_2: - joystick_update(); + default: + joystick_update(dcycs); } } void paddle_trigger_mouse(double dcycs) { - int val_x; - int val_y; + int val_x, val_y; + int mouse_x, mouse_y; val_x = 0; - /* mous_phys_x is 0->560, convert that to 0-255 cyc */ - /* so, mult by 117 then divide by 256 */ - if(g_mouse_fifo_x[0] > BASE_MARGIN_LEFT) { - val_x = (g_mouse_fifo_x[0] - BASE_MARGIN_LEFT) * 117; - val_x = val_x >> 8; - } - /* mous_phys_y is 0->384, convert that to 0-255 cyc */ - /* so, mult by 170 then divide by 256 (shift right by 8) */ - val_y = 0; - if(g_mouse_fifo_y[0] > BASE_MARGIN_TOP) { - val_y = ((g_mouse_fifo_y[0] - BASE_MARGIN_TOP) * 170) >> 8; - } + mouse_x = g_mouse_raw_x; + mouse_y = g_mouse_raw_y; + /* mous_phys_x is 0->560, convert that to -32768 to + 32767 cyc */ + /* So subtract 280 then mult by 117 */ + val_x = (mouse_x - 280) * 117; - if(val_x > 280) { - val_x = 280; - } - if(val_y > 280) { - val_y = 280; - } + /* mous_phys_y is 0->384, convert that to -32768 to + 32767 cyc */ + /* so subtract 192 then mult by 180 to overscale it a bit */ + val_y = (mouse_y - 192) * 180; g_paddle_val[0] = val_x; g_paddle_val[1] = val_y; - g_paddle_val[2] = 255; - g_paddle_val[3] = 255; - g_paddle_button[2] = 1; - g_paddle_button[3] = 1; + g_paddle_val[2] = 32767; + g_paddle_val[3] = 32767; + g_paddle_buttons |= 0xc; + paddle_update_trigger_dcycs(dcycs); } -int -read_paddles(int paddle, double dcycs) +void +paddle_trigger_keypad(double dcycs) +{ + int get_y; + int val_x, val_y; + + + val_x = adb_get_keypad_xy(get_y=0); + val_y = adb_get_keypad_xy(get_y=1); + /* val_x and val_y are already scale -32768 to +32768 */ + + g_paddle_val[0] = val_x; + g_paddle_val[1] = val_y; + g_paddle_val[2] = 32767; + g_paddle_val[3] = 32767; + g_paddle_buttons |= 0xc; + paddle_update_trigger_dcycs(dcycs); +} + +void +paddle_update_trigger_dcycs(double dcycs) { double trig_dcycs; int val; + int paddle_num; + int scale, trim; + int i; - /* This routine is called by any read to $c064-$c067 */ - if(g_swap_paddles) { - paddle = paddle ^ 1; + for(i = 0; i < 4; i++) { + paddle_num = i; + if(g_swap_paddles) { + paddle_num = i ^ 1; + } + val = g_paddle_val[paddle_num]; + if(g_invert_paddles) { + val = -val; + } + /* convert -32768 to +32768 into 0->2816.0 cycles (the */ + /* paddle delay const) */ + /* First multiply by the scale factor to adjust range */ + if(paddle_num & 1) { + scale = g_joystick_scale_factor_y; + trim = g_joystick_trim_amount_y; + } else { + scale = g_joystick_scale_factor_x; + trim = g_joystick_trim_amount_x; + } +#if 0 + if(i == 0) { + printf("val was %04x(%d) * scale %03x = %d\n", + val, val, scale, (val*scale)>>16); + } +#endif + val = val * scale >> 16; + /* Val is now from -128 to + 128 since scale is */ + /* 256=1.0, 128 = 0.5 */ + val = val + 128 + trim; + if(val >= 255) { + val = 280; /* increase range */ + } + trig_dcycs = dcycs + (val * 11.04); + g_paddle_dcycs[i] = trig_dcycs; } +} - paddle = paddle & 3; +int +read_paddles(double dcycs, int paddle) +{ + double trig_dcycs; - val = g_paddle_val[paddle]; - - if(g_invert_paddles) { - val = 255 - val; - } - - /* convert 0->255 into 0->2816.0 cycles (the paddle delay const) */ - trig_dcycs = g_paddle_trig_dcycs + (val * 11.0); + trig_dcycs = g_paddle_dcycs[paddle & 3]; if(dcycs < trig_dcycs) { return 0x80; @@ -112,3 +181,9 @@ read_paddles(int paddle, double dcycs) } } +void +paddle_update_buttons() +{ + paddle_fixup_joystick_type(); + joystick_update_buttons(); +} diff --git a/src/protos.h b/src/protos.h index 680ced2..cf1d9d8 100644 --- a/src/protos.h +++ b/src/protos.h @@ -9,10 +9,13 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsid_protos_h[] = "@(#)$KmKId: protos.h,v 1.173 2004-03-23 17:26:19-05 kentd Exp $"; +const char rcsid_protos_h[] = "@(#)$KmKId: protos.h,v 1.188 2004-12-06 19:08:34-05 kentd Exp $"; #endif /* xdriver.c and macdriver.c and windriver.c */ +int x_show_alert(int is_fatal, const char *str); +int win_nonblock_read_stdin(int fd, char *bufptr, int len); +void x_dialog_create_kegs_conf(const char *str); void update_color_array(int col_num, int a2_color); void set_border_color(int val); void x_update_physical_colormap(void); @@ -31,6 +34,7 @@ void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, void x_push_done(); void x_hide_pointer(int); void x_get_kimage(Kimage *kimage_ptr); +void x_full_screen(int do_full); /* test65.c */ void do_gen_test(int got_num, int base_seed); @@ -52,6 +56,7 @@ int get_memory16_act_stub_asm(word32 addr, int cycs); void set_memory_c(word32 addr, word32 val, int cycs); void set_memory16_c(word32 addr, word32 val, int cycs); +void set_memory24_c(word32 addr, word32 val, int cycs); int enter_engine(Engine_reg *ptr); void clr_halt_act(void); @@ -60,19 +65,19 @@ void set_halt_act(int val); /* special scc_macdriver.c prototypes */ int scc_serial_mac_init(int port); void scc_serial_mac_change_params(int port); -void scc_serial_mac_fill_readbuf(int port, double dcycs); +void scc_serial_mac_fill_readbuf(int port, int space_left, double dcycs); void scc_serial_mac_empty_writebuf(int port); /* special scc_windriver.c prototypes */ int scc_serial_win_init(int port); void scc_serial_win_change_params(int port); -void scc_serial_win_fill_readbuf(int port, double dcycs); +void scc_serial_win_fill_readbuf(int port, int space_left, double dcycs); void scc_serial_win_empty_writebuf(int port); /* special joystick_driver.c prototypes */ void joystick_init(void); -void joystick_update(void); -void joystick_update_button(void); +void joystick_update(double dcycs); +void joystick_update_buttons(void); /* END_HDR */ @@ -103,8 +108,10 @@ int adb_read_c027(void); void adb_write_c027(int val); int read_adb_ram(word32 addr); void write_adb_ram(word32 addr, int val); +int adb_get_keypad_xy(int get_y); int update_mouse(int x, int y, int button_states, int buttons_valid); int mouse_read_c024(double dcycs); +void mouse_compress_fifo(double dcycs); void adb_key_event(int a2code, int is_up); word32 adb_read_c000(void); word32 adb_access_c010(void); @@ -114,6 +121,7 @@ int adb_is_option_key_down(void); void adb_increment_speed(void); void adb_physical_key_update(int a2code, int is_up); void adb_virtual_key_update(int a2code, int is_up); +void adb_all_keys_up(void); void adb_kbd_repeat_off(void); @@ -127,9 +135,6 @@ void clk_write_bram(FILE *fconf); void update_cur_time(void); void clock_update(void); void clock_update_if_needed(void); -word32 clock_read_c033(void); -word32 clock_read_c034(void); -void clock_write_c033(word32 val); void clock_write_c034(word32 val); void do_clock_data(void); @@ -141,10 +146,12 @@ void do_clock_data(void); void config_init_menus(Cfg_menu *menuptr); void config_init(void); void cfg_exit(void); +void cfg_toggle_config_panel(void); void cfg_text_screen_dump(void); void config_vbl_update(int doit_3_persec); void config_parse_option(char *buf, int pos, int len, int line); void config_parse_bram(char *buf, int pos, int len); +void config_load_roms(void); void config_parse_config_kegs_file(void); Disk *cfg_get_dsk_from_slot_drive(int slot, int drive); void config_generate_config_kegs_name(char *outstr, int maxlen, Disk *dsk, int with_extras); @@ -166,7 +173,7 @@ void cfg_putchar(int c); void cfg_printf(const char *fmt, ...); void cfg_print_num(int num, int max_len); void cfg_get_disk_name(char *outstr, int maxlen, int type_ext, int with_extras); -void cfg_parse_menu(Cfg_menu *menu_ptr, int menu_pos, int highlight_pos, int change); +void cfg_parse_menu(Cfg_menu *menuptr, int menu_pos, int highlight_pos, int change); void cfg_get_base_path(char *pathptr, const char *inptr, int go_up); void cfg_file_init(void); void cfg_free_alldirents(Cfg_listhdr *listhdrptr); @@ -178,6 +185,7 @@ char *cfg_shorten_filename(const char *in_ptr, int maxlen); void cfg_fix_topent(Cfg_listhdr *listhdrptr); void cfg_file_draw(void); void cfg_partition_selected(void); +void cfg_file_update_ptr(char *str); void cfg_file_selected(void); void cfg_file_handle_key(int key); void config_control_panel(void); @@ -200,7 +208,9 @@ void xam_mem(int count); void show_hex_mem(int startbank, word32 start, int endbank, word32 end, int count); int read_line(char *buf, int len); void do_debug_list(void); -void load_roms(void); +void dis_do_memmove(void); +void dis_do_pattern_search(void); +void dis_do_compare(void); void do_debug_unix(void); void do_debug_load(void); int do_dis(FILE *outfile, word32 kpc, int accsize, int xsize, int op_provided, word32 instr); @@ -216,7 +226,7 @@ void scc_hard_reset_port(int port); void scc_reset_port(int port); void scc_regen_clocks(int port); void scc_port_init(int port); -void scc_try_to_empty_writebuf(int port); +void scc_try_to_empty_writebuf(int port, double dcycs); void scc_try_fill_readbuf(int port, double dcycs); void scc_update(double dcycs); void do_scc_event(int type, double dcycs); @@ -236,6 +246,8 @@ void scc_clr_tx_int(int port); void scc_set_zerocnt_int(int port); void scc_clr_zerocnt_int(int port); void scc_add_to_readbuf(int port, word32 val, double dcycs); +void scc_add_to_readbufv(int port, double dcycs, const char *fmt, ...); +void scc_transmit(int port, word32 val, double dcycs); void scc_add_to_writebuf(int port, word32 val, double dcycs); word32 scc_read_data(int port, double dcycs); void scc_write_data(int port, word32 val, double dcycs); @@ -243,10 +255,23 @@ void scc_write_data(int port, word32 val, double dcycs); /* scc_socket_driver.c */ void scc_socket_init(int port); +void scc_socket_maybe_open_incoming(int port, double dcycs); +void scc_socket_open_outgoing(int port, double dcycs); +void scc_socket_make_nonblock(int port, double dcycs); void scc_socket_change_params(int port); -void scc_accept_socket(int port); -void scc_socket_fill_readbuf(int port, double dcycs); -void scc_socket_empty_writebuf(int port); +void scc_socket_close(int port, int full_close, double dcycs); +void scc_accept_socket(int port, double dcycs); +void scc_socket_telnet_reqs(int port, double dcycs); +void scc_socket_fill_readbuf(int port, int space_left, double dcycs); +void scc_socket_recvd_char(int port, int c, double dcycs); +void scc_socket_empty_writebuf(int port, double dcycs); +void scc_socket_modem_write(int port, int c, double dcycs); +void scc_socket_do_cmd_str(int port, double dcycs); +void scc_socket_send_modem_code(int port, int code, double dcycs); +void scc_socket_modem_hangup(int port, double dcycs); +void scc_socket_modem_connect(int port, double dcycs); +void scc_socket_modem_do_ring(int port, double dcycs); +void scc_socket_do_answer(int port, double dcycs); /* scc_windriver.c */ @@ -257,6 +282,7 @@ void scc_socket_empty_writebuf(int port); /* iwm.c */ void iwm_init_drive(Disk *dsk, int smartport, int drive, int disk_525); +void disk_set_num_tracks(Disk *dsk, int num_tracks); void iwm_init(void); void iwm_reset(void); void draw_iwm_status(int line, char *buf); @@ -268,7 +294,6 @@ void iwm_move_to_track(Disk *dsk, int new_track); void iwm525_phase_change(int drive, int phase); int iwm_read_status35(double dcycs); void iwm_do_action35(double dcycs); -void iwm_set_apple35_sel(int newval); int iwm_read_c0ec(double dcycs); int read_iwm(int loc, double dcycs); void write_iwm(int loc, int val, double dcycs); @@ -279,20 +304,20 @@ int iwm_read_data(Disk *dsk, int fast_disk_emul, double dcycs); void iwm_write_data(Disk *dsk, word32 val, int fast_disk_emul, double dcycs); void sector_to_partial_nib(byte *in, byte *nib_ptr); int disk_unnib_4x4(Disk *dsk); -int iwm_denib_track525(Disk *dsk, Track *trk, int qtr_track, byte *outbuf); -int iwm_denib_track35(Disk *dsk, Track *trk, int qtr_track, byte *outbuf); +int iwm_denib_track525(Disk *dsk, Trk *trk, int qtr_track, byte *outbuf); +int iwm_denib_track35(Disk *dsk, Trk *trk, int qtr_track, byte *outbuf); int disk_track_to_unix(Disk *dsk, int qtr_track, byte *outbuf); void show_hex_data(byte *buf, int count); void disk_check_nibblization(Disk *dsk, int qtr_track, byte *buf, int size); void disk_unix_to_nib(Disk *dsk, int qtr_track, int unix_pos, int unix_len, int nib_len); -void iwm_nibblize_track_nib525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track); -void iwm_nibblize_track_525(Disk *dsk, Track *trk, byte *track_buf, int qtr_track); -void iwm_nibblize_track_35(Disk *dsk, Track *trk, byte *track_buf, int qtr_track); +void iwm_nibblize_track_nib525(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track); +void iwm_nibblize_track_525(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track); +void iwm_nibblize_track_35(Disk *dsk, Trk *trk, byte *track_buf, int qtr_track); void disk_4x4_nib_out(Disk *dsk, word32 val); void disk_nib_out(Disk *dsk, byte val, int size); void disk_nib_end_track(Disk *dsk); void iwm_show_track(int slot_drive, int track); -void iwm_show_a_track(Track *trk); +void iwm_show_a_track(Trk *trk); /* joystick_driver.c */ @@ -334,9 +359,13 @@ int read_vid_counters(int loc, double dcycs); /* paddles.c */ +void paddle_fixup_joystick_type(void); void paddle_trigger(double dcycs); void paddle_trigger_mouse(double dcycs); -int read_paddles(int paddle, double dcycs); +void paddle_trigger_keypad(double dcycs); +void paddle_update_trigger_dcycs(double dcycs); +int read_paddles(double dcycs, int paddle); +void paddle_update_buttons(void); /* sim65816.c */ @@ -351,11 +380,12 @@ void show_regs(void); void my_exit(int ret); void do_reset(void); void check_engine_asm_defines(void); -byte *memalloc_align(int size, int skip_amt); +byte *memalloc_align(int size, int skip_amt, void **alloc_ptr); void memory_ptr_init(void); int kegsmain(int argc, char **argv); +void load_roms_init_memory(void); void kegs_expand_path(char *out_ptr, const char *in_ptr, int maxlen); -void setup_kegs_file(char *outname, int maxlen, int ok_if_missing, const char **name_ptr); +void setup_kegs_file(char *outname, int maxlen, int ok_if_missing, int can_create_file, const char **name_ptr); void initialize_events(void); void check_for_one_event_type(int type); void add_event_entry(double dcycs, int type); @@ -371,8 +401,8 @@ void show_all_events(void); void show_pmhz(void); void setup_zip_speeds(void); void run_prog(void); -void add_irq(void); -void remove_irq(void); +void add_irq(word32 irq_mask); +void remove_irq(word32 irq_mask); void take_irq(int is_it_brk); void show_dtime_array(void); void update_60hz(double dcycs, double dtime_now); @@ -388,6 +418,11 @@ void do_wdm(word32 arg); void do_wai(void); void do_stp(void); void size_fail(int val, word32 v1, word32 v2); +int fatal_printf(const char *fmt, ...); +int kegs_vprintf(const char *fmt, va_list ap); +void must_write(int fd, char *bufptr, int len); +void clear_fatal_logs(void); +char *kegs_malloc_str(char *in_str); /* smartport.c */ @@ -433,8 +468,6 @@ int doc_read_c03c(double dcycs); int doc_read_c03d(double dcycs); void doc_write_c03c(int val, double dcycs); void doc_write_c03d(int val, double dcycs); -void doc_write_c03e(int val); -void doc_write_c03f(int val); void doc_show_ensoniq_state(int osc); @@ -474,6 +507,7 @@ int video_rebuild_super_hires_palette(word32 scan_info, int line, int reparse); void redraw_changed_super_hires(int start_offset, int start_line, int num_lines, int in_reparse, byte *screen_data); void display_screen(void); void video_update_event_line(int line); +void video_check_input_events(void); void video_update_through_line(int line); void video_refresh_lines(int st_line, int num_lines, int must_reparse); void refresh_border(void); @@ -492,4 +526,5 @@ void video_update_color_array(int col_num, int a2_color); void video_update_colormap(void); void video_update_status_line(int line, const char *string); void video_show_debug_info(void); +word32 float_bus(double dcycs); diff --git a/src/protos_engine_c.h b/src/protos_engine_c.h index 195f3f3..50bb265 100644 --- a/src/protos_engine_c.h +++ b/src/protos_engine_c.h @@ -9,7 +9,7 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsid_protos_engine_c_h[] = "@(#)$KmKId: protos_engine_c.h,v 1.10 2004-01-10 15:50:02-05 kentd Exp $"; +const char rcsid_protos_engine_c_h[] = "@(#)$KmKId: protos_engine_c.h,v 1.11 2004-10-11 22:48:16-04 kentd Exp $"; #endif /* END_HDR */ @@ -20,7 +20,7 @@ word32 get_memory8_io_stub(word32 addr, byte *stat, double *fcycs_ptr, double fp word32 get_memory16_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); word32 get_memory24_pieces_stub(word32 addr, byte *stat, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); void set_memory8_io_stub(word32 addr, word32 val, byte *stat, double *fcycs_ptr, double fplus_x_m1); -void set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); +void set_memory16_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, double fplus_1, double fplus_x_m1, int in_bank); void set_memory24_pieces_stub(word32 addr, word32 val, double *fcycs_ptr, Fplus *fplus_ptr, int in_bank); word32 get_memory_c(word32 addr, int cycs); word32 get_memory16_c(word32 addr, int cycs); diff --git a/src/protos_macdriver.h b/src/protos_macdriver.h index 3fd840f..756cb9e 100644 --- a/src/protos_macdriver.h +++ b/src/protos_macdriver.h @@ -8,13 +8,15 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_protos_mac_h[] = "@(#)$KmKId: protos_macdriver.h,v 1.6 2004-03-23 17:27:31-05 kentd Exp $"; +const char rcsid_protos_mac_h[] = "@(#)$KmKId: protos_macdriver.h,v 1.11 2004-11-14 10:24:03-05 kentd Exp $"; /* END_HDR */ /* macdriver.c */ pascal OSStatus quit_event_handler(EventHandlerCallRef call_ref, EventRef event, void *ignore); -void show_alert(const char *str1, const char *str2, const char *str3, int num); +void show_simple_alert(char *str1, char *str2, char *str3, int num); +void x_dialog_create_kegs_conf(const char *str); +int x_show_alert(int is_fatal, const char *str); pascal OSStatus my_cmd_handler(EventHandlerCallRef handlerRef, EventRef event, void *userdata); void update_window(void); void show_event(UInt32 event_class, UInt32 event_kind, int handled); @@ -37,4 +39,6 @@ void x_push_done(void); void x_auto_repeat_on(int must); void x_auto_repeat_off(int must); void x_hide_pointer(int do_hide); +void x_full_screen(int do_full); +void update_main_window_size(void); diff --git a/src/protos_xdriver.h b/src/protos_xdriver.h index f43bf8d..ad72407 100644 --- a/src/protos_xdriver.h +++ b/src/protos_xdriver.h @@ -8,29 +8,38 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_protos_x_h[] = "@(#)$KmKId: protos_xdriver.h,v 1.18 2002-11-19 03:10:38-05 kadickey Exp $"; +const char rcsid_protos_x_h[] = "@(#)$KmKId: protos_xdriver.h,v 1.19 2004-11-15 16:24:13-05 kentd Exp $"; /* END_HDR */ /* xdriver.c */ int main(int argc, char **argv); +void x_dialog_create_kegs_conf(const char *str); +int x_show_alert(int is_fatal, const char *str); +void x_update_color(int col_num, int red, int green, int blue, word32 rgb); void x_update_physical_colormap(void); void show_xcolor_array(void); int my_error_handler(Display *display, XErrorEvent *ev); void xdriver_end(void); void show_colormap(char *str, Colormap cmap, int index1, int index2, int index3); +void x_badpipe(int signum); void dev_video_init(void); Visual *x_try_find_visual(int depth, int screen_num, XVisualInfo **visual_list_ptr); void x_set_mask_and_shift(word32 x_mask, word32 *mask_ptr, int *shift_left_ptr, int *shift_right_ptr); int xhandle_shm_error(Display *display, XErrorEvent *event); +void x_get_kimage(Kimage *kimage_ptr); int get_shm(Kimage *kimage_ptr); void get_ximage(Kimage *kimage_ptr); -void update_status_line(int line, const char *string); -void redraw_status_lines(void); +void x_redraw_status_lines(void); +void x_push_kimage(Kimage *kimage_ptr, int destx, int desty, int srcx, int srcy, int width, int height); +void x_push_done(void); +int x_update_mouse(int raw_x, int raw_y, int button_states, int buttons_valid); void check_input_events(void); +void x_hide_pointer(int do_hide); void handle_keysym(XEvent *xev_in); int x_keysym_to_a2code(int keysym, int is_up); void x_update_modifier_state(int state); void x_auto_repeat_on(int must); void x_auto_repeat_off(int must); +void x_full_screen(int do_full); diff --git a/src/scc.c b/src/scc.c index b21f5fd..91e482f 100644 --- a/src/scc.c +++ b/src/scc.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_scc_c[] = "@(#)$KmKId: scc.c,v 1.38 2003-11-20 23:50:32-05 kentd Exp $"; +const char rcsid_scc_c[] = "@(#)$KmKId: scc.c,v 1.44 2004-12-03 17:33:40-05 kentd Exp $"; #include "defc.h" @@ -17,9 +17,10 @@ extern int g_code_yellow; extern double g_cur_dcycs; extern int g_raw_serial; extern int g_serial_out_masking; +extern int g_irq_pending; -/* my scc port 0 == channel A = slot 1 */ -/* port 1 == channel B = slot 2 */ +/* my scc port 0 == channel A = slot 1 = c039/c03b */ +/* port 1 == channel B = slot 2 = c038/c03a */ #include "scc.h" #define SCC_R14_DPLL_SOURCE_BRG 0x100 @@ -45,23 +46,39 @@ void scc_init() { Scc *scc_ptr; - int i; + int i, j; for(i = 0; i < 2; i++) { scc_ptr = &(scc_stat[i]); scc_ptr->accfd = -1; + scc_ptr->sockfd = -1; + scc_ptr->socket_state = -1; scc_ptr->rdwrfd = -1; scc_ptr->state = 0; scc_ptr->host_handle = 0; scc_ptr->host_handle2 = 0; - scc_ptr->int_pending_rx = 0; - scc_ptr->int_pending_tx = 0; - scc_ptr->int_pending_zerocnt = 0; scc_ptr->br_event_pending = 0; scc_ptr->rx_event_pending = 0; scc_ptr->tx_event_pending = 0; scc_ptr->char_size = 8; scc_ptr->baud_rate = 9600; + scc_ptr->telnet_mode = 0; + scc_ptr->telnet_iac = 0; + scc_ptr->out_char_dcycs = 0.0; + scc_ptr->socket_num_rings = 0; + scc_ptr->socket_last_ring_dcycs = 0; + scc_ptr->modem_mode = 0; + scc_ptr->modem_dial_or_acc_mode = 0; + scc_ptr->modem_plus_mode = 0; + scc_ptr->modem_s0_val = 0; + scc_ptr->modem_cmd_len = 0; + scc_ptr->modem_cmd_str[0] = 0; + for(j = 0; j < 2; j++) { + scc_ptr->telnet_local_mode[j] = 0; + scc_ptr->telnet_remote_mode[j] = 0; + scc_ptr->telnet_reqwill_mode[j] = 0; + scc_ptr->telnet_reqdo_mode[j] = 0; + } } scc_reset(); @@ -83,6 +100,7 @@ scc_reset() scc_ptr->in_wrptr = 0; scc_ptr->out_rdptr = 0; scc_ptr->out_wrptr = 0; + scc_ptr->dcd = 0; scc_ptr->wantint_rx = 0; scc_ptr->wantint_tx = 0; scc_ptr->wantint_zerocnt = 0; @@ -308,7 +326,7 @@ scc_port_init(int port) } void -scc_try_to_empty_writebuf(int port) +scc_try_to_empty_writebuf(int port, double dcycs) { Scc *scc_ptr; int state; @@ -329,7 +347,7 @@ scc_try_to_empty_writebuf(int port) scc_serial_win_empty_writebuf(port); #endif } else if(state == 1) { - scc_socket_empty_writebuf(port); + scc_socket_empty_writebuf(port, dcycs); } } @@ -337,10 +355,22 @@ void scc_try_fill_readbuf(int port, double dcycs) { Scc *scc_ptr; + int space_used, space_left; int state; scc_ptr = &(scc_stat[port]); state = scc_ptr->state; + + space_used = scc_ptr->in_wrptr - scc_ptr->in_rdptr; + if(space_used < 0) { + space_used += SCC_INBUF_SIZE; + } + space_left = (7*SCC_INBUF_SIZE/8) - space_used; + if(space_left < 1) { + /* Buffer is pretty full, don't try to get more */ + return; + } + #if 0 if(scc_ptr->read_called_this_vbl) { return; @@ -351,13 +381,13 @@ scc_try_fill_readbuf(int port, double dcycs) if(state == 2) { #if defined(MAC) - scc_serial_mac_fill_readbuf(port, dcycs); + scc_serial_mac_fill_readbuf(port, space_left, dcycs); #endif #if defined(_WIN32) - scc_serial_win_fill_readbuf(port, dcycs); + scc_serial_win_fill_readbuf(port, space_left, dcycs); #endif } else if(state == 1) { - scc_socket_fill_readbuf(port, dcycs); + scc_socket_fill_readbuf(port, space_left, dcycs); } } @@ -370,8 +400,8 @@ scc_update(double dcycs) scc_stat[0].read_called_this_vbl = 0; scc_stat[1].read_called_this_vbl = 0; - scc_try_to_empty_writebuf(0); - scc_try_to_empty_writebuf(1); + scc_try_to_empty_writebuf(0, dcycs); + scc_try_to_empty_writebuf(1, dcycs); scc_try_fill_readbuf(0, dcycs); scc_try_fill_readbuf(1, dcycs); @@ -423,6 +453,9 @@ show_scc_state() scc_ptr->reg[j], scc_ptr->reg[j+1], scc_ptr->reg[j+2], scc_ptr->reg[j+3]); } + printf("state: %d, accfd: %d, rdwrfd: %d, host:%p, host2:%p\n", + scc_ptr->state, scc_ptr->accfd, scc_ptr->rdwrfd, + scc_ptr->host_handle, scc_ptr->host_handle2); printf("in_rdptr: %04x, in_wr:%04x, out_rd:%04x, out_wr:%04x\n", scc_ptr->in_rdptr, scc_ptr->in_wrptr, scc_ptr->out_rdptr, scc_ptr->out_wrptr); @@ -430,9 +463,6 @@ show_scc_state() scc_ptr->rx_queue_depth, scc_ptr->rx_queue[0], scc_ptr->rx_queue[1], scc_ptr->rx_queue[2], scc_ptr->rx_queue[3]); - printf("int_pendings: rx:%d, tx:%d, zc:%d\n", - scc_ptr->int_pending_rx, scc_ptr->int_pending_tx, - scc_ptr->int_pending_zerocnt); printf("want_ints: rx:%d, tx:%d, zc:%d\n", scc_ptr->wantint_rx, scc_ptr->wantint_tx, scc_ptr->wantint_zerocnt); @@ -446,6 +476,18 @@ show_scc_state() printf("char_size: %d, baud_rate: %d, mode: %d\n", scc_ptr->char_size, scc_ptr->baud_rate, scc_ptr->mode); + printf("modem_dial_mode:%d, telnet_mode:%d iac:%d, " + "modem_cmd_len:%d\n", scc_ptr->modem_dial_or_acc_mode, + scc_ptr->telnet_mode, scc_ptr->telnet_iac, + scc_ptr->modem_cmd_len); + printf("telnet_loc_modes:%08x %08x, telnet_rem_motes:" + "%08x %08x\n", scc_ptr->telnet_local_mode[0], + scc_ptr->telnet_local_mode[1], + scc_ptr->telnet_remote_mode[0], + scc_ptr->telnet_remote_mode[1]); + printf("modem_mode:%08x plus_mode: %d, out_char_dcycs: %f\n", + scc_ptr->modem_mode, scc_ptr->modem_plus_mode, + scc_ptr->out_char_dcycs); } } @@ -518,7 +560,11 @@ scc_read_reg(int port, double dcycs) switch(regnum) { case 0: case 4: - ret = 0x68; /* 0x44 = no dcd, no cts,0x6c = dcd ok, cts ok*/ + ret = 0x60; /* 0x44 = no dcd, no cts,0x6c = dcd ok, cts ok*/ + if(scc_ptr->dcd) { + ret |= 0x08; + } + ret |= 0x8; /* HACK HACK */ if(scc_ptr->rx_queue_depth) { ret |= 0x01; } @@ -559,12 +605,7 @@ scc_read_reg(int port, double dcycs) case 3: case 7: if(port == 0) { - ret = (scc_stat[1].int_pending_zerocnt) | - (scc_stat[1].int_pending_tx << 1) | - (scc_stat[1].int_pending_rx << 2) | - (scc_stat[0].int_pending_zerocnt << 3) | - (scc_stat[0].int_pending_tx << 4) | - (scc_stat[0].int_pending_rx << 5); + ret = (g_irq_pending & 0x3f); } else { ret = 0; } @@ -608,6 +649,7 @@ scc_write_reg(int port, word32 val, double dcycs) Scc *scc_ptr; word32 old_val; word32 changed_bits; + word32 irq_mask; int regnum; int mode; int tmp1; @@ -654,11 +696,16 @@ scc_write_reg(int port, word32 val, double dcycs) case 0x6: /* reset rr1 bits */ break; case 0x7: /* reset highest pri int pending */ - if(scc_ptr->int_pending_rx) { + irq_mask = g_irq_pending; + if(port == 0) { + /* Move SCC0 ints into SCC1 positions */ + irq_mask = irq_mask >> 3; + } + if(irq_mask & IRQ_PENDING_SCC1_RX) { scc_clr_rx_int(port); - } else if(scc_ptr->int_pending_tx) { + } else if(irq_mask & IRQ_PENDING_SCC1_TX) { scc_clr_tx_int(port); - } else if(scc_ptr->int_pending_zerocnt) { + } else if(irq_mask & IRQ_PENDING_SCC1_ZEROCNT) { scc_clr_zerocnt_int(port); } break; @@ -673,7 +720,7 @@ scc_write_reg(int port, word32 val, double dcycs) break; case 0x1: /* reset rx crc */ case 0x2: /* reset tx crc */ - halt_printf("Wr c03%x to wr0 of %02x!\n", 8+port, val); + printf("Wr c03%x to wr0 of %02x!\n", 8+port, val); break; case 0x3: /* reset tx underrun/eom latch */ /* if no extern status pending, or being reset now */ @@ -850,34 +897,48 @@ void scc_evaluate_ints(int port) { Scc *scc_ptr; + word32 irq_add_mask, irq_remove_mask; int mie; scc_ptr = &(scc_stat[port]); mie = scc_stat[0].reg[9] & 0x8; /* Master int en */ - if(mie && scc_ptr->wantint_rx && !scc_ptr->int_pending_rx) { - scc_ptr->int_pending_rx = 1; - add_irq(); + if(!mie) { + /* There can be no interrupts if MIE=0 */ + remove_irq(IRQ_PENDING_SCC1_RX | IRQ_PENDING_SCC1_TX | + IRQ_PENDING_SCC1_ZEROCNT | + IRQ_PENDING_SCC0_RX | IRQ_PENDING_SCC0_TX | + IRQ_PENDING_SCC0_ZEROCNT); + return; } - if(scc_ptr->int_pending_rx && (!mie || !scc_ptr->wantint_rx)) { - scc_ptr->int_pending_rx = 0; - remove_irq(); + + irq_add_mask = 0; + irq_remove_mask = 0; + if(scc_ptr->wantint_rx) { + irq_add_mask |= IRQ_PENDING_SCC1_RX; + } else { + irq_remove_mask |= IRQ_PENDING_SCC1_RX; } - if(mie && scc_ptr->wantint_tx && !scc_ptr->int_pending_tx) { - scc_ptr->int_pending_tx = 1; - add_irq(); + if(scc_ptr->wantint_tx) { + irq_add_mask |= IRQ_PENDING_SCC1_TX; + } else { + irq_remove_mask |= IRQ_PENDING_SCC1_TX; } - if(scc_ptr->int_pending_tx && (!mie || !scc_ptr->wantint_tx)) { - scc_ptr->int_pending_tx = 0; - remove_irq(); + if(scc_ptr->wantint_zerocnt) { + irq_add_mask |= IRQ_PENDING_SCC1_ZEROCNT; + } else { + irq_remove_mask |= IRQ_PENDING_SCC1_ZEROCNT; } - if(mie && scc_ptr->wantint_zerocnt && !scc_ptr->int_pending_zerocnt) { - scc_ptr->int_pending_zerocnt = 1; - add_irq(); + if(port == 0) { + /* Port 1 is in bits 0-2 and port 0 is in bits 3-5 */ + irq_add_mask = irq_add_mask << 3; + irq_remove_mask = irq_remove_mask << 3; } - if(scc_ptr->int_pending_zerocnt && (!mie || !scc_ptr->wantint_zerocnt)){ - scc_ptr->int_pending_zerocnt = 0; - remove_irq(); + if(irq_add_mask) { + add_irq(irq_add_mask); + } + if(irq_remove_mask) { + remove_irq(irq_remove_mask); } } @@ -1044,11 +1105,33 @@ scc_add_to_readbuf(int port, word32 val, double dcycs) } void -scc_add_to_writebuf(int port, word32 val, double dcycs) +scc_add_to_readbufv(int port, double dcycs, const char *fmt, ...) +{ + va_list ap; + char *bufptr; + int ret, len, c; + int i; + + va_start(ap, fmt); + bufptr = malloc(4096); + bufptr[0] = 0; + ret = vsnprintf(bufptr, 4090, fmt, ap); + len = strlen(bufptr); + for(i = 0; i < len; i++) { + c = bufptr[i]; + if(c == 0x0a) { + scc_add_to_readbuf(port, 0x0d, dcycs); + } + scc_add_to_readbuf(port, c, dcycs); + } + va_end(ap); +} + +void +scc_transmit(int port, word32 val, double dcycs) { Scc *scc_ptr; int out_wrptr; - int out_wrptr_next; int out_rdptr; scc_ptr = &(scc_stat[port]); @@ -1081,6 +1164,31 @@ scc_add_to_writebuf(int port, word32 val, double dcycs) val = val & 0x7f; } + scc_add_to_writebuf(port, val, dcycs); +} + +void +scc_add_to_writebuf(int port, word32 val, double dcycs) +{ + Scc *scc_ptr; + int out_wrptr; + int out_wrptr_next; + int out_rdptr; + + scc_ptr = &(scc_stat[port]); + + /* See if port initialized, if not, do so now */ + if(scc_ptr->state == 0) { + scc_port_init(port); + } + if(scc_ptr->state < 0) { + /* No working serial port, just toss it and go */ + return; + } + + out_wrptr = scc_ptr->out_wrptr; + out_rdptr = scc_ptr->out_rdptr; + out_wrptr_next = (out_wrptr + 1) & (SCC_OUTBUF_SIZE - 1); if(out_wrptr_next != out_rdptr) { scc_ptr->out_buf[out_wrptr] = val; @@ -1144,9 +1252,9 @@ scc_write_data(int port, word32 val, double dcycs) /* local loopback! */ scc_add_to_readbuf(port, val, dcycs); } else { - scc_add_to_writebuf(port, val, dcycs); + scc_transmit(port, val, dcycs); } - scc_try_to_empty_writebuf(port); + scc_try_to_empty_writebuf(port, dcycs); scc_maybe_tx_event(port, dcycs); } diff --git a/src/scc.h b/src/scc.h index ace256c..33804ae 100644 --- a/src/scc.h +++ b/src/scc.h @@ -9,30 +9,41 @@ /************************************************************************/ #ifdef INCLUDE_RCSID_C -const char rcsid_scc_h[] = "@(#)$KmKId: scc.h,v 1.12 2003-11-21 00:27:00-05 kentd Exp $"; +const char rcsid_scc_h[] = "@(#)$KmKId: scc.h,v 1.17 2004-12-03 14:03:12-05 kentd Exp $"; #endif +#include + #ifdef _WIN32 -# include +# include #else # include # include +# include #endif -#if defined(HPUX) || defined(__linux__) || defined(SOLARIS) || defined(MAC) || defined(__MACH__) +#if defined(HPUX) || defined(__linux__) || defined(SOLARIS) || defined(MAC) || defined(__MACH__) || defined(_WIN32) # define SCC_SOCKETS #endif /* my scc port 0 == channel A, port 1 = channel B */ -#define SCC_INBUF_SIZE 4096 /* must be a power of 2 */ -#define SCC_OUTBUF_SIZE 4096 /* must be a power of 2 */ +#define SCC_INBUF_SIZE 512 /* must be a power of 2 */ +#define SCC_OUTBUF_SIZE 512 /* must be a power of 2 */ + +#define SCC_MODEM_MAX_CMD_STR 128 + +#ifndef SOCKET +# define SOCKET word32 /* for non-windows */ +#endif STRUCT(Scc) { int port; int state; int accfd; + SOCKET sockfd; + int socket_state; int rdwrfd; void *host_handle; void *host_handle2; @@ -60,9 +71,7 @@ STRUCT(Scc) { int wantint_rx; int wantint_tx; int wantint_zerocnt; - int int_pending_rx; - int int_pending_tx; - int int_pending_zerocnt; + int dcd; double br_dcycs; double tx_dcycs; @@ -74,5 +83,24 @@ STRUCT(Scc) { int char_size; int baud_rate; + double out_char_dcycs; + + int socket_num_rings; + int socket_last_ring_dcycs; + word32 modem_mode; + int modem_dial_or_acc_mode; + int modem_plus_mode; + int modem_s0_val; + int telnet_mode; + int telnet_iac; + word32 telnet_local_mode[2]; + word32 telnet_remote_mode[2]; + word32 telnet_reqwill_mode[2]; + word32 telnet_reqdo_mode[2]; + int modem_cmd_len; + byte modem_cmd_str[SCC_MODEM_MAX_CMD_STR + 5]; }; +#define SCCMODEM_NOECHO 0x0001 +#define SCCMODEM_NOVERBOSE 0x0002 + diff --git a/src/scc_macdriver.c b/src/scc_macdriver.c index 11c4184..23f3bf6 100644 --- a/src/scc_macdriver.c +++ b/src/scc_macdriver.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_scc_macdriver_c[] = "@(#)$KmKId: scc_macdriver.c,v 1.3 2003-11-03 01:52:49-05 kentd Exp $"; +const char rcsid_scc_macdriver_c[] = "@(#)$KmKId: scc_macdriver.c,v 1.5 2004-11-25 13:32:51-05 kentd Exp $"; /* This file contains the Mac serial calls */ @@ -35,7 +35,8 @@ scc_serial_mac_init(int port) scc_ptr->state = 0; /* mark as uninitialized */ - sprintf(&str_buf[0], "/dev/tty.USA19QW11P1.1"); + /*sprintf(&str_buf[0], "/dev/tty.USA19QW11P1.1"); */ + sprintf(&str_buf[0], "/dev/tty.USA19H181P1.1"); /* HACK: fix this... */ fd = open(&str_buf[0], O_RDWR | O_NONBLOCK); @@ -129,7 +130,7 @@ scc_serial_mac_change_params(int port) } void -scc_serial_mac_fill_readbuf(int port, double dcycs) +scc_serial_mac_fill_readbuf(int port, int space_left, double dcycs) { byte tmp_buf[256]; Scc *scc_ptr; @@ -145,7 +146,8 @@ scc_serial_mac_fill_readbuf(int port, double dcycs) } /* Try reading some bytes */ - ret = read(fd, tmp_buf, 256); + space_left = MIN(space_left, 256); + ret = read(fd, tmp_buf, space_left); if(ret > 0) { for(i = 0; i < ret; i++) { diff --git a/src/scc_socket_driver.c b/src/scc_socket_driver.c index 1decca5..f2ebf5c 100644 --- a/src/scc_socket_driver.c +++ b/src/scc_socket_driver.c @@ -1,6 +1,6 @@ /************************************************************************/ /* KEGS: Apple //gs Emulator */ -/* Copyright 2002 by Kent Dickey */ +/* Copyright 2002-2004 by Kent Dickey */ /* */ /* This code is covered by the GNU GPL */ /* */ @@ -8,41 +8,95 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_scc_socket_driver_c[] = "@(#)$KmKId: scc_socket_driver.c,v 1.4 2003-11-20 23:43:41-05 kentd Exp $"; +const char rcsid_scc_socket_driver_c[] = "@(#)$KmKId: scc_socket_driver.c,v 1.11 2004-12-06 19:42:09-05 kentd Exp $"; -/* This file contains the Unix socket calls */ +/* This file contains the socket calls */ #include "defc.h" #include "scc.h" #include extern Scc scc_stat[2]; +extern int g_serial_modem[]; + +extern int h_errno; +int g_wsastartup_called = 0; + +/* Usage: scc_socket_init() called to init socket mode */ +/* At all times, we try to have a listen running on the incoming socket */ +/* If we want to dial out, we close the incoming socket and create a new */ +/* outgoing socket. Any hang-up causes the socket to be closed and it will */ +/* then re-open on a subsequent call to scc_socket_open */ void scc_socket_init(int port) { -#ifdef SCC_SOCKETS + Scc *scc_ptr; + +#ifdef _WIN32 + WSADATA wsadata; + int ret; + + if(g_wsastartup_called == 0) { + ret = WSAStartup(MAKEWORD(2,0), &wsadata); + printf("WSAStartup ret: %d\n", ret); + g_wsastartup_called = 1; + } +#endif + scc_ptr = &(scc_stat[port]); + scc_ptr->state = 1; /* successful socket */ + scc_ptr->sockfd = -1; /* Indicate no socket open yet */ + scc_ptr->accfd = -1; /* Indicate no socket open yet */ + scc_ptr->rdwrfd = -1; /* Indicate no socket open yet */ + scc_ptr->socket_state = -2; /* 0 means talk to "modem" */ + /* 1 connected */ + scc_ptr->socket_num_rings = 0; + scc_ptr->socket_last_ring_dcycs = 0; + scc_ptr->dcd = 0; /* 0 means no carrier */ + scc_ptr->modem_s0_val = 0; + scc_ptr->host_aux1 = sizeof(struct sockaddr_in); + scc_ptr->host_handle = malloc(scc_ptr->host_aux1); + /* Real init will be done when bytes need to be read/write from skt */ +} + +void +scc_socket_maybe_open_incoming(int port, double dcycs) +{ Scc *scc_ptr; struct sockaddr_in sa_in; int on; - int flags; int ret; - int sockfd; + SOCKET sockfd; int inc; inc = 0; scc_ptr = &(scc_stat[port]); - scc_ptr->state = -1; /* mark as failed for now */ - scc_ptr->host_aux1 = sizeof(struct sockaddr_in); - scc_ptr->host_handle = malloc(scc_ptr->host_aux1); + if(scc_ptr->sockfd != -1) { + /* it's already open, get out */ + return; + } + if(scc_ptr->socket_state < 0) { + /* not initialized, get out */ + return; + } + + printf("scc socket close being called from socket_open_out\n"); + scc_socket_close(port, 0, dcycs); + + scc_ptr->socket_state = 0; + scc_ptr->socket_num_rings = 0; + memset(scc_ptr->host_handle, 0, scc_ptr->host_aux1); while(1) { sockfd = socket(AF_INET, SOCK_STREAM, 0); - if(sockfd < 0) { + printf("sockfd ret: %d\n", sockfd); + if(sockfd == -1) { printf("socket ret: %d, errno: %d\n", sockfd, errno); + scc_socket_close(port, 0, dcycs); + scc_ptr->socket_state = -1; return; } /* printf("socket ret: %d\n", sockfd); */ @@ -53,6 +107,8 @@ scc_socket_init(int port) if(ret < 0) { printf("setsockopt REUSEADDR ret: %d, err:%d\n", ret, errno); + scc_socket_close(port, 0, dcycs); + scc_ptr->socket_state = -1; return; } @@ -63,65 +119,239 @@ scc_socket_init(int port) ret = bind(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in)); - if(ret < 0) { - printf("bind ret: %d, errno: %d\n", ret, errno); - inc++; - close(sockfd); - printf("Trying next port: %d\n", 6501 + port + inc); - if(inc >= 10) { - printf("Too many retries, quitting\n"); - return; - } - } else { + if(ret >= 0) { + ret = listen(sockfd, 1); break; } + /* else ret to bind was < 0 */ + printf("bind ret: %d, errno: %d\n", ret, errno); + inc++; + close(sockfd); + printf("Trying next port: %d\n", 6501 + port + inc); + if(inc >= 10) { + printf("Too many retries, quitting\n"); + scc_socket_close(port, 0, dcycs); + scc_ptr->socket_state = -1; + return; + } } printf("SCC port %d is at unix port %d\n", port, 6501 + port + inc); - ret = listen(sockfd, 1); + scc_ptr->sockfd = sockfd; + scc_ptr->state = 1; /* successful socket */ + scc_socket_make_nonblock(port, dcycs); + +} + +void +scc_socket_open_outgoing(int port, double dcycs) +{ + Scc *scc_ptr; + struct sockaddr_in sa_in; + struct hostent *hostentptr; + int on; + int ret; + SOCKET sockfd; + + scc_ptr = &(scc_stat[port]); + + printf("scc socket close being called from socket_open_out\n"); + scc_socket_close(port, 0, dcycs); + + scc_ptr->socket_state = 0; + + memset(scc_ptr->host_handle, 0, scc_ptr->host_aux1); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + printf("sockfd ret: %d\n", sockfd); + if(sockfd == -1) { + printf("socket ret: %d, errno: %d\n", sockfd, errno); + scc_socket_close(port, 1, dcycs); + return; + } + /* printf("socket ret: %d\n", sockfd); */ + + on = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)); + if(ret < 0) { + printf("setsockopt REUSEADDR ret: %d, err:%d\n", + ret, errno); + scc_socket_close(port, 1, dcycs); + return; + } + + memset(&sa_in, 0, sizeof(sa_in)); + sa_in.sin_family = AF_INET; + sa_in.sin_port = htons(23); + hostentptr = gethostbyname(&scc_ptr->modem_cmd_str[0]); + if(hostentptr == 0) { +#ifdef _WIN32 + fatal_printf("Lookup host %s failed\n", + &scc_ptr->modem_cmd_str[0]); +#else + fatal_printf("Lookup host %s failed, herrno: %d\n", + &scc_ptr->modem_cmd_str[0], h_errno); +#endif + close(sockfd); + scc_socket_close(port, 1, dcycs); + x_show_alert(0, 0); + return; + } + memcpy(&sa_in.sin_addr.s_addr, hostentptr->h_addr, + hostentptr->h_length); + /* The above copies the 32-bit internet address into */ + /* sin_addr.s_addr. It's in correct network format */ + + ret = connect(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in)); + if(ret < 0) { + printf("connect ret: %d, errno: %d\n", ret, errno); + close(sockfd); + scc_socket_close(port, 1, dcycs); + return; + } + scc_socket_modem_connect(port, dcycs); + scc_ptr->dcd = 1; /* carrier on */ + scc_ptr->socket_state = 1; /* talk to socket */ + scc_ptr->socket_num_rings = 0; + + printf("SCC port %d is now outgoing to %s\n", port, + &scc_ptr->modem_cmd_str[0]); + + scc_ptr->sockfd = sockfd; + scc_ptr->state = 1; /* successful socket */ + + scc_socket_make_nonblock(port, dcycs); + scc_ptr->rdwrfd = scc_ptr->sockfd; +} + +void +scc_socket_make_nonblock(int port, double dcycs) +{ + Scc *scc_ptr; + SOCKET sockfd; + int ret; +#ifdef _WIN32 + u_long flags; +#else + int flags; +#endif + + scc_ptr = &(scc_stat[port]); + sockfd = scc_ptr->sockfd; + +#ifdef _WIN32 + flags = 1; + ret = ioctlsocket(sockfd, FIONBIO, &flags); + if(ret != 0) { + printf("ioctlsocket ret: %d\n", ret); + } +#else flags = fcntl(sockfd, F_GETFL, 0); if(flags == -1) { printf("fcntl GETFL ret: %d, errno: %d\n", flags, errno); + scc_socket_close(port, 1, dcycs); + scc_ptr->socket_state = -1; return; } ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); if(ret == -1) { printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno); + scc_socket_close(port, 1, dcycs); + scc_ptr->socket_state = -1; return; } - - scc_ptr->accfd = sockfd; - scc_ptr->state = 1; /* successful socket */ -#endif /* SCC_SOCKETS */ +#endif } void scc_socket_change_params(int port) { -#ifdef SCC_SOCKETS -#endif } void -scc_accept_socket(int port) +scc_socket_close(int port, int full_close, double dcycs) +{ + Scc *scc_ptr; + int rdwrfd; + SOCKET sockfd; + int i; + + scc_ptr = &(scc_stat[port]); + + printf("In scc_socket_close, %d, %d, %f\n", port, full_close, dcycs); + + rdwrfd = scc_ptr->rdwrfd; + if(rdwrfd >= 0) { + printf("socket_close: rdwrfd=%d, closing\n", rdwrfd); + close(rdwrfd); + } + sockfd = scc_ptr->sockfd; + if(sockfd != -1) { + printf("socket_close: sockfd=%d, closing\n", sockfd); + close(sockfd); + } + + scc_ptr->modem_cmd_len = 0; + scc_ptr->telnet_mode = 0; + scc_ptr->telnet_iac = 0; + for(i = 0; i < 2; i++) { + scc_ptr->telnet_local_mode[i] = 0; + scc_ptr->telnet_remote_mode[i] = 0; + scc_ptr->telnet_reqwill_mode[i] = 0; + scc_ptr->telnet_reqdo_mode[i] = 0; + } + scc_ptr->rdwrfd = -1; + scc_ptr->sockfd = -1; + scc_ptr->dcd = 0; + scc_ptr->socket_num_rings = 0; + + if(!full_close) { + return; + } + + scc_socket_modem_hangup(port, dcycs); + + /* and go back to modem mode */ + scc_ptr->socket_state = 0; + if(g_serial_modem[port]) { + scc_ptr->modem_dial_or_acc_mode = 0; + } else { + scc_ptr->modem_dial_or_acc_mode = 2; /* always accept */ + } +} + +void +scc_accept_socket(int port, double dcycs) { #ifdef SCC_SOCKETS Scc *scc_ptr; int flags; + int num_rings; int rdwrfd; int ret; scc_ptr = &(scc_stat[port]); - if(scc_ptr->rdwrfd <= 0) { - rdwrfd = accept(scc_ptr->accfd, scc_ptr->host_handle, - &(scc_ptr->host_aux1)); + if(scc_ptr->sockfd == -1) { + printf("in accept_socket, call socket_open\n"); + scc_socket_maybe_open_incoming(port, dcycs); + } + if(scc_ptr->sockfd == -1) { + return; /* just give up */ + } + if(scc_ptr->rdwrfd == -1) { + rdwrfd = accept(scc_ptr->sockfd, scc_ptr->host_handle, + &(scc_ptr->host_aux1)); if(rdwrfd < 0) { return; } + flags = 0; + ret = 0; +#ifndef _WIN32 /* For Linux, we need to set O_NONBLOCK on the rdwrfd */ flags = fcntl(rdwrfd, F_GETFL, 0); if(flags == -1) { @@ -133,70 +363,312 @@ scc_accept_socket(int port) printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno); return; } - +#endif scc_ptr->rdwrfd = rdwrfd; + printf("Set port[%d].rdwrfd = %d\n", port, rdwrfd); + + num_rings = 4; + if(scc_ptr->modem_s0_val > 0) { + num_rings = scc_ptr->modem_s0_val; + } + scc_ptr->socket_num_rings = num_rings; + scc_ptr->socket_last_ring_dcycs = 0; /* do ring now*/ + scc_socket_modem_do_ring(port, dcycs); + + /* and send some telnet codes */ + scc_ptr->telnet_reqwill_mode[0] = 0xa; /* 3=GO_AH and 1=ECHO */ + scc_ptr->telnet_reqdo_mode[0] = 0xa; /* 3=GO_AH and 1=ECHO */ +#if 0 + scc_ptr->telnet_reqdo_mode[1] = 0x4; /* 34=LINEMODE */ +#endif } #endif } void -scc_socket_fill_readbuf(int port, double dcycs) +scc_socket_telnet_reqs(int port, double dcycs) +{ + Scc *scc_ptr; + word32 mask, willmask, domask; + int i, j; + + scc_ptr = &(scc_stat[port]); + + for(i = 0; i < 64; i++) { + j = i >> 5; + mask = 1 << (i & 31); + willmask = scc_ptr->telnet_reqwill_mode[j]; + if(willmask & mask) { + scc_add_to_writebuf(port, 0xff, dcycs); + scc_add_to_writebuf(port, 0xfb, dcycs); /* WILL */ + scc_add_to_writebuf(port, i, dcycs); + } + domask = scc_ptr->telnet_reqdo_mode[j]; + if(domask & mask) { + scc_add_to_writebuf(port, 0xff, dcycs); + scc_add_to_writebuf(port, 0xfd, dcycs); /* DO */ + scc_add_to_writebuf(port, i, dcycs); + } + } +} + +void +scc_socket_fill_readbuf(int port, int space_left, double dcycs) { #ifdef SCC_SOCKETS byte tmp_buf[256]; Scc *scc_ptr; int rdwrfd; - int i; int ret; + int i; scc_ptr = &(scc_stat[port]); - /* Accept socket if not already open */ - scc_accept_socket(port); + scc_accept_socket(port, dcycs); + scc_socket_modem_do_ring(port, dcycs); + if(scc_ptr->socket_state == 0 && g_serial_modem[port]) { + /* Just get out, this is modem mode */ + /* The transmit function stuffs any bytes in receive buf */ + return; + } rdwrfd = scc_ptr->rdwrfd; if(rdwrfd < 0) { - return; + return; /* just get out */ } /* Try reading some bytes */ - ret = read(rdwrfd, tmp_buf, 256); + space_left = MIN(space_left, 256); + ret = recv(rdwrfd, tmp_buf, space_left, 0); if(ret > 0) { for(i = 0; i < ret; i++) { if(tmp_buf[i] == 0) { /* Skip null chars */ continue; } - scc_add_to_readbuf(port, tmp_buf[i], dcycs); + scc_socket_recvd_char(port, tmp_buf[i], dcycs); } } else if(ret == 0) { /* assume socket close */ - close(rdwrfd); - scc_ptr->rdwrfd = -1; + printf("recv got 0 from rdwrfd=%d, closing\n", rdwrfd); + scc_socket_close(port, 1, dcycs); } #endif } +int g_scc_dbg_print_cnt = 50; + void -scc_socket_empty_writebuf(int port) +scc_socket_recvd_char(int port, int c, double dcycs) +{ + Scc *scc_ptr; + word32 locmask, remmask, mask; + word32 reqwillmask, reqdomask; + int telnet_mode, telnet_iac; + int eff_c, cpos; + int reply; + + scc_ptr = &(scc_stat[port]); + + scc_socket_maybe_open_incoming(port, dcycs); + + telnet_mode = scc_ptr->telnet_mode; + telnet_iac = scc_ptr->telnet_iac; + if(c >= 0xf0 || telnet_mode || telnet_iac) { + g_scc_dbg_print_cnt = 50; + } +#if 0 + if(g_scc_dbg_print_cnt) { + printf("Recv: %02x mode: %d\n", c, telnet_mode); + g_scc_dbg_print_cnt--; + } +#endif + + eff_c = c; + if(telnet_iac == 0) { + if(c == 0xff) { + scc_ptr->telnet_iac = 0xff; + return; /* and just get out */ + } + } else { + /* last char was 0xff, see if this is 0xff */ + if(c != 0xff) { + /* this is some kind of command */ + eff_c = eff_c | 0x100; /* indicate prev char IAC */ + } + } + scc_ptr->telnet_iac = 0; + + mask = 1 << (c & 31); + cpos = (c >> 5) & 1; + locmask = scc_ptr->telnet_local_mode[cpos] & mask; + remmask = scc_ptr->telnet_remote_mode[cpos] & mask; + reqwillmask = scc_ptr->telnet_reqwill_mode[cpos] & mask; + reqdomask = scc_ptr->telnet_reqdo_mode[cpos] & mask; + switch(telnet_mode) { + case 0: /* just passing through bytes */ + switch(eff_c) { + case 0x1fe: /* DON'T */ + case 0x1fd: /* DO */ + case 0x1fc: /* WON'T */ + case 0x1fb: /* WILL */ + case 0x1fa: /* SB */ + telnet_mode = c; + break; + default: + if(eff_c < 0x100) { + scc_add_to_readbuf(port, c, dcycs); + } + break; + } + break; + case 3: /* LINEMODE SB SLC, octet 0 */ + if(eff_c == 0x1f0) { + /* SE, the end */ + telnet_mode = 0; + } + printf("LINEMODE SLC octet 0: %02x\n", c); + telnet_mode = 4; + break; + case 4: /* LINEMODE SB SLC, octet 1 */ + printf("LINEMODE SLC octet 1: %02x\n", c); + telnet_mode = 5; + if(eff_c == 0x1f0) { + /* SE, the end */ + printf("Got SE at octet 1...\n"); + telnet_mode = 0; + } + break; + case 5: /* LINEMODE SB SLC, octet 2 */ + printf("LINEMODE SLC octet 2: %02x\n", c); + telnet_mode = 3; + if(eff_c == 0x1f0) { + /* SE, the end */ + printf("Got SE at octet 2...\n"); + telnet_mode = 0; + } + break; + case 34: /* LINEMODE SB beginning */ + switch(c) { + case 3: /* SLC */ + telnet_mode = 3; + break; + default: + telnet_mode = 0xee; /* go to SB eat */ + break; + } + break; + case 0xfa: /* in 0xfa = SB mode, eat up subcommands */ + switch(c) { + case 34: /* LINEMODE */ + telnet_mode = 34; + break; + default: + telnet_mode = 0xee; /* SB eat mode */ + break; + } + break; + case 0xee: /* in SB eat mode */ + if(eff_c == 0x1f0) { /* SE, end of sub-command */ + telnet_mode = 0; + } else { + /* just stay in eat mode */ + } + break; + case 0xfe: /* previous char was "DON'T" */ + if(locmask && (reqwillmask == 0)) { + /* it's a mode change */ + /* always OK to turn off a mode that we had on */ + scc_add_to_writebuf(port, 0xff, dcycs); + scc_add_to_writebuf(port, 0xfc, dcycs); /* WON'T */ + scc_add_to_writebuf(port, c, dcycs); + } + scc_ptr->telnet_local_mode[cpos] &= ~mask; + scc_ptr->telnet_reqwill_mode[cpos] &= ~mask; + telnet_mode = 0; + break; + case 0xfd: /* previous char was "DO" */ + reply = 0xfc; + if(locmask == 0 && (reqwillmask == 0)) { + /* it's a mode change, send some response */ + reply = 0xfc; /* nack it with WON'T */ + if(c == 0x03 || c == 0x01) { + reply = 0xfb; /* Ack with WILL */ + } + scc_add_to_writebuf(port, 0xff, dcycs); + scc_add_to_writebuf(port, reply, dcycs); + scc_add_to_writebuf(port, c, dcycs); + } + if(reqwillmask || (reply == 0xfb)) { + scc_ptr->telnet_local_mode[cpos] |= mask; + } + scc_ptr->telnet_reqwill_mode[cpos] &= ~mask; + telnet_mode = 0; + break; + case 0xfc: /* previous char was "WON'T" */ + if(remmask && (reqdomask == 0)) { + /* it's a mode change, ack with DON'T */ + scc_add_to_writebuf(port, 0xff, dcycs); + scc_add_to_writebuf(port, 0xfe, dcycs); /* DON'T */ + scc_add_to_writebuf(port, c, dcycs); + } + scc_ptr->telnet_remote_mode[cpos] &= ~mask; + scc_ptr->telnet_reqdo_mode[cpos] &= ~mask; + telnet_mode = 0; + break; + case 0xfb: /* previous char was "WILL" */ + reply = 0xfe; /* nack it with DON'T */ + if(remmask == 0 && (reqdomask == 0)) { + /* it's a mode change, send some response */ + if(c == 0x03 || c == 0x01) { + reply = 0xfd; /* Ack with DO */ + } + scc_add_to_writebuf(port, 0xff, dcycs); + scc_add_to_writebuf(port, reply, dcycs); + scc_add_to_writebuf(port, c, dcycs); + } + if(reqdomask || (reply == 0xfd)) { + scc_ptr->telnet_remote_mode[cpos] |= mask; + } + scc_ptr->telnet_reqdo_mode[cpos] &= ~mask; + telnet_mode = 0; + break; + default: + telnet_mode = 0; + break; + } + scc_ptr->telnet_mode = telnet_mode; +} + +void +scc_socket_empty_writebuf(int port, double dcycs) { #ifdef SCC_SOCKETS +# ifndef _WIN32 struct sigaction newact, oldact; +# endif Scc *scc_ptr; + double diff_dcycs; + int plus_mode; int rdptr; int wrptr; int rdwrfd; int done; int ret; int len; + int c; + int i; scc_ptr = &(scc_stat[port]); - scc_accept_socket(port); - - rdwrfd = scc_ptr->rdwrfd; - if(rdwrfd < 0) { - return; + /* See if +++ done and we should go to command mode */ + diff_dcycs = dcycs - scc_ptr->out_char_dcycs; + if((diff_dcycs > 900.0*1000) && (scc_ptr->modem_plus_mode == 3) && + (scc_ptr->socket_state >= 1) && + (g_serial_modem[port] != 0)) { + scc_ptr->socket_state = 0; /* go modem mode, stay connect*/ + scc_ptr->modem_plus_mode = 0; + scc_socket_send_modem_code(port, 0, dcycs); } /* Try writing some bytes */ @@ -208,6 +680,7 @@ scc_socket_empty_writebuf(int port) done = 1; break; } + rdwrfd = scc_ptr->rdwrfd; len = wrptr - rdptr; if(len < 0) { len = SCC_OUTBUF_SIZE - rdptr; @@ -220,26 +693,73 @@ scc_socket_empty_writebuf(int port) break; } - /* ignore SIGPIPE around writes to the socket, so we can */ - /* catch a closed socket and prepare to re-accept a new */ - /* connection. Otherwise, SIGPIPE kills KEGS */ - sigemptyset(&newact.sa_mask); - newact.sa_handler = SIG_IGN; - newact.sa_flags = 0; - sigaction(SIGPIPE, &newact, &oldact); - - ret = write(rdwrfd, &(scc_ptr->out_buf[rdptr]), len); + if(scc_ptr->socket_state < 1 && g_serial_modem[port]) { + len = 1; + scc_socket_modem_write(port, scc_ptr->out_buf[rdptr], + dcycs); + ret = 1; + } else { + if(rdwrfd == -1) { + if(g_serial_modem[port]) { + printf("socket_state: %d, ser_mod: %d, " + "rdwrfd: %d\n", + scc_ptr->socket_state, + g_serial_modem[port], rdwrfd); + } + scc_ptr->socket_state = 0; + scc_socket_maybe_open_incoming(port, dcycs); + return; + } + for(i = 0; i < len; i++) { + c = scc_ptr->out_buf[rdptr + i]; + plus_mode = scc_ptr->modem_plus_mode; + diff_dcycs = dcycs - scc_ptr->out_char_dcycs; + if(c == '+' && plus_mode == 0) { + if(diff_dcycs > 500*1000) { + scc_ptr->modem_plus_mode = 1; + } + } else if(c == '+') { + if(diff_dcycs < 800.0*1000) { + plus_mode++; + scc_ptr->modem_plus_mode = + plus_mode; + } + } else { + scc_ptr->modem_plus_mode = 0; + } + scc_ptr->out_char_dcycs = dcycs; + } - sigaction(SIGPIPE, &oldact, 0); +# ifdef _WIN32 + ret = send(rdwrfd, &(scc_ptr->out_buf[rdptr]), len, 0); +# else + /* ignore SIGPIPE around writes to the socket, so we */ + /* can catch a closed socket and prepare to accept */ + /* a new connection. Otherwise, SIGPIPE kills KEGS */ + sigemptyset(&newact.sa_mask); + newact.sa_handler = SIG_IGN; + newact.sa_flags = 0; + sigaction(SIGPIPE, &newact, &oldact); + + ret = send(rdwrfd, &(scc_ptr->out_buf[rdptr]), len, 0); + + sigaction(SIGPIPE, &oldact, 0); /* restore previous SIGPIPE behavior */ +# endif /* WIN32 */ + +#if 0 + printf("sock output: %02x\n", scc_ptr->out_buf[rdptr]); +#endif + + } if(ret == 0) { done = 1; /* give up for now */ break; } else if(ret < 0) { /* assume socket is dead */ - close(rdwrfd); - scc_ptr->rdwrfd = -1; + printf("socket write failed, resuming modem mode\n"); + scc_socket_close(port, 1, dcycs); done = 1; break; } else { @@ -253,3 +773,360 @@ scc_socket_empty_writebuf(int port) #endif } +void +scc_socket_modem_write(int port, int c, double dcycs) +{ + Scc *scc_ptr; + char *str; + word32 modem_mode; + int do_echo; + int got_at; + int len; + + scc_ptr = &(scc_stat[port]); + + if(scc_ptr->sockfd == -1) { + scc_ptr->socket_state = 0; + scc_socket_maybe_open_incoming(port, dcycs); + } + + modem_mode = scc_ptr->modem_mode; + str = &(scc_ptr->modem_cmd_str[0]); + +#if 0 + printf("M: %02x\n", c); +#endif + do_echo = ((modem_mode & SCCMODEM_NOECHO) == 0); + len = scc_ptr->modem_cmd_len; + got_at = 0; + if(len >= 2 && str[0] == 'a' && str[1] == 't') { + /* we've got an 'at', do not back up past it */ + got_at = 1; + } + if(c == 0x0d) { + if(do_echo) { + scc_add_to_readbuf(port, c, dcycs); /* echo cr */ + scc_add_to_readbuf(port, 0x0a, dcycs); /* echo lf */ + } + do_echo = 0; /* already did the echo */ + scc_socket_do_cmd_str(port, dcycs); + scc_ptr->modem_cmd_len = 0; + len = 0; + str[0] = 0; + } else if(c == 0x08) { + if(len <= 0) { + do_echo = 0; /* do not go past left margin */ + } else if(len == 2 && got_at) { + do_echo = 0; /* do not erase "AT" */ + } else { + /* erase a character */ + len--; + str[len] = 0; + } + } else if(c < 0x20) { + /* ignore all control characters, don't echo */ + /* includes line feeds and nulls */ + do_echo = 0; + } else { + /* other characters */ + if(len < SCC_MODEM_MAX_CMD_STR) { + str[len] = tolower(c); + str[len+1] = 0; + len++; + } + } + scc_ptr->modem_cmd_len = len; + if(do_echo) { + scc_add_to_readbuf(port, c, dcycs); /* echo */ + } +} + +void +scc_socket_do_cmd_str(int port, double dcycs) +{ + Scc *scc_ptr; + char *str; + int pos, len; + int ret_val; + int reg, reg_val; + int was_amp; + int c; + int i; + + scc_ptr = &(scc_stat[port]); + + str = &(scc_ptr->modem_cmd_str[0]); + printf("Got modem string :%s:=%02x %02x %02x\n", str, str[0], str[1], + str[2]); + + len = scc_ptr->modem_cmd_len; + str[len] = 0; + str[len+1] = 0; + str[len+2] = 0; + pos = -1; + if(len < 2) { + /* just ignore it */ + return; + } + if(str[0] != 'a' || str[1] != 't') { + return; + } + + /* Some AT command received--make sure socket 6501/6502 is open */ + printf("Some AT command received, sockfd=%d\n", scc_ptr->sockfd); + + pos = 2 - 1; + ret_val = 0; /* "OK" */ + was_amp = 0; + while(++pos < len) { + c = str[pos] + was_amp; + was_amp = 0; + switch(c) { + case '&': /* at& */ + was_amp = 0x100; + break; + case 'z': /* atz */ + scc_ptr->modem_mode = 0; + scc_ptr->modem_s0_val = 0; + pos = len; /* ignore any other commands */ + break; + case 'e': /* ate = echo */ + c = str[pos+1]; + if(c == '1') { + scc_ptr->modem_mode &= ~SCCMODEM_NOECHO; + pos++; + } else { + scc_ptr->modem_mode |= SCCMODEM_NOECHO; + pos++; + } + break; + case 'v': /* atv = verbose */ + c = str[pos+1]; + if(c == '1') { + scc_ptr->modem_mode &= ~SCCMODEM_NOVERBOSE; + pos++; + } else { + scc_ptr->modem_mode |= SCCMODEM_NOVERBOSE; + pos++; + } + break; + case 'o': /* ato = go online */ + printf("ato\n"); + if(scc_ptr->dcd && (scc_ptr->rdwrfd != -1) && + (scc_ptr->socket_state == 0)) { + printf("Going back online\n"); + scc_ptr->socket_state = 1; + scc_socket_modem_connect(port, dcycs); + ret_val = -1; + } + break; + case 'h': /* ath = hang up */ + printf("ath, hanging up\n"); + scc_socket_close(port, (scc_ptr->rdwrfd != -1), dcycs); + /* scc_socket_maybe_open_incoming(port, dcycs); */ + /* reopen listen */ + break; + case 'a': /* ata */ + printf("Doing ATA\n"); + scc_socket_do_answer(port, dcycs); + ret_val = -1; + break; + case 'd': /* atd */ + pos++; + c = str[pos]; + if(c == 't' || c == 'p') { + /* skip tone or pulse */ + pos++; + } + /* see if it is 111 */ + if(strcmp(&str[pos], "111") == 0) { + /* Do PPP! */ + } else { + /* get string to connect to */ + /* Shift string so hostname moves to str[0] */ + for(i = 0; i < len; i++) { + str[i] = str[pos]; + if(pos >= len) { + break; + } + pos++; + } + + } + scc_ptr->modem_dial_or_acc_mode = 1; + scc_socket_open_outgoing(port, dcycs); + ret_val = -1; + pos = len; /* always eat rest of the line */ + break; + case 's': /* atsnn=yy */ + pos++; + reg = 0; + while(1) { + c = str[pos]; + if(c < '0' || c > '9') { + break; + } + reg = (reg * 10) + c - '0'; + pos++; + } + if(c == '?') { + /* display S-register */ + if(reg == 0) { + scc_add_to_readbufv(port, dcycs, + "S0=%d\n", + scc_ptr->modem_s0_val); + } + break; + } + if(c != '=') { + break; + } + pos++; + reg_val = 0; + while(1) { + c = str[pos]; + if(c < '0' || c >'9') { + break; + } + reg_val = (reg_val * 10) + c - '0'; + pos++; + } + printf("ats%d = %d\n", reg, reg_val); + if(reg == 0) { + scc_ptr->modem_s0_val = reg_val; + } + pos--; + break; + default: + /* some command--peek into next chars to finish it */ + while(1) { + c = str[pos+1]; + if(c >= '0' && c <= '9') { + /* eat numbers */ + pos++; + continue; + } + if(c == '=') { + /* eat this as well */ + pos++; + continue; + } + /* else get out */ + break; + } + } + } + + if(ret_val >= 0) { + scc_socket_send_modem_code(port, ret_val, dcycs); + } +} + +void +scc_socket_send_modem_code(int port, int code, double dcycs) +{ + Scc *scc_ptr; + char *str; + word32 modem_mode; + + scc_ptr = &(scc_stat[port]); + + switch(code) { + case 0: str = "OK"; break; + case 1: str = "CONNECT"; break; + case 2: str = "RING"; break; + case 3: str = "NO CARRIER"; break; + case 4: str = "ERROR"; break; + case 5: str = "CONNECT 1200"; break; + case 13: str = "CONNECT 9600"; break; + case 16: str = "CONNECT 19200"; break; + case 25: str = "CONNECT 14400"; break; + case 85: str = "CONNECT 19200"; break; + default: + str = "ERROR"; + } + + printf("Sending modem code %d = %s\n", code, str); + + modem_mode = scc_ptr->modem_mode; + if(modem_mode & SCCMODEM_NOVERBOSE) { + /* just the number */ + scc_add_to_readbufv(port, dcycs, "%d", code); + scc_add_to_readbuf(port, 0x0d, dcycs); + } else { + scc_add_to_readbufv(port, dcycs, "%s\n", str); + } +} + +void +scc_socket_modem_hangup(int port, double dcycs) +{ + scc_socket_send_modem_code(port, 3, dcycs); +} + +void +scc_socket_modem_connect(int port, double dcycs) +{ + /* decide which code to send. Default to 1 if needed */ + scc_socket_send_modem_code(port, 13, dcycs); /*13=9600*/ +} + +void +scc_socket_modem_do_ring(int port, double dcycs) +{ + Scc *scc_ptr; + double diff_dcycs; + int num_rings; + + scc_ptr = &(scc_stat[port]); + num_rings = scc_ptr->socket_num_rings; + if(num_rings > 0 && scc_ptr->socket_state == 0) { + num_rings--; + diff_dcycs = dcycs - scc_ptr->socket_last_ring_dcycs; + if(diff_dcycs < 2.0*1000*1000 && g_serial_modem[port]) { + return; /* nothing more to do */ + } + printf("In modem_do_ring, ringing at %f\n", dcycs); + if(g_serial_modem[port]) { + scc_socket_send_modem_code(port, 2, dcycs); /* RING */ + } else { + num_rings = 0; + } + scc_ptr->socket_num_rings = num_rings; + scc_ptr->socket_last_ring_dcycs = dcycs; + if(num_rings <= 0) { + /* decide on answering */ + if(scc_ptr->modem_s0_val || (g_serial_modem[port]==0)) { + scc_socket_do_answer(port, dcycs); + } else { + printf("No answer, closing socket\n"); + scc_socket_close(port, 0, dcycs); + } + } + } +} + +void +scc_socket_do_answer(int port, double dcycs) +{ + Scc *scc_ptr; + + scc_ptr = &(scc_stat[port]); + scc_ptr->modem_dial_or_acc_mode = 2; + scc_accept_socket(port, dcycs); + if(scc_ptr->rdwrfd == -1) { + printf("Answer when rdwrfd=-1, closing\n"); + scc_socket_close(port, 1, dcycs); + /* send NO CARRIER message */ + } else { + scc_ptr->socket_state = 1; + scc_socket_telnet_reqs(port, dcycs); + printf("Send telnet reqs, rdwrfd=%d\n", scc_ptr->rdwrfd); + if(g_serial_modem[port]) { + scc_socket_modem_connect(port, dcycs); + } + scc_ptr->dcd = 1; /* carrier on */ + scc_ptr->socket_state = 1; /* talk to socket */ + scc_ptr->socket_num_rings = 0; + } +} diff --git a/src/scc_windriver.c b/src/scc_windriver.c index 57efd0b..34aeff7 100644 --- a/src/scc_windriver.c +++ b/src/scc_windriver.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_scc_windriver_c[] = "@(#)$KmKId: scc_windriver.c,v 1.3 2003-09-20 15:05:15-04 kentd Exp $"; +const char rcsid_scc_windriver_c[] = "@(#)$KmKId: scc_windriver.c,v 1.4 2004-11-19 02:00:46-05 kentd Exp $"; /* This file contains the Win32 COM1/COM2 calls */ @@ -151,7 +151,7 @@ scc_serial_win_change_params(int port) } void -scc_serial_win_fill_readbuf(int port, double dcycs) +scc_serial_win_fill_readbuf(int port, int space_left, double dcycs) { byte tmp_buf[256]; Scc *scc_ptr; @@ -168,7 +168,8 @@ scc_serial_win_fill_readbuf(int port, double dcycs) } /* Try reading some bytes */ - ret = ReadFile(host_handle, tmp_buf, 256, &bytes_read, NULL); + space_left = MIN(256, space_left); + ret = ReadFile(host_handle, tmp_buf, space_left, &bytes_read, NULL); if(ret == 0) { printf("ReadFile ret 0\n"); diff --git a/src/sim65816.c b/src/sim65816.c index 0f38d36..484e691 100644 --- a/src/sim65816.c +++ b/src/sim65816.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_sim65816_c[] = "@(#)$KmKId: sim65816.c,v 1.346 2004-03-23 17:26:10-05 kentd Exp $"; +const char rcsid_sim65816_c[] = "@(#)$KmKId: sim65816.c,v 1.367 2004-11-22 02:39:26-05 kentd Exp $"; #include @@ -16,13 +16,16 @@ const char rcsid_sim65816_c[] = "@(#)$KmKId: sim65816.c,v 1.346 2004-03-23 17:26 #include "defc.h" #undef INCLUDE_RCSID_C +#define PC_LOG_LEN (8*1024) + + char g_argv0_path[256] = "./"; const char *g_kegs_default_paths[] = { "", "./", "${HOME}/", + "${HOME}/Library/KEGS/", "${0}/Contents/Resources/", "/usr/local/lib/", "/usr/local/kegs/", "/usr/local/lib/kegs/", "/usr/share/kegs/", - "/usr/share/", "/var/lib/", "/usr/lib/", "/lib/", "/etc/", - "/etc/kegs/", "${0}/", 0 }; + "/var/lib/", "/usr/lib/kegs/", "${0}/", 0 }; #define MAX_EVENTS 64 @@ -38,26 +41,18 @@ const char *g_kegs_default_paths[] = { "", "./", "${HOME}/", extern int g_stepping; -extern int statereg; +extern int g_c068_statereg; extern int g_cur_a2_stat; -extern int wrdefram; -extern int int_crom[8]; +extern int g_c08x_wrdefram; +extern int g_c02d_int_crom; -extern int shadow_text; - -extern int shadow_reg; -extern int speed_fast; -extern word32 g_slot_motor_detect; +extern int g_c035_shadow_reg; +extern int g_c036_val_speed; extern int g_c023_val; -extern int c023_1sec_int_irq_pending; -extern int c023_scan_int_irq_pending; -extern int c041_en_25sec_ints; -extern int c041_en_vbl_ints; +extern int g_c041_val; extern int g_c046_val; -extern int c046_25sec_irq_pend; -extern int c046_vbl_irq_pending; extern int g_zipgs_reg_c059; extern int g_zipgs_reg_c05a; extern int g_zipgs_reg_c05b; @@ -71,9 +66,6 @@ extern int defs_instr_end_16; extern int op_routs_start; extern int op_routs_end; -extern int updated_mod_latch; -extern int capslock_key_down; - Engine_reg engine; extern word32 table8[]; extern word32 table16[]; @@ -83,7 +75,7 @@ extern byte doc_ram[]; extern int g_iwm_motor_on; extern int g_fast_disk_emul; extern int g_slow_525_emul_wr; -extern int g_apple35_sel; +extern int g_c031_disk35; extern int g_config_control_panel; extern int g_audio_enable; @@ -94,7 +86,8 @@ void U_STACK_TRACE(); double g_fcycles_stop = 0.0; int halt_sim = 0; int enter_debug = 0; -int g_rom_version = 0; +int g_rom_version = -1; +int g_user_halt_bad = 0; int g_halt_on_bad_read = 0; int g_ignore_bad_acc = 1; int g_ignore_halts = 1; @@ -102,15 +95,12 @@ int g_code_red = 0; int g_code_yellow = 0; int g_use_alib = 0; int g_raw_serial = 1; +int g_iw2_emul = 0; int g_serial_out_masking = 0; +int g_serial_modem[2] = { 0, 1 }; int g_config_iwm_vbl_count = 0; -const char g_kegs_version_str[] = "0.86"; - -#if 0 -const double g_drecip_cycles_in_16ms = (1.0/(DCYCS_IN_16MS)); -const double g_dcycles_in_16ms = DCYCS_IN_16MS; -#endif +const char g_kegs_version_str[] = "0.91"; #define START_DCYCS (0.0) @@ -122,7 +112,8 @@ double g_dadjcycs = 0.0; int g_wait_pending = 0; -int g_irq_pending = 0; +int g_stp_pending = 0; +extern int g_irq_pending; int g_num_irq = 0; int g_num_brk = 0; @@ -137,6 +128,11 @@ int g_engine_doc_int = 0; int g_testing = 0; int g_testing_enabled = 0; +#define MAX_FATAL_LOGS 20 + +int g_debug_file_fd = -1; +int g_fatal_log = -1; +char *g_fatal_log_strs[MAX_FATAL_LOGS]; word32 stop_run_at; @@ -161,25 +157,28 @@ byte *g_dummy_memory1_ptr = 0; byte *g_rom_fc_ff_ptr = 0; byte *g_rom_cards_ptr = 0; +void *g_memory_alloc_ptr = 0; /* for freeing memory area */ + Page_info page_info_rd_wr[2*65536 + PAGE_INFO_PAD_SIZE]; -int kbd_in_end = 0; -byte kbd_in_buf[LEN_KBD_BUF]; +Pc_log g_pc_log_array[PC_LOG_LEN + 2]; +Data_log g_data_log_array[PC_LOG_LEN + 2]; +Pc_log *g_log_pc_ptr = &(g_pc_log_array[0]); +Pc_log *g_log_pc_start_ptr = &(g_pc_log_array[0]); +Pc_log *g_log_pc_end_ptr = &(g_pc_log_array[PC_LOG_LEN]); -#define PC_LOG_LEN (8*1024) - -Pc_log pc_log_array[PC_LOG_LEN + 2]; - -Pc_log *log_pc_ptr = &(pc_log_array[0]); -Pc_log *log_pc_start_ptr = &(pc_log_array[0]); -Pc_log *log_pc_end_ptr = &(pc_log_array[PC_LOG_LEN]); +Data_log *g_log_data_ptr = &(g_data_log_array[0]); +Data_log *g_log_data_start_ptr = &(g_data_log_array[0]); +Data_log *g_log_data_end_ptr = &(g_data_log_array[PC_LOG_LEN]); void show_pc_log() { FILE *pcfile; + Pc_log *log_pc_ptr; + Data_log *log_data_ptr; double dcycs; double start_dcycs; word32 instr; @@ -188,23 +187,52 @@ show_pc_log() word32 stack, direct; word32 dbank; word32 kpc; + int data_wrap; int accsize, xsize; int num; int i; - pcfile = fopen("pc_log_out", "wt"); + pcfile = fopen("pc_log_out", "w"); if(pcfile == 0) { fprintf(stderr,"fopen failed...errno: %d\n", errno); exit(2); } + + log_pc_ptr = g_log_pc_ptr; + log_data_ptr = g_log_data_ptr; #if 0 fprintf(pcfile, "current pc_log_ptr: %p, start: %p, end: %p\n", log_pc_ptr, log_pc_start_ptr, log_pc_end_ptr); #endif start_dcycs = log_pc_ptr->dcycs; + dcycs = start_dcycs; + + data_wrap = 0; + /* find first data entry */ + while(data_wrap < 2 && (log_data_ptr->dcycs < dcycs)) { + log_data_ptr++; + if(log_data_ptr >= g_log_data_end_ptr) { + log_data_ptr = g_log_data_start_ptr; + data_wrap++; + } + } + fprintf(pcfile, "start_dcycs: %9.2f\n", start_dcycs); for(i = 0; i < PC_LOG_LEN; i++) { + dcycs = log_pc_ptr->dcycs; + while((data_wrap < 2) && (log_data_ptr->dcycs <= dcycs) && + (log_data_ptr->dcycs >= start_dcycs)) { + fprintf(pcfile, "DATA set %06x = %06x (%d) %9.2f\n", + log_data_ptr->addr, log_data_ptr->val, + log_data_ptr->size, + log_data_ptr->dcycs - start_dcycs); + log_data_ptr++; + if(log_data_ptr >= g_log_data_end_ptr) { + log_data_ptr = g_log_data_start_ptr; + data_wrap++; + } + } dbank = (log_pc_ptr->dbank_kpc >> 24) & 0xff; kpc = log_pc_ptr->dbank_kpc & 0xffffff; instr = log_pc_ptr->instr; @@ -214,9 +242,8 @@ show_pc_log() yreg = log_pc_ptr->xreg_yreg & 0xffff;; stack = (log_pc_ptr->stack_direct >> 16) & 0xffff;; direct = log_pc_ptr->stack_direct & 0xffff;; - dcycs = log_pc_ptr->dcycs; - num = log_pc_ptr - log_pc_start_ptr; + num = log_pc_ptr - g_log_pc_start_ptr; accsize = 2; xsize = 2; @@ -234,8 +261,8 @@ show_pc_log() do_dis(pcfile, kpc, accsize, xsize, 1, instr); log_pc_ptr++; - if(log_pc_ptr >= log_pc_end_ptr) { - log_pc_ptr = log_pc_start_ptr; + if(log_pc_ptr >= g_log_pc_end_ptr) { + log_pc_ptr = g_log_pc_start_ptr; } } @@ -380,7 +407,7 @@ get_memory_io(word32 loc, double *cyc_ptr) } g_code_yellow++; - if(g_ignore_bad_acc) { + if(g_ignore_bad_acc && !g_user_halt_bad) { /* print no message, just get out. User doesn't want */ /* to be bothered by buggy programs */ return 0; @@ -389,7 +416,7 @@ get_memory_io(word32 loc, double *cyc_ptr) printf("get_memory_io for addr: %06x\n", loc); printf("stat for addr: %06x = %p\n", loc, GET_PAGE_INFO_RD((loc >> 8) & 0xffff)); - set_halt(g_halt_on_bad_read); + set_halt(g_halt_on_bad_read | g_user_halt_bad); return 0; } @@ -498,7 +525,7 @@ set_memory_io(word32 loc, int val, double *cyc_ptr) return; } - if(g_ignore_bad_acc) { + if(g_ignore_bad_acc && !g_user_halt_bad) { /* print no message, just get out. User doesn't want */ /* to be bothered by buggy programs */ return; @@ -579,15 +606,14 @@ my_exit(int ret) void do_reset() { - int i; - statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ + g_c068_statereg = 0x08 + 0x04 + 0x01; /* rdrom, lcbank2, intcx */ + g_c035_shadow_reg = 0; - wrdefram = 1; - for(i = 1; i < 7; i++) { - int_crom[i] = 0; - } - int_crom[7] = 0; + g_c08x_wrdefram = 1; + g_c02d_int_crom = 0; + g_c023_val = 0; + g_c041_val = 0; engine.psr = (engine.psr | 0x134) & ~(0x08); engine.stack = 0x100 + (engine.stack & 0xff); @@ -596,6 +622,7 @@ do_reset() engine.xreg &= 0xff; engine.yreg &= 0xff; g_wait_pending = 0; + g_stp_pending = 0; video_reset(); @@ -606,6 +633,8 @@ do_reset() setup_pageinfo(); change_display_mode(g_cur_dcycs); + g_irq_pending = 0; + engine.kpc = get_memory16_c(0x00fffc, 0); g_stepping = 0; @@ -665,14 +694,18 @@ check_engine_asm_defines() } byte * -memalloc_align(int size, int skip_amt) +memalloc_align(int size, int skip_amt, void **alloc_ptr) { byte *bptr; word32 addr; word32 offset; skip_amt = MAX(256, skip_amt); - bptr = malloc(size + skip_amt); + bptr = calloc(size + skip_amt, 1); + if(alloc_ptr) { + /* Save allocation address */ + *alloc_ptr = bptr; + } addr = PTR2WORD(bptr) & 0xff; @@ -681,11 +714,7 @@ memalloc_align(int size, int skip_amt) offset = ((addr + skip_amt - 1) & (~0xff)) - addr; - bptr += offset; - - /* Gilles Tschopp recommended zeroing memory, this is a good idea */ - memset(bptr, 0, size); - return bptr; + return (bptr + offset); } void @@ -693,9 +722,15 @@ memory_ptr_init() { word32 mem_size; + /* This routine may be called several times--each time the ROM file */ + /* changes this will be called */ mem_size = MIN(0xdf0000, g_mem_size_base + g_mem_size_exp); g_mem_size_total = mem_size; - g_memory_ptr = memalloc_align(mem_size, 3*1024); + if(g_memory_alloc_ptr) { + free(g_memory_alloc_ptr); + g_memory_alloc_ptr = 0; + } + g_memory_ptr = memalloc_align(mem_size, 256, &g_memory_alloc_ptr); printf("RAM size is 0 - %06x (%.2fMB)\n", mem_size, (double)mem_size/(1024.0*1024.0)); @@ -807,8 +842,7 @@ kegsmain(int argc, char **argv) printf("Not using X shared memory\n"); g_use_shmem = 0; } else if(!strcmp("-joystick", argv[i])) { - printf("Trying to use joystick\n"); - joystick_init(); + printf("Ignoring -joystick option\n"); } else if(!strcmp("-dhr140", argv[i])) { printf("Using simple dhires color map\n"); g_use_dhr140 = 1; @@ -854,8 +888,7 @@ kegsmain(int argc, char **argv) iwm_init(); config_init(); - load_roms(); - memory_ptr_init(); + load_roms_init_memory(); init_reg(); clear_halt(); @@ -870,8 +903,11 @@ kegsmain(int argc, char **argv) sound_init(); scc_init(); - clk_setup_bram_version(); /* load_roms must be called first! */ adb_init(); + joystick_init(); + if(g_rom_version >= 3) { + g_c036_val_speed |= 0x40; /* set power-on bit */ + } do_reset(); g_stepping = 0; @@ -884,6 +920,27 @@ kegsmain(int argc, char **argv) return 0; } +void +load_roms_init_memory() +{ + config_load_roms(); + memory_ptr_init(); + clk_setup_bram_version(); /* Must be after config_load_roms */ + if(g_rom_version >= 3) { + g_c036_val_speed |= 0x40; /* set power-on bit */ + } else { + g_c036_val_speed &= (~0x40); /* clear the bit */ + } + do_reset(); + + /* if user booted ROM 01, switches to ROM 03, then switches back */ + /* to ROM 01, then the reset routines call to Tool $0102 looks */ + /* at uninitialized $e1/15fe and if it is negative it will JMP */ + /* through $e1/1688 which ROM 03 left pointing to fc/0199 */ + /* So set e1/15fe = 0 */ + set_memory16_c(0xe115fe, 0, 0); +} + void kegs_expand_path(char *out_ptr, const char *in_ptr, int maxlen) { @@ -952,7 +1009,7 @@ kegs_expand_path(char *out_ptr, const char *in_ptr, int maxlen) void setup_kegs_file(char *outname, int maxlen, int ok_if_missing, - const char **name_ptr) + int can_create_file, const char **name_ptr) { char local_path[256]; struct stat stat_buf; @@ -984,20 +1041,41 @@ setup_kegs_file(char *outname, int maxlen, int ok_if_missing, path_ptr++; } - if(ok_if_missing) { - outname[0] = 0; + outname[0] = 0; + if(ok_if_missing > 0) { return; } /* couldn't find it, print out all the attempts */ path_ptr = save_path_ptr; - printf("Could not find %s in any of these directories:\n", *name_ptr); + fatal_printf("Could not find required file \"%s\" in any of these " + "directories:\n", *name_ptr); while(*path_ptr) { - printf(" %s\n", *path_ptr++); + fatal_printf(" %s\n", *path_ptr++); } + + if(can_create_file) { + // Ask user if it's OK to create the file + x_dialog_create_kegs_conf(*name_ptr); + can_create_file = 0; + + // But clear out the fatal_printfs first + clear_fatal_logs(); + setup_kegs_file(outname, maxlen, ok_if_missing, + can_create_file, name_ptr); + // It's one-level of recursion--it cannot loop since we + // clear can_create_file. + // If it returns, then there was succes and we should get out + return; + } else if(ok_if_missing) { + /* Just show an alert and return if ok_if_missing < 0 */ + x_show_alert(0, 0); + return; + } + system("pwd"); - exit(2); + my_exit(2); } Event g_event_list[MAX_EVENTS]; @@ -1248,14 +1326,11 @@ Fplus g_recip_projected_pmhz_fast; Fplus g_recip_projected_pmhz_zip; Fplus g_recip_projected_pmhz_unl; -Fplus *g_cur_fplus_ptr = 0; - void show_pmhz() { - printf("Pmhz: %f, plus_1: %f, fast: %d, limit: %d\n", - g_projected_pmhz, g_cur_fplus_ptr->plus_1, speed_fast, - g_limit_speed); + printf("Pmhz: %f, c036:%02x, limit: %d\n", + g_projected_pmhz, g_c036_val_speed, g_limit_speed); } @@ -1329,12 +1404,15 @@ run_prog() zip_speed_0tof = g_zipgs_reg_c05a & 0xf0; setup_zip_speeds(); - if(g_cur_fplus_ptr == 0) { + if(engine.fplus_ptr == 0) { g_recip_projected_pmhz_unl = g_recip_projected_pmhz_slow; } while(1) { fflush(stdout); + if(g_config_control_panel) { + config_control_panel(); + } if(g_irq_pending && !(engine.psr & 0x4)) { irq_printf("taking an irq!\n"); @@ -1344,11 +1422,11 @@ run_prog() motor_on = g_iwm_motor_on; limit_speed = g_limit_speed; - apple35_sel = g_apple35_sel; + apple35_sel = g_c031_disk35 & 0x40; zip_en = ((g_zipgs_reg_c05b & 0x10) == 0); zip_follow_cps = ((g_zipgs_reg_c059 & 0x8) != 0); zip_speed_0tof_new = g_zipgs_reg_c05a & 0xf0; - fast = speed_fast || (zip_en && !zip_follow_cps); + fast = (g_c036_val_speed & 0x80) || (zip_en && !zip_follow_cps); if(zip_speed_0tof_new != zip_speed_0tof) { zip_speed_0tof = zip_speed_0tof_new; @@ -1356,7 +1434,7 @@ run_prog() } iwm_1 = motor_on && !apple35_sel && - (g_slot_motor_detect & 0x4) && + (g_c036_val_speed & 0x4) && (g_slow_525_emul_wr || !g_fast_disk_emul); iwm_25 = (motor_on && apple35_sel) && !g_fast_disk_emul; faster_than_28 = fast && (!iwm_1 && !iwm_25) && zip_en && @@ -1381,7 +1459,6 @@ run_prog() fplus_ptr = &g_recip_projected_pmhz_slow; } - g_cur_fplus_ptr = fplus_ptr; engine.fplus_ptr = fplus_ptr; this_type = g_event_start.next->type; @@ -1514,9 +1591,6 @@ run_prog() if(g_stepping) { break; } - if(g_config_control_panel) { - config_control_panel(); - } } if(!g_testing) { @@ -1527,19 +1601,20 @@ run_prog() } void -add_irq() +add_irq(word32 irq_mask) { - g_irq_pending++; + if(g_irq_pending & irq_mask) { + /* Already requested, just get out */ + return; + } + g_irq_pending |= irq_mask; set_halt(HALT_EVENT); } void -remove_irq() +remove_irq(word32 irq_mask) { - g_irq_pending--; - if(g_irq_pending < 0) { - halt_printf("remove_irq: g_irq_pending: %d\n", g_irq_pending); - } + g_irq_pending = g_irq_pending & (~irq_mask); } void @@ -1559,10 +1634,6 @@ take_irq(int is_it_brk) g_wait_pending = 0; } - if(g_irq_pending < 0) { - halt_printf("g_irq_pending: %d!\n", g_irq_pending); - } - if(engine.psr & 0x100) { /* Emulation */ set_memory_c(engine.stack, (engine.kpc >> 8) & 0xff, 0); @@ -1577,7 +1648,7 @@ take_irq(int is_it_brk) engine.stack = ((engine.stack -1) & 0xff) + 0x100; va = 0xfffffe; - if(shadow_reg & 0x40) { + if(g_c035_shadow_reg & 0x40) { /* I/O shadowing off...use ram locs */ va = 0x00fffe; } @@ -1599,13 +1670,13 @@ take_irq(int is_it_brk) if(is_it_brk) { /* break */ va = 0xffffe6; - if(shadow_reg & 0x40) { + if(g_c035_shadow_reg & 0x40) { va = 0xffe6; } } else { /* irq */ va = 0xffffee; - if(shadow_reg & 0x40) { + if(g_c035_shadow_reg & 0x40) { va = 0xffee; } } @@ -1967,19 +2038,18 @@ update_60hz(double dcycs, double dtime_now) g_dtime_eff_pmhz_array[prev_vbl_index] = eff_pmhz; - if(c041_en_vbl_ints) { + if(g_c041_val & C041_EN_VBL_INTS) { add_event_vbl(); } g_25sec_cntr++; if(g_25sec_cntr >= 16) { g_25sec_cntr = 0; - if(c041_en_25sec_ints && !c046_25sec_irq_pend) { + if(g_c041_val & C041_EN_25SEC_INTS) { + add_irq(IRQ_PENDING_C046_25SEC); g_c046_val |= 0x10; - c046_25sec_irq_pend = 1; - add_irq(); - irq_printf("Setting c046 .25 sec int to 1, " - "g_irq_pend: %d\n", g_irq_pending); + irq_printf("Setting c046 .25 sec int, g_irq_pend:%d\n", + g_irq_pending); } } @@ -1988,10 +2058,9 @@ update_60hz(double dcycs, double dtime_now) g_1sec_cntr = 0; tmp = g_c023_val; tmp |= 0x40; /* set 1sec int */ - if((tmp & 0x04) && !c023_1sec_int_irq_pending) { - c023_1sec_int_irq_pending = 1; + if(tmp & 0x04) { tmp |= 0x80; - add_irq(); + add_irq(IRQ_PENDING_C023_1SEC); irq_printf("Setting c023 to %02x irq_pend: %d\n", tmp, g_irq_pending); } @@ -2017,16 +2086,15 @@ update_60hz(double dcycs, double dtime_now) sound_update(dcycs); clock_update(); scc_update(dcycs); - joystick_update_button(); + paddle_update_buttons(); } void do_vbl_int() { - if(c041_en_vbl_ints && !c046_vbl_irq_pending) { + if(g_c041_val & C041_EN_VBL_INTS) { g_c046_val |= 0x08; - c046_vbl_irq_pending = 1; - add_irq(); + add_irq(IRQ_PENDING_C046_VBL); irq_printf("Setting c046 vbl_int_status to 1, irq_pend: %d\n", g_irq_pending); } @@ -2045,12 +2113,12 @@ do_scan_int(double dcycs, int line) } /* make sure scan int is still enabled for this line */ - if(g_slow_memory_ptr[0x19d00 + line] & 0x40) { + if((g_slow_memory_ptr[0x19d00 + line] & 0x40) && + (g_cur_a2_stat & ALL_STAT_SUPER_HIRES)) { /* valid interrupt, do it */ c023_val |= 0xa0; /* vgc_int and scan_int */ - if((c023_val & 0x02) && !c023_scan_int_irq_pending) { - add_irq(); - c023_scan_int_irq_pending = 1; + if(c023_val & 0x02) { + add_irq(IRQ_PENDING_C023_SCAN); irq_printf("Setting c023 to %02x, irq_pend: %d\n", c023_val, g_irq_pending); } @@ -2063,7 +2131,6 @@ do_scan_int(double dcycs, int line) } } - void check_scan_line_int(double dcycs, int cur_video_line) { @@ -2128,6 +2195,7 @@ init_reg() engine.stack = 0x1ff; engine.direct = 0; engine.psr = 0x134; + engine.fplus_ptr = 0; } @@ -2174,6 +2242,9 @@ handle_action(word32 ret) case RET_WDM: do_wdm(ret & 0xff); break; + case RET_STP: + do_stp(); + break; default: halt_printf("Unknown special action: %08x!\n", ret); } @@ -2274,7 +2345,11 @@ do_wai() void do_stp() { - halt_printf("Hit do_stp at addr: %06x\n", engine.kpc); + if(!g_stp_pending) { + g_stp_pending = 1; + halt_printf("Hit STP instruction at: %06x, press RESET to " + "continue\n", engine.kpc); + } } void @@ -2283,3 +2358,86 @@ size_fail(int val, word32 v1, word32 v2) halt_printf("Size failure, val: %08x, %08x %08x\n", val, v1, v2); } +int +fatal_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + + if(g_fatal_log < 0) { + g_fatal_log = 0; + } + ret = kegs_vprintf(fmt, ap); + va_end(ap); + + return ret; +} + +int +kegs_vprintf(const char *fmt, va_list ap) +{ + char *bufptr, *buf2ptr; + int len; + int ret; + + bufptr = malloc(4096); + ret = vsnprintf(bufptr, 4090, fmt, ap); + + len = strlen(bufptr); + if(g_fatal_log >= 0 && g_fatal_log < MAX_FATAL_LOGS) { + buf2ptr = malloc(len+1); + memcpy(buf2ptr, bufptr, len+1); + g_fatal_log_strs[g_fatal_log++] = buf2ptr; + } + must_write(1, bufptr, len); + if(g_debug_file_fd >= 0) { + must_write(g_debug_file_fd, bufptr, len); + } + free(bufptr); + + return ret; +} + +void +must_write(int fd, char *bufptr, int len) +{ + int ret; + + while(len > 0) { + ret = write(fd, bufptr, len); + if(ret >= 0) { + len -= ret; + bufptr += ret; + } else if(errno != EAGAIN && errno != EINTR) { + return; // just get out + } + } +} + +void +clear_fatal_logs() +{ + int i; + + for(i = 0; i < g_fatal_log; i++) { + free(g_fatal_log_strs[i]); + g_fatal_log_strs[i] = 0; + } + g_fatal_log = -1; +} + +char * +kegs_malloc_str(char *in_str) +{ + char *str; + int len; + + len = strlen(in_str) + 1; + str = malloc(len); + memcpy(str, in_str, len); + + return str; +} + diff --git a/src/smartport.c b/src/smartport.c index 24ca31e..86b98aa 100644 --- a/src/smartport.c +++ b/src/smartport.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_smartport_c[] = "@(#)$KmKId: smartport.c,v 1.29 2003-11-17 15:44:44-05 kentd Exp $"; +const char rcsid_smartport_c[] = "@(#)$KmKId: smartport.c,v 1.31 2004-11-12 23:10:50-05 kentd Exp $"; #include "defc.h" @@ -195,12 +195,9 @@ do_c70d(word32 arg0) /* see technotes/smpt/tn-smpt-002 */ set_memory_c(status_ptr, g_highest_smartport_unit+1, 0); set_memory_c(status_ptr+1, 0xff, 0); /* interrupt stat*/ - set_memory_c(status_ptr+2, 0x02, 0); /* vendor id */ - set_memory_c(status_ptr+3, 0x00, 0); /* vendor id */ - set_memory_c(status_ptr+4, 0x00, 0); /* version lo */ - set_memory_c(status_ptr+5, 0x10, 0); /* version hi */ - set_memory_c(status_ptr+6, 0x00, 0); - set_memory_c(status_ptr+7, 0x00, 0); + set_memory16_c(status_ptr+2, 0x0002, 0); /* vendor id */ + set_memory16_c(status_ptr+4, 0x1000, 0); /* version */ + set_memory16_c(status_ptr+6, 0x0000, 0); engine.xreg = 8; engine.yreg = 0; @@ -219,9 +216,7 @@ do_c70d(word32 arg0) size = (size+511) / 512; } set_memory_c(status_ptr, stat_val, 0); - set_memory_c(status_ptr +1, size & 0xff, 0); - set_memory_c(status_ptr +2, (size >> 8) & 0xff, 0); - set_memory_c(status_ptr +3, (size >> 16) & 0xff, 0); + set_memory24_c(status_ptr +1, size, 0); engine.xreg = 4; if(cmd & 0x40) { set_memory_c(status_ptr + 4, @@ -249,9 +244,7 @@ do_c70d(word32 arg0) } /* DIB for unit 1 */ set_memory_c(status_ptr, stat_val, 0); - set_memory_c(status_ptr +1, size & 0xff, 0); - set_memory_c(status_ptr +2, (size >> 8) & 0xff, 0); - set_memory_c(status_ptr +3, (size >> 16) & 0xff, 0); + set_memory24_c(status_ptr +1, size, 0); if(cmd & 0x40) { set_memory_c(status_ptr + 4, (size >> 24) & 0xff, 0); @@ -267,11 +260,8 @@ do_c70d(word32 arg0) set_memory_c(status_ptr +8, 'S', 0); /* hard disk supporting extended calls */ - set_memory_c(status_ptr + 21, 0x02, 0); - set_memory_c(status_ptr + 22, 0xa0, 0); - - set_memory_c(status_ptr + 23, 0x00, 0); - set_memory_c(status_ptr + 24, 0x00, 0); + set_memory16_c(status_ptr + 21, 0xa002, 0); + set_memory16_c(status_ptr + 23, 0x0000, 0); if(cmd & 0x40) { engine.xreg = 26; @@ -766,18 +756,15 @@ do_c700(word32 ret) ret = do_read_c7(0, 0x800, 0); set_memory_c(0x7f8, 7, 0); - set_memory_c(0x42, 0x01, 0); - set_memory_c(0x43, 0x70, 0); - set_memory_c(0x44, 0x0, 0); - set_memory_c(0x45, 0x8, 0); - set_memory_c(0x46, 0x0, 0); - set_memory_c(0x47, 0x0, 0); + set_memory16_c(0x42, 0x7001, 0); + set_memory16_c(0x44, 0x0800, 0); + set_memory16_c(0x46, 0x0000, 0); engine.xreg = 0x70; engine.kpc = 0x801; if(ret != 0) { printf("Failure reading boot disk in s7d1!\n"); - engine.kpc = 0xe000; + engine.kpc = 0xff59; /* Jump to monitor, fix $36-$39 */ } } diff --git a/src/sound.c b/src/sound.c index 2ba8d06..4d5ea51 100644 --- a/src/sound.c +++ b/src/sound.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_sound_c[] = "@(#)$KmKId: sound.c,v 1.103 2003-10-17 15:07:47-04 kentd Exp $"; +const char rcsid_sound_c[] = "@(#)$KmKId: sound.c,v 1.108 2004-10-31 00:56:07-04 kentd Exp $"; #include "defc.h" @@ -25,6 +25,7 @@ extern int g_use_shmem; extern word32 g_vbl_count; extern int g_preferred_rate; +extern int g_c03ef_doc_ptr; extern double g_last_vbl_dcycs; @@ -34,7 +35,6 @@ byte doc_ram[0x10000 + 16]; word32 doc_sound_ctl = 0; word32 doc_saved_val = 0; -word32 doc_ptr = 0; int g_doc_num_osc_en = 1; double g_dcycs_per_doc_update = 1.0; double g_dupd_per_dcyc = 1.0; @@ -154,7 +154,7 @@ show_doc_log(void) int pos; int i; - docfile = fopen("doc_log_out", "wt"); + docfile = fopen("doc_log_out", "w"); if(docfile == 0) { printf("fopen failed, errno: %d\n", errno); return; @@ -397,10 +397,12 @@ sound_reset(double dcycs) halt_printf("reset: has_irq[%02x] = %d\n", i, g_doc_regs[i].has_irq_pending); } + g_doc_regs[i].has_irq_pending = 0; } if(g_num_osc_interrupting) { halt_printf("reset: num_osc_int:%d\n", g_num_osc_interrupting); } + g_num_osc_interrupting = 0; g_doc_num_osc_en = 1; UPDATE_G_DCYCS_PER_DOC_UPDATE(1); @@ -1212,7 +1214,7 @@ add_sound_irq(int osc) g_doc_regs[osc].has_irq_pending = num_osc_interrupting; g_num_osc_interrupting = num_osc_interrupting; - add_irq(); + add_irq(IRQ_PENDING_DOC); if(num_osc_interrupting == 1) { doc_reg_e0 = 0x00 + (osc << 1); } @@ -1238,7 +1240,9 @@ remove_sound_irq(int osc, int must) g_num_osc_interrupting--; g_doc_regs[osc].has_irq_pending = 0; DOC_LOG("rem_irq", osc, g_cur_dcycs * g_dsamps_per_dcyc, 0); - remove_irq(); + if(g_num_osc_interrupting == 0) { + remove_irq(IRQ_PENDING_DOC); + } first = 0x40 | (doc_reg_e0 >> 1); /* if none found, then def = no ints */ @@ -1641,13 +1645,13 @@ doc_read_c03d(double dcycs) if(doc_sound_ctl & 0x40) { /* Read RAM */ - doc_saved_val = doc_ram[doc_ptr]; + doc_saved_val = doc_ram[g_c03ef_doc_ptr]; } else { /* Read DOC */ doc_saved_val = 0; - osc = doc_ptr & 0x1f; - type = (doc_ptr >> 5) & 0x7; + osc = g_c03ef_doc_ptr & 0x1f; + type = (g_c03ef_doc_ptr >> 5) & 0x7; rptr = &(g_doc_regs[osc]); switch(type) { @@ -1698,24 +1702,24 @@ doc_read_c03d(double dcycs) default: doc_saved_val = 0; halt_printf("Reading bad doc_reg[%04x]: %02x\n", - doc_ptr, doc_saved_val); + g_c03ef_doc_ptr, doc_saved_val); } break; default: doc_saved_val = 0; halt_printf("Reading bad doc_reg[%04x]: %02x\n", - doc_ptr, doc_saved_val); + g_c03ef_doc_ptr, doc_saved_val); } } doc_printf("read c03d, doc_ptr: %04x, ret: %02x, saved: %02x\n", - doc_ptr, ret, doc_saved_val); + g_c03ef_doc_ptr, ret, doc_saved_val); - DOC_LOG("read c03d", -1, dsamps, (doc_ptr << 16) + + DOC_LOG("read c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + (doc_saved_val << 8) + ret); if(doc_sound_ctl & 0x20) { - doc_ptr = (doc_ptr + 1) & 0xffff; + g_c03ef_doc_ptr = (g_c03ef_doc_ptr + 1) & 0xffff; } @@ -1758,17 +1762,17 @@ doc_write_c03d(int val, double dcycs) dsamps = dcycs * g_dsamps_per_dcyc; eff_dsamps = dsamps; doc_printf("write c03d, doc_ptr: %04x, val: %02x\n", - doc_ptr, val); + g_c03ef_doc_ptr, val); - DOC_LOG("write c03d", -1, dsamps, (doc_ptr << 16) + val); + DOC_LOG("write c03d", -1, dsamps, (g_c03ef_doc_ptr << 16) + val); if(doc_sound_ctl & 0x40) { /* RAM */ - doc_ram[doc_ptr] = val; + doc_ram[g_c03ef_doc_ptr] = val; } else { /* DOC */ - osc = doc_ptr & 0x1f; - type = (doc_ptr >> 5) & 0x7; + osc = g_c03ef_doc_ptr & 0x1f; + type = (g_c03ef_doc_ptr >> 5) & 0x7; rptr = &(g_doc_regs[osc]); ctl = rptr->ctl; @@ -1777,7 +1781,7 @@ doc_write_c03d(int val, double dcycs) if(type < 2 || type == 4 || type == 6) { halt_printf("Osc %d is running, old ctl: %02x, " "but write reg %02x=%02x\n", - osc, ctl, doc_ptr & 0xff, val); + osc, ctl, g_c03ef_doc_ptr & 0xff, val); } } #endif @@ -1901,35 +1905,23 @@ doc_write_c03d(int val, double dcycs) /* and apparently TaskForce, OOTW, etc */ /* writes to e2-ff, for no apparent reason */ doc_printf("Writing doc 0x%x with %02x\n", - doc_ptr, val); + g_c03ef_doc_ptr, val); break; } break; default: halt_printf("Writing %02x into bad doc_reg[%04x]\n", - val, doc_ptr); + val, g_c03ef_doc_ptr); } } if(doc_sound_ctl & 0x20) { - doc_ptr = (doc_ptr + 1) & 0xffff; + g_c03ef_doc_ptr = (g_c03ef_doc_ptr + 1) & 0xffff; } doc_saved_val = val; } -void -doc_write_c03e(int val) -{ - doc_ptr = (doc_ptr & 0xff00) + val; -} - -void -doc_write_c03f(int val) -{ - doc_ptr = (doc_ptr & 0xff) + (val << 8); -} - void doc_show_ensoniq_state(int osc) { @@ -1939,8 +1931,8 @@ doc_show_ensoniq_state(int osc) printf("Ensoniq state\n"); printf("c03c doc_sound_ctl: %02x, doc_saved_val: %02x\n", doc_sound_ctl, doc_saved_val); - printf("doc_ptr: %04x, num_osc_en: %02x, e0: %02x\n", doc_ptr, - g_doc_num_osc_en, doc_reg_e0); + printf("doc_ptr: %04x, num_osc_en: %02x, e0: %02x\n", + g_c03ef_doc_ptr, g_doc_num_osc_en, doc_reg_e0); for(i = 0; i < 32; i += 8) { printf("irqp: %02x: %04x %04x %04x %04x %04x %04x %04x %04x\n", diff --git a/src/sound_driver.c b/src/sound_driver.c index 30f9b61..c36d8ad 100644 --- a/src/sound_driver.c +++ b/src/sound_driver.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_sound_driver_c[] = "@(#)$KmKId: sound_driver.c,v 1.16 2004-03-22 19:08:08-05 kentd Exp $"; +const char rcsid_sound_driver_c[] = "@(#)$KmKId: sound_driver.c,v 1.17 2004-09-21 10:37:15-04 kentd Exp $"; #include "defc.h" #include "sound.h" @@ -17,10 +17,6 @@ const char rcsid_sound_driver_c[] = "@(#)$KmKId: sound_driver.c,v 1.16 2004-03-2 # include #endif -#ifdef SOLARIS -# include -#endif - #if defined(__linux__) || defined(OSS) # include #endif @@ -33,7 +29,6 @@ const char rcsid_sound_driver_c[] = "@(#)$KmKId: sound_driver.c,v 1.16 2004-03-2 extern int Verbose; -extern int g_use_alib; extern int g_audio_rate; @@ -57,7 +52,6 @@ word32 *g_childsnd_shm_addr = 0; void child_sound_init_linux(); void child_sound_init_hpdev(); -void child_sound_init_solaris(); void child_sound_init_win32(); void child_sound_init_mac(); @@ -137,9 +131,6 @@ child_sound_loop(int read_fd, int write_fd, word32 *shm_addr) #ifdef HPUX child_sound_init_hpdev(); #endif -#ifdef SOLARIS - child_sound_init_solaris(); -#endif #if defined(__linux__) || defined(OSS) child_sound_init_linux(); #endif @@ -360,37 +351,6 @@ child_sound_init_hpdev() } #endif /* HPUX */ -#ifdef SOLARIS -void -child_sound_init_solaris() -{ - struct audio_info audioi; - int ret; - - g_audio_socket = open("/dev/audio", O_WRONLY, 0); - if(g_audio_socket < 0) { - printf("open /dev/audio failed, ret: %d, errno:%d\n", - g_audio_socket, errno); - exit(1); - } - - ret = ioctl(g_audio_socket, AUDIO_GETINFO, &audioi); - if(ret < 0) { - printf("ioctl audio getinfo ret: %d, errno:%d\n", ret, errno); - exit(1); - } - audioi.play.sample_rate = g_preferred_rate; - audioi.play.encoding = AUDIO_ENCODING_LINEAR; - audioi.play.precision = 16; - audioi.play.channels = 2; - ret = ioctl(g_audio_socket, AUDIO_SETINFO, &audioi); - if(ret < 0) { - printf("ioctl audio setinfo ret: %d, errno:%d\n", ret, errno); - exit(1); - } -} -#endif /* SOLARIS */ - #if defined(__linux__) || defined(OSS) void child_sound_init_linux() diff --git a/src/vars_x86solaris b/src/vars_x86solaris index 69d8671..778cb85 100644 --- a/src/vars_x86solaris +++ b/src/vars_x86solaris @@ -3,7 +3,7 @@ TARGET = xkegs OBJECTS = $(OBJECTS1) xdriver.o CC = gcc CCOPTS = -O -OPTS = -DNDEBUG -DSOLARIS -DKEGS_LITTLE_ENDIAN -DOSS +OPTS = -DNDEBUG -DSOLARIS -DKEGS_LITTLE_ENDIAN -DSOLARISSOUND SUFFIX = NAME = xkegs LDFLAGS = diff --git a/src/video.c b/src/video.c index b7a4055..37afc98 100644 --- a/src/video.c +++ b/src/video.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_video_c[] = "@(#)$KmKId: video.c,v 1.125 2004-03-23 17:25:50-05 kentd Exp $"; +const char rcsid_video_c[] = "@(#)$KmKId: video.c,v 1.135 2004-11-12 23:09:44-05 kentd Exp $"; #include @@ -41,12 +41,11 @@ extern byte *g_slow_memory_ptr; extern int g_screen_depth; extern int g_screen_mdepth; -extern int statereg; extern double g_cur_dcycs; extern int g_line_ref_amt; -extern int g_border_color; +extern int g_c034_val; extern int g_config_control_panel; typedef byte Change; @@ -72,6 +71,15 @@ Kimage g_mainwin_kimage; extern double g_last_vbl_dcycs; +double g_video_dcycs_check_input = 0.0; +int g_video_extra_check_inputs = 0; +int g_video_act_margin_left = BASE_MARGIN_LEFT; +int g_video_act_margin_right = BASE_MARGIN_RIGHT; +int g_video_act_margin_top = BASE_MARGIN_TOP; +int g_video_act_margin_bottom = BASE_MARGIN_BOTTOM; +int g_video_act_width = X_A2_WINDOW_WIDTH; +int g_video_act_height = X_A2_WINDOW_HEIGHT; + int g_need_redraw = 1; int g_palette_change_summary = 0; word32 g_palette_change_cnt[16]; @@ -98,6 +106,7 @@ int g_expanded_col_2[16]; int g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | (0xf << BIT_ALL_STAT_TEXT_COLOR); +extern int g_save_cur_a2_stat; /* from config.c */ int g_a2vid_palette = 0xe; int g_installed_full_superhires_colormap = 0; @@ -445,8 +454,6 @@ video_init() video_reset(); display_screen(); - vid_printf("Done with display_screen\n"); - fflush(stdout); } @@ -463,7 +470,8 @@ show_a2_line_stuff() g_a2_line_right_edge[i]); } - printf("new_a2_stat_cur_line: %d\n", g_new_a2_stat_cur_line); + printf("new_a2_stat_cur_line: %d, cur_a2_stat:%04x\n", + g_new_a2_stat_cur_line, g_cur_a2_stat); for(i = 0; i < 200; i++) { printf("cur_all[%d]: %03x new_all: %03x\n", i, g_a2_cur_all_stat[i], g_a2_new_all_stat[i]); @@ -476,13 +484,20 @@ int g_flash_count = 0; void video_reset() { + int stat; int i; g_installed_full_superhires_colormap = (g_screen_depth != 8); - g_cur_a2_stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | - (0xf << BIT_ALL_STAT_TEXT_COLOR); + stat = ALL_STAT_TEXT | ALL_STAT_ANNUNC3 | + (0xf << BIT_ALL_STAT_TEXT_COLOR); if(g_use_bw_hires) { - g_cur_a2_stat |= ALL_STAT_COLOR_C021; + stat |= ALL_STAT_COLOR_C021; + } + if(g_config_control_panel) { + /* Don't update cur_a2_stat when in configuration panel */ + g_save_cur_a2_stat = stat; + } else { + g_cur_a2_stat = stat; } g_palette_change_summary = 0; @@ -502,17 +517,11 @@ word32 g_cycs_in_check_input = 0; void video_update() { - register word32 start_time; - register word32 end_time; int did_video; update_border_info(); - GET_ITIMER(start_time); - check_input_events(); - GET_ITIMER(end_time); - - g_cycs_in_check_input += (end_time - start_time); + video_check_input_events(); g_screen_redraw_skip_count--; did_video = 0; @@ -536,8 +545,7 @@ video_update() if(did_video) { g_new_a2_stat_cur_line = 0; - g_a2_new_all_stat[0] = (g_cur_a2_stat & (~ALL_STAT_PAGE2)) + - PAGE2; + g_a2_new_all_stat[0] = g_cur_a2_stat; g_vid_update_last_line = 0; video_update_through_line(0); } @@ -740,8 +748,7 @@ change_display_mode(double dcycs) video_update_all_stat_through_line(tmp_line); if(line < 200) { - g_a2_new_all_stat[line] = - (g_cur_a2_stat & (~ALL_STAT_PAGE2)) + PAGE2; + g_a2_new_all_stat[line] = g_cur_a2_stat; } /* otherwise, g_cur_a2_stat is covered at the end of vbl */ } @@ -813,12 +820,12 @@ update_border_info() color_now = g_vbl_border_color; - dlines_per_dcyc = (double)(262.0 / DCYCS_IN_16MS); + dlines_per_dcyc = (double)(1.0 / 65.0); limit = g_num_border_changes; if(g_border_last_vbl_changes || limit) { /* add a dummy entry */ g_border_changes[limit].fcycs = DCYCS_IN_16MS + 21.0; - g_border_changes[limit].val = g_border_color; + g_border_changes[limit].val = (g_c034_val & 0xf); limit++; } last_line_offset = (-1 << 8) + 44; @@ -826,7 +833,7 @@ update_border_info() dcycs = g_border_changes[i].fcycs; dline = dcycs * dlines_per_dcyc; new_line = (int)dline; - dcyc_line_start = (double)new_line * (DCYCS_IN_16MS/262.0); + dcyc_line_start = (double)new_line * 65.0; offset = ((int)(dcycs - dcyc_line_start)) & 0xff; /* here comes the tricky part */ @@ -880,7 +887,7 @@ update_border_info() } g_num_border_changes = 0; - g_vbl_border_color = g_border_color; + g_vbl_border_color = (g_c034_val & 0xf); } void @@ -943,8 +950,8 @@ update_border_line(int st_line_offset, int end_line_offset, int color) right = MIN(4, end_offset - 44); video_border_pixel_write(&g_kimage_border_sides, 2*line, 2, val, - 32 + (left * EFF_BORDER_WIDTH/4), - 32 + (right * EFF_BORDER_WIDTH/4)); + BORDER_WIDTH + (left * EFF_BORDER_WIDTH/4), + BORDER_WIDTH + (right * EFF_BORDER_WIDTH/4)); g_border_sides_refresh_needed = 1; } } @@ -2638,6 +2645,26 @@ video_update_event_line(int line) add_event_vid_upd(1); /* add event for new screen */ } } + + if(g_video_extra_check_inputs) { + if(g_video_dcycs_check_input < g_cur_dcycs) { + video_check_input_events(); + } + } +} + +void +video_check_input_events() +{ + word32 start_time, end_time; + + g_video_dcycs_check_input = g_cur_dcycs + 4000.0; + + GET_ITIMER(start_time); + check_input_events(); + GET_ITIMER(end_time); + + g_cycs_in_check_input += (end_time - start_time); } void @@ -2654,7 +2681,7 @@ video_update_through_line(int line) int i; #if 0 - vid_printf("\nvideo_upd for line %d, lines: %06x\n\n", line, + vid_printf("\nvideo_upd for line %d, lines: %06x\n", line, get_lines_since_vbl(g_cur_dcycs)); #endif @@ -3062,9 +3089,8 @@ video_push_lines(Kimage *kimage_ptr, int start_line, int end_line, int left_pix, g_refresh_bytes_xfer += 2*(end_line - start_line) * (right_pix - left_pix); - - x_push_kimage(kimage_ptr, BASE_MARGIN_LEFT + left_pix, - BASE_MARGIN_TOP + srcy, left_pix, srcy, + x_push_kimage(kimage_ptr, g_video_act_margin_left + left_pix, + g_video_act_margin_top + srcy, left_pix, srcy, (right_pix - left_pix), 2*(end_line - start_line)); } @@ -3087,8 +3113,30 @@ video_push_border_sides_lines(int src_x, int dest_x, int width, int start_line, g_refresh_bytes_xfer += 2 * (end_line - start_line) * width; srcy = 2 * start_line; - x_push_kimage(kimage_ptr, dest_x, BASE_MARGIN_TOP + srcy, + + // Adjust dext_x to accound for changed margins + dest_x = dest_x + g_video_act_margin_left - BASE_MARGIN_LEFT; + if(dest_x < BASE_MARGIN_LEFT) { + src_x = src_x + g_video_act_margin_left - BASE_MARGIN_LEFT; + // Don't adjust src_x if doing right border + } + if(dest_x < 0) { + width = width + dest_x; + src_x = src_x - dest_x; + dest_x = 0; + } + if(src_x < 0) { + width = width + src_x; + dest_x = dest_x - src_x; + src_x = 0; + } + if(dest_x + width > g_video_act_width) { + width = g_video_act_width - dest_x; + } + if(width > 0) { + x_push_kimage(kimage_ptr, dest_x, g_video_act_margin_top + srcy, src_x, srcy, width, 2*(end_line - start_line)); + } } void @@ -3134,18 +3182,39 @@ video_push_border_special() { Kimage *kimage_ptr; int width, height; - - width = X_A2_WINDOW_WIDTH; - height = BASE_MARGIN_TOP; + int src_x, src_y; + int dest_x, dest_y; kimage_ptr = &g_kimage_border_special; + width = g_video_act_width; g_refresh_bytes_xfer += width * (BASE_MARGIN_TOP + BASE_MARGIN_BOTTOM); - x_push_kimage(kimage_ptr, 0, BASE_MARGIN_TOP + A2_WINDOW_HEIGHT, - 0, 0, width, BASE_MARGIN_BOTTOM); - x_push_kimage(kimage_ptr, 0, 0, - 0, BASE_MARGIN_BOTTOM, width, BASE_MARGIN_TOP); - + // First do bottom border: dest_x from 0 to 640+MARGIN_LEFT+MARGIN_RIGHT + // and dest_y of BASE_MARGIN_BOTTOM starting at TOP+A2_HEIGHT + // src_x is dest_x, and src_y is 0. + dest_y = g_video_act_margin_top + A2_WINDOW_HEIGHT; + height = g_video_act_margin_bottom; + src_y = BASE_MARGIN_BOTTOM - height; + + dest_x = 0; + src_x = BASE_MARGIN_LEFT - g_video_act_margin_left; + + if(width > 0 && height > 0) { + x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y, + width, height); + } + + // Then fix top border: dest_x from 0 to 640+LEFT+RIGHT and + // dest_y from 0 to TOP. src_x is dest_x, but src_y is + // BOTTOM to BOTTOM+TOP + // Just use src_x and dest_x from earlier. + height = g_video_act_margin_top; + dest_y = 0; + src_y = BASE_MARGIN_BOTTOM; + if(width > 0 && height > 0) { + x_push_kimage(kimage_ptr, dest_x, dest_y, src_x, src_y, + width, height); + } } void @@ -3352,3 +3421,70 @@ video_show_debug_info() printf("lines since vbl: %06x\n", tmp1); printf("Last line updated: %d\n", g_vid_update_last_line); } + +word32 +float_bus(double dcycs) +{ + word32 val; + int lines_since_vbl; + int line, eff_line, line24; + int all_stat; + int byte_offset; + int hires, page2; + int addr; + + lines_since_vbl = get_lines_since_vbl(dcycs); + +/* For floating bus, model hires style: Visible lines 0-191 are simply the */ +/* data being displayed at that time. Lines 192-255 are lines 0 - 63 again */ +/* and lines 256-261 are lines 58-63 again */ +/* For each line, figure out starting byte at -25 mod 128 bytes from this */ +/* line's start */ +/* This emulates an Apple II style floating bus. A reall IIgs does not */ +/* drive anything meaningful during the 25 horizontal blanking lines, */ +/* nor during veritical blanking. The data seems to be 0 or related to */ +/* the instruction fetches on a real IIgs during blankings */ + + line = lines_since_vbl >> 8; + byte_offset = lines_since_vbl & 0xff; + /* byte offset is from 0 to 65, where the visible screen is drawn */ + /* from 25 to 65 */ + + eff_line = line; + if(line >= 192) { + eff_line = line - 192; + if(line >= 256) { + eff_line = line - 262 + 64; + } + } + all_stat = g_cur_a2_stat; + hires = all_stat & ALL_STAT_HIRES; + if((all_stat & ALL_STAT_MIX_T_GR) && (line >= 160)) { + hires = 0; + } + page2 = EXTRU(all_stat, 31 - BIT_ALL_STAT_PAGE2, 1); + if(all_stat & ALL_STAT_ST80) { + page2 = 0; + } + + line24 = (eff_line >> 3) & 0x1f; + addr = g_screen_index[line24] & 0x3ff; + addr = (addr & 0x380) + (((addr & 0x7f) - 25 + byte_offset) & 0x7f); + if(hires) { + addr = 0x2000 + addr + ((eff_line & 7) << 10) + (page2 << 13); + } else { + addr = 0x400 + addr + (page2 << 10); + } + + val = g_slow_memory_ptr[addr]; + if(byte_offset < 10) { + /* Bob Bishop's sample program seems to get confused by */ + /* these bytes--so mask some off to prevent seeing some */ + val = 0; + } +#if 0 + printf("For %04x (%d) addr=%04x, val=%02x, dcycs:%9.2f\n", + lines_since_vbl, eff_line, addr, val, dcycs - g_last_vbl_dcycs); +#endif + return val; +} diff --git a/src/windriver.c b/src/windriver.c index 787c9b6..c929656 100644 --- a/src/windriver.c +++ b/src/windriver.c @@ -8,7 +8,10 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_windriver_c[] = "@(#)$KmKId: windriver.c,v 1.8 2004-03-23 17:25:37-05 kentd Exp $"; +const char rcsid_windriver_c[] = "@(#)$KmKId: windriver.c,v 1.11 2004-11-24 16:43:46-05 kentd Exp $"; + +/* Based on code from Chea Chee Keong from KEGS32, which is available at */ +/* http://www.geocities.com/akilgard/kegs32 */ #define WIN32_LEAN_AND_MEAN /* Tell windows we want less header gunk */ #define STRICT /* Tell Windows we want compile type checks */ @@ -187,6 +190,34 @@ int g_a2_key_to_wsym[][3] = { { -1, -1, -1 } }; +int +win_nonblock_read_stdin(int fd, char *bufptr, int len) +{ + HANDLE oshandle; + DWORD dwret; + int ret; + + errno = EAGAIN; + oshandle = (HANDLE)_get_osfhandle(fd); // get stdin handle + dwret = WaitForSingleObject(oshandle, 1); // wait 1msec for data + ret = -1; + if(dwret == WAIT_OBJECT_0) { + ret = read(fd, bufptr, len); + } + return ret; +} + +void +x_dialog_create_kegs_conf(const char *str) +{ +} + +int +x_show_alert(int is_fatal, const char *str) +{ + return 0; +} + int win_update_mouse(int x, int y, int button_states, int buttons_valid) { @@ -635,3 +666,9 @@ x_hide_pointer(int do_hide) ShowCursor(1); } } + +void +x_full_screen(int do_full) +{ + return; +} diff --git a/src/xdriver.c b/src/xdriver.c index 7e5f7be..8d77b43 100644 --- a/src/xdriver.c +++ b/src/xdriver.c @@ -8,7 +8,7 @@ /* You may contact the author at: kadickey@alumni.princeton.edu */ /************************************************************************/ -const char rcsid_xdriver_c[] = "@(#)$KmKId: xdriver.c,v 1.181 2004-03-23 17:25:25-05 kentd Exp $"; +const char rcsid_xdriver_c[] = "@(#)$KmKId: xdriver.c,v 1.187 2004-11-15 16:24:19-05 kentd Exp $"; # if !defined(__CYGWIN__) && !defined(__POWERPC__) /* No shared memory on Cygwin */ @@ -136,7 +136,7 @@ int g_num_a2_keycodes = 0; int a2_key_to_xsym[][3] = { { 0x35, XK_Escape, 0 }, { 0x7a, XK_F1, 0 }, - { 0x7b, XK_F2, 0 }, + { 0x78, XK_F2, 0 }, { 0x63, XK_F3, 0 }, { 0x76, XK_F4, 0 }, { 0x60, XK_F5, 0 }, @@ -165,7 +165,7 @@ int a2_key_to_xsym[][3] = { { 0x1b, '-', '_' }, { 0x18, '=', '+' }, { 0x33, XK_BackSpace, 0 }, - { 0x72, XK_Insert, 0 }, /* Help? */ + { 0x72, XK_Insert, XK_Help }, /* Help? */ /* { 0x73, XK_Home, 0 }, alias XK_Home to be XK_KP_Equal! */ { 0x74, XK_Page_Up, 0 }, { 0x47, XK_Num_Lock, XK_Clear }, /* Clear */ @@ -248,6 +248,23 @@ main(int argc, char **argv) return kegsmain(argc, argv); } +void +x_dialog_create_kegs_conf(const char *str) +{ + /* do nothing -- not implemented yet */ + return; +} + +int +x_show_alert(int is_fatal, const char *str) +{ + /* Not implemented yet */ + adb_all_keys_up(); + + clear_fatal_logs(); + return 0; +} + #define MAKE_2(val) ( (val << 8) + val) @@ -1160,15 +1177,23 @@ handle_keysym(XEvent *xev_in) switch(keysym) { case XK_Alt_R: case XK_Meta_R: + case XK_Super_R: case XK_Mode_switch: case XK_Cancel: keysym = XK_Print; /* option */ break; case XK_Alt_L: case XK_Meta_L: + case XK_Super_L: case XK_Menu: keysym = XK_Scroll_Lock; /* cmd */ break; + case 0x1000003: + if(keycode == 0x3c) { + /* enter key on Mac OS X laptop--make it option */ + keysym = XK_Print; + } + break; case NoSymbol: switch(keycode) { /* 94-95 are for my PC101 kbd + windows keys on HPUX */ @@ -1196,6 +1221,7 @@ handle_keysym(XEvent *xev_in) keysym = XK_Scroll_Lock; break; case 0x0048: + case 0x0076: /* Windows menu key on Mac OS X */ /* menu windows == option */ keysym = XK_Print; break; @@ -1304,3 +1330,9 @@ x_auto_repeat_off(int must) adb_kbd_repeat_off(); } } + +void +x_full_screen(int do_full) +{ + return; +}