commit b46cb7b8ab96c8321f12767a92eb703447c6a9e4 Author: John D. Corrado Date: Fri Jul 31 13:28:40 2015 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70d19ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +aclocal.m4 +config.h +config.h.in +config.log +config.status +configure +depcomp +INSTALL +install-sh +Makefile +Makefile.in +missing +stamp-h1 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..9733d9d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +John D. Corrado +Verhille Arnaud + diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d60c31a --- /dev/null +++ b/COPYING @@ -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/ChangeLog b/ChangeLog new file mode 100644 index 0000000..75f1bc6 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,36 @@ +Sat Mar 03 12:21:45 EST 2012 jdcorrado + + v1.0.0 + Optimized options code and added better error handling. + Load option now has option to simulate keyboard input for ASCII format. + Added show about option. + Added command line parameters. + +Mon Aug 16 16:06:48 EST 2010 jdcorrado + + v0.0.5 + Added mutexes to protect access to screen and to lock/unlock blinking cursor. + +Sat Aug 14 22:49:55 EST 2010 jdcorrado + + v0.0.4 + Fixed input and output of valid characters. + Added optional cursor (block or @) and blinking. + +Tue May 15 19:40:03 EST 2007 jdcorrado + + v0.0.3 + Fixed problems with certain addressing modes where zero page would not wrap around. + +Tue Feb 27 20:49:21 EST 2007 jdcorrado + + v0.0.2 + Fixed problems from signed types. + Moved updateScreen call. + Set BRK flag instead of IRQ flag in BRK function (Thanks Kallikak). + Other minor code changes. + +Fri Sep 29 23:01:37 EST 2006 jdcorrado + + v0.0.1 + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..894919b --- /dev/null +++ b/Makefile.am @@ -0,0 +1,13 @@ +DOC_FILES = \ + AUTHORS \ + ChangeLog \ + NEWS \ + README + +EXTRA_DIST = $(DOC_FILES) + +docdir = $(prefix)/share/doc/@PACKAGE@ +doc_DATA = $(DOC_FILES) + +SUBDIRS = src +DIST_SUBDIRS = src diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..bd8163c --- /dev/null +++ b/NEWS @@ -0,0 +1,18 @@ +1.0.0 (2012-03-03): + First stable release. + +0.0.5 (2010-08-16): + Fifth beta release. + +0.0.4 (2010-08-14): + Fourth beta release. + +0.0.3 (2007-05-16): + Third beta release. + +0.0.2 (2007-02-27): + Second beta release. + +0.0.1 (2006-09-29): + First beta release. + diff --git a/README b/README new file mode 100644 index 0000000..4d5e264 --- /dev/null +++ b/README @@ -0,0 +1,34 @@ +Pom1 is an Apple 1 emulator being ported to C from the original Java +version. It uses the Simple DirectMedia Layer library and works on most +platforms. + +== Options == + +Pom1 has many options to configure and utilize the emulator. They are +accessed by Ctrl+. Some options also have corresponding command +line parameters. + +Option Letter Parameter Description +-------------------------------------------------------------------------------------------- +Load Memory L Load memory from a binary or ascii file. +Save Memory S Save memory to a binary or ascii file. +Quit Q Quit the emulator. +Reset R Soft reset the emulator. +Hard Reset H Hard reset the emulator. +Pixel Size P -pixelsize Set the pixel size (1 or 2). +Scanlines N -scanlines Turn scanlines on or off (pixel size 2 only). +Terminal Speed T -terminalspeed Set the terminal speed (Range: 1 - 120). +RAM 8K E -ram8k Use only 8KB of RAM or entire 64KB of RAM. +Write In ROM W -writeinrom Allow writing data in ROM or not. +IRQ/BRK Vector V Set address of interrupt vector. +Fullscreen F -fullscreen Switch to fullscreen or window. +Blink Cursor B -blinkcursor Set the cursor to blink or not. +Cursor Block C -blockcursor Set the cursor to block or @. +Show About A Show version and copyright information. + +== Other information == + + * You can find more information about the project at the Pom1 website: + + http://pom1.sourceforge.net/ + diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..e747a52 --- /dev/null +++ b/configure.ac @@ -0,0 +1,40 @@ +AC_PREREQ([2.68]) +AC_INIT([Pom1 Apple 1 Emulator], [1.0.0], [jdcorrado@gmail.com], [pom1]) +AC_CONFIG_SRCDIR([src/main.c]) +AC_CONFIG_HEADERS([config.h]) + +PACKAGE_SHORTDESC="Apple 1 emulator" +PACKAGE_COPYRIGHT="Copyright (C) 2000-2012" +PACKAGE_LICENSE="GNU General Public License, version 2" +PACKAGE_MAINTAINER="John D. Corrado" +PACKAGE_URL="http://pom1.sourceforge.net/" + +AC_PROG_CC +AC_PROG_INSTALL + +AC_CHECK_HEADERS([stdlib.h string.h]) + +AC_FUNC_MALLOC +AC_CHECK_FUNCS([atexit memset mkdir strcasecmp strdup strrchr]) + +AM_PATH_SDL([1.1.3]) + +CFLAGS="$CFLAGS $SDL_CFLAGS" +LDFLAGS="$LDFLAGS $SDL_LIBS" + +AM_INIT_AUTOMAKE([1.8.0]) + +AC_SUBST([PACKAGE_SHORTDESC]) +AC_SUBST([PACKAGE_COPYRIGHT]) +AC_SUBST([PACKAGE_LICENSE]) +AC_SUBST([PACKAGE_MAINTAINER]) +AC_SUBST([PACKAGE_URL]) + +AC_CONFIG_FILES([ +Makefile +src/Makefile +src/pom1.desktop +src/roms/Makefile +src/pom1 +]) +AC_OUTPUT diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..8890834 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +pom1 +pom1-1.0.0 +pom1.desktop +.deps +*.o diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..0d0a782 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,27 @@ +EXEEXT=-@PACKAGE_VERSION@ +bin_PROGRAMS = pom1 +bin_SCRIPTS = pom1 + +SOURCE_FILES = \ + configuration.c configuration.h \ + keyboard.c keyboard.h \ + m6502.c m6502.h \ + main.c \ + memory.c memory.h \ + options.c options.h \ + pia6820.c pia6820.h \ + screen.c screen.h + +pom1_SOURCES = $(SOURCE_FILES) +pom1_LDADD = @LDFLAGS@ + +EXTRA_DIST = pom1.png + +appdir = $(prefix)/share/applications +app_DATA = pom1.desktop + +iconsdir = $(prefix)/share/icons +icons_DATA = pom1.png + +SUBDIRS = roms +DIST_SUBDIRS = roms diff --git a/src/configuration.c b/src/configuration.c new file mode 100644 index 0000000..374b9fc --- /dev/null +++ b/src/configuration.c @@ -0,0 +1,186 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include +#include +#include +#include "screen.h" +#include "memory.h" + +static char *_romdir; + +void freeRomDirectory(void) +{ + free(_romdir); +} + +void setRomDirectory(const char *romdir) +{ + if (_romdir) + free(_romdir); + + _romdir = strdup(romdir); +} + +const char *getRomDirectory(void) +{ + return _romdir; +} + +void loadConfiguration(void) +{ + FILE *fp; + char *configdir, *filename, buffer[256], *value; + +#if !defined(_WIN32) + char *homedir = getenv("HOME"); + + if (homedir) + { + configdir = (char *)malloc(strlen(homedir) + 8); + sprintf(configdir, "%s/.pom1/", homedir); + } + else +#endif + configdir = strdup(""); + + filename = (char *)malloc(strlen(configdir) + 9); + sprintf(filename, "%spom1.cfg", configdir); + + free(configdir); + + fp = fopen(filename, "r"); + + free(filename); + + if (fp) + { + while (!feof(fp)) + { + if (!fgets(buffer, 256, fp)) + continue; + + if (buffer[0] == '/' || buffer[0] == '\n') + continue; + + *(strrchr(buffer, '\n')) = '\0'; + value = strrchr(buffer, '=') + 1; + *(strrchr(buffer, '=')) = '\0'; + + if (!strcmp(buffer, "pixelSize")) + setPixelSize(value[0] & 0x03); + else if (!strcmp(buffer, "scanlines")) + setScanlines(value[0] & 0x01); + else if (!strcmp(buffer, "terminalSpeed")) + setTerminalSpeed(atoi(value)); + else if (!strcmp(buffer, "ram8k")) + setRam8k(value[0] & 0x01); + else if (!strcmp(buffer, "writeInRom")) + setWriteInRom(value[0] & 0x01); + else if (!strcmp(buffer, "fullscreen")) + setFullscreen(value[0] & 0x01); + else if (!strcmp(buffer, "blinkCursor")) + setBlinkCursor(value[0] & 0x01); + else if (!strcmp(buffer, "blockCursor")) + setBlockCursor(value[0] & 0x01); + } + + fclose(fp); + } +} + +void saveConfiguration(void) +{ + FILE *fp; + char *configdir, *filename, buffer[256]; + +#if !defined(_WIN32) + char *homedir = getenv("HOME"); + + if (homedir) + { + configdir = (char *)malloc(strlen(homedir) + 8); + sprintf(configdir, "%s/.pom1/", homedir); + mkdir(configdir, 0755); + } + else +#endif + configdir = strdup(""); + + filename = (char *)malloc(strlen(configdir) + 9); + sprintf(filename, "%spom1.cfg", configdir); + + free(configdir); + + fp = fopen(filename, "w"); + + free(filename); + + if (fp) + { + fputs("// Pom1 Configuration\n", fp); + + strcpy(buffer, "pixelSize="); + buffer[10] = getPixelSize() | 0x30; + buffer[11] = '\n'; + buffer[12] = '\0'; + fputs(buffer, fp); + + strcpy(buffer, "scanlines="); + buffer[10] = getScanlines() | 0x30; + buffer[11] = '\n'; + buffer[12] = '\0'; + fputs(buffer, fp); + + strcpy(buffer, "terminalSpeed="); + sprintf(&buffer[14], "%d\n", getTerminalSpeed()); + fputs(buffer, fp); + + strcpy(buffer, "ram8k="); + buffer[6] = getRam8k() | 0x30; + buffer[7] = '\n'; + buffer[8] = '\0'; + fputs(buffer, fp); + + strcpy(buffer, "writeInRom="); + buffer[11] = getWriteInRom() | 0x30; + buffer[12] = '\n'; + buffer[13] = '\0'; + fputs(buffer, fp); + + strcpy(buffer, "fullscreen="); + buffer[11] = getFullscreen() | 0x30; + buffer[12] = '\n'; + buffer[13] = '\0'; + fputs(buffer, fp); + + strcpy(buffer, "blinkCursor="); + buffer[12] = getBlinkCursor() | 0x30; + buffer[13] = '\n'; + buffer[14] = '\0'; + fputs(buffer, fp); + + strcpy(buffer, "blockCursor="); + buffer[12] = getBlockCursor() | 0x30; + buffer[13] = '\n'; + buffer[14] = '\0'; + fputs(buffer, fp); + + fclose(fp); + } +} diff --git a/src/configuration.h b/src/configuration.h new file mode 100644 index 0000000..adc6e96 --- /dev/null +++ b/src/configuration.h @@ -0,0 +1,28 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __CONFIGURATION_H__ +#define __CONFIGURATION_H__ + +void freeRomDirectory(void); +void setRomDirectory(const char *romdir); +const char *getRomDirectory(void); +void loadConfiguration(void); +void saveConfiguration(void); + +#endif diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 0000000..33afff2 --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,213 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "SDL.h" +#include "m6502.h" +#include "memory.h" +#include "options.h" +#include "pia6820.h" +#include "screen.h" + +static FILE *_fp; +static const char *_filename; +static char buffer[1024]; +static int i, length; + +void setInputFile(FILE *fp, const char *filename) +{ + _fp = fp; + _filename = filename; + i = length = 0; +} + +void closeInputFile(void) +{ + if (_fp) + { + fclose(_fp); + _fp = NULL; + } +} + +int isInputFileOpen(void) +{ + return (_fp ? 1 : 0); +} + +const char *getInputFileName(void) +{ + return _filename; +} + +int handleInput(void) +{ + SDL_Event event; + unsigned char tmp; + + if (readKbdCr() == 0x27 && _fp) + { + if (i < length) + { + tmp = buffer[i++]; + + if (tmp >= 0x61 && tmp <= 0x7A) + tmp &= 0x5F; + else if (tmp == 0x0D) + i++; + else if (tmp == 0x0A) + tmp = 0x0D; + + if (tmp < 0x60) + { + writeKbd((unsigned char)(tmp | 0x80)); + writeKbdCr(0xA7); + } + } + else if (feof(_fp)) + { + closeInputFile(); + printf("stdout: Successfully loaded \"%s\"\n", _filename); + } + else + { + i = 0; + length = fread(buffer, 1, 1024, _fp); + } + } + + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + return 0; + + if (event.type == SDL_KEYDOWN && event.key.keysym.mod & KMOD_CTRL) + { + if (event.key.keysym.sym == SDLK_l) + { + loadMemory(); + return 1; + } + else if (event.key.keysym.sym == SDLK_s) + { + saveMemory(); + return 1; + } + else if (event.key.keysym.sym == SDLK_q) + return 0; + else if (event.key.keysym.sym == SDLK_r) + { + resetPia6820(); + resetM6502(); + return 1; + } + else if (event.key.keysym.sym == SDLK_h) + { + stopM6502(); + resetM6502(); + resetScreen(); + resetPia6820(); + resetMemory(); + startM6502(); + return 1; + } + else if (event.key.keysym.sym == SDLK_p) + { + changePixelSize(); + return 1; + } + else if (event.key.keysym.sym == SDLK_n) + { + if (getPixelSize() > 1) + { + setScanlines(!getScanlines()); + printf("stdout: scanlines=%d\n", getScanlines()); + redrawScreen(); + } + + return 1; + } + else if (event.key.keysym.sym == SDLK_t) + { + changeTerminalSpeed(); + return 1; + } + else if (event.key.keysym.sym == SDLK_e) + { + setRam8k(!getRam8k()); + printf("stdout: ram8k=%d\n", getRam8k()); + return 1; + } + else if (event.key.keysym.sym == SDLK_w) + { + setWriteInRom(!getWriteInRom()); + printf("stdout: writeInRom=%d\n", getWriteInRom()); + return 1; + } + else if (event.key.keysym.sym == SDLK_v) + { + setIrqBrkVector(); + return 1; + } + else if (event.key.keysym.sym == SDLK_f) + { + setFullscreen(!getFullscreen()); + printf("stdout: fullscreen=%d\n", getFullscreen()); + SDL_SetVideoMode(280 * getPixelSize(), 192 * getPixelSize(), 8, SDL_HWSURFACE | (getFullscreen() ? SDL_FULLSCREEN : 0)); + initScreen(); + SDL_ShowCursor(!getFullscreen()); + redrawScreen(); + return 1; + } + else if (event.key.keysym.sym == SDLK_b) + { + setBlinkCursor(!getBlinkCursor()); + printf("stdout: blinkCursor=%d\n", getBlinkCursor()); + redrawScreen(); + return 1; + } + else if (event.key.keysym.sym == SDLK_c) + { + setBlockCursor(!getBlockCursor()); + printf("stdout: blockCursor=%d\n", getBlockCursor()); + redrawScreen(); + return 1; + } + else if (event.key.keysym.sym == SDLK_a) + { + showAbout(); + return 1; + } + } + + if (readKbdCr() == 0x27 && !_fp && event.type == SDL_KEYDOWN && !(event.key.keysym.unicode & 0xFF80) && event.key.keysym.unicode) + { + tmp = event.key.keysym.unicode & 0x7F; + + if (tmp >= 0x61 && tmp <= 0x7A) + tmp &= 0x5F; + + if (tmp < 0x60) + { + writeKbd((unsigned char)(tmp | 0x80)); + writeKbdCr(0xA7); + } + } + } + + return 1; +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 0000000..8905af7 --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,28 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __KEYBOARD_H__ +#define __KEYBOARD_H__ + +void setInputFile(FILE *fd, const char *filename); +void closeInputFile(void); +int isInputFileOpen(void); +const char *getInputFileName(void); +int handleInput(void); + +#endif diff --git a/src/m6502.c b/src/m6502.c new file mode 100644 index 0000000..964dda2 --- /dev/null +++ b/src/m6502.c @@ -0,0 +1,1816 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "SDL.h" +#include "memory.h" + +#define N 0x80 +#define V 0x40 +#define B 0x10 +#define D 0x08 +#define I 0x04 +#define Z 0x02 +#define C 0x01 + +static unsigned char accumulator, xRegister, yRegister, statusRegister = 0x24, stackPointer; +static int IRQ = 0, NMI = 0; +static unsigned short programCounter; +static unsigned char btmp; +static unsigned short op, opH, opL, ptr, ptrH, ptrL, tmp; +static long lastTime; +static int cycles, cyclesBeforeSynchro, _synchroMillis; +static SDL_Thread *thread; +static int running; + +static unsigned short memReadAbsolute(unsigned short adr) +{ + return (memRead(adr) | memRead((unsigned short)(adr + 1)) << 8); +} + +static void synchronize(void) +{ + int realTimeMillis = SDL_GetTicks() - lastTime; + int sleepMillis = _synchroMillis - realTimeMillis; + + if (sleepMillis < 0) + sleepMillis = 5; + + SDL_Delay(sleepMillis); + + lastTime = SDL_GetTicks(); +} + +static void pushProgramCounter(void) +{ + memWrite((unsigned short)(stackPointer + 0x100), (unsigned char)(programCounter >> 8)); + stackPointer--; + memWrite((unsigned short)(stackPointer + 0x100), (unsigned char)programCounter); + stackPointer--; + cycles += 2; +} + +static void popProgramCounter(void) +{ + stackPointer++; + programCounter = memRead((unsigned short)(stackPointer + 0x100)); + stackPointer++; + programCounter += memRead((unsigned short)(stackPointer + 0x100)) << 8; + cycles += 2; +} + +static void handleIRQ(void) +{ + pushProgramCounter(); + memWrite((unsigned short)(0x100 + stackPointer), (unsigned char)(statusRegister & ~0x10)); + stackPointer--; + statusRegister |= I; + programCounter = memReadAbsolute(0xFFFE); + cycles += 8; +} + +static void handleNMI(void) +{ + pushProgramCounter(); + memWrite((unsigned short)(0x100 + stackPointer), (unsigned char)(statusRegister & ~0x10)); + stackPointer--; + statusRegister |= I; + NMI = 0; + programCounter = memReadAbsolute(0xFFFA); + cycles += 8; +} + +static void Imp(void) +{ + cycles++; +} + +static void Imm(void) +{ + op = programCounter++; +} + +static void Zero(void) +{ + op = memRead(programCounter++); + cycles++; +} + +static void ZeroX(void) +{ + op = memRead(programCounter++) + xRegister & 0xFF; + cycles++; +} + +static void ZeroY(void) +{ + op = memRead(programCounter++) + yRegister & 0xFF; + cycles++; +} + +static void Abs(void) +{ + op = memReadAbsolute(programCounter); + programCounter += 2; + cycles += 2; +} + +static void AbsX(void) +{ + opL = memRead(programCounter++) + xRegister; + opH = memRead(programCounter++) << 8; + cycles += 2; + + if (opL & 0x100) + cycles++; + + op = opH + opL; +} + +static void AbsY(void) +{ + opL = memRead(programCounter++) + yRegister; + opH = memRead(programCounter++) << 8; + cycles += 2; + + if (opL & 0x100) + cycles++; + + op = opH + opL; +} + +static void Ind(void) +{ + ptrL = memRead(programCounter++); + ptrH = memRead(programCounter++) << 8; + op = memRead((unsigned short)(ptrH + ptrL)); + ptrL = ptrL + 1 & 0xFF; + op += memRead((unsigned short)(ptrH + ptrL)) << 8; + cycles += 4; +} + +static void IndZeroX(void) +{ + ptr = memRead(programCounter++) + xRegister & 0xFF; + op = memRead(ptr); + op += memRead((unsigned short)(ptr + 1 & 0xFF)) << 8; + cycles += 3; +} + +static void IndZeroY(void) +{ + ptr = memRead(programCounter++); + opL = memRead(ptr) + yRegister; + opH = memRead((unsigned short)(ptr + 1 & 0xFF)) << 8; + cycles += 3; + + if (opL & 0x100) + cycles++; + + op = opH + opL; +} + +static void Rel(void) +{ + op = memRead(programCounter++); + + if (op & 0x80) + op |= 0xFF00; + + op += programCounter; + cycles++; +} + +static void WAbsX(void) +{ + opL = memRead(programCounter++) + xRegister; + opH = memRead(programCounter++) << 8; + cycles += 3; + op = opH + opL; +} + +static void WAbsY(void) +{ + opL = memRead(programCounter++) + yRegister; + opH = memRead(programCounter++) << 8; + cycles += 3; + op = opH + opL; +} + +static void WIndZeroY(void) +{ + ptr = memRead(programCounter++); + opL = memRead(ptr) + yRegister; + opH = memRead((unsigned short)(ptr + 1 & 0xFF)) << 8; + cycles += 4; + op = opH + opL; +} + +static void setStatusRegisterNZ(unsigned char val) +{ + if (val & 0x80) + statusRegister |= N; + else + statusRegister &= ~N; + + if (!val) + statusRegister |= Z; + else + statusRegister &= ~Z; +} + +static void LDA(void) +{ + accumulator = memRead(op); + setStatusRegisterNZ(accumulator); + cycles++; +} + +static void LDX(void) +{ + xRegister = memRead(op); + setStatusRegisterNZ(xRegister); + cycles++; +} + +static void LDY(void) +{ + yRegister = memRead(op); + setStatusRegisterNZ(yRegister); + cycles++; +} + +static void STA(void) +{ + memWrite(op, accumulator); + cycles++; +} + +static void STX(void) +{ + memWrite(op, xRegister); + cycles++; +} + +static void STY(void) +{ + memWrite(op, yRegister); + cycles++; +} + +static void setFlagCarry(unsigned short val) +{ + if (val & 0x100) + statusRegister |= C; + else + statusRegister &= ~C; +} + +static void ADC(void) +{ + unsigned short Op1 = accumulator, Op2 = memRead(op); + cycles++; + + if (statusRegister & D) + { + if (!(Op1 + Op2 + (statusRegister & C ? 1 : 0) & 0xFF)) + statusRegister |= Z; + else + statusRegister &= ~Z; + + tmp = (Op1 & 0x0F) + (Op2 & 0x0F) + (statusRegister & C ? 1 : 0); + accumulator = tmp < 0x0A ? tmp : tmp + 6; + tmp = (Op1 & 0xF0) + (Op2 & 0xF0) + (tmp & 0xF0); + + if (tmp & 0x80) + statusRegister |= N; + else + statusRegister &= ~N; + + if ((Op1 ^ tmp) & ~(Op1 ^ Op2) & 0x80) + statusRegister |= V; + else + statusRegister &= ~V; + + tmp = (accumulator & 0x0F) | (tmp < 0xA0 ? tmp : tmp + 0x60); + + if (tmp & 0x100) + statusRegister |= C; + else + statusRegister &= ~C; + + accumulator = tmp & 0xFF; + } + else + { + tmp = Op1 + Op2 + (statusRegister & C ? 1 : 0); + accumulator = tmp & 0xFF; + + if ((Op1 ^ accumulator) & ~(Op1 ^ Op2) & 0x80) + statusRegister |= V; + else + statusRegister &= ~V; + + setFlagCarry(tmp); + setStatusRegisterNZ(accumulator); + } +} + +static void setFlagBorrow(unsigned short val) +{ + if (!(val & 0x100)) + statusRegister |= C; + else + statusRegister &= ~C; +} + +static void SBC(void) +{ + unsigned short Op1 = accumulator, Op2 = memRead(op); + cycles++; + + if (statusRegister & D) + { + tmp = (Op1 & 0x0F) - (Op2 & 0x0F) - (statusRegister & C ? 0 : 1); + accumulator = !(tmp & 0x10) ? tmp : tmp - 6; + tmp = (Op1 & 0xF0) - (Op2 & 0xF0) - (accumulator & 0x10); + accumulator = (accumulator & 0x0F) | (!(tmp & 0x100) ? tmp : tmp - 0x60); + tmp = Op1 - Op2 - (statusRegister & C ? 0 : 1); + setFlagBorrow(tmp); + setStatusRegisterNZ((unsigned char)tmp); + } + else + { + tmp = Op1 - Op2 - (statusRegister & C ? 0 : 1); + accumulator = tmp & 0xFF; + + if ((Op1 ^ Op2) & (Op1 ^ accumulator) & 0x80) + statusRegister |= V; + else + statusRegister &= ~V; + + setFlagBorrow(tmp); + setStatusRegisterNZ(accumulator); + } +} + +static void CMP(void) +{ + tmp = accumulator - memRead(op); + cycles++; + setFlagBorrow(tmp); + setStatusRegisterNZ((unsigned char)tmp); +} + +static void CPX(void) +{ + tmp = xRegister - memRead(op); + cycles++; + setFlagBorrow(tmp); + setStatusRegisterNZ((unsigned char)tmp); +} + +static void CPY(void) +{ + tmp = yRegister - memRead(op); + cycles++; + setFlagBorrow(tmp); + setStatusRegisterNZ((unsigned char)tmp); +} + +static void AND(void) +{ + accumulator &= memRead(op); + cycles++; + setStatusRegisterNZ(accumulator); +} + +static void ORA(void) +{ + accumulator |= memRead(op); + cycles++; + setStatusRegisterNZ(accumulator); +} + +static void EOR(void) +{ + accumulator ^= memRead(op); + cycles++; + setStatusRegisterNZ(accumulator); +} + +static void ASL(void) +{ + btmp = memRead(op); + + if (btmp & 0x80) + statusRegister |= C; + else + statusRegister &= ~C; + + btmp <<= 1; + setStatusRegisterNZ(btmp); + memWrite(op, btmp); + cycles += 3; +} + +static void ASL_A(void) +{ + tmp = accumulator << 1; + accumulator = tmp & 0xFF; + setFlagCarry(tmp); + setStatusRegisterNZ(accumulator); +} + +static void LSR(void) +{ + btmp = memRead(op); + + if (btmp & 1) + statusRegister |= C; + else + statusRegister &= ~C; + + btmp >>= 1; + setStatusRegisterNZ(btmp); + memWrite(op, btmp); + cycles += 3; +} + +static void LSR_A(void) +{ + if (accumulator & 1) + statusRegister |= C; + else + statusRegister &= ~C; + + accumulator >>= 1; + setStatusRegisterNZ(accumulator); +} + +static void ROL(void) +{ + int newCarry; + + btmp = memRead(op); + newCarry = btmp & 0x80; + btmp = (btmp << 1) | (statusRegister & C ? 1 : 0); + + if (newCarry) + statusRegister |= C; + else + statusRegister &= ~C; + + setStatusRegisterNZ(btmp); + memWrite(op, btmp); + cycles += 3; +} + +static void ROL_A(void) +{ + tmp = (accumulator << 1) | (statusRegister & C ? 1 : 0); + accumulator = tmp & 0xFF; + setFlagCarry(tmp); + setStatusRegisterNZ(accumulator); +} + +static void ROR(void) +{ + int newCarry; + + btmp = memRead(op); + newCarry = btmp & 1; + btmp = (btmp >> 1) | (statusRegister & C ? 0x80 : 0); + + if (newCarry) + statusRegister |= C; + else + statusRegister &= ~C; + + setStatusRegisterNZ(btmp); + memWrite(op, btmp); + cycles += 3; +} + +static void ROR_A(void) +{ + tmp = accumulator | (statusRegister & C ? 0x100 : 0); + + if (accumulator & 1) + statusRegister |= C; + else + statusRegister &= ~C; + + accumulator = tmp >> 1; + setStatusRegisterNZ(accumulator); +} + +static void INC(void) +{ + btmp = memRead(op); + btmp++; + setStatusRegisterNZ(btmp); + memWrite(op, btmp); + cycles += 2; +} + +static void DEC(void) +{ + btmp = memRead(op); + btmp--; + setStatusRegisterNZ(btmp); + memWrite(op, btmp); + cycles += 2; +} + +static void INX(void) +{ + xRegister++; + setStatusRegisterNZ(xRegister); +} + +static void INY(void) +{ + yRegister++; + setStatusRegisterNZ(yRegister); +} + +static void DEX(void) +{ + xRegister--; + setStatusRegisterNZ(xRegister); +} + +static void DEY(void) +{ + yRegister--; + setStatusRegisterNZ(yRegister); +} + +static void BIT(void) +{ + btmp = memRead(op); + + if (btmp & 0x40) + statusRegister |= V; + else + statusRegister &= ~V; + + if (btmp & 0x80) + statusRegister |= N; + else + statusRegister &= ~N; + + if (!(btmp & accumulator)) + statusRegister |= Z; + else + statusRegister &= ~Z; + + cycles++; +} + +static void PHA(void) +{ + memWrite((unsigned short)(0x100 + stackPointer), accumulator); + stackPointer--; + cycles++; +} + +static void PHP(void) +{ + memWrite((unsigned short)(0x100 + stackPointer), statusRegister); + stackPointer--; + cycles++; +} + +static void PLA(void) +{ + stackPointer++; + accumulator = memRead((unsigned short)(stackPointer + 0x100)); + setStatusRegisterNZ(accumulator); + cycles += 2; +} + +static void PLP(void) +{ + stackPointer++; + statusRegister = memRead((unsigned short)(stackPointer + 0x100)); + cycles += 2; +} + +static void BRK(void) +{ + pushProgramCounter(); + PHP(); + statusRegister |= B; + programCounter = memReadAbsolute(0xFFFE); + cycles += 3; +} + +static void RTI(void) +{ + PLP(); + popProgramCounter(); + cycles++; +} + +static void JMP(void) +{ + programCounter = op; +} + +static void RTS(void) +{ + popProgramCounter(); + programCounter++; + cycles += 2; +} + +static void JSR(void) +{ + opL = memRead(programCounter++); + pushProgramCounter(); + programCounter = opL + (memRead(programCounter) << 8); + cycles += 3; +} + +static void branch(void) +{ + cycles++; + + if ((programCounter & 0xFF00) != (op & 0xFF00)) + cycles++; + + programCounter = op; +} + +static void BNE(void) +{ + if (!(statusRegister & Z)) + branch(); +} + +static void BEQ(void) +{ + if (statusRegister & Z) + branch(); +} + +static void BVC(void) +{ + if (!(statusRegister & V)) + branch(); +} + +static void BVS(void) +{ + if (statusRegister & V) + branch(); +} + +static void BCC(void) +{ + if (!(statusRegister & C)) + branch(); +} + +static void BCS(void) +{ + if (statusRegister & C) + branch(); +} + +static void BPL(void) +{ + if (!(statusRegister & N)) + branch(); +} + +static void BMI(void) +{ + if (statusRegister & N) + branch(); +} + +static void TAX(void) +{ + xRegister = accumulator; + setStatusRegisterNZ(accumulator); +} + +static void TXA(void) +{ + accumulator = xRegister; + setStatusRegisterNZ(accumulator); +} + +static void TAY(void) +{ + yRegister = accumulator; + setStatusRegisterNZ(accumulator); +} + +static void TYA(void) +{ + accumulator = yRegister; + setStatusRegisterNZ(accumulator); +} + +static void TXS(void) +{ + stackPointer = xRegister; +} + +static void TSX(void) +{ + xRegister = stackPointer; + setStatusRegisterNZ(xRegister); +} + +static void CLC(void) +{ + statusRegister &= ~C; +} + +static void SEC(void) +{ + statusRegister |= C; +} + +static void CLI(void) +{ + statusRegister &= ~I; +} + +static void SEI(void) +{ + statusRegister |= I; +} + +static void CLV(void) +{ + statusRegister &= ~V; +} + +static void CLD(void) +{ + statusRegister &= ~D; +} + +static void SED(void) +{ + statusRegister |= D; +} + +static void NOP(void) +{ +} + +static void Unoff(void) +{ +} + +static void Unoff1(void) +{ +} + +static void Unoff2(void) +{ + programCounter++; +} + +static void Unoff3(void) +{ + programCounter += 2; +} + +static void Hang(void) +{ + programCounter--; +} + +static void executeOpcode(void) +{ + unsigned char opcode = memRead(programCounter++); + + switch (opcode) + { + case 0x00: + Imm(); + BRK(); + break; + case 0x01: + IndZeroX(); + ORA(); + break; + case 0x02: + Hang(); + break; + case 0x03: + Unoff(); + break; + case 0x04: + Unoff2(); + break; + case 0x05: + Zero(); + ORA(); + break; + case 0x06: + Zero(); + ASL(); + break; + case 0x07: + Unoff(); + break; + case 0x08: + Imp(); + PHP(); + break; + case 0x09: + Imm(); + ORA(); + break; + case 0x0A: + Imp(); + ASL_A(); + break; + case 0x0B: + Imm(); + AND(); + break; + case 0x0C: + Unoff3(); + break; + case 0x0D: + Abs(); + ORA(); + break; + case 0x0E: + Abs(); + ASL(); + break; + case 0x0F: + Unoff(); + break; + case 0x10: + Rel(); + BPL(); + break; + case 0x11: + IndZeroY(); + ORA(); + break; + case 0x12: + Hang(); + break; + case 0x13: + Unoff(); + break; + case 0x14: + Unoff2(); + break; + case 0x15: + ZeroX(); + ORA(); + break; + case 0x16: + ZeroX(); + ASL(); + break; + case 0x17: + Unoff(); + break; + case 0x18: + Imp(); + CLC(); + break; + case 0x19: + AbsY(); + ORA(); + break; + case 0x1A: + Unoff1(); + break; + case 0x1B: + Unoff(); + break; + case 0x1C: + Unoff3(); + break; + case 0x1D: + AbsX(); + ORA(); + break; + case 0x1E: + WAbsX(); + ASL(); + break; + case 0x1F: + Unoff(); + break; + case 0x20: + JSR(); + break; + case 0x21: + IndZeroX(); + AND(); + break; + case 0x22: + Hang(); + break; + case 0x23: + Unoff(); + break; + case 0x24: + Zero(); + BIT(); + break; + case 0x25: + Zero(); + AND(); + break; + case 0x26: + Zero(); + ROL(); + break; + case 0x27: + Unoff(); + break; + case 0x28: + Imp(); + PLP(); + break; + case 0x29: + Imm(); + AND(); + break; + case 0x2A: + Imp(); + ROL_A(); + break; + case 0x2B: + Imm(); + AND(); + break; + case 0x2C: + Abs(); + BIT(); + break; + case 0x2D: + Abs(); + AND(); + break; + case 0x2E: + Abs(); + ROL(); + break; + case 0x2F: + Unoff(); + break; + case 0x30: + Rel(); + BMI(); + break; + case 0x31: + IndZeroY(); + AND(); + break; + case 0x32: + Hang(); + break; + case 0x33: + Unoff(); + break; + case 0x34: + Unoff2(); + break; + case 0x35: + ZeroX(); + AND(); + break; + case 0x36: + ZeroX(); + ROL(); + break; + case 0x37: + Unoff(); + break; + case 0x38: + Imp(); + SEC(); + break; + case 0x39: + AbsY(); + AND(); + break; + case 0x3A: + Unoff1(); + break; + case 0x3B: + Unoff(); + break; + case 0x3C: + Unoff3(); + break; + case 0x3D: + AbsX(); + AND(); + break; + case 0x3E: + WAbsX(); + ROL(); + break; + case 0x3F: + Unoff(); + break; + case 0x40: + Imp(); + RTI(); + break; + case 0x41: + IndZeroX(); + EOR(); + break; + case 0x42: + Hang(); + break; + case 0x43: + Unoff(); + break; + case 0x44: + Unoff2(); + break; + case 0x45: + Zero(); + EOR(); + break; + case 0x46: + Zero(); + LSR(); + break; + case 0x47: + Unoff(); + break; + case 0x48: + Imp(); + PHA(); + break; + case 0x49: + Imm(); + EOR(); + break; + case 0x4A: + Imp(); + LSR_A(); + break; + case 0x4B: + Unoff(); + break; + case 0x4C: + Abs(); + JMP(); + break; + case 0x4D: + Abs(); + EOR(); + break; + case 0x4E: + Abs(); + LSR(); + break; + case 0x4F: + Unoff(); + break; + case 0x50: + Rel(); + BVC(); + break; + case 0x51: + IndZeroY(); + EOR(); + break; + case 0x52: + Hang(); + break; + case 0x53: + Unoff(); + break; + case 0x54: + Unoff2(); + break; + case 0x55: + ZeroX(); + EOR(); + break; + case 0x56: + ZeroX(); + LSR(); + break; + case 0x57: + Unoff(); + break; + case 0x58: + Imp(); + CLI(); + break; + case 0x59: + AbsY(); + EOR(); + break; + case 0x5A: + Unoff1(); + break; + case 0x5B: + Unoff(); + break; + case 0x5C: + Unoff3(); + break; + case 0x5D: + AbsX(); + EOR(); + break; + case 0x5E: + WAbsX(); + LSR(); + break; + case 0x5F: + Unoff(); + break; + case 0x60: + Imp(); + RTS(); + break; + case 0x61: + IndZeroX(); + ADC(); + break; + case 0x62: + Hang(); + break; + case 0x63: + Unoff(); + break; + case 0x64: + Unoff2(); + break; + case 0x65: + Zero(); + ADC(); + break; + case 0x66: + Zero(); + ROR(); + break; + case 0x67: + Unoff(); + break; + case 0x68: + Imp(); + PLA(); + break; + case 0x69: + Imm(); + ADC(); + break; + case 0x6A: + Imp(); + ROR_A(); + break; + case 0x6B: + Unoff(); + break; + case 0x6C: + Ind(); + JMP(); + break; + case 0x6D: + Abs(); + ADC(); + break; + case 0x6E: + Abs(); + ROR(); + break; + case 0x6F: + Unoff(); + break; + case 0x70: + Rel(); + BVS(); + break; + case 0x71: + IndZeroY(); + ADC(); + break; + case 0x72: + Hang(); + break; + case 0x73: + Unoff(); + break; + case 0x74: + Unoff2(); + break; + case 0x75: + ZeroX(); + ADC(); + break; + case 0x76: + ZeroX(); + ROR(); + break; + case 0x77: + Unoff(); + break; + case 0x78: + Imp(); + SEI(); + break; + case 0x79: + AbsY(); + ADC(); + break; + case 0x7A: + Unoff1(); + break; + case 0x7B: + Unoff(); + break; + case 0x7C: + Unoff3(); + break; + case 0x7D: + AbsX(); + ADC(); + break; + case 0x7E: + WAbsX(); + ROR(); + break; + case 0x7F: + Unoff(); + break; + case 0x80: + Unoff2(); + break; + case 0x81: + IndZeroX(); + STA(); + break; + case 0x82: + Unoff2(); + break; + case 0x83: + Unoff(); + break; + case 0x84: + Zero(); + STY(); + break; + case 0x85: + Zero(); + STA(); + break; + case 0x86: + Zero(); + STX(); + break; + case 0x87: + Unoff(); + break; + case 0x88: + Imp(); + DEY(); + break; + case 0x89: + Unoff2(); + break; + case 0x8A: + Imp(); + TXA(); + break; + case 0x8B: + Unoff(); + break; + case 0x8C: + Abs(); + STY(); + break; + case 0x8D: + Abs(); + STA(); + break; + case 0x8E: + Abs(); + STX(); + break; + case 0x8F: + Unoff(); + break; + case 0x90: + Rel(); + BCC(); + break; + case 0x91: + WIndZeroY(); + STA(); + break; + case 0x92: + Hang(); + break; + case 0x93: + Unoff(); + break; + case 0x94: + ZeroX(); + STY(); + break; + case 0x95: + ZeroX(); + STA(); + break; + case 0x96: + ZeroY(); + STX(); + break; + case 0x97: + Unoff(); + break; + case 0x98: + Imp(); + TYA(); + break; + case 0x99: + WAbsY(); + STA(); + break; + case 0x9A: + Imp(); + TXS(); + break; + case 0x9B: + Unoff(); + break; + case 0x9C: + Unoff(); + break; + case 0x9D: + WAbsX(); + STA(); + break; + case 0x9E: + Unoff(); + break; + case 0x9F: + Unoff(); + break; + case 0xA0: + Imm(); + LDY(); + break; + case 0xA1: + IndZeroX(); + LDA(); + break; + case 0xA2: + Imm(); + LDX(); + break; + case 0xA3: + Unoff(); + break; + case 0xA4: + Zero(); + LDY(); + break; + case 0xA5: + Zero(); + LDA(); + break; + case 0xA6: + Zero(); + LDX(); + break; + case 0xA7: + Unoff(); + break; + case 0xA8: + Imp(); + TAY(); + break; + case 0xA9: + Imm(); + LDA(); + break; + case 0xAA: + Imp(); + TAX(); + break; + case 0xAB: + Unoff(); + break; + case 0xAC: + Abs(); + LDY(); + break; + case 0xAD: + Abs(); + LDA(); + break; + case 0xAE: + Abs(); + LDX(); + break; + case 0xAF: + Unoff(); + break; + case 0xB0: + Rel(); + BCS(); + break; + case 0xB1: + IndZeroY(); + LDA(); + break; + case 0xB2: + Hang(); + break; + case 0xB3: + Unoff(); + break; + case 0xB4: + ZeroX(); + LDY(); + break; + case 0xB5: + ZeroX(); + LDA(); + break; + case 0xB6: + ZeroY(); + LDX(); + break; + case 0xB7: + Unoff(); + break; + case 0xB8: + Imp(); + CLV(); + break; + case 0xB9: + AbsY(); + LDA(); + break; + case 0xBA: + Imp(); + TSX(); + break; + case 0xBB: + Unoff(); + break; + case 0xBC: + AbsX(); + LDY(); + break; + case 0xBD: + AbsX(); + LDA(); + break; + case 0xBE: + AbsY(); + LDX(); + break; + case 0xBF: + Unoff(); + break; + case 0xC0: + Imm(); + CPY(); + break; + case 0xC1: + IndZeroX(); + CMP(); + break; + case 0xC2: + Unoff2(); + break; + case 0xC3: + Unoff(); + break; + case 0xC4: + Zero(); + CPY(); + break; + case 0xC5: + Zero(); + CMP(); + break; + case 0xC6: + Zero(); + DEC(); + break; + case 0xC7: + Unoff(); + break; + case 0xC8: + Imp(); + INY(); + break; + case 0xC9: + Imm(); + CMP(); + break; + case 0xCA: + Imp(); + DEX(); + break; + case 0xCB: + Unoff(); + break; + case 0xCC: + Abs(); + CPY(); + break; + case 0xCD: + Abs(); + CMP(); + break; + case 0xCE: + Abs(); + DEC(); + break; + case 0xCF: + Unoff(); + break; + case 0xD0: + Rel(); + BNE(); + break; + case 0xD1: + IndZeroY(); + CMP(); + break; + case 0xD2: + Hang(); + break; + case 0xD3: + Unoff(); + break; + case 0xD4: + Unoff2(); + break; + case 0xD5: + ZeroX(); + CMP(); + break; + case 0xD6: + ZeroX(); + DEC(); + break; + case 0xD7: + Unoff(); + break; + case 0xD8: + Imp(); + CLD(); + break; + case 0xD9: + AbsY(); + CMP(); + break; + case 0xDA: + Unoff1(); + break; + case 0xDB: + Unoff(); + break; + case 0xDC: + Unoff3(); + break; + case 0xDD: + AbsX(); + CMP(); + break; + case 0xDE: + WAbsX(); + DEC(); + break; + case 0xDF: + Unoff(); + break; + case 0xE0: + Imm(); + CPX(); + break; + case 0xE1: + IndZeroX(); + SBC(); + break; + case 0xE2: + Unoff2(); + break; + case 0xE3: + Unoff(); + break; + case 0xE4: + Zero(); + CPX(); + break; + case 0xE5: + Zero(); + SBC(); + break; + case 0xE6: + Zero(); + INC(); + break; + case 0xE7: + Unoff(); + break; + case 0xE8: + Imp(); + INX(); + break; + case 0xE9: + Imm(); + SBC(); + break; + case 0xEA: + Imp(); + NOP(); + break; + case 0xEB: + Imm(); + SBC(); + break; + case 0xEC: + Abs(); + CPX(); + break; + case 0xED: + Abs(); + SBC(); + break; + case 0xEE: + Abs(); + INC(); + break; + case 0xEF: + Unoff(); + break; + case 0xF0: + Rel(); + BEQ(); + break; + case 0xF1: + IndZeroY(); + SBC(); + break; + case 0xF2: + Hang(); + break; + case 0xF3: + Unoff(); + break; + case 0xF4: + Unoff2(); + break; + case 0xF5: + ZeroX(); + SBC(); + break; + case 0xF6: + ZeroX(); + INC(); + break; + case 0xF7: + Unoff(); + break; + case 0xF8: + Imp(); + SED(); + break; + case 0xF9: + AbsY(); + SBC(); + break; + case 0xFA: + Unoff1(); + break; + case 0xFB: + Unoff(); + break; + case 0xFC: + Unoff3(); + break; + case 0xFD: + AbsX(); + SBC(); + break; + case 0xFE: + WAbsX(); + INC(); + break; + case 0xFF: + Unoff(); + break; + } +} + +static int runM6502(void *data) +{ + while (running) + { + synchronize(); + + cycles = 0; + + while (running && cycles < cyclesBeforeSynchro) + { + if (!(statusRegister & I) && IRQ) + handleIRQ(); + if (NMI) + handleNMI(); + + executeOpcode(); + } + } + + return 0; +} + +void startM6502(void) +{ + running = 1; + lastTime = SDL_GetTicks(); + thread = SDL_CreateThread(runM6502, NULL); +} + +void stopM6502(void) +{ + running = 0; + SDL_WaitThread(thread, NULL); +} + +void resetM6502(void) +{ + statusRegister |= I; + stackPointer = 0xFF; + programCounter = memReadAbsolute(0xFFFC); +} + +void setSpeed(int freq, int synchroMillis) +{ + cyclesBeforeSynchro = synchroMillis * freq; + _synchroMillis = synchroMillis; +} + +void setIRQ(int state) +{ + IRQ = state; +} + +void setNMI(void) +{ + NMI = 1; +} + +int *dumpState(void) +{ + int *state = (int *)malloc(sizeof(int) * 6); + + state[0] = programCounter; + state[1] = statusRegister; + state[2] = accumulator; + state[3] = xRegister; + state[4] = yRegister; + state[5] = stackPointer; + + return state; +} + +void loadState(int *state) +{ + programCounter = state[0]; + statusRegister = state[1]; + accumulator = state[2]; + xRegister = state[3]; + yRegister = state[4]; + stackPointer = state[5]; +} diff --git a/src/m6502.h b/src/m6502.h new file mode 100644 index 0000000..703798c --- /dev/null +++ b/src/m6502.h @@ -0,0 +1,31 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __M6502_H__ +#define __M6502_H__ + +void startM6502(void); +void stopM6502(void); +void resetM6502(void); +void setSpeed(int freq, int synchroMillis); +void setIRQ(int state); +void setNMI(void); +int *dumpState(void); +void loadState(int *state); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..88c5297 --- /dev/null +++ b/src/main.c @@ -0,0 +1,131 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "SDL.h" +#include "configuration.h" +#include "keyboard.h" +#include "m6502.h" +#include "memory.h" +#include "screen.h" +#include "config.h" + +#ifdef _WIN32 +#define strcasecmp _stricmp +#endif + +int main(int argc, char *argv[]) +{ + int i, temp; + char *romdir = getenv("POM1ROMDIR"); + + atexit(freeRomDirectory); + + if (romdir) + setRomDirectory(romdir); + else + setRomDirectory("roms"); + + loadConfiguration(); + + atexit(saveConfiguration); + + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + if (!strcasecmp("-romdir", argv[i]) && i + 1 < argc) + setRomDirectory(argv[i + 1]); + else if (!strcasecmp("-pixelsize", argv[i]) && i + 1 < argc) + { + temp = atoi(argv[i + 1]); + + if (temp == 1 || temp == 2) + { + if (temp == 1) + setScanlines(0); + + setPixelSize(temp); + } + } + else if (!strcasecmp("-scanlines", argv[i])) + if (getPixelSize() > 1) + setScanlines(1); + else if (!strcasecmp("-terminalspeed", argv[i]) && i + 1 < argc) + { + temp = atoi(argv[i + 1]); + + if (temp >= 1 && temp <= 120) + setTerminalSpeed(temp); + } + else if (!strcasecmp("-ram8k", argv[i])) + setRam8k(1); + else if (!strcasecmp("-writeinrom", argv[i])) + setWriteInRom(1); + else if (!strcasecmp("-fullscreen", argv[i])) + setFullscreen(1); + else if (!strcasecmp("-blinkcursor", argv[i])) + setBlinkCursor(1); + else if (!strcasecmp("-blockcursor", argv[i])) + setBlockCursor(1); + } + } + + if (SDL_Init(SDL_INIT_VIDEO) < 0) + { + fprintf(stderr, "stderr: Could not initialize SDL\n"); + return 1; + } + + atexit(SDL_Quit); + + SDL_WM_SetCaption(PACKAGE_NAME, NULL); + + if (!SDL_SetVideoMode(280 * getPixelSize(), 192 * getPixelSize(), 8, SDL_HWSURFACE | (getFullscreen() ? SDL_FULLSCREEN : 0))) + { + fprintf(stderr, "stderr: Could not set video mode to %dx%dx8\n", 280 * getPixelSize(), 192 * getPixelSize()); + return 1; + } + + initScreen(); + + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + SDL_EnableUNICODE(1); + + SDL_ShowCursor(!getFullscreen()); + + if (!loadCharMap()) + { + fprintf(stderr, "stderr: Could not load character map\n"); + return 1; + } + + resetScreen(); + resetMemory(); + setSpeed(1000, 50); + resetM6502(); + startM6502(); + + atexit(stopM6502); + atexit(closeInputFile); + + while (handleInput()) + updateScreen(); + + return 0; +} diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..dce1faa --- /dev/null +++ b/src/memory.c @@ -0,0 +1,174 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include +#include +#include +#include "configuration.h" +#include "pia6820.h" + +static unsigned char mem[65536]; +static int ram8k = 0, writeInRom = 1; + +static int loadMonitor(void) +{ + const char *romdir = getRomDirectory(); + char *filename; + FILE *fp; + + filename = (char *)malloc(strlen(romdir) + 13); + sprintf(filename, "%s/monitor.rom", romdir); + + fp = fopen(filename, "rb"); + + free(filename); + + if (fp) + { + fread(&mem[0xFF00], 1, 256, fp); + fclose(fp); + } + else + return 0; + + return 1; +} + +static int loadBasic(void) +{ + const char *romdir = getRomDirectory(); + char *filename; + FILE *fp; + + filename = (char *)malloc(strlen(romdir) + 11); + sprintf(filename, "%s/basic.rom", romdir); + + fp = fopen(filename, "rb"); + + free(filename); + + if (fp) + { + fread(&mem[0xE000], 1, 4096, fp); + fclose(fp); + } + else + return 0; + + return 1; +} + + +void resetMemory(void) +{ + memset(mem, 0, 57344); + + if (!loadMonitor()) + { + fprintf(stderr, "stderr: Could not load monitor\n"); + exit(1); + } + + if (!loadBasic()) + { + fprintf(stderr, "stderr: Could not load basic\n"); + exit(1); + } +} + +void setRam8k(int b) +{ + ram8k = b; +} + +int getRam8k() +{ + return ram8k; +} + +void setWriteInRom(int b) +{ + writeInRom = b; +} + +int getWriteInRom(void) +{ + return writeInRom; +} + +unsigned char memRead(unsigned short address) +{ + if (address == 0xD013) + return readDspCr(); + if (address == 0xD012) + return readDsp(); + if (address == 0xD011) + return readKbdCr(); + if (address == 0xD010) + return readKbd(); + + return mem[address]; +} + +void memWrite(unsigned short address, unsigned char value) +{ + if (address == 0xD013) + { + writeDspCr(value); + return; + } + if (address == 0xD012) + { + writeDsp((unsigned char)(value | 0x80)); + return; + } + if (address == 0xD011) + { + writeKbdCr(value); + return; + } + if (address == 0xD010) + { + writeKbd(value); + return; + } + + if (address >= 0xFF00 && !writeInRom) + return; + if (ram8k && address >= 0x2000 && address < 0xFF00) + return; + + mem[address] = value; +} + +unsigned char *dumpMemory(unsigned short start, unsigned short end) +{ + unsigned char *fbrut = (unsigned char *)malloc(end - start + 1); + + if (!fbrut) + fprintf(stderr, "stderr: Could not allocate memory block\n"); + else + memcpy(fbrut, &mem[start], end - start + 1); + + return fbrut; +} + +void setMemory(const unsigned char *data, unsigned short start, unsigned int size) +{ + memcpy(&mem[start], data, size); +} diff --git a/src/memory.h b/src/memory.h new file mode 100644 index 0000000..50aed7f --- /dev/null +++ b/src/memory.h @@ -0,0 +1,32 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +void resetMemory(void); +void setRam8k(int b); +int getRam8k(void); +void setWriteInRom(int b); +int getWriteInRom(void); +unsigned char memRead(unsigned short address); +void memWrite(unsigned short address, unsigned char value); +unsigned char *dumpMemory(unsigned short start, unsigned short end); +void setMemory(const unsigned char *data, unsigned short start, unsigned int size); + +#endif diff --git a/src/options.c b/src/options.c new file mode 100644 index 0000000..9227124 --- /dev/null +++ b/src/options.c @@ -0,0 +1,687 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "SDL.h" +#include "memory.h" +#include "keyboard.h" +#include "screen.h" +#include "config.h" + +#define TYPE_STRING 1 +#define TYPE_DECIMAL 2 +#define TYPE_HEXADECIMAL 3 +#define TYPE_CHOICE 4 + +#define isHexDigit(c) ((c >= '0' && c <= '9') || ((c & 0x5F) >= 'A' && (c & 0x5F) <= 'F')) + +static int step, type, max, choice; +static unsigned int start; +static char filename[1024], buffer[1024]; +static FILE *fp; + +static void drawString(const char *str, int x, int y) +{ + char c; + const char *p = str; + int X = x; + int characterWidth = 7 * getPixelSize(), characterHeight = 8 * getPixelSize(); + + while (c = *p++) + { + if (c == '\n') + { + X = x; + y += characterHeight; + } + else + { + drawCharacter(X, y, 0, 0, 0, c); + X += characterWidth; + } + } +} + +static void inputLoop(const char *str, int (*func)(void)) +{ + SDL_Event event; + SDL_Rect rect; + SDL_Surface *screen = SDL_GetVideoSurface(); + int screenWidth = screen->w, screenHeight = screen->h; + int i, c = 0, x = 0; + char tmp; + int pixelSize = getPixelSize(); + int characterWidth = 7 * pixelSize, characterHeight = 8 * pixelSize; + + rect.x = 0; + rect.y = screenHeight - (2 * characterHeight + pixelSize); + rect.w = screenWidth; + rect.h = 2 * characterHeight + pixelSize; + + SDL_FillRect(screen, &rect, 255); + + drawString(str, 0, screenHeight - 16 * pixelSize); + + if (type != TYPE_CHOICE) + drawCharacter(0, screenHeight - characterHeight, 0, 0, 0, 0x01); + + SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h); + + step = 1; + + while (1) + { + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.mod & KMOD_CTRL && event.key.keysym.sym == SDLK_q)) + exit(0); + + if (event.type == SDL_KEYDOWN) + { + if (event.key.keysym.sym == SDLK_ESCAPE) + { + redrawScreen(); + return; + } + else if (event.key.keysym.sym == SDLK_SPACE && type == TYPE_STRING) + { + if (c < max) + buffer[c++] = ' '; + else + continue; + + if (c - 1 < 39) + { + rect.x = x; + rect.y = screenHeight - characterHeight; + rect.w = characterWidth; + rect.h = characterHeight; + + SDL_FillRect(screen, &rect, 255); + + x += characterWidth; + + drawCharacter(x, rect.y, 0, 0, 0, 0x01); + + SDL_UpdateRect(screen, rect.x, rect.y, 2 * characterWidth, characterHeight); + } + else + { + rect.x = 0; + rect.y = screenHeight - characterHeight; + rect.w = screenWidth - characterWidth; + rect.h = characterHeight; + + SDL_FillRect(screen, &rect, 255); + + rect.w = characterWidth; + + for (i = 0; i < 39; i++) + { + rect.x = characterWidth * i; + + if (buffer[(c - 39) + i] == ' ') + SDL_FillRect(screen, &rect, 255); + else + drawCharacter(rect.x, rect.y, 0, 0, 0, buffer[(c - 39) + i]); + } + + SDL_UpdateRect(screen, 0, rect.y, screenWidth - characterWidth, characterHeight); + } + } + else if (event.key.keysym.sym == SDLK_BACKSPACE && type != TYPE_CHOICE) + { + if (c > 0) + buffer[--c] = '\0'; + else + continue; + + if (x > 0 && c < 39) + { + x -= characterWidth; + + rect.x = x; + rect.y = screenHeight - characterHeight; + rect.w = 2 * characterWidth; + rect.h = characterHeight; + + SDL_FillRect(screen, &rect, 255); + + drawCharacter(x, rect.y, 0, 0, 0, 0x01); + + SDL_UpdateRect(screen, rect.x, rect.y, rect.w, characterHeight); + } + else + { + rect.x = 0; + rect.y = screenHeight - characterHeight; + rect.w = screenWidth - characterWidth; + rect.h = characterHeight; + + SDL_FillRect(screen, &rect, 255); + + rect.w = characterWidth; + + for (i = 0; i < 39; i++) + { + rect.x = characterWidth * i; + + if (buffer[(c - 39) + i] == ' ') + SDL_FillRect(screen, &rect, 255); + else + drawCharacter(rect.x, rect.y, 0, 0, 0, buffer[(c - 39) + i]); + } + + SDL_UpdateRect(screen, 0, rect.y, screenWidth - characterWidth, characterHeight); + } + } + else if ((event.key.keysym.sym == SDLK_RETURN && c) || (type == TYPE_CHOICE && (event.key.keysym.sym == SDLK_1 || event.key.keysym.sym == SDLK_2))) + { + if (type == TYPE_CHOICE) + choice = event.key.keysym.sym & 0x03; + + rect.x = 0; + rect.y = screenHeight - (2 * characterHeight + pixelSize); + rect.w = screenWidth; + rect.h = 2 * characterHeight + pixelSize; + + SDL_FillRect(screen, &rect, 255); + + buffer[c] = '\0'; + + if (!(*func)()) + { + redrawScreen(); + return; + } + + SDL_UpdateRect(screen, 0, rect.y, screenWidth, rect.h); + + c = x = 0; + + step++; + } + else if (!(event.key.keysym.unicode & 0xFF80) && event.key.keysym.unicode) + { + tmp = event.key.keysym.unicode & 0x7F; + + if (type == TYPE_HEXADECIMAL && tmp >= 0x61 && tmp <= 0x66) + tmp &= 0x5F; + + if (c < max && ((type == TYPE_STRING && tmp >= 0x21 && tmp <= 0x7E) || (type == TYPE_DECIMAL && tmp >= 0x30 && tmp <= 0x39) || (type == TYPE_HEXADECIMAL && ((tmp >= 0x30 && tmp <= 0x39) || (tmp >= 0x41 && tmp <= 0x46))))) + buffer[c++] = tmp; + else + continue; + + if (c - 1 < 39) + { + rect.x = x; + rect.y = screenHeight - characterHeight; + rect.w = characterWidth; + rect.h = characterHeight; + + SDL_FillRect(screen, &rect, 255); + + drawCharacter(x, rect.y, 0, 0, 0, tmp); + + x += characterWidth; + + drawCharacter(x, rect.y, 0, 0, 0, 0x01); + + SDL_UpdateRect(screen, rect.x, rect.y, 2 * characterWidth, characterHeight); + } + else + { + rect.x = 0; + rect.y = screenHeight - characterHeight; + rect.w = screenWidth - characterWidth; + rect.h = characterHeight; + + SDL_FillRect(screen, &rect, 255); + + rect.w = characterWidth; + + for (i = 0; i < 39; i++) + { + rect.x = 7 * pixelSize * i; + + if (buffer[(c - 39) + i] == ' ') + SDL_FillRect(screen, &rect, 255); + else + drawCharacter(rect.x, rect.y, 0, 0, 0, buffer[(c - 39) + i]); + } + + SDL_UpdateRect(screen, 0, rect.y, screenWidth - characterWidth, characterHeight); + } + } + } + } + } +} + +static int loadMemoryFunc(void) +{ + int i, length, size; + unsigned int address, value; + unsigned char *fbrut; + + if (step == 1) + { + type = TYPE_CHOICE; + + strcpy(filename, buffer); + + drawString("Choose file format:\nPress 1 for ASCII or 2 for Binary", 0, 192 * getPixelSize() - 16 * getPixelSize()); + } + else if (step == 2) + { + if (choice == 1) + { + choice = 0; + + drawString("Do you want to simulate keyboard input?:\nPress 1 for yes or 2 for no", 0, 192 * getPixelSize() - 16 * getPixelSize()); + } + else + { + type = TYPE_HEXADECIMAL; + max = 4; + + drawString("Enter starting address:", 0, 192 * getPixelSize() - 16 * getPixelSize()); + + return 1; + } + } + else if (step == 3) + { + if (choice == 1 || choice == 2) + { + fp = fopen(filename, "r"); + + if (!fp) + { + fprintf(stderr, "stderr: Could not open \"%s\" for read\n", filename); + return 0; + } + + if (choice == 1) + { + if (isInputFileOpen()) + { + drawString("Do you want to abort the current read?:\nPress 1 for yes or 2 for no", 0, 192 * getPixelSize() - 16 * getPixelSize()); + return 1; + } + + setInputFile(fp, filename); + + return 0; + } + + while (!feof(fp)) + { + if (!fgets(buffer, 1024, fp)) + continue; + + if (buffer[0] == '/') + continue; + + if (buffer[0] != ':') + { + if (isHexDigit(buffer[0])) + { + if (buffer[1] == ':' || buffer[2] == '\0') + i = 2; + else if (isHexDigit(buffer[1])) + { + if (buffer[2] == ':' || buffer[3] == '\0') + i = 3; + else if (isHexDigit(buffer[2])) + { + if (buffer[3] == ':' || buffer[4] == '\0') + i = 4; + else if (isHexDigit(buffer[3])) + { + if (buffer[4] == ':' || buffer[5] == '\0') + i = 5; + else + continue; + } + else + continue; + } + else + continue; + } + else + continue; + } + else + continue; + + sscanf(buffer, "%4X", &address); + + if (buffer[i] == ' ') + i++; + else if (buffer[i] == '\0') + continue; + } + else if (buffer[1] == ' ') + i = 2; + else + i = 1; + + length = strlen(buffer); + + for (; i < length; i += 3) + { + sscanf(&buffer[i], "%2X", &value); + memWrite(address++, value); + } + } + + printf("stdout: Successfully loaded \"%s\"\n", filename); + } + else + { + sscanf(buffer, "%4X", &start); + + fp = fopen(filename, "rb"); + + if (!fp) + { + fprintf(stderr, "stderr: Could not open \"%s\" for write\n", filename); + return 0; + } + + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + + if (size > 65536 || start + size - 1 > 65535) + fprintf(stderr, "stderr: File size too large\n"); + else + { + fbrut = (unsigned char *)malloc(size); + + if (!fbrut) + fprintf(stderr, "stderr: Could not allocate memory block\n"); + else + { + fread(fbrut, 1, size, fp); + setMemory(fbrut, start, size); + printf("stdout: Successfully loaded \"%s\"\n", filename); + } + } + } + + fclose(fp); + + return 0; + } + else if (step == 4) + { + if (choice == 1) + { + closeInputFile(); + printf("stdout: Canceled loading \"%s\"\n", getInputFileName()); + setInputFile(fp, filename); + } + else + fclose(fp); + + return 0; + } + + return 1; +} + +void loadMemory(void) +{ + type = TYPE_STRING; + max = 1024; + + inputLoop("Enter file to load:", &loadMemoryFunc); +} + +static int saveMemoryFunc(void) +{ + int i, j, k, length; + unsigned int end, temp; + unsigned char *fbrut; + char *strFile; + + if (step == 1) + { + type = TYPE_CHOICE; + + strcpy(filename, buffer); + + drawString("Choose file format:\nPress 1 for ASCII or 2 for Binary", 0, 192 * getPixelSize() - 16 * getPixelSize()); + } + else if (step == 2) + { + type = TYPE_HEXADECIMAL; + max = 4; + + drawString("Enter starting address:", 0, 192 * getPixelSize() - 16 * getPixelSize()); + } + else if (step == 3) + { + sscanf(buffer, "%4X", &start); + + drawString("Enter ending address:", 0, 192 * getPixelSize() - 16 * getPixelSize()); + } + else if (step == 4) + { + sscanf(buffer, "%4X", &end); + + if (start > end) + { + temp = start; + start = end; + end = temp; + } + + if (choice == 1) + { + fp = fopen(filename, "w"); + + if (!fp) + { + fprintf(stderr, "stderr: Could not open \"%s\" for write\n", filename); + return 0; + } + + fbrut = dumpMemory(start, end); + + if (fbrut) + { + strcpy(buffer, "// Pom1 Save - "); + + strFile = strrchr(filename, '/'); + + if (!strFile) + { + strFile = strrchr(filename, '\\'); + + if (!strFile) + strFile = filename; + else + strFile++; + } + else + strFile++; + + strcat(buffer, strFile); + + length = end - start + 1; + + for (i = 0, j = start; i < length; i++, k += 3) + { + if (i % 8 == 0) + { + fputs(buffer, fp); + sprintf(buffer, "\n%04X: ", j); + j += 8; + k = 7; + } + + sprintf(&buffer[k], "%02X ", fbrut[i]); + } + + fputs(buffer, fp); + + printf("stdout: Successfully saved \"%s\"\n", filename); + } + } + else + { + fp = fopen(filename, "wb"); + + if (!fp) + { + fprintf(stderr, "stderr: Could not open \"%s\" for write\n", filename); + return 0; + } + + fbrut = dumpMemory(start, end); + + if (fbrut) { + fwrite(fbrut, 1, end - start + 1, fp); + printf("stdout: Successfully saved \"%s\"\n", filename); + } + } + + free(fbrut); + + fclose(fp); + + return 0; + } + + return 1; +} + +void saveMemory(void) +{ + type = TYPE_STRING; + max = 1024; + + inputLoop("Enter file to save:", &saveMemoryFunc); +} + +static int changePixelSizeFunc(void) +{ + setPixelSize(choice); + printf("stdout: pixelSize=%d\n", getPixelSize()); + + if (choice == 1) + setScanlines(0); + + SDL_SetVideoMode(280 * getPixelSize(), 192 * getPixelSize(), 8, SDL_HWSURFACE | (getFullscreen() ? SDL_FULLSCREEN : 0)); + + return 0; +} + +void changePixelSize(void) +{ + type = TYPE_CHOICE; + + inputLoop("Choose pixel size:\nPress 1 for 1x or 2 for 2x", &changePixelSizeFunc); +} + +static int changeTerminalSpeedFunc(void) +{ + int terminalSpeed = atoi(buffer); + + if (terminalSpeed < 1 || terminalSpeed > 120) + fprintf(stderr, "stderr: Terminal speed out of range\n"); + else + { + setTerminalSpeed(terminalSpeed); + printf("stdout: terminalSpeed=%d\n", getTerminalSpeed()); + } + + return 0; +} + +void changeTerminalSpeed(void) +{ + type = TYPE_DECIMAL; + max = 3; + + inputLoop("Enter terminal speed (Range: 1 - 120):", &changeTerminalSpeedFunc); +} + +static int setIrqBrkVectorFunc(void) +{ + unsigned int brkVector; + + sscanf(buffer, "%4X", &brkVector); + memWrite(0xFFFE, (unsigned char)brkVector); + memWrite(0xFFFF, (unsigned char)(brkVector >> 8)); + printf("stdout: brkVector=%s\n", buffer); + + return 0; +} + +void setIrqBrkVector(void) +{ + type = TYPE_HEXADECIMAL; + max = 4; + + inputLoop("Enter IRQ/BRK vector:", &setIrqBrkVectorFunc); +} + +void showAbout(void) +{ + SDL_Event event; + SDL_Rect rect; + SDL_Surface *screen = SDL_GetVideoSurface(); + int screenWidth = screen->w, screenHeight = screen->h; + int pixelSize = getPixelSize(); + int characterWidth = 7 * pixelSize, characterHeight = 8 * pixelSize; + + rect.x = (screenWidth - (36 * characterWidth)) / 2; + rect.y = (screenHeight - (10 * characterHeight)) / 2; + rect.w = 36 * characterWidth; + rect.h = 10 * characterHeight; + + SDL_FillRect(screen, &rect, 255); + + drawString(PACKAGE_NAME, (screenWidth - strlen(PACKAGE_NAME) * characterWidth) / 2, rect.y + characterHeight); + drawString(PACKAGE_VERSION, (screenWidth - strlen(PACKAGE_VERSION) * characterWidth) / 2, rect.y + 3 * characterHeight); + drawString("Copyright (C) 2000 Verhille Arnaud", (screenWidth - 34 * characterWidth) / 2, rect.y + 5 * characterHeight); + drawString("Copyright (C) 2012 John D. Corrado", (screenWidth - 34 * characterWidth) / 2, rect.y + 6 * characterHeight); + drawString("Press Esc to continue", (screenWidth - 21 * characterWidth) / 2, rect.y + 8 * characterHeight); + + SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h); + + while (1) + { + while (SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.mod & KMOD_CTRL && event.key.keysym.sym == SDLK_q)) + exit(0); + + if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE) + { + redrawScreen(); + return; + } + } + } +} diff --git a/src/options.h b/src/options.h new file mode 100644 index 0000000..205feeb --- /dev/null +++ b/src/options.h @@ -0,0 +1,29 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __OPTIONS_H__ +#define __OPTIONS_H__ + +void loadMemory(void); +void saveMemory(void); +void changePixelSize(void); +void changeTerminalSpeed(void); +void setIrqBrkVector(void); +void showAbout(void); + +#endif diff --git a/src/pia6820.c b/src/pia6820.c new file mode 100644 index 0000000..5f717d8 --- /dev/null +++ b/src/pia6820.c @@ -0,0 +1,72 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +static unsigned char _dspCr = 0, _dsp = 0, _kbdCr = 0, _kbd = 0x80; + +void resetPia6820(void) +{ + _kbdCr = _dspCr = _dsp = 0; + _kbd = 0x80; +} + +void writeDspCr(unsigned char dspCr) +{ + _dspCr = dspCr; +} + +void writeDsp(unsigned char dsp) +{ + if (!(_dspCr & 0x04)) + return; + + _dsp = dsp; +} + +void writeKbdCr(unsigned char kbdCr) +{ + if (!_kbdCr) + kbdCr = 0x27; + + _kbdCr = kbdCr; +} + +void writeKbd(unsigned char kbd) +{ + _kbd = kbd; +} + +unsigned char readDspCr(void) +{ + return _dspCr; +} + +unsigned char readDsp(void) +{ + return _dsp; +} + +unsigned char readKbdCr(void) +{ + return _kbdCr; +} + +unsigned char readKbd(void) +{ + _kbdCr = 0x27; + return _kbd; +} diff --git a/src/pia6820.h b/src/pia6820.h new file mode 100644 index 0000000..9db8e84 --- /dev/null +++ b/src/pia6820.h @@ -0,0 +1,32 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __PIA6820_H__ +#define __PIA6820_H__ + +void resetPia6820(void); +void writeDspCr(unsigned char dspCr); +void writeDsp(unsigned char dsp); +void writeKbdCr(unsigned char kbdCr); +void writeKbd(unsigned char kbd); +unsigned char readDspCr(void); +unsigned char readDsp(void); +unsigned char readKbdCr(void); +unsigned char readKbd(void); + +#endif diff --git a/src/pom1.desktop.in b/src/pom1.desktop.in new file mode 100644 index 0000000..8568d7a --- /dev/null +++ b/src/pom1.desktop.in @@ -0,0 +1,7 @@ +[Desktop Entry] +Name=@PACKAGE_NAME@ +Exec=pom1 +Icon=pom1 +Type=Application +Comment=@PACKAGE_SHORTDESC@ +Categories=Emulator; diff --git a/src/pom1.in b/src/pom1.in new file mode 100644 index 0000000..4b1059f --- /dev/null +++ b/src/pom1.in @@ -0,0 +1,5 @@ +#!/bin/sh + +export POM1ROMDIR="@prefix@/share/@PACKAGE@/roms" + +pom1-@PACKAGE_VERSION@ $@ diff --git a/src/pom1.png b/src/pom1.png new file mode 100644 index 0000000..35d8eea Binary files /dev/null and b/src/pom1.png differ diff --git a/src/roms/.gitignore b/src/roms/.gitignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/src/roms/.gitignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/src/roms/Makefile.am b/src/roms/Makefile.am new file mode 100644 index 0000000..121f2c0 --- /dev/null +++ b/src/roms/Makefile.am @@ -0,0 +1,9 @@ +ROMFILES = \ + basic.rom \ + charmap.rom \ + monitor.rom + +romdir = $(prefix)/share/@PACKAGE@/roms +rom_DATA = $(ROMFILES) + +EXTRA_DIST = $(ROMFILES) diff --git a/src/roms/basic.rom b/src/roms/basic.rom new file mode 100644 index 0000000..cdd0fb5 Binary files /dev/null and b/src/roms/basic.rom differ diff --git a/src/roms/charmap.rom b/src/roms/charmap.rom new file mode 100644 index 0000000..dd087a8 Binary files /dev/null and b/src/roms/charmap.rom differ diff --git a/src/roms/monitor.rom b/src/roms/monitor.rom new file mode 100644 index 0000000..7280907 Binary files /dev/null and b/src/roms/monitor.rom differ diff --git a/src/screen.c b/src/screen.c new file mode 100644 index 0000000..d642850 --- /dev/null +++ b/src/screen.c @@ -0,0 +1,283 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "SDL.h" +#include "configuration.h" +#include "pia6820.h" + +static unsigned char charac[1024], screenTbl[960]; +static int indexX, indexY, pixelSize = 2, _scanlines = 0, terminalSpeed = 60; +static long lastTime; +static int _fullscreen = 0; +static int _blinkCursor = 1, _blockCursor = 0; +static SDL_Surface *screen; + +int loadCharMap(void) +{ + const char *romdir = getRomDirectory(); + char *filename; + FILE *fp; + + filename = (char *)malloc(strlen(romdir) + 13); + sprintf(filename, "%s/charmap.rom", romdir); + + fp = fopen(filename, "rb"); + + free(filename); + + if (fp) + { + fread(charac, 1, 1024, fp); + fclose(fp); + } + else + return 0; + + return 1; +} + +void setPixelSize(int ps) +{ + pixelSize = ps; +} + +int getPixelSize(void) +{ + return pixelSize; +} + +void setScanlines(int scanlines) +{ + _scanlines = scanlines; +} + +int getScanlines(void) +{ + return _scanlines; +} + +void setTerminalSpeed(int ts) +{ + terminalSpeed = ts; +} + +int getTerminalSpeed(void) +{ + return terminalSpeed; +} + +static void synchronizeOutput(void) +{ + int sleepMillis = ((1000 / terminalSpeed) - (SDL_GetTicks() - lastTime)); + + if (sleepMillis > 0) + SDL_Delay(sleepMillis); + + lastTime = SDL_GetTicks(); +} + +static void newLine(void) +{ + memcpy(&screenTbl, &screenTbl[40], 920); + memset(&screenTbl[920], 0, 40); +} + +static void outputDsp(unsigned char dsp) +{ + unsigned char tmp; + + dsp &= 0x7F; + + tmp = dsp; + + if (dsp >= 0x60 && dsp <= 0x7F) + tmp &= 0x5F; + + switch (tmp) + { + case 0x0D: + indexX = 0; + indexY++; + break; + default: + if (tmp >= 0x20 && tmp <= 0x5F) + { + screenTbl[indexY * 40 + indexX] = tmp; + indexX++; + } + break; + } + + if (indexX == 40) + { + indexX = 0; + indexY++; + } + if (indexY == 24) + { + newLine(); + indexY--; + } + + writeDsp(dsp); +} + +static void drawCharac(int xPosition, int yPosition, unsigned char r, unsigned char g, unsigned char b, unsigned char characNumber) +{ + SDL_Rect rect; + int k, l; + + for (k = 0; k < 8; k++) + { + for (l = 1; l < 8; l++) + { + if (charac[characNumber * 8 + k] & (0x01 << l)) + { + rect.x = xPosition + pixelSize * (l - 1); + rect.y = yPosition + pixelSize * k; + rect.w = pixelSize; + rect.h = pixelSize - (_scanlines ? 1 : 0); + + SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, r, g, b)); + } + } + } +} + +void setFullscreen(int fullscreen) +{ + _fullscreen = fullscreen; +} + +int getFullscreen() +{ + return _fullscreen; +} + +void setBlinkCursor(int blinkCursor) +{ + _blinkCursor = blinkCursor; +} + +int getBlinkCursor(void) +{ + return _blinkCursor; +} + +void setBlockCursor(int blockCursor) +{ + _blockCursor = blockCursor; +} + +int getBlockCursor(void) +{ + return _blockCursor; +} + +static void drawBlinkingCursor(void) +{ + static int clearCursor = 0; + static long lastTime = 0; + + SDL_Rect rect; + + if ((SDL_GetTicks() - lastTime) > 500) + { + lastTime = SDL_GetTicks(); + + rect.x = indexX * pixelSize * 7; + rect.y = indexY * pixelSize * 8; + rect.w = pixelSize * 7; + rect.h = pixelSize * 8; + + if (clearCursor) + SDL_FillRect(screen, &rect, 0); + else + drawCharac(rect.x, rect.y, 0, 255, 0, (unsigned char)(_blockCursor ? 0x01 : 0x40)); + + SDL_UpdateRect(screen, rect.x, rect.y, rect.w, rect.h); + + clearCursor = !clearCursor; + } +} + +void redrawScreen(void) +{ + int xPosition, yPosition; + int i, j; + + SDL_FillRect(screen, NULL, 0); + + for (i = 0; i < 40; i++) + { + for (j = 0; j < 24; j++) + { + xPosition = i * pixelSize * 7; + yPosition = j * pixelSize * 8; + + drawCharac(xPosition, yPosition, 0, 255, 0, screenTbl[j * 40 + i]); + } + } + + if (!_blinkCursor) + drawCharac(indexX * pixelSize * 7, indexY * pixelSize * 8, 0, 255, 0, (unsigned char)(_blockCursor ? 0x01 : 0x40)); + + SDL_UpdateRect(screen, 0, 0, 0, 0); +} + +void resetScreen(void) +{ + indexX = indexY = 0; + + memset(screenTbl, 0, 960); + + lastTime = SDL_GetTicks(); + + redrawScreen(); +} + +void updateScreen(void) +{ + unsigned char dsp = readDsp(); + + if (dsp & 0x80) + { + outputDsp(dsp); + redrawScreen(); + synchronizeOutput(); + } + else if (_blinkCursor) + drawBlinkingCursor(); +} + +void drawCharacter(int xPosition, int yPosition, unsigned char r, unsigned char g, unsigned char b, unsigned char characNumber) +{ + if (_scanlines) + { + _scanlines = 0; + drawCharac(xPosition, yPosition, 0, 0, 0, characNumber); + _scanlines = 1; + } + else + drawCharac(xPosition, yPosition, 0, 0, 0, characNumber); +} + +void initScreen(void) +{ + screen = SDL_GetVideoSurface(); +} diff --git a/src/screen.h b/src/screen.h new file mode 100644 index 0000000..f64e16b --- /dev/null +++ b/src/screen.h @@ -0,0 +1,42 @@ +// Pom1 Apple 1 Emulator +// Copyright (C) 2000 Verhille Arnaud +// Copyright (C) 2012 John D. Corrado +// +// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef __SCREEN_H__ +#define __SCREEN_H__ + +int loadCharMap(void); +void resetScreen(void); +void setPixelSize(int ps); +int getPixelSize(void); +void setScanlines(int scanlines); +int getScanlines(void); +void setTerminalSpeed(int ts); +int getTerminalSpeed(void); +void redrawScreen(void); +void updateScreen(void); +void drawCharacter(int xPosition, int yPosition, unsigned char r, unsigned char g, unsigned char b, unsigned char characNumber); +void setFullscreen(int fullscreen); +int getFullscreen(void); +void drawCursor(void); +void setBlinkCursor(int blickCursor); +int getBlinkCursor(void); +void setBlockCursor(int blockCursor); +int getBlockCursor(void); +void initScreen(void); + +#endif