From 4b8f46b13d29f23e7dca973f29dc1b6cf2bbe377 Mon Sep 17 00:00:00 2001 From: Gwenhael Le Moine Date: Tue, 22 Mar 2022 13:47:02 +0100 Subject: [PATCH] first commit --- COPYING.txt | 340 +++++++++++++ CVS/Entries | 4 + CVS/Entries.Log | 3 + CVS/Repository | 1 + CVS/Root | 1 + Makefile | 67 +++ README.txt | 128 +++++ bin/CVS/Entries | 2 + bin/CVS/Repository | 1 + bin/CVS/Root | 1 + bin/tmp.txt | 1 + obj/CVS/Entries | 2 + obj/CVS/Repository | 1 + obj/CVS/Root | 1 + obj/tmp.txt | 1 + src/CVS/Entries | 44 ++ src/CVS/Repository | 1 + src/CVS/Root | 1 + src/bus.c | 449 +++++++++++++++++ src/bus.h | 91 ++++ src/color.c | 155 ++++++ src/color.h | 59 +++ src/cpu.c | 84 ++++ src/cpu.h | 67 +++ src/disasm.c | 319 ++++++++++++ src/disasm.h | 35 ++ src/display.c | 155 ++++++ src/display.h | 46 ++ src/emulator.c | 210 ++++++++ src/emulator.h | 49 ++ src/gui.c | 233 +++++++++ src/gui.h | 73 +++ src/hdw.c | 193 ++++++++ src/hdw.h | 39 ++ src/keyboard.c | 109 +++++ src/keyboard.h | 39 ++ src/main.c | 124 +++++ src/opcodes.c | 1164 ++++++++++++++++++++++++++++++++++++++++++++ src/opcodes.h | 41 ++ src/opinline.h | 404 +++++++++++++++ src/pabout.c | 119 +++++ src/pabout.h | 38 ++ src/pcalc.c | 210 ++++++++ src/pcalc.h | 38 ++ src/pdebug.c | 267 ++++++++++ src/pdebug.h | 42 ++ src/pfiles.c | 134 +++++ src/pfiles.h | 38 ++ src/pmenu.c | 124 +++++ src/pmenu.h | 38 ++ src/ports.c | 115 +++++ src/ports.h | 38 ++ src/ram.c | 54 ++ src/ram.h | 34 ++ src/rom.c | 84 ++++ src/rom.h | 34 ++ src/rpl.c | 199 ++++++++ src/rpl.h | 38 ++ src/timers.c | 95 ++++ src/timers.h | 41 ++ src/types.h | 42 ++ 61 files changed, 6560 insertions(+) create mode 100644 COPYING.txt create mode 100644 CVS/Entries create mode 100644 CVS/Entries.Log create mode 100644 CVS/Repository create mode 100644 CVS/Root create mode 100644 Makefile create mode 100644 README.txt create mode 100644 bin/CVS/Entries create mode 100644 bin/CVS/Repository create mode 100644 bin/CVS/Root create mode 100644 bin/tmp.txt create mode 100644 obj/CVS/Entries create mode 100644 obj/CVS/Repository create mode 100644 obj/CVS/Root create mode 100644 obj/tmp.txt create mode 100644 src/CVS/Entries create mode 100644 src/CVS/Repository create mode 100644 src/CVS/Root create mode 100644 src/bus.c create mode 100644 src/bus.h create mode 100644 src/color.c create mode 100644 src/color.h create mode 100644 src/cpu.c create mode 100644 src/cpu.h create mode 100644 src/disasm.c create mode 100644 src/disasm.h create mode 100644 src/display.c create mode 100644 src/display.h create mode 100644 src/emulator.c create mode 100644 src/emulator.h create mode 100644 src/gui.c create mode 100644 src/gui.h create mode 100644 src/hdw.c create mode 100644 src/hdw.h create mode 100644 src/keyboard.c create mode 100644 src/keyboard.h create mode 100644 src/main.c create mode 100644 src/opcodes.c create mode 100644 src/opcodes.h create mode 100644 src/opinline.h create mode 100644 src/pabout.c create mode 100644 src/pabout.h create mode 100644 src/pcalc.c create mode 100644 src/pcalc.h create mode 100644 src/pdebug.c create mode 100644 src/pdebug.h create mode 100644 src/pfiles.c create mode 100644 src/pfiles.h create mode 100644 src/pmenu.c create mode 100644 src/pmenu.h create mode 100644 src/ports.c create mode 100644 src/ports.h create mode 100644 src/ram.c create mode 100644 src/ram.h create mode 100644 src/rom.c create mode 100644 src/rom.h create mode 100644 src/rpl.c create mode 100644 src/rpl.h create mode 100644 src/timers.c create mode 100644 src/timers.h create mode 100644 src/types.h diff --git a/COPYING.txt b/COPYING.txt new file mode 100644 index 0000000..dcfa4c2 --- /dev/null +++ b/COPYING.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/CVS/Entries b/CVS/Entries new file mode 100644 index 0000000..66b1ae4 --- /dev/null +++ b/CVS/Entries @@ -0,0 +1,4 @@ +/COPYING.txt/1.1.1.1/Mon Oct 28 14:59:01 2002// +/Makefile/1.1.1.1/Mon Oct 28 14:59:01 2002// +/README.txt/1.2/Mon Oct 28 16:40:18 2002// +D diff --git a/CVS/Entries.Log b/CVS/Entries.Log new file mode 100644 index 0000000..e089a48 --- /dev/null +++ b/CVS/Entries.Log @@ -0,0 +1,3 @@ +A D/bin//// +A D/obj//// +A D/src//// diff --git a/CVS/Repository b/CVS/Repository new file mode 100644 index 0000000..c93a787 --- /dev/null +++ b/CVS/Repository @@ -0,0 +1 @@ +hpemu diff --git a/CVS/Root b/CVS/Root new file mode 100644 index 0000000..7004248 --- /dev/null +++ b/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@a.cvs.sourceforge.net:/cvsroot/hpemu diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e9e4b2d --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +# / +# /__ ___ ___ ____ +# / / / / /__/ / / / / / +# / / /__/ /__ / / /__/ +# / +# / version 0.9.0 +# +# Copyright 2002 Daniel Nilsson +# +# This file is part of hpemu. +# +# Hpemu is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Hpemu is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with hpemu; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +HPEMU = bin/hpemu.exe +OBJS = obj/bus.o obj/color.o obj/cpu.o obj/disasm.o obj/display.o obj/emulator.o obj/gui.o obj/hdw.o obj/keyboard.o obj/main.o obj/opcodes.o obj/pabout.o obj/pcalc.o obj/pdebug.o obj/pfiles.o obj/pmenu.o obj/ports.o obj/ram.o obj/rom.o obj/rpl.o obj/timers.o + +CC = gcc +CFLAGS = -Wall -Werror -O3 + +all: hpemu + +hpemu: $(HPEMU) + +$(HPEMU): $(OBJS) + $(CC) -mwindows -o $@ $+ -lalleg + +obj/%.o: src/%.c + $(CC) $(CFLAGS) -c -o $@ $< + +obj/bus.o: src/types.h src/rom.h src/ram.h src/ports.h src/hdw.h src/bus.h +obj/color.o: src/color.h +obj/cpu.o: src/types.h src/emulator.h src/bus.h src/opcodes.h src/cpu.h +obj/cpu.o: src/types.h src/opcodes.h src/disasm.h +obj/display.o: src/types.h src/bus.h +obj/emulator.o: src/types.h src/cpu.h src/bus.h src/timers.h src/display.h src/gui.h src/pdebug.h src/emulator.h +obj/gui.o: src/color.h src/pmenu.h src/pcalc.h src/pdebug.h src/pfiles.h src/pabout.h src/gui.h +obj/hdw.o: src/types.h src/bus.h src/ports.h src/timers.h src/display.h src/hdw.h +obj/keyboard.o: src/types.h src/cpu.h src/keyboard.h +obj/main.o: src/types.h src/emulator.h src/gui.h src/color.h +obj/opcodes.o: src/types.h src/cpu.h src/bus.h src/keyboard.h src/opcodes.h src/opinline.h +obj/pabout.o: src/color.h src/gui.h src/pabout.h +obj/pcalc.o: src/color.h src/display.h src/keyboard.h src/gui.h src/pcalc.h +obj/pdebug.o: src/types.h src/emulator.h src/cpu.h src/bus.h src/disasm.h src/color.h src/gui.h src/pdebug.h +obj/pfiles.o: src/color.h src/gui.h src/rpl.h src/pfiles.h +obj/pmenu.o: src/emulator.h src/color.h src/gui.h src/pmenu.h +obj/ports.o: src/types.h src/bus.h src/ports.h +obj/ram.o: src/types.h src/bus.h src/ram.h +obj/rom.o: src/types.h src/bus.h src/rom.h +obj/rpl.o: src/types.h src/bus.h src/opinline.h src/rpl.h +obj/timers.o: src/types.h src/cpu.h src/timers.h + + + + + diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..e37d12f --- /dev/null +++ b/README.txt @@ -0,0 +1,128 @@ + / + /__ ___ ___ ____ + / / / / /__/ / / / / / + / / /__/ /__ / / /__/ + / + / version 0.9.0 + +Copyright 2002 Daniel Nilsson + +This file is part of hpemu. + +Hpemu is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +Hpemu is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with hpemu; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +The GNU General Public License is included in the file COPYING.txt + + +******************** +*** INTRODUCTION *** +******************** + +Hpemu is an emulator for the HP48GX calculator. +Hpemu is intended for developers of software for the calculator but +other people may find it usefull too. +It is developed for the windows platform but should be easy to port to +other platforms. + + +**************** +*** FEATURES *** +**************** + +Features of the HP48 that are implemented in this version: + + * Saturn CPU (most instructions) + * Daisy-chain + * ROM + * RAM + * Card ports 1 & 2 (untested) + * Bank-switcher (untested) + * Hardware registers (some of them) + * Hardware CRC + * Timer1 (not complete) + * Timer2 (not complete) + * Interrup system (not complete) + * LCD (grayscale) + * Keyboard (not complete) + +Unimplemented features: + + * Indicators above LCD + * UART + * IR + * Speaker + * Things marked "not complete" + +******************** +*** INSTALLATION *** +******************** + +If you have the Windows binary distribution (hpemu-X.Y.Z-win32.zip): + +1. Unzip the file in a new directory. You should get these files: + + bin\hpemu.exe - The program itself + bin\allegNN.dll - Allegro DLL needed to run hpemu + README.txt - This file + COPYING.txt - The GNU General Public License + +2. Get a dump of the calculator's ROM and save it as hpemu.rom in the + same directory as phemu.exe. (ROM revision R is known to work) + +3. Execute hpemu.exe + + +If you have the source distribution (hpemu-X.Y.Z-src.zip): + +1. Unzip the file in a new directory. + You should get a bunch of .c and .h files in the src directory + and some other files. + +2. Make sure you have the Allegro library and headers properly + installed (http://alleg.sourceforge.net/) + +3a. A makefile for MinGW is included so if that is your compiler just + execute make to build the program. + +3b. If you use another compiler or platform you will need to get all + files compiled and linked against the Allegro library. If you get + hpemu to work on another platform please contact me and tell me if + you had any problems. + +4. Get a dump of the calculators ROM and save it as hpemu.rom in the + same directory as the executable. (ROM revision R is known to work) + +5. Execute the program. + + +**************************** +*** COMMAND LINE OPTIONS *** +**************************** + +The command line options are: + + -f Run program i fullscreen + -w Run program i a window + + +******************** +*** CONTACT INFO *** +******************** + +Latest version of hpemu can allways be found on the hpemu homepage: +sourceforge.net/projects/hpemu + +Contact the author: + Daniel Nilsson diff --git a/bin/CVS/Entries b/bin/CVS/Entries new file mode 100644 index 0000000..c86cdd7 --- /dev/null +++ b/bin/CVS/Entries @@ -0,0 +1,2 @@ +/tmp.txt/1.1.1.1/Mon Oct 28 14:59:01 2002// +D diff --git a/bin/CVS/Repository b/bin/CVS/Repository new file mode 100644 index 0000000..357ce38 --- /dev/null +++ b/bin/CVS/Repository @@ -0,0 +1 @@ +hpemu/bin diff --git a/bin/CVS/Root b/bin/CVS/Root new file mode 100644 index 0000000..7004248 --- /dev/null +++ b/bin/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@a.cvs.sourceforge.net:/cvsroot/hpemu diff --git a/bin/tmp.txt b/bin/tmp.txt new file mode 100644 index 0000000..9c81019 --- /dev/null +++ b/bin/tmp.txt @@ -0,0 +1 @@ +Needed to keep empty directory. \ No newline at end of file diff --git a/obj/CVS/Entries b/obj/CVS/Entries new file mode 100644 index 0000000..c86cdd7 --- /dev/null +++ b/obj/CVS/Entries @@ -0,0 +1,2 @@ +/tmp.txt/1.1.1.1/Mon Oct 28 14:59:01 2002// +D diff --git a/obj/CVS/Repository b/obj/CVS/Repository new file mode 100644 index 0000000..0e147bb --- /dev/null +++ b/obj/CVS/Repository @@ -0,0 +1 @@ +hpemu/obj diff --git a/obj/CVS/Root b/obj/CVS/Root new file mode 100644 index 0000000..7004248 --- /dev/null +++ b/obj/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@a.cvs.sourceforge.net:/cvsroot/hpemu diff --git a/obj/tmp.txt b/obj/tmp.txt new file mode 100644 index 0000000..9c81019 --- /dev/null +++ b/obj/tmp.txt @@ -0,0 +1 @@ +Needed to keep empty directory. \ No newline at end of file diff --git a/src/CVS/Entries b/src/CVS/Entries new file mode 100644 index 0000000..798d689 --- /dev/null +++ b/src/CVS/Entries @@ -0,0 +1,44 @@ +/bus.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/bus.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/color.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/color.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/cpu.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/cpu.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/disasm.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/disasm.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/display.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/display.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/emulator.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/emulator.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/gui.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/gui.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/hdw.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/hdw.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/keyboard.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/keyboard.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/main.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/opcodes.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/opcodes.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/opinline.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pabout.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pabout.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pcalc.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pcalc.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pdebug.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pdebug.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pfiles.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pfiles.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pmenu.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/pmenu.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/ports.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/ports.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/ram.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/ram.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/rom.c/1.1.1.1/Mon Oct 28 14:59:01 2002// +/rom.h/1.1.1.1/Mon Oct 28 14:59:01 2002// +/rpl.c/1.1.1.1/Mon Oct 28 14:59:02 2002// +/rpl.h/1.1.1.1/Mon Oct 28 14:59:02 2002// +/timers.c/1.1.1.1/Mon Oct 28 14:59:02 2002// +/timers.h/1.1.1.1/Mon Oct 28 14:59:02 2002// +/types.h/1.1.1.1/Mon Oct 28 14:59:02 2002// +D diff --git a/src/CVS/Repository b/src/CVS/Repository new file mode 100644 index 0000000..f095153 --- /dev/null +++ b/src/CVS/Repository @@ -0,0 +1 @@ +hpemu/src diff --git a/src/CVS/Root b/src/CVS/Root new file mode 100644 index 0000000..7004248 --- /dev/null +++ b/src/CVS/Root @@ -0,0 +1 @@ +:pserver:anonymous@a.cvs.sourceforge.net:/cvsroot/hpemu diff --git a/src/bus.c b/src/bus.c new file mode 100644 index 0000000..a9ef462 --- /dev/null +++ b/src/bus.c @@ -0,0 +1,449 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "rom.h" +#include "ram.h" +#include "ports.h" +#include "hdw.h" +#include "bus.h" + +BusInfo bus_info = { +// hdw ram sz ram ce1 sz ce1 ce2 sz ce2 nce3 sz nce3 + 0x00000,0x00000,0x00000,0x00000,0x00000,0x00000,0x00000,0x00000,0x00000, // base or size + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, // configured + FALSE, FALSE, FALSE, // read only +// ce1_bs da19 ben + FALSE, FALSE, FALSE, +// rom ram ce1 ce2 nce3 + NULL, NULL, NULL, NULL, NULL, // data + 0x00000,0x00000,0x00000,0x00000,0x00000 // mask +}; + +static byte *read_map[256]; +static byte *write_map[256]; +static address hdw_seg; + +#define SEG_OF(adr) ((adr)>>12) +#define OFFSET_OF(adr) ((adr)&0xFFF) +#define CAN_READ(adr) (read_map[SEG_OF(adr)] != NULL) +#define CAN_WRITE(adr) (write_map[SEG_OF(adr)] != NULL) +#define MAP_READ(adr) (read_map[SEG_OF(adr)]+OFFSET_OF(adr)) +#define MAP_WRITE(adr) (write_map[SEG_OF(adr)]+OFFSET_OF(adr)) + +#define MIN(a,b) ((a)<(b)?(a):(b)) + +word crc; + +void bus_init(void) +{ + rom_init(); + hdw_init(); + ram_init(); + ports_init(); + bus_reset(); +} + +void bus_exit(void) +{ + rom_exit(); + hdw_exit(); + ram_exit(); + ports_exit(); +} + +static __inline void update_crc(byte nibble) +{ + crc = (crc >> 4) ^ (((crc ^ nibble) & 0xF) * 0x1081); +} + +void bus_read(byte *buf, address adr, address len) +{ + int n, i; + + while (TRUE) { + if (hdw_seg == SEG_OF(adr) && ((bus_info.hdw_base ^ adr) & 0xFFFC0) == 0) { + n = MIN(len, 0x40 - (adr & 0x3F)); + for (i = 0; i < n; i++) { + buf[i] = hdw_read_nibble((adr & 0x3F) + i); + } + if (((adr & 0x3F) + n) == 0x40) { + update_crc(buf[n-1]); + } + } else { + if (hdw_seg == SEG_OF(adr) && (bus_info.hdw_base & 0xFFFC0) - adr > 0) { + n = MIN(len, (bus_info.hdw_base & 0xFFFC0) - adr); + } else { + n = MIN(len, 0x1000 - OFFSET_OF (adr)); + } + if (CAN_READ(adr)) { + memcpy(buf, MAP_READ(adr), n); + } else { + for (i = 0; i < n; i++) { + buf[i] = ((i+adr)&1) ? 0xE : 0xD; + } + if (bus_info.ce1_bs && bus_info.ce1_cfg && + ((bus_info.ce1_base ^ adr) & bus_info.ce1_size)) { + ports_switch_bank(OFFSET_OF(adr+n)); + } + } + for (i = 0; i < n; i++) { + update_crc(buf[i]); + } + } + len -= n; + if (!len) { + break; + } + buf += n; + adr += n; + adr &= 0xFFFFF; + } +} + +void bus_write(byte *buf, address adr, address len) +{ + int n, i; + + while (TRUE) { + if (hdw_seg == SEG_OF(adr) && ((bus_info.hdw_base ^ adr) & 0xFFFC0) == 0) { + n = MIN(len, 0x40 - (adr & 0x3F)); + for (i = 0; i < n; i++) { + hdw_write_nibble(buf[i], (adr & 0x3F) + i); + } + } else { + if (hdw_seg == SEG_OF(adr) && (bus_info.hdw_base & 0xFFFC0) - adr > 0) { + n = MIN(len, (bus_info.hdw_base & 0xFFFC0) - adr); + } else { + n = MIN(len, 0x1000 - OFFSET_OF (adr)); + } + if (CAN_WRITE(adr)) { + memcpy (MAP_WRITE(adr), buf, n); + } else if (bus_info.ce1_bs) { + if (bus_info.ce1_cfg && ((bus_info.ce1_base ^ adr) & bus_info.ce1_size)) { + if (!bus_info.nce3_r_o) { + ports_switch_bank(OFFSET_OF(adr+n-1)); + } else if ((adr+n) & 1) { + ports_switch_bank(OFFSET_OF(adr+n-1)); + } else if (adr & 0x1) { + ports_switch_bank(OFFSET_OF(adr)); + } + } + } + } + len -= n; + if (!len) { + break; + } + buf += n; + adr += n; + adr &= 0xFFFFF; + } +} + +static void bus_peek(byte *buf, address adr, address len) +{ + int n, i; + + while (TRUE) { + if (hdw_seg == SEG_OF(adr) && ((bus_info.hdw_base ^ adr) & 0xFFFC0) == 0) { + n = MIN(len, 0x40 - (adr & 0x3F)); + for (i = 0; i < n; i++) { + buf[i] = hdw_read_nibble((adr & 0x3F) + i); + } + } else { + if (hdw_seg == SEG_OF(adr) && (bus_info.hdw_base & 0xFFFC0) - adr > 0) { + n = MIN(len, (bus_info.hdw_base & 0xFFFC0) - adr); + } else { + n = MIN(len, 0x1000 - OFFSET_OF (adr)); + } + if (CAN_READ(adr)) { + memcpy(buf, MAP_READ(adr), n); + } else { + for (i = 0; i < n; i++) { + buf[i] = ((i+adr)&1) ? 0xE : 0xD; + } + } + } + len -= n; + if (!len) { + break; + } + buf += n; + adr += n; + adr &= 0xFFFFF; + } +} + +/* Call only when you know that hdw is not in the range of nibbles read */ +static void bus_peek_no_hdw(byte *buf, address adr, address len) +{ + int n, i; + + while (TRUE) { + n = MIN(len, 0x1000 - OFFSET_OF(adr)); + if (CAN_READ(adr)) { + memcpy(buf, MAP_READ(adr), n); + } else { + for (i = 0; i < n; i++) { + buf[i] = ((i+adr)&1) ? 0xE : 0xD; + } + } + len -= n; + if (!len) { + break; + } + buf += n; + adr += n; + adr &= 0xFFFFF; + } +} + + +/* Returns a pointer for fast read access to memory (don't write). + * If a direct pointer can't be returnd it will use the caller supplied buffer instead. + * If the buffer is not used the pointer returned is valid as long as bus_info.map_cnt + * has the same value (until a call to bus_remap). + * If the buffer is used the pointer returned (== buf) is valid only until the memory + * is written to. + * Set len to the number of nibbles you want to access. It is changed to the actual number of + * nibbles that can safetly be read through the pointer (can be more or less then the original). + */ +byte *bus_fast_peek(byte *buf, address adr, int *len) +{ + static byte tmp_buf[FAST_PEEK_MAX]; + static int tmp_len; + address adr2; + + if (!buf) { + buf = tmp_buf; + } + if (!len) { + tmp_len = FAST_PEEK_MAX; + len = &tmp_len; + } + if (*len > FAST_PEEK_MAX) { + *len = FAST_PEEK_MAX; + } + + adr2 = adr + *len - 1; + + if ((SEG_OF(adr) == hdw_seg || SEG_OF(adr2) == hdw_seg) && + (((bus_info.hdw_base ^ adr) & 0xFFFC0) == 0 || + ((bus_info.hdw_base ^ adr2) & 0xFFFC0) == 0)) { + bus_peek(buf, adr, *len); + return buf; + } else if (!CAN_READ(adr)) { + bus_peek_no_hdw(buf, adr, *len); + return buf; + } else if (SEG_OF(adr) == SEG_OF(adr2)) { + if (hdw_seg == SEG_OF(adr) && (bus_info.hdw_base & 0xFFFC0) - adr > 0) { + *len = (bus_info.hdw_base & 0xFFFC0) - adr; + } else { + *len = 0x1000 - OFFSET_OF (adr); + } + return MAP_READ(adr); + } else if (CAN_READ(adr2) && MAP_READ(adr) + *len-1 == MAP_READ(adr2)) { + if (hdw_seg == SEG_OF(adr2)) { + *len = (bus_info.hdw_base & 0xFFFC0) - adr; + } else { + *len = 0x2000 - OFFSET_OF(adr); + } + return MAP_READ(adr); + } else { + bus_peek_no_hdw(buf, adr, *len); + return buf; + } +} + +void bus_remap(void) +{ + int adr; + + for (adr = 0; adr < 0x100000; adr += 0x01000) { + if (bus_info.ram_cfg && ((bus_info.ram_base ^ adr) & bus_info.ram_size) == 0) { + read_map[SEG_OF(adr)] = bus_info.ram_data + (adr & bus_info.ram_mask); + write_map[SEG_OF(adr)] = bus_info.ram_data + (adr & bus_info.ram_mask); + } else if (bus_info.ce2_cfg && ((bus_info.ce2_base ^ adr) & bus_info.ce2_size) == 0) { + if (bus_info.ce2_data) { + read_map[SEG_OF(adr)] = bus_info.ce2_data + (adr & bus_info.ce2_mask); + if (!bus_info.ce2_r_o) { + write_map[SEG_OF(adr)] = bus_info.ce2_data + (adr & bus_info.ce2_mask); + } else { + write_map[SEG_OF(adr)] = NULL; + } + } else { + read_map[SEG_OF(adr)] = NULL; + write_map[SEG_OF(adr)] = NULL; + } + } else if (bus_info.ce1_cfg && ((bus_info.ce1_base ^ adr) & bus_info.ce1_size) == 0) { + if (bus_info.ce1_data) { + read_map[SEG_OF(adr)] = bus_info.ce1_data + (adr & bus_info.ce1_mask); + if (!bus_info.ce1_r_o) { + write_map[SEG_OF(adr)] = bus_info.ce1_data + (adr & bus_info.ce1_mask); + } else { + write_map[SEG_OF(adr)] = NULL; + } + } else { + read_map[SEG_OF(adr)] = NULL; + write_map[SEG_OF(adr)] = NULL; + } + } else if (bus_info.nce3_cfg && ((bus_info.nce3_base ^ adr) & bus_info.nce3_size) == 0) { + if (bus_info.nce3_data && bus_info.ben && !bus_info.da19) { + read_map[SEG_OF(adr)] = bus_info.nce3_data + (adr & bus_info.nce3_mask); + if (!bus_info.nce3_r_o) { + write_map[SEG_OF(adr)] = bus_info.nce3_data + (adr & bus_info.nce3_mask); + } else { + write_map[SEG_OF(adr)] = NULL; + } + } else { + read_map[SEG_OF(adr)] = NULL; + write_map[SEG_OF(adr)] = NULL; + } + } else { + read_map[SEG_OF(adr)] = bus_info.rom_data + (adr & bus_info.rom_mask & (bus_info.da19 ? 0xFFFFF : 0x7FFFF)); + write_map[SEG_OF(adr)] = NULL; + } + } + bus_info.map_cnt++; // Flag that pointers returned by bus_fast_peek may be invalid +} + +void bus_configure(address adr) +{ + if (!bus_info.hdw_cfg) { + bus_info.hdw_base = adr & 0xFFFC0; + bus_info.hdw_cfg = TRUE; + hdw_seg = SEG_OF (adr); + } else if (!bus_info.ram_sz_cfg) { + bus_info.ram_size = adr & 0xFF000; + bus_info.ram_sz_cfg = TRUE; + } else if (!bus_info.ram_cfg) { + bus_info.ram_base = adr & 0xFF000; + bus_info.ram_cfg = TRUE; + bus_remap(); + } else if (!bus_info.ce1_sz_cfg) { + bus_info.ce1_size = adr & 0xFF000; + bus_info.ce1_sz_cfg = TRUE; + } else if (!bus_info.ce1_cfg) { + bus_info.ce1_base = adr & 0xFF000; + bus_info.ce1_cfg = TRUE; + bus_remap(); + } else if (!bus_info.ce2_sz_cfg) { + bus_info.ce2_size = adr & 0xFF000; + bus_info.ce2_sz_cfg = TRUE; + } else if (!bus_info.ce2_cfg) { + bus_info.ce2_base = adr & 0xFF000; + bus_info.ce2_cfg = TRUE; + bus_remap(); + } else if (!bus_info.nce3_sz_cfg) { + bus_info.nce3_size = adr & 0xFF000; + bus_info.nce3_sz_cfg = TRUE; + } else if (!bus_info.nce3_cfg) { + bus_info.nce3_base = adr & 0xFF000; + bus_info.nce3_cfg = TRUE; + bus_remap(); + } +} + +void bus_unconfigure(address adr) +{ + if (bus_info.hdw_cfg && ((adr ^ bus_info.hdw_base) & 0xFFFC0) == 0) { + bus_info.hdw_cfg = FALSE; + hdw_seg = -1; + } else if (bus_info.ram_cfg && ((adr ^ bus_info.ram_base) & bus_info.ram_size) == 0) { + bus_info.ram_cfg = FALSE; + bus_info.ram_sz_cfg = FALSE; + bus_remap(); + } else if (bus_info.ce2_cfg && ((adr ^ bus_info.ce2_base) & bus_info.ce2_size) == 0) { + bus_info.ce2_cfg = FALSE; + bus_info.ce2_sz_cfg = FALSE; + bus_remap(); + } else if (bus_info.ce1_cfg && ((adr ^ bus_info.ce1_base) & bus_info.ce1_size) == 0) { + bus_info.ce1_cfg = FALSE; + bus_info.ce1_sz_cfg = FALSE; + bus_remap(); + } else if (bus_info.nce3_cfg && ((adr ^ bus_info.nce3_base) & bus_info.nce3_size) == 0) { + bus_info.nce3_cfg = FALSE; + bus_info.nce3_sz_cfg = FALSE; + bus_remap(); + } +} + +void bus_reset(void) +{ + bus_info.hdw_base = 0x00000; + bus_info.hdw_cfg = FALSE; + + bus_info.ram_base = 0x00000; + bus_info.ram_size = 0x00000; + bus_info.ram_cfg = FALSE; + bus_info.ram_sz_cfg = FALSE; + + bus_info.ce1_base = 0x00000; + bus_info.ce1_size = 0x00000; + bus_info.ce1_cfg = FALSE; + bus_info.ce1_sz_cfg = FALSE; + + bus_info.ce2_base = 0x00000; + bus_info.ce2_size = 0x00000; + bus_info.ce2_cfg = FALSE; + bus_info.ce2_sz_cfg = FALSE; + + bus_info.nce3_base = 0x00000; + bus_info.nce3_size = 0x00000; + bus_info.nce3_cfg = FALSE; + bus_info.nce3_sz_cfg = FALSE; + + hdw_seg = -1; + bus_remap(); +} + +address bus_get_id(void) +{ + if (!bus_info.hdw_cfg) { + return bus_info.hdw_base | 0x00019; + } else if (!bus_info.ram_sz_cfg) { + return bus_info.ram_size | 0x00003; + } else if (!bus_info.ram_cfg) { + return bus_info.ram_base | 0x000F4; + } else if (!bus_info.ce1_sz_cfg) { + return bus_info.ce1_size | 0x00005; + } else if (!bus_info.ce1_cfg) { + return bus_info.ce1_base | 0x000F6; + } else if (!bus_info.ce2_sz_cfg) { + return bus_info.ce2_size | 0x00007; + } else if (!bus_info.ce2_cfg) { + return bus_info.ce2_base | 0x000F8; + } else if (!bus_info.nce3_sz_cfg) { + return bus_info.nce3_size | 0x00001; + } else if (!bus_info.nce3_cfg) { + return bus_info.nce3_base | 0x000F2; + } else { + return 0x00000; + } +} diff --git a/src/bus.h b/src/bus.h new file mode 100644 index 0000000..130f634 --- /dev/null +++ b/src/bus.h @@ -0,0 +1,91 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __BUS_H +#define __BUS_H + +#include "types.h" + +typedef struct { + address hdw_base; + address ram_size; + address ram_base; + address ce1_size; + address ce1_base; + address ce2_size; + address ce2_base; + address nce3_size; + address nce3_base; + boolean hdw_cfg :1; + boolean ram_sz_cfg :1; + boolean ram_cfg :1; + boolean ce1_sz_cfg :1; + boolean ce1_cfg :1; + boolean ce2_sz_cfg :1; + boolean ce2_cfg :1; + boolean nce3_sz_cfg :1; + boolean nce3_cfg :1; + boolean ce1_r_o :1; + boolean ce2_r_o :1; + boolean nce3_r_o :1; + boolean ce1_bs :1; + boolean da19 :1; + boolean ben :1; + byte *rom_data; + byte *ram_data; + byte *ce1_data; + byte *ce2_data; + byte *nce3_data; + address rom_mask; + address ram_mask; + address ce1_mask; + address ce2_mask; + address nce3_mask; + dword map_cnt; +} BusInfo; + +extern BusInfo bus_info; + +extern word crc; + +// FAST_PEEK_MAX must not be greater than the size of the hdw registers (64) +#define FAST_PEEK_MAX 64 + +void bus_init(void); +void bus_exit(void); + +void bus_read(byte *buf, address adr, address len); +void bus_write(byte *buf, address adr, address len); +byte *bus_fast_peek(byte *buf, address adr, address *len); + +void bus_remap(void); +void bus_configure(address adr); +void bus_unconfigure(address adr); +void bus_reset(void); +address bus_get_id(); + +#endif diff --git a/src/color.c b/src/color.c new file mode 100644 index 0000000..8e84997 --- /dev/null +++ b/src/color.c @@ -0,0 +1,155 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "color.h" + +#define RESERVED_LCD 128 + +int color[C_COUNT]; + +static PALETTE palette; + +static int lcd_0_r, lcd_0_g, lcd_0_b; +static int lcd_1_r, lcd_1_g, lcd_1_b; +static int lcd_mode; + +static void set_lcd_color(int i, int v) +{ + palette[i].r = (lcd_0_r * (255 - v) + lcd_1_r * v) / 255; + palette[i].g = (lcd_0_g * (255 - v) + lcd_1_g * v) / 255; + palette[i].b = (lcd_0_b * (255 - v) + lcd_1_b * v) / 255; +} + +static int bit_count(unsigned int i) +{ + int n = 0; + + while (i) { + n += i & 1; + i >>= 1; + } + return n; +} + +static int simple_color(int i) +{ + return (i & 0x40) ? 255 : 0; +} + +static int gray4_color(int i) +{ + return bit_count(i & 0x70) * 85; +} + +static int gray8_color(int i) +{ + return bit_count(i) * 255 / 7; +} + +static int exp_color(int i) +{ + return i * 255 / 127; +} + +typedef int (*lcd_color_func)(int i); + +lcd_color_func lcd_color_functions[] = { + simple_color, + gray4_color, + gray8_color, + exp_color +}; + +static void build_lcd_palette(void) +{ + int i; + + for (i = 0; i < RESERVED_LCD; i++) { + set_lcd_color(i, lcd_color_functions[lcd_mode](i)); + } + + set_palette_range(palette, 0, RESERVED_LCD-1, FALSE); +} + +void color_lcd(int r0, int g0, int b0, int r1, int g1, int b1) +{ + lcd_0_r = r0 >> 2; + lcd_0_g = g0 >> 2; + lcd_0_b = b0 >> 2; + lcd_1_r = r1 >> 2; + lcd_1_g = g1 >> 2; + lcd_1_b = b1 >> 2; + build_lcd_palette(); +} + +void color_lcd_mode(int mode) +{ + lcd_mode = mode; + build_lcd_palette(); +} + +void color_set(int i, int r, int g, int b) +{ + if (bitmap_color_depth(screen) == 8) { + palette[color[i]].r = r >> 2; + palette[color[i]].g = g >> 2; + palette[color[i]].b = b >> 2; + set_color(color[i], palette + color[i]); + } else { + color[i] = makecol(r, g, b); + } +} + +void color_init(void) +{ + int i; + + if (bitmap_color_depth(screen) == 8) { + for (i = 0; i < C_COUNT; i++) { + color[i] = RESERVED_LCD + i; + } + } + color_set(C_BACKGROUND, 0, 0, 0); + color_set(C_PANEL_BACK, 64, 64, 64); + color_set(C_PANEL_BORDER, 128, 128, 128); + color_set(C_PANEL_TEXT, 255, 255, 255); + color_set(C_PANEL_DISABLED, 128, 128, 128); + color_set(C_BUTTON_BACK, 64, 64, 64); + color_set(C_BUTTON_BORDER, 128, 128, 128); + color_set(C_BUTTON_PUSHED, 128, 128, 128); + color_set(C_BUTTON_TEXT, 255, 255, 255); + color_set(C_BUTTON_DISABLED,128, 128, 128); + + color_lcd(128, 192, 128, 0, 0, 64); + color_lcd_mode(LCD_MODE_GRAY4); + set_palette(palette); + set_mouse_sprite(NULL); + gui_bg_color = color[C_PANEL_BACK]; + gui_mg_color = color[C_PANEL_DISABLED]; + gui_fg_color = color[C_PANEL_TEXT]; +} diff --git a/src/color.h b/src/color.h new file mode 100644 index 0000000..e2d93aa --- /dev/null +++ b/src/color.h @@ -0,0 +1,59 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __COLOR_H +#define __COLOR_H + +enum LCD_Modes { + LCD_MODE_SIMPLE, + LCD_MODE_GRAY4, + LCD_MODE_GRAY8, + LCD_MODE_EXP +}; + +enum Colors { + C_BACKGROUND, + C_PANEL_BACK, + C_PANEL_BORDER, + C_PANEL_TEXT, + C_PANEL_DISABLED, + C_BUTTON_BACK, + C_BUTTON_BORDER, + C_BUTTON_PUSHED, + C_BUTTON_TEXT, + C_BUTTON_DISABLED, + C_COUNT +}; + +extern int color[C_COUNT]; + +void color_lcd(int r0, int g0, int b0, int r1, int g1, int b1); +void color_lcd_mode(int mode); +void color_set(int i, int r, int g, int b); +void color_init(void); + +#endif diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 0000000..c2f5684 --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,84 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "types.h" +#include "emulator.h" +#include "bus.h" +#include "opcodes.h" +#include "cpu.h" + +Cpu cpu; + +#define MAX_OPC_LEN 21 + +void cpu_interrupt(void) +{ + if (cpu.inte) { + cpu.inte = FALSE; + cpu.rstk_ptr = (cpu.rstk_ptr - 1) & 7; + cpu.rstk[cpu.rstk_ptr] = cpu.pc; + cpu.pc = 0x0000F; + } +} + +static void decode(byte *ptr) +{ + Opcode *op = opcodes; + int i = 0; + + while (op[ptr[i]].next) { + op = op[ptr[i]].next; + i++; + } + if (op[ptr[i]].exec) { + op[ptr[i]].exec(ptr); + cpu.pc &= 0xFFFFF; + cpu.inst_cnt++; + } else { + emulator_set_state(EMULATOR_STOP); + } +} + +void execute_instruction(void) +{ + static byte buffer[FAST_PEEK_MAX]; + static byte *ptr; + static dword old_map_cnt; + static address len; + static address adr; + + if (cpu.pc < adr || adr + len < cpu.pc + MAX_OPC_LEN || bus_info.map_cnt != old_map_cnt || !ptr) { + len = MAX_OPC_LEN; + adr = cpu.pc; + ptr = bus_fast_peek(buffer, adr, &len); + old_map_cnt = bus_info.map_cnt; + if (ptr == buffer) { // Not direct memory access + old_map_cnt--; // Force new peek next time + } + } + decode(ptr + cpu.pc - adr); +} diff --git a/src/cpu.h b/src/cpu.h new file mode 100644 index 0000000..b619a31 --- /dev/null +++ b/src/cpu.h @@ -0,0 +1,67 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CPU_H +#define __CPU_H + +#include "types.h" + +typedef struct { + byte reg[4][16]; + byte reg_r[5][16]; + byte st[4]; + byte in[4]; + byte out[3]; + byte hst; + byte p; + address d[2]; + address pc; + address rstk[8]; + int rstk_ptr; + boolean carry :1; + boolean dec :1; + boolean shutdown :1; + boolean inte :1; + boolean keyscan :1; + boolean keyintp :1; + dword cycles; + dword inst_cnt; +} Cpu; + +#define HST_XM 1 +#define HST_SB 2 +#define HST_SR 4 +#define HST_MP 8 + +enum RegisterNames { A, B, C, D }; + +extern Cpu cpu; + +void cpu_interrupt(void); +void execute_instruction(void); + +#endif diff --git a/src/disasm.c b/src/disasm.c new file mode 100644 index 0000000..0e44313 --- /dev/null +++ b/src/disasm.c @@ -0,0 +1,319 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "opcodes.h" +#include "disasm.h" + +static const char hex_tab[16] = "0123456789ABCDEF"; + +static const char r_tab[11][16] = { + "ABCDABCDBCACBCAC", // p + "BCAC1111ABCDABCD", // q + "ABCDBCACABCDBCAC", // r + "BCACABCDBCACABCD", // s + "ABCDABCDBCACABCD", // t + "ABCDABCDABCDABCD", // u (different than in opcodes.c) + "BCACBCACBCACBCAC", // v (different than in opcodes.c) + "BCACABCDABCD1111", // w + "ABCDABCDBCACABAC", // x + "0000BCACABCDBCCD", // y + "BCACBCAC00000000", // z +}; + +static const char *f_tab[8] = { "P", "WP", "XS", "X", "S", "M", "B", "W" }; + +#define HEX(x) (hex_tab[x]) + +#define ADD_OFFSET(x,s) do { if (*(s) == '+') { \ + (s)++; \ + (x) += *(s)++ - '0'; \ + } } while (0) + +static __inline int nib_to_signed(byte *nib, int len) +{ + int x; + + len--; + x = nib[len]; + if (x & 8) x -= 16; + while (len--) { + x <<= 4; + x |= nib[len]; + } + return x; +} + +static void expand(char *dest, char *src, byte *ptr) +{ + int i, n; + int x; + + while (*src) { + if (*src != '%') { + *dest++ = *src++; + } else { + src++; + switch (*src++) { + + case 'I': // One digit integer + i = *src++ - '0'; + x = ptr[i]; + ADD_OFFSET(x, src); + if (x >= 10) { + *dest++ = '0' + x / 10; + *dest++ = '0' + x % 10; + } else { + *dest++ = '0' + x; + } + break; + + case 'X': // Hexadecimal number + i = *src++ - '0'; + n = *src++ - '0'; + while (n--) { + *dest++ = HEX(ptr[i+n]); + } + break; + + case 'N': // Variable length hexadecimal number + i = *src++ - '0'; + n = ptr[i] + 1; + while (n) { + *dest++ = HEX(ptr[i+n]); + n--; + } + break; + + case 'R': // Relative address + i = *src++ - '0'; + n = *src++ - '0'; + x = nib_to_signed(ptr + i, n); + ADD_OFFSET(x, src); + if (x < 0) { + *dest++ = '-'; + x = -x; + } else { + *dest++ = '+'; + } + while (n--) { + *dest++ = HEX((x >> (n*4)) & 0xF); + } + break; + + case 'T': // Relative address for tests + i = *src++ - '0'; + n = *src++ - '0'; + x = nib_to_signed(ptr + i, n); + if (x == 0) { + ADD_OFFSET (x, src); // skip over the optional "+i" + break; + } + ADD_OFFSET (x, src); + if (x < 0) { + *dest++ = '-'; + x = -x; + } else { + *dest++ = '+'; + } + while (n--) { + *dest++ = HEX((x >> (n*4)) & 0xF); + } + break; + + case 'G': // "GO" or "RTN" for tests + i = *src++ - '0'; + n = *src++ - '0'; + x = nib_to_signed(ptr + i, n); + if (x == 0) { + *dest++ = 'R'; + *dest++ = 'T'; + *dest++ = 'N'; + } else { + *dest++ = 'G'; + *dest++ = 'O'; + } + break; + + case 'F': // Field name + i = *src++ - '0'; + if (*src == 'A') { + src++; + if (ptr[i] == 0xF) { + *dest++ = 'A'; + break; + } + } + *dest++ = f_tab[ptr[i]&7][0]; + if (f_tab[ptr[i]&7][1]) + *dest++ = f_tab[ptr[i]&7][1]; + break; + + case 'B': // Field A or B + i = *src++ -'0'; + *dest++ = (ptr[i]&8) ? 'B' : 'A'; + break; + + case 'p': // Subtraction source 1 + case 'q': // Subtraction source 2 + case 'r': // Logic destination & source 1 + case 's': // Logic source 2 + case 't': // Arithmethic destination & addition source 1 + case 'u': // Compare source 1 + case 'v': // Compare source 2 for <, >, <= and >= + case 'w': // Addition source 2 + case 'x': // Assignment destination + case 'y': // Assignment source + case 'z': // Compare source 2 for = and # + i = *src++ - '0'; + *dest++ = r_tab[src[-2]-'p'][ptr[i]]; + break; + + case 'a': // "A" or "C" + i = *src++ - '0'; + *dest++ = (ptr[i]&8) ? 'C' : 'A'; + break; + + case 'i': // R-register number + i = *src++ - '0'; + *dest++ = '0' + ((ptr[i]&7) > 4 ? ptr[i]&3 : ptr[i]&7); + break; + + case '#': // "#" or "=" for comparisons + i = *src++ - '0'; + *dest++ = (ptr[i]&4) ? '#' : '='; + break; + + case '>': // ">", "<", ">=" or "<=" for comparisons + i = *src++ - '0'; + *dest++ = (ptr[i] & 4) ? '<' : '>'; + if (ptr[i] & 8) *dest++ = '='; + break; + + case '=': // Conditional "=" for assignments + i = *src++ - '0'; + if (ptr[i] < 0xC) *dest++ = '='; + break; + + case 'E': // Conditionsl "EX" for assignments + i = *src++ - '0'; + if (ptr[i] >= 0xC) { + *dest++ = 'E'; + *dest++ = 'X'; + } + break; + + case '+': // "+" or "-" for add / dec + i = *src++ - '0'; + *dest++ = (ptr[i] < 0xC) ? '+' : '-'; + break; + + case '-': // "-" or "+" for sub / inc + i = *src++ - '0'; + *dest++ = ((ptr[i]&0xC) != 0x4) ? '-' : '+'; + break; + + case '~': // "+" or "-" for +con and -con + i = *src++ - '0'; + *dest++ = (ptr[i]&8) ? '-' : '+'; + break; + + case '&': // "&" or "!" for and / or + i = *src++ - '0'; + *dest++ = (ptr[i]&8) ? '!' : '&'; + break; + + case 'D': // DATi=r or r=DATi + i = *src++ - '0'; + if (!(ptr[i]&2)) { + *dest++ = 'D'; + *dest++ = 'A'; + *dest++ = 'T'; + *dest++ = '0' + (ptr[i]&1); + *dest++ = '='; + *dest++ = 'A' + ((ptr[i]&4)>>1); + } else { + *dest++ = 'A' + ((ptr[i]&4)>>1); + *dest++ = '='; + *dest++ = 'D'; + *dest++ = 'A'; + *dest++ = 'T'; + *dest++ = '0' + (ptr[i]&1); + } + break; + + case '%': // Litteral % + *(dest++) = '%'; + break; + } + } + } + *dest = '\0'; +} + +char *disassemble(byte *ptr) +{ + static char buffer[64]; + + Opcode *op = opcodes; + int i = 0; + + while (op[ptr[i]].next) { + op = op[ptr[i]].next; + i++; + } + if (op[ptr[i]].dissasm) { + expand(buffer, op[ptr[i]].dissasm, ptr); + } else { + sprintf (buffer, "Unknown (%s)", nib_to_hex(ptr, i+1)); + } + return buffer; +} + +char *nib_to_hex(byte *nib, int n) +{ + static char buffer[17]; + + buffer[n] = '\0'; + while (n--) { + buffer[n] = HEX(nib[n]); + } + return buffer; +} + +char *nib_to_hex_rev(byte *nib, int n) +{ + static char buffer[17]; + + buffer[n] = '\0'; + while (n--) { + buffer[n] = HEX(*nib++); + } + return buffer; +} + diff --git a/src/disasm.h b/src/disasm.h new file mode 100644 index 0000000..865bfd3 --- /dev/null +++ b/src/disasm.h @@ -0,0 +1,35 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DISASM_H +#define __DISASM_H + +char *disassemble(byte *ptr); +char *nib_to_hex(byte *nib, int n); +char *nib_to_hex_rev(byte *nib, int n); + +#endif diff --git a/src/display.c b/src/display.c new file mode 100644 index 0000000..3dd932a --- /dev/null +++ b/src/display.c @@ -0,0 +1,155 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "bus.h" + +#define LCD_X 364 +#define LCD_Y 60 + +address menu_base; +address display_base; +address display_line_offset; +byte display_line_count; +byte display_height; +byte display_offset; +boolean display_enable; + +static address cur_adr; +static boolean in_menu; +static byte off_cur_line; +static byte off_line; +static int off_cnt; +static BITMAP *lcd; + +static void fade_lcd_line(int y) +{ + byte *lcd_line0 = (byte *)lcd->line[y*2]; + byte *lcd_line1 = (byte *)lcd->line[y*2+1]; + int x = 0; + + while (x < 131) { + lcd_line0[x*2] = lcd_line0[x*2+1] = lcd_line1[x*2] = lcd_line1[x*2+1] = (lcd_line0[x*2] >> 1); + x++; + } +} + +static address draw_lcd_line(address adr, int y) +{ + int x = 0; + int bit = 0; + byte data = 0; //Initialized to remove warning + byte *ptr; + byte *lcd_line0 = (byte *)lcd->line[y*2]; + byte *lcd_line1 = (byte *)lcd->line[y*2+1]; + + ptr = bus_fast_peek(NULL, adr, NULL); + + /* Horisontal pixel offset */ + if (!in_menu) { + if (display_offset > 3) ptr++; + data = *ptr++; + data >>= display_offset & 3; + bit = 4 - (display_offset & 3); + } + + while (x < 131) { + if (bit == 0) { + data = *ptr++; + bit = 4; + } + lcd_line0[x*2] = lcd_line0[x*2+1] = lcd_line1[x*2] = lcd_line1[x*2+1] = (lcd_line0[x*2] >> 1) | ((data & 1) << 6); + data >>= 1; + bit--; + x++; + } + return (adr + 0x22 + (!in_menu && (display_offset&4)?2:0)) & 0xFFFFF; +} + +void display_init(void) +{ + lcd = create_bitmap_ex(8, 131*2, 64*2); + clear_to_color(lcd, 0); +} + +void display_exit(void) +{ + destroy_bitmap (lcd); + lcd = NULL; +} + +void display_update(void) +{ + if (!display_enable && !off_cnt) { /* Turn off display */ + off_cnt = 1; + off_cur_line = off_line = display_line_count; + display_line_count = 0; + } else if (display_enable && off_cnt) { /* Turn on display */ + off_cnt = 0; + display_line_count = 0; + in_menu = 0; + cur_adr = display_base; + } + if (!off_cnt) { /* Display is on */ + cur_adr = draw_lcd_line(cur_adr, display_line_count); + + acquire_screen(); + scare_mouse_area(LCD_X, LCD_Y+display_line_count*2, 131*2, 2); + blit(lcd, screen, 0, display_line_count*2, LCD_X, LCD_Y+display_line_count*2, 131*2, 2); + unscare_mouse(); + release_screen(); + + if (!in_menu) { + cur_adr += display_line_offset; + } + if (display_line_count == display_height) { + in_menu = 1; + cur_adr = menu_base; + } + display_line_count++; + if (display_line_count == 64) { + display_line_count = 0; + in_menu = 0; + cur_adr = display_base; + } + } else if (off_cnt <= 7) { /* Display is off and still fading */ + fade_lcd_line(off_cur_line); + + acquire_screen(); + scare_mouse_area(LCD_X, LCD_Y+off_cur_line*2, 131*2, 2); + blit(lcd, screen, 0, off_cur_line*2, LCD_X, LCD_Y+off_cur_line*2, 131*2, 2); + unscare_mouse(); + release_screen(); + + off_cur_line++; + if (off_cur_line == 64) off_cur_line = 0; + if (off_cur_line == off_line) { + off_cnt++; + } + } +} diff --git a/src/display.h b/src/display.h new file mode 100644 index 0000000..4eb2c16 --- /dev/null +++ b/src/display.h @@ -0,0 +1,46 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DISPLAY_H +#define __DISPLAY_H + +#include +#include "types.h" + +extern address menu_base; +extern address display_base; +extern address display_line_offset; +extern byte display_line_count; +extern byte display_height; +extern byte display_offset; +extern boolean display_enable; + +void display_init(void); +void display_exit(void); +void display_update(void); + +#endif diff --git a/src/emulator.c b/src/emulator.c new file mode 100644 index 0000000..a33547e --- /dev/null +++ b/src/emulator.c @@ -0,0 +1,210 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "cpu.h" +#include "bus.h" +#include "timers.h" +#include "display.h" +#include "gui.h" +#include "pdebug.h" +#include "emulator.h" + +/* Define TRUE_TIMER2 to make timer2 run in true speed (8192 hz). + * If it is not defined timer2 is syncronized to the cpu speed. + */ +#define TRUE_TIMER2 + +#define MAX_DELTA 4000 + +typedef struct { + dword next; + dword freq; + void (*proc)(void); +} CycleEvent; + +typedef struct { + volatile int value; + int speed; + boolean running; + void (*proc)(void); +} TimerEvent; + +static void true_speed_proc(void); + +static CycleEvent cycle_events[] = { + { 0, 16, timer1_update }, +#ifndef TRUE_TIMER2 + { 0, 8192, timer2_update }, +#endif + { 0, 4096, display_update }, + { 0, 0, NULL } +}; + +static TimerEvent timer_events[] = { + { 0, BPS_TO_TIMER(20), FALSE, gui_update }, + { 0, BPS_TO_TIMER(1), FALSE, true_speed_proc }, +#ifdef TRUE_TIMER2 + { 0, BPS_TO_TIMER(8192), FALSE, timer2_update }, +#endif + { 0, 0, FALSE, NULL } +}; + +volatile boolean please_exit = FALSE; +dword emulator_speed = 4000000; +static int emulator_state = EMULATOR_STOP; + +static void true_speed_proc(void) +{ + static dword last_cycles; + + pdebug_draw_true_speed(cpu.cycles - last_cycles); + last_cycles = cpu.cycles; +} + +static void timer_event_proc(void *what) +{ + ((TimerEvent *)what)->value++; +} END_OF_STATIC_FUNCTION(timer_event_proc); + +static void start_timer_proc(void (*proc)(void)) +{ + TimerEvent *ptr = timer_events; + + while (ptr->proc && ptr->proc != proc) { + ptr++; + } + if (ptr->proc && !ptr->running) { + ptr->value = 0; + ptr->running = TRUE; + install_param_int_ex(timer_event_proc, (void *)ptr, ptr->speed); + } +} + +static void stop_timer_proc(void (*proc) (void)) +{ + TimerEvent *ptr = timer_events; + + while (ptr->proc && ptr->proc != proc) { + ptr++; + } + if (ptr->proc && ptr->running) { + ptr->value = 0; + ptr->running = FALSE; + remove_param_int(timer_event_proc, (void *)ptr); + } +} + +void emulator_set_state(int state) +{ +#ifdef TRUE_TIMER2 + if (state != EMULATOR_STOP) { + start_timer_proc(timer2_update); + } else { + stop_timer_proc(timer2_update); + } +#endif + emulator_state = state; + pdebug_state_changed(); +} + +int emulator_get_state(void) +{ + return emulator_state; +} + +void emulator_init(void) +{ + static boolean locked = FALSE; + + bus_init(); + display_init(); + + if (!locked) { + LOCK_VARIABLE(timer_events); + LOCK_FUNCTION(timer_event_proc); + locked = TRUE; + } +} + +void emulator_exit(void) +{ + display_exit(); + bus_exit(); +} + +void emulator_run(void) +{ + CycleEvent *cep; + TimerEvent *tep; + dword delta; + + start_timer_proc(gui_update); + start_timer_proc(true_speed_proc); + + while (!please_exit) { + if (emulator_state != EMULATOR_STOP) { + if (!cpu.shutdown) { + execute_instruction(); + if (emulator_state == EMULATOR_STEP) { + emulator_set_state(EMULATOR_STOP); + } + } else { + delta = MAX_DELTA; + for (cep = cycle_events; cep->proc; cep++) { + delta = MIN(delta, cep->next - cpu.cycles + 1); + } + cpu.cycles += delta; + } + for (cep = cycle_events; cep->proc; cep++) { + if ((cep->next - cpu.cycles) & 0x80000000) { + cep->next += emulator_speed / cep->freq; + cep->proc(); + } + } + } + for (tep = timer_events; tep->proc; tep++) { + if (tep->running && tep->value) { + tep->value--; + tep->proc(); + } + } + if (emulator_state == EMULATOR_STOP) { + rest(10); + } else { + yield_timeslice (); + } + } +#ifdef TRUE_TIMER2 + if (emulator_state != EMULATOR_STOP) { + stop_timer_proc(timer2_update); + } +#endif + stop_timer_proc(true_speed_proc); + stop_timer_proc(gui_update); +} diff --git a/src/emulator.h b/src/emulator.h new file mode 100644 index 0000000..30424de --- /dev/null +++ b/src/emulator.h @@ -0,0 +1,49 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __EMULATOR_H +#define __EMULATOR_H + +#include "types.h" + +enum EmulatorStates { + EMULATOR_STOP, + EMULATOR_STEP, + EMULATOR_RUN +}; + +extern volatile boolean please_exit; +extern dword emulator_speed; + +void emulator_init(void); +void emulator_exit(void); +void emulator_run(void); + +void emulator_set_state(int state); +int emulator_get_state(void); + +#endif diff --git a/src/gui.c b/src/gui.c new file mode 100644 index 0000000..5f212f1 --- /dev/null +++ b/src/gui.c @@ -0,0 +1,233 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "color.h" +#include "pmenu.h" +#include "pcalc.h" +#include "pdebug.h" +#include "pfiles.h" +#include "pabout.h" +#include "gui.h" + +#define PANEL_FLAG_VISIBLE 0x01 + +typedef struct GuiPanel { + int x, y; + int w, h; + int flags; + BITMAP *bmp; + void (*show)(BITMAP *bmp); + void (*hide)(void); + void (*mouse_down)(int mx, int my, int mb); + void (*mouse_up)(int mx, int my, int mb); +} GuiPanel; + +static GuiPanel panels[PANEL_COUNT] = { + { 10, 10, 620, 20, 0, NULL, pmenu_show, pmenu_hide, pmenu_down, pmenu_up }, + { 360, 40, 270, 430, 0, NULL, pcalc_show, pcalc_hide, pcalc_down, pcalc_up }, + { 10, 40, 340, 430, 0, NULL, pdebug_show, pdebug_hide, pdebug_down, pdebug_up }, + { 10, 40, 340, 430, 0, NULL, pfiles_show, pfiles_hide, pfiles_down, pfiles_up }, + { 10, 40, 340, 430, 0, NULL, pabout_show, pabout_hide, pabout_down, pabout_up }, +}; + +void gui_init(void) +{ + clear_to_color(screen, color[C_BACKGROUND]); + gui_show_panel(PANEL_MENU); + gui_show_panel(PANEL_CALC); + gui_show_panel(PANEL_ABOUT); +} + +void gui_exit(void) +{ + int i; + + for (i = 0; i < PANEL_COUNT; i++) { + gui_hide_panel(i); + } +} + +static __inline int panel_at(int x, int y) +{ + int i; + + for (i = PANEL_COUNT; i >= 0; i--) { + if (panels[i].flags & PANEL_FLAG_VISIBLE && + x >= panels[i].x && x < panels[i].x+panels[i].w && + y >= panels[i].y && y < panels[i].y+panels[i].h) { + break; + } + } + return i; +} + +void gui_update(void) +{ + static int down_panel = -1; + static int down_mb = 0; + int mx, my, mb; + + mx = mouse_x; + my = mouse_y; + mb = mouse_b; + + if (!down_mb && (mb & 1)) { + down_panel = panel_at(mx, my); + if (down_panel >= 0) { + down_mb = 1; + panels[down_panel].mouse_down(mx - panels[down_panel].x, my - panels[down_panel].y, down_mb); + } + } else if (!down_mb && (mb & 2)) { + down_panel = panel_at(mx, my); + if (down_panel >= 0) { + down_mb = 2; + panels[down_panel].mouse_down(mx - panels[down_panel].x, my - panels[down_panel].y, down_mb); + } + } else if (down_mb && !(mb & 3)) { + panels[down_panel].mouse_up(mx - panels[down_panel].x, my - panels[down_panel].y, down_mb); + down_mb = 0; + down_panel = -1; + } +} + +void gui_show_panel(int i) +{ + if (!(panels[i].flags & PANEL_FLAG_VISIBLE)) { + panels[i].flags |= PANEL_FLAG_VISIBLE; + panels[i].bmp = create_sub_bitmap(screen, panels[i].x, panels[i].y, panels[i].w, panels[i].h); + acquire_screen(); + scare_mouse(); + rect(screen, panels[i].x-1, panels[i].y-1, panels[i].x+panels[i].w, panels[i].y+panels[i].h, color[C_PANEL_BORDER]); + panels[i].show(panels[i].bmp); + unscare_mouse(); + release_screen(); + } +} + +void gui_hide_panel(int i) +{ + if (panels[i].flags & PANEL_FLAG_VISIBLE) { + panels[i].flags &= ~PANEL_FLAG_VISIBLE; + panels[i].hide(); + destroy_bitmap(panels[i].bmp); + panels[i].bmp = NULL; + } +} + + +void button_draw(BITMAP *bmp, Button *b) +{ + int c; + + c = color[(b->flags&BUTTON_PUSHED) ? C_BUTTON_PUSHED : C_BUTTON_BACK]; + text_mode(c); + acquire_bitmap(bmp); + scare_mouse(); + rect(bmp, b->x-1, b->y-1, b->x+b->w, b->y+b->h, color[C_BUTTON_BORDER]); + rectfill(bmp, b->x, b->y, b->x+b->w-1, b->y+b->h-1, c); + c = color[(b->flags&BUTTON_DISABLED) ? C_BUTTON_DISABLED : C_BUTTON_TEXT]; + textout_centre(bmp, font, b->text, b->x+b->w/2, b->y+(b->h-text_height (font))/2, c); + unscare_mouse(); + release_bitmap(bmp); +} + +void button_draw_all(BITMAP *bmp, Button *buttons) +{ + acquire_bitmap(bmp); + scare_mouse(); + while (buttons->text) { + button_draw(bmp, buttons); + buttons++; + } + unscare_mouse(); + release_bitmap(bmp); +} + +static __inline Button *find_button(Button *b, int x, int y) +{ + while (b->text) { + if (x >= b->x && x < b->x+b->w && y >= b->y && y < b->y+b->h) { + return b; + } + b++; + } + return NULL; +} + +int button_mouse_down(BITMAP *bmp, Button *buttons, int mx, int my, int mb) +{ + Button *b = find_button(buttons, mx, my); + + if (!b) { + return 0; + } + if (!(b->flags & BUTTON_DISABLED)) { + if ((mb == 2 && (b->flags & BUTTON_B2TOGGLE)) || + (mb == 1 && (b->flags & BUTTON_B1TOGGLE))) { + if (b->flags & BUTTON_PUSHED) { + b->flags &= ~BUTTON_PUSHED; + button_draw(bmp, b); + if (b->up) b->up(TRUE); + } else { + b->flags |= BUTTON_PUSHED; + button_draw(bmp, b); + if (b->down) b->down(); + } + } else if (mb == 1 && !(b->flags & BUTTON_PUSHED)) { + b->flags |= BUTTON_PUSHED; + button_draw(bmp, b); + if (b->down) b->down(); + } + } + return 1; +} + +int button_mouse_up(BITMAP *bmp, Button *buttons, int mx, int my, int mb) +{ + Button *b = find_button(buttons, mx, my); + int ret = (b != NULL); + + if (b && !(b->flags & BUTTON_DISABLED)) { + if (mb == 1 && (b->flags & BUTTON_PUSHED) && !(b->flags & BUTTON_B1TOGGLE)) { + b->flags &= ~BUTTON_PUSHED; + button_draw(bmp, b); + if (b->up) b->up(TRUE); + } + } + if (mb == 1) { + for (b = buttons; b->text; b++) { + if ((b->flags & (BUTTON_B1RELEASE|BUTTON_PUSHED)) == (BUTTON_B1RELEASE|BUTTON_PUSHED)) { + b->flags &= ~BUTTON_PUSHED; + button_draw(bmp, b); + if (b->up) b->up(FALSE); + ret = 1; + } + } + } + return ret; +} diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..00a8558 --- /dev/null +++ b/src/gui.h @@ -0,0 +1,73 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __GUI_H +#define __GUI_H + +#include "types.h" + +enum Panels { + PANEL_MENU, + PANEL_CALC, + PANEL_DEBUG, + PANEL_FILES, + PANEL_ABOUT, + PANEL_COUNT +}; + +typedef struct { + int x, y; + int w, h; + int flags; + char *text; + void (*down)(void); + void (*up)(boolean action); +} Button; + +/* Button flags: + * Use BUTTON_B1RELEASE for normal buttons. + * Use BUTTON_B1RELEASE | BUTTON_B2TOGGLE for calculator buttons. + * Use BUTTON_B1TOGGLE for toggle buttons + */ +#define BUTTON_PUSHED 0x01 // Set if button is pushed +#define BUTTON_DISABLED 0x02 // If set the button will be grayed out +#define BUTTON_B1TOGGLE 0x04 // Mouse button 1 toggles this button +#define BUTTON_B2TOGGLE 0x08 // Mouse button 2 toggles this button +#define BUTTON_B1RELEASE 0x10 // Releaseing mouse button 1 anywhere unpushes the button + +void gui_init(void); +void gui_exit(void); +void gui_update(void); +void gui_show_panel(int i); +void gui_hide_panel(int i); + +void button_draw(BITMAP *bmp, Button *buttons); +void button_draw_all(BITMAP *bmp, Button *buttons); +int button_mouse_down(BITMAP *bmp, Button *butons, int mx, int my, int mb); +int button_mouse_up(BITMAP *bmp, Button *buttons, int mx, int my, int mb); + +#endif diff --git a/src/hdw.c b/src/hdw.c new file mode 100644 index 0000000..4c60c12 --- /dev/null +++ b/src/hdw.c @@ -0,0 +1,193 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "types.h" +#include "bus.h" +#include "ports.h" +#include "timers.h" +#include "display.h" +#include "hdw.h" + +static byte hdw_ram[64]; + +void hdw_init(void) +{ +} + +void hdw_exit(void) +{ +} + +byte hdw_read_nibble(address adr) +{ + switch (adr) { + + case 0x00: return display_offset | (display_enable ? 0x8 : 0x0); + + case 0x04: return (byte) crc & 0xF; + case 0x05: return (byte) (crc >> 4) & 0xF; + case 0x06: return (byte) (crc >> 8) & 0xF; + case 0x07: return (byte) (crc >> 12) & 0xF; + + case 0x0F: return (hdw_ram[0x0E] & 0x8) ? ports_card_detect() : 0; + + case 0x28: return display_line_count & 0xF; + case 0x29: return (display_line_count>>4) | (hdw_ram[0x29] & 0x4) | (bus_info.da19 ? 0x8 : 0x0); + + case 0x2E: return timer1_control; + case 0x2F: return timer2_control; + + case 0x37: return timer1_value; + case 0x38: return (byte) timer2_value & 0xF; + case 0x39: return (byte) (timer2_value >> 4) & 0xF; + case 0x3A: return (byte) (timer2_value >> 8) & 0xF; + case 0x3B: return (byte) (timer2_value >> 12) & 0xF; + case 0x3C: return (byte) (timer2_value >> 16) & 0xF; + case 0x3D: return (byte) (timer2_value >> 20) & 0xF; + case 0x3E: return (byte) (timer2_value >> 24) & 0xF; + case 0x3F: return (byte) (timer2_value >> 28) & 0xF; + + default: return hdw_ram[adr]; + + } +} + +void hdw_write_nibble(byte data, address adr) +{ + int tmp; + + switch (adr) { + + case 0x00: display_offset = data & 7; + display_enable = (data & 8) ? TRUE : FALSE; + break; + + case 0x04: crc &= 0xFFF0; + crc |= (word) data; + break; + case 0x05: crc &= 0xFF0F; + crc |= (word) data << 4; + break; + case 0x06: crc &= 0xF0FF; + crc |= (word) data << 8; + break; + case 0x07: crc &= 0x0FFF; + crc |= (word) data << 12; + break; + + case 0x0F: break; + + case 0x20: display_base &= 0xFFFF0; + display_base |= (address) data & 0xE; + break; + case 0x21: display_base &= 0xFFF0F; + display_base |= (address) data << 4; + break; + case 0x22: display_base &= 0xFF0FF; + display_base |= (address) data << 8; + break; + case 0x23: display_base &= 0xF0FFF; + display_base |= (address) data << 12; + break; + case 0x24: display_base &= 0x0FFFF; + display_base |= (address) data << 16; + break; + case 0x25: display_line_offset &= 0xFF0; + display_line_offset |= (address) data & 0xE; + break; + case 0x26: display_line_offset &= 0xF0F; + display_line_offset |= (address) data << 4; + break; + case 0x27: display_line_offset &= 0x0FF; + display_line_offset |= (address) data << 8; + if (display_line_offset & 0x800) + display_line_offset |= ~0xFFF; + else + display_line_offset &= 0xFFF; + break; + case 0x28: display_height &= 0xF0; + display_height |= data; + break; + case 0x29: display_height &= 0x0F; + display_height |= (data&3) << 4; + hdw_ram[0x29] = data & 0x4; + tmp = bus_info.da19; + bus_info.da19 = (data & 0x8) ? TRUE : FALSE; + if (tmp != bus_info.da19) { + bus_remap(); + } + break; + + case 0x2E: timer1_control = data; break; + case 0x2F: timer2_control = data; break; + + case 0x30: menu_base &= 0xFFFF0; + menu_base |= (address) data & 0xE; + break; + case 0x31: menu_base &= 0xFFF0F; + menu_base |= (address) data << 4; + break; + case 0x32: menu_base &= 0xFF0FF; + menu_base |= (address) data << 8; + break; + case 0x33: menu_base &= 0xF0FFF; + menu_base |= (address) data << 12; + break; + case 0x34: menu_base &= 0x0FFFF; + menu_base |= (address) data << 16; + break; + + case 0x37: timer1_value = data; break; + case 0x38: timer2_value &= 0xFFFFFFF0; + timer2_value |= (dword) data; + break; + case 0x39: timer2_value &= 0xFFFFFF0F; + timer2_value |= (dword) data << 4; + break; + case 0x3A: timer2_value &= 0xFFFFF0FF; + timer2_value |= (dword) data << 8; + break; + case 0x3B: timer2_value &= 0xFFFF0FFF; + timer2_value |= (dword) data << 12; + break; + case 0x3C: timer2_value &= 0xFFF0FFFF; + timer2_value |= (dword) data << 16; + break; + case 0x3D: timer2_value &= 0xFF0FFFFF; + timer2_value |= (dword) data << 20; + break; + case 0x3E: timer2_value &= 0xF0FFFFFF; + timer2_value |= (dword) data << 24; + break; + case 0x3F: timer2_value &= 0x0FFFFFFF; + timer2_value |= (dword) data << 28; + break; + + default: hdw_ram[adr] = data; + break; + } +} diff --git a/src/hdw.h b/src/hdw.h new file mode 100644 index 0000000..9b90d94 --- /dev/null +++ b/src/hdw.h @@ -0,0 +1,39 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __HDW_H +#define __HDW_H + +#include "types.h" + +void hdw_init(void); +void hdw_exit(void); + +byte hdw_read_nibble(address adr); +void hdw_write_nibble(byte data, address adr); + +#endif diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..e66ed9f --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,109 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "types.h" +#include "cpu.h" +#include "keyboard.h" + +boolean kbd_on; + +static byte kbd_row[9]; + +static void update_in(void) +{ + byte in = 0; + + // TODO: Emulate real HP48 keyboard circuit + + if (cpu.out[0]&1) in |= kbd_row[0]; + if (cpu.out[0]&2) in |= kbd_row[1]; + if (cpu.out[0]&4) in |= kbd_row[2]; + if (cpu.out[0]&8) in |= kbd_row[3]; + if (cpu.out[1]&1) in |= kbd_row[4]; + if (cpu.out[1]&2) in |= kbd_row[5]; + if (cpu.out[1]&4) in |= kbd_row[6]; + if (cpu.out[1]&8) in |= kbd_row[7]; + if (cpu.out[2]&1) in |= kbd_row[8]; + + cpu.in[0] = in & 0xF; + cpu.in[1] = (in >> 4) & 0xF; + cpu.in[2] = 0; + cpu.in[3] = kbd_on ? 8 : 0; +} + +void kbd_out_changed(void) +{ + update_in(); +} + +void kbd_key_pressed(int row, int col) +{ + boolean no_key = !cpu.in[0] && !cpu.in[1] && !cpu.in[3]; + kbd_row[row] |= 1 << col; + update_in(); + if (cpu.shutdown && no_key && (cpu.in[0] || cpu.in[1] || cpu.in[3])) { + cpu.shutdown = FALSE; + } + if (cpu.keyscan && no_key && (cpu.in[0] || cpu.in[1] || cpu.in[3])) { + if (cpu.inte) { + cpu.keyintp = FALSE; + cpu_interrupt(); + } else { + cpu.keyintp = TRUE; + } + } else if (!cpu.in[0] && !cpu.in[1] && !cpu.in[3]) { + cpu.keyintp = FALSE; + } +} + +void kbd_key_released(int row, int col) +{ + kbd_row[row] &= ~(1 << col); + update_in(); + if (!cpu.in[0] && !cpu.in[1] && !cpu.in[3]) { + cpu.keyintp = FALSE; + } +} + +void kbd_on_pressed(void) +{ + boolean no_key = !cpu.in[3]; + kbd_on = TRUE; + cpu.in[3] |= 8; + if (cpu.shutdown && no_key) { + cpu.shutdown = FALSE; + } + if (cpu.inte && no_key) { + cpu_interrupt(); + } +} + +void kbd_on_released(void) +{ + kbd_on = FALSE; + cpu.in[3] &= ~8; +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 0000000..440c6bc --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,39 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __KEYBOARD_H +#define __KEYBOARD_H + +extern boolean kbd_on; + +void kbd_out_changed(void); +void kbd_key_pressed(int row, int col); +void kbd_key_released(int row, int col); +void kbd_on_pressed(void); +void kbd_on_released(void); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..e1af9a5 --- /dev/null +++ b/src/main.c @@ -0,0 +1,124 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "emulator.h" +#include "gui.h" +#include "color.h" + +static int fullscreen = FALSE; + +static void parse_args(int argc, char *argv[]) +{ + while (--argc) { + argv++; + if (argv[0][0] == '-') { + switch (argv[0][1]) { + case 'f': + fullscreen = TRUE; + break; + case 'w': + fullscreen = FALSE; + break; + } + } + } +} + +static void close_hook(void) +{ + please_exit = TRUE; +} + +static void program_init(void) +{ + int depth; + + if (install_allegro(SYSTEM_AUTODETECT, &errno, atexit) < 0) { + allegro_message("Can't install allegro"); + exit(1); + } + if (install_timer() < 0) { + allegro_message("Can't install timer driver"); + exit(1); + } + if (install_keyboard() < 0) { + allegro_message("Can't install keyboard driver"); + exit(1); + } + if (install_mouse() < 0) { + allegro_message("Can't install mouse driver"); + exit(1); + } + + if (fullscreen) { + depth = 8; + } else { + depth = desktop_color_depth(); + if (depth == 0) { + depth = 8; + } + } + set_color_depth(depth); + + if (set_gfx_mode(fullscreen + ? GFX_AUTODETECT_FULLSCREEN + : GFX_AUTODETECT_WINDOWED, + 640, 480, 0, 0) < 0) { + allegro_message("Can't set graphics mode (%s)", allegro_error); + exit(1); + } + + set_window_title("hpemu 0.9.0"); + set_window_close_hook(close_hook); + + color_init(); + + show_mouse(screen); +} + +static void program_exit(void) +{ +} + +int main (int argc, char *argv[]) +{ + parse_args (argc, argv); + program_init(); + emulator_init(); + gui_init(); + + emulator_run(); + + gui_exit(); + emulator_exit(); + program_exit(); + + return 0; +} END_OF_MAIN(); + diff --git a/src/opcodes.c b/src/opcodes.c new file mode 100644 index 0000000..7bed6c8 --- /dev/null +++ b/src/opcodes.c @@ -0,0 +1,1164 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "cpu.h" +#include "bus.h" +#include "keyboard.h" +#include "opcodes.h" +#include "opinline.h" + +// P WP XS X S M B W +static int fs[16] = { 0, 0, 2, 0, 15, 3, 0, 0, + 0, 0, 2, 0, 15, 3, 0, 0 }; +static int fl[16] = { 1, 1, 1, 3, 1, 12, 2, 16, + 1, 1, 1, 3, 1, 12, 2, 16 }; +// 0 1 2 3 4 5 6 7 8 9 A B C D E F +static const int regr[16] = { A, B, C, D, B, C, A, C, A, B, C, D, B, C, A, C }; +static const int regs[16] = { B, C, A, C, A, B, C, D, B, C, A, C, A, B, C, D }; +static const int regt[16] = { A, B, C, D, A, B, C, D, B, C, A, C, A, B, C, D }; +static const int regu[16] = { A, B, C, D, B, C, A, C, B, C, A, C, A, B, C, D }; +static const int regv[16] = { B, C, A, C, A, B, C, D, A, B, C, D, B, C, A, C }; + +#define REGr(i) (cpu.reg[regr[i]]) +#define REGs(i) (cpu.reg[regs[i]]) +#define REGt(i) (cpu.reg[regt[i]]) +#define REGu(i) (cpu.reg[regu[i]]) +#define REGv(i) (cpu.reg[regv[i]]) +#define REGrF(i,f) (REGr(i) + fs[f]) +#define REGsF(i,f) (REGs(i) + fs[f]) +#define REGtF(i,f) (REGt(i) + fs[f]) +#define REGuF(i,f) (REGu(i) + fs[f]) +#define REGvF(i,f) (REGv(i) + fs[f]) + +static __inline void update_fields(void) +{ + fs[0] = fs[8] = cpu.p; + fl[1] = fl[9] = cpu.p + 1; +} + +static void op00(byte *opc) // RTNSXM +{ + cpu.hst |= HST_XM; + cpu.pc = rstk_pop(); + cpu.cycles += 9; +} + +static void op01(byte *opc) // RTN +{ + cpu.pc = rstk_pop(); + cpu.cycles += 9; +} + +static void op02_3(byte *opc) // RTNSC / RTNCC +{ + cpu.carry = (opc[1] & 1) ? FALSE : TRUE; + cpu.pc = rstk_pop(); + cpu.cycles += 9; +} + +static void op04_5(byte *opc) // SETHEX / SETDEC +{ + cpu.dec = (opc[1] & 1) ? TRUE : FALSE; + cpu.pc += 2; + cpu.cycles += 3; +} + +static void op06(byte *opc) // RSTK=C +{ + rstk_push(nib_to_unsigned(cpu.reg[C], 5)); + cpu.pc += 2; + cpu.cycles += 8; +} + +static void op07(byte *opc) // C=RSTK +{ + unsigned_to_nib(cpu.reg[C], rstk_pop(), 5); + cpu.pc += 2; + cpu.cycles += 8; +} + +static void op08(byte *opc) // CLRST +{ + reg_zero(cpu.st, 3); + cpu.pc += 2; + cpu.cycles += 5; +} + +static void op09(byte *opc) // C=ST +{ + reg_cpy(cpu.reg[C], cpu.st, 3); + cpu.pc += 2; + cpu.cycles += 5; +} + +static void op0A(byte *opc) // ST=C +{ + reg_cpy(cpu.st, cpu.reg[C], 3); + cpu.pc += 2; + cpu.cycles += 5; +} + +static void op0B(byte *opc) // CSTEX +{ + reg_ex(cpu.reg[C], cpu.st, 3); + cpu.pc += 2; + cpu.cycles += 5; +} + +static void op0C(byte *opc) // P=P+1 +{ + if (cpu.p != 0xF) { + cpu.p++; + cpu.carry = FALSE; + } else { + cpu.p = 0; + cpu.carry = TRUE; + } + update_fields(); + cpu.pc += 2; + cpu.cycles += 3; +} + +static void op0D(byte *opc) // P=P-1 +{ + if (cpu.p) { + cpu.p--; + cpu.carry = FALSE; + } else { + cpu.p = 0xF; + cpu.carry = TRUE; + } + update_fields(); + cpu.pc += 2; + cpu.cycles += 3; +} + +static void op0E (byte *opc) // r=r&s f/A / r=r!s f/A +{ + int len = (opc[2] == 0xF) ? 5 : fl[opc[2]]; + if (!(opc[3]&8)) { + alu_and(REGrF(opc[3], opc[2]), REGsF(opc[3], opc[2]), len); + } else { + alu_or(REGrF(opc[3], opc[2]), REGsF(opc[3], opc[2]), len); + } + cpu.pc += 4; + cpu.cycles += 4 + len; +} + +static void op0F(byte *opc) // RTI +{ + // TODO: Implement RTI + cpu.inte = TRUE; + cpu.pc = rstk_pop(); + cpu.cycles += 9; + if ((cpu.keyintp && cpu.keyscan) || kbd_on) { + cpu.keyintp = FALSE; + cpu_interrupt (); + } +} + +static void op10(byte *opc) // Ri=r +{ + int i = (opc[2] & 7) > 4 ? opc[2] & 3 : opc[2] & 7; + reg_cpy(cpu.reg_r[i], cpu.reg[(opc[2]&8)>>2], 16); + cpu.pc += 3; + cpu.cycles += 19; +} + +static void op11(byte *opc) // r=Ri +{ + int i = (opc[2] & 7) > 4 ? opc[2] & 3 : opc[2] & 7; + reg_cpy(cpu.reg[(opc[2]&8)>>2], cpu.reg_r[i], 16); + cpu.pc += 3; + cpu.cycles += 19; +} + +static void op12(byte *opc) // rRiEX +{ + int i = (opc[2] & 7) > 4 ? opc[2] & 3 : opc[2] & 7; + reg_ex(cpu.reg[(opc[2]&8)>>2], cpu.reg_r[i], 16); + cpu.pc += 3; + cpu.cycles += 19; +} + +static void op13a(byte *opc) // Di=r / rDiEX +{ + address tmp = cpu.d[opc[2]&1]; + cpu.d[opc[2]&1] = nib_to_unsigned(cpu.reg[(opc[2]&4)>>1], 5); + if (opc[2]&2) unsigned_to_nib(cpu.reg[(opc[2]&4)>>1], tmp, 5); + cpu.pc += 3; + cpu.cycles += 8; +} + +static void op13b(byte *opc) // Di=rS / rDiEXS +{ + address tmp = cpu.d[opc[2]&1]; + cpu.d[opc[2]&1] &= 0xF0000; + cpu.d[opc[2]&1] |= nib_to_unsigned(cpu.reg[(opc[2]&4)>>1], 4); + if (opc[2]&2) unsigned_to_nib(cpu.reg[(opc[2]&4)>>1], tmp, 4); + cpu.pc += 3; + cpu.cycles += 7; +} + +static void op14(byte *opc) // DATi=r A/B / r=DATi A/B +{ + if (!(opc[2]&2)) { + bus_write(cpu.reg[(opc[2]&4)>>1], cpu.d[opc[2]&1], (opc[2]&8) ? 2 : 5); + } else { + bus_read(cpu.reg[(opc[2]&4)>>1], cpu.d[opc[2]&1], (opc[2]&8) ? 2 : 5); + cpu.cycles++; + } + cpu.pc += 3; + cpu.cycles += (opc[2]&8) ? 14 : 17; +} + +static void op15a(byte *opc) // DATi=r f / r=DATi f +{ + if (!(opc[2]&2)) { + bus_write(cpu.reg[(opc[2]&4)>>1] + fs[opc[3]], cpu.d[opc[2]&1], fl[opc[3]]); + } else { + bus_read(cpu.reg[(opc[2]&4)>>1] + fs[opc[3]], cpu.d[opc[2]&1], fl[opc[3]]); + cpu.cycles++; + } + cpu.pc += 4; + cpu.cycles += 16 + fl[opc[3]]; +} + +static void op15b(byte *opc) // DATi=r n / r=DATi n +{ + if (!(opc[2]&2)) { + bus_write(cpu.reg[(opc[2]&4)>>1], cpu.d[opc[2]&1], opc[3]+1); + } else { + bus_read(cpu.reg[(opc[2]&4)>>1], cpu.d[opc[2]&1], opc[3]+1); + cpu.cycles++; + } + cpu.pc += 4; + cpu.cycles += 15 + opc[3]+1; +} + +static void op16_7(byte *opc) // Di=Di+ +{ + cpu.d[opc[1]&1] += opc[2] + 1; + if (cpu.d[opc[1]&1] & ~0xFFFFF) { + cpu.d[opc[1]&1] &= 0xFFFFF; + cpu.carry = TRUE; + } else { + cpu.carry = FALSE; + } + cpu.pc += 3; + cpu.cycles += 7; +} + +static void op18_C(byte *opc) // Di=Di- +{ + cpu.d[(opc[1]>>2)&1] -= opc[2] + 1; + if (cpu.d[(opc[1]>>2)&1] & ~0xFFFFF) { + cpu.d[(opc[1]>>2)&1] &= 0xFFFFF; + cpu.carry = TRUE; + } else { + cpu.carry = FALSE; + } + cpu.pc += 3; + cpu.cycles += 7; +} + +static void op19_D(byte *opc) // Di=(2) +{ + cpu.d[(opc[1]>>2)&1] &= 0xFFF00; + cpu.d[(opc[1]>>2)&1] |= nib_to_unsigned(opc+2, 2); + cpu.pc += 4; + cpu.cycles += 4; +} + +static void op1A_E(byte *opc) // Di=(4) +{ + cpu.d[(opc[1]>>2)&1] &= 0xF0000; + cpu.d[(opc[1]>>2)&1] |= nib_to_unsigned(opc+2, 4); + cpu.pc += 6; + cpu.cycles += 6; +} + +static void op1B_F(byte *opc) // Di=(5) +{ + cpu.d[(opc[1]>>2)&1] = nib_to_unsigned(opc+2, 5); + cpu.pc += 7; + cpu.cycles += 7; +} + +static void op2(byte *opc) // P= +{ + cpu.p = opc[1]; + update_fields(); + cpu.pc += 2; + cpu.cycles += 2; +} + +static void op3(byte *opc) // LC +{ + load(cpu.reg[C], opc+2, cpu.p, opc[1]+1); + cpu.pc += 2 + opc[1]+1; + cpu.cycles += 3 + opc[1]+1; +} + +static void op4(byte *opc) // GOC +{ + goyes(opc, 1); + cpu.cycles += 3; +} + +static void op5(byte *opc) // GONC +{ + cpu.carry = !cpu.carry; + goyes (opc, 1); + cpu.carry = !cpu.carry; + cpu.cycles += 3; +} + +static void op6(byte *opc) // GOTO +{ + cpu.pc += nib_to_signed(opc+1, 3) + 1; + cpu.cycles += 11; +} + +static void op7(byte *opc) // GOSUB +{ + rstk_push(cpu.pc + 4); + cpu.pc += nib_to_signed(opc+1, 3) + 4; + cpu.cycles += 12; +} + +static void op800_1(byte *opc) // OUT=CS / OUT=C +{ + reg_cpy(cpu.out, cpu.reg[C], opc[2] ? 3 : 1); + cpu.pc += 3; + cpu.cycles += opc[2] ? 6 : 4; + kbd_out_changed(); +} + +static void op802_3(byte *opc) // r=IN +{ + reg_cpy(cpu.reg[(opc[2]&1)<<1], cpu.in, 4); + if (!(cpu.pc & 1)) cpu.pc += 3; // Saturn bug! + cpu.cycles += 7; +} + +static void op804(byte *opc) // UNCNFG +{ + bus_unconfigure(nib_to_unsigned(cpu.reg[C], 5)); + cpu.pc += 3; + cpu.cycles += 12; +} + +static void op805(byte *opc) // CONFIG +{ + bus_configure(nib_to_unsigned(cpu.reg[C], 5)); + cpu.pc += 3; + cpu.cycles += 11; +} + +static void op806(byte *opc) // C=ID +{ + unsigned_to_nib(cpu.reg[C], bus_get_id(), 5); + cpu.pc += 3; + cpu.cycles += 11; +} + +static void op807(byte *opc) // SHUTND +{ + // TODO: Fix SHUTDN + if (!cpu.in[0] && !cpu.in[1] && !cpu.in[3]) { + cpu.shutdown = TRUE; + } + cpu.pc += 3; + cpu.cycles += 5; +} + +static void op8080(byte *opc) // INTON +{ + cpu.keyscan = TRUE; + cpu.pc += 4; + cpu.cycles += 5; + if (cpu.keyintp) { + cpu.keyintp = FALSE; + cpu_interrupt (); + } +} + +static void op8081(byte *opc) // RSI +{ + // TODO: Implement RSI + // Note: Is the opcode 80810? + // if (opc[4] == 0) + cpu.pc += 5; + cpu.cycles += 6; +} + +static void op8082(byte *opc) // LA +{ + load(cpu.reg[A], opc+5, cpu.p, opc[4]+1); + cpu.pc += 5 + opc[4]+1; + cpu.cycles += 6 + opc[4]+1; +} + +static void op8084_5_8_9(byte *opc) // rBIT=b +{ + reg_bit(cpu.reg[(opc[3]&8)>>2], opc[4], opc[3]&1); + cpu.pc += 5; + cpu.cycles += 6; +} + +static void op8086_7_A_B (byte *opc) // ?rBIT=b +{ + comp_bit_zero(cpu.reg[(opc[3]&8)>>2], opc[4]); + if (opc[3] & 1) cpu.carry = !cpu.carry; + goyes(opc, 5); + cpu.cycles += 9; +} + +static void op808C_E(byte *opc) // PC=(r) +{ + byte tmp[5]; + bus_read(tmp, nib_to_unsigned(cpu.reg[opc[3]&2], 5), 5); + cpu.pc = nib_to_unsigned(tmp, 5); + cpu.cycles += 23; +} + +static void op808F(byte *opc) // INTOFF +{ + // TODO: Implement INTOFF + cpu.keyscan = FALSE; + cpu.pc += 4; + cpu.cycles += 5; +} + +static void op809(byte *opc) // C+P+1 +{ + alu_add_con(cpu.reg[C], cpu.p, 0, 5); + cpu.pc += 3; + cpu.cycles += 8; +} + +static void op80A(byte *opc) // RESET +{ + bus_reset(); + cpu.pc += 3; + cpu.cycles += 6; +} + +static void op80C(byte *opc) // C=P +{ + cpu.reg[C][opc[3]] = cpu.p; + cpu.pc += 4; + cpu.cycles += 6; +} + +static void op80D(byte *opc) // P=C +{ + cpu.p = cpu.reg[C][opc[3]]; + update_fields(); + cpu.pc += 4; + cpu.cycles += 6; +} + +static void op80F(byte *opc) // CPEX +{ + byte tmp = cpu.reg[C][opc[3]]; + cpu.reg[C][opc[3]] = cpu.p; + cpu.p = tmp; + update_fields(); + cpu.pc += 4; + cpu.cycles += 6; +} + +static void op810_3(byte *opc) // rSLC +{ + alu_slc(cpu.reg[opc[2]&3], 16); + cpu.pc += 3; + cpu.cycles += 21; +} + +static void op814_7(byte *opc) // rSRC +{ + alu_src(cpu.reg[opc[2]&3], 16); + cpu.pc += 3; + cpu.cycles += 21; +} + +static void op818 (byte *opc) // r=r+CON f/A / r=r-CON f/A +{ + int len = (opc[3] == 0xF) ? 5 : ((fl[opc[3]] == 1) ? 17 : fl[opc[3]]); + // Note: What happens if opc[4]&4 + if (!(opc[4]&8)) { + alu_add_con(cpu.reg[opc[4]&3], opc[5], fs[opc[3]], len); + } else { + alu_sub_con(cpu.reg[opc[4]&3], opc[5], fs[opc[3]], len); + } + cpu.pc += 6; + cpu.cycles += 5 + len; +} + +static void op819(byte *opc) // rSRB f/A +{ + int len = (opc[3] == 0xF) ? 5 : fl[opc[3]]; + alu_srb(cpu.reg[opc[4]&3] + fs[opc[3]], len); + cpu.pc += 5; + cpu.cycles += 20; +} + +static void op81Af0(byte *opc) // Ri=r f/A +{ + int i = (opc[5] & 7) > 4 ? opc[5] & 3 : opc[5] & 7; + int len = (opc[3] == 0xF) ? 5 : fl[opc[3]]; + reg_cpy(cpu.reg_r[i] + fs[opc[3]], cpu.reg[(opc[5]&8)>>2] + fs[opc[3]], len); + cpu.pc += 6; + cpu.cycles += 6 + len; +} + +static void op81Af1(byte *opc) // r=Ri f/A +{ + int i = (opc[5] & 7) > 4 ? opc[5] & 3 : opc[5] & 7; + int len = (opc[3] == 0xF) ? 5 : fl[opc[3]]; + reg_cpy(cpu.reg[(opc[5]&8)>>2] + fs[opc[3]], cpu.reg_r[i] + fs[opc[3]], len); + cpu.pc += 6; + cpu.cycles += 6 + len; +} + +static void op81Af2(byte *opc) // rRiEX f/A +{ + int i = (opc[5] & 7) > 4 ? opc[5] & 3 : opc[5] & 7; + int len = (opc[3] == 0xF) ? 5 : fl[opc[3]]; + reg_ex(cpu.reg[(opc[5]&8)>>2] + fs[opc[3]], cpu.reg_r[i] + fs[opc[3]], len); + cpu.pc += 6; + cpu.cycles += 6 + len; +} + +static void op81B2_3(byte *opc) // PC=r +{ + cpu.pc = nib_to_unsigned(cpu.reg[(opc[3]&1)<<1], 5); + cpu.cycles += 16; +} + +static void op81B4_5(byte *opc) // r=PC +{ + cpu.pc += 4; + unsigned_to_nib(cpu.reg[(opc[3]&1)<<1], cpu.pc, 5); + cpu.cycles += 9; +} + +static void op81C_F(byte *opc) // rSRB +{ + alu_srb(cpu.reg[opc[2]&3], 16); + cpu.pc += 3; + cpu.cycles += 20; +} + +static void op82(byte *opc) // HST=0 +{ + cpu.hst &= ~opc[2]; + cpu.pc += 3; + cpu.cycles += 3; +} + +static void op83(byte *opc) // ?HST=0 +{ + cpu.carry = (cpu.hst & opc[2]) ? FALSE : TRUE; + goyes(opc, 3); + cpu.cycles += 6; +} + +static void op84_5(byte *opc) // ST=b +{ + reg_bit(cpu.st, opc[2], opc[1] & 1); + cpu.pc += 3; + cpu.cycles += 4; +} + +static void op86_7(byte *opc) // ?ST=b +{ + comp_bit_zero(cpu.st, opc[2]); + if (opc[1] & 1) cpu.carry = !cpu.carry; + goyes(opc, 3); + cpu.cycles += 7; +} + +static void op88_9(byte *opc) // ?P# / ?P= +{ + cpu.carry = (cpu.p == opc[2]) == (opc[1]&1) ? TRUE : FALSE; + goyes(opc, 3); + cpu.cycles += 6; +} + +static void op8A(byte *opc) // ?u=v A / ?u#v A / ?u=0 A / ?u#0 A +{ + if (!(opc[2] & 8)) { + comp_eq(REGu(opc[2]), REGv(opc[2]), 5); + } else { + comp_zero (cpu.reg[opc[2]&3], 5); + } + if (opc[2] & 4) cpu.carry = !cpu.carry; + goyes(opc, 3); + cpu.cycles += 11; +} + +static void op8B(byte *opc) // ?u>v A / u=v A / u<=v A +{ + comp_gt(REGu(opc[2]), REGv(opc[2]), 5); + if (opc[2] & 8) cpu.carry = !cpu.carry; + goyes(opc, 3); + cpu.cycles += 11; +} + +static void op8C(byte *opc) // GOLONG +{ + cpu.pc += nib_to_signed(opc+2, 4) + 2; + cpu.cycles += 14; +} + +static void op8D(byte *opc) // GOVLNG +{ + cpu.pc = nib_to_unsigned(opc+2, 5); + cpu.cycles += 14; +} + +static void op8E(byte *opc) // GOSUBL +{ + rstk_push(cpu.pc + 6); + cpu.pc += nib_to_signed(opc+2, 4) + 6; + cpu.cycles += 14; +} + +static void op8F(byte *opc) // GOSBVL +{ + rstk_push(cpu.pc + 7); + cpu.pc = nib_to_unsigned(opc+2, 5); + cpu.cycles += 15; +} + +static void op9a(byte *opc) // ?u=v f / ?u#v f / ?u=0 f / ?u#0 f +{ + if (!(opc[2] & 8)) { + comp_eq(REGuF(opc[2], opc[1]), REGvF(opc[2], opc[1]), fl[opc[1]]); + } else { + comp_zero(cpu.reg[opc[2]&3] + fs[opc[1]], fl[opc[1]]); + } + if (opc[2] & 4) cpu.carry = !cpu.carry; + goyes(opc, 3); + cpu.cycles += 6 + fl[opc[1]]; +} + +static void op9b(byte *opc) // ?u>v f / u=v f / u<=v f +{ + comp_gt(REGuF(opc[2], opc[1]), REGvF(opc[2], opc[1]), fl[opc[1]]); + if (opc[2] & 8) cpu.carry = !cpu.carry; + goyes(opc, 3); + cpu.cycles += 6 + fl[opc[1]]; +} + +static void opAa(byte *opc) // t=t+v f / t=t-1 f +{ + switch (opc[2] & 0xC) { + case 0x0: + case 0x4: + case 0x8: + alu_add(REGtF(opc[2], opc[1]), REGvF(opc[2], opc[1]), fl[opc[1]]); + break; + case 0xC: + alu_dec(REGtF(opc[2], opc[1]), fl[opc[1]]); + break; + } + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opAb(byte *opc) // t=0 f / t=r f / trEX f +{ + switch (opc[2] & 0xC) { + case 0x0: + reg_zero(REGtF(opc[2], opc[1]), fl[opc[1]]); + break; + case 0x4: + case 0x8: + reg_cpy(REGtF(opc[2], opc[1]), REGrF(opc[2], opc[1]), fl[opc[1]]); + break; + case 0xC: + reg_ex(REGtF(opc[2], opc[1]), REGrF(opc[2], opc[1]), fl[opc[1]]); + break; + } + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opBa(byte *opc) // t=t-v f / t=t+1 f / t=v-t f +{ + switch (opc[2] & 0xC) { + case 0x0: + case 0x8: + alu_sub(REGtF(opc[2], opc[1]), REGvF(opc[2], opc[1]), fl[opc[1]]); + break; + case 0x4: + alu_inc(REGtF(opc[2], opc[1]), fl[opc[1]]); + break; + case 0xC: + alu_sub2(REGtF(opc[2], opc[1]), REGvF(opc[2], opc[1]), fl[opc[1]]); + break; + } + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opBb0_3(byte *opc) // rSL f +{ + alu_sl(cpu.reg[opc[2]&3] + fs[opc[1]], fl[opc[1]]); + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opBb4_7(byte *opc) // rSR f +{ + alu_sr(cpu.reg[opc[2]&3] + fs[opc[1]], fl[opc[1]]); + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opBb8_B(byte *opc) // r=-r f +{ + alu_neg(cpu.reg[opc[2]&3] + fs[opc[1]], fl[opc[1]]); + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opBbC_F(byte *opc) // r=-r-1 f +{ + alu_not(cpu.reg[opc[2]&3] + fs[opc[1]], fl[opc[1]]); + cpu.pc += 3; + cpu.cycles += 3 + fl[opc[1]]; +} + +static void opC(byte *opc) // t=t+v A / t=t-1 A +{ + switch (opc[1] & 0xC) { + case 0x0: + case 0x4: + case 0x8: + alu_add(REGt(opc[1]), REGv(opc[1]), 5); + break; + case 0xC: + alu_dec(REGt(opc[1]), 5); + break; + } + cpu.pc += 2; + cpu.cycles += 7; +} + +static void opD(byte *opc) // t=0 A / t=r A / trEX A +{ + switch (opc[1] & 0xC) { + case 0x0: + reg_zero(REGt(opc[1]), 5); + break; + case 0x4: + case 0x8: + reg_cpy(REGt(opc[1]), REGr(opc[1]), 5); + break; + case 0xC: + reg_ex(REGt(opc[1]), REGr(opc[1]), 5); + break; + } + cpu.pc += 2; + cpu.cycles += 7; +} + +static void opE(byte *opc) // t=t-v A / t=t+1 A / t=v-t A +{ + switch (opc[1] & 0xC) { + case 0x0: + case 0x8: + alu_sub(REGt(opc[1]), REGv(opc[1]), 5); + break; + case 0x4: + alu_inc(REGt(opc[1]), 5); + break; + case 0xC: + alu_sub2(REGt(opc[1]), REGv(opc[1]), 5); + break; + } + cpu.pc += 2; + cpu.cycles += 7; +} + +static void opF0_3(byte *opc) // rSL f +{ + alu_sl(cpu.reg[opc[1]&3], 5); + cpu.pc += 2; + cpu.cycles += 7; +} + +static void opF4_7(byte *opc) // rSR f +{ + alu_sr(cpu.reg[opc[1]&3], 5); + cpu.pc += 2; + cpu.cycles += 7; +} + +static void opF8_B(byte *opc) // r=-r A +{ + alu_neg(cpu.reg[opc[1]&3], 5); + cpu.pc += 2; + cpu.cycles += 7; +} + +static void opFC_F(byte *opc) // r=-r-1 A +{ + alu_not(cpu.reg[opc[1]&3], 5); + cpu.pc += 2; + cpu.cycles += 7; +} + +static Opcode opcodes0[16] = { + { op00, NULL, "RTNSXM" }, + { op01, NULL, "RTN" }, + { op02_3, NULL, "RTNSC" }, + { op02_3, NULL, "RTNCC" }, + { op04_5, NULL, "SETHEX" }, + { op04_5, NULL, "SETDEC" }, + { op06, NULL, "RSTK=C" }, + { op07, NULL, "C=RSTK" }, + { op08, NULL, "CLRST" }, + { op09, NULL, "C=ST" }, + { op0A, NULL, "ST=C" }, + { op0B, NULL, "CSTEX" }, + { op0C, NULL, "P=P+1" }, + { op0D, NULL, "P=P-1" }, + { op0E, NULL, "%r3=%r3%&3%s3 %F2A" }, + { op0F, NULL, "RTI" } +}; + +static Opcode opcodes13[16] = { + { op13a, NULL, "D0=A" }, + { op13a, NULL, "D1=A" }, + { op13a, NULL, "AD0EX" }, + { op13a, NULL, "AD1EX" }, + { op13a, NULL, "D0=C" }, + { op13a, NULL, "D1=C" }, + { op13a, NULL, "CD0EX" }, + { op13a, NULL, "CD1EX" }, + { op13b, NULL, "D0=AS" }, + { op13b, NULL, "D1=AS" }, + { op13b, NULL, "AD0EXS" }, + { op13b, NULL, "AD1EXS" }, + { op13b, NULL, "D0=CS" }, + { op13b, NULL, "D1=CS" }, + { op13b, NULL, "CD0EXS" }, + { op13b, NULL, "CD1EXS" } +}; + +static Opcode opcodes15[16] = { + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15a, NULL, "%D2 %F3" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" }, + { op15b, NULL, "%D2 %I3+1" } +}; + +static Opcode opcodes1[16] = { + { op10, NULL, "R%i2=%a2" }, + { op11, NULL, "%a2=R%i2" }, + { op12, NULL, "%a2R%i2EX" }, + { NULL, opcodes13, NULL }, + { op14, NULL, "%D2 %B2" }, + { NULL, opcodes15, NULL }, + { op16_7, NULL, "D0=D0+ %I2+1" }, + { op16_7, NULL, "D1=D1+ %I2+1" }, + { op18_C, NULL, "D0=D0- %I2+1" }, + { op19_D, NULL, "D0=(2) %X22" }, + { op1A_E, NULL, "D0=(4) %X24" }, + { op1B_F, NULL, "D0=(5) %X25" }, + { op18_C, NULL, "D1=D1- %I2+1" }, + { op19_D, NULL, "D1=(2) %X22" }, + { op1A_E, NULL, "D1=(4) %X24" }, + { op1B_F, NULL, "D1=(5) %X25" }, +}; + +static Opcode opcodes808[16] = { + { op8080, NULL, "INTON" }, + { op8081, NULL, "RSI" }, + { op8082, NULL, "LA #%N4" }, + { NULL, NULL, NULL }, + { op8084_5_8_9, NULL, "ABIT=0 %I4" }, + { op8084_5_8_9, NULL, "ABIT=1 %I4" }, + { op8086_7_A_B, NULL, "?ABIT=0 %I4, %G52YES %T52+5" }, + { op8086_7_A_B, NULL, "?ABIT=1 %I4, %G52YES %T52+5" }, + { op8084_5_8_9, NULL, "CBIT=0 %I4" }, + { op8084_5_8_9, NULL, "CBIT=1 %I4" }, + { op8086_7_A_B, NULL, "?CBIT=0 %I4, %G52YES %T52+5" }, + { op8086_7_A_B, NULL, "?CBIT=1 %I4, %G52YES %T52+5" }, + { op808C_E, NULL, "PC=(A)" }, + { NULL, NULL, NULL }, + { op808C_E, NULL, "PC=(C)" }, + { op808F, NULL, "INTOFF" } +}; + +static Opcode opcodes80[16] = { + { op800_1, NULL, "OUT=CS" }, + { op800_1, NULL, "OUT=C" }, + { op802_3, NULL, "A=IN" }, + { op802_3, NULL, "C=IN" }, + { op804, NULL, "UNCONFIG" }, + { op805, NULL, "CONFIG" }, + { op806, NULL, "C=ID" }, + { op807, NULL, "SHUTDN" }, + { NULL, opcodes808, NULL }, + { op809, NULL, "C+P+1" }, + { op80A, NULL, "RESET" }, + { NULL, NULL, NULL }, + { op80C, NULL, "C=P %I3" }, + { op80D, NULL, "P=C %I3" }, + { NULL, NULL, NULL }, + { op80F, NULL, "CPEX %I3" } +}; + +static Opcode opcodes81Af[16] = { + { op81Af0, NULL, "R%i5=%a5 %F3A" }, + { op81Af1, NULL, "%a5=R%i5 %F3A" }, + { op81Af2, NULL, "%a5R%i5EX %F3A" }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; + +static Opcode opcodes81A[16] = { + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL }, + { NULL, opcodes81Af,NULL } +}; + +static Opcode opcodes81B[16] = { + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { op81B2_3, NULL, "PC=A" }, + { op81B2_3, NULL, "PC=C" }, + { op81B4_5, NULL, "A=PC" }, + { op81B4_5, NULL, "C=PC" }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL }, + { NULL, NULL, NULL } +}; + +static Opcode opcodes81[16] = { + { op810_3, NULL, "ASLC" }, + { op810_3, NULL, "BSLC" }, + { op810_3, NULL, "CSLC" }, + { op810_3, NULL, "DSLC" }, + { op814_7, NULL, "ASRC" }, + { op814_7, NULL, "BSRC" }, + { op814_7, NULL, "CSRC" }, + { op814_7, NULL, "DSRC" }, + { op818, NULL, "%u4=%u4%~4CON %F3A, %I6+1" }, + { op819, NULL, "%u4SRB %F3A" }, + { NULL, opcodes81A, NULL }, + { NULL, opcodes81B, NULL }, + { op81C_F, NULL, "ASRB" }, + { op81C_F, NULL, "BSRB" }, + { op81C_F, NULL, "CSRB" }, + { op81C_F, NULL, "DSRB" } +}; + +static Opcode opcodes8[16] = { + { NULL, opcodes80, NULL }, + { NULL, opcodes81, NULL }, + { op82, NULL, "HST=0 #%X21" }, + { op83, NULL, "?HST=0 #%X21, %G32YES %T32+3" }, + { op84_5, NULL, "ST=0 %I2" }, + { op84_5, NULL, "ST=1 %I2" }, + { op86_7, NULL, "?ST=0 %I2, %G32YES %T32+3" }, + { op86_7, NULL, "?ST=1 %I2, %G32YES %T32+3" }, + { op88_9, NULL, "?P# %I2, %G32YES %T32+3" }, + { op88_9, NULL, "?P= %I2, %G32YES %T32+3" }, + { op8A, NULL, "?%u2%#2%z2 A, %G32YES %T32+3" }, + { op8B, NULL, "?%u2%>2%v2 A, %G32YES %T32+3" }, + { op8C, NULL, "GOLONG %R24+2" }, + { op8D, NULL, "GOVLNG %X25" }, + { op8E, NULL, "GOSUBL %R24+6" }, + { op8F, NULL, "GOSBVL %X25" }, +}; + +static Opcode opcodes9[16] = { + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9a, NULL, "?%u2%#2%z2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" }, + { op9b, NULL, "?%u2%>2%v2 %F1, %G32YES %T32+3" } +}; + +static Opcode opcodesA[16] = { + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAa, NULL, "%t2=%t2%+2%w2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" }, + { opAb, NULL, "%x2%=2%y2%E2 %F1" } +}; + +static Opcode opcodesBb[16] = { + { opBb0_3, NULL, "ASL %F1" }, + { opBb0_3, NULL, "BSL %F1" }, + { opBb0_3, NULL, "CSL %F1" }, + { opBb0_3, NULL, "DSL %F1" }, + { opBb4_7, NULL, "ASR %F1" }, + { opBb4_7, NULL, "BSR %F1" }, + { opBb4_7, NULL, "CSR %F1" }, + { opBb4_7, NULL, "DSR %F1" }, + { opBb8_B, NULL, "A=-A %F1" }, + { opBb8_B, NULL, "B=-B %F1" }, + { opBb8_B, NULL, "C=-C %F1" }, + { opBb8_B, NULL, "D=-D %F1" }, + { opBbC_F, NULL, "A=-A-1 %F1" }, + { opBbC_F, NULL, "B=-B-1 %F1" }, + { opBbC_F, NULL, "C=-C-1 %F1" }, + { opBbC_F, NULL, "D=-D-1 %F1" } +}; + +static Opcode opcodesB[16] = { + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { opBa, NULL, "%t2=%p2%-2%q2 %F1" }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL }, + { NULL, opcodesBb, NULL } +}; + +static Opcode opcodesF[16] = { + { opF0_3, NULL, "ASL A" }, + { opF0_3, NULL, "BSL A" }, + { opF0_3, NULL, "CSL A" }, + { opF0_3, NULL, "DSL A" }, + { opF4_7, NULL, "ASR A" }, + { opF4_7, NULL, "BSR A" }, + { opF4_7, NULL, "CSR A" }, + { opF4_7, NULL, "DSR A" }, + { opF8_B, NULL, "A=-A A" }, + { opF8_B, NULL, "B=-B A" }, + { opF8_B, NULL, "C=-C A" }, + { opF8_B, NULL, "D=-D A" }, + { opFC_F, NULL, "A=-A-1 A" }, + { opFC_F, NULL, "B=-B-1 A" }, + { opFC_F, NULL, "C=-C-1 A" }, + { opFC_F, NULL, "D=-D-1 A" }, +}; + +Opcode opcodes[16] = { + { NULL, opcodes0, NULL }, + { NULL, opcodes1, NULL }, + { op2, NULL, "P= %I1" }, + { op3, NULL, "LC #%N1" }, + { op4, NULL, "%G12C %T12+1" }, + { op5, NULL, "%G12NC %T12+1" }, + { op6, NULL, "GOTO %R13+1" }, + { op7, NULL, "GOSUB %R13+4" }, + { NULL, opcodes8, NULL }, + { NULL, opcodes9, NULL }, + { NULL, opcodesA, NULL }, + { NULL, opcodesB, NULL }, + { opC, NULL, "%t1=%t1%+1%w1 A" }, + { opD, NULL, "%x1%=1%y1%E1 A" }, + { opE, NULL, "%t1=%p1%-1%q1 A" }, + { NULL, opcodesF, NULL } +}; diff --git a/src/opcodes.h b/src/opcodes.h new file mode 100644 index 0000000..df7f06a --- /dev/null +++ b/src/opcodes.h @@ -0,0 +1,41 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __OPCODES_H +#define __OPCODES_H + +typedef struct Opcode Opcode; + +struct Opcode { + void (*exec)(byte *); + Opcode *next; + char *dissasm; +}; + +extern Opcode opcodes[16]; + +#endif diff --git a/src/opinline.h b/src/opinline.h new file mode 100644 index 0000000..07469ed --- /dev/null +++ b/src/opinline.h @@ -0,0 +1,404 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __OPINLINE_H +#define __OPINLINE_H + +#include +#include "emulator.h" +#include "cpu.h" + +static __inline void load(byte *reg, byte *data, int start, int len) +{ + if (start + len <= 16) { + memcpy(reg+start, data, len); + } else { + memcpy(reg+start, data, 16-start); + memcpy(reg, data+(16-start), len-(16-start)); + } +} + +static __inline unsigned int nib_to_unsigned(byte *nib, int len) +{ + int x = 0; + + while (len--) { + x <<= 4; + x |= nib[len]; + } + return x; +} + +static __inline int nib_to_signed(byte *nib, int len) +{ + int x; + + len--; + x = nib[len]; + if (x & 8) x -= 16; + while (len--) { + x <<= 4; + x |= nib[len]; + } + return x; +} + +static __inline void unsigned_to_nib(byte *nib, int x, int len) +{ + while (len--) { + *nib++ = x & 0xF; + x >>= 4; + } +} + +static __inline address rstk_pop(void) +{ + address adr = cpu.rstk[cpu.rstk_ptr]; + cpu.rstk[cpu.rstk_ptr] = 0x00000; + cpu.rstk_ptr = (cpu.rstk_ptr + 1) & 7; + return adr; +} + +static __inline void rstk_push(address adr) +{ + cpu.rstk_ptr = (cpu.rstk_ptr - 1) & 7; + cpu.rstk[cpu.rstk_ptr] = adr & 0xFFFFF; +} + +static __inline void goyes(byte *opc, int offset) +{ + if (cpu.carry) { + address rel = nib_to_signed(opc + offset, 2); + if (rel) { + cpu.pc += rel + offset; + } else { + cpu.pc = rstk_pop(); + } + cpu.cycles += 7; + } else { + cpu.pc += offset + 2; + } +} + +static __inline void reg_zero(byte *reg, int len) +{ + memset(reg, 0, len); +} + +static __inline void reg_bit(byte *reg, int bit, int value) +{ + if (value) { + reg[bit>>2] |= 1 << (bit & 3); + } else { + reg[bit>>2] &= ~(1 << (bit & 3)); + } +} + +static __inline void reg_cpy(byte *dest, byte *src, int len) +{ + memcpy(dest, src, len); +} + +static __inline void reg_ex(byte *reg1, byte *reg2, int len) +{ + static byte tmp[16]; + + memcpy(tmp, reg1, len); + memcpy(reg1, reg2, len); + memcpy(reg2, tmp, len); +} + +static __inline void comp_bit_zero(byte *reg, int bit) +{ + cpu.carry =(reg[bit>>2] & (1 << (bit & 3))) ? FALSE : TRUE; +} + +static __inline void comp_zero(byte *reg, int len) +{ + while (len--) { + if (*reg++) { + cpu.carry = FALSE; + return; + } + } + cpu.carry = TRUE; +} + +static __inline void comp_eq(byte *reg1, byte *reg2, int len) +{ + while (len--) { + if (*reg1++ != *reg2++) { + cpu.carry = FALSE; + return; + } + } + cpu.carry = TRUE; +} + +static __inline void comp_gt(byte *reg1, byte *reg2, int len) +{ + while (--len && reg1[len] == reg2[len]) + ; + cpu.carry = (reg1[len] > reg2[len]) ? TRUE : FALSE; +} + +static __inline void alu_add(byte *dest, byte *src, int len) +{ + byte c = 0; + byte base = cpu.dec ? 10 : 16; + + while (len--) { + if (*dest >= base) *dest &= 7; + *dest += *src + c; + if (*dest >= base) { + *dest -= base; + c = 1; + } else { + c = 0; + } + dest++; + src++; + } + cpu.carry = c ? TRUE : FALSE; +} + +static __inline void alu_sub(byte *dest, byte *src, int len) +{ + byte c = 0; + byte base = cpu.dec ? 10 : 16; + + while (len--) { + *dest -= *src + c; + if (*dest & 0xF0) { + *dest += base; + c = 1; + } else { + c = 0; + } + dest++; + src++; + } + cpu.carry = c ? TRUE : FALSE; +} + +static __inline void alu_sub2(byte *dest, byte *src, int len) +{ + byte c = 0; + byte base = cpu.dec ? 10 : 16; + + while (len--) { + *dest = *src - (*dest + c); + if (*dest & 0xF0) { + *dest += base; + c = 1; + } else { + c = 0; + } + dest++; + src++; + } + cpu.carry = c ? TRUE : FALSE; +} + +static __inline void alu_add_con(byte *reg, byte con, int i, int len) +{ + reg[i] += con; + while (len--) { + reg[i]++; + if (!(reg[i] & 0xF0)) { + cpu.carry = FALSE; + return; + } + reg[i] -= 16; + i = (i + 1) & 0xF; + } + cpu.carry = TRUE; +} + +static __inline void alu_sub_con(byte *reg, byte con, int i, int len) +{ + reg[i] -= con; + while (len--) { + reg[i]--; + if (!(reg[i] & 0xF0)) { + cpu.carry = FALSE; + return; + } + reg[i] += 16; + i = (i + 1) & 0xF; + } + cpu.carry = TRUE; +} + +static __inline void alu_inc(byte *reg, int len) +{ + if (cpu.dec) { + byte c = 1; + while (len--) { + if (*reg >= 10) *reg &= 7; + *reg += c; + if (*reg >= 10) { + *reg -= 10; + c = 1; + } else { + c = 0; + } + reg++; + } + cpu.carry = c ? TRUE : FALSE; + } else { + while (len--) { + (*reg)++; + if (!(*reg & 0xF0)) { + cpu.carry = FALSE; + return; + } + *reg -= 16; + reg++; + } + cpu.carry = TRUE; + } +} + +static __inline void alu_dec(byte *reg, int len) +{ + byte base = cpu.dec ? 10 : 16; + + while (len--) { + (*reg)--; + if (!(*reg & 0xF0)) { + cpu.carry = FALSE; + return; + } + *reg += base; + reg++; + } + cpu.carry = TRUE; +} + +static __inline void alu_neg(byte *reg, int len) +{ + byte base = cpu.dec ? 10 : 16; + + while (len && *reg == 0) { + reg++; + len--; + } + cpu.carry = len ? TRUE : FALSE; + if (cpu.carry) { + *reg = base - *reg; + if (*reg & 0xF0) *reg &= 7; + reg++; + len--; + base--; + while (len--) { + *reg = base - *reg; + if (*reg & 0xF0) *reg &= 7; + reg++; + } + } +} + +static __inline void alu_not(byte *reg, int len) +{ + byte base = cpu.dec ? 9 : 15; + + while (len--) { + *reg = base - *reg; + if (*reg & 0xF0) *reg &= 7; + reg++; + } + cpu.carry = FALSE; +} + +static __inline void alu_and(byte *dest, byte *src, int len) +{ + while (len--) { + *dest++ &= *src++; + } +} + +static __inline void alu_or(byte *dest, byte *src, int len) +{ + while (len--) { + *dest++ |= *src++; + } +} + +static __inline void alu_sl(byte *reg, int len) +{ + while (--len) { + reg[len] = reg[len-1]; + } + reg[0] = 0; +} + +static __inline void alu_slc(byte *reg, int len) +{ + byte tmp = reg[len-1]; + + while (--len) { + reg[len] = reg[len-1]; + } + reg[0] = tmp; +} + +static __inline void alu_sr(byte *reg, int len) +{ + if (reg[0]) cpu.hst |= HST_SB; + + while (--len) { + reg[0] = reg[1]; + reg++; + } + reg[0] = 0; +} + +static __inline void alu_src(byte *reg, int len) +{ + byte tmp = reg[0]; + + while (--len) { + reg[0] = reg[1]; + reg++; + } + reg[0] = tmp; +} + +static __inline void alu_srb(byte *reg, int len) +{ + if (*reg & 1) cpu.hst |= HST_SB; + + while (--len) { + *reg >>= 1; + if (reg[1] & 1) *reg |= 8; + reg++; + } + *reg >>= 1; +} + +#endif diff --git a/src/pabout.c b/src/pabout.c new file mode 100644 index 0000000..d695da9 --- /dev/null +++ b/src/pabout.c @@ -0,0 +1,119 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "color.h" +#include "gui.h" +#include "pabout.h" + +static BITMAP *about_bmp; + +static char *about_line[] = { + "C / ", + "C /__ ___ ___ ____ ", + "C / / / / /__/ / / / / /", + "C/ / /__/ /__ / / /__/ ", + "C / ", + "C / version 0.9.0 ", + "P", + " Copyright 2002 Daniel Nilsson", + "P", + "JHpemu is free software; you can", + "Jredistribute it and/or modify it under", + "Jthe terms of the GNU General Public", + "JLicense as published by the Free Software", + "JFoundation; either version 2 of the", + "JLicense, or (at your option) any later", + "Jversion.", + "P", + "JHpemu is distributed in the hope that it", + "Jwill be useful, but WITHOUT ANY WARRANTY;", + "Jwithout even the implied warranty of", + "JMERCHANTABILITY or FITNESS FOR A", + "JPARTICULAR PURPOSE. See the GNU General", + "JPublic License for more details.", + "P", + "JYou should have received a copy of the", + "JGNU General Public License along with", + "Jhpemu; if not, write to the Free Software", + "JFoundation, Inc., 59 Temple Place,", + "JSuite 330, Boston, MA 02111-1307 USA", + NULL +}; + +static void draw_about(void) +{ + int i, y; + + text_mode(color[C_PANEL_BACK]); + + acquire_bitmap(about_bmp); + scare_mouse(); + + y = 10; + for (i = 0; about_line[i]; i++) { + switch (about_line[i][0]) { + case 'C': + textout_centre(about_bmp, font, about_line[i]+1, 170, y, color[C_PANEL_TEXT]); + break; + case 'J': + textout_justify(about_bmp, font, about_line[i]+1, 10, 330, y, 150, color[C_PANEL_TEXT]); + break; + case 'P': + y += 5; + break; + default: + textout(about_bmp, font, about_line[i]+1, 10, y, color[C_PANEL_TEXT]); + break; + } + y += 10; + } + + unscare_mouse(); + release_bitmap(about_bmp); +} + +void pabout_show(BITMAP *bmp) +{ + about_bmp = bmp; + + clear_to_color(about_bmp, color[C_PANEL_BACK]); + draw_about(); +} + +void pabout_hide(void) +{ + about_bmp = NULL; +} + +void pabout_down(int mx, int my, int mb) +{ +} + +void pabout_up(int mx, int my, int mb) +{ +} diff --git a/src/pabout.h b/src/pabout.h new file mode 100644 index 0000000..5a574f1 --- /dev/null +++ b/src/pabout.h @@ -0,0 +1,38 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PABOUT_H +#define __PABOUT_H + +#include + +void pabout_show(BITMAP *bmp); +void pabout_hide(void); +void pabout_down(int mx, int my, int mb); +void pabout_up(int mx, int my, int mb); + +#endif diff --git a/src/pcalc.c b/src/pcalc.c new file mode 100644 index 0000000..aa2176f --- /dev/null +++ b/src/pcalc.c @@ -0,0 +1,210 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "color.h" +#include "display.h" +#include "keyboard.h" +#include "gui.h" +#include "pcalc.h" + +static BITMAP *calc_bmp; + +static void dn00(void) { kbd_key_pressed (0, 0); } +static void up00(boolean action) { kbd_key_released (0, 0); } +static void dn01(void) { kbd_key_pressed (0, 1); } +static void up01(boolean action) { kbd_key_released (0, 1); } +static void dn02(void) { kbd_key_pressed (0, 2); } +static void up02(boolean action) { kbd_key_released (0, 2); } +static void dn03(void) { kbd_key_pressed (0, 3); } +static void up03(boolean action) { kbd_key_released (0, 3); } +static void dn04(void) { kbd_key_pressed (0, 4); } +static void up04(boolean action) { kbd_key_released (0, 4); } +static void dn10(void) { kbd_key_pressed (1, 0); } +static void up10(boolean action) { kbd_key_released (1, 0); } +static void dn11(void) { kbd_key_pressed (1, 1); } +static void up11(boolean action) { kbd_key_released (1, 1); } +static void dn12(void) { kbd_key_pressed (1, 2); } +static void up12(boolean action) { kbd_key_released (1, 2); } +static void dn13(void) { kbd_key_pressed (1, 3); } +static void up13(boolean action) { kbd_key_released (1, 3); } +static void dn14(void) { kbd_key_pressed (1, 4); } +static void up14(boolean action) { kbd_key_released (1, 4); } +static void dn15(void) { kbd_key_pressed (1, 5); } +static void up15(boolean action) { kbd_key_released (1, 5); } +static void dn20(void) { kbd_key_pressed (2, 0); } +static void up20(boolean action) { kbd_key_released (2, 0); } +static void dn21(void) { kbd_key_pressed (2, 1); } +static void up21(boolean action) { kbd_key_released (2, 1); } +static void dn22(void) { kbd_key_pressed (2, 2); } +static void up22(boolean action) { kbd_key_released (2, 2); } +static void dn23(void) { kbd_key_pressed (2, 3); } +static void up23(boolean action) { kbd_key_released (2, 3); } +static void dn24(void) { kbd_key_pressed (2, 4); } +static void up24(boolean action) { kbd_key_released (2, 4); } +static void dn25(void) { kbd_key_pressed (2, 5); } +static void up25(boolean action) { kbd_key_released (2, 5); } +static void dn30(void) { kbd_key_pressed (3, 0); } +static void up30(boolean action) { kbd_key_released (3, 0); } +static void dn31(void) { kbd_key_pressed (3, 1); } +static void up31(boolean action) { kbd_key_released (3, 1); } +static void dn32(void) { kbd_key_pressed (3, 2); } +static void up32(boolean action) { kbd_key_released (3, 2); } +static void dn33(void) { kbd_key_pressed (3, 3); } +static void up33(boolean action) { kbd_key_released (3, 3); } +static void dn34(void) { kbd_key_pressed (3, 4); } +static void up34(boolean action) { kbd_key_released (3, 4); } +static void dn35(void) { kbd_key_pressed (3, 5); } +static void up35(boolean action) { kbd_key_released (3, 5); } +static void dn40(void) { kbd_key_pressed (4, 0); } +static void up40(boolean action) { kbd_key_released (4, 0); } +static void dn41(void) { kbd_key_pressed (4, 1); } +static void up41(boolean action) { kbd_key_released (4, 1); } +static void dn42(void) { kbd_key_pressed (4, 2); } +static void up42(boolean action) { kbd_key_released (4, 2); } +static void dn43(void) { kbd_key_pressed (4, 3); } +static void up43(boolean action) { kbd_key_released (4, 3); } +static void dn44(void) { kbd_key_pressed (4, 4); } +static void up44(boolean action) { kbd_key_released (4, 4); } +static void dn50(void) { kbd_key_pressed (5, 0); } +static void up50(boolean action) { kbd_key_released (5, 0); } +static void dn51(void) { kbd_key_pressed (5, 1); } +static void up51(boolean action) { kbd_key_released (5, 1); } +static void dn52(void) { kbd_key_pressed (5, 2); } +static void up52(boolean action) { kbd_key_released (5, 2); } +static void dn53(void) { kbd_key_pressed (5, 3); } +static void up53(boolean action) { kbd_key_released (5, 3); } +static void dn54(void) { kbd_key_pressed (5, 4); } +static void up54(boolean action) { kbd_key_released (5, 4); } +static void dn60(void) { kbd_key_pressed (6, 0); } +static void up60(boolean action) { kbd_key_released (6, 0); } +static void dn61(void) { kbd_key_pressed (6, 1); } +static void up61(boolean action) { kbd_key_released (6, 1); } +static void dn62(void) { kbd_key_pressed (6, 2); } +static void up62(boolean action) { kbd_key_released (6, 2); } +static void dn63(void) { kbd_key_pressed (6, 3); } +static void up63(boolean action) { kbd_key_released (6, 3); } +static void dn64(void) { kbd_key_pressed (6, 4); } +static void up64(boolean action) { kbd_key_released (6, 4); } +static void dn70(void) { kbd_key_pressed (7, 0); } +static void up70(boolean action) { kbd_key_released (7, 0); } +static void dn71(void) { kbd_key_pressed (7, 1); } +static void up71(boolean action) { kbd_key_released (7, 1); } +static void dn72(void) { kbd_key_pressed (7, 2); } +static void up72(boolean action) { kbd_key_released (7, 2); } +static void dn73(void) { kbd_key_pressed (7, 3); } +static void up73(boolean action) { kbd_key_released (7, 3); } +static void dn74(void) { kbd_key_pressed (7, 4); } +static void up74(boolean action) { kbd_key_released (7, 4); } +static void dn80(void) { kbd_key_pressed (8, 0); } +static void up80(boolean action) { kbd_key_released (8, 0); } +static void dn81(void) { kbd_key_pressed (8, 1); } +static void up81(boolean action) { kbd_key_released (8, 1); } +static void dn82(void) { kbd_key_pressed (8, 2); } +static void up82(boolean action) { kbd_key_released (8, 2); } +static void dn83(void) { kbd_key_pressed (8, 3); } +static void up83(boolean action) { kbd_key_released (8, 3); } +static void dn84(void) { kbd_key_pressed (8, 4); } +static void up84(boolean action) { kbd_key_released (8, 4); } +static void dnON(void) { kbd_on_pressed (); } +static void upON(boolean action) { kbd_on_released (); } + +static Button calc_buttons[] = { + { 5, 160, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "", dn14, up14 }, + { 49, 160, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "", dn84, up84 }, + { 93, 160, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "", dn83, up83 }, + { 137, 160, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "", dn82, up82 }, + { 181, 160, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "", dn81, up81 }, + { 225, 160, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "", dn80, up80 }, + { 5, 184, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "MTH", dn24, up24 }, + { 49, 184, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "PRG", dn74, up74 }, + { 93, 184, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "CST", dn73, up73 }, + { 137, 184, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "VAR", dn72, up72 }, + { 181, 184, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "^", dn71, up71 }, + { 225, 184, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "NXT", dn70, up70 }, + { 5, 208, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "'", dn04, up04 }, + { 49, 208, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "STO", dn64, up64 }, + { 93, 208, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "EVAL", dn63, up63 }, + { 137, 208, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "<", dn62, up62 }, + { 181, 208, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "v", dn61, up61 }, + { 225, 208, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, ">", dn60, up60 }, + { 5, 232, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "SIN", dn34, up34 }, + { 49, 232, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "COS", dn54, up54 }, + { 93, 232, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "TAN", dn53, up53 }, + { 137, 232, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "/x", dn52, up52 }, + { 181, 232, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "yx", dn51, up51 }, + { 225, 232, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "1/x", dn50, up50 }, + { 5, 256, 84, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "ENTER",dn44, up44 }, + { 93, 256, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "+/-", dn43, up43 }, + { 137, 256, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "EEX", dn42, up42 }, + { 181, 256, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "DEL", dn41, up41 }, + { 225, 256, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "<-", dn40, up40 }, + { 5, 280, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "a", dn35, up35 }, + { 49, 280, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "7", dn33, up33 }, + { 104, 280, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "8", dn32, up32 }, + { 159, 280, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "9", dn31, up31 }, + { 214, 280, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "/", dn30, up30 }, + { 5, 304, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "<-", dn25, up25 }, + { 49, 304, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "4", dn23, up23 }, + { 104, 304, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "5", dn22, up22 }, + { 159, 304, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "6", dn21, up21 }, + { 214, 304, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "X", dn20, up20 }, + { 5, 328, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "->", dn15, up15 }, + { 49, 328, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "1", dn13, up13 }, + { 104, 328, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "2", dn12, up12 }, + { 159, 328, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "3", dn11, up11 }, + { 214, 328, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "-", dn10, up10 }, + { 5, 352, 40, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "ON", dnON, upON }, + { 49, 352, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "0", dn03, up03 }, + { 104, 352, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, ".", dn02, up02 }, + { 159, 352, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "SPC", dn01, up01 }, + { 214, 352, 51, 20, BUTTON_B1RELEASE | BUTTON_B2TOGGLE, "+", dn00, up00 }, + { 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + +void pcalc_show(BITMAP *bmp) +{ + calc_bmp = bmp; + + clear_to_color(calc_bmp, color[C_PANEL_BACK]); + button_draw_all(calc_bmp, calc_buttons); +} + +void pcalc_hide(void) +{ + calc_bmp = NULL; +} + +void pcalc_down(int mx, int my, int mb) +{ + button_mouse_down(calc_bmp, calc_buttons, mx, my, mb); +} + +void pcalc_up(int mx, int my, int mb) +{ + button_mouse_up(calc_bmp, calc_buttons, mx, my, mb); +} diff --git a/src/pcalc.h b/src/pcalc.h new file mode 100644 index 0000000..17c4525 --- /dev/null +++ b/src/pcalc.h @@ -0,0 +1,38 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PCALC_H +#define __PCALC_H + +#include + +void pcalc_show(BITMAP *bmp); +void pcalc_hide(void); +void pcalc_down(int mx, int my, int mb); +void pcalc_up(int mx, int my, int mb); + +#endif diff --git a/src/pdebug.c b/src/pdebug.c new file mode 100644 index 0000000..c78b589 --- /dev/null +++ b/src/pdebug.c @@ -0,0 +1,267 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "emulator.h" +#include "cpu.h" +#include "bus.h" +#include "disasm.h" +#include "color.h" +#include "gui.h" +#include "pdebug.h" + +static void run_up(boolean action); +static void break_up(boolean action); +static void step_up(boolean action); + +static Button debug_buttons[] = { + { 0, 0, 79, 20, BUTTON_B1RELEASE, "Break", NULL, break_up }, + { 80, 0, 79, 20, BUTTON_B1RELEASE, "Run", NULL, run_up }, + { 160, 0, 79, 20, BUTTON_B1RELEASE, "Step", NULL, step_up }, + { 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + +#define BREAK_BUTTON 0 +#define RUN_BUTTON 1 +#define STEP_BUTTON 2 + +static BITMAP *debug_bmp; + +static void update_buttons(void) +{ + if (emulator_get_state() == EMULATOR_STOP) { + if (debug_buttons[RUN_BUTTON].flags & BUTTON_DISABLED) { + debug_buttons[RUN_BUTTON].flags &= ~BUTTON_DISABLED; + if (debug_bmp) button_draw(debug_bmp, debug_buttons + RUN_BUTTON); + } + if (!(debug_buttons[BREAK_BUTTON].flags & BUTTON_DISABLED)) { + debug_buttons[BREAK_BUTTON].flags |= BUTTON_DISABLED; + if (debug_bmp) button_draw(debug_bmp, debug_buttons + BREAK_BUTTON); + } + if (debug_buttons[STEP_BUTTON].flags & BUTTON_DISABLED) { + debug_buttons[STEP_BUTTON].flags &= ~BUTTON_DISABLED; + if (debug_bmp) button_draw(debug_bmp, debug_buttons + STEP_BUTTON); + } + } else { + if (!(debug_buttons[RUN_BUTTON].flags & BUTTON_DISABLED)) { + debug_buttons[RUN_BUTTON].flags |= BUTTON_DISABLED; + if (debug_bmp) button_draw(debug_bmp, debug_buttons + RUN_BUTTON); + } + if (debug_buttons[BREAK_BUTTON].flags & BUTTON_DISABLED) { + debug_buttons[BREAK_BUTTON].flags &= ~BUTTON_DISABLED; + if (debug_bmp) button_draw(debug_bmp, debug_buttons + BREAK_BUTTON); + } + if (!(debug_buttons[STEP_BUTTON].flags & BUTTON_DISABLED)) { + debug_buttons[STEP_BUTTON].flags |= BUTTON_DISABLED; + if (debug_bmp) button_draw(debug_bmp, debug_buttons + STEP_BUTTON); + } + } +} + +static void run_up(boolean action) +{ + if (action) { + emulator_set_state(EMULATOR_RUN); + } +} + +static void break_up(boolean action) +{ + if (action) { + emulator_set_state(EMULATOR_STOP); + } +} + +static void step_up(boolean action) +{ + if (action) { + emulator_set_state(EMULATOR_STEP); + } +} + +static void draw_cpu(void) +{ + int c1 = color[C_PANEL_TEXT]; + int c2 = color[C_PANEL_DISABLED]; + int i; + char *tmp; + + if (!debug_bmp) { + return; + } + + text_mode(color[C_PANEL_BACK]); + + acquire_bitmap(debug_bmp); + scare_mouse(); + + tmp = disassemble(bus_fast_peek(NULL, cpu.pc, NULL)); + textprintf(debug_bmp, font, 10, 30, c1, "PC = #%05X %-24s", (int) cpu.pc, tmp); + + textprintf(debug_bmp, font, 10, 50, c1, "A = #%s", nib_to_hex_rev(cpu.reg[A], 16)); + textprintf(debug_bmp, font, 10, 60, c1, "B = #%s", nib_to_hex_rev(cpu.reg[B], 16)); + textprintf(debug_bmp, font, 10, 70, c1, "C = #%s", nib_to_hex_rev(cpu.reg[C], 16)); + textprintf(debug_bmp, font, 10, 80, c1, "D = #%s", nib_to_hex_rev(cpu.reg[D], 16)); + textprintf(debug_bmp, font, 58, 90, c2, "%*c%*c", (int) 16-cpu.p, 'P', (int) cpu.p+1, '\0'); + textprintf(debug_bmp, font, 10, 100, c1, "R0 = #%s", nib_to_hex_rev(cpu.reg_r[0], 16)); + textprintf(debug_bmp, font, 10, 110, c1, "R1 = #%s", nib_to_hex_rev(cpu.reg_r[1], 16)); + textprintf(debug_bmp, font, 10, 120, c1, "R2 = #%s", nib_to_hex_rev(cpu.reg_r[2], 16)); + textprintf(debug_bmp, font, 10, 130, c1, "R3 = #%s", nib_to_hex_rev(cpu.reg_r[3], 16)); + textprintf(debug_bmp, font, 10, 140, c1, "R4 = #%s", nib_to_hex_rev(cpu.reg_r[4], 16)); + + tmp = nib_to_hex(bus_fast_peek(NULL, cpu.d[0], NULL), 16); + textprintf(debug_bmp, font, 10, 160, c1, "D0 = #%05X (%s)", (int) cpu.d[0], tmp); + tmp = nib_to_hex(bus_fast_peek(NULL, cpu.d[1], NULL), 16); + textprintf(debug_bmp, font, 10, 170, c1, "D1 = #%05X (%s)", (int) cpu.d[1], tmp); + + textout(debug_bmp, font, "RSTK", 10, 190, c1); + for (i = 0; i < 8; i++) { + textprintf(debug_bmp, font, 50, 190+i*10, c1, "#%05X", (int) cpu.rstk[(cpu.rstk_ptr+i)&7]); + } + + textprintf(debug_bmp, font, 200, 50, c1, "P = #%X", (int) cpu.p); + + textprintf(debug_bmp, font, 200, 70, c1, "OUT = #%s", nib_to_hex_rev(cpu.out, 3)); + textprintf(debug_bmp, font, 200, 80, c1, "IN = #%s", nib_to_hex_rev(cpu.in, 4)); + + textprintf(debug_bmp, font, 200, 100, c1, "ST = #%s", nib_to_hex_rev(cpu.st, 4)); + + textout(debug_bmp, font, "MP", 200, 120, (cpu.hst & 0x8) ? c1 : c2); + textout(debug_bmp, font, "SR", 224, 120, (cpu.hst & 0x4) ? c1 : c2); + textout(debug_bmp, font, "SB", 248, 120, (cpu.hst & 0x2) ? c1 : c2); + textout(debug_bmp, font, "XM", 272, 120, (cpu.hst & 0x1) ? c1 : c2); + + textout(debug_bmp, font, "CARRY", 200, 130, cpu.carry ? c1 : c2); + textout(debug_bmp, font, cpu.dec ? "DEC" : "HEX", 200, 140, c1); + + textout(debug_bmp, font, "SHUTDOWN", 10, 280, cpu.shutdown ? c1 : c2); + textout(debug_bmp, font, "KEYSCAN", 90, 280, cpu.keyscan ? c1 : c2); + textout(debug_bmp, font, "INTE", 170, 280, cpu.inte ? c1 : c2); + textout(debug_bmp, font, "KEYINTP", 250, 280, cpu.keyintp ? c1 : c2); + + textout(debug_bmp, font, "HDWREG RAM CE1 CE2 NCE3", 58, 310, c1); + textout(debug_bmp, font, "Mask", 10, 320, c1); + textout(debug_bmp, font, "-----", 58, 320, c1); + if (bus_info.ram_sz_cfg) { + textprintf(debug_bmp, font, 114, 320, c1, "%05X", bus_info.ram_size); + } else { + textout(debug_bmp, font, "-----", 114, 320, c1); + } + if (bus_info.ce1_sz_cfg) { + textprintf(debug_bmp, font, 170, 320, c1, "%05X", bus_info.ce1_size); + } else { + textout(debug_bmp, font, "-----", 170, 320, c1); + } + if (bus_info.ce2_sz_cfg) { + textprintf(debug_bmp, font, 226, 320, c1, "%05X", bus_info.ce2_size); + } else { + textout(debug_bmp, font, "-----", 226, 320, c1); + } + if (bus_info.nce3_sz_cfg) { + textprintf(debug_bmp, font, 282, 320, c1, "%05X", bus_info.nce3_size); + } else { + textout(debug_bmp, font, "-----", 282, 320, c1); + } + textout(debug_bmp, font, "Base", 10, 330, c1); + if (bus_info.hdw_cfg) { + textprintf(debug_bmp, font, 58, 330, c1, "%05X", bus_info.hdw_base); + } else { + textout(debug_bmp, font, "-----", 58, 330, c1); + } + if (bus_info.ram_cfg) { + textprintf(debug_bmp, font, 114, 330, c1, "%05X", bus_info.ram_base); + } else { + textout(debug_bmp, font, "-----", 114, 330, c1); + } + if (bus_info.ce1_cfg) { + textprintf(debug_bmp, font, 170, 330, c1, "%05X", bus_info.ce1_base); + } else { + textout(debug_bmp, font, "-----", 170, 330, c1); + } + if (bus_info.ce2_cfg) { + textprintf(debug_bmp, font, 226, 330, c1, "%05X", bus_info.ce2_base); + } else { + textout(debug_bmp, font, "-----", 226, 330, c1); + } + if (bus_info.nce3_cfg) { + textprintf(debug_bmp, font, 282, 330, c1, "%05X", bus_info.nce3_base); + } else { + textout(debug_bmp, font, "-----", 282, 330, c1); + } + + textprintf(debug_bmp, font, 10, 380, c1, "Instruction count = %u", cpu.inst_cnt); + textprintf(debug_bmp, font, 10, 390, c1, "Cycle count = %u", cpu.cycles); + + unscare_mouse(); + release_bitmap(debug_bmp); +} + +void pdebug_draw_true_speed(dword speed) +{ + if (!debug_bmp) { + return; + } + text_mode(color[C_PANEL_BACK]); + acquire_bitmap(debug_bmp); + scare_mouse(); + textprintf(debug_bmp, font, 10, 410, color[C_PANEL_TEXT], "True speed: %10u Hz", speed); + unscare_mouse(); + release_bitmap(debug_bmp); +} + +void pdebug_state_changed(void) +{ + update_buttons(); + draw_cpu(); +} + +void pdebug_show(BITMAP *bmp) +{ + update_buttons(); + + debug_bmp = bmp; + + clear_to_color(debug_bmp, color[C_PANEL_BACK]); + button_draw_all(debug_bmp, debug_buttons); + draw_cpu(); +} + +void pdebug_hide(void) +{ + debug_bmp = NULL; +} + +void pdebug_down(int mx, int my, int mb) +{ + button_mouse_down(debug_bmp, debug_buttons, mx, my, mb); +} + +void pdebug_up(int mx, int my, int mb) +{ + button_mouse_up(debug_bmp, debug_buttons, mx, my, mb); +} diff --git a/src/pdebug.h b/src/pdebug.h new file mode 100644 index 0000000..53e5fb3 --- /dev/null +++ b/src/pdebug.h @@ -0,0 +1,42 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PDEBUG_H +#define __PDEBUG_H + +#include +#include "types.h" + +void pdebug_state_changed(void); +void pdebug_draw_true_speed(dword speed); + +void pdebug_show(BITMAP *bmp); +void pdebug_hide(void); +void pdebug_down(int mx, int my, int mb); +void pdebug_up(int mx, int my, int mb); + +#endif diff --git a/src/pfiles.c b/src/pfiles.c new file mode 100644 index 0000000..6af4107 --- /dev/null +++ b/src/pfiles.c @@ -0,0 +1,134 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "color.h" +#include "gui.h" +#include "rpl.h" +#include "pfiles.h" + +static void load_up(boolean action); + +static Button files_buttons[] = { + { 0, 0, 79, 20, BUTTON_B1RELEASE, "Load", NULL, load_up }, + { 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + +static BITMAP *files_bmp; + +static void load_file(char *name) +{ + PACKFILE *f; + byte *buf; + byte *obj; + int i, j; + int fsize; + address size; + + fsize = file_size(name); + if (fsize < 11) // "PHPH48-X" + prologue (8 + 2.5) + return; + + buf = malloc(fsize); + if (!buf) + return; + + f = pack_fopen(name, "r"); + if (!f) { + free(buf); + return; + } + + if (pack_fread(buf, fsize, f) != fsize) { + free(buf); + pack_fclose(f); + return; + } + pack_fclose(f); + + if (memcmp(buf, "HPHP48-", 7)) { + free(buf); + return; + } + + obj = malloc((fsize - 8) * 2); + if (!obj) { + free(buf); + return; + } + + for (i = 8, j = 0; i < fsize; i++) { + obj[j++] = buf[i] & 0x0F; + obj[j++] = (buf[i] >> 4) & 0x0F; + } + free(buf); + + size = rpl_object_size(obj); + if (size > (fsize - 8) * 2) { + free(obj); + return; + } + rpl_push_object(obj, size); + free(obj); +} + +#define PATH_SIZE 1024 + +static void load_up(boolean action) +{ + static char path[PATH_SIZE] = ""; + + if (action) { + if (file_select_ex("Load Object", path, NULL, PATH_SIZE, 0, 0)) { + load_file(path); + } + } +} + +void pfiles_show(BITMAP *bmp) +{ + files_bmp = bmp; + + clear_to_color(files_bmp, color[C_PANEL_BACK]); + button_draw_all(files_bmp, files_buttons); +} + +void pfiles_hide(void) +{ + files_bmp = NULL; +} + +void pfiles_down(int mx, int my, int mb) +{ + button_mouse_down(files_bmp, files_buttons, mx, my, mb); +} + +void pfiles_up(int mx, int my, int mb) +{ + button_mouse_up(files_bmp, files_buttons, mx, my, mb); +} diff --git a/src/pfiles.h b/src/pfiles.h new file mode 100644 index 0000000..e579426 --- /dev/null +++ b/src/pfiles.h @@ -0,0 +1,38 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PFILES_H +#define __PFILES_H + +#include + +void pfiles_show(BITMAP *bmp); +void pfiles_hide(void); +void pfiles_down(int mx, int my, int mb); +void pfiles_up(int mx, int my, int mb); + +#endif diff --git a/src/pmenu.c b/src/pmenu.c new file mode 100644 index 0000000..3dd0b03 --- /dev/null +++ b/src/pmenu.c @@ -0,0 +1,124 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "emulator.h" +#include "color.h" +#include "gui.h" +#include "pmenu.h" + +static void exit_up(boolean action); +static void debug_up(boolean action); +static void files_up(boolean action); +static void about_up(boolean action); + +static Button menu_buttons[] = { + { 0, 0, 79, 20, BUTTON_B1RELEASE, "Exit", NULL, exit_up }, + { 80, 0, 79, 20, BUTTON_B1RELEASE, "Debug", NULL, debug_up }, + { 160, 0, 79, 20, BUTTON_B1RELEASE, "Files", NULL, files_up }, + { 240, 0, 79, 20, BUTTON_DISABLED | BUTTON_B1RELEASE, "About", NULL, about_up }, + { 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + +enum MenuButtons { + MENU_EXIT, + MENU_DEBUG, + MENU_FILES, + MENU_ABOUT, + MENU_COUNT +}; + +static BITMAP *menu_bmp; + +static void exit_up(boolean action) +{ + if (action) { + please_exit = TRUE; + } +} + +static void debug_up(boolean action) +{ + if (action) { + menu_buttons[MENU_DEBUG].flags |= BUTTON_DISABLED; + menu_buttons[MENU_FILES].flags &= ~BUTTON_DISABLED; + menu_buttons[MENU_ABOUT].flags &= ~BUTTON_DISABLED; + button_draw_all(menu_bmp, menu_buttons); + gui_hide_panel(PANEL_FILES); + gui_hide_panel(PANEL_ABOUT); + gui_show_panel(PANEL_DEBUG); + } +} + +static void files_up(boolean action) +{ + if (action) { + menu_buttons[MENU_DEBUG].flags &= ~BUTTON_DISABLED; + menu_buttons[MENU_FILES].flags |= BUTTON_DISABLED; + menu_buttons[MENU_ABOUT].flags &= ~BUTTON_DISABLED; + button_draw_all(menu_bmp, menu_buttons); + gui_hide_panel(PANEL_DEBUG); + gui_hide_panel(PANEL_ABOUT); + gui_show_panel(PANEL_FILES); + } +} + +static void about_up(boolean action) +{ + if (action) { + menu_buttons[MENU_DEBUG].flags &= ~BUTTON_DISABLED; + menu_buttons[MENU_FILES].flags &= ~BUTTON_DISABLED; + menu_buttons[MENU_ABOUT].flags |= BUTTON_DISABLED; + button_draw_all(menu_bmp, menu_buttons); + gui_hide_panel(PANEL_DEBUG); + gui_hide_panel(PANEL_FILES); + gui_show_panel(PANEL_ABOUT); + } +} + +void pmenu_show(BITMAP *bmp) +{ + menu_bmp = bmp; + + clear_to_color(menu_bmp, color[C_PANEL_BACK]); + button_draw_all(menu_bmp, menu_buttons); +} + +void pmenu_hide(void) +{ + menu_bmp = NULL; +} + +void pmenu_down(int mx, int my, int mb) +{ + button_mouse_down(menu_bmp, menu_buttons, mx, my, mb); +} + +void pmenu_up(int mx, int my, int mb) +{ + button_mouse_up(menu_bmp, menu_buttons, mx, my, mb); +} diff --git a/src/pmenu.h b/src/pmenu.h new file mode 100644 index 0000000..c6a17b5 --- /dev/null +++ b/src/pmenu.h @@ -0,0 +1,38 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PMENU_H +#define __PMENU_H + +#include + +void pmenu_show(BITMAP *bmp); +void pmenu_hide(void); +void pmenu_down(int mx, int my, int mb); +void pmenu_up(int mx, int my, int mb); + +#endif diff --git a/src/ports.c b/src/ports.c new file mode 100644 index 0000000..560e6b1 --- /dev/null +++ b/src/ports.c @@ -0,0 +1,115 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "bus.h" +#include "ports.h" + +static byte current_bank; +static byte *port2; +static address port2mask; + +void ports_init(void) +{ + // ce1 = bank switcher + bus_info.ce1_data = NULL; + bus_info.ce1_mask = 0x0007F; + bus_info.ce1_r_o = TRUE; + bus_info.ce1_bs = TRUE; + +#if 1 + // ce2 = port1 (unplugged) + bus_info.ce2_data = NULL; + bus_info.ce2_mask = 0x00000; + bus_info.ce2_r_o = TRUE; +#else +#define PORT1_SIZE (64*1024) // Nibbles + // ce2 = port1 (plugged) + bus_info.ce2_data = malloc(PORT1_SIZE); + bus_info.ce2_mask = PORT1_SIZE-1; + bus_info.ce2_r_o = FALSE; +#endif + +#if 1 + // nce3 = port2 (unplugged) + port2 = NULL; + port2mask = 0x00000; + bus_info.nce3_data = port2; + bus_info.nce3_mask = port2mask & 0x3FFFF; + bus_info.nce3_r_o = TRUE; +#else +#define PORT2_SIZE (512*1024) // Nibbles + // nce3 = port2 (plugged) + port2 = malloc(PORT2_SIZE); + port2mask = PORT2_SIZE-1; + bus_info.nce3_data = port2; + bus_info.nce3_mask = port2mask & 0x3FFFF; + bus_info.nce3_r_o = FALSE; +#endif + + bus_info.ben = FALSE; + current_bank = 0; +} + +void ports_exit(void) +{ +} + +void ports_switch_bank(address adr) +{ + boolean need_remap = FALSE; + + if (current_bank != (((byte) adr >> 1) & 0x1F)) { + current_bank = ((byte) adr >> 1) & 0x1F; + if (port2) { + bus_info.nce3_data = port2 + ((current_bank << 18) & port2mask); + if (bus_info.nce3_cfg) { + need_remap = TRUE; + } + } + } + if (!bus_info.ben != !(adr & 0x40)) { + bus_info.ben = (adr & 0x40) ? TRUE : FALSE; + if (bus_info.nce3_cfg) { + need_remap = TRUE; + } + } + if (need_remap) { + bus_remap(); + } +} + +byte ports_card_detect(void) +{ + byte x = 0; + if (bus_info.nce3_data) x |= 0x1; + if (bus_info.ce2_data) x |= 0x2; + if (!bus_info.nce3_r_o) x |= 0x4; + if (!bus_info.ce2_r_o) x |= 0x8; + return x; +} diff --git a/src/ports.h b/src/ports.h new file mode 100644 index 0000000..0693081 --- /dev/null +++ b/src/ports.h @@ -0,0 +1,38 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __PORTS_H +#define __PORTS_H + +#include "types.h" + +void ports_init(void); +void ports_exit(void); +void ports_switch_bank(address adr); +byte ports_card_detect(void); + +#endif diff --git a/src/ram.c b/src/ram.c new file mode 100644 index 0000000..9e56998 --- /dev/null +++ b/src/ram.c @@ -0,0 +1,54 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "types.h" +#include "bus.h" +#include "ram.h" + +static address ram_size = 256*1024; // in nibbles, not bytes! + +void ram_init(void) +{ + byte *buf; + + buf = malloc(ram_size); + if (!buf) { + exit(0x20); + } + memset(buf, 0, ram_size); + bus_info.ram_data = buf; + bus_info.ram_mask = ram_size-1; +} + +void ram_exit(void) +{ + free(bus_info.ram_data); + bus_info.ram_data = NULL; + bus_info.ram_mask = 0x00000; +} diff --git a/src/ram.h b/src/ram.h new file mode 100644 index 0000000..2b1e270 --- /dev/null +++ b/src/ram.h @@ -0,0 +1,34 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __RAM_H +#define __RAM_H + +void ram_init(void); +void ram_exit(void); + +#endif diff --git a/src/rom.c b/src/rom.c new file mode 100644 index 0000000..e863abd --- /dev/null +++ b/src/rom.c @@ -0,0 +1,84 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "bus.h" +#include "rom.h" + +void rom_init(void) +{ + int size; + char *name = "hpemu.rom"; + byte *buf, *ptr1, *ptr2; + PACKFILE *f; + + size = file_size(name); + if (!size) { + exit(0x10); + } + if (size != 256*1024 && size != 512*1024 && size != 1024*1024) { + exit (0x11); + } + buf = malloc(size); + if (!buf) { + exit(0x12); + } + f = pack_fopen(name, "r"); + if (!f) { + exit(0x13); + } + if (pack_fread(buf, size, f) != size) { + exit(0x14); + } + pack_fclose(f); + if (buf[0] & 0xF0 || buf[1] & 0xF0) { + if (size == 1024*1024) { + exit(0x15); + } + buf = realloc(buf, size*2); + if (!buf) { + exit(0x16); + } + ptr1 = buf+size-1; + size *= 2; + ptr2 = buf+size-1; + do { + *(ptr2--) = (*ptr1 >> 4) & 0x0F; + *(ptr2--) = *(ptr1--) & 0x0F; + } while (ptr1 != ptr2); + } + bus_info.rom_data = buf; + bus_info.rom_mask = size - 1; +} + +void rom_exit(void) +{ + free(bus_info.rom_data); + bus_info.rom_data = NULL; + bus_info.rom_mask = 0x00000; +} diff --git a/src/rom.h b/src/rom.h new file mode 100644 index 0000000..dd0125b --- /dev/null +++ b/src/rom.h @@ -0,0 +1,34 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __ROM_H +#define __ROM_H + +void rom_init(void); +void rom_exit(void); + +#endif diff --git a/src/rpl.c b/src/rpl.c new file mode 100644 index 0000000..5c22532 --- /dev/null +++ b/src/rpl.c @@ -0,0 +1,199 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "types.h" +#include "bus.h" +#include "opinline.h" +#include "rpl.h" + +#define TEMPOB 0x806E9 +#define TEMPTOP 0x806EE +#define RSKTOP 0x806F3 +#define DSKTOP 0x806F8 +#define AVMEM 0x807ED +#define INTRPPTR 0x8072F + +int rpl_object_size(byte *obj) +{ + int size; + int prologue; + int n; + + prologue = nib_to_unsigned(obj, 5); + + switch (prologue) { + + case 0x0312B: size = 0; break; // SEMI + case 0x029BF: size = 7; break; // Character + case 0x02911: size = 10; break; // System binary integer + case 0x02E92: size = 11; break; // XLIB name + case 0x02BAA: size = 15; break; // Extended pointer + case 0x02933: size = 21; break; // Real number + case 0x02955: size = 26; break; // Long real + case 0x02977: size = 37; break; // Complex number + case 0x0299D: size = 47; break; // Long complex + + case 0x02A2C: // String + case 0x02A4E: // User binary integer + case 0x02B1E: // Graphic object + case 0x02DCC: // Code object + case 0x02B88: // Library data + case 0x029E8: // Array + case 0x02B40: // Library + case 0x02B62: // Backup + case 0x02A0A: // Linked array + size = 5 + nib_to_unsigned(obj+5, 5); + break; + + case 0x02E48: // Global name + case 0x02E6D: // Local name + case 0x02AFC: // Tagged object + case 0x02ADA: // Unit object + size = 7 + 2 * nib_to_unsigned(obj+5, 2); + if (prologue == 0x02AFC) { // Tagged object + size += rpl_object_size(obj + size); + } + break; + + case 0x02A74: // List + case 0x02D9D: // RPL program + case 0x02AB8: // Algebraic expression + size = 5; + n = 5; + do { + size += n; + obj += n; + n = rpl_object_size(obj); + } while (n > 0); + break; + + case 0x02A96: // Directory + n = nib_to_unsigned(obj+8, 5); + if (n == 0) { + size = 13; + } else { + size = 8 + n; + size += 4 + 2 * nib_to_unsigned(obj + size, 2); + size += rpl_object_size(obj + size); + } + break; + + default: + size = 5; + } + return size; +} + +static address read_address(address adr) +{ + byte buf[5]; + word ocrc; + + ocrc = crc; + bus_read(buf, adr, 5); + crc = ocrc; + + return nib_to_unsigned(buf, 5); +} + +static void write_address(address adr, address val) +{ + byte buf[5]; + + unsigned_to_nib(buf, val, 5); + bus_write(buf, adr, 5); +} + +static int moveup(address src, address dst, address cnt) +{ + byte *buf = malloc(cnt * sizeof(byte)); + word ocrc; + + if (!buf) + return -1; + + ocrc = crc; + bus_read(buf, src, cnt); + bus_write(buf, dst, cnt); + crc = ocrc; + + free(buf); + return 0; +} + +address rpl_make_temp(address size) +{ + address temptop, rsktop, dsktop; + + size += 6; + + temptop = read_address(TEMPTOP); + rsktop = read_address(RSKTOP); + dsktop = read_address(DSKTOP); + + if (rsktop + size > dsktop) + return 0; + + if (moveup(temptop, temptop + size, rsktop - temptop)) + return 0; + + write_address(TEMPTOP, temptop + size); + write_address(RSKTOP, rsktop + size); + write_address(AVMEM, (dsktop - rsktop - size) / 5); + write_address(temptop + size - 5, size); + + return temptop + 1; +} + +void rpl_push(address adr) +{ + address dsktop, avmem; + + avmem = read_address(AVMEM); + if (!avmem) + return; + write_address(AVMEM, avmem-1); + + dsktop = read_address(DSKTOP); + dsktop -= 5; + write_address(dsktop, adr); + write_address(DSKTOP, dsktop); +} + +int rpl_push_object(byte *obj, address size) +{ + address adr; + + adr = rpl_make_temp(size); + if (!adr) + return -1; + + bus_write(obj, adr, size); + rpl_push(adr); + return 0; +} diff --git a/src/rpl.h b/src/rpl.h new file mode 100644 index 0000000..157bef0 --- /dev/null +++ b/src/rpl.h @@ -0,0 +1,38 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __RPL_H +#define __RPL_H + +#include "types.h" + +int rpl_object_size(byte *obj); +address rpl_make_temp(address size); +void rpl_push(address adr); +int rpl_push_object(byte *obj, address size); + +#endif diff --git a/src/timers.c b/src/timers.c new file mode 100644 index 0000000..3428dd7 --- /dev/null +++ b/src/timers.c @@ -0,0 +1,95 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "types.h" +#include "cpu.h" +#include "timers.h" + +#define TIMER1_EXTRA 0x1 +#define TIMER1_INT 0x2 +#define TIMER1_WAKE 0x4 +#define TIMER1_SRQ 0x8 + +#define TIMER_RUN 0x1 +#define TIMER2_INT 0x2 +#define TIMER2_WAKE 0x4 +#define TIMER2_SRQ 0x8 + +byte timer1_control; +byte timer2_control; +byte timer1_value; +dword timer2_value; + +void timer1_update(void) +{ + if (timer2_control & TIMER_RUN) { + timer1_value--; + timer1_value &= 0xF; + + if (timer1_value & 0x8) { + if (timer1_control & TIMER1_WAKE) { + timer1_control |= TIMER1_SRQ; + if (cpu.shutdown) { + cpu.shutdown = FALSE; + timer1_control &= ~TIMER1_WAKE; + } + } + if (timer1_control & TIMER1_INT) { + timer1_control |= TIMER1_SRQ; + if (!cpu.shutdown) { + cpu_interrupt(); + } + } + } else { + timer1_control &= ~TIMER1_SRQ; + } + } +} + +void timer2_update(void) +{ + if (timer2_control & TIMER_RUN) { + timer2_value--; + if (timer2_value & 0x80000000) { + if (timer2_control & TIMER2_WAKE) { + timer2_control |= TIMER2_SRQ; + if (cpu.shutdown) { + cpu.shutdown = 0; + timer2_control &= ~TIMER2_WAKE; + } + } + if (timer2_control & TIMER2_INT) { + timer2_control |= TIMER2_SRQ; + if (!cpu.shutdown) { + cpu_interrupt(); + } + } + } else { + timer2_control &= ~TIMER2_SRQ; + } + } +} diff --git a/src/timers.h b/src/timers.h new file mode 100644 index 0000000..8a10351 --- /dev/null +++ b/src/timers.h @@ -0,0 +1,41 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __TIMERS_H +#define __TIMERS_H + +#include "types.h" + +extern byte timer1_control; +extern byte timer2_control; +extern byte timer1_value; +extern dword timer2_value; + +void timer1_update(void); +void timer2_update(void); + +#endif diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..a9fdc0b --- /dev/null +++ b/src/types.h @@ -0,0 +1,42 @@ +/* + * / + * /__ ___ ___ ____ + * / / / / /__/ / / / / / + * / / /__/ /__ / / /__/ + * / + * / version 0.9.0 + * + * Copyright 2002 Daniel Nilsson + * + * This file is part of hpemu. + * + * Hpemu is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Hpemu is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with hpemu; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __TYPES_H +#define __TYPES_H + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned int dword; +typedef signed int address; +typedef char boolean; + +#ifndef TRUE +#define TRUE -1 +#define FALSE 0 +#endif + +#endif