diff options
77 files changed, 13162 insertions, 0 deletions
diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..a4fec3d --- /dev/null +++ b/.cvsignore @@ -0,0 +1,13 @@ +.emacs.desktop +Makefile +Makefile.in +config.cache +config.h +config.h.in +config.log +config.status +configure +intl +mdk-0.1.tar.gz +stamp-h +stamp-h.in @@ -0,0 +1,4 @@ +Authors of mdk. +See also the files THANKS and ChangeLog. + +jose antonio ortega ruiz designed and implemented mdk. @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 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..e69de29 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,179 @@ +Basic Installation +================== + + For more information specific to this package, please read the README +file. This source code distribution is autoconfiguring and you should be +able to compile it and install it without manual interventions such as +editing Makefiles, configuration files, and so on. These are generic +instructions for people who are not familiar with installing autoconfiguring +software. + +The simplest way to compile this package is to enter the source code +main directory and do the following: + + 1. Configure the source code by typing: + % sh ./configure + + If you're planning to install the package into your home directory + or to a location other than `/usr/local' then add the flag + `--prefix=PATH' to `configure'. For example, if your home directory + is `/home/luser' you can configure the package to install itself there + by invoking: + % sh ./configure --prefix=/home/luser + + While running, `configure' prints some messages telling which + features is it checking for. + + 2. Compile the package by typing: + % make + Running `make' takes a while. If this is a very large package, now + is the time to go make some coffee. + + 3. Some packages are bundled with self-tests for source-code + verification. If this package includes such tests, you can + optionally run them after compilation by typing + % make check + + 4. Type `make install' to install the programs and any data files and + documentation. Type `make uninstall' to undo the installation. + During installation, the following files go to the following directories: + Executables -> /prefix/bin + Libraries -> /prefix/lib + Public header files -> /prefix/include + Man pages -> /prefix/man/man? + Info files -> /prefix/info + where `prefix' is either `/usr/local' or the PATH that you specified + in the `--prefix' flag. + + If any of these directories do not presently exist, they will be + created on demand. + + If you are installing in your home directory make sure that + `/home/luser/bin' is in your path. If you're using the bash shell + add this line at the end of your .cshrc file: + PATH="/home/luser/bin:${PATH}" + export PATH + If you are using csh or tcsh, then use this line instead: + setenv PATH /home/luser/bin:${PATH} + By prepending your home directory to the rest of the PATH you can + override systemwide installed software with your own custom installation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. + +Compiler configuration +====================== + + The `configure' shell script is responsible for choosing and configuring +the compiler(s). + +The following options allow you to specify whether you +want to enable or disable various debugging mechanisms: + +`--with-warnings' + Make the compilers very picky about warnings. Try this whenever you + write new code since it may catch a few bugs. This is not active by + default because all too often warnings can be too picky and scare + the end-user. + +`--disable-assert' + Compile without using assertions. This results in faster code, + but should not be used during developerment, or to run `make check' + which depends on assertions. It should only be used for production + runs on code that you believe is bug free. + +All programs are compiled with optimization level 2 by default (-O2). +Occasionally that confuses the debugger when code is inlined. To disable +optimization and enable debugging, set the shell environment variables +CFLAGS, CXXFLAGS, FFLAGS to `-g'. On the bash shell, you can do this +like this: + $ export CFLAGS="-g" + $ export CXXFLAGS="-g" + $ export FFLAGS="-g" +On the tcsh shell, use the `setenv' command instead: + % setenv CFLAGS "-g" + ...etc... +For other shell, please consult your shell's documentation. + +Similarly, you can increase the optimization level by assigning these +variables to "-g -O3". + +The following options allow you to reconsider the `configure' shell script's +choice of Fortran compilers. + +`--with-f2c' + Compile the Fortran code by translating it to C, even if a native + Fortran compiler is available. A copy of the f2c translator should be + bundled in the distribution. It will be compiled and then used to + compile your Fortran code. +`--with-g77' + Compile the Fortran code with g77 even if a proprietary Fortran + compiler is available +`--with-f77=F77' + Compile the Fortran code with the specified Fortran compiler. + +Depending on what languages the package uses, some of these options may +or may not be available. To see what is available, type: + % sh ./configure --help + +About the configure script +========================== + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +Advanced installation options. +============================== + + The `configure' script also understands the following more advanced +options, to handle situations for which `--prefix' alone is not sufficient. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..c57ce00 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,15 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Jose Antonio Ortega Ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +EXTRA_DIST = ABOUT-NLS autogen.sh configure +SUBDIRS = po intl doc mixlib mixutils samples + @@ -0,0 +1,26 @@ +mdk -- History of visible changes. + +Copyright (C) 2000, jose antonio ortega ruiz <jaortega@acm.org> +See the end for copying conditions. + +Please send mdk bug reports to jaortega@acm.org. + +Version 0.1 + +* Initial version + +------------------------------------------------------- +Copying information: + +Copyright (C) 2000, jose antonio ortega ruiz <jaortega@acm.org> + + Permission is granted to anyone to make or distribute verbatim copies + of this document as received, in any medium, provided that the + copyright notice and this permission notice are preserved, + thus giving the recipient permission to redistribute in turn. + + Permission is granted to distribute modified versions + of this document, or of portions of it, + under the above conditions, provided also that they + carry prominent notices stating who last changed them. + @@ -0,0 +1,20 @@ +Welcome to MDK. + +MDK stands for MIX Development Kit and provides tools for developing +and executing, in a MIX virtual machine, MIXAL programs. The MIX +is Donald Knuth's mythical computer, described in the first volume +of _The Art of Computer Programming_ (Addison Wesley, 1997), which +is programmed using MIXAL, the MIX Assembly language. + +Currently, MDK includes a MIXAL assembler, mixasm, and a MIX virtual +machine, mixvm, with a command line interface. + +MDK is free software. Please see the file COPYING for details. +For documentation, please see the files in the doc subdirectory. +For building and installation instructions please see the INSTALL file. +For sample MIXAL programs, please see the samples subdirectory. +For translations (MDK uses GNU's gettext), please see the po subdirectory[0]. + +-- +[0] New translations are welcome. If you'd like to contribute one, + please contact the author, jaortega@acm.org.
\ No newline at end of file @@ -0,0 +1,8 @@ +MDK THANKS file + +MDK has originally been written by jose antonio ortega ruiz. +Many people have further contributed to MDK by reporting problems, +suggesting various improvements, or submitting actual code. Here is +a list of these people. Help me keep it complete and exempt of errors. + +* nobody yet :-) @@ -0,0 +1,11 @@ +- mixvm trace command outputting executed instructions +- allow MIXAL instructions as commands at the mixvm prompt + (e.g. MIX > exec LDA 2000) +- improve detection of pseudoinstructions in mixasm listing files +- include timing statistics + +* allow abbrevs of mixvm commands (e.g. ed file -> edit file) +* ncurses based frontend +* add GTK/GNOME support (see gaby's config hacks for making it optional) + + diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..06f5f49 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,10 @@ +#undef PACKAGE +#undef VERSION +#undef HAVE_LIBSM +#undef HAVE_CATGETS +#undef HAVE_GETTEXT +#undef HAVE_LC_MESSAGES +#undef HAVE_STPCPY +#undef ENABLE_NLS +#undef LOCALEDIR + diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..bd51429 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,838 @@ +dnl aclocal.m4 generated automatically by aclocal 1.4 + +dnl Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AC_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) +AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Add --enable-maintainer-mode option to configure. +# From Jim Meyering + +# serial 1 + +AC_DEFUN(AM_MAINTAINER_MODE, +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT($USE_MAINTAINER_MODE) + AM_CONDITIONAL(MAINTAINER_MODE, test $USE_MAINTAINER_MODE = yes) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +# Define a conditional. + +AC_DEFUN(AM_CONDITIONAL, +[AC_SUBST($1_TRUE) +AC_SUBST($1_FALSE) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi]) + + +# serial 1 + +# @defmac AC_PROG_CC_STDC +# @maindex PROG_CC_STDC +# @ovindex CC +# If the C compiler in not in ANSI C mode by default, try to add an option +# to output variable @code{CC} to make it so. This macro tries various +# options that select ANSI C on some system or another. It considers the +# compiler to be in ANSI C mode if it handles function prototypes correctly. +# +# If you use this macro, you should check after calling it whether the C +# compiler has been set to accept ANSI C; if not, the shell variable +# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source +# code in ANSI C, you can make an un-ANSIfied copy of it by using the +# program @code{ansi2knr}, which comes with Ghostscript. +# @end defmac + +AC_DEFUN(AM_PROG_CC_STDC, +[AC_REQUIRE([AC_PROG_CC]) +AC_BEFORE([$0], [AC_C_INLINE]) +AC_BEFORE([$0], [AC_C_CONST]) +dnl Force this before AC_PROG_CPP. Some cpp's, eg on HPUX, require +dnl a magic option to avoid problems with ANSI preprocessor commands +dnl like #elif. +dnl FIXME: can't do this because then AC_AIX won't work due to a +dnl circular dependency. +dnl AC_BEFORE([$0], [AC_PROG_CPP]) +AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C) +AC_CACHE_VAL(am_cv_prog_cc_stdc, +[am_cv_prog_cc_stdc=no +ac_save_CC="$CC" +# Don't try gcc -ansi; that turns off useful extensions and +# breaks some systems' header files. +# AIX -qlanglvl=ansi +# Ultrix and OSF/1 -std1 +# HP-UX -Aa -D_HPUX_SOURCE +# SVR4 -Xc -D__EXTENSIONS__ +for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + AC_TRY_COMPILE( +[#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +], [ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; +], +[am_cv_prog_cc_stdc="$ac_arg"; break]) +done +CC="$ac_save_CC" +]) +if test -z "$am_cv_prog_cc_stdc"; then + AC_MSG_RESULT([none needed]) +else + AC_MSG_RESULT($am_cv_prog_cc_stdc) +fi +case "x$am_cv_prog_cc_stdc" in + x|xno) ;; + *) CC="$CC $am_cv_prog_cc_stdc" ;; +esac +]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + +# Macro to add for using GNU gettext. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 5 + +AC_DEFUN(AM_WITH_NLS, + [AC_MSG_CHECKING([whether NLS is requested]) + dnl Default is enabled NLS + AC_ARG_ENABLE(nls, + [ --disable-nls do not use Native Language Support], + USE_NLS=$enableval, USE_NLS=yes) + AC_MSG_RESULT($USE_NLS) + AC_SUBST(USE_NLS) + + USE_INCLUDED_LIBINTL=no + + dnl If we use NLS figure out what method + if test "$USE_NLS" = "yes"; then + AC_DEFINE(ENABLE_NLS) + AC_MSG_CHECKING([whether included gettext is requested]) + AC_ARG_WITH(included-gettext, + [ --with-included-gettext use the GNU gettext library included here], + nls_cv_force_use_gnu_gettext=$withval, + nls_cv_force_use_gnu_gettext=no) + AC_MSG_RESULT($nls_cv_force_use_gnu_gettext) + + nls_cv_use_gnu_gettext="$nls_cv_force_use_gnu_gettext" + if test "$nls_cv_force_use_gnu_gettext" != "yes"; then + dnl User does not insist on using GNU NLS library. Figure out what + dnl to use. If gettext or catgets are available (in this order) we + dnl use this. Else we have to fall back to GNU NLS library. + dnl catgets is only used if permitted by option --with-catgets. + nls_cv_header_intl= + nls_cv_header_libgt= + CATOBJEXT=NONE + + AC_CHECK_HEADER(libintl.h, + [AC_CACHE_CHECK([for gettext in libc], gt_cv_func_gettext_libc, + [AC_TRY_LINK([#include <libintl.h>], [return (int) gettext ("")], + gt_cv_func_gettext_libc=yes, gt_cv_func_gettext_libc=no)]) + + if test "$gt_cv_func_gettext_libc" != "yes"; then + AC_CHECK_LIB(intl, bindtextdomain, + [AC_CACHE_CHECK([for gettext in libintl], + gt_cv_func_gettext_libintl, + [AC_CHECK_LIB(intl, gettext, + gt_cv_func_gettext_libintl=yes, + gt_cv_func_gettext_libintl=no)], + gt_cv_func_gettext_libintl=no)]) + fi + + if test "$gt_cv_func_gettext_libc" = "yes" \ + || test "$gt_cv_func_gettext_libintl" = "yes"; then + AC_DEFINE(HAVE_GETTEXT) + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no)dnl + if test "$MSGFMT" != "no"; then + AC_CHECK_FUNCS(dcgettext) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_TRY_LINK(, [extern int _nl_msg_cat_cntr; + return _nl_msg_cat_cntr], + [CATOBJEXT=.gmo + DATADIRNAME=share], + [CATOBJEXT=.mo + DATADIRNAME=lib]) + INSTOBJEXT=.mo + fi + fi + ]) + + if test "$CATOBJEXT" = "NONE"; then + AC_MSG_CHECKING([whether catgets can be used]) + AC_ARG_WITH(catgets, + [ --with-catgets use catgets functions if available], + nls_cv_use_catgets=$withval, nls_cv_use_catgets=no) + AC_MSG_RESULT($nls_cv_use_catgets) + + if test "$nls_cv_use_catgets" = "yes"; then + dnl No gettext in C library. Try catgets next. + AC_CHECK_LIB(i, main) + AC_CHECK_FUNC(catgets, + [AC_DEFINE(HAVE_CATGETS) + INTLOBJS="\$(CATOBJS)" + AC_PATH_PROG(GENCAT, gencat, no)dnl + if test "$GENCAT" != "no"; then + AC_PATH_PROG(GMSGFMT, gmsgfmt, no) + if test "$GMSGFMT" = "no"; then + AM_PATH_PROG_WITH_TEST(GMSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], no) + fi + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.cat + INSTOBJEXT=.cat + DATADIRNAME=lib + INTLDEPS='$(top_builddir)/intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=intl/libintl.h + nls_cv_header_libgt=intl/libgettext.h + fi]) + fi + fi + + if test "$CATOBJEXT" = "NONE"; then + dnl Neither gettext nor catgets in included in the C library. + dnl Fall back on GNU gettext library. + nls_cv_use_gnu_gettext=yes + fi + fi + + if test "$nls_cv_use_gnu_gettext" = "yes"; then + dnl Mark actions used to generate GNU NLS library. + INTLOBJS="\$(GETTOBJS)" + AM_PATH_PROG_WITH_TEST(MSGFMT, msgfmt, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep 'dv '`"], msgfmt) + AC_PATH_PROG(GMSGFMT, gmsgfmt, $MSGFMT) + AM_PATH_PROG_WITH_TEST(XGETTEXT, xgettext, + [test -z "`$ac_dir/$ac_word -h 2>&1 | grep '(HELP)'`"], :) + AC_SUBST(MSGFMT) + USE_INCLUDED_LIBINTL=yes + CATOBJEXT=.gmo + INSTOBJEXT=.mo + DATADIRNAME=share + INTLDEPS='$(top_builddir)/intl/libintl.a' + INTLLIBS=$INTLDEPS + LIBS=`echo $LIBS | sed -e 's/-lintl//'` + nls_cv_header_intl=intl/libintl.h + nls_cv_header_libgt=intl/libgettext.h + fi + + dnl Test whether we really found GNU xgettext. + if test "$XGETTEXT" != ":"; then + dnl If it is no GNU xgettext we define it as : so that the + dnl Makefiles still can work. + if $XGETTEXT --omit-header /dev/null 2> /dev/null; then + : ; + else + AC_MSG_RESULT( + [found xgettext program is not GNU xgettext; ignore it]) + XGETTEXT=":" + fi + fi + + # We need to process the po/ directory. + POSUB=po + else + DATADIRNAME=share + nls_cv_header_intl=intl/libintl.h + nls_cv_header_libgt=intl/libgettext.h + fi + AC_LINK_FILES($nls_cv_header_libgt, $nls_cv_header_intl) + AC_OUTPUT_COMMANDS( + [case "$CONFIG_FILES" in *po/Makefile.in*) + sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile + esac]) + + + # If this is used in GNU gettext we have to set USE_NLS to `yes' + # because some of the sources are only built for this goal. + if test "$PACKAGE" = gettext; then + USE_NLS=yes + USE_INCLUDED_LIBINTL=yes + fi + + dnl These rules are solely for the distribution goal. While doing this + dnl we only have to keep exactly one list of the available catalogs + dnl in configure.in. + for lang in $ALL_LINGUAS; do + GMOFILES="$GMOFILES $lang.gmo" + POFILES="$POFILES $lang.po" + done + + dnl Make all variables we use known to autoconf. + AC_SUBST(USE_INCLUDED_LIBINTL) + AC_SUBST(CATALOGS) + AC_SUBST(CATOBJEXT) + AC_SUBST(DATADIRNAME) + AC_SUBST(GMOFILES) + AC_SUBST(INSTOBJEXT) + AC_SUBST(INTLDEPS) + AC_SUBST(INTLLIBS) + AC_SUBST(INTLOBJS) + AC_SUBST(POFILES) + AC_SUBST(POSUB) + ]) + +AC_DEFUN(AM_GNU_GETTEXT, + [AC_REQUIRE([AC_PROG_MAKE_SET])dnl + AC_REQUIRE([AC_PROG_CC])dnl + AC_REQUIRE([AC_PROG_RANLIB])dnl + AC_REQUIRE([AC_ISC_POSIX])dnl + AC_REQUIRE([AC_HEADER_STDC])dnl + AC_REQUIRE([AC_C_CONST])dnl + AC_REQUIRE([AC_C_INLINE])dnl + AC_REQUIRE([AC_TYPE_OFF_T])dnl + AC_REQUIRE([AC_TYPE_SIZE_T])dnl + AC_REQUIRE([AC_FUNC_ALLOCA])dnl + AC_REQUIRE([AC_FUNC_MMAP])dnl + + AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h string.h \ +unistd.h sys/param.h]) + AC_CHECK_FUNCS([getcwd munmap putenv setenv setlocale strchr strcasecmp \ +strdup __argz_count __argz_stringify __argz_next]) + + if test "${ac_cv_func_stpcpy+set}" != "set"; then + AC_CHECK_FUNCS(stpcpy) + fi + if test "${ac_cv_func_stpcpy}" = "yes"; then + AC_DEFINE(HAVE_STPCPY) + fi + + AM_LC_MESSAGES + AM_WITH_NLS + + if test "x$CATOBJEXT" != "x"; then + if test "x$ALL_LINGUAS" = "x"; then + LINGUAS= + else + AC_MSG_CHECKING(for catalogs to be installed) + NEW_LINGUAS= + for lang in ${LINGUAS=$ALL_LINGUAS}; do + case "$ALL_LINGUAS" in + *$lang*) NEW_LINGUAS="$NEW_LINGUAS $lang" ;; + esac + done + LINGUAS=$NEW_LINGUAS + AC_MSG_RESULT($LINGUAS) + fi + + dnl Construct list of names of catalog files to be constructed. + if test -n "$LINGUAS"; then + for lang in $LINGUAS; do CATALOGS="$CATALOGS $lang$CATOBJEXT"; done + fi + fi + + dnl The reference to <locale.h> in the installed <libintl.h> file + dnl must be resolved because we cannot expect the users of this + dnl to define HAVE_LOCALE_H. + if test $ac_cv_header_locale_h = yes; then + INCLUDE_LOCALE_H="#include <locale.h>" + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header <locale.h>. Take care yourself. */" + fi + AC_SUBST(INCLUDE_LOCALE_H) + + dnl Determine which catalog format we have (if any is needed) + dnl For now we know about two different formats: + dnl Linux libc-5 and the normal X/Open format + test -d intl || mkdir intl + if test "$CATOBJEXT" = ".cat"; then + AC_CHECK_HEADER(linux/version.h, msgformat=linux, msgformat=xopen) + + dnl Transform the SED scripts while copying because some dumb SEDs + dnl cannot handle comments. + sed -e '/^#/d' $srcdir/intl/$msgformat-msg.sed > intl/po2msg.sed + fi + dnl po2tbl.sed is always needed. + sed -e '/^#.*[^\\]$/d' -e '/^#$/d' \ + $srcdir/intl/po2tbl.sed.in > intl/po2tbl.sed + + dnl In the intl/Makefile.in we have a special dependency which makes + dnl only sense for gettext. We comment this out for non-gettext + dnl packages. + if test "$PACKAGE" = "gettext"; then + GT_NO="#NO#" + GT_YES= + else + GT_NO= + GT_YES="#YES#" + fi + AC_SUBST(GT_NO) + AC_SUBST(GT_YES) + + dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we possibly + dnl find the mkinstalldirs script in another subdir but ($top_srcdir). + dnl Try to locate is. + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + AC_SUBST(MKINSTALLDIRS) + + dnl *** For now the libtool support in intl/Makefile is not for real. + l= + AC_SUBST(l) + + dnl Generate list of files to be processed by xgettext which will + dnl be included in po/Makefile. + test -d po || mkdir po + if test "x$srcdir" != "x."; then + if test "x`echo $srcdir | sed 's@/.*@@'`" = "x"; then + posrcprefix="$srcdir/" + else + posrcprefix="../$srcdir/" + fi + else + posrcprefix="../" + fi + rm -f po/POTFILES + sed -e "/^#/d" -e "/^\$/d" -e "s,.*, $posrcprefix& \\\\," -e "\$s/\(.*\) \\\\/\1/" \ + < $srcdir/po/POTFILES.in > po/POTFILES + ]) + +# Search path for a program which passes the given test. +# Ulrich Drepper <drepper@cygnus.com>, 1996. +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR, +dnl TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]]) +AC_DEFUN(AM_PATH_PROG_WITH_TEST, +[# Extract the first word of "$2", so it can be a program name with args. +set dummy $2; ac_word=[$]2 +AC_MSG_CHECKING([for $ac_word]) +AC_CACHE_VAL(ac_cv_path_$1, +[case "[$]$1" in + /*) + ac_cv_path_$1="[$]$1" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in ifelse([$5], , $PATH, [$5]); do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if [$3]; then + ac_cv_path_$1="$ac_dir/$ac_word" + break + fi + fi + done + IFS="$ac_save_ifs" +dnl If no 4th arg is given, leave the cache variable unset, +dnl so AC_PATH_PROGS will keep looking. +ifelse([$4], , , [ test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4" +])dnl + ;; +esac])dnl +$1="$ac_cv_path_$1" +if test -n "[$]$1"; then + AC_MSG_RESULT([$]$1) +else + AC_MSG_RESULT(no) +fi +AC_SUBST($1)dnl +]) + +# Check whether LC_MESSAGES is available in <locale.h>. +# Ulrich Drepper <drepper@cygnus.com>, 1995. +# +# This file can be copied and used freely without restrictions. It can +# be used in projects which are not available under the GNU Public License +# but which still want to provide support for the GNU gettext functionality. +# Please note that the actual code is *not* freely available. + +# serial 1 + +AC_DEFUN(AM_LC_MESSAGES, + [if test $ac_cv_header_locale_h = yes; then + AC_CACHE_CHECK([for LC_MESSAGES], am_cv_val_LC_MESSAGES, + [AC_TRY_LINK([#include <locale.h>], [return LC_MESSAGES], + am_cv_val_LC_MESSAGES=yes, am_cv_val_LC_MESSAGES=no)]) + if test $am_cv_val_LC_MESSAGES = yes; then + AC_DEFINE(HAVE_LC_MESSAGES) + fi + fi]) + +# Configure paths for GLIB +# Owen Taylor 97-11-3 + +dnl AM_PATH_GLIB([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if "gmodule" or +dnl gthread is specified in MODULES, pass to glib-config +dnl +AC_DEFUN(AM_PATH_GLIB, +[dnl +dnl Get the cflags and libraries from the glib-config script +dnl +AC_ARG_WITH(glib-prefix,[ --with-glib-prefix=PFX Prefix where GLIB is installed (optional)], + glib_config_prefix="$withval", glib_config_prefix="") +AC_ARG_WITH(glib-exec-prefix,[ --with-glib-exec-prefix=PFX Exec prefix where GLIB is installed (optional)], + glib_config_exec_prefix="$withval", glib_config_exec_prefix="") +AC_ARG_ENABLE(glibtest, [ --disable-glibtest Do not try to compile and run a test GLIB program], + , enable_glibtest=yes) + + if test x$glib_config_exec_prefix != x ; then + glib_config_args="$glib_config_args --exec-prefix=$glib_config_exec_prefix" + if test x${GLIB_CONFIG+set} != xset ; then + GLIB_CONFIG=$glib_config_exec_prefix/bin/glib-config + fi + fi + if test x$glib_config_prefix != x ; then + glib_config_args="$glib_config_args --prefix=$glib_config_prefix" + if test x${GLIB_CONFIG+set} != xset ; then + GLIB_CONFIG=$glib_config_prefix/bin/glib-config + fi + fi + + for module in . $4 + do + case "$module" in + gmodule) + glib_config_args="$glib_config_args gmodule" + ;; + gthread) + glib_config_args="$glib_config_args gthread" + ;; + esac + done + + AC_PATH_PROG(GLIB_CONFIG, glib-config, no) + min_glib_version=ifelse([$1], ,0.99.7,$1) + AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) + no_glib="" + if test "$GLIB_CONFIG" = "no" ; then + no_glib=yes + else + GLIB_CFLAGS=`$GLIB_CONFIG $glib_config_args --cflags` + GLIB_LIBS=`$GLIB_CONFIG $glib_config_args --libs` + glib_config_major_version=`$GLIB_CONFIG $glib_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + glib_config_minor_version=`$GLIB_CONFIG $glib_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + glib_config_micro_version=`$GLIB_CONFIG $glib_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_glibtest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$GLIB_LIBS $LIBS" +dnl +dnl Now check if the installed GLIB is sufficiently new. (Also sanity +dnl checks the results of glib-config to some extent +dnl + rm -f conf.glibtest + AC_TRY_RUN([ +#include <glib.h> +#include <stdio.h> +#include <stdlib.h> + +int +main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.glibtest"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = g_strdup("$min_glib_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_glib_version"); + exit(1); + } + + if ((glib_major_version != $glib_config_major_version) || + (glib_minor_version != $glib_config_minor_version) || + (glib_micro_version != $glib_config_micro_version)) + { + printf("\n*** 'glib-config --version' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", + $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, + glib_major_version, glib_minor_version, glib_micro_version); + printf ("*** was found! If glib-config was correct, then it is best\n"); + printf ("*** to remove the old version of GLIB. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If glib-config was wrong, set the environment variable GLIB_CONFIG\n"); + printf("*** to point to the correct copy of glib-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } + else if ((glib_major_version != GLIB_MAJOR_VERSION) || + (glib_minor_version != GLIB_MINOR_VERSION) || + (glib_micro_version != GLIB_MICRO_VERSION)) + { + printf("*** GLIB header files (version %d.%d.%d) do not match\n", + GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + glib_major_version, glib_minor_version, glib_micro_version); + } + else + { + if ((glib_major_version > major) || + ((glib_major_version == major) && (glib_minor_version > minor)) || + ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", + glib_major_version, glib_minor_version, glib_micro_version); + printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the glib-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GLIB, but you can also set the GLIB_CONFIG environment to point to the\n"); + printf("*** correct copy of glib-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_glib" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$GLIB_CONFIG" = "no" ; then + echo "*** The glib-config script installed by GLIB could not be found" + echo "*** If GLIB was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GLIB_CONFIG environment variable to the" + echo "*** full path to glib-config." + else + if test -f conf.glibtest ; then + : + else + echo "*** Could not run GLIB test program, checking why..." + CFLAGS="$CFLAGS $GLIB_CFLAGS" + LIBS="$LIBS $GLIB_LIBS" + AC_TRY_LINK([ +#include <glib.h> +#include <stdio.h> +], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GLIB or finding the wrong" + echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" + echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" + echo "*** came with the system with the command" + echo "***" + echo "*** rpm --erase --nodeps gtk gtk-devel" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GLIB was incorrectly installed" + echo "*** or that you have moved GLIB since it was installed. In the latter case, you" + echo "*** may want to edit the glib-config script: $GLIB_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GLIB_CFLAGS="" + GLIB_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GLIB_CFLAGS) + AC_SUBST(GLIB_LIBS) + rm -f conf.glibtest +]) + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..bda8fda --- /dev/null +++ b/autogen.sh @@ -0,0 +1,91 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +ORIGDIR=`pwd` +cd $srcdir +PROJECT=mdk +TEST_TYPE=-d +FILE=mixlib + +DIE=0 + +grep "^AM_GNU_GETTEXT" $srcdir/configure.in >/dev/null && { + (gettext --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: You must have \`gettext' installed to compile $PROJECT." + echo "Download the appropriate package for your distribution," + echo "or get ftp://alpha.gnu.org/gnu/gettext-0.10.35.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + } +} + +(autoconf --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have autoconf installed to compile $PROJECT." + echo "Download the appropriate package for your distribution," + echo "or get the source tarball at ftp://ftp.gnu.org/pub/gnu/" + DIE=1 +} + +(automake --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "You must have automake installed to compile $PROJECT." + echo "Get ftp://sourceware.cygnus.com/pub/automake/automake-1.4.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 + NO_AUTOMAKE=yes +} + +# if no automake, don't bother testing for aclocal +test -n "$NO_AUTOMAKE" || (aclocal --version) < /dev/null > /dev/null 2>&1 || { + echo + echo "**Error**: Missing \`aclocal'. The version of \`automake'" + echo "installed doesn't appear recent enough." + echo "Get ftp://ftp.gnu.org/pub/gnu/automake-1.3.tar.gz" + echo "(or a newer version if it is available)" + DIE=1 +} + + +if test "$DIE" -eq 1; then + exit 1 +fi + +test $TEST_TYPE $FILE || { + echo "You must run this script in the top-level $PROJECT directory" + exit 1 +} + +if test -z "$*"; then + echo "I am going to run ./configure with no arguments - if you wish " + echo "to pass any to it, please specify them on the $0 command line." +fi + +case $CC in +*xlc | *xlc\ * | *lcc | *lcc\ *) am_opt=--include-deps;; +esac + +echo "Running gettextize... Ignore non-fatal messages." +echo "no" | gettextize --force + +echo "Running aclocal ..." +aclocal $ACLOCAL_FLAGS + +# optionally feature autoheader +(autoheader --version) < /dev/null > /dev/null 2>&1 && autoheader + +echo "Running automake --add-missing --gnu $am_opt ..." +automake -a --gnu $am_opt + +echo "Running autoconf ..." +autoconf +cd $ORIGDIR + +$srcdir/configure --enable-maintainer-mode "$@" + +echo +echo "Now type 'make' to compile $PROJECT." diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..d2386d0 --- /dev/null +++ b/configure.in @@ -0,0 +1,56 @@ +# Copyright (C) 2000 Jose Antonio Ortega Ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +AC_INIT(mixlib/mix.h) +AM_CONFIG_HEADER(config.h) +AM_INIT_AUTOMAKE(mdk,0.1) + +AM_MAINTAINER_MODE + +AC_ISC_POSIX +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC + +AM_PROG_LEX +AC_PROG_RANLIB + +dnl i18n stuff +ALL_LINGUAS="ca" +AM_GNU_GETTEXT + +test "x$prefix" = xNONE && prefix=$ac_default_prefix + +AC_DEFINE_UNQUOTED(LOCALEDIR, "${prefix}/share/locale") + +dnl Check for readline and history +AC_CHECK_LIB(readline, readline, , AC_MSG_ERROR(Cannot find GNU readline lib)) +AC_CHECK_LIB(history, add_history, , AC_MSG_ERROR(Cannot GNU history lib)) + + +dnl Check for glib +AM_PATH_GLIB(1.2.0, + [LIBS="$LIBS $GLIB_LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS"], + AC_MSG_ERROR(Cannot find GLIB), "gmodule" ) + +CFLAGS="$CFLAGS -Wall" +AC_SUBST(CFLAGS) + +AC_OUTPUT( +Makefile +doc/Makefile +doc/html/Makefile +mixlib/Makefile +mixlib/testsuite/Makefile +mixutils/Makefile +intl/Makefile +samples/Makefile +po/Makefile.in +) diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..26676b1 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,8 @@ +Makefile +Makefile.in +mdk.html +mdk.info +mdk.info-1 +mdk.info-2 +stamp-vti +version.texi diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..754ab11 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,15 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 jose antonio ortega ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +SUBDIRS = html +info_TEXINFOS = mdk.texi +mdk_TEXINFOS = gpl.texi diff --git a/doc/gpl.texi b/doc/gpl.texi new file mode 100644 index 0000000..5b0da1a --- /dev/null +++ b/doc/gpl.texi @@ -0,0 +1,396 @@ +@setfilename gpl.info + +@unnumbered GNU GENERAL PUBLIC LICENSE +@center Version 2, June 1991 + +@display +Copyright @copyright{} 1989, 1991 Free Software Foundation, Inc. +675 Mass Ave, Cambridge, MA 02139, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +@end display + +@unnumberedsec 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. + +@iftex +@unnumberedsec TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@end iftex +@ifinfo +@center TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +@end ifinfo + +@enumerate +@item +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. + +@item +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. + +@item +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: + +@enumerate a +@item +You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +@item +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. + +@item +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.) +@end enumerate + +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. + +@item +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: + +@enumerate a +@item +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, + +@item +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, + +@item +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.) +@end enumerate + +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. + +@item +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. + +@item +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. + +@item +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. + +@item +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. + +@item +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. + +@item +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. + +@item +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. + +@iftex +@heading NO WARRANTY +@end iftex +@ifinfo +@center NO WARRANTY +@end ifinfo + +@item +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. + +@item +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 enumerate + +@iftex +@heading END OF TERMS AND CONDITIONS +@end iftex +@ifinfo +@center END OF TERMS AND CONDITIONS +@end ifinfo + +@page +@unnumberedsec 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. + +@smallexample +@var{one line to give the program's name and an idea of what it does.} +Copyright (C) 19@var{yy} @var{name of author} + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +@end smallexample + +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: + +@smallexample +Gnomovision version 69, Copyright (C) 19@var{yy} @var{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. +@end smallexample + +The hypothetical commands @samp{show w} and @samp{show c} should show +the appropriate parts of the General Public License. Of course, the +commands you use may be called something other than @samp{show w} and +@samp{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: + +@smallexample +@group +Yoyodyne, Inc., hereby disclaims all copyright +interest in the program `Gnomovision' +(which makes passes at compilers) written +by James Hacker. + +@var{signature of Ty Coon}, 1 April 1989 +Ty Coon, President of Vice +@end group +@end smallexample + +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/doc/html/.cvsignore b/doc/html/.cvsignore new file mode 100644 index 0000000..b44cc40 --- /dev/null +++ b/doc/html/.cvsignore @@ -0,0 +1,16 @@ +Makefile +Makefile.in +doc.html +mdk.html +mdk_1.html +mdk_2.html +mdk_3.html +mdk_4.html +mdk_5.html +mdk_6.html +mdk_7.html +mdk_8.html +mdk_abt.html +mdk_fot.html +mdk_ovr.html +mdk_toc.html diff --git a/doc/html/Makefile.am b/doc/html/Makefile.am new file mode 100644 index 0000000..ecd8550 --- /dev/null +++ b/doc/html/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Jose Antonio Ortega Ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +EXTRA_DIST = index.html download.html + diff --git a/doc/html/download.html b/doc/html/download.html new file mode 100644 index 0000000..0749404 --- /dev/null +++ b/doc/html/download.html @@ -0,0 +1,105 @@ +<!-- -*-html-*- --> +<html> + + <head> + <title>MDK download</title> + </head> + + <body bgcolor="white" link="#ff0000" vlink="#a00000"> + <a name="top"></a> + <table cellspacing="0" cellpadding="5" border="0" align="center"> + <tr> + <td width="100" bgcolor="#696969"> </td> + <td bgcolor="#696969" width="600" align="center"> + <font color="white"><b>MDK download</b></font> + </td> + <td bgcolor="#696969" width="10"> </td> + </tr> + <tr> + <td colspan="2"> </td> + <td bgcolor="#696969" > </td> + </tr> + <tr> + <td bgcolor="#909090" valign="top"> + <br> + <a href="index.html">MDK home</a><br> + <a href="mdk.html">Documentation</a><br> + <a href="http://sourceforge.net/projects/mdk"> + MDK at SourceForge</a><br> + <a href="http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/?cvsroot=mdk"> + CVS repository</a><br><br> + <p align="center">Thanks to<br> + <A href="http://sourceforge.net"> + <IMG src="http://sourceforge.net/sflogo.php?group_id=13897&type=1" + width="88" height="31" border="0" + alt="SourceForge Logo"> </A> + </td> + <td > + <p align="right"><font color="#000069" size="+1"> + Download + </font></p> + <p>The latest version (0.1) source tarball is available for + download <a href="http://sourceforge.net/projects/mdk">here.</a></p> + <p>A tarball containing the HTML documentation is available + <a href="mdk-doc.tar.gz">here.</a></p> + <p align="right"><font color="#000069" size="+1"> + <a name="reqs">Requirements</a> + </font></p> + MDK is written in ANSI C and uses the following libraries: + <ul> + <li>GNU readline and history + <li><a href="http://www.gnu.org/software/flex/flex.html"> + GNU Flex</a>, version 2.3 or latter + <li><a href="http://www.gtk.org">glib</a>, version 1.2.0 or latter + </ul> + These libraries are fairly common in any GNU/Linux distribution + (MDK is developed on a <a href="www.debian.org">Debian 2.3</a> + box). Although I haven't tested it, MDK should be also installable + on BSD operating systems such as FreeBSD if the above libraries + are installed. Please, + <a href="mailto:jaortega@acm.org">drop me</a> a line if you install + MDK, and I'll add your platform to the list of supported ones. + <p align="right"><font color="#000069" size="+1"> + Installation + </font></p> + MDK uses autoconf/automake, so that compilation and installation + should follow the typical uncompress, configure, make, install cycle. + First, uncompress the source tarball using: + <pre> + tar xvfz mdk-latest.tar.gz + </pre> + This will create a folder named mdk-X.Y (where X.Y stands for + the version you downloaded, e.g., 0.1). To build the MDK tools, + enter this folder and type + <pre> + ./configure + make + </pre> + Finally, to install the binaries and documentation, type, as root + <pre> + make install + </pre> + See the file named INSTALL in the source folder for fine tuning + of build and installation options. + <p align="right"> + Contact the <a href="mailto:jaortega@acm.org">author.</a> + </p> + </td> + <td bgcolor="#696969" > </td> + </tr> + <tr> + <td bgcolor="#909090"> </td> + <td colspan="2"> </td> + </tr> + <tr> + <td bgcolor="#909090"> </td> + <td colspan="2" bgcolor="#909090" align="right"> + + </td> + </tr> + </table> + + </body> +</html> + + diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..f4d4549 --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,104 @@ +<!-- -*-html-*- --> +<html> + + <head> + <title>MIX Development Kit</title> + </head> + + <body bgcolor="white" link="#ff0000" vlink="#a00000"> + <a name="top"></a> + <table cellspacing="0" cellpadding="5" border="0" align="center"> + <tr> + <td width="100" bgcolor="#696969"> </td> + <td bgcolor="#696969" width="600" align="center"> + <font color="white"><b>MDK, the MIX development kit</b></font> + </td> + <td bgcolor="#696969" width="10"> </td> + </tr> + <tr> + <td colspan="2"> </td> + <td bgcolor="#696969" > </td> + </tr> + <tr> + <td bgcolor="#909090" valign="top"> + <br> + <a href="download.html">Download</a><br> + <a href="mdk.html">Documentation</a><br> + <a href="http://sourceforge.net/projects/mdk"> + MDK at SourceForge</a><br> + <a href="http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/?cvsroot=mdk"> + CVS repository</a><br><br> + <p align="center">Thanks to<br> + <A href="http://sourceforge.net"> + <IMG src="http://sourceforge.net/sflogo.php?group_id=13897&type=1" + width="88" height="31" border="0" + alt="SourceForge Logo"> </A> + </td> + <td > + <p align="right"><font color="#000069" size="+1"> + What is the MIX? + </font></p> + <b>MIX</b> is Donald Knuth's mythical computer as described + in his monumental work <a + href="http://Sunburn.Stanford.EDU/~knuth/taocp.html"> The + Art Of Computer Programming</a>. As any of its real + counterparts, the MIX features registers, memory cells, an + overflow toggle, comparison flags, input-output devices, and + a set of binary instructions executable by its virtual + CPU. You can programme the MIX using an assembly language + called <b>MIXAL</b>, the MIX Assembly Language. <p> So, + what's the use of learning MIXAL? Well, if you're interested + in programming, please buy, borrow or steal a copy of TAOCP, + and you'll see the use. + <br> <br> + <p align="right"><font color="#000069" size="+1"> + What is the MDK? + </font></p> + The <b>M</b>IX <b>D</b>evelopment <b>K</b>it offers an emulation of + <b>MIX</b> and <b>MIXAL</b>. The <a href="download.html"> + current version</a> of MDK includes two applications: + <ul> + <li><b><i>mixasm</i></b> A MIXAL compiler, which + translates your source files into binary ones, executable + by the MIX virtual machine. + <li><b><i>mixvm</i></b> A MIX virtual machine which is + able to run and debug compiled MIXAL programs, using a + command line interface with readline's line editting + capabilities. + </ul> + Using the MDK tools, you'll be able to + <ul> + <li>write, compile and execute MIXAL programs, + <li>set breakpoints and run your programs step by step, + <li>inspect and modify the MIX registers, flags and memory + contents at any step, + <li>simulate MIX input-output devices using the standard + output and your file system. + </ul> + See the MDK <a href="mdk.html">user's manual</a> for a complete + description of the toolkit. + The MDK utils will run on any GNU/Linux box (see + <a href="download.html#reqs">requirements</a>) and, of course, are + <a href="http://www.gnu.org/copyleft/gpl.html">free software</a>. + <p align="right"> + Contact the <a href="mailto:jaortega@acm.org">author.</a> + </p> + </td> + <td bgcolor="#696969" > </td> + </tr> + <tr> + <td bgcolor="#909090"> </td> + <td colspan="2"> </td> + </tr> + <tr> + <td bgcolor="#909090"> </td> + <td colspan="2" bgcolor="#909090" align="right"> + + </td> + </tr> + </table> + + </body> +</html> + + diff --git a/doc/mdk.texi b/doc/mdk.texi new file mode 100644 index 0000000..47dc6b9 --- /dev/null +++ b/doc/mdk.texi @@ -0,0 +1,1763 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename mdk.info +@settitle MIX Development Kit (mdk) +@finalout +@setchapternewpage odd +@c %**end of header + +@include version.texi +@set JAO Jos@'e Antonio Ortega Ruiz +@footnotestyle separate + +@ifinfo +This file documents the the @sc{mdk} utilities for developing +programs using Donald Knuth's MIX language. + +Copyright (C) 2000 @value{JAO} + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Copying'' and ``GNU General Public License'' are +included exactly as in the original, and provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by the Free Software Foundation. +@end ifinfo + +@titlepage +@title MDK +@subtitle MIX Development Kit +@subtitle Edition @value{EDITION}, for @sc{mdk} Version @value{VERSION} +@subtitle @value{UPDATED} +@author by @value{JAO} + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 2000 @value{JAO} + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided also that the +sections entitled ``Copying'' and ``GNU General Public License'' are +included exactly as in the original, and provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation +approved by the Free Software Foundation. +@end titlepage + +@node Top, Introduction, (dir), (dir) + +@ifinfo +This file documents the @sc{mdk} utilities to develop programs +using Donald Knuth's MIXAL language. MIXAL is an assembler-like +language for writing programs for the (virtual) MIX computer. They are +described in the first volume of @cite{The Art of Computer Programming} +by D. Knuth (Addison Wesley, 1997), and used throughout the (up to now) +three published volumes. + +@sc{mdk} was written by @value{JAO} and is released under the GNU +General Public license (@pxref{Copying}), so that users are free to share +and change it. + +@end ifinfo + +@menu +* Introduction:: +* MIX and MIXAL overview:: Quick tutorial of Knuth's MIX computer. +* Getting started:: Basic usage of the @sc{mdk} tools. +* mixvm:: Invoking the MIX virtual machine. +* mixasm:: Invoking the MIXAL assembler. +* Copying:: @sc{mdk} licensing terms. +* Problems:: Reporting bugs. +* Concept Index:: Index of concepts. + +@detailmenu + --- The Detailed Node Listing --- + +MIX and MIXAL overview + +* The MIX computer:: Architecture and instruction set + of the MIX computer. +* MIXAL:: The MIX assembly language. + +The MIX computer + +* MIX architecture:: +* MIX instruction set:: + +MIX instruction set + +* Loading operators:: +* Storing operators:: +* Arithmetic operators:: +* Address transfer operators:: +* Comparison operators:: +* Jump operators:: +* Miscellaneous operators:: +* Input-output operators:: +* Conversion operators:: + +MIXAL + +* Instructions:: +* Comments:: +* Expressions:: +* Local symbols:: +* Miscellaneous:: + +Getting started + +* Writing a source file:: A sample MIXAL source file. +* Compiling:: Using @code{mixasm} to compile source + files into binary format. +* Running the program:: Running and debugging your program. + +Running the program + +* Non-interactive mode:: Running your programs non-interactively. +* Interactive mode:: Running programs interactively. +* Debugging:: Commands for debugging your programs. + +@code{mixvm}, the MIX computer simulator + +* Invocation:: Options when invoking @code{mixvm}. +* Commands:: Commands available in interactive mode. +* Devices:: MIX block devices implementation. + +@code{mixasm}, the MIXAL assembler + +* Invoking @code{mixasm}:: @code{mixasm} options + +@end detailmenu +@end menu + +@node Introduction, MIX and MIXAL overview, Top, Top +@comment node-name, next, previous, up +@unnumbered Introduction +@cindex Introduction + +In his book series @cite{The Art of Computer Programming} (published by +Addison Wesley), D. Knuth uses an imaginary computer, the MIX, and its +associated machine-code and assembly languages to ilustrate the +concepts and algorithms as they are presented. + +The MIX's architecture is a simplified version of those found in real +CSIC CPUs, and the MIX assembly language provides a set of primitives +that will be very familiar to any person with a minimum experience in +assembly programming. The MIX/MIXAL definition is powerful and complete +enough to provide a virtual development platform for writing quite +complex programs, and close enough to real computers to be worth using +when learning programming techniques. At any rate, if you want to read +and learn from Knuth excellent books on computer programming, a MIX +development environment would come in handy. + +The @sc{mdk} package aims at providing such virtual development +environment on a GNU box. Thus, @sc{mdk} offers you a set of utilities +to simulate the MIX computer and to write, compile, run and debug MIXAL +programs. As of version @value{VERSION}, @sc{mdk} includes +the following programs: + +@table @code +@item mixvm +MIX virtual machine. Emulation of the MIX computer. +@item mixasm +MIXAL assembler. Assembler which translates MIXAL source files into +programs that can be run (and debugged) by @code{mixvm}. +@end table + +@code{mixvm} implements a simulator of the MIX computer, giving you a +virtual machine for executing and debugging MIX programs. These binary +programs could be written by hand, but it is easier to produce them +compiling MIXAL source files, using the MIXAL assembler @code{mixasm}. + +This manual gives you a brief survey of MIX and MIXAL, and a thorough +description of the use of the @sc{mdk} utilities. + + + +@node MIX and MIXAL overview, Getting started, Introduction, Top +@comment node-name, next, previous, up +@chapter MIX and MIXAL overview +@cindex MIX +@cindex MIXAL + +In the book series @cite{The Art of Computer Programming}, by D. Knuth, +a virtual computer, the MIX, is used by the author, together with the +set of binary instructions that the virtual CPU accepts, in the example +programs and exercises. Like any other real computer, there is a +symbolic assembler language that can be used to program the MIX: the MIX +assembly language, or MIXAL for short. The MIX computer architecture and +the MIXAL language are defined in volume 1 of the series, +@cite{Fundamental Algorithms}. In the following subsections you will +find a brief survey of these topics, which is not meant to replace the +precise description given in the book (if you are interested in using +the @sc{mdk} utilities, most probably the reason is that you have access +to a copy of TAOCP), but to serve as a quick reminder of key points and +nomenclature used in the rest of this manual. + +@menu +* The MIX computer:: Architecture and instruction set + of the MIX computer. +* MIXAL:: The MIX assembly language. +@end menu + +@node The MIX computer, MIXAL, MIX and MIXAL overview, MIX and MIXAL overview +@comment node-name, next, previous, up +@section The MIX computer + +In this section, you will find a brief description of the MIX computer, +its components and instruction set. + +@menu +* MIX architecture:: +* MIX instruction set:: +@end menu + +@node MIX architecture, MIX instruction set, The MIX computer, The MIX computer +@comment node-name, next, previous, up +@subsection MIX architecture +@cindex byte +@cindex MIX byte +@cindex word +@cindex MIX word +@cindex MIX architecture +@cindex MIX computer +@cindex register +@cindex MIX register +@cindex field specification +@cindex fspec +@cindex instruction +@cindex MIX instruction +@cindex address +@cindex memory cell +@cindex cell +@cindex memory +@cindex index + +The basic information storage unit in the MIX computer is the +@dfn{byte}, which stores positive values in the range 0-63 . Note that a +MIX byte can be then represented as 6 bits, instead of the common 8 bits +for a @emph{regular} byte. Unless otherwise stated, we shall use the +word @dfn{byte} to refer to a MIX 6-bit byte. + +A MIX @dfn{word} is defined as a set of 5 bytes plus a sign. The bytes +within a word are numbered for 1 to 5, being byte number one the most +significant one. The sign is denoted by index 0. Graphically, + +@example + ----------------------------------------------- +| 0 | 1 | 2 | 3 | 4 | 5 | + ----------------------------------------------- +| +/- | byte | byte | byte | byte | byte | + ----------------------------------------------- +@end example + +You can refer to subfields within a word using a +@dfn{field specification} or @dfn{fspec} of the form @samp{(L:R)}, where +@samp{L} denotes the first byte and @samp{R} the last byte of the +subfield. When @samp{L} is zero, the subfield includes the word's +sign. An fspec can be also represented as a single value @samp{F}, given +by @code{F = 8*L + R}. + +The MIX computer stores information in @dfn{registers}, that can store +either a word or two bytes and sign (see below), and @dfn{memory cells}, +each one containing a word. Specifically, the MIX computer has 4000 +memory cells with addresses 0 to 3999 (i.e., two bytes are enough to +address a memory cell) and the following registers: + +@table @samp +@item rA +A register. General purpose register holding a word. Usually its +contents serves as operator for arithmetic and storing instructions. +@item rX +X register. General purpose register holding a word. Often it acts as an +extension or a replacement of @samp{rA}. +@item rJ +J (jump) register. This register stores positive two-byte values, +usually representing a jump address. +@item rI[1-6] +Index registers. These six registers can store a signed two-byte +value. Their contents is used as indexing values for the computation of +an effective memory address. +@end table + +@cindex @sc{ov} +@cindex @sc{cm} +@cindex @samp{Un} +@cindex overflow toggle +@cindex comparison indicator +@cindex input-output devices +@noindent +In addition, the MIX computer contains: + +@itemize @minus +@item +An @dfn{overflow toggle} (a single bit with values @dfn{on} or +@dfn{off}). In this manual, this toggle is denoted @sc{ov}. +@item +A @dfn{comparison indicator} (having three values: @dfn{EQUAL}, +@dfn{GREATER} or @dfn{LESS}). In this manual, this indicator is denoted +@sc{cm}. +@item +Input-output devices. Each device is labelled as @samp{Un}, where +@samp{n} runs from 0 to 19@footnote{@samp{U0-7} are magnetic tape units, +@samp{U8-15} are disks and drums, @samp{U16} is a card reader, +@samp{U17} is a card writer, @samp{U18} is a line printer and +@samp{U19}, a paper tape.}. +@end itemize + +MIX @dfn{instructions} are codified as words with the following subfield +structure: + +@multitable @columnfractions .15 .20 .65 +@item @emph{Subfield} @tab @emph{fspec} @tab @emph{Description} + +@item ADDRESS @tab (0:2) +@tab The first two bytes plus sign are the @dfn{address} field. Combined +with the INDEX field, denotes the memory address to be used by the +instruction. +@item INDEX @tab (3:3) @tab +The third byte is the @dfn{index}, normally used for indexing the +address@footnote{The actual memory address the instruction refers to, is +obtained by adding to ADDRESS the value of the @samp{rI} register +denoted by INDEX.}. +@item MOD @tab (4:4) @tab +Byte four is used either as an operation code modifier or as a field +specification. +@item OPCODE @tab (5:5) @tab +The last (least significant) byte in the word denotes the operation +code. +@end multitable + +@noindent +or, graphically, + +@example + ------------------------------------------------ +| 0 | 1 | 2 | 3 | 4 | 5 | + ------------------------------------------------ +| ADDRESS | INDEX | MOD | OPCODE | + ------------------------------------------------ +@end example + +The MIX computer understands a quite complete set of instructions +commonly found in real computers, including arithmetic, logical, +storing, comparison and jump instructions. We refer the reader to +D. Knuth's TAOCP (volume 1, section 1.3.1) for a complete description of +these instructions. @xref{MIX instruction set}, gives a quick synopsis +of the available instructions. + +@node MIX instruction set, , MIX architecture, The MIX computer +@comment node-name, next, previous, up +@subsection MIX instruction set +@cindex instruction set + +The following subsections summarize the instruction set of the MIX +computer. In this description @samp{M} stands for +the memory address obtained after indexing the ADDRESS subfield of the +instruction (using its INDEX byte), and @samp{V} is the contents of the +subfield indicated by MOD of the memory cell with address @samp{M}. + +@menu +* Loading operators:: +* Storing operators:: +* Arithmetic operators:: +* Address transfer operators:: +* Comparison operators:: +* Jump operators:: +* Miscellaneous operators:: +* Input-output operators:: +* Conversion operators:: +@end menu + +@node Loading operators, Storing operators, MIX instruction set, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Loading operators +@cindex loading operators + +The following instructions are used to load memory contents into a +register. + +@ftable @code +@item LDA +Load rA. OPCODE = 8, MOD = fspec. @code{rA <- V}. +@item LDX +Load rX. OPCODE = 15, MOD = fspec. @code{rX <- V}. +@item LDi +Load rIi. OPCODE = 8 + i, MOD = fspec. @code{rIi <- V}. +@item LDAN +Load rA negative. OPCODE = 16, MOD = fspec. @code{rA <- -V}. +@item LDXN +Load rX negative. OPCODE = 23, MOD = fspec. @code{rX <- -V}. +@item LDiN +Load rIi negative. OPCODE = 16 + i, MOD = fspec. @code{rIi <- -V}. +@end ftable + + +@node Storing operators, Arithmetic operators, Loading operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Storing operators +@cindex storing operators + +The following instructions are used to store a subfield of a register +into a memory location. + +@ftable @code +@item STA +Store rA. OPCODE = 24, MOD = fspec. @code{V <- rA}. +@item STX +Store rX. OPCODE = 31, MOD = fspec. @code{V <- rX}. +@item STi +Store rIi. OPCODE = 24 + i, MOD = fspec. @code{V <- rIi}. +@item STJ +Store rJ. OPCODE = 32, MOD = fspec. @code{V <- rJ}. +@item STZ +Store zero. OPCODE = 33, MOD = fspec. @code{V <- 0}. +@end ftable + + +@node Arithmetic operators, Address transfer operators, Storing operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Arithmetic operators +@cindex arithmetic operators + +The following instructions perform arithmetic operations between rA and +rX register and memory contents. + +@ftable @code +@item ADD +Add and set OV if overflow. OPCODE = 1, MOD = fspec. +@code{rA <- rA +V}. +@item SUB +Sub and set OV if overflow. OPCODE = 2, MOD = fspec. +@code{rA <- rA - V}. +@item MUL +Multiply V times rA and store the 10-bytes product in rAX. +OPCODE = 3, MOD = fspec. @code{rAX <- rA x V}. +@item DIV +rAX is considered a 10-bytes number, and it is divided by V. +OPCODE = 4, MOD = fspec. @code{rA <- rAX / V}, @code{rX} <- reminder. +@end ftable + +@node Address transfer operators, Comparison operators, Arithmetic operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Address transfer operators +@cindex address transfer operators + +In these instructions, M (the address of the instruction after indexing) +is used as a number instead of as the address of a memory cell. + +@ftable @code +@item ENTA +Enter rA. OPCODE = 48, MOD = 2. @code{rA <- M}. +@item ENTX +Enter rX. OPCODE = 55, MOD = 2. @code{rX <- M}. +@item ENTi +Enter rIi. OPCODE = 48 + i, MOD = 2. @code{rIi <- M}. +@item ENNA +Enter negative rA. OPCODE = 48, MOD = 3. @code{rA <- -M}. +@item ENNX +Enter negative rX. OPCODE = 55, MOD = 3. @code{rX <- -M}. +@item ENNi +Enter negative rIi. OPCODE = 48 + i, MOD = 3. @code{rIi <- -M}. +@item INCA +Increase rA. OPCODE = 48, MOD = 0. @code{rA <- rA + M}. +@item INCX +Increase rX. OPCODE = 55, MOD = 0. @code{rX <- rX + M}. +@item INCi +Increase rIi. OPCODE = 48 + i, MOD = 0. @code{rIi <- rIi + M}. +@item DECA +Decrease rA. OPCODE = 48, MOD = 1. @code{rA <- rA - M}. +@item DECX +Decrease rX. OPCODE = 55, MOD = 0. @code{rX <- rX - M}. +@item DECi +Decrease rIi. OPCODE = 48 + i, MOD = 0. @code{rIi <- rIi - M}. +@end ftable + + +@node Comparison operators, Jump operators, Address transfer operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Comparison operators +@cindex comparison operators + +The following instructions compare the value of a register with V, and +set the CM indicator to the result of the comparison. + +@ftable @code +@item CMPA +Compare rA with V. OPCODE = 56, MOD = fspec. +@item CMPX +Compare rX with V. OPCODE = 63, MOD = fspec. +@item CMPi +Compare rIi with V. OPCODE = 56 + i, MOD = fspec. +@end ftable + +@node Jump operators, Miscellaneous operators, Comparison operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Jump operators +@cindex jump operators + +The following instructions provoke jumps by setting the program +counter (address of the next instruction to fetch) to M (if a condition +is met). If a jump occurs, the value of the next instruction address +that would have been fetched in the absence of the jump is stored in rJ +(except for @code{JSJ}). + +@ftable @code +@item JMP +Unconditional jump. OPCODE = 39, MOD = 0. +@item JSJ +Unconditional jump, but rJ is not modified. OPCODE = 39, MOD = 1. +@item JOV +Jump if OV is set (and turn it off). OPCODE = 39, MOD = 2. +@item JNOV +Jump if OV is not set (and turn it off). OPCODE = 39, MOD = 3. +@item JL +@itemx JE +@itemx JG +@itemx JGE +@itemx JNE +@itemx JLE +Jump according to the value of CM. OPCODE = 39, MOD = 4, 5, 6, 7, 8, 9. +@item JAN +@itemx JAZ +@itemx JAP +@itemx JANN +@itemx JANZ +@itemx JANP +Jump if the contents of rA is, respectively, negative, zero, positive, +non-negative, non-zero or non-positive. +OPCODE = 40, MOD = 0, 1, 2, 3, 4, 5. +@item JXN +@itemx JXZ +@itemx JXP +@itemx JXNN +@itemx JXNZ +@itemx JXNP +Jump if the contents of rX is, respectively, negative, zero, positive, +non-negative, non-zero or non-positive. +OPCODE = 47, MOD = 0, 1, 2, 3, 4, 5. +@item JiN +@itemx JiZ +@itemx JiP +@itemx JiNN +@itemx JiNZ +@itemx JiNP +Jump if the contents of rIi is, respectively, negative, zero, positive, +non-negative, non-zero or non-positive. +OPCODE = 40 + i, MOD = 0, 1, 2, 3, 4, 5. +@end ftable + +@node Miscellaneous operators, Input-output operators, Jump operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Miscellaneous operators +@cindex miscellaneous operators + +@ftable @code +@item SLA +@itemx SRA +@itemx SLAX +@itemx SRAX +@itemx SLC +@itemx SRC +Shift rA or rAX left, right, or rAX circularly left or right. M +specifies the number of bytes to be shifted. +OPCODE = 6, MOD = 0, 1, 2, 3, 4, 5. +@item MOVE +Move MOD words from M to the location stored in rI1. +OPCODE = 7, MOD = no. of bytes. +@item NOP +No operation. OPCODE = 0, MOD = 0. +@item HLT +Halt. Stops instruction fetching. OPCODE = 5, MOD = 2. +@end ftable + +@node Input-output operators, Conversion operators, Miscellaneous operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Input-output operators +@cindex input-output operators + +The following instructions perform input-output operations. + +@ftable @code +@item IN +Transfer a block of words from the specified unit to memory, starting at +address M. +OPCODE = 36, MOD = I/O unit. +@item OUT +Transfer a block of words from memory (starting at address M) to the +specified unit. +OPCODE = 37, MOD = I/O unit. +@item IOC +Perfom a control operation (given by M) on the specified unit. +OPCODE = 35, MOD = I/O unit. +@item JRED +Jump to M if the specified unit is ready. +OPCODE = 38, MOD = I/O unit. +@item JBUS +Jump to M if the specified unit is busy. +OPCODE = 34, MOD = I/O unit. +@end ftable + +@node Conversion operators, , Input-output operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Conversion operators +@cindex conversion operators + +The following instructions convert between numerical values and their +character representations. + +@ftable @code +@item NUM +Convert rAX, assumed to contain a character representation of a number, +to its numerical value and store it in rA. +OPCODE = 5, MOD = 0. +@item CHAR +Convert the number stored in rA to a character representation and store +it in rAX. +OPCODE = 5, MOD = 1. +@end ftable + +@node MIXAL, , The MIX computer, MIX and MIXAL overview +@comment node-name, next, previous, up +@section MIXAL +@cindex MIXAL +@cindex MIX assembly language +@cindex assembly + +The MIX computer can be programmed using an assembly language, MIXAL, +which provides a symbolic way of writing the binary instructions +understood by the imaginary MIX computer. If you have used assembler +languages before, you will find MIXAL a very familiar language. MIXAL is +fully described in volume 1 of D. Knuth's TAOCP. This section is not +meant as a replacement of the book's description, but as a brief survey +of MIXAL. + +@menu +* Instructions:: +* Comments:: +* Expressions:: +* Local symbols:: +* Miscellaneous:: +@end menu + +@node Instructions, Comments, MIXAL, MIXAL +@comment node-name, next, previous, up +@subsection Instructions +@cindex MIXAL instructions +@cindex instructions +@cindex instruction parts + +MIX instructions are written in MIXAL according to the following +pattern: + +@example +[LABEL] OPCODE [OPERAND] [COMMENT] +@end example + +@noindent +where @samp{OPERAND} is of the form + +@example +[ADDRESS][,INDEX][(MOD)] +@end example + +Items between square brackets are optional, and + +@table @code +@item LABEL +Is an alphanumeric identifier (a @dfn{symbol}) which gets the value of +the current compilation address, and can be used in subsequent +expressions. +@item OPCODE +Is a literal denoting the operation code of the instruction +(e.g. @code{LDA}, @code{STA}) or an assembly pseudoinstruction +(e.g. @code{ORG}, @code{EQU}). +@item ADDRESS +Expression evaluating to the address subfield of the instruction. +@item INDEX +Expression evaluating to the index subfield of the instruction. It +defaults to 0 (i.e., no use of indexing) and can only be used when +@code{ADDRESS} is present. +@item MOD +Expression evaluating to the mod subfield of the instruction. Its +default value, when omitted, depends on @code{OPCODE}. +@item COMMENT +Any number of spaces after the operand mark the beggining of a comment, +i.e. any text separated by white space from the operand is ignored by +the assembler (note that spaces are not allowed within the +@samp{OPERAND} field). +@end table + +Note that spaces are @emph{not} allowed between the @code{ADDRESS}, +@code{INDEX} and @code{MOD} fields if they are present. White space is +used to separate the label, operation code and operand parts of the +instruction@footnote{In fact, Knuth's definition of MIXAL restricts the +column number at which each of these instruction parts must start. The +MIXAL assembler included in @sc{mdk}, @code{mixasm}, does not impose +such restriction.}. + +MIXAL instructions can be either one of the MIX machine instructions +(@pxref{MIX instruction set}) or one of the following assembly +pseudoinstructions: + +@ftable @code +@item ORIG +Sets the value of the memory address to which following instructions +will be allocated after compilation. +@item EQU +Used to define a symbol's value, e.g. @w{@code{SYM EQU 2*200/3}}. +@item CON +The value of the given expression is copied directly into the current +memory address. +@item ALF +Takes as operand five characters, constituting the five bytes of a word +which is copied directly into the current memory address. +@item END +Marks the end of the program. Its operand gives the start address for +program execution. +@end ftable + +Sample MIXAL instructions are + +@example +HERE LDA 2000 + LDX HERE,2(1:3) this is a comment + JMP 1234 +NEXT STA HERE*2(8) + ORG 4000 +VALUE EQU NEXT+HERE//2 +@end example + +@node Comments, Expressions, Instructions, MIXAL +@comment node-name, next, previous, up +@subsection Comments +@cindex comments + +Any line starting with an asterisk is treated as a comment and ignored +by the assembler. + +@example +* This is a comment: this line is ignored. + * This line is an error: * must be in column 1. +@end example + +As noted in the previous section, comments can also be located after the +@samp{OPERAND} field of an instruction, separated from it by white +space, as in + +@example +LABEL LDA 100 This is also a comment +@end example + +@node Expressions, Local symbols, Comments, MIXAL +@comment node-name, next, previous, up +@subsection Expressions +@cindex operator +@cindex binary operator +@cindex unary operator +The @code{ADDRESS}, @code{INDEX} and @code{MOD} fields of a MIXAL +instruction can be expressions, formed by numbers, identifiers and +binary operators (@code{+ - * / // :}). @code{+} and @code{-} can also +be used as unary operators. Order of evaluation is from left to right: +there is no other operator precedence rule, and parentheses cannot be +used for grouping. A stand-alone asterisk denotes the current memory +location; thus, for instance, + +@example + 4+2** +@end example + +@noindent +evaluates to 4 plus two times the current memory location. White space +is not allowed within expressions. + +All symbols appearing within an expression must be defined. Future +references are only allowed when appearing stand-alone (or modified by +an unary operator) in the @code{ADDRESS} part of a MIXAL instruction, +e.g. + +@example +* OK: stand alone future reference + STA -S1(1:5) +* ERROR: future reference in expression + LDX 2-S1 +S1 LD1 2000 +@end example + +@node Local symbols, Miscellaneous, Expressions, MIXAL +@comment node-name, next, previous, up +@subsection Local symbols +@cindex local symbols + +Besides user defined symbols, MIXAL programmers can use the so called +@dfn{local symbols}, which are symbols of the form @code{[1-9][HBF]}. A +local symbol @code{nB} refers to the address of the last previous +occurrence of @code{nH} as a label, while @code{nF} refers to the next +@code{nH} occurrence. Unlike user defined symbols, @code{nH} can appear +multiple times in the @code{LABEL} part of different MIXAL +instructions. The following code shows an instance of local symbols' +usage: + +@example +* line 1 +1H LDA 100 +* line 2: 1B refers to address of line 1, 3F refers to address of line 4 + STA 3F,2(1B//2) +* line 3: redefinition of 1H +1H STZ +* line 4: 1B refers to address of line 3 +3H JMP 1B +@end example + +@node Miscellaneous, , Local symbols, MIXAL +@comment node-name, next, previous, up +@subsection Miscellaneous +@cindex literal constants + +MIXAL allows the introduction of @dfn{literal constants}, which are +automatically stored in memory addresses after the end of the program by +the assembler. Literal constants are denoted as @code{=exp=}, where +@code{exp} is an expression. For instance, the code + +@example +L EQU 10 + LDA =20-L= +@end example + +causes the assembler to add after the program's end an instruction with +contents 10, and to assemble the above code as the instruction @w{@code{ +LDA a}}, where @code{a} stands for the address in which the value 10 is +stored. In other words, the compiled code is equivalent to the +following: + +@example +L EQU 10 + LDA a +@dots{} +a CON 20-L + END start +@end example + + +@node Getting started, mixvm, MIX and MIXAL overview, Top +@comment node-name, next, previous, up +@chapter Getting started + +In this chapter, you will find a sample code-compile-run-debug session +using the @sc{mdk} utilities. Familiarity with the MIX mythical computer +and its assembly language MIXAL (as described in Knuth's TAOCP) is +assumed; for a compact reminder, see @ref{MIX and MIXAL overview}. + +@menu +* Writing a source file:: A sample MIXAL source file. +* Compiling:: Using @code{mixasm} to compile source + files into binary format. +* Running the program:: Running and debugging your program. +@end menu + +@node Writing a source file, Compiling, Getting started, Getting started +@comment node-name, next, previous, up +@section Writing a source file +@cindex MIXAL +@cindex source file + +MIXAL programs can be written as ASCII files with your editor of choice. +Here you have the mandatory @emph{hello world} as written in the MIXAL +assembly language: + +@example +* (1) +* hello.mixal: say 'hello world' in MIXAL (2) +* (3) +* label ins operand comment (4) +TERM EQU 19 the MIX console device number (5) + ORIG 1000 start address (6) +START OUT MSG(TERM) output data at address MSG (7) + HLT halt execution (8) +MSG ALF "MIXAL" (9) + ALF " HELL" (10) + ALF "O WOR" (11) + ALF "LD " (12) + END START end of the program (13) +@end example + +@noindent MIXAL source files should have the extension @file{.mixal} +when used with the @sc{mdk} utilities. As you can see in the above +sample, each line in a MIXAL file can be divided into four fields +separated by an arbitrary amount of whitespace characters (blanks and or +tabs). While Knuth's definition of MIXAL each field must start at a +fixed pre-defined column number, the @sc{mdk} assembler loosens this +requirement and lets you format the file as you see fit. The only +restrictions retained are for comment lines (like 1-4) which must begin +with an asterisk (*) placed at column 1, and for the label field (see +below) which, if present, must also start at column 1. The four fields +in each non-comment line are: + +@itemize @minus +@item +an optional label, which either refers to the current memory address (as +@code{START} and @code{MSG} in lines 7 and 9) or a defined symbol +(@code{TERM}) (if present, the label must always start at the first +column in its line, for the first whitespace in the line maks the +beginning of the second field), +@item +an operation mnemonic, which can represent either a MIX instruction +(@code{OUT} and @code{HLT} in lines 6 and 7 above), or an assembly +pseudoinstruction. +@item +an optional operand for the (pseudo)instruction, and +@item +an optional free text comment. +@end itemize + +@noindent Lines 9-12 of the @file{hello.mixal} file above also show the +second (and last) difference between Knuth's MIXAL definition and ours: +the operand of the @code{ALF} pseudoinstruction (a word of five +characters) must be quoted with using ""@footnote{In Knuth's definition, +the operand always starts at a fixed column number, and the use of +quotation is therefore unnecessary. As @code{mixasm} releases this +requirement, marking the beginning and end of the @code{ALF} operand +disambiguates the parser's recognition of this operand when it includes +blanks}. + +The workings of this sample program should be straightforward if you are +familiar with MIXAL. See TAOCP vol. 1 for a thorought definition or +@ref{MIX and MIXAL overview}, for a quick tutorial. + +@node Compiling, Running the program, Writing a source file, Getting started +@comment node-name, next, previous, up +@section Compiling +@cindex compiling +@cindex binary programs +@cindex virtual machine +@cindex assembler +@cindex @code{mixasm} + +A simulator of the MIX computer, called @code{mixvm} (MIX virtual +machine) is included in the @sc{mdk} tools. It is able to run binary +files containing MIX instructions written in their binary +representation. You can translate MIXAL source files into this binary +form using @code{mixasm}, the MIXAL assembler. So, in order to compile +the @file{hello.mixal} file, you can type the following +command at your shell prompt: + +@example +mixasm -g hello @key{RET} +@end example + +If the source file contains no errors, this will produce a binary file +called @file{hello.mix} which can be loaded and run by the MIX virtual +machine. The @code{-g} flag tells the assembler to include debug +information in the executable file (for a complete description of all +the compilation options, see @ref{mixasm}.) Now, your are ready to run +your first MIX program, as described in the following section. + + +@node Running the program, , Compiling, Getting started +@comment node-name, next, previous, up +@section Running the program +@cindex @code{mixvm} +@cindex non-interactive mode +@cindex interactive mode + +MIX is a mythical computer, so it is no use ordering it from your +favorite hardware provider. @sc{mdk} provides a software simulator of +the computer, though. It is called @code{mixvm}, which stands for +@dfn{MIX virtual machine}. Using it, you can run your MIXAL programs, +after compiling them with @code{mixasm} into binary @file{.mix} +files. @code{mixvm} can be used either in @dfn{interactive} or +@dfn{non-interactive} mode. In the second case, @code{mixvm} will load +your program into memory, execute it (producing any output due to MIXAL +@code{OUT} instructions present in the program), and exit when it +encounters a @code{HLT} instruction. In interactive mode, you will enter +a shell prompt which allows you issuing commands to the running virtual +machine. This commands will permit you loading, running and debugging +programs, as well as inspecting the MIX computer state (register +contents, memory cells contents and so on). + +@menu +* Non-interactive mode:: Running your programs non-interactively. +* Interactive mode:: Running programs interactively. +* Debugging:: Commands for debugging your programs. +@end menu + +@node Non-interactive mode, Interactive mode, Running the program, Running the program +@comment node-name, next, previous, up +@subsection Non-interactive mode +@cindex non-interactive mode + +To make @code{mixvm} work in non-interactive mode, use the @code{-r} +flag. Thus, to run our @file{hello.mix} program, simply type + +@example +mixvm -r hello @key{RET} +@end example + +@noindent at your command prompt, and you will get the following output: + +@example +MIXAL HELLO WORLD +@end example + +@noindent Since our hello world program uses MIX's device number 19 as +its output device (@pxref{Writing a source file}), the output is +redirected to the shell's standard output. Had you used any other MIX +output devices (disks, drums, line printer, etc.), @code{mixvm} would +have created a file named after the device used (e.g. @file{disk4.dev}) +and written its output there. + +Sometimes, you will prefer to store the results of your program in MIX +registers rather than writing them to a device. In such cases, +@code{mixvm}'s @code{-d} flag is your friend: it makes @code{mixvm} to +dump the contents of its registers and flags after executing the loaded +program. For instance, typing the following command at your shell's +prompt + +@example +mixvm -d -r hello +@end example + +@noindent you will obtain the following output: + +@example +MIXAL HELLO WORLD +rA: + 00 00 00 00 00 (0000000000) +rX: + 00 00 00 00 00 (0000000000) +rJ: + 00 00 (0000) +rI1: + 00 00 (0000) rI2: + 00 00 (0000) +rI3: + 00 00 (0000) rI4: + 00 00 (0000) +rI5: + 00 00 (0000) rI6: + 00 00 (0000) +Overflow: F +Cmp: E +@end example + +@noindent which, in addition to the program's outputs, gives you the +contents of the MIX registers and the values of the overflow toggle and +comparison flag (admittedly, rather uninteresting in our sample). + +As you can see, running programs non-interactively has many +limitations. You cannot peek the virtual machine's memory contents, not +to mention stepping through your program's instructions or setting +breakpoints. Enter interactive mode. + +@node Interactive mode, Debugging, Non-interactive mode, Running the program +@comment node-name, next, previous, up +@subsection Interactive mode +@cindex interactive mode + +To enter the MIX virtual machine interactive mode, simply type + +@example +mixvm @key{RET} +@end example + +@noindent at your shell command prompt. This command enters the +@code{mixvm} command shell. You will be presented the following command +prompt: + +@example +MIX > +@end example + +@noindent The virtual machine is initialised and ready to accept your +commands. The @code{mixvm} command shell uses GNU's readline, so that +you have at your disposal command completion (using @key{TAB}) and +history functionality, as well as other line editing shortcuts common to +all utilities using this library (for a complete description of +readline's line editing usage, see @ref{Command Line +Editing,,,Readline}.) + +Usually, the first thing you will want to do is loading a compiled MIX +program into memory. This is acomplished by the @code{load} command, +which takes as an argument the name of the @file{.mix} file to be +loaded. Thus, typing + +@example +MIX > load hello @key{RET} +Program loaded. Start address: 3000 +MIX > +@end example + +@noindent will load @file{hello.mix} into the virtual machine's memory +and set the program counter to the address of the first instruction. You +can obtain the contents of the program counter using the command +@code{pc}: + +@example +MIX > pc +Current address: 3000 +MIX > +@end example + +After loading it, you are ready to run the program, +using, as you surely have guessed, the @code{run} command: + +@example +MIX > run +Running ... +MIXAL HELLO WORLD +... done +MIX > +@end example + +@noindent After running the program, the program counter will point to +the address after the one containing the @code{HLT} instruction. In our +case, asking the value of the program counter after executing the +program will give us + +@example +MIX > pc +Current address: 3002 +MIX > +@end example + +@noindent You can check the contents of a memory cell giving its address +as an argument of the command @code{pmem}, like this + +@example +MIX > pmem 3001 +3001: + 00 00 00 02 05 (0000000133) +MIX > +@end example + +@noindent +and convince yourself that address 3001 contains the binary +representation of the instruction @code{HLT}. An address range of the +form FROM-TO can also be used as the argument of @code{pmem}: + +@example +MIX > pmem 3000-3006 +3000: + 46 58 00 19 37 (0786957541) +3001: + 00 00 00 02 05 (0000000133) +3002: + 14 09 27 01 13 (0237350989) +3003: + 00 08 05 13 13 (0002118477) +3004: + 16 00 26 16 19 (0268542995) +3005: + 13 04 00 00 00 (0219152384) +3006: + 00 00 00 00 00 (0000000000) +MIX > +@end example + +@noindent +In a similar manner, you can look at the contents of the MIX registers +and flags. For instance, to ask for the contents of the A register you +can type + +@example +MIX > preg A +rA: + 00 00 00 00 00 (0000000000) +MIX > +@end example + +@noindent +Use the comand @code{help} to obtain a list of all available commands, +and @code{help COMMAND} for help on a specific command, e.g. + +@example +MIX > help run +run Run loaded or given MIX code file. Usage: run [FILENAME] +MIX > +@end example + +@noindent +For a complete list of commands available at the MIX propmt, +@xref{mixvm}. In the following subsection, you will find a quick tour +over commands useful for debugging your programs. + +@node Debugging, , Interactive mode, Running the program +@comment node-name, next, previous, up +@subsection Debugging commands + +The interactive mode of @code{mixvm} lets you step by step execution of +programs as well as breakpoint setting. Use @code{next} to step through +the program, running its instructions one by one. To run our +two-instruction @file{hello.mix} sample you can do the following: + +@example +MIX > load hello +Program loaded. Start address: 3000 +MIX > pc +Current address: 3000 +MIX > next +MIXAL HELLO WORLD +MIX > pc +Current address: 3001 +MIX > next +MIX > pc +Current address: 3002 +MIX > next +End of program reached at address 3002 +MIX > +@end example + +You can set a breakpoint at a given address using the command +@code{sbpa} (set breakpoint at address). When a breakpoint is set, +@code{run} will stop before executing the instruction at the given +address. Typing @code{run} again will resume program execution. Coming +back to our hello world example, we would have: + +@example +MIX > sbpa 3001 +Breakpoint set at address 3001 +MIX > run +Running ... +MIXAL HELLO WORLD +... stopped: breakpoint at line 8 (address 3001) +MIX > run +Running ... +... done +MIX > +@end example + +@noindent +Note that, since we compiled @file{hello.mixal} with debug info enabled +(the @code{-g} flag of @code{mixasm}), the virtual machine is able to +tell us the line in the source file corresponding to the breakpoint we +are setting. As a matter of fact, you can directly set breakpoints at +source code lines using the command @code{sbp LINE_NO}, e.g. + +@example +MIX > sbp 4 +Breakpoint set at line 7 +MIX > +@end example + +@noindent +@code{sbp} sets the breakpoint at the first meaningful source code line; +thus, in the above example we have requested a breakpoint at a line +which does not correspond to a MIX instruction and the breakpoint is set +at the first line containing a real instruction after the given one. To +unset breakpoints, use @code{cbpa ADDRESS} and @code{cbp LINE_NO}, or +@code{cabp} to remove all currently set breakpoints. + +MIXAL lets you define symbolic constants, either using the @code{EQU} +pseudoinstruction or starting an instruction line with a label (which +assigns to the label the value of the current memory address). Each +MIXAL program has, therefore, an associated symbol table which you can +inspect using the @code{psym} command. For our hello world sample, you +will obtain the following output: + +@example +MIX > psym +START: 3000 +TERM: 19 +MSG: 3002 +MIX > +@end example + +For a complete description of all available MIX commands, @xref{mixvm}. + + + +@node mixvm, mixasm, Getting started, Top +@comment node-name, next, previous, up +@chapter @code{mixvm}, the MIX computer simulator + +@cindex mixvm + +This chapter describes @code{mixvm}, the MIX computer +simulator. @code{mixvm} is a command line interface programme which +simulates the MIX computer (@pxref{The MIX computer}). It is able +to run MIXAL programs (@pxref{MIXAL}) previously compiled with the MIX +assembler (@pxref{mixasm}). The simulator allows inspection of the MIX +computer components (registers, memory cells, comparison flag and overflow +toggle), step by step execution of MIX programmes, and breakpoint +setting to aid you in debugging your code. For a tutorial description of +@code{mixvm} usage, @xref{Running the program}. + +@menu +* Invocation:: Options when invoking @code{mixvm}. +* Commands:: Commands available in interactive mode. +* Devices:: MIX block devices implementation. +@end menu + +@node Invocation, Commands, mixvm, mixvm +@comment node-name, next, previous, up +@section Invoking @code{mixvm} + +@code{mixvm} can be invoked with the following command line options +(note, that, following GNU's conventions, we provide a long option name +for each available single letter switch): + +@example +mixvm [-vhurd] [--version] [--help] [--usage] [--run] [--dump] + [FILE[.mix]] +@end example + +@noindent +The meaning of these options is as follows: + +@defopt -v +@defoptx --version +Prints version and copyleft information and exits. +@end defopt + +@defopt -h +@defoptx --help +@defoptx -u +@defoptx --usage +Prints a summary of available options and exits. +@end defopt + +@defopt -r +@defoptx --run +Loads the specified @var{FILE} and executes it. After the program +execution, @code{mixvm} exits. @var{FILE} must be the name of a binary +@file{.mix} program compiled with @code{mixasm}. If your program does +not produce any output, use the @code{-d} flag (see below) to peek at +the virtual machine's state after execution. +@end defopt + +@defopt -d +@defoptx --dump +This option must be used in conjuction with @code{-r}, and tells +@code{mixvm} to print the value of the virtual machine's registers, +comparison flag and overflow toggle after executing the program named +@var{FILE}. See @xref{Non-interactive mode}, for sample usage. +@end defopt + +When run without the @code{-r} flag, @code{mixvm} enters its interactive +mode, showing you a prompt like this one: + +@example +MIX > +@end example + +@noindent +and waiting for your commands (@pxref{Commands}). If the +optional @var{FILE} argument is given, the file @file{FILE.mix} will be +loaded into the virtual machine memory before entering the interactive +mode. + +@node Commands, Devices, Invocation, mixvm +@comment node-name, next, previous, up +@section Interactive commands + +You can enter the interactive mode of the MIX virtual machine by simply +invoking @code{mixvm} without arguments. You will then presented a shell +prompt + +@example +MIX > +@end example + +@noindent +which indicates that a new virtual machine has been initialised and is +ready to execute your commands. As we have already mentioned, this +command prompt offers you command line editing facilities as described +in the Readline user's manual (chances are that you are already familiar +with these command line editing capabilities, as they are present in +many GNU utilities, e.g. the @code{bash} shell). As a beginner, your +best friend will be the @code{help} command, which shows you a summary +of all available MIX commands and their usage; its syntax is as follows: + +@deffn {@code{mixvm} command} help [command] +@deffnx {@code{mixvm} command} ? [command] +Prints a short description of the given @var{command} and its usage. If +@var{command} is omitted, all available commands are described. +@end deffn + +You have at your disposal a series of commands that let you load and +execute MIX executable file, as well as manipulate MIXAL source files: + +@deffn {file command} load file[.mix] +This command loads a binary file, @var{file.mix} into the virtual +machine memory, and positions the program counter at the beginning of +the loaded program. This address is indicated in the MIXAL source file +as the operand of the @code{END} pseudoinstruction. Thus, if your +@file{sample.mixal} source file contains the line: + +@example + END 3000 +@end example + +@noindent +and you compile it with @code{mixasm} to produce the binary file +@file{sample.mix}, you will load it into the virtual machine as follows: + +@example +MIX > load sample +Program loaded. Start address: 3000 +MIX > +@end example + +@end deffn + +@deffn {file command} run [file[.mix]] +When executed without argument, this command initiates or resumes +execution of instructions from the current program counter +address. Therefore, issuing this command after a successful @code{load}, +will run the loaded program until either a @code{HLT} instruction or a +breakpoint is found. If you provide a MIX filename as argument, the +given file will be loaded (as with @code{load} @var{file}) and +executed. If @code{run} is invoked again after program execution +completion (i.e., after the @code{HLT} instruction has been found in a +previous run), the program counter is repositioned and execution starts +again from the beginning. +@end deffn + +@deffn {file command} edit file[.mixal] +The source file @var{file.mixal} is edited using the editor defined in +the environment variable @var{MIX_EDITOR}. If this variable is not set, +the following ones are tried out in order: @var{X_EDITOR}, @var{EDITOR} +and @var{VISUAL}. +@end deffn + +@deffn {file command} compile file[.mixal] +The source file @var{file.mixal} is compiled (with debug information +enabled) using @code{mixasm}. +@end deffn + +Sequential execution of loaded programs can be interrupted using the +following debug commands: + +@deffn {debug command} next [ins_number] +This command causes the virtual machine to fetch and execute up to +@var{ins_number} instructions, beginning from the current program +counter position. Execution is interrupted either when the specified +number of instructions have been fetched or a breakpoint is found, +whatever happens first. If run without arguments, one instruction is +executed. +@end deffn + +@deffn {debug command} sbp line_number +Sets a breakpoint at the specified source file line number. If the line +specified corresponds to a command or to a MIXAL pseudoinstruction which +does not produce a MIX instruction in the binary file (such as +@code{ORIG} or @code{EQU}) the breakpoint is set at the first source +code line giving rise to a MIX instruction after the specified +one. Thus, for our sample @file{hello.mixal} file: + +@example +* (1) +* hello.mixal: say 'hello world' in MIXAL (2) +* (3) +* label ins operand comment (4) +TERM EQU 19 the MIX console device number (5) + ORIG 1000 start address (6) +START OUT MSG(TERM) output data at address MSG (7) +... +@end example + +@noindent +trying to set a breakpoint at line 5, will produce the following result: + +@example +MIX > sbp 5 +Breakpoint set at line 7 +MIX > +@end example + +@noindent +since line 7 is the first one compiled into a MIX instruction (at +address 3000). In order to @code{sbp} to work, the source file must be +compiled using the @code{-g} flags, which tells @code{mixasm} to include +debug information in the binary @file{.mix} file. +@end deffn + +@deffn {debug command} spba address +Sets a breakpoint at the given memory @var{address}. The argument must +be a valid MIX memory address, i.e., it must belong into the range +@w{[0-3999]}. Note that no check is performed to verify that the +specified address is reachable during program execution. No debug +information is needed to set a breakpoint by address with @code{sbpa}. +@end deffn + +@deffn {debug command} cbp line_no +Clears a (previously set) breakpoint at the given source file line. +@end deffn + +@deffn {debug command} cbpa address +Clears a (previously set) breakpoint at the given memory address. +@end deffn + +@deffn {debug command} cabp +Clears all currently set breakpoints. +@end deffn + +@deffn {debug command} psym [symbol_name] +MIXAL programs can define symbolic constants, using either the +@code{EQU} pseudoinstruction or a label at the beginning of a +line. Thus, in the program fragment + +@example +VAR EQU 2168 + ORIG 4000 +START LDA VAR +@end example + +@noindent +the symbol @code{VAR} stands for the value 2168, while @code{START} is +assigned the value 4000. When MIXAL programs are compiled using the +@code{-g} flag (which tells @code{mixasm} to include debug information +in the binary @file{.mix} file), the symbol table can be consulted from +the @code{mixvm} command line using @code{psym} followed by the name of +the symbol whose contents you are interested in. When run without +arguments, @code{psym} will print all defined symbols and their values. +@end deffn + +Inspection and modification of the virtual machine state (memory, +registers, overflow toggle and comparison flag contents) is accomplished +using the following commands: + +@deffn {state command} pc +Prints the current value of the program counter, which stores the +address of the next instruction to be executed in a non-halted program. +@end deffn + +@deffn {state command} preg [A | X | J | I[1-6]] +@deffnx {state command} pall +@deffnx {state command} sreg A | X | J | I[1-6] value +@code{preg} prints the contents of a given MIX register. For instance, +@w{@code{preg} @var{A}} will print the contents of the A-register. When +invoked without arguments, all registers shall be printed: + +@example +MIX > preg +rA: - 00 00 00 00 35 (0000000035) +rX: + 00 00 00 15 40 (0000001000) +rJ: + 00 00 (0000) +rI1: + 00 00 (0000) rI2: + 00 00 (0000) +rI3: + 00 00 (0000) rI4: + 00 00 (0000) +rI5: + 00 00 (0000) rI6: + 00 00 (0000) +MIX > +@end example + +As you can see in the above sample, the contents is printed as the sign +plus the values of the MIX bytes stored in the register and, between +parenthesis, the decimal representation of its module. + +@code{pall} prints the contents of all registers plus the comparison +flag and overflow toggle. + +Finally, @code{sreg} Sets the contents of the given register to +@var{value}, expressed as a decimal constant. If @var{value} exceeds the +maximum value storable in the given register, @math{VALUE mod +MAXIMU_VALUE} is stored, e.g. + +@example +MIX > sreg I1 1000 +MIX > preg I1 +rI1: + 15 40 (1000) +MIX > sreg I1 1000000 +MIX > preg I1 +rI1: + 09 00 (0576) +MIX > +@end example + +@end deffn + + +@deffn {state command} pflags +@deffnx {state command} scmp E | G | L +@deffnx {state command} sover F | T +@code{pflags} prints the value of the comparison flag and overflow +toggle of the virtual machine, e.g. + +@example +MIX > pflags +Overflow: F +Cmp: E +MIX > +@end example + +@noindent +The values of the overflow toggle are either @var{F} (false) or @var{T} +(true), and, for the comparison flag, @var{E}, @var{G}, @var{L} (equal, +greater, lesser). @code{scmp} and @code{sover} are setters of the +comparison flag and overflow toggle values. +@end deffn + +@deffn {state command} pmem from[-to] +@deffnx {state command} smem address value +@code{pmem} prints the contents of memory cells in the address range +@w{[@var{FROM}-@var{TO}]}. If the upper limit @var{to} is omitted, only +the contents of the memory cell with address @var{FROM} is printed, as +in + +@example +MIX > pmem 3000 +3000: + 46 58 00 19 37 (0786957541) +MIX > +@end example + +The memory contents is displayed both as the set of five MIX bytes plus +sign composing the stored MIX word and, between parenthesis, the decimal +representation of the module of the stored value. + +@code{smem} sets the content of the memory cell with address +@var{address} to @var{value}, expressed as a decimal constant. + +@end deffn + +Finally, you can use the @code{quit} command to exit @code{mixvm}. + +@node Devices, , Commands, mixvm +@comment node-name, next, previous, up +@section MIX block devices + +The MIX computer comes equipped with a set of block devices for +input-output operations (@pxref{Input-output operators}). @code{mixvm} +implements these block devices as disk files, with the exception of +block device no. 19 (typewriter terminal) which is redirected to +standard output. When you request an output operation on any other +(output) device, a file named according to the following table will be +created in the current directory, and the specified MIX words will be +written to the file in binary form (for binary devices) or in ASCII (for +char devices). Files corresponding to input block devices should be +created and filled beforehand to be used by the MIX virtual machine (for +input-output devices this creation can be accomplished by a MIXAL +program writing to the device the required data, or, if you prefer, with +your favourite editor). + +@multitable {the device name} {xx-xx} {filena[x-x].dev} {bin i/o} +@item @emph{Device} @tab @emph{No.} @tab @emph{filename} @tab @emph{type} +@item Tape @tab 0-7 @tab @file{tape[0-7].dev} @tab bin i/o +@item Disks @tab 8-15 @tab @file{disk[0-7].dev} @tab bin i/o +@item Card reader @tab 16 @tab @file{cardrd.dev} @tab char in +@item Card writer @tab 17 @tab @file{cardwr.dev} @tab char out +@item Line printer @tab 18 @tab @file{printer.dev} @tab char out +@item Terminal @tab 19 @tab @code{stdout} @tab char out +@item Paper tape @tab 20 @tab @file{paper.dev} @tab char out +@end multitable + + + +@node mixasm, Copying, mixvm, Top +@comment node-name, next, previous, up +@chapter @code{mixasm}, the MIXAL assembler +@cindex @code{mixasm} +@cindex MIXAL +@cindex assembler + +MIX programs, as executed by @code{mixvm}, are composed of binary +instructions loaded into the virtual machine memory as MIX +words. Although you could write your MIX programs directly as a series +of words in binary format, you have at your disposal a more friendly +assembly language, MIXAL (@pxref{MIXAL}) which is compiled into binary +form by @code{mixasm}, the MIXAL assembler included in @sc{mdk}. In this +chapter, you will find a complete description of @code{mixasm} options. + +@menu +* Invoking @code{mixasm}:: @code{mixasm} options +@end menu + +@node Invoking @code{mixasm}, , mixasm, mixasm +@comment node-name, next, previous, up +@section Invoking @code{mixasm} + +In its simplest form, @code{mixasm} is invoked with a single argument, +which is the name of the MIXAL file to be compiled, e.g. + +@example +mixasm hello +@end example + +@noindent +will compile either @file{hello} or @file{hello.mixal}, producing a +binary file named @file{hello.mix} if no errors are found. + +In addition, @code{mixasm} can be invoked with the following command +line options (note, that, following GNU's conventions, we provide a long +option name for each available single letter switch): + +@example +mixasm [-vhulg] [-o OUTPUT_FILE] [--version] [--help] + [--usage] [--debug] [--output=OUTPUT_FILE] [--list[=LIST_FILE]] file +@end example + +@noindent +The meaning of these options is as follows: + +@defopt -v +@defoptx --version +Prints version and copyleft information and exits. +@end defopt + +@defopt -h +@defoptx --help +@defoptx -u +@defoptx --usage +Prints a summary of available options and exits. +@end defopt + +@defopt -g +@defoptx --debug +Includes debugging information in the compiled file, allowing breakpoint +setting at source level and symbol table inspection under @code{mixvm}. +@end defopt + +@defopt -o output_file +@defoptx --output=output_file +By default, the given source file @var{file.mixal} is compiled into +@var{file.mix}. You can provide a different name for the output file +using this option. +@end defopt + +@defopt -l +@defoptx --list[=list_file] +This option causes @code{mixasm} to produce, in addion to the +@file{.mix} file, an ASCII file containing a summary of the compilation +results. The file is named after the MIXAL source file, changing its +extension to @file{.mls} if no argument is provided; otherwise, the +listing file is named according to the argument. +@end defopt + + + +@node Copying, Problems, mixasm, Top +@chapter Copying +@lowersections +@include gpl.texi +@raisesections + +@node Problems, Concept Index, Copying, Top +@chapter Reporting Bugs +@cindex bugs +@cindex problems + +If you find a bug in @sc{mdk} (or have questions, comments or suggestions +about it), please send electronic mail to @email{jaortega@@acm.org, +the author}. + +In your report, please include the version number, which you can find by +running @w{@samp{mixasm --version}}. Also include in your message the +output that the program produced and the output you expected. + +@node Concept Index, , Problems, Top +@unnumbered Concept Index + +@cindex tail recursion +@printindex cp + +@c @node MIXAL instructions, , Concept Index, Top +@comment node-name, next, previous, up +@c @unnumbered MIXAL instructions +@c @printindex fn + +@shortcontents +@contents +@bye diff --git a/mixlib/.cvsignore b/mixlib/.cvsignore new file mode 100644 index 0000000..d2486ce --- /dev/null +++ b/mixlib/.cvsignore @@ -0,0 +1,5 @@ +.deps +Makefile +Makefile.in +mix_scanner.c + diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am new file mode 100644 index 0000000..26355cf --- /dev/null +++ b/mixlib/Makefile.am @@ -0,0 +1,37 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 jose antonio ortega ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +SUBDIRS = testsuite +INCLUDES = -I$(includedir) -DG_LOG_DOMAIN=\"libmix\" + +noinst_LIBRARIES = libmix.a +libmix_a_SOURCES = mix.h mix.c \ + mix_types.h mix_types.c \ + mix_ins.h mix_ins.c \ + mix_vm.h mix_vm.c xmix_vm.h xmix_vm.c \ + mix_vm_dump.h mix_vm_dump.c \ + mix_io.h mix_io.c xmix_io.h xmix_io.c \ + mix_symbol_table.h mix_symbol_table.c \ + mix_file.h mix_file.c \ + mix_code_file.h mix_code_file.c \ + mix_parser.h xmix_parser.h mix_parser.c mix_scanner.l \ + mix_device.h mix_device.c + + + + + + + + + + diff --git a/mixlib/mix.c b/mixlib/mix.c new file mode 100644 index 0000000..14e4c13 --- /dev/null +++ b/mixlib/mix.c @@ -0,0 +1,63 @@ +/* -*-c-*- -------------- mix.c : + * Implementation of the functions declared in mix.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#include "mix_types.h" +#include "mix_ins.h" +#include "mix_code_file.h" +#include "mix.h" + + +/* This function must be called before using the library */ +void +mix_init_lib(void) +{ + mix_init_types (); + mix_init_ins (); + mix_code_file_set_defext (MIX_CODE_DEFEXT); +} + + +/* This function must be called for deallocating the lib resources + when it is no longer in use +*/ +void +mix_release_lib (void) +{ + /* clean the user defined code file extension (if any) */ + mix_code_file_set_defext (NULL); + mix_release_ins (); +} + +const char *MIX_GPL_LICENSE = +"Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org>\n" +"This program is free software; you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation; either version 2 of the License, or\n" +"(at your option) any later version.\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program; if not, write to the Free Software\n" +"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"; + diff --git a/mixlib/mix.h b/mixlib/mix.h new file mode 100644 index 0000000..a75bbcd --- /dev/null +++ b/mixlib/mix.h @@ -0,0 +1,65 @@ +/* -*-c-*- ---------------- mix.h : + * Initialisation of the mix library + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_H +#define MIX_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#else +# warning "config.h not found, package misconfigured." +# define PACKAGE "mdk" +# define VERSION "0.0" +#endif + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif + +#ifdef HAVE_GETTEXT +# include <libintl.h> +# define gettext_noop(String) (String) +#else +# include <intl/libintl.h> +#endif + +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include <glib.h> + +/* This function must be called before using the library */ +extern void +mix_init_lib (void); + +/* This function must be called for deallocating the lib resources + when it is no longer in use +*/ +extern void +mix_release_lib (void); + + +extern const char *MIX_GPL_LICENSE; + + +#endif /* MIX_H */ + diff --git a/mixlib/mix_code_file.c b/mixlib/mix_code_file.c new file mode 100644 index 0000000..9bcd098 --- /dev/null +++ b/mixlib/mix_code_file.c @@ -0,0 +1,320 @@ +/* -*-c-*- -------------- mix_code_file.c : + * Implementation of the functions declared in mix_code_file.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include "mix.h" +#include "xmix_io.h" +#include "mix_code_file.h" + +/* mix_code_file_t type */ +static const gint32 SIGNATURE_ = 0xDEADBEEF; /* release files */ +static const gint32 SIGNATURE_D_ = 0xBEEFDEAD; /* debug files */ + +#define IS_DEBUG_(file) ((file)->header.signature == SIGNATURE_D_) +#define IS_RELEASE_(file) ((file)->header.signature == SIGNATURE_) + + +typedef struct mix_cfheader_t mix_cfheader_t; +struct mix_cfheader_t +{ + gint32 signature; + gint mj_ver; + gint mn_ver; + gint16 start; + size_t path_len; +}; + +struct mix_code_file_t +{ + mix_file_t *file; /* the underlying disk file */ + mix_address_t address; /* current address while reading */ + mix_cfheader_t header; /* file header */ + gchar *source_path; /* variable length part of the header*/ + mix_symbol_table_t *symbol_table; /* code files with debug info fill it*/ +}; + +#define to_io_(cf) MIX_IOCHANNEL (cf->file) + +/* Code files are lists of tagged words. A MIX_INS_TAG_ denotes + * that the word is an instruction, whose address is the next to + * the previous instruction's one, while a MIX_ADDR_TAG_ indicates + * that the word is a new address origin for the next instructions. + * The tags are stored as bit patterns in bit 31 of the mix word. + */ +#define MIX_ADDR_TAG_ (MIX_WORD_SIGN_BIT<<1) + +#define is_ins_(word) (((word)&MIX_ADDR_TAG_) == MIX_WORD_ZERO) +#define is_addr_(word) (((word)&MIX_ADDR_TAG_) == MIX_ADDR_TAG_) +#define tag_ins_(word) (word) +#define tag_addr_(word) ((word)|MIX_ADDR_TAG_) +#define extract_ins_(tagged) (tagged) +#define extract_addr_(tagged) ((tagged)&MIX_SHORT_MAX) + +/* mix code files have a default extension (.mix) which is customizable */ +static const gchar *DEFEXT_ = NULL; + +const gchar * +mix_code_file_get_defext (void) +{ + return DEFEXT_; +} + +gboolean +mix_code_file_set_defext (const gchar *ext) +{ + if (DEFEXT_ != NULL) g_free ((void *)DEFEXT_); + DEFEXT_ = (ext != NULL)? g_strdup (ext):NULL; + return (DEFEXT_ != NULL || ext == NULL); +} + +/* create/destroy code files for read or write */ +static mix_code_file_t * +mix_code_file_new_ (const gchar *name, mix_fmode_t mode) +{ + mix_code_file_t *result = g_new (mix_code_file_t, 1); + if ( result != NULL ) + { + result->file = mix_file_new_with_def_ext (name, mode, DEFEXT_); + result->address = MIX_SHORT_ZERO; + result->symbol_table = NULL; + } + if ( result != NULL && result->file == NULL ) + { + g_free (result); + result = NULL; + } + return result; +} + +mix_code_file_t * +mix_code_file_new_read (const gchar *name) +{ + mix_code_file_t *result = mix_code_file_new_ (name, mix_io_READ); + mix_cfheader_t *header; + FILE *file; + gboolean check; + + if ( result == NULL ) + return NULL; + + file = mix_file_to_FILE (result->file); + header = &(result->header); + check = fread (header, sizeof (mix_cfheader_t), 1, file); + + if ( check ) + check = IS_RELEASE_ (result) || IS_DEBUG_ (result); + if ( check ) + {/* a code file is compatible if its major version is + is the same as this package's and its minor version is <= */ + gint major, minor; + sscanf (VERSION, "%d.%d", &major, &minor); + check = header->mj_ver == major && header->mn_ver <= minor; + } + if ( check ) + {/* get source path */ + result->source_path = g_strnfill (1 + header->path_len, '\0'); + check = result->source_path != NULL + && fgets (result->source_path, 1 + header->path_len, file) != NULL; + } + if ( check && IS_DEBUG_ (result) ) + {/* read symbol table */ + result->symbol_table = mix_symbol_table_new_from_file (file); + check = result->symbol_table != NULL; + } + if ( !check ) + { + mix_code_file_delete (result); + return NULL; + } + return result; +} + +mix_code_file_t * +mix_code_file_new_write(const gchar *name, mix_address_t addr, + const gchar *source_path, gboolean debug, + const mix_symbol_table_t *table) +{ + mix_code_file_t *result; + FILE *file; + gboolean check; + + result = mix_code_file_new_ (name, mix_io_WRITE); + if ( result == NULL || ( file = mix_file_to_FILE (result->file) ) == NULL ) + return NULL; + else if ( source_path != NULL ) + { + result->source_path = g_strdup (source_path/*, MAX_PATH_LEN_*/); + if ( result->source_path == NULL ) + { + mix_code_file_delete (result); + return NULL; + } + } + else + result->source_path = NULL; + + result->header.signature = debug? SIGNATURE_D_:SIGNATURE_; + sscanf (VERSION, "%d.%d", &result->header.mj_ver, &result->header.mn_ver); + result->header.start = (gint16) addr; + result->header.path_len = strlen (result->source_path); + check = write_data_ (to_io_ (result), &result->header, 1); + if ( check && result->source_path != NULL ) + check = fputs (result->source_path, file) != EOF; + if ( check && debug ) + mix_symbol_table_print (table, MIX_SYM_LINE, file); + if ( !check ) + { + mix_code_file_delete (result); + return NULL; + } + return result; +} + +void +mix_code_file_delete (mix_code_file_t *file) +{ + g_return_if_fail (file != NULL); + mix_file_delete (file->file); + if ( file->source_path ) g_free (file->source_path); + g_free (file); +} + + + +/* get general parameters from a code file */ +gboolean +mix_code_file_is_debug (const mix_code_file_t *file) +{ + return (file == NULL ) ? FALSE : IS_DEBUG_ (file); +} + + +gint +mix_code_file_major_version (const mix_code_file_t *file) +{ + g_return_val_if_fail (file != NULL, 0); + return file->header.mj_ver; +} + +gint +mix_code_file_minor_version (const mix_code_file_t *file) +{ + g_return_val_if_fail (file != NULL, 0); + return file->header.mn_ver; +} + +mix_address_t +mix_code_file_get_start_addr (const mix_code_file_t *file) +{ + g_return_val_if_fail (file != NULL, MIX_SHORT_ZERO); + return mix_short_new (file->header.start); +} + +mix_symbol_table_t * +mix_code_file_get_symbol_table(mix_code_file_t *file) +{ + mix_symbol_table_t *result = NULL; + g_return_val_if_fail (file != NULL, NULL); + result = file->symbol_table; + file->symbol_table = NULL; + return result; +} + +/* read instructions from a code file */ +gboolean +mix_code_file_is_eof (mix_code_file_t *file) +{ + return is_eof_ (to_io_ (file)); +} + +gboolean +mix_code_file_get_ins (mix_code_file_t *file, mix_ins_desc_t *desc) +{ + mix_word_t next; + g_return_val_if_fail (file != NULL, FALSE); + g_return_val_if_fail (desc != NULL, FALSE); + while (TRUE) + { + if ( ! mix_io_read_word_array (to_io_ (file), &next, 1) ) return FALSE; + if ( is_addr_ (next) ) + file->address = extract_addr_ (next); + else if ( is_ins_ (next) ) + { + desc->ins = extract_ins_ (next); + desc->address = (file->address)++; + if ( IS_DEBUG_ (file) ) + { + mix_short_t lineno; + if ( !mix_io_read_short_array (to_io_ (file), &lineno, 1) ) + return FALSE; + desc->lineno = mix_short_magnitude (lineno); + } + else + desc->lineno = 0; + return TRUE; + } + else + { + g_assert_not_reached (); + return FALSE; + } + }; +} + +/* Write instructions to a code file */ +gboolean +mix_code_file_write_ins (mix_code_file_t *file, const mix_ins_desc_t *desc) +{ + g_return_val_if_fail (desc != NULL, FALSE); + return ( mix_code_file_set_address (file, desc->address) && + mix_code_file_write_next_ins (file, desc->ins, desc->lineno) ); +} + +gboolean +mix_code_file_write_next_ins (mix_code_file_t *file, mix_word_t ins, + guint lineno) +{ + g_return_val_if_fail (file != NULL, FALSE); + if ( mix_io_write_word (to_io_ (file), tag_ins_ (ins)) + && ( IS_RELEASE_ (file) + || mix_io_write_short (to_io_ (file), mix_short_new (lineno)) ) + ) + { + ++(file->address); + return TRUE; + } + else + return FALSE; +} + +gboolean +mix_code_file_set_address (mix_code_file_t *file, mix_address_t address) +{ + g_return_val_if_fail(file != NULL, FALSE); + if ( file->address != address ) { + if ( !mix_io_write_word (to_io_ (file), + tag_addr_ (mix_short_to_word_fast (address))) ) + return FALSE; + file->address = address; + } + return TRUE; +} + + diff --git a/mixlib/mix_code_file.h b/mixlib/mix_code_file.h new file mode 100644 index 0000000..34c0f21 --- /dev/null +++ b/mixlib/mix_code_file.h @@ -0,0 +1,102 @@ +/* -*-c-*- ---------------- mix_code_file.h : + * Declaration of mix_code_file_t, a file containing compiled mix + * instructions. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_CODE_FILE_H +#define MIX_CODE_FILE_H + +#include "mix_file.h" +#include "mix_ins.h" +#include "mix_symbol_table.h" + +/* mix_code_file_t type */ +typedef struct mix_code_file_t mix_code_file_t; + +/* instructions are loaded at specific memory addresses and related to + source line numbers +*/ +typedef struct mix_ins_desc_t mix_ins_desc_t; +struct mix_ins_desc_t +{ + mix_word_t ins; /* a mix instruction coded into a word */ + mix_address_t address; /* the address of this instruction */ + guint lineno; /* source file line no. */ +}; + +/* mix code files have a default extension (.mix) which is customizable */ +extern const gchar * +mix_code_file_get_defext(void); + +extern gboolean +mix_code_file_set_defext(const gchar *ext); + +/* create/destroy code files for read or write */ +/* if -name- does not end with defext, it is automatically appended */ +extern mix_code_file_t * +mix_code_file_new_read(const gchar *name); + +/* open a code file for write with/out debug information */ +extern mix_code_file_t * +mix_code_file_new_write(const gchar *name, mix_address_t start, + const gchar *source_path, gboolean debug, + const mix_symbol_table_t *table); + +extern void +mix_code_file_delete(mix_code_file_t *file); + +/* get general parameters from a code file */ +extern gboolean +mix_code_file_is_debug(const mix_code_file_t *file); + +extern gint +mix_code_file_major_version(const mix_code_file_t *file); + +extern gint +mix_code_file_minor_version(const mix_code_file_t *file); + +extern mix_address_t +mix_code_file_get_start_addr(const mix_code_file_t *file); + +extern mix_symbol_table_t * +mix_code_file_get_symbol_table(mix_code_file_t *file); + +/* read instructions from a code file */ +extern gboolean +mix_code_file_is_eof(mix_code_file_t *file); + +extern gboolean +mix_code_file_get_ins(mix_code_file_t *file, mix_ins_desc_t *desc); + +/* write instructions to a code file */ +extern gboolean +mix_code_file_write_ins(mix_code_file_t *file, const mix_ins_desc_t *desc); + +extern gboolean +mix_code_file_write_next_ins(mix_code_file_t *file, mix_word_t ins, + guint lineno); + +extern gboolean +mix_code_file_set_address(mix_code_file_t *file, mix_address_t address); + + +#endif /* MIX_CODE_FILE_H */ + diff --git a/mixlib/mix_device.c b/mixlib/mix_device.c new file mode 100644 index 0000000..30fee7e --- /dev/null +++ b/mixlib/mix_device.c @@ -0,0 +1,217 @@ +/* -*-c-*- -------------- mix_device.c : + * Implementation of the functions declared in mix_device.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#include "mix_file.h" +#include "mix_device.h" + +/* + Actual definition of a mix device, which can be cast to + a mix file. +*/ +struct mix_device_t +{ + mix_iochannel_t *file; + mix_device_type_t type; +}; + + +static const char *DEV_EXT_ = ".dev"; + +static const char *DEF_NAMES_[] = { + "tape0", "tape1", "tape2", "tape3", "tape4", "tape5", "tape6", "tape7", + "disk0", "disk1", "disk2", "disk3", "disk4", "disk5", "disk6", "disk7", + "cardrd", "cardwr", "printer", "console", "paper" +}; + +static const size_t SIZES_[] = { + 100, 100, 100, 100, 100, 100, 100, 100, + 100, 100, 100, 100, 100, 100, 100, 100, + 16, 16, 24, 14, 14 +}; + +static const mix_device_mode_t MODES_[] = { + mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, + mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, + mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, mix_dev_BIN, + mix_dev_BIN, mix_dev_CHAR, mix_dev_CHAR, mix_dev_CHAR, mix_dev_CHAR, + mix_dev_CHAR +}; + +static const mix_fmode_t FMODES_[] = { + mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, + mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, + mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, + mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, mix_io_RDWRT, + mix_io_READ, mix_io_WRITE, mix_io_WRITE, mix_io_RDWRT, mix_io_WRITE +}; + +#define GET_CHANNEL_(dev) (dev->file) +#define GET_FILE_(dev) ((mix_file_t *)(dev->file)) + +mix_device_t * +mix_device_new (mix_device_type_t type) +{ + mix_device_t *result = g_new (mix_device_t, 1); + g_return_val_if_fail (result != NULL, result); + result->type = type; + if (type != mix_dev_CONSOLE) { + result->file = MIX_IOCHANNEL(mix_file_new_with_def_ext (DEF_NAMES_[type], + FMODES_[type], + DEV_EXT_)); + } else + result->file = mix_io_new (stdout); + + return result; +} + +void +mix_device_delete (mix_device_t *dev) +{ + if (dev != NULL) + { + if (dev->type != mix_dev_CONSOLE && GET_FILE_(dev) != NULL) + mix_file_delete (GET_FILE_(dev)); + g_free (dev); + } +} + +mix_device_t * +mix_device_new_with_name (mix_device_type_t type, const gchar *name) +{ + mix_device_t *result = NULL; + g_return_val_if_fail (name != NULL, result); + result = g_new (mix_device_t, 1); + g_return_val_if_fail (result != NULL, result); + result->type = type; + if (type != mix_dev_CONSOLE) + { + result->file = MIX_IOCHANNEL(mix_file_new_with_def_ext (name, + FMODES_[type], + DEV_EXT_)); + } + else + { + result->file = mix_io_new (stdout); + } + return result; +} + +const char * +mix_device_get_name (mix_device_t *dev) +{ + g_return_val_if_fail (dev != NULL, NULL); + return mix_file_base_name(GET_FILE_(dev)); +} + +/* + Get the device block size +*/ +size_t +mix_device_block_size (mix_device_t *dev) +{ + g_return_val_if_fail (dev != NULL, 0); + return SIZES_[dev->type]; +} + +/* + Get the device io mode +*/ +mix_device_mode_t +mix_device_mode (mix_device_t *dev) +{ + g_return_val_if_fail (dev != NULL, 0); + return MODES_[dev->type]; +} + +/* + Write a block to the device. +*/ +gboolean +mix_device_write (mix_device_t *dev, const mix_word_t *block) +{ + gboolean result; + + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (block != NULL, FALSE); + if (FMODES_[dev->type] == mix_io_READ) return FALSE; + if (MODES_[dev->type] == mix_dev_CHAR) + result = mix_io_write_word_array_as_char (GET_CHANNEL_ (dev), + block, SIZES_[dev->type]); + else + result = mix_io_write_word_array (GET_CHANNEL_ (dev), + block, SIZES_[dev->type]); + if (result && mix_device_mode(dev) == mix_dev_CHAR) + putc ('\n', mix_io_to_FILE (GET_CHANNEL_ (dev))); + + return result; +} + +gboolean +mix_device_read (mix_device_t *dev, mix_word_t *block) +{ + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (block != NULL, FALSE); + if (FMODES_[dev->type] == mix_io_WRITE) return FALSE; + if (MODES_[dev->type] == mix_dev_CHAR) + return mix_io_read_word_array_as_char (GET_CHANNEL_ (dev), + block, SIZES_[dev->type]); + else + return mix_io_read_word_array (GET_CHANNEL_ (dev), + block, SIZES_[dev->type]); +} + +gboolean +mix_device_ioc (mix_device_t *dev, mix_short_t arg) +{ + int m; + FILE *file; + + g_return_val_if_fail (dev != NULL, FALSE); + + m = mix_short_magnitude(arg); + if (mix_short_is_negative(arg)) m = -m; + m *= sizeof (mix_word_t) * SIZES_[dev->type]; + file = mix_io_to_FILE (GET_CHANNEL_(dev)); + + if (dev->type >= mix_dev_TAPE_0 && dev->type <= mix_dev_TAPE_7) + { + if (m == 0) rewind (file); + else fseek (file, m, SEEK_CUR); + } + if (dev->type >= mix_dev_DISK_0 && dev->type <= mix_dev_DISK_7) + { + g_return_val_if_fail (m == 0, FALSE); + // position disk + } + if (dev->type == mix_dev_PAPER_TAPE) + { + g_return_val_if_fail (m == 0, FALSE); + rewind (file); + } + return TRUE; +} + +gboolean +mix_device_busy (mix_device_t *dev) +{ + return (dev != NULL && !mix_io_is_ready(GET_CHANNEL_(dev))); +} diff --git a/mixlib/mix_device.h b/mixlib/mix_device.h new file mode 100644 index 0000000..c2e7edf --- /dev/null +++ b/mixlib/mix_device.h @@ -0,0 +1,135 @@ +/* -*-c-*- ---------------- mix_device.h : + * Declaration of mix_device_t and associated methods. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_DEVICE_H +#define MIX_DEVICE_H + +#include <stddef.h> +#include "mix.h" +#include "mix_types.h" + +/* + A mix device, which derives from mix_io_channel_t +*/ +typedef struct mix_device_t mix_device_t; + +/* + The device type +*/ +typedef enum { + mix_dev_TAPE_0, + mix_dev_TAPE_1, + mix_dev_TAPE_2, + mix_dev_TAPE_3, + mix_dev_TAPE_4, + mix_dev_TAPE_5, + mix_dev_TAPE_6, + mix_dev_TAPE_7, + mix_dev_DISK_0, + mix_dev_DISK_1, + mix_dev_DISK_2, + mix_dev_DISK_3, + mix_dev_DISK_4, + mix_dev_DISK_5, + mix_dev_DISK_6, + mix_dev_DISK_7, + mix_dev_CARD_RD, + mix_dev_CARD_WR, + mix_dev_PRINTER, + mix_dev_CONSOLE, + mix_dev_PAPER_TAPE +} mix_device_type_t; + +/* + The device io mode +*/ +typedef enum { + mix_dev_BIN, + mix_dev_CHAR +} mix_device_mode_t; + +/* + Create a new device with default name and given type. +*/ +extern mix_device_t * +mix_device_new (mix_device_type_t type); + +/* + Create a new device with a given type and name. +*/ +extern mix_device_t * +mix_device_new_with_name (mix_device_type_t type, const gchar *name); + +/* + Delete a device. +*/ +extern void +mix_device_delete(mix_device_t *dev); + +/* + Get a device name +*/ +extern const char * +mix_device_get_name (mix_device_t *dev); + +/* + Get the device block size +*/ +extern size_t +mix_device_block_size (mix_device_t *dev); + +/* + Get the device io mode +*/ +extern mix_device_mode_t +mix_device_mode (mix_device_t *dev); + +/* + Write a block to the device. +*/ +extern gboolean +mix_device_write (mix_device_t *dev, const mix_word_t *block); + +/* + Read a block from the device. +*/ +extern gboolean +mix_device_read (mix_device_t *dev, mix_word_t *block); + +/* + Perform an io control operation on the device. + The parameter _arg_ is the operation's argument: + 0- rewind to beginning + <0 - rewind the given number of blocks + >0 - skip forward the given number of blocks +*/ +extern gboolean +mix_device_ioc (mix_device_t *dev, mix_short_t arg); + +/* + Check if a device is busy +*/ +extern gboolean +mix_device_busy (mix_device_t *dev); + +#endif /* MIX_DEVICE_H */ + diff --git a/mixlib/mix_file.c b/mixlib/mix_file.c new file mode 100644 index 0000000..45d45e0 --- /dev/null +++ b/mixlib/mix_file.c @@ -0,0 +1,142 @@ +/* -*-c-*- -------------- mix_file.c : + * Implementation of the functions declared in mix_file.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#include "xmix_io.h" +#include "mix_file.h" + +const gchar *MIX_SRC_DEFEXT = ".mixal", + *MIX_LIST_DEFEXT = ".mls", *MIX_CODE_DEFEXT = ".mix"; + +/* file names completions */ +#define needs_completion_(name,defext) \ + ( strcmp(name + strlen(name) - strlen(defext), defext) != 0 ) + +#define add_completion_(name, defext) \ + g_strconcat(name, defext, NULL) + +/* The actual definition of mix_file_t */ +struct mix_file_t +{ + mix_iochannel_t parent; + gchar *base_name; + gchar *ext; +}; + +/* Creation/destruction of files */ +static mix_file_t * +open_file_(const gchar *name, mix_fmode_t mode) +{ + mix_file_t *result; + FILE *file; + + file = fopen(name, fmode_to_type_(mode)); + if ( file == NULL ) return NULL; + result = g_new(mix_file_t, 1); + if ( result == NULL ) + { + fclose(file); + return NULL; + } + io_init_from_file_(MIX_IOCHANNEL(result), file); + return result; +} + +mix_file_t * +mix_file_new(const gchar *name, mix_fmode_t mode) +{ + mix_file_t *result; + gchar *bname; + + if ( name == NULL ) return NULL; + bname = g_strdup(name); + if ( bname == NULL ) return NULL; + result = open_file_(name, mode); + if ( result == NULL ) + { + g_free(bname); + return NULL; + } + result->base_name = bname; + result->ext = NULL; + return result; +} + +/* creates a file adding to its name the defext if missing */ +mix_file_t * +mix_file_new_with_def_ext(const gchar *name, mix_fmode_t mode, + const gchar *defext) +{ + const gchar *real_name; + mix_file_t *result; + + if ( name == NULL ) return NULL; + if ( defext == NULL ) return mix_file_new(name, mode); + real_name = needs_completion_(name, defext) ? + add_completion_(name, defext) : name; + result = open_file_(real_name, mode); + if ( real_name != name ) g_free((void *)real_name); + if ( result == NULL ) return NULL; + result->ext = g_strdup(defext); + if ( needs_completion_(name, defext) ) + result->base_name = g_strdup(name); + else + result->base_name = g_strndup(name, strlen(name) - strlen(defext)); + if ( result->ext == NULL || result->base_name == NULL ) + { + mix_file_delete(result); + return NULL; + } + return result; +} + +void +mix_file_delete(mix_file_t *file) +{ + g_return_if_fail(file != NULL); + io_close_(MIX_IOCHANNEL(file)); + if (file->base_name) g_free(file->base_name); + if (file->ext) g_free(file->ext); + g_free(file); +} + +/* convert to a standard FILE */ +extern FILE * +mix_file_to_FILE(const mix_file_t *file) +{ + if ( file == NULL ) return NULL; + return io_get_FILE_(file); +} + +/* Get the base name and extension of file */ +const gchar * +mix_file_base_name(const mix_file_t *file) +{ + g_return_val_if_fail(file != NULL, NULL); + return file->base_name; +} + +const gchar * +mix_file_extension(const mix_file_t *file) +{ + g_return_val_if_fail(file != NULL, NULL); + return file->ext; +} diff --git a/mixlib/mix_file.h b/mixlib/mix_file.h new file mode 100644 index 0000000..5be6717 --- /dev/null +++ b/mixlib/mix_file.h @@ -0,0 +1,61 @@ +/* -*-c-*- ---------------- mix_file.h : + * Declarations for the mix_file_t type. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_FILE_H +#define MIX_FILE_H + +#include "mix_io.h" + +/* The mix_file_t type, deriving from mix_iochannel_t and + representing a disk file +*/ +typedef struct mix_file_t mix_file_t; + +/* Creation/destruction of files */ +extern mix_file_t * +mix_file_new(const gchar *name, mix_fmode_t mode); + +/* creates a file adding to its name the defext if missing */ +extern mix_file_t * +mix_file_new_with_def_ext(const gchar *name, mix_fmode_t mode, + const gchar *defext); + +extern void +mix_file_delete(mix_file_t *file); + +/* convert to a standard FILE */ +extern FILE * +mix_file_to_FILE(const mix_file_t *file); + +/* standard default extensions */ +extern const gchar *MIX_SRC_DEFEXT, *MIX_LIST_DEFEXT, *MIX_CODE_DEFEXT; + +/* Get the base name and extension of file */ +extern const gchar * +mix_file_base_name(const mix_file_t *file); + +extern const gchar * +mix_file_extension(const mix_file_t *file); + + +#endif /* MIX_FILE_H */ + diff --git a/mixlib/mix_ins.c b/mixlib/mix_ins.c new file mode 100644 index 0000000..c5fcaf7 --- /dev/null +++ b/mixlib/mix_ins.c @@ -0,0 +1,258 @@ +/* -*-c-*- ------------------ mix_ins.c : + * Implementation of the functions declared in mix_ins.h + * ------------------------------------------------------------------ + * Copyright (C) 1999 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include "mix_ins.h" + +/* -------------------------------------> MOVE to VM +static mix_time_t interlock_time_ = 0; +static const mix_time_t exec_times_[] = { + 1, 2, 2, 10, 12, 10, 2, 1, + 2, 2, 2, 2 , 2, 2, 2, 2, + 2, 2, 2, 2 , 2, 2, 2, 2, + 2, 2, 2, 2 , 2, 2, 2, 2, + 2, 2, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2 , 2, 2, 2, 2 +}; +------------------------------------------------------*/ + + + +struct mix_ins_desc_ +{ + mix_opcode_t opcode; + mix_fspec_t def_fspec; + const gchar *string_rep; + gboolean is_ext; +}; + +#define IDES_(c,f,s) {c,f,#s,FALSE} +#define IDESX_(c,f,s) {c,f,#s,TRUE} + +static const struct mix_ins_desc_ id_to_desc_[] = { + IDES_(0,0,NOP), IDES_(1,5,ADD), IDES_(2,5,SUB), IDES_(3,5,MUL), + IDES_(4,5,DIV), + IDESX_(5,0,NUM), IDESX_(5,1,CHAR), IDESX_(5,2,HLT), + IDESX_(6,0,SLA), IDESX_(6,1,SRA), IDESX_(6,2,SLAX), IDESX_(6,3,SRAX), + IDESX_(6,4,SLC), IDESX_(6,5,SRC), + IDES_(7,1,MOVE), IDES_(8,5,LDA), IDES_(9,5,LD1), IDES_(10,5,LD2), + IDES_(11,5,LD3), IDES_(12,5,LD4), IDES_(13,5,LD5), + IDES_(14,5,LD6), IDES_(15,5,LDX), IDES_(16,5,LDAN), IDES_(17,5,LD1N), + IDES_(18,5,LD2N), IDES_(19,5,LD3N), IDES_(20,5,LD4N), + IDES_(21,5,LD5N), IDES_(22,5,LD6N), IDES_(23,5,LDXN), + IDES_(24,5,STA), IDES_(25,5,ST1), IDES_(26,5,ST2), IDES_(27,5,ST3), + IDES_(28,5,ST4), IDES_(29,5,ST5), IDES_(30,5,ST6), IDES_(31,5,STX), + IDES_(32,2,STJ), IDES_(33,5,STZ), IDES_(34,0,JBUS), IDES_(35,0,IOC), + IDES_(36,0,IN), IDES_(37,0,OUT), IDES_(38,0,JRED), + IDESX_(39,0,JMP), IDESX_(39,1,JSJ), IDESX_(39,2,JOV), IDESX_(39,3,JNOV), + IDESX_(39,4,JL), IDESX_(39,5,JE), IDESX_(39,6,JG), IDESX_(39,7,JGE), + IDESX_(39,8,JNE), IDESX_(39,9,JLE), + IDESX_(40,0,JAN), IDESX_(40,1,JAZ), IDESX_(40,2,JAP), IDESX_(40,3,JANN), + IDESX_(40,4,JANZ), IDESX_(40,5,JANP), + IDESX_(41,0,J1N), IDESX_(41,1,J1Z), IDESX_(41,2,J1P), IDESX_(41,3,J1NN), + IDESX_(41,4,J1NZ), IDESX_(41,5,J1NP), + IDESX_(42,0,J2N), IDESX_(42,1,J2Z), IDESX_(42,2,J2P), IDESX_(42,3,J2NN), + IDESX_(42,4,J2NZ), IDESX_(42,5,J2NP), + IDESX_(43,0,J3N), IDESX_(43,1,J3Z), IDESX_(43,2,J3P), IDESX_(43,3,J3NN), + IDESX_(43,4,J3NZ), IDESX_(43,5,J3NP), + IDESX_(44,0,J4N), IDESX_(44,1,J4Z), IDESX_(44,2,J4P), IDESX_(44,3,J4NN), + IDESX_(44,4,J4NZ), IDESX_(44,5,J4NP), + IDESX_(45,0,J5N), IDESX_(45,1,J5Z), IDESX_(45,2,J5P), IDESX_(45,3,J5NN), + IDESX_(45,4,J5NZ), IDESX_(45,5,J5NP), + IDESX_(46,0,J6N), IDESX_(46,1,J6Z), IDESX_(46,2,J6P), IDESX_(46,3,J6NN), + IDESX_(46,4,J6NZ), IDESX_(46,5,J6NP), + IDESX_(47,0,JXN), IDESX_(47,1,JXZ), IDESX_(47,2,JXP), IDESX_(47,3,JXNN), + IDESX_(47,4,JXNZ), IDESX_(47,5,JXNP), + IDESX_(48,0,INCA), IDESX_(48,1,DECA), IDESX_(48,2,ENTA), IDESX_(48,3,ENNA), + IDESX_(49,0,INC1), IDESX_(49,1,DEC1), IDESX_(49,2,ENT1), IDESX_(49,3,ENN1), + IDESX_(50,0,INC2), IDESX_(50,1,DEC2), IDESX_(50,2,ENT2), IDESX_(50,3,ENN2), + IDESX_(51,0,INC3), IDESX_(51,1,DEC3), IDESX_(51,2,ENT3), IDESX_(51,3,ENN3), + IDESX_(52,0,INC4), IDESX_(52,1,DEC4), IDESX_(52,2,ENT4), IDESX_(52,3,ENN4), + IDESX_(53,0,INC5), IDESX_(53,1,DEC5), IDESX_(53,2,ENT5), IDESX_(53,3,ENN5), + IDESX_(54,0,INC6), IDESX_(54,1,DEC6), IDESX_(54,2,ENT6), IDESX_(54,3,ENN6), + IDESX_(55,0,INCX), IDESX_(55,1,DECX), IDESX_(55,2,ENTX), IDESX_(55,3,ENNX), + IDES_(56,5,CMPA), IDES_(57,5,CMP1), IDES_(58,5,CMP2), IDES_(59,5,CMP3), + IDES_(60,5,CMP4), IDES_(61,5,CMP5), IDES_(62,5,CMP6), IDES_(63,5,CMPX) +}; + +static const gsize ID_TO_DESC_SIZE_= + sizeof(id_to_desc_)/sizeof(id_to_desc_[0]); + +/* To look for the mix_ins_id corresponding to a pair (fspec,opcode) + we use an array indexed by opcode with values + (initial_ins, final_ins - initial_ins) +*/ +struct mix_opcode_desc_ +{ + mix_ins_id_t init_id; + guchar inc; /* when inc == 0, the id does not depend on fspec */ +}; + +static struct mix_opcode_desc_ opcode_to_id_[MIX_BYTE_MAX + 1]; + +/* a hash table mapping strings to mix_ins_id's */ +static GHashTable *string_to_id_ = NULL; + +void +mix_init_ins(void) +{ + guint k; + g_assert(ID_TO_DESC_SIZE_ == mix_INVALID_INS); + + for ( k = 0; k < MIX_BYTE_MAX + 1; ++k ) + { + opcode_to_id_[k].init_id = mix_INVALID_INS; + opcode_to_id_[k].inc = 0; + } + + for ( k = 0; k < ID_TO_DESC_SIZE_; ++k ) + { + if ( opcode_to_id_[id_to_desc_[k].opcode].init_id == mix_INVALID_INS ) + opcode_to_id_[id_to_desc_[k].opcode].init_id = k; + else + ++opcode_to_id_[id_to_desc_[k].opcode].inc; + } + + if ( string_to_id_ == NULL ) + { + string_to_id_ = g_hash_table_new(g_str_hash, g_str_equal); + for ( k = 0; k < ID_TO_DESC_SIZE_; ++k) + g_hash_table_insert(string_to_id_, (gpointer)id_to_desc_[k].string_rep, + GUINT_TO_POINTER(k)); + } + +} + +void +mix_release_ins(void) +{ + g_hash_table_destroy(string_to_id_); +} + +/* Conversions between words and ins */ +mix_word_t +mix_ins_to_word(const mix_ins_t *ins) +{ + g_return_val_if_fail(ins != NULL, MIX_WORD_ZERO); + return (mix_word_t)((ins->address<<18)| + ((ins->index&7)<<12)|(ins->fspec<<6)|(ins->opcode)); +} + +mix_ins_id_t +mix_word_to_ins(mix_word_t word, mix_ins_t *ins) +{ + mix_ins_id_t result = mix_get_ins_id(mix_get_ins_opcode(word), + mix_get_ins_fspec(word)); + + g_return_val_if_fail(ins != NULL, result); + mix_word_to_ins_uncheck(word,*ins); + return result; +} + +/* Getting ins parameters */ +mix_opcode_t +mix_get_opcode_from_id(mix_ins_id_t id) +{ + g_return_val_if_fail(id < ID_TO_DESC_SIZE_, MIX_BYTE_ZERO); + return id_to_desc_[id].opcode; +} + +gboolean +mix_ins_id_is_extended(mix_ins_id_t id) +{ + g_return_val_if_fail(id < ID_TO_DESC_SIZE_, FALSE); + return id_to_desc_[id].is_ext; +} + + +mix_fspec_t +mix_get_fspec_from_id(mix_ins_id_t id) +{ + g_return_val_if_fail(id < ID_TO_DESC_SIZE_, MIX_BYTE_ZERO); + return id_to_desc_[id].def_fspec; +} + + +const gchar * +mix_get_string_from_id(mix_ins_id_t id) +{ + g_return_val_if_fail(id < ID_TO_DESC_SIZE_, NULL); + return id_to_desc_[id].string_rep; +} + +mix_ins_id_t +mix_get_id_from_string(const gchar *name) +{ + gpointer key, value; + if ( !g_hash_table_lookup_extended(string_to_id_, (gpointer)name, + &key, &value) ) + return mix_INVALID_INS; + return (mix_ins_id_t)GPOINTER_TO_UINT(value); +} + + +mix_ins_id_t +mix_get_ins_id(mix_opcode_t code, mix_fspec_t fspec) +{ + if ( opcode_to_id_[code].inc == 0 ) + return opcode_to_id_[code].init_id; + else if ( opcode_to_id_[code].inc < fspec ) + return mix_INVALID_INS; + else + return (opcode_to_id_[code].init_id + fspec); +} + +/* Printable representation */ +extern gchar * /* this pointer must be freed by caller */ +mix_ins_to_string(const mix_ins_t *ins) +{ + gboolean needs_f; + gchar *result; + mix_ins_id_t id; + + g_return_val_if_fail(ins != NULL, NULL); + id = mix_ins_id_from_ins(*ins); + needs_f = ins->fspec != id_to_desc_[id].def_fspec; + if ( needs_f ) + result = g_strdup_printf("%s\t%s%d,%d(%d:%d)", + mix_get_string_from_id(id), + mix_short_is_negative(ins->address)?"-":"", + mix_short_magnitude(ins->address), ins->index, + mix_fspec_left(ins->fspec), + mix_fspec_right(ins->fspec)); + else + result = g_strdup_printf("%s\t%s%d,%d", mix_get_string_from_id(id), + mix_short_is_negative(ins->address)?"-":"", + mix_short_magnitude(ins->address), ins->index); + return result; +} + +void +mix_ins_print(const mix_ins_t *ins) +{ + g_return_if_fail(ins != NULL); + g_print(mix_get_string_from_id(mix_ins_id_from_ins(*ins))); + g_print(" %s%d,%d(%d:%d)", mix_short_is_negative(ins->address)?"-":"+", + mix_short_magnitude(ins->address), ins->index, + mix_fspec_left(ins->fspec), mix_fspec_right(ins->fspec)); +} + diff --git a/mixlib/mix_ins.h b/mixlib/mix_ins.h new file mode 100644 index 0000000..5915a19 --- /dev/null +++ b/mixlib/mix_ins.h @@ -0,0 +1,192 @@ +/* -*-c-*- -------------------- mix_ins.h: + * This file declares types and functions for manipulating MIX + * instructions + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_INS_H +#define MIX_INS_H + +#include "mix_types.h" + + +/* Initialise and free mix_ins data */ +extern void +mix_init_ins(void); + +extern void +mix_release_ins(void); + +/* A MIX instruction is made up of address, index, fspec and op_code */ + +/*-- Address field: contains two bytes */ +typedef mix_short_t mix_address_t; + +/*-- Index field: a value between 0 and 6 */ +typedef enum { + mix_I0, mix_I1, mix_I2, mix_I3, mix_I4, mix_I5, mix_I6 } mix_index_t; + +/*-- Instruction id: enumeration of MIX instruction set */ +typedef enum { + mix_NOP, mix_ADD, mix_SUB, mix_MUL, mix_DIV, + mix_NUM, mix_CHAR, mix_HLT, + mix_SLA, mix_SRA, mix_SLAX, mix_SRAX, mix_SLC, mix_SRC, + mix_MOVE, mix_LDA, mix_LD1, mix_LD2, mix_LD3, mix_LD4, mix_LD5, + mix_LD6, mix_LDX, mix_LDAN, mix_LD1N, mix_LD2N, mix_LD3N, mix_LD4N, + mix_LD5N, mix_LD6N, mix_LDXN, mix_STA, mix_ST1, mix_ST2, mix_ST3, mix_ST4, + mix_ST5, mix_ST6, mix_STX, mix_STJ, mix_STZ, mix_JBUS, mix_IOC, mix_IN, + mix_OUT, mix_JRED, + mix_JMP, mix_JSJ, mix_JOV, mix_JNOV, mix_JL, mix_JE, mix_JG, mix_JGE, + mix_JNE, mix_JLE, + mix_JAN, mix_JAZ, mix_JAP, mix_JANN, mix_JANZ, mix_JANP, + mix_J1N, mix_J1Z, mix_J1P, mix_J1NN, mix_J1NZ, mix_J1NP, + mix_J2N, mix_J2Z, mix_J2P, mix_J2NN, mix_J2NZ, mix_J2NP, + mix_J3N, mix_J3Z, mix_J3P, mix_J3NN, mix_J3NZ, mix_J3NP, + mix_J4N, mix_J4Z, mix_J4P, mix_J4NN, mix_J4NZ, mix_J4NP, + mix_J5N, mix_J5Z, mix_J5P, mix_J5NN, mix_J5NZ, mix_J5NP, + mix_J6N, mix_J6Z, mix_J6P, mix_J6NN, mix_J6NZ, mix_J6NP, + mix_JXN, mix_JXZ, mix_JXP, mix_JXNN, mix_JXNZ, mix_JXNP, + mix_INCA, mix_DECA, mix_ENTA, mix_ENNA, + mix_INC1, mix_DEC1, mix_ENT1, mix_ENN1, + mix_INC2, mix_DEC2, mix_ENT2, mix_ENN2, + mix_INC3, mix_DEC3, mix_ENT3, mix_ENN3, + mix_INC4, mix_DEC4, mix_ENT4, mix_ENN4, + mix_INC5, mix_DEC5, mix_ENT5, mix_ENN5, + mix_INC6, mix_DEC6, mix_ENT6, mix_ENN6, + mix_INCX, mix_DECX, mix_ENTX, mix_ENNX, + mix_CMPA, mix_CMP1, mix_CMP2, mix_CMP3, mix_CMP4, + mix_CMP5, mix_CMP6, mix_CMPX, mix_INVALID_INS +} mix_ins_id_t; + +/* each one of the above id's has associated an opcode, a default + fspec and a string representation */ +/* the opcode fits in a byte */ +typedef mix_byte_t mix_opcode_t; + +/* labels for each opcode */ +enum { + mix_opNOP = 0, mix_opADD, mix_opSUB, mix_opMUL, mix_opDIV, + mix_opSPC, mix_opSLx, mix_opMOVE, + mix_opLDA, mix_opLD1, mix_opLD2, mix_opLD3, mix_opLD4, mix_opLD5, + mix_opLD6, mix_opLDX, mix_opLDAN, mix_opLD1N, mix_opLD2N, mix_opLD3N, + mix_opLD4N, mix_opLD5N, mix_opLD6N, mix_opLDXN, + mix_opSTA, mix_opST1, mix_opST2, mix_opST3, mix_opST4, + mix_opST5, mix_opST6, mix_opSTX, mix_opSTJ, mix_opSTZ, + mix_opJBUS, mix_opIOC, mix_opIN, mix_opOUT, mix_opJRED, + mix_opJMP, mix_opJAx, mix_opJ1x, mix_opJ2x, mix_opJ3x, + mix_opJ4x, mix_opJ5x, mix_opJ6x, mix_opJXx, + mix_opINCA, mix_opINC1, mix_opINC2, mix_opINC3, + mix_opINC4, mix_opINC5, mix_opINC6, mix_opINCX, + mix_opCMPA, mix_opCMP1, mix_opCMP2, mix_opCMP3, mix_opCMP4, + mix_opCMP5, mix_opCMP6, mix_opCMPX +}; + +extern mix_opcode_t +mix_get_opcode_from_id(mix_ins_id_t id); + +extern mix_fspec_t +mix_get_fspec_from_id(mix_ins_id_t id); + +/* For extended instructions, both the opcode and fspec determine + the id (i.e., an explicit fspec cannot be used) +*/ +extern gboolean +mix_ins_id_is_extended(mix_ins_id_t id); + +extern const gchar * +mix_get_string_from_id(mix_ins_id_t id); + +extern mix_ins_id_t +mix_get_id_from_string(const gchar *name); + +extern mix_ins_id_t +mix_get_ins_id(mix_opcode_t code, mix_fspec_t fspec); + + +/*-- MIX instruction type */ +typedef struct mix_ins_t mix_ins_t; +struct mix_ins_t +{ + mix_address_t address; + mix_index_t index; + mix_fspec_t fspec; + mix_opcode_t opcode; +}; + +#define mix_ins_fill_from_id(ins,id) \ + do { \ + (ins).opcode = mix_get_opcode_from_id(id); \ + (ins).fspec = mix_get_fspec_from_id(id); \ + } while(FALSE) + + +/* A mix ins can be codified into a word */ +extern mix_word_t +mix_ins_to_word(const mix_ins_t *ins); + +extern mix_ins_id_t +mix_word_to_ins(mix_word_t w, mix_ins_t *ins); + +#define mix_word_set_address(word,addr) (word) |= ((addr)<<18) + +/* decompose an instruction codified in a word into its parts */ +#define mix_get_ins_address(word) ((mix_address_t)((word)>>18)) +#define mix_get_ins_index(word) ((mix_index_t)(((word)>>12)&7)) +#define mix_get_ins_fspec(word) ((mix_fspec_t)(mix_byte_new((word)>>6))) +#define mix_get_ins_opcode(word) ((mix_opcode_t)(mix_byte_new(word))) + +/* unchecked versions for speed */ +#define mix_ins_to_word_uncheck(ins) \ + (mix_word_t)(((ins).address<<18)| \ + (((ins).index&7)<<12)|((ins).fspec<<6)|((ins).opcode)) + +#define mix_word_to_ins_uncheck(word,ins) \ + do { \ + (ins).address = mix_get_ins_address(word); \ + (ins).index = mix_get_ins_index(word); \ + (ins).fspec = mix_get_ins_fspec(word); \ + (ins).opcode = mix_get_ins_opcode(word); \ + } while(FALSE) + +#define mix_ins_id_from_ins(ins) mix_get_ins_id((ins).opcode,(ins).fspec) + + +/* Printable representation */ +extern gchar * /* this pointer must be freed by caller */ +mix_ins_to_string(const mix_ins_t *ins); + +extern void +mix_ins_print(const mix_ins_t *ins); + + + +/* A MIX ins has an associated execution time */ +/* Initialise mix_ins data providing an interlock time for I/O devices */ +/* --------------------------------------> MOVE to VM +typedef guint mix_time_t; + +extern void +mix_init_ins_with_interlock_time(mix_time_t t); + +extern mix_time_t +mix_ins_exec_time(const mix_ins_t *ins); +*/ + +#endif /* MIX_INS_H */ diff --git a/mixlib/mix_io.c b/mixlib/mix_io.c new file mode 100644 index 0000000..9014902 --- /dev/null +++ b/mixlib/mix_io.c @@ -0,0 +1,220 @@ +/* -*-c-*- --------------- mix_io.c : + * Implementation of the functions declared in mix_io.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#include "xmix_io.h" + +mix_iochannel_t * +mix_io_new (FILE *file) +{ + mix_iochannel_t *result; + g_return_val_if_fail (file != NULL, NULL); + result = g_new (mix_iochannel_t, 1); + g_return_val_if_fail (result != NULL, NULL); + result->file = file; + return result; +} + +void +mix_io_delete (mix_iochannel_t *ch) +{ + if (ch != NULL) + { + fclose (ch->file); + g_free (ch); + } +} + +FILE * +mix_io_to_FILE (mix_iochannel_t *ioc) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + return ioc->file; +} + +gboolean +mix_io_eof (mix_iochannel_t *ioc) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + return is_eof_ (ioc); +} + +gboolean +mix_io_is_ready (mix_iochannel_t *ioc) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + return is_ready_ (ioc); +} + +gboolean +mix_io_write_byte (mix_iochannel_t *ioc, mix_byte_t b) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + return write_data_ (ioc, &b, 1); +} + +gboolean +mix_io_write_byte_array (mix_iochannel_t *ioc, const mix_byte_t *b, + size_t s) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (b != NULL, FALSE); + return write_data_ (ioc, b, s); +} + + +mix_byte_t +mix_io_read_byte (mix_iochannel_t *ioc) +{ + mix_byte_t result = MIX_BYTE_ZERO; + g_return_val_if_fail (ioc != NULL, result); + g_return_val_if_fail (read_data_ (ioc, &result, 1), MIX_BYTE_ZERO); + return result; +} + +gboolean +mix_io_read_byte_array (mix_iochannel_t *ioc, mix_byte_t *b, size_t s) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (b != NULL, FALSE); + return read_data_ (ioc, b, s); +} + +gboolean +mix_io_write_word (mix_iochannel_t *ioc, mix_word_t w) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + return write_data_ (ioc, &w, 1); +} + +gboolean +mix_io_write_word_array (mix_iochannel_t *ioc, const mix_word_t *w, + size_t s) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (w != NULL, FALSE); + return write_data_ (ioc, &w, s); +} + +mix_word_t +mix_io_read_word (mix_iochannel_t *ioc) +{ + mix_word_t result = MIX_WORD_ZERO; + g_return_val_if_fail (ioc != NULL, result); + g_return_val_if_fail (read_data_ (ioc, &result, 1), MIX_WORD_ZERO); + return result; +} + +gboolean +mix_io_read_word_array (mix_iochannel_t *ioc, mix_word_t *w, size_t s) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (w != NULL, FALSE); + return read_data_ (ioc, w, s); +} + +gboolean +mix_io_write_short (mix_iochannel_t *ioc, mix_short_t w) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + return write_data_ (ioc, &w, 1); +} + +gboolean +mix_io_write_short_array (mix_iochannel_t *ioc, const mix_short_t *w, + size_t s) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (w != NULL, FALSE); + return write_data_ (ioc, &w, s); +} + +mix_short_t +mix_io_read_short (mix_iochannel_t *ioc) +{ + mix_short_t result = MIX_SHORT_ZERO; + g_return_val_if_fail (ioc != NULL, result); + g_return_val_if_fail (read_data_ (ioc, &result, 1), MIX_SHORT_ZERO); + return result; +} + +gboolean +mix_io_read_short_array (mix_iochannel_t *ioc, mix_short_t *w, size_t s) +{ + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (w != NULL, FALSE); + return read_data_ (ioc, w, s); +} + +gboolean +mix_io_write_char (mix_iochannel_t *ioc, mix_char_t c) +{ + guchar value = mix_char_to_ascii (c); + g_return_val_if_fail (ioc != NULL, FALSE); + return write_data_ (ioc, &value, 1); +} + +mix_char_t +mix_io_read_char (mix_iochannel_t *ioc) +{ + guchar value; + g_return_val_if_fail (ioc != NULL, MIX_CHAR_MAX); + g_return_val_if_fail (read_data_ (ioc, &value, 1), MIX_CHAR_MAX); + return mix_ascii_to_char (value); +} + +gboolean +mix_io_write_word_array_as_char (mix_iochannel_t *ioc, + const mix_word_t *w, size_t s) +{ + guint k, j; + + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (w != NULL, FALSE); + + for (k = 0; k < s; k++) + for (j = 1; j < 6; j++) + { + mix_char_t ch = mix_word_get_byte (w[k], j); + guchar value = mix_char_to_ascii (ch); + if (!write_data_ (ioc, &value, 1)) return FALSE; + } + return TRUE; +} + +gboolean +mix_io_read_word_array_as_char (mix_iochannel_t *ioc, + mix_word_t *w, size_t s) +{ + guint k, j; + + g_return_val_if_fail (ioc != NULL, FALSE); + g_return_val_if_fail (w != NULL, FALSE); + + for (k = 0; k < s; k++) + for (j = 1; j < 6; j++) + { + guchar value; + if (!read_data_ (ioc, &value, 1)) return FALSE; + mix_word_set_byte (&w[k], j, mix_ascii_to_char (value)); + } + return TRUE; +} diff --git a/mixlib/mix_io.h b/mixlib/mix_io.h new file mode 100644 index 0000000..f153398 --- /dev/null +++ b/mixlib/mix_io.h @@ -0,0 +1,123 @@ +/* -*-c-*- ------------------ mix_io.h : + * Declarations for mix_iochannel_t and mix_file_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_IOCHANNEL_H +#define MIX_IOCHANNEL_H + +#include <stdio.h> +#include "mix_types.h" + +/* mix_iochannel_t: an object for input/output of mix types */ +typedef struct mix_iochannel_t mix_iochannel_t; + +/* Cast to mix_iochannel_t */ +#define MIX_IOCHANNEL(file) (mix_iochannel_t *)(file) + +/* I/O channels can be created in different modes: */ +typedef enum { + mix_io_READ, /* read existing file */ + mix_io_WRITE, /* write new file */ + mix_io_RDWRT, /* read/write existing from beginning */ + mix_io_APPEND, /* append to existing or new file */ + mix_io_RAPPEND /* read from beginning, append to end */ +} mix_fmode_t; + +/* Create from a file handle */ +extern mix_iochannel_t * +mix_io_new (FILE *file); + +/* Delete */ +extern void +mix_io_delete(mix_iochannel_t *ch); + +/* Convert to a FILE * */ +extern FILE * +mix_io_to_FILE (mix_iochannel_t *ioc); + +/* Read/write from/to an iochannel */ +extern gboolean +mix_io_eof(mix_iochannel_t *ioc); + +extern gboolean +mix_io_is_ready(mix_iochannel_t *ioc); + +extern gboolean +mix_io_write_byte(mix_iochannel_t *ioc, mix_byte_t b); + +extern gboolean +mix_io_write_byte_array(mix_iochannel_t *ioc, const mix_byte_t *b, + size_t s); + + +extern mix_byte_t +mix_io_read_byte(mix_iochannel_t *ioc); + +extern gboolean +mix_io_read_byte_array(mix_iochannel_t *ioc, mix_byte_t *b, size_t s); + + +extern gboolean +mix_io_write_word(mix_iochannel_t *ioc, mix_word_t w); + + +extern gboolean +mix_io_write_word_array(mix_iochannel_t *ioc, const mix_word_t *w, + size_t s); + +extern mix_word_t +mix_io_read_word(mix_iochannel_t *ioc); + +extern gboolean +mix_io_read_word_array(mix_iochannel_t *ioc, mix_word_t *w, size_t s); + +extern gboolean +mix_io_write_short(mix_iochannel_t *ioc, mix_short_t w); + + +extern gboolean +mix_io_write_short_array(mix_iochannel_t *ioc, const mix_short_t *w, + size_t s); + +extern mix_short_t +mix_io_read_short(mix_iochannel_t *ioc); + +extern gboolean +mix_io_read_short_array(mix_iochannel_t *ioc, mix_short_t *w, size_t s); + + +extern gboolean +mix_io_write_char(mix_iochannel_t *ioc, mix_char_t c); + +extern mix_char_t +mix_io_read_char(mix_iochannel_t *ioc); + +extern gboolean +mix_io_write_word_array_as_char (mix_iochannel_t *ioc, + const mix_word_t *w, size_t s); + +extern gboolean +mix_io_read_word_array_as_char (mix_iochannel_t *ioc, + mix_word_t *w, size_t s); + + +#endif /* MIX_IOCHANNEL_H */ + diff --git a/mixlib/mix_parser.c b/mixlib/mix_parser.c new file mode 100644 index 0000000..74317ac --- /dev/null +++ b/mixlib/mix_parser.c @@ -0,0 +1,519 @@ +/* -*-c-*- -------------- mix_parser.c : + * Implementation of the functions declared in mix_parser.h and + * xmix_parser.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include "mix.h" +#include "mix_code_file.h" +#include "xmix_parser.h" + +/* The flex-generated scanner, according to file mix_parser.l */ +extern mix_parser_err_t +mix_flex_scan (mix_parser_t *parser); + +/*------------ mixparser.h functions -------------------------------------*/ + +/* error messages */ +static const gchar * const ERR_MESSAGE_[] = { + N_("successful compilation"), + N_("file not yet compiled"), + N_("internal error"), + N_("unable to open MIX source file"), + N_("unable to open MIX output file"), + N_("unexpected end of file"), + N_("invalid location field"), + N_("duplicated symbol"), + N_("symbol too long"), + N_("missing operator field"), + N_("unexpected location symbol"), + N_("invalid address field"), + N_("invalid index field"), + N_("invalid f-specification"), + N_("invalid operation field"), + N_("invalid expression"), + N_("undefined symbol"), + N_("mismatched parenthesis"), + N_("unexpected f-specfication"), + N_("missing symbol name"), + N_("symbol is an instruction name"), + N_("failed write access to code file"), + N_("operand of ALF pseudo instruction has less than 5 chars"), + N_("operand of ALF pseudo instruction has more than 5 chars") +}; + +static const guint NO_OF_MESSAGES_ = sizeof(ERR_MESSAGE_)/sizeof (gchar*); + +const gchar * +mix_parser_err_string (mix_parser_err_t error) +{ + return (error < NO_OF_MESSAGES_) ? _(ERR_MESSAGE_[error]) : NULL; +} + +guint +mix_parser_err_count (const mix_parser_t *parser) +{ + return (parser) ? parser->err_count : 0; +} + +guint +mix_parser_warning_count (const mix_parser_t *parser) +{ + return (parser) ? parser->warn_count : 0; +} + +const gchar * +mix_parser_src_file_base_name (const mix_parser_t *parser) +{ + return (parser) ? mix_file_base_name (parser->in_file) : NULL; +} + +const gchar * +mix_parser_src_file_extension (const mix_parser_t *parser) +{ + return (parser) ? mix_file_extension (parser->in_file) : NULL; +} + + +/* Create/destroy a mix_parser */ +/* compare function for the table of ins */ +static gint +compare_shorts_ (gconstpointer s1, gconstpointer s2) +{ + mix_short_t a = (mix_short_t)GPOINTER_TO_UINT(s1); + mix_short_t b = (mix_short_t)GPOINTER_TO_UINT (s2); + if ( mix_short_sign (a) == mix_short_sign (b) ) + return mix_short_magnitude (a) - mix_short_magnitude (b); + else if ( mix_short_magnitude (a) == 0 && mix_short_magnitude (b) == 0 ) + return 0; + else if ( mix_short_is_positive (a) ) + return 1; + return -1; +} + +mix_parser_t * +mix_parser_new (const gchar *in_file) +{ + mix_parser_t *result; + mix_file_t *f = mix_file_new_with_def_ext (in_file, mix_io_READ, + MIX_SRC_DEFEXT); + + if ( f == NULL ) return NULL; + result = g_new (mix_parser_t, 1); + if ( result == NULL ) + { + g_warning (_("No system resources")); + mix_file_delete (f); + return NULL; + } + result->symbol_table = mix_symbol_table_new (); + result->ls_table = mix_symbol_table_new (); + result->cur_ls = 0; + result->future_refs = g_hash_table_new (g_str_hash, g_str_equal); + result->ins_table = g_tree_new (compare_shorts_); + if ( result->symbol_table == NULL || result->future_refs == NULL + || result->ins_table == NULL || result->ls_table == NULL ) + { + mix_symbol_table_delete (result->symbol_table); + mix_symbol_table_delete (result->ls_table); + g_hash_table_destroy (result->future_refs); + g_tree_destroy (result->ins_table); + mix_file_delete (f); + g_free (result); + g_warning (_("No system resources")); + return NULL; + } + result->in_file = f; + result->loc_count = MIX_SHORT_ZERO; + result->status = MIX_PERR_NOCOMP; + result->err_line = 0; + result->err_count = 0; + result->warn_count = 0; + return result; +} + +static void +delete_list_vals_ (gpointer key, gpointer value, gpointer data) +{ + g_free (key); + g_slist_free ((GSList*)value); +} + +static int +delete_tree_vals_ (gpointer key, gpointer value, gpointer data) +{ + g_free (value); + return FALSE; +} + +void +mix_parser_delete (mix_parser_t *parser) +{ + g_return_if_fail (parser != NULL); + /* clear the GSList values of future_refs and its keys */ + g_hash_table_foreach (parser->future_refs, delete_list_vals_, NULL); + /* clear the ins_node_'s of the ins tree */ + g_tree_traverse (parser->ins_table, delete_tree_vals_, G_IN_ORDER, NULL); + /* destroy the tree and hash tables */ + g_tree_destroy (parser->ins_table); + mix_symbol_table_delete (parser->symbol_table); + mix_symbol_table_delete (parser->ls_table); + g_hash_table_destroy (parser->future_refs); + mix_file_delete (parser->in_file); + g_free (parser); +} + +/* Compile a mix source file */ +static gboolean +undef_warning_ (gpointer symbol, gpointer value, gpointer data) +{ + mix_parser_log_error ((mix_parser_t *)data, MIX_PERR_UNDEF_SYM, 1, + (const gchar *)symbol, TRUE); + /* move the symbol to the symbol table */ + mix_symbol_table_insert_static (((mix_parser_t *)data)->symbol_table, symbol, + MIX_WORD_ZERO); + return TRUE; +} + +static void +update_future_refs_ (mix_parser_t *parser, const gchar *name) +{ + GSList *list = NULL; + gpointer key; + + g_assert (parser != NULL && name != NULL); + + if ( g_hash_table_lookup_extended (parser->future_refs, name, &key, + (gpointer *)&list) ) + { + GSList *tmp = list; + ins_node_ *node; + while ( tmp != NULL ) + { + node = + (ins_node_ *)g_tree_lookup (parser->ins_table,tmp->data); + g_assert (node); + mix_word_set_address (node->ins, parser->loc_count); + g_tree_insert (parser->ins_table, tmp->data, (gpointer)node); + tmp = g_slist_next (tmp); + } + g_hash_table_remove (parser->future_refs, name); + g_free (key); + g_slist_free (list); + } +} + +static void +update_ls_ (gpointer symbol, gpointer value, gpointer parser) +{ /* add an instruction on current location and update refs to it */ + mix_ins_t ins; + mix_word_t w = (mix_word_t) GPOINTER_TO_UINT (value); + mix_parser_t *par = (mix_parser_t *) parser; + + mix_word_to_ins_uncheck (w, ins); + mix_parser_add_ins (par, &ins, 0); + update_future_refs_ (par, (const gchar *)symbol); + par->loc_count++; +} + +mix_parser_err_t +mix_parser_compile (mix_parser_t *parser) +{ + g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); + g_return_val_if_fail (parser->in_file != NULL, MIX_PERR_NOIN); + g_return_val_if_fail (parser->symbol_table != NULL, MIX_PERR_INTERNAL); + g_return_val_if_fail (parser->future_refs != NULL, MIX_PERR_INTERNAL); + g_return_val_if_fail (parser->ins_table != NULL, MIX_PERR_INTERNAL); + + parser->status = mix_flex_scan (parser); + if ( parser->status == MIX_PERR_OK ) + { + mix_symbol_table_foreach (parser->ls_table, update_ls_, + (gpointer)parser); + g_hash_table_foreach_remove (parser->future_refs, + undef_warning_, (gpointer)parser); + } + + return parser->status; +} + +/* Write a compiled source to a code file */ +struct write_code_context_ +{ + mix_code_file_t *file; + mix_parser_t *parser; +}; + +static gint +write_code_ (gpointer address, gpointer ins_node, gpointer context) +{ + mix_ins_desc_t desc; + struct write_code_context_ *cntx = (struct write_code_context_ *)context; + desc.ins = ((ins_node_ *)ins_node)->ins; + desc.lineno = ((ins_node_ *)ins_node)->lineno; + desc.address = (mix_address_t)GPOINTER_TO_UINT (address); + if ( mix_code_file_write_ins (cntx->file, &desc) ) + return FALSE; + else + { + cntx->parser->status = MIX_PERR_NOWRITE; + return TRUE; + } +} + +mix_parser_err_t +mix_parser_write_code (mix_parser_t *parser, const gchar *code_file, + gboolean debug) +{ + struct write_code_context_ context; + const gchar *cfname = (code_file) ? + code_file : mix_file_base_name (parser->in_file); + gchar *dir; + gchar *source_path; + + g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); + if (parser->status != MIX_PERR_OK ) return parser->status; + context.parser = parser; + dir = g_get_current_dir (); + source_path = g_strconcat (dir, G_DIR_SEPARATOR_S, + mix_file_base_name (parser->in_file), NULL); + context.file = mix_code_file_new_write (cfname, parser->start, source_path, + debug, parser->symbol_table); + g_free (dir); + g_free (source_path); + if (context.file == NULL) return MIX_PERR_NOOUT; + g_tree_traverse (parser->ins_table, write_code_, + G_IN_ORDER, (gpointer)&context); + mix_code_file_delete (context.file); + return parser->status; +} + +/* Produce a listing file summarising the compilation */ +static gint +write_listing_ (gpointer address, gpointer ins, gpointer context) +{ + guint k; + FILE *file = (FILE *)context; + ins_node_ *ins_node = (ins_node_ *)ins; + mix_ins_t instruct; + gchar *instext = NULL; + + mix_ins_id_t id = mix_word_to_ins (ins_node->ins, &instruct); + if (id != mix_INVALID_INS) + instext = mix_ins_to_string (&instruct); + fprintf (file, "%d\t%s ", GPOINTER_TO_INT (address), + mix_word_is_negative (ins_node->ins)? "-":"+"); + for ( k = 1; k < 6; ++k ) + fprintf (file, "%02d ", mix_word_get_byte (ins_node->ins, k)); + fprintf (file, _("\t%s\t(line %d)\n"), instext? instext:"--DATA--", + ins_node->lineno); + if (instext) g_free (instext); + return FALSE; +} + +mix_parser_err_t +mix_parser_write_listing (mix_parser_t *parser, const gchar *list_file) +{ + FILE *file; + mix_file_t *mfile; + const gchar *name; + + g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); + if (parser->status != MIX_PERR_OK ) return parser->status; + name = (list_file) ? list_file : mix_file_base_name (parser->in_file); + mfile = mix_file_new_with_def_ext (name, mix_io_WRITE, MIX_LIST_DEFEXT); + if ( mfile == NULL ) return MIX_PERR_NOOUT; + file = mix_file_to_FILE (mfile); + fprintf (file, _("*** %s%s: compilation summary ***\n\n"), + mix_file_base_name (parser->in_file), + mix_file_extension (parser->in_file)); + fputs ( _("*** Address / Compiled word / Symbolic rep / Source file line\n"), + file); + g_tree_traverse (parser->ins_table, write_listing_, + G_IN_ORDER, (gpointer)file); + fprintf (file, _("\n*** Start address: %d\n"), + mix_short_magnitude (parser->start)); + fprintf (file, _("\n*** Symbol table\n")); + mix_symbol_table_print (parser->symbol_table, MIX_SYM_ROWS, file); + fprintf (file, _("\n*** End of summary ***\n")); + mix_file_delete (mfile); + return parser->status; +} + +/* load a virtual machine's memory with the contents of a compiled file */ +static gint +load_vm_ (gpointer address, gpointer ins, gpointer vm) +{ + mix_vm_set_addr_contents ((mix_vm_t*)vm, + (mix_address_t)GPOINTER_TO_UINT (address), + ((ins_node_ *)ins)->ins); + return FALSE; +} + +mix_parser_err_t +mix_parser_load_vm (const mix_parser_t *parser, mix_vm_t *vm) +{ + g_return_val_if_fail (parser != NULL, MIX_PERR_INTERNAL); + g_return_val_if_fail (vm != NULL, MIX_PERR_INTERNAL); + g_return_val_if_fail (parser->status == MIX_PERR_OK, parser->status); + mix_vm_reset (vm); + g_tree_traverse (parser->ins_table, load_vm_, G_IN_ORDER, (gpointer)vm); + mix_vm_set_start_addr (vm, parser->start); + return parser->status; +} + + + +/*------------ xmiparser.h functions -------------------------------------*/ +/* functions to manipulate mix_parser_t during compilation */ + + +/* symbol table */ +/* Define a new symbol with value equal to the current loc_count + * and update future refs to this symbol + */ +mix_parser_err_t +mix_parser_define_symbol_here (mix_parser_t *parser, const gchar *name) +{ + mix_word_t value = mix_short_to_word_fast (parser->loc_count); + + g_assert (parser != NULL && name != NULL); + + switch (mix_symbol_table_add (parser->symbol_table, name, value)) + { + case MIX_SYM_OK: + if ( parser->status == MIX_PERR_NOCOMP ) + update_future_refs_ (parser, name); + return MIX_PERR_OK; + case MIX_SYM_LONG: return MIX_PERR_LONG_SYMBOL; + case MIX_SYM_DUP: return MIX_PERR_DUP_SYMBOL; + default: return MIX_PERR_INTERNAL; + } +} + +/* Obtain the value of a symbol */ +void +mix_parser_set_future_ref (mix_parser_t *parser, const gchar *name) +{ + const gchar *nname = name; + GSList *list; + + g_assert (parser != NULL && name != NULL); + + if ( parser->status == MIX_PERR_NOCOMP ) + { + list = g_hash_table_lookup (parser->future_refs, name); + if ( list == NULL ) nname = g_strdup (name); + list = g_slist_prepend (list, (gpointer)((guint)parser->loc_count)); + g_hash_table_insert (parser->future_refs, (gpointer)nname, list); + } +} + +/* Redefine the value of a local symbol as the current loc_count */ +void +mix_parser_manage_local_symbol (mix_parser_t *parser, const gchar *name) +{ + gchar ref[3]; + ref[2] = 0; + + g_assert (parser != NULL && name != NULL); + g_assert (strlen(name) == 2); + + switch (name[1]) + { + case 'f': case 'F': + mix_parser_set_future_ref (parser, name); + break; + case 'h': case 'H': + ref[0] = name[0]; + ref[1] = 'F'; + if ( parser->status == MIX_PERR_NOCOMP ) + update_future_refs_ (parser, ref); + ref[1] = 'B'; + mix_symbol_table_insert (parser->symbol_table, ref, + mix_short_to_word_fast (parser->loc_count)); + break; + default: + return; + } +} + +/* Literal strings symbols */ +void +mix_parser_define_ls (mix_parser_t *parser, mix_word_t value) +{ + gchar *name = g_strdup_printf ("%05d", parser->cur_ls++); + mix_symbol_table_add (parser->ls_table, name, value); + mix_parser_set_future_ref (parser, name); + g_free (name); +} + +/* Compilation */ +void +mix_parser_add_ins (mix_parser_t *parser, const mix_ins_t *new_ins, + guint lineno) +{ + g_assert (parser != NULL && new_ins != NULL); + mix_parser_add_raw (parser, mix_ins_to_word_uncheck (*new_ins), lineno); +} + +void +mix_parser_add_raw (mix_parser_t *parser, mix_word_t word, guint lineno) +{ + g_assert (parser != NULL); + if ( parser->status == MIX_PERR_NOCOMP || parser->status == MIX_PERR_OK ) + { + ins_node_ *node = g_new (ins_node_, 1); + if ( node == NULL ) { + g_warning (_("Unable to allocate memory")); + return; + } + node->ins = word; + node->lineno = lineno; + g_tree_insert (parser->ins_table, (gpointer)((guint)parser->loc_count), + (gpointer)node); + } +} + +/* Error handling */ +void +mix_parser_log_error (mix_parser_t *parser, mix_parser_err_t error, + gint lineno, const gchar *comment, gboolean warn) +{ + g_assert (parser != NULL); + if ( warn ) + parser->warn_count += 1; + else + { + parser->err_count += 1; + parser->err_line = lineno; + parser->status = error; + } + + fprintf (stderr, "%s%s:%d: %s: %s", + mix_file_base_name (parser->in_file), + mix_file_extension (parser->in_file), + lineno, warn ? _("warning"):_("error"), _(ERR_MESSAGE_[error])); + + if (comment != NULL) + fprintf (stderr, ": %s\n", comment); + else + fputs ("\n", stderr); +} + diff --git a/mixlib/mix_parser.h b/mixlib/mix_parser.h new file mode 100644 index 0000000..cd1a047 --- /dev/null +++ b/mixlib/mix_parser.h @@ -0,0 +1,110 @@ +/* -*-c-*- ---------------- mix_parser.h : + * Declarations for mix_parser_t, which compiles a source file into + * a mix code file. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_PARSER_H +#define MIX_PARSER_H + +#include <glib.h> +#include "mix_vm.h" + +/* The parser type */ +typedef struct mix_parser_t mix_parser_t; + +/* Create/destroy a mix_parser */ +extern mix_parser_t * +mix_parser_new(const gchar *in_file); + +extern void +mix_parser_delete(mix_parser_t *parser); + +/* Access source file name */ +extern const gchar * +mix_parser_src_file_base_name(const mix_parser_t *parser); + +extern const gchar * +mix_parser_src_file_extension(const mix_parser_t *parser); + +/* Compile a mix source file */ +/* compilation errors */ +typedef enum { + MIX_PERR_OK, /* no error */ + MIX_PERR_NOCOMP, /* file not yet compiled */ + MIX_PERR_INTERNAL, /* internal error */ + MIX_PERR_NOIN, /* unable to open input file */ + MIX_PERR_NOOUT, /* unable to open output file */ + MIX_PERR_UNEX_EOF, /* unexpected end of file */ + MIX_PERR_INV_LOC, /* invalid loc field */ + MIX_PERR_DUP_SYMBOL, /* duplicated symbol */ + MIX_PERR_LONG_SYMBOL, /* symbol name too long */ + MIX_PERR_NOOP, /* missing op field */ + MIX_PERR_UNEX_LOC, /* unexpected location symbol */ + MIX_PERR_INV_ADDRESS, /* invalid address field */ + MIX_PERR_INV_IDX, /* invalid index field */ + MIX_PERR_INV_FSPEC, /* invalid fspec */ + MIX_PERR_INV_OP, /* invalid operation */ + MIX_PERR_INV_EXPR, /* invalid expression */ + MIX_PERR_UNDEF_SYM, /* undefined symbol */ + MIX_PERR_MIS_PAREN, /* mismatched parenthesis */ + MIX_PERR_UNEX_FSPEC, /* unexpected f-spec */ + MIX_PERR_MIS_SYM, /* missing symbol name */ + MIX_PERR_SYM_INS, /* symbol has the same name as instruction */ + MIX_PERR_NOWRITE, /* failed code write */ + MIX_PERR_SHORT_ALF, /* short ALF operand */ + MIX_PERR_LONG_ALF /* too long ALF operand */ +} mix_parser_err_t; + +extern const gchar * +mix_parser_err_string(mix_parser_err_t error); + +extern mix_parser_err_t +mix_parser_compile(mix_parser_t *parser); + +extern guint +mix_parser_warning_count(const mix_parser_t *parser); + +extern guint +mix_parser_err_count(const mix_parser_t *parser); + +/* Write the compilation result to a code file with the given name. + code_file is completed, if required, with the requisite extension; + if code_file == NULL [source_file_name].[extension] is used. + If debug == TRUE, debug information is written. +*/ +extern mix_parser_err_t +mix_parser_write_code(mix_parser_t *parser, const gchar *code_file, + gboolean debug); + +/* Write a "canonical" listing of a compiled source, i.e. a source + file with all symbols substituted by their actual values after + compilation. +*/ +extern mix_parser_err_t +mix_parser_write_listing(mix_parser_t *parser, const gchar *list_file); + +/* load a virtual machine's memory with the contents of a compiled file */ +extern mix_parser_err_t +mix_parser_load_vm(const mix_parser_t *parser, mix_vm_t *vm); + + +#endif /* MIX_PARSER_H */ + diff --git a/mixlib/mix_scanner.l b/mixlib/mix_scanner.l new file mode 100644 index 0000000..f740d10 --- /dev/null +++ b/mixlib/mix_scanner.l @@ -0,0 +1,497 @@ +/* -*-c-*- ------------------ mix_scanner.l : + * Lexical scanner used by mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +%{ +#include "mix.h" +#include "xmix_parser.h" + +#define YY_DECL mix_parser_err_t mix_flex_scan (mix_parser_t *parser) + +#define RESET() \ + do { \ + mix_ins_fill_from_id (ins, mix_NOP); \ + ins.address = 0; \ + ins.index = 0; \ + nof = FALSE; \ + lsf = FALSE; \ + if (symbol != NULL ) \ + { \ + g_free (symbol); \ + symbol = NULL; \ + } \ + } while (FALSE) + +#define NEXT() \ + do { \ + parser->loc_count++; \ + RESET (); \ + ++lineno; \ + BEGIN (INITIAL); \ + } while (FALSE) + +#define ADD_INS() \ + do { \ + mix_parser_add_ins (parser, &ins, lineno); \ + NEXT (); \ + } while (FALSE) + +#define ADD_RAW(value) \ + do { \ + mix_parser_add_raw (parser, value, lineno); \ + NEXT (); \ + } while (FALSE) + + +#define ENTER_EVAL() \ + do { \ + expr_val = MIX_WORD_ZERO; \ + yyless (0); \ + yy_push_state (EVAL); \ + } while (FALSE) + +#define ENTER_WEVAL() \ + do { \ + wexpr_val = MIX_WORD_ZERO; \ + wexpr_val_tmp = MIX_WORD_ZERO; \ + is_fp = FALSE; \ + yyless (0); \ + yy_push_state (WEVAL); \ + } while (FALSE) + +#define RETURN_ERROR(error, comment) \ + do { \ + char c; \ + mix_parser_log_error (parser,error,lineno,comment,FALSE); \ + while ( (c = input ()) != '\n' && c != EOF ) ; \ + if ( c == EOF ) return error; else ++lineno; \ + RESET (); \ + BEGIN (INITIAL); \ + } while (FALSE) + + +static mix_word_t + eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y); + +static void + unput_word_ (mix_word_t word); + +%} + +%option nomain +%option caseless +%option pointer +%option stack +%option noyywrap +%option noyy_top_state +%option noreject +%option outfile="lex.yy.c" + +%s LOC +%s OP +%s ADDRESS +%s INDEX +%s FSPEC +%s EVAL +%s WEVAL +%s ORIG +%s CON +%s EQU +%s END + +ws [ \t]+ +digit [0-9] +letter [A-Z] +number [+-]?{digit}+ +mixchar [0-9A-Z .,'')(+*/=$<>@;:\-] +locsymbol {digit}H +flocsymbol {digit}F +blocsymbol {digit}B +symbol {digit}*{letter}+[A-Z0-9]* +binop "+"|"-"|"*"|"/"|"//"|":" +atexpr {digit}+|{symbol}|\* +expr [+-]?{atexpr}({binop}{1}{atexpr})* +fpart \({expr}\) +wexpr {expr}({fpart})?(,{expr}({fpart})?)* + + +%% + +%{ + + mix_ins_t ins; + gboolean nof = FALSE, is_fp = FALSE, end = FALSE, lsf = FALSE; + mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO, + wexpr_val_tmp = MIX_WORD_ZERO; + gchar *symbol = NULL; + guint lineno = 1; + mix_ins_fill_from_id (ins, mix_NOP); + ins.address = 0; + ins.index = 0; + parser->err_line = 0; + yyin = mix_file_to_FILE (parser->in_file); + +%} + + +<*><<EOF>> { + mix_parser_log_error (parser, MIX_PERR_UNEX_EOF, lineno, NULL, FALSE); + return MIX_PERR_UNEX_EOF; +} + +<INITIAL>{ + ^\*.* /* eat comments */ + . { + if ( end ) return parser->status; + yyless (0); + BEGIN (LOC); + } + \n { + ++lineno; + if ( end ) return parser->status; + } +} + +<LOC>{ + {ws}+ BEGIN (OP); /* LOC field is empty */ + {locsymbol} { /* manage local symbol */ + mix_parser_manage_local_symbol (parser,yytext); + BEGIN (OP); + } + {flocsymbol}|{blocsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext); + {symbol}/{ws}+EQU { /* store symbol name for future definition */ + symbol = g_strdup (yytext); + if ( symbol == NULL ) { + mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE); + return MIX_PERR_INTERNAL; + } + BEGIN (OP); + } + {symbol} { /* define a new symbol */ + mix_parser_err_t err; + if ( mix_get_id_from_string (yytext) != mix_INVALID_INS ) + mix_parser_log_error (parser, MIX_PERR_SYM_INS, lineno, yytext, TRUE); + if ( (err = mix_parser_define_symbol_here (parser,yytext)) != MIX_PERR_OK ) + mix_parser_log_error (parser, err, lineno, yytext, FALSE); + BEGIN (OP); + } + . RETURN_ERROR (MIX_PERR_INV_LOC, yytext); + \n ++lineno; /* empty line */ +} + +<OP>{ + {ws} /* eat leading whitespace */ + \n RETURN_ERROR (MIX_PERR_NOOP, NULL); + ORIG{ws}+ BEGIN (ORIG); + CON{ws}+ BEGIN (CON); + EQU{ws}+ BEGIN (EQU); + END{ws}+ BEGIN (END); + ALF{ws}+\"{mixchar}{5,}\"{ws}+.*\n | + ALF{ws}+\"{mixchar}{5,}\"{ws}*\n { + mix_byte_t bytes[5]; + mix_word_t value; + guint k, j = 4; + + while ( yytext[j++] != '\"' ) ; + for ( k = j; k < 5+j && yytext[k] != '\"'; ++k ) + bytes[k-j] = mix_ascii_to_char (yytext[k]); + if ( k-j < 5 ) + mix_parser_log_error (parser, MIX_PERR_SHORT_ALF, lineno, NULL, TRUE); + else if ( yytext[k] != '\"' ) + mix_parser_log_error (parser, MIX_PERR_LONG_ALF, lineno, NULL, TRUE); + + value = mix_bytes_to_word (bytes, 5); + + ADD_RAW (value); + } + [A-Z0-9]+{ws}*/\n | + [A-Z0-9]+{ws}+ { + mix_ins_id_t id = mix_get_id_from_string (g_strchomp (yytext)); + if ( id == mix_INVALID_INS ) + mix_parser_log_error (parser, MIX_PERR_INV_OP, lineno, yytext, FALSE); + else { + mix_ins_fill_from_id (ins, id); + nof = mix_ins_id_is_extended (id); + } + BEGIN (ADDRESS); + } + {expr} RETURN_ERROR (MIX_PERR_INV_OP, yytext); + . RETURN_ERROR (MIX_PERR_INV_OP, yytext); +} + + +<ORIG>{ + {number}{ws}*\n | + {number}{ws}+.*\n { + mix_word_t value = mix_word_new (atol (yytext)); + parser->loc_count = mix_word_to_short_fast (value); + ++lineno; + BEGIN (INITIAL); + } +} + +<CON>{ + {number}{ws}*\n | + {number}{ws}+.*\n { + mix_word_t value = mix_word_new (atol (yytext)); + mix_word_to_ins_uncheck (value, ins); + ADD_INS (); + } +} + +<EQU>{ + {number}{ws}*\n | + {number}{ws}+.*\n { + mix_word_t value; + gint def; + if ( symbol == NULL ) RETURN_ERROR (MIX_PERR_MIS_SYM, NULL); + value = mix_word_new (atol (yytext)); + def = mix_symbol_table_add (parser->symbol_table, symbol, value); + if ( def == MIX_SYM_DUP ) RETURN_ERROR (MIX_PERR_DUP_SYMBOL, symbol); + if ( def == MIX_SYM_LONG ) RETURN_ERROR (MIX_PERR_LONG_SYMBOL, symbol); + ++lineno; + BEGIN (INITIAL); + } +} + +<END>{ + {number}{ws}*\n | + {number}{ws}+.*\n { + parser->start = mix_short_new (atol (yytext)); + end = TRUE; + if ( parser->status == MIX_PERR_NOCOMP ) parser->status = MIX_PERR_OK; + return parser->status; + } +} + +<ORIG,CON,EQU,END>{ + {wexpr} ENTER_WEVAL (); + . RETURN_ERROR (MIX_PERR_INV_OP, yytext); +} + + +<ADDRESS,INDEX,FSPEC>{locsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext); + +<ADDRESS>{ + =/[+-]?{number}= lsf = TRUE; + =/{expr}= lsf = TRUE; + [+-]?{number}={ws}*\n | + [+-]?{number}={ws}+.*\n { + if (!lsf) RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext); + mix_parser_define_ls (parser, mix_word_new (atol (yytext))); + ADD_INS (); + } + [+-]?{number}{ws}+.*\n | + [+-]?{number}[(,\n] { + ins.address = mix_short_new (atol (yytext)); + switch ( yytext[yyleng-1] ) { + case '(' : BEGIN (FSPEC); break; + case ',' : BEGIN (INDEX); break; + case '\n' : ADD_INS (); break; + default: g_assert_not_reached (); + } + } + ([+-]?{symbol})/[(,\n\t ] { + gboolean neg = (yytext[0] == '-'); + const gchar *s = (neg || yytext[0] == '+')? yytext+1 : yytext; + if ( !mix_symbol_table_is_defined (parser->symbol_table, s) ) + { + mix_parser_set_future_ref (parser, s); + unput ('0'); + } + else + { + mix_word_t v = mix_symbol_table_value (parser->symbol_table, s); + if ( neg ) mix_word_reverse_sign (v); + unput_word_ (v); + } + } + {expr}/[(,=\n\t ] ENTER_EVAL (); + \n ADD_INS (); + . RETURN_ERROR (MIX_PERR_INV_ADDRESS, yytext); +} + + +<INDEX>{ + {number}[\n(\t ] { + int end = yytext[yyleng-1]; + ins.index = mix_byte_new (atol (yytext)); + if ( end == '\n' ) + ADD_INS (); + else if ( end == '(' ) + BEGIN (FSPEC); + else + { /* eat rest of line (comment) */ + while ( (end = input()) != '\n' && end != EOF ) ; + if ( end == '\n' ) ADD_INS (); + else RETURN_ERROR (MIX_PERR_UNEX_EOF, NULL); + } + } + {expr}/[\n(\t ] ENTER_EVAL (); + \n { + mix_parser_log_error (parser, MIX_PERR_INV_IDX, lineno++, NULL, FALSE); + RESET (); + BEGIN (INITIAL); + } + . RETURN_ERROR (MIX_PERR_INV_IDX, yytext); +} + +<FSPEC>{ + {number}")"(({ws}+.*\n)|\n) { + glong val = atol (yytext); + if ( val < 0 || val > MIX_BYTE_MAX ) + RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL); + if ( ins.opcode != mix_opMOVE + && ( ins.opcode < mix_opJBUS || ins.opcode > mix_opJXx ) + && !mix_fspec_is_valid (mix_byte_new (val)) ) + RETURN_ERROR (MIX_PERR_INV_FSPEC, NULL); + if ( nof ) + mix_parser_log_error (parser, MIX_PERR_INV_FSPEC, + lineno, _("ignored"), TRUE); + else + { + ins.fspec = mix_byte_new (val); + ADD_INS (); + } + } + {expr}/")" { + ENTER_EVAL (); + } + . RETURN_ERROR (MIX_PERR_INV_FSPEC, yytext); +} + + +<EVAL>{ + {binop}{digit}+ { + const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; + mix_word_t value = mix_word_new (atol (s)); + expr_val = eval_binop_ (yytext, expr_val, value); + } + {binop}{symbol} { + const gchar *s = ( yytext[1] == '/' ) ? yytext+2 : yytext+1; + if ( !mix_symbol_table_is_defined (parser->symbol_table, s) ) { + mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, FALSE); + yy_pop_state (); + } + expr_val = eval_binop_ (yytext, expr_val, + mix_symbol_table_value (parser->symbol_table, s)); + } + {binop}"*" { + expr_val = eval_binop_ (yytext, expr_val, + mix_short_to_word_fast (parser->loc_count)); + } + "*" unput_word_ (mix_short_to_word_fast (parser->loc_count)); + {number} expr_val = mix_word_new (atol (yytext)); + {symbol} { + if ( !mix_symbol_table_is_defined (parser->symbol_table, yytext) ) { + mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, yytext, FALSE); + yy_pop_state (); + } + expr_val = mix_symbol_table_value (parser->symbol_table, yytext); + } + [,)(=\n\t ] unput (yytext[0]); unput_word_ (expr_val); yy_pop_state (); + . RETURN_ERROR (MIX_PERR_INV_EXPR, yytext); +} + +<WEVAL>{ + {number}"(" { + is_fp = TRUE; + wexpr_val_tmp = mix_word_new (atol (yytext)); + } + {number}")" { + glong val = atol (yytext); + if ( !is_fp ) { + mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE); + yy_pop_state (); + } + if ( val < 0 || val > MIX_BYTE_MAX + || !mix_fspec_is_valid (mix_byte_new (val)) ) { + mix_parser_log_error (parser, MIX_PERR_INV_FSPEC, lineno, NULL, FALSE); + yy_pop_state (); + } + is_fp = FALSE; + wexpr_val = mix_word_store_field (mix_byte_new (val), wexpr_val_tmp, + wexpr_val); + } + {number} wexpr_val = mix_word_new (atol (yytext)); + {expr} ENTER_EVAL (); + ,/{expr} /* eat comma if followed by expression */ + [\n\t ] { /* ok if not inside an f-part */ + if ( is_fp ) { + mix_parser_log_error (parser, MIX_PERR_MIS_PAREN, lineno, NULL, FALSE); + yy_pop_state (); + } + unput (yytext[yyleng-1]); + unput_word_ (wexpr_val); + yy_pop_state (); + } + . RETURN_ERROR (MIX_PERR_INV_EXPR, NULL); +} + +%% + +static mix_word_t +eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y) +{ + mix_word_t result = MIX_WORD_ZERO; + switch (op[0]) + { + case '+': + result = mix_word_add (x,y); + break; + case '-': + result = mix_word_sub (x,y); + break; + case '*': + mix_word_mul (x, y, NULL, &result); + break; + case ':': + { + mix_word_t a; + mix_word_mul (x, 8, NULL, &a); + result = mix_word_add (a, y); + break; + } + case '/': + if ( strlen (op) > 1 && op[1] == '/' ) { + mix_word_div (x,MIX_WORD_ZERO,y, &result, NULL); + } else { + mix_word_div (MIX_WORD_ZERO, x, y, &result, NULL); + } + break; + default: + g_assert_not_reached (); + } + return result; +} + + +static void +unput_word_ (mix_word_t word) +{ + gchar *value; + gint k; + value = g_strdup_printf ("%s%ld", + mix_word_is_negative (word)? "-":"+", + mix_word_magnitude (word)); + for (k = strlen (value) - 1; k >= 0; --k) + unput (value[k]); + g_free (value); +} diff --git a/mixlib/mix_symbol_table.c b/mixlib/mix_symbol_table.c new file mode 100644 index 0000000..7f3c4df --- /dev/null +++ b/mixlib/mix_symbol_table.c @@ -0,0 +1,139 @@ +/* -*-c-*- -------------- mix_symbol_table.c : + * Implementation of the functions declared in mix_symbol_table.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#include "mix_symbol_table.h" + +/* Create an empty table */ +mix_symbol_table_t * +mix_symbol_table_new(void) +{ + return g_hash_table_new(g_str_hash, g_str_equal); +} + +/* Create a table and populate it with the contents of a table stored + in -file- using mix_symbol_table_print(table, MIX_SYM_LINE, file) +*/ +mix_symbol_table_t * +mix_symbol_table_new_from_file(FILE *file) +{ + mix_symbol_table_t *result = mix_symbol_table_new(); + if ( result != NULL ) + { + gchar sym[MIX_SYM_MAX_LEN + 1]; + glong val; + + while ( getc(file) == ',' ) + { + if ( fscanf(file, "%s =%ld", sym, &val) != EOF ) + mix_symbol_table_add(result, sym, mix_word_new(val)); + } + } + return result; +} + +/* Delete a table */ +static void +delete_hash_keys_(gpointer key, gpointer value, gpointer data) +{ + g_free(key); +} + +void +mix_symbol_table_delete(mix_symbol_table_t *table) +{ + g_hash_table_foreach(table, delete_hash_keys_, NULL); + g_hash_table_destroy(table); +} + + +/* Add/remove symbols one by one */ +gint +mix_symbol_table_add(mix_symbol_table_t *table, + const gchar *sym, mix_word_t value) +{ + gpointer key, val; + + if ( table == NULL || sym == NULL ) return MIX_SYM_FAIL; + if ( strlen(sym) > MIX_SYM_MAX_LEN ) return MIX_SYM_LONG; + + if ( !g_hash_table_lookup_extended(table, sym, &key, &val) ) + { + key = g_strdup(sym); + g_hash_table_insert(table, key, (gpointer)value); + return MIX_SYM_OK; + } + else + return MIX_SYM_DUP; +} + +/* Add or modify symbol if it exists */ +gint +mix_symbol_table_insert(mix_symbol_table_t *table, + const gchar *sym, mix_word_t new_value) +{ + gpointer key, val; + + if ( table == NULL || sym == NULL ) return MIX_SYM_FAIL; + if ( strlen(sym) > MIX_SYM_MAX_LEN ) return MIX_SYM_LONG; + + if ( !g_hash_table_lookup_extended(table, sym, &key, &val) ) + key = g_strdup(sym); + g_hash_table_insert(table, key, (gpointer)new_value); + return MIX_SYM_OK; +} + + +/* Symbols lookup */ +gboolean +mix_symbol_table_is_defined(const mix_symbol_table_t *table, const gchar *sym) +{ + gpointer key, val; + return g_hash_table_lookup_extended((GHashTable *)table, sym, &key, &val); +} + +/* Print table */ +static void +print_sym_rows_(gpointer symbol, gpointer value, gpointer file) +{ + mix_word_t word = (mix_word_t)GPOINTER_TO_UINT(value); + fprintf((FILE *)file, "%s: %s%ld\n", (gchar *)symbol, + mix_word_is_negative(word)? "-":"", mix_word_magnitude(word)); +} + +static void +print_sym_line_(gpointer symbol, gpointer value, gpointer file) +{ + mix_word_t word = (mix_word_t)GPOINTER_TO_UINT(value); + fprintf((FILE *)file, ",%s =%s%ld", (gchar *)symbol, + mix_word_is_negative(word)? "-":"", mix_word_magnitude(word)); +} + +void +mix_symbol_table_print(const mix_symbol_table_t *table, gint mode, FILE *file) +{ + GHFunc func = (mode == MIX_SYM_LINE)? print_sym_line_ : print_sym_rows_; + if ( table != NULL ) + g_hash_table_foreach((GHashTable *)table, func, (gpointer)file); + if ( mode == MIX_SYM_LINE ) putc(';', file); /* to mark end-of-table */ +} + + diff --git a/mixlib/mix_symbol_table.h b/mixlib/mix_symbol_table.h new file mode 100644 index 0000000..d9eaede --- /dev/null +++ b/mixlib/mix_symbol_table.h @@ -0,0 +1,99 @@ +/* -*-c-*- ---------------- mix_symbol_table.h : + * Type mix_symbol_table_t and functions to manipulate it. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_SYMBOL_TABLE_H +#define MIX_SYMBOL_TABLE_H + +#include <stdio.h> +#include "mix_types.h" + +/* A symbol table shall be implemented as a hash table */ +typedef GHashTable mix_symbol_table_t ; + +/* Maximum length of stored symbols */ +#define MIX_SYM_MAX_LEN 10 + +/* Create an empty table */ +extern mix_symbol_table_t * +mix_symbol_table_new(void); + +/* Create a table and populate it with the contents of a table stored + in -file- using mix_symbol_table_print(table, MIX_SYM_LINE, file) +*/ +extern mix_symbol_table_t * +mix_symbol_table_new_from_file(FILE *file); + + +/* Delete a table */ +extern void +mix_symbol_table_delete(mix_symbol_table_t *table); + +/* Add/remove symbols one by one */ +/* possible outcomes: */ +enum { + MIX_SYM_FAIL, /* attempt failed */ + MIX_SYM_OK, + MIX_SYM_DUP, /* duplicated symbol */ + MIX_SYM_LONG /* symbol too long: only MIX_SYM_MAX_LEN chars used */ +}; + +extern gint +mix_symbol_table_add(mix_symbol_table_t *table, + const gchar *sym, mix_word_t value); + +#define mix_symbol_table_remove(table, sym) \ + g_hash_table_remove(table, sym) + + +/* Add or modify symbol if it exists */ +extern gint +mix_symbol_table_insert(mix_symbol_table_t *table, + const gchar *sym, mix_word_t new_value); + +/* Add or modify symbol if it exists, without copiying sym */ +#define mix_symbol_table_insert_static(table,sym,value)\ + g_hash_table_insert(table,(gpointer)sym,GUINT_TO_POINTER(value)) + +/* Symbols lookup */ +extern gboolean +mix_symbol_table_is_defined(const mix_symbol_table_t *table, const gchar *sym); + +#define mix_symbol_table_value(table,sym) \ + (mix_word_t)GPOINTER_TO_UINT (g_hash_table_lookup ((GHashTable *)table, \ + (gpointer)sym)) + +/* Traverse the table */ +#define mix_symbol_table_foreach(table,func,data) \ + g_hash_table_foreach(table,func,data) + +/* Print the table */ +enum { + MIX_SYM_ROWS, /* each symbol/value in a row */ + MIX_SYM_LINE /* {,symbol =value}*; in a single row */ +}; + +extern void +mix_symbol_table_print(const mix_symbol_table_t *table, gint mode, FILE *file); + + +#endif /* MIX_SYMBOL_TABLE_H */ + diff --git a/mixlib/mix_types.c b/mixlib/mix_types.c new file mode 100644 index 0000000..32b505f --- /dev/null +++ b/mixlib/mix_types.c @@ -0,0 +1,543 @@ +/* -*-c-*- ------------------ mix_types.c : + * Implementation file for mix_types.h declarations. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include "mix.h" +#include <limits.h> +#include "mix_types.h" + + +/*------------------------ initialisation stuff ------------------------*/ +/* flag telling whether a field spec is valid */ +static gboolean is_bad_field_[MIX_BYTE_MAX + 1]; +/* shift associated with a fspec */ +static guint shift_[MIX_BYTE_MAX + 1]; +/* mask associated with a fspec */ +static glong mask_[MIX_BYTE_MAX + 1]; + +/* maps from gchar's to mix_char_t */ +#define NONP_ (guchar)('?') +static mix_char_t ascii_to_mix_char_[UCHAR_MAX + 1]; +static guchar mix_char_to_ascii_[MIX_CHAR_MAX + 1] = { + ' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'd', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 's', 'p', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', + '7', '8', '9', '.', ',', '(', ')', '+', '-', '*', '/', '=', '$', + '<', '>', '@', ';', ':', '\'' +}; + + +/* initialise the above arrays */ +void +mix_init_types (void) +{ + guint lt, rt; + for (lt = 0; lt < 8; ++lt) + for (rt = 0; rt < 8; ++rt) + { + guint F = 8 * lt + rt; + is_bad_field_[F] = rt < lt || 5 < rt; + if ( is_bad_field_[F] ) + shift_[F] = 0, mask_[F] = 0; + else + { + guint width = rt - (lt == 0 ? 1 : lt) + 1; + shift_[F] = 6 * (5 - rt); + mask_[F] = ((1L << (6 * width)) - 1) << shift_[F]; + } + } + + for ( lt = 0; lt < UCHAR_MAX + 1; ++lt ) + ascii_to_mix_char_[lt] = NONP_; + for ( lt = 0; lt < MIX_CHAR_MAX + 1; ++lt ) + ascii_to_mix_char_[mix_char_to_ascii_[lt]] = (guchar)lt; +} + +mix_char_t +mix_ascii_to_char (guchar c) +{ + return ascii_to_mix_char_[c]; +} + + +guchar +mix_char_to_ascii (mix_char_t c) +{ + return c > MIX_CHAR_MAX ? NONP_ : mix_char_to_ascii_[c]; +} + + +/*---------------------------- m_word_t --------------------------------- */ + +/* Create mix_word_t from an array of mix_byte_t */ +mix_word_t +mix_bytes_to_word (mix_byte_t *bytes, guint byteno) +{ + mix_word_t result = 0; + guint k; + + g_return_val_if_fail (bytes != NULL, MIX_WORD_ZERO); + g_return_val_if_fail (byteno != 0, MIX_WORD_ZERO); + + if ( byteno > 5 ) byteno = 5; + for ( k = 0; k < byteno; k++ ) + result |= ((gulong)bytes[k]) << (6*(byteno-k-1)); + + return result; +} + + +/* Field operations */ +mix_word_t /* the specified field or 0 if f is not valid */ +mix_word_get_field (mix_fspec_t f, mix_word_t word) +{ + mix_word_t result; + + g_return_val_if_fail (!is_bad_field_[f],MIX_WORD_ZERO); + + result = ( (word & mask_[f]) >> shift_[f] ); + if (f < 8) /* if f is of the form (0:R), retain the sign of word */ + result |= mix_word_sign (word); + + return result; +} + + +mix_word_t +mix_word_set_field (mix_fspec_t f, mix_word_t from, mix_word_t to) +{ + mix_word_t result; + glong m = mask_[f]; + + g_return_val_if_fail (!is_bad_field_[f],to); + + if (f < 8) /* if F is of the form (0:R), use the sign of -from- */ + result = (to & ~m & ~MIX_WORD_SIGN_BIT) + | ((from /*<< shift_[f]*/) & m) | mix_word_sign (from); + else + result = (to & ~m) | ((from /*<< shift_[f]*/) & m); + + return result; +} + +mix_word_t +mix_word_store_field (mix_fspec_t f, mix_word_t from, mix_word_t to) +{ + mix_word_t result; + glong m = mask_[f]; + + g_return_val_if_fail (!is_bad_field_[f],to); + + if (f < 8) /* if F is of the form (0:R), use the sign of -from- */ + result = (to & ~m & ~MIX_WORD_SIGN_BIT) + | ((from << shift_[f]) & m) | mix_word_sign (from); + else + result = (to & ~m) | ((from << shift_[f]) & m); + + return result; +} + + + +gboolean +mix_fspec_is_valid (mix_fspec_t f) +{ + return !(is_bad_field_[f]); +} + +mix_byte_t +mix_word_get_byte (mix_word_t word, /* word parsed */ + guint idx /* byte: 1 to 5 */ ) +{ + mix_byte_t fspec = mix_fspec_new (idx,idx); + + g_return_val_if_fail ((idx > 0 && idx < 6), MIX_BYTE_ZERO); + + return mix_byte_new (mix_word_get_field (fspec,word)); +} + + +extern void +mix_word_set_byte (mix_word_t *into, guint idx, mix_byte_t value) +{ + mix_word_t from = value; + mix_byte_t fspec = mix_fspec_new (idx,idx); + + g_return_if_fail (into != NULL); + g_return_if_fail (idx > 0 && idx < 6); + + from <<= shift_[fspec]; + *into = mix_word_set_field (fspec,from,*into); +} + +/* Arithmetic operations */ +mix_word_t +mix_word_add (mix_word_t x, mix_word_t y) +{ + static const gulong MIX_WORD_MAX_SIM = 2*MIX_WORD_MAX + 1; + + gint32 result; + if ( mix_word_sign (x) == mix_word_sign (y) ) + { + result = (mix_word_magnitude (x) + mix_word_magnitude (y)); + if ( result > MIX_WORD_MAX ) { + /* for instance MIX_WORD_MAX + 1 = - MIX_WORD_MAX */ + result = MIX_WORD_MAX_SIM - result; + result |= mix_word_sign (mix_word_negative (x)); + } else if ( result != 0 ) + result |= mix_word_sign (x); + /* keep positive sign for 0 so that w - w == -w + w */ + } + else + { + result = mix_word_magnitude (x) - mix_word_magnitude (y); + if (result < 0) + result = -result|mix_word_sign (y); + else if (result > 0) + result = result|mix_word_sign (x); + /* keep positive sign for 0 so that w - w == -w + w */ + } + + g_assert ( result >= 0 ); + + return (mix_word_t)result; +} + +gboolean /* TRUE if overflow */ +mix_word_add_and_carry (mix_word_t x, mix_word_t y, + mix_word_t *h, mix_word_t *l) +{ + gboolean result; + + if ( mix_word_sign (x) == mix_word_sign (y) ) + { + guint32 sum = (mix_word_magnitude (x) + mix_word_magnitude (y)); + if ( sum > MIX_WORD_MAX ) + { + result = TRUE; + if ( l != NULL ) + { + *l = sum - MIX_WORD_MAX -1; + *l |= mix_word_sign (x); + } + if ( h != NULL ) + { + *h = sum >> 30; + *h |= mix_word_sign (x); + } + } + else /* sum <= MIX_WORD_MAX */ + { + result = FALSE; + if ( h != NULL ) *h = 0; + if ( l != NULL ) + { + *l = sum; + if ( sum != 0 ) + *l |= mix_word_sign (x); + /* keep positive sign for 0 so that w - w == -w + w */ + } + } + } + else /* mix_word_sign (x) != mix_word_sign (y) */ + { + result = FALSE; + if ( h != NULL ) *h = 0; + if ( l != NULL ) + { + gint32 dif = mix_word_magnitude (x) - mix_word_magnitude (y); + if ( dif < 0) + *l = (-dif)|mix_word_sign (y); + else if ( dif > 0) + *l = dif|mix_word_sign (x); + else /* keep positive sign for 0 so that w - w == -w + w */ + *l = MIX_WORD_ZERO; + } + } + + return result; +} + + +void +mix_word_mul (mix_word_t x, mix_word_t y, + mix_word_t *high_word, mix_word_t *low_word) +{ + guint32 sign = mix_word_sign (x) ^ mix_word_sign (y); + + /* + x = x0 + x1 * 2 ^ 10 + x2 * 2 ^ 20 + y = y0 + y1 * 2 ^ 10 + y2 * 2 ^ 20 + x0, x1, x2, y0, y1, y2 are < 2 ^ 10 + */ + guint32 x0 = (x & 0x000003FF); + guint32 x1 = (x & 0x000FFC00) >> 10; + guint32 x2 = (x & 0x3FF00000) >> 20; + guint32 y0 = (y & 0x000003FF); + guint32 y1 = (y & 0x000FFC00) >> 10; + guint32 y2 = (y & 0x3FF00000) >> 20; + + /* + x * y = partial0 + + partial1 * 2 ^ 10 + + partial2 * 2 ^ 20 + + partial3 * 2 ^ 30 + + partial4 * 2 ^ 40 + partial0 and partial4 are < 2 ^ 20 + partial1 and partial3 are < 2 ^ 21 + partial2 is < 3 * 2 ^ 20 + */ + guint32 partial0 = x0 * y0; + guint32 partial1 = x0 * y1 + x1 * y0; + guint32 partial2 = x0 * y2 + x1 * y1 + x2 * y0; + guint32 partial3 = x1 * y2 + x2 * y1; + guint32 partial4 = x2 * y2; + + /* sum1 has a place value of 1 and is < 2 ^ 32 */ + guint32 sum1 = partial0 + (partial1 << 10); + guint32 carry1 = (sum1 & 0xFFF00000) >> 20; + + /* sum2 has a place value of 2 ^ 20 and is < 2 ^ 32 */ + guint32 sum2 = partial2 + (partial3 << 10) + carry1; + guint32 carry2 = (sum2 & 0xFFF00000) >> 20; + + /* sum3 has a place value of 2 ^ 40 and is < 2 ^ 20 */ + guint32 sum3 = partial4 + carry2; + + sum1 &= ~0xFFF00000; + sum2 &= ~0xFFF00000; + + /* + Now paste the three values back into two. + */ + if ( low_word != NULL ) { + *low_word = sum1 | ((sum2 & 0x000003FF) << 20); + *low_word |= sign; + } + if ( high_word != NULL ) { + *high_word = ((sum2 & 0x000FFC00) >> 10) | (sum3 << 10); + *high_word |= sign; + } +} + + +gboolean +mix_word_div (mix_word_t n1, mix_word_t n0, mix_word_t d, + mix_word_t *quotient, mix_word_t *remainder) +{ + gboolean overflow = FALSE; + long magn1 = mix_word_magnitude (n1); + long magd = mix_word_magnitude (d); + + if (magd == 0) + { + overflow = TRUE; + /* just so they have -some- valid value */ + if ( quotient != NULL ) *quotient = 0; + if ( remainder != NULL ) *remainder = 0; + } + else if (magn1 == 0) + { /* special-cased for speed */ + if ( quotient != NULL ) + *quotient = (mix_word_sign (n1) ^ mix_word_sign (d)) + | (mix_word_magnitude (n0) / magd); + if ( remainder != NULL ) + *remainder = mix_word_sign (n1) | (mix_word_magnitude (n0) % magd); + } + else if (magd <= magn1) + { + overflow = TRUE; + if ( quotient != NULL ) *quotient = 0; + if ( remainder != NULL ) *remainder = 0; + } + else + { + long q = mix_word_magnitude (n0); + long r = magn1; + unsigned i; + for (i = 30; i != 0; --i) { + r <<= 1; + if ( (q & (1L << 29)) != 0 ) + ++r; + q = (q << 1) & ((1L << 30) - 1); + if (magd <= r) + ++q, r -= magd; + } + if ( quotient != NULL ) + *quotient = (mix_word_sign (n1) ^ mix_word_sign (d)) | q; + if ( remainder != NULL ) + *remainder = mix_word_sign(n1) | r; + } + return overflow; +} + +void +mix_word_shift_right (mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX) +{ + if ( pX != NULL ) *pX = mix_word_sign (X); + if ( pA != NULL ) *pA = mix_word_sign (A); + if (count < 5) { + if ( pA != NULL ) + *pA |= mix_word_magnitude (A) >> (6 * count); + if ( pX != NULL ) + *pX |= MIX_WORD_MAX & ( (mix_word_magnitude (X) >> (6 * count)) + | (A << (30 - 6 * count)) ); + } else if (count < 10 && pX != NULL) + *pX |= mix_word_magnitude (A) >> (6 * count - 30); + else + ; +} + + +void +mix_word_shift_left (mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX) +{ + if ( pX != NULL ) *pX = mix_word_sign (X); + if ( pA != NULL ) *pA = mix_word_sign (A); + if (count < 5) { + if ( pX != NULL ) *pX |= MIX_WORD_MAX & (X << (6 * count)); + if ( pA != NULL ) + *pA |= MIX_WORD_MAX & ( (A << (6 * count)) | + (mix_word_magnitude (X) >> (30 - 6 * count)) ); + } else if (count < 10 && pA != NULL) + *pA |= MIX_WORD_MAX & (X << (6 * count - 30)); + else + ; +} + +void +mix_word_shift_left_circular (mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX) +{ + mix_word_t A1, X1; + guint c; + + count %= 10; + A1 = count < 5 ? A : X; + X1 = count < 5 ? X : A; + c = 6 * (count < 5 ? count : count - 5); + if ( pX != NULL ) + *pX = mix_word_sign (X) + | ( MIX_WORD_MAX & (X1 << c) ) | ( mix_word_magnitude (A1) >> (30 - c) ); + if ( pA != NULL ) + *pA = mix_word_sign (A) + | ( MIX_WORD_MAX & (A1 << c) ) | ( mix_word_magnitude (X1) >> (30 - c) ); +} + +void +mix_word_shift_right_circular (mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX) +{ + mix_word_t A1, X1; + guint c; + + count %= 10; + A1 = count < 5 ? A : X; + X1 = count < 5 ? X : A; + c = 6 * (count < 5 ? count : count - 5); + if ( pX != NULL ) + *pX = mix_word_sign (X) + | ( mix_word_magnitude (X1) >> c ) | ( MIX_WORD_MAX & (A1 << (30 - c)) ); + if ( pA != NULL ) + *pA = mix_word_sign (A) + | ( mix_word_magnitude (A1) >> c ) | ( MIX_WORD_MAX & (X1 << (30 - c)) ); +} + + +/* Printable representation */ +void +mix_word_print (mix_word_t word, const char *message) +{ + guint k; + if ( message ) g_print ("%s ", message); + g_print ("%s ", mix_word_sign (word) == 0 ? "+" : "-"); + for ( k = 1; k < 6; ++k ) { + g_print ("%02d ", mix_word_get_byte (word,k)); + } + g_print ("(%010ld)", mix_word_magnitude (word)); +} + +/* Conversions between words and shorts */ +mix_short_t +mix_word_to_short (mix_word_t word) +{ + if ( mix_word_is_negative (word) ) + return ( (word & MIX_SHORT_MAX) | MIX_SHORT_SIGN_BIT ); + else + return (word & MIX_SHORT_MAX); +} + +mix_word_t +mix_short_to_word (mix_short_t s) +{ + if ( mix_short_is_negative (s) ) + return ((mix_word_t) (mix_short_magnitude (s) | MIX_WORD_SIGN_BIT)); + else + return ((mix_word_t)s); +} + +mix_short_t +mix_short_add (mix_short_t x, mix_short_t y) +{ + static const guint16 MIX_SHORT_MAX_SIM = 2*MIX_SHORT_MAX + 1; + + gint16 result; + if ( mix_short_sign (x) == mix_short_sign (y) ) + { + result = (mix_short_magnitude (x) + mix_short_magnitude (y)); + if ( result > MIX_SHORT_MAX ) { + /* for instance MIX_SHORT_MAX + 1 = - MIX_SHORT_MAX */ + result = MIX_SHORT_MAX_SIM - result; + result |= mix_short_sign (mix_short_negative (x)); + } else if ( result != 0 ) + result |= mix_short_sign (x); + /* keep positive sign for 0 so that w - w == -w + w */ + } + else + { + result = mix_short_magnitude (x) - mix_short_magnitude (y); + if (result < 0) + result = -result|mix_short_sign (y); + else if (result > 0) + result = result|mix_short_sign (x); + /* keep positive sign for 0 so that w - w == -w + w */ + } + + g_assert ( result >= 0 ); + + return (mix_short_t)result; +} + + +/* Printable representation */ +void +mix_short_print (mix_short_t s, const gchar *message) +{ + if ( message ) g_print ("%s ", message); + g_print ("%s ", mix_short_sign (s) == 0 ? "+" : "-"); + g_print ("%02d %02d ", mix_byte_new (s>>6), mix_byte_new (s)); + g_print ("(%04d)", mix_short_magnitude (s)); +} + + + + diff --git a/mixlib/mix_types.h b/mixlib/mix_types.h new file mode 100644 index 0000000..a011d18 --- /dev/null +++ b/mixlib/mix_types.h @@ -0,0 +1,283 @@ +/* -*-c-*- --------------- mix_types.h: + * This file contains declarations for the basic types used in MIX: + * mix_byte_t, mix_char_t, mix_short_t and mix_word_t. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_TYPES_H +#define MIX_TYPES_H + +#include <glib.h> + +/* Initialisation function to be called before using the other + * functions in this file + */ +extern void +mix_init_types(void); + + +/*----------------- m_byte_t --------------------------------------------*/ +/* MIX byte type */ +typedef guint8 mix_byte_t; + +/* Maximum value stored in an mix_byte_t */ +#define MIX_BYTE_MAX ((1L << 6) - 1) + +/* Zero mix byte */ +#define MIX_BYTE_ZERO ((mix_byte_t)0) + +/* Create a mix_byte_t from any native type */ +#define mix_byte_new(x) ((mix_byte_t)((x) & MIX_BYTE_MAX )) + +/* Operations */ +/* Addition */ +#define mix_byte_add(x,y) mix_byte_new((x) + (y)) +/* Substraction */ +#define mix_byte_sub(x,y) mix_byte_new((x) - (y)) +/* Product */ +#define mix_byte_mul(x,y) mix_byte_new((x) * (y)) +/* Quotient */ +#define mix_byte_div(x,y) mix_byte_new((x) / (y)) + + +/*----------------- mix_char_t --------------------------------------------*/ +/* MIX char type: chars are coded in MIX from 0 to MIX_CHAR_MAX */ +typedef guint8 mix_char_t; + +#define MIX_CHAR_MAX 55 + +/* Conversions for mix_char_t's */ +#define mix_char_to_byte(mchar) mix_byte_new(mchar) +#define mix_byte_to_char(byte) ((mix_char_t)(byte&MIX_CHAR_MAX)) + +extern mix_char_t +mix_ascii_to_char(guchar c); + +extern guchar +mix_char_to_ascii(mix_char_t c); + + +/*----------------- mix_word_t --------------------------------------------*/ +/* + * Represented as a gint32 (glib ensures that this type has 32 + * bits). Bit 30 is the sign, higher bits are 0, + * and bits 0-29 are the magnitude. + * Each MIX 'byte' is a 6-bit substring of the magnitude. + */ +typedef guint32 mix_word_t; + +/* Maximum value stored in an mix_word_t */ +#define MIX_WORD_MAX ((1L << 30) - 1) +/* Sign bit in a word */ +#define MIX_WORD_SIGN_BIT (1L << 30) +/* Zero mix word */ +#define MIX_WORD_ZERO ((mix_word_t)0) +/* Negative zero mix word */ +#define MIX_WORD_MINUS_ZERO (MIX_WORD_ZERO | MIX_WORD_SIGN_BIT) + + +/* Create a mix_word_t from any native type */ +#define mix_word_new(x) \ +( (x) < 0 \ + ? ( MIX_WORD_SIGN_BIT | ((mix_word_t)(-(x)) & MIX_WORD_MAX) ) \ + : ( (mix_word_t)(x) & MIX_WORD_MAX ) \ +) + +/* Create a mix_word_t from individual bytes */ +#define mix_word_new_b(b1,b2,b3,b4,b5) \ +((mix_word_t)(mix_byte_new(b5) + (mix_byte_new(b4)<<6) + \ + (mix_byte_new(b3)<<12) + (mix_byte_new(b2)<<18) + \ + (mix_byte_new(b1)<<24))) + +/* Create a negative mix_word_t from individual bytes */ +#define mix_word_new_bn(b1,b2,b3,b4,b5) \ + mix_word_negative(mix_word_new_b(b1,b2,b3,b4,b5)) + +/* Create mix_word_t from an array of mix_byte_t */ +extern mix_word_t +mix_bytes_to_word(mix_byte_t *bytes, guint byteno); + +/* Access byte within a word */ +extern mix_byte_t /* byte -idx- or MIX_BYTE_ZERO if -idx- out of range */ +mix_word_get_byte(mix_word_t word, /* word parsed */ + guint idx /* byte: 1 to 5 */); + +/* Set a byte within a mix_word_t */ +extern void +mix_word_set_byte(mix_word_t *into, /* word to be modified */ + guint idx, /* byte: 1 to 5 */ + mix_byte_t value /* byte's value */); + + +/* Operations */ +/* Sign-related definitions */ +#define mix_word_negative(word) ( (word) ^ MIX_WORD_SIGN_BIT ) +#define mix_word_reverse_sign(word) ( word ^= MIX_WORD_SIGN_BIT ) +#define mix_word_sign(word) ( (word) & MIX_WORD_SIGN_BIT ) +#define mix_word_magnitude(word) ( (word) & (MIX_WORD_SIGN_BIT - 1) ) +#define mix_word_is_positive(word) ( mix_word_sign(word) == 0 ) +#define mix_word_is_negative(word) ( mix_word_sign(word) != 0 ) + + +/* Arithmetic operations */ +extern mix_word_t +mix_word_add(mix_word_t x, mix_word_t y); + +#define mix_word_sub(x,y) ( mix_word_add((x),mix_word_negative(y)) ) + +/* Add two words filling a high word if needed. + -high_word- and/or -low_word- can be NULL. +*/ +extern gboolean /* TRUE if overflow */ +mix_word_add_and_carry(mix_word_t x, mix_word_t y, + mix_word_t *high_word, mix_word_t *low_word); + +/* Product, stored in -high_word- and -low_word-, which + can be NULL. +*/ +extern void +mix_word_mul(mix_word_t x, mix_word_t y, + mix_word_t *high_word, mix_word_t *low_word); + +/* Division. -quotient- and/or -remainder- can be NULL. */ +extern gboolean /* TRUE if overflow */ +mix_word_div(mix_word_t n1, mix_word_t n0, mix_word_t d, + mix_word_t *quotient, mix_word_t *remainder); + +/* Shift operations */ +extern void +mix_word_shift_left(mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX); +extern void +mix_word_shift_right(mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX); +extern void +mix_word_shift_left_circular(mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX); +extern void +mix_word_shift_right_circular(mix_word_t A, mix_word_t X, gulong count, + mix_word_t *pA, mix_word_t *pX); + + + + +/* + * Fields within a word: a word containing the (L:R) + * bytes of the original one. L and R (with 0 <= L <= R < 6) + * are specified by a mix_fspec_t F = 8*L + R. + */ +typedef guint8 mix_fspec_t; + +#define mix_fspec_left(f) ( ((f)>>3) & 7 ) +#define mix_fspec_right(f) ( (f) & 7 ) +#define mix_fspec_new(L,R) ( mix_byte_new(8*(L) + (R)) ) + +extern gboolean +mix_fspec_is_valid(mix_fspec_t f); + +extern mix_word_t /* the specified field or 0 if f is not valid */ +mix_word_get_field(mix_fspec_t f, mix_word_t word); + +extern mix_word_t /* -to- with the field -f- from -from- or -to- + if -f- is not a valid fspec */ +mix_word_set_field(mix_fspec_t f, mix_word_t from, mix_word_t to); + +/* set field into a zero word */ +#define mix_word_extract_field(fspec,from_word) \ + mix_word_set_field(fspec,from_word,MIX_WORD_ZERO) + +/* Store operation: the no. of bytes determined by -f- is taken + * from the right of -from- and stored into -to- in the location + * specified by -f- + */ +extern mix_word_t +mix_word_store_field(mix_fspec_t f, mix_word_t from, mix_word_t to); + + +/* Printable representation */ +extern void +mix_word_print(mix_word_t word, const char *message); + + +/*----------------- mix_short_t ------------------------------------------*/ +typedef guint16 mix_short_t; + +#define MIX_SHORT_MAX ((1L << 12) - 1) +#define MIX_SHORT_SIGN_BIT ((mix_short_t)(1L << 12)) +#define MIX_SHORT_ZERO ((mix_short_t)0) +#define MIX_SHORT_MINUS_ZERO (MIX_SHORT_ZERO | MIX_SHORT_SIGN_BIT) + +/* Sign-related definitions */ +#define mix_short_negative(s) ( (s) ^ MIX_SHORT_SIGN_BIT ) +#define mix_short_sign(s) ( (s) & MIX_SHORT_SIGN_BIT ) +#define mix_short_magnitude(s) \ + ( (s) & (MIX_SHORT_SIGN_BIT - 1) ) +#define mix_short_is_positive(s) ( mix_short_sign(s) == 0 ) +#define mix_short_is_negative(s) ( mix_short_sign(s) != 0 ) + +/* create short from a long */ +#define mix_short_new(val) \ + ((val)>= 0 ? (val)&MIX_SHORT_MAX : mix_short_negative(-(val))) + +/* Create shorts from individual bytes */ +#define mix_short_new_b(b1,b2) \ +((mix_short_t)((mix_byte_new(b1)<<6) + mix_byte_new(b2))) + +#define mix_short_new_bn(b1,b2) mix_short_negative(mix_short_new_b(b1,b2)) + +/* Conversions between words and shorts. Arithmetic operations + on shorts are not provided but for addition: use words instead. +*/ +/* Make a short taking word's sign and its two least significant + bytes (bytes no. 4 and 5) +*/ +extern mix_short_t +mix_word_to_short(mix_word_t word); + +extern mix_word_t +mix_short_to_word(mix_short_t s); + +/* fast conversion (these macros' argument are evaluated twice */ +#define mix_word_to_short_fast(w) \ +( mix_word_is_negative(w) ? \ + ((w) & MIX_SHORT_MAX)|MIX_SHORT_SIGN_BIT : (w)&MIX_SHORT_MAX ) + +#define mix_short_to_word_fast(s) \ +( mix_short_is_negative(s) ? \ +(mix_word_t) (mix_short_magnitude(s)|MIX_WORD_SIGN_BIT): (mix_word_t)(s) ) + + +extern mix_short_t +mix_short_add(mix_short_t x, mix_short_t y); + + +/* printable representation */ +extern void +mix_short_print(mix_short_t s, const gchar *message); + + + + + +#endif /* MIX_TYPES_H */ + + + + diff --git a/mixlib/mix_vm.c b/mixlib/mix_vm.c new file mode 100644 index 0000000..7e17979 --- /dev/null +++ b/mixlib/mix_vm.c @@ -0,0 +1,445 @@ +/* -*-c-*- ------------------ mix_vm.c : + * Implementation of the functions declared in mix_vm.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include "mix.h" +#include "xmix_vm.h" + +static void +vm_reset_ (mix_vm_t *vm) +{ + guint k; + set_rA_ (vm, MIX_WORD_ZERO); + set_rX_ (vm, MIX_WORD_ZERO); + set_rJ_ (vm, MIX_WORD_ZERO); + for ( k = 1; k < IREG_NO_+1; ++k ) + set_rI_ (vm, k, MIX_WORD_ZERO); + set_over_ (vm, FALSE); + set_cmp_ (vm, mix_EQ); + set_loc_ (vm, MIX_WORD_ZERO); + for ( k = 0; k < MEM_CELLS_NO_; ++k) + set_cell_ (vm, k, MIX_WORD_ZERO); + halt_ (vm, FALSE); + if (vm->symbol_table != NULL ) + { + mix_symbol_table_delete (vm->symbol_table); + vm->symbol_table = NULL; + } + if (vm->line_table != NULL) + { + g_tree_destroy (vm->line_table); + vm->line_table = NULL; + } + bp_clear_all_ (vm); +} + + +/* Create/destroy a mix vm */ +mix_vm_t * +mix_vm_new (void) +{ + int i; + + mix_vm_t *vm = g_new (struct mix_vm_t,1); + g_return_val_if_fail (vm != NULL, NULL); + vm->line_table = NULL; + vm->symbol_table = NULL; + + for (i = 0; i < BD_NO_; ++i) + vm->devices[i] = NULL; + + vm_reset_ (vm); + return vm; +} + +void +mix_vm_delete (mix_vm_t * vm) +{ + int i; + + if (vm->line_table != NULL) g_tree_destroy (vm->line_table); + if (vm->symbol_table != NULL) mix_symbol_table_delete (vm->symbol_table); + for (i = 0; i < BD_NO_; ++i) + mix_device_delete (vm->devices[i]); + g_free (vm); +} + +/* Reset a vm (set state as of a newly created one) */ +void +mix_vm_reset (mix_vm_t * vm) +{ + g_return_if_fail (vm != NULL); + vm_reset_ (vm); +} + +/* Set start address for execution */ +void +mix_vm_set_start_addr (mix_vm_t *vm, mix_address_t addr) +{ + g_return_if_fail (vm != NULL); + set_loc_ (vm, addr); +} + +/* Access to the vm's registers */ +mix_word_t +mix_vm_get_rA (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO); + return get_rA_ (vm); +} + +mix_word_t +mix_vm_get_rX (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO); + return get_rX_ (vm); +} + +mix_short_t +mix_vm_get_rJ (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO); + return mix_word_to_short_fast (get_rJ_ (vm)); +} + +mix_short_t +mix_vm_get_rI (const mix_vm_t *vm, guint idx) +{ + g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO); + g_return_val_if_fail (IOK_ (idx), MIX_SHORT_ZERO); + return mix_word_to_short_fast (get_rI_ (vm, idx)); +} + +void +mix_vm_set_rA (mix_vm_t *vm, mix_word_t value) +{ + g_return_if_fail (vm != NULL); + set_rA_ (vm, value); +} + +void +mix_vm_set_rX (mix_vm_t *vm, mix_word_t value) +{ + g_return_if_fail (vm != NULL); + set_rX_ (vm, value); +} + +void +mix_vm_set_rJ (mix_vm_t *vm, mix_short_t value) +{ + g_return_if_fail (vm != NULL); + g_return_if_fail (mix_short_is_positive (value)); + set_rJ_ (vm, mix_short_to_word_fast (value)); +} + +void +mix_vm_set_rI (mix_vm_t *vm, guint idx, mix_short_t value) +{ + g_return_if_fail (vm != NULL); + g_return_if_fail (IOK_ (idx)); + set_rI_ (vm, idx, mix_short_to_word_fast (value)); +} + +/* Access to the comparison flag and overflow toggle */ +mix_cmpflag_t +mix_vm_get_cmpflag (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, mix_EQ); + return get_cmp_ (vm); +} + +void +mix_vm_set_cmpflag (mix_vm_t *vm, mix_cmpflag_t value) +{ + g_return_if_fail (vm != NULL); + set_cmp_ (vm, value); +} + +gboolean +mix_vm_get_overflow (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, TRUE); + return get_over_ (vm); +} + +void +mix_vm_set_overflow (mix_vm_t *vm, gboolean value) +{ + g_return_if_fail (vm != NULL); + set_over_ (vm, value); +} + +void +mix_vm_toggle_overflow (mix_vm_t *vm) +{ + g_return_if_fail (vm != NULL); + set_over_ (vm, !get_over_ (vm)); +} + +/* Access to memory cells */ +mix_word_t +mix_vm_get_addr_contents (const mix_vm_t *vm, mix_address_t addr) +{ + g_return_val_if_fail (vm != NULL, MIX_WORD_ZERO); + g_return_val_if_fail (MEMOK_ (addr), MIX_WORD_ZERO); + return get_cell_ (vm, addr); +} + +void +mix_vm_set_addr_contents (mix_vm_t *vm, mix_address_t addr, mix_word_t value) +{ + g_return_if_fail (vm != NULL); + g_return_if_fail (MEMOK_ (addr)); + set_cell_ (vm, addr, value); +} + +gboolean +mix_vm_is_halted (const mix_vm_t *vm) +{ + return is_halted_ (vm); +} + +/* Execution of instructions */ +gboolean /* TRUE if success */ +mix_vm_exec_ins (mix_vm_t *vm, const mix_ins_t *ins) +{ + g_return_val_if_fail (vm != NULL, FALSE); + g_return_val_if_fail (ins != NULL, FALSE); + return (*ins_handlers_[ins->opcode]) (vm,ins); +} + +/* comparison function for the line table tree */ +static gint +cmp_lineno_ (gconstpointer a, gconstpointer b) +{ + return GPOINTER_TO_UINT (a) - GPOINTER_TO_UINT (b); +} + +gboolean +mix_vm_load_file (mix_vm_t *vm, const gchar *name) +{ + mix_code_file_t *file; + mix_ins_desc_t ins; + + g_return_val_if_fail (vm != NULL, FALSE); + file = mix_code_file_new_read (name); + if (file == NULL) return FALSE; + vm_reset_ (vm); + if ( mix_code_file_is_debug (file) ) + { + vm->symbol_table = mix_code_file_get_symbol_table (file); + vm->line_table = g_tree_new (cmp_lineno_); + } + while ( mix_code_file_get_ins (file, &ins) ) + { + set_cell_ (vm, ins.address, ins.ins); + if ( vm->line_table != NULL ) + g_tree_insert (vm->line_table, + GUINT_TO_POINTER (ins.lineno), + GUINT_TO_POINTER ((guint)ins.address)); + } + set_loc_ (vm, mix_code_file_get_start_addr (file)); + set_start_ (vm, get_loc_ (vm)); + mix_code_file_delete (file); + + return TRUE; +} + +const mix_symbol_table_t * +mix_vm_get_symbol_table (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, NULL); + return vm->symbol_table; +} + +mix_address_t +mix_vm_get_prog_count (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, MIX_SHORT_ZERO); + return get_loc_ (vm); +} + +/* continue execution of instructions in memory */ +int +mix_vm_run (mix_vm_t *vm) +{ + mix_ins_t ins; + g_return_val_if_fail (vm != NULL, MIX_VM_ERROR); + + if ( is_halted_ (vm) ) + { + reset_loc_ (vm); /* set current location to start address */ + halt_ (vm, FALSE); + } + + while ( !is_halted_ (vm) ) + { + mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins); + if ( !(*ins_handlers_[ins.opcode]) (vm,&ins) ) + return MIX_VM_ERROR; + if (bp_is_set_ (vm, get_loc_ (vm))) + return MIX_VM_BREAK; + } + return MIX_VM_HALT; +} + +/* execute next memory instruction */ +int +mix_vm_exec_next (mix_vm_t *vm) +{ + mix_ins_t ins; + g_return_val_if_fail (vm != NULL, MIX_VM_ERROR); + if ( is_halted_ (vm) ) return MIX_VM_HALT; + mix_word_to_ins_uncheck (get_cell_ (vm, get_loc_ (vm)), ins); + if (!(*ins_handlers_[ins.opcode]) (vm, &ins)) + return MIX_VM_ERROR; + return MIX_VM_BREAK; +} + +/* Breakpoints */ +typedef struct +{ + mix_address_t address; + gulong lineno; +} fline_t; + +static int +find_break_ (gpointer key, gpointer value, gpointer data) +{ + fline_t *fl = (fline_t *)data; + + if ( mix_short_new (GPOINTER_TO_UINT (value)) == fl->address ) + { + fl->lineno = GPOINTER_TO_UINT (key); + return TRUE; + } + return FALSE; +} + +gulong +mix_vm_get_break_lineno (const mix_vm_t *vm) +{ + fline_t fl; + + g_return_val_if_fail (vm != NULL, 0); + if (vm->line_table == NULL) return 0; + fl.lineno = 0; + fl.address = get_loc_ (vm); + g_tree_traverse (vm->line_table, find_break_, G_IN_ORDER, (gpointer) &fl); + return fl.lineno; +} + +typedef struct +{ + mix_vm_t *vm; + guint lineno; + gint result; +} bp_traverse_t; + +static gint +set_break_ (gpointer key, gpointer value, gpointer data) +{ + bp_traverse_t *tr = (bp_traverse_t *)data; + if (GPOINTER_TO_UINT (key) >= tr->lineno) + { + bp_set_ (tr->vm, mix_short_new (GPOINTER_TO_UINT (value))); + tr->lineno = GPOINTER_TO_UINT (key); + tr->result = MIX_VM_BP_OK; + return TRUE; + } + return FALSE; +} + +gint /* if >0 the line no. of the break point */ +mix_vm_set_breakpoint (mix_vm_t *vm, guint lineno) +{ + bp_traverse_t tr; + + g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); + if (!vm->line_table) return MIX_VM_BP_NDEBUG; + tr.lineno = lineno; + tr.vm = vm; + tr.result = MIX_VM_BP_INV_LINE; + g_tree_traverse (vm->line_table, set_break_, G_IN_ORDER, (gpointer)&tr); + if (tr.result == MIX_VM_BP_OK) + return tr.lineno; + else + return tr.result; +} + +gint +mix_vm_set_breakpoint_address (mix_vm_t *vm, guint address) +{ + g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); + if (address >= MIX_VM_CELL_NO) + return MIX_VM_BP_INV_ADDRESS; + else + bp_set_ (vm, mix_short_new (address)); + return MIX_VM_BP_OK; +} + +static gint +clear_break_ (gpointer key, gpointer value, gpointer data) +{ + bp_traverse_t *tr = (bp_traverse_t *)data; + if (GPOINTER_TO_UINT (key) == tr->lineno) + { + bp_clear_ (tr->vm, mix_short_new (GPOINTER_TO_UINT (value))); + tr->result = MIX_VM_BP_OK; + return TRUE; + } + else if (GPOINTER_TO_UINT (key) > tr->lineno) + return TRUE; + + return FALSE; +} + +gint /* one of MIX_VM_BP_ */ +mix_vm_clear_breakpoint (mix_vm_t *vm, guint lineno) +{ + bp_traverse_t tr; + + g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); + if (!vm->line_table) return MIX_VM_BP_NDEBUG; + tr.lineno = lineno; + tr.vm = vm; + tr.result = MIX_VM_BP_INV_LINE; + g_tree_traverse (vm->line_table, clear_break_, G_IN_ORDER, (gpointer)&tr); + return tr.result; +} + +gint +mix_vm_clear_breakpoint_address (mix_vm_t *vm, guint address) +{ + g_return_val_if_fail (vm != NULL, MIX_VM_BP_ERROR); + if (address >= MIX_VM_CELL_NO) + return MIX_VM_BP_INV_ADDRESS; + else + bp_clear_ (vm, mix_short_new (address)); + return MIX_VM_BP_OK; +} + +void +mix_vm_clear_all_breakpoints (mix_vm_t *vm) +{ + g_return_if_fail (vm != NULL); + bp_clear_all_ (vm); +} + diff --git a/mixlib/mix_vm.h b/mixlib/mix_vm.h new file mode 100644 index 0000000..6ddbb8e --- /dev/null +++ b/mixlib/mix_vm.h @@ -0,0 +1,171 @@ +/* ---------------------- mix_vm.h : + * Types and functions implementing the MIX virtual machine + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIX_VM_H +#define MIX_VM_H + +#include "mix_types.h" +#include "mix_ins.h" +#include "mix_code_file.h" +#include "mix_symbol_table.h" + +/* Comparison flag */ +typedef enum { mix_LESS, mix_EQ, mix_GREAT } mix_cmpflag_t; + +/* Number of memory cells in the virtual machine */ +enum { MIX_VM_CELL_NO = 4000 }; + +/* Opaque type for the mix virtual machine */ +typedef struct mix_vm_t mix_vm_t; + +/* Create/destroy a mix vm */ +extern mix_vm_t * +mix_vm_new(void); + +extern void +mix_vm_delete(mix_vm_t * vm); + +/* Reset a vm (set state as of a newly created one) */ +extern void +mix_vm_reset(mix_vm_t * vm); + +/* Set start address for execution */ +extern void +mix_vm_set_start_addr(mix_vm_t *vm, mix_address_t addr); + +/* Access to the vm's registers */ +extern mix_word_t +mix_vm_get_rA(const mix_vm_t *vm); + +extern mix_word_t +mix_vm_get_rX(const mix_vm_t *vm); + +extern mix_short_t +mix_vm_get_rJ(const mix_vm_t *vm); + +extern mix_short_t +mix_vm_get_rI(const mix_vm_t *vm, guint idx); + +extern void +mix_vm_set_rA(mix_vm_t *vm, mix_word_t value); + +extern void +mix_vm_set_rX(mix_vm_t *vm, mix_word_t value); + +extern void +mix_vm_set_rJ(mix_vm_t *vm, mix_short_t value); + +extern void +mix_vm_set_rI(mix_vm_t *vm, guint idx, mix_short_t value); + + +/* Access to the comparison flag and overflow toggle */ +extern mix_cmpflag_t +mix_vm_get_cmpflag(const mix_vm_t *vm); + +extern void +mix_vm_set_cmpflag(mix_vm_t *vm, mix_cmpflag_t value); + +extern gboolean +mix_vm_get_overflow(const mix_vm_t *vm); + +extern void +mix_vm_set_overflow(mix_vm_t *vm, gboolean value); + +extern void +mix_vm_toggle_overflow(mix_vm_t *vm); + +extern gboolean +mix_vm_is_halted(const mix_vm_t *vm); + +/* Access to memory cells */ +extern mix_word_t +mix_vm_get_addr_contents(const mix_vm_t *vm, mix_address_t addr); + +extern void +mix_vm_set_addr_contents(mix_vm_t *vm, mix_address_t addr, mix_word_t value); + +/* Execution of instructions and programs */ +extern gboolean /* TRUE if success */ +mix_vm_exec_ins(mix_vm_t *vm, const mix_ins_t *ins); + +/* Load a code file into memory (-name- does not need the default extension) + * resetting the vm's state + */ +extern gboolean +mix_vm_load_file(mix_vm_t *vm, const gchar *name); + +/* Get symbol table of loaded file */ +extern const mix_symbol_table_t * +mix_vm_get_symbol_table (const mix_vm_t *vm); + +/* Get current program counter */ +extern mix_address_t +mix_vm_get_prog_count (const mix_vm_t *vm); + +/* continue execution of instructions in memory */ +/* Possible outcomes */ +enum { + MIX_VM_ERROR, /* error executing instructions */ + MIX_VM_BREAK, /* breakpoint found */ + MIX_VM_HALT /* end of execution */ +}; + +extern int +mix_vm_run (mix_vm_t *vm); + +/* execute next memory instruction */ +extern int +mix_vm_exec_next (mix_vm_t *vm); + +/* get the line no. of the last break or 0 if not found */ +extern gulong +mix_vm_get_break_lineno (const mix_vm_t *vm); + +/* Breakpoints */ +/* possible error outcomes */ +enum { + MIX_VM_BP_ERROR = -4, /* internal error */ + MIX_VM_BP_NDEBUG = -3, /* no debug info */ + MIX_VM_BP_INV_ADDRESS = -2, /* address out of range */ + MIX_VM_BP_INV_LINE = -1, /* invalid line no. */ + MIX_VM_BP_OK = 0 /* success */ +}; + +extern gint /* if >0 the line no. of the break point */ +mix_vm_set_breakpoint (mix_vm_t *vm, guint lineno); + +extern gint /* one of MIX_VM_BP_ */ +mix_vm_set_breakpoint_address (mix_vm_t *vm, guint address); + +extern gint /* one of MIX_VM_BP_ */ +mix_vm_clear_breakpoint (mix_vm_t *vm, guint lineno); + +extern gint /* one of MIX_VM_BP_ */ +mix_vm_clear_breakpoint_address (mix_vm_t *vm, guint address) ; + +extern void +mix_vm_clear_all_breakpoints (mix_vm_t *vm); + + +#endif /* MIX_VM_H */ + diff --git a/mixlib/mix_vm_dump.c b/mixlib/mix_vm_dump.c new file mode 100644 index 0000000..33b5c38 --- /dev/null +++ b/mixlib/mix_vm_dump.c @@ -0,0 +1,194 @@ +/* ---------------------- mix_vm_dump.c : + * Implementation of the functions declared in mix_vm_dump.h + * ------------------------------------------------------------------ +** Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> +** +** 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. +** +*/ + +#include "mix.h" +#include <unistd.h> +#include "xmix_vm.h" +#include "mix_vm_dump.h" + +/* Create/destroy a dump context */ +mix_dump_context_t * +mix_dump_context_new(gint fd, mix_address_t begin, mix_address_t end, + guint32 options) +{ + mix_dump_context_t *result = NULL; + GIOChannel *channel = NULL; + + if ( fd == MIX_DUMP_DEF_CHANNEL ) fd = STDIN_FILENO; + channel = g_io_channel_unix_new (fd); + g_return_val_if_fail (channel != NULL, NULL); + + if ( begin > end ) begin = end; + if ( end >= MEM_CELLS_NO_ ) end = MEM_CELLS_NO_; + + result = g_new (mix_dump_context_t,1); + g_return_val_if_fail (result != NULL, NULL); + + result->options = options; + result->begin = begin; + result->end = end; + result->channel = channel; + + return result; +} + +void +mix_dump_context_delete (mix_dump_context_t *dc) +{ + g_return_if_fail (dc != NULL); + g_io_channel_close (dc->channel); + g_free (dc); +} + +gboolean /* TRUE if success */ +mix_dump_context_set_channel (mix_dump_context_t *dc, gint fd) +{ + g_return_val_if_fail (dc != NULL, FALSE); + g_io_channel_close (dc->channel); + dc->channel = g_io_channel_unix_new (fd == MIX_DUMP_DEF_CHANNEL? + STDERR_FILENO : fd); + return ( dc->channel != NULL ); +} + +/* Use the dump context */ +#define WORD_FMT_ "%s %02d %02d %02d %02d %02d (%010ld)" +#define SHORT_FMT_ "%s %02d %02d (%04d)" +#define WORD_SIGN_(w) mix_word_is_negative (w)? "-":"+" +#define SHORT_SIGN_(s) mix_short_is_negative (s)? "-":"+" +#define WORD_ABS_(w) mix_word_magnitude (w) +#define SHORT_ABS_(s) mix_short_magnitude (s) +#define WORD_BYTE_(w,i) mix_byte_new (mix_word_magnitude (w)>>(6*(5-i))) +#define SHORT_BYTE_(s,i) mix_byte_new (mix_short_magnitude (s)>>(6*(2-i))) +#define WORD_ARGS_(w) WORD_SIGN_ (w), WORD_BYTE_ (w,1), WORD_BYTE_ (w,2), \ + WORD_BYTE_ (w,3), WORD_BYTE_ (w,4), WORD_BYTE_ (w,5), WORD_ABS_ (w) +#define SHORT_ARGS_(s) SHORT_SIGN_ (s), SHORT_BYTE_ (s,1), SHORT_BYTE_ (s,2), \ + SHORT_ABS_ (s) + +static gboolean +write_buffer_ (const gchar *buf, guint len, GIOChannel *io) +{ + guint k, err; + + while ( len > 0 ) { + err = g_io_channel_write (io, (gchar *) buf, len, &k); + g_return_val_if_fail (err == G_IO_ERROR_NONE || + err == G_IO_ERROR_AGAIN, FALSE); + len -= k; + } + return TRUE; +} + + + +void +mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc) +{ + static const guint BUF_LEN = 40; + gchar buf[BUF_LEN]; + guint j, i; + + g_return_if_fail (vm != NULL); + g_return_if_fail (dc != NULL); + + + if ( (dc->options & MIX_DUMP_rA) == MIX_DUMP_rA ) + { + mix_word_t rA = get_rA_ (vm); + guint k = g_snprintf (buf, BUF_LEN, "rA: " WORD_FMT_ "\n", + WORD_ARGS_ (rA)); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + } + + if ( (dc->options & MIX_DUMP_rX) == MIX_DUMP_rX ) + { + mix_word_t rX = get_rX_ (vm); + guint k = g_snprintf (buf, BUF_LEN, "rX: " WORD_FMT_ "\n", + WORD_ARGS_ (rX)); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + } + + if ( (dc->options & MIX_DUMP_rJ) == MIX_DUMP_rJ ) + { + mix_short_t rJ = get_rJ_ (vm); + guint k = g_snprintf (buf, BUF_LEN, "rJ: " SHORT_FMT_ "\n", + SHORT_ARGS_ (rJ)); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + } + + for (j = 0, i = 0; j < IREG_NO_; ++j) + { + if ( (dc->options & (MIX_DUMP_rI1<<j)) == (MIX_DUMP_rI1<<j) ) + { + mix_short_t rI = mix_word_to_short_fast (get_rI_ (vm, j+1)); + guint k = g_snprintf (buf, BUF_LEN, "rI%d: " SHORT_FMT_ "\t", + j+1, SHORT_ARGS_ (rI)); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + i++; + } + if ( i%2 == 0 && i != 0 ) + g_return_if_fail (write_buffer_ ("\n", 1, dc->channel)); + } + + if ( i%2 == 1 ) + g_return_if_fail (write_buffer_ ("\n", 1, dc->channel)); + + if ( (dc->options & MIX_DUMP_OVER) == MIX_DUMP_OVER ) + { + guint k = g_snprintf (buf, BUF_LEN, _("Overflow: %s\n"), + get_over_ (vm)? "T":"F"); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + } + + if ( (dc->options & MIX_DUMP_CMP) == MIX_DUMP_CMP ) + { + guint k; + const gchar *val = "?"; + switch (get_cmp_ (vm)) + { + case mix_LESS: + val = "L"; + break; + case mix_GREAT: + val = "G"; + break; + case mix_EQ: + val = "E"; + break; + default: + g_assert_not_reached (); + break; + } + k = g_snprintf (buf, BUF_LEN, _("Cmp: %s\n"), val); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + } + + if ( (dc->options & MIX_DUMP_CELLS) == MIX_DUMP_CELLS ) + { + for (j = dc->begin; j < dc->end; ++j) + { + mix_word_t cell = get_cell_ (vm,j); + guint k = g_snprintf (buf, BUF_LEN, "%04d: " WORD_FMT_ "\n", j, + WORD_ARGS_ (cell)); + g_return_if_fail (write_buffer_ (buf, k, dc->channel)); + } + } +} + diff --git a/mixlib/mix_vm_dump.h b/mixlib/mix_vm_dump.h new file mode 100644 index 0000000..b854175 --- /dev/null +++ b/mixlib/mix_vm_dump.h @@ -0,0 +1,92 @@ +/* ---------------------- mix_vm_dump.h : + * This file declares types and functions for dumping the contents + * of a mix virtual machine. + * ------------------------------------------------------------------ +** Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> +** +** 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. +** +*/ + + +#ifndef MIX_VM_DUMP_H +#define MIX_VM_DUMP_H + +#include "mix_vm.h" + +/* Dump context: a structure defining the properties of dumping */ +typedef struct mix_dump_context_t mix_dump_context_t; +struct mix_dump_context_t +{ + /* flags activating dumps (see enum below) */ + guint32 options; + /* range of addresses dumped: [begin,end) */ + mix_address_t begin; + mix_address_t end; + /* IO channel for dumping */ + GIOChannel *channel; +}; + +/* Flags for activating dumps */ +#define MIX_DUMP_NONE 0 +#define MIX_DUMP_rA 1 +#define MIX_DUMP_rX (1<<1) +#define MIX_DUMP_rJ (1<<2) +#define MIX_DUMP_rI1 (1<<3) +#define MIX_DUMP_rI2 (1<<4) +#define MIX_DUMP_rI3 (1<<5) +#define MIX_DUMP_rI4 (1<<6) +#define MIX_DUMP_rI5 (1<<7) +#define MIX_DUMP_rI6 (1<<8) +#define MIX_DUMP_rIa MIX_DUMP_rI1|MIX_DUMP_rI2|MIX_DUMP_rI3 \ + |MIX_DUMP_rI4|MIX_DUMP_rI5|MIX_DUMP_rI6 +#define MIX_DUMP_rALL MIX_DUMP_rA|MIX_DUMP_rX|MIX_DUMP_rJ|MIX_DUMP_rIa +#define MIX_DUMP_OVER (1<<9) +#define MIX_DUMP_CMP (1<<10) +#define MIX_DUMP_CELLS (1<<11) +#define MIX_DUMP_ALL MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP|MIX_DUMP_CELLS +#define MIX_DUMP_ALL_NOMEM MIX_DUMP_rALL|MIX_DUMP_OVER|MIX_DUMP_CMP + +/* Default output channel (stdout) */ +#define MIX_DUMP_DEF_CHANNEL (-1) + +/* Create/destroy a dump context */ +extern mix_dump_context_t * +mix_dump_context_new(gint fd, mix_address_t begin, mix_address_t end, + guint32 options); + +extern void +mix_dump_context_delete(mix_dump_context_t *dc); + +/* Modify an existing dump context */ +#define mix_dump_context_add_opt(dc,opt) ((dc)->options |= (opt)) +#define mix_dump_context_del_opt(dc,opt) ((dc)->options &= ~(opt)) +#define mix_dump_context_set_opt(dc,opt) ((dc)->options = (opt)) +#define mix_dump_context_range(dc,first,last) \ +do { \ + (dc)->begin = first; \ + (dc)->end = last; \ +} while (FALSE) + +extern gboolean /* TRUE if success */ +mix_dump_context_set_channel(mix_dump_context_t *dc, gint fd); + +/* Use the dump context */ +extern void +mix_vm_dump(const mix_vm_t *vm, const mix_dump_context_t *dc); + + +#endif /* MIX_VM_DUMP_H */ + diff --git a/mixlib/testsuite/.cvsignore b/mixlib/testsuite/.cvsignore new file mode 100644 index 0000000..fa47ca5 --- /dev/null +++ b/mixlib/testsuite/.cvsignore @@ -0,0 +1,27 @@ +.deps +Makefile +Makefile.in +cardwr.dev +disk0.dev +disk1.dev +disk2.dev +disk3.dev +disk4.dev +disk5.dev +disk6.dev +disk7.dev +mixdevtest +mixinstest +mixparsertest +mixtypest +mixvminstest +paper.dev +printer.dev +tape0.dev +tape1.dev +tape2.dev +tape3.dev +tape4.dev +tape5.dev +tape6.dev +tape7.dev diff --git a/mixlib/testsuite/Makefile.am b/mixlib/testsuite/Makefile.am new file mode 100644 index 0000000..62d5db6 --- /dev/null +++ b/mixlib/testsuite/Makefile.am @@ -0,0 +1,26 @@ +# Copyright (C) 1999 jose antonio ortega ruiz <jaortega@acm.org> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +INCLUDES = -I.. +LDADD = $(top_builddir)/mixlib/libmix.a + +check_PROGRAMS = mixtypest mixinstest mixvminstest mixparsertest mixdevtest +TESTS = $(check_PROGRAMS) + +mixtypest_SOURCES = test.h mix_types_t.c +mixinstest_SOURCES = test.h mix_ins_t.c +mixvminstest_SOURCES = test.h mix_vm_ins_t.c +mixparsertest_SOURCES = test.h mix_parser_t.c +mixdevtest_SOURCES = test.h mix_device_t.c + + + + + diff --git a/mixlib/testsuite/mix_device_t.c b/mixlib/testsuite/mix_device_t.c new file mode 100644 index 0000000..0b3e066 --- /dev/null +++ b/mixlib/testsuite/mix_device_t.c @@ -0,0 +1,76 @@ +/* -*-c-*- -------------- mix_device_t.c : + * Implementation of the functions declared in mix_device_t.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include <stdlib.h> +#include <mix_device.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +static int S_ = MIX_CHAR_MAX +1; + +int +main (int argc, char **argv) +{ + mix_device_t *console; + size_t s; + mix_word_t **block; + mix_char_t mchars[S_]; + gchar chars[S_]; + int i, j; + int bno; + + + INIT_TEST; + + console = mix_device_new (mix_dev_CONSOLE); + s = mix_device_block_size (console); + bno = S_/(s*5); + if (bno == 0) bno = 1; + + block = g_new (mix_word_t *, bno); + for (i = 0; i < bno; ++i) + block[i] = g_new (mix_word_t, s); + + for (i = 0; i < S_; ++i) { + chars[i] = mix_char_to_ascii (i); + mchars[i] = mix_ascii_to_char (chars[i]); + g_assert (mchars[i] == i); + } + + for (i = 0; i < bno; ++i) { + for (j = 0; j < s; ++j) { + int n = i*s + 5*j; + if (n < S_) + block[i][j] = mix_bytes_to_word (mchars + n, 5); + else + block[i][j] = 0; + } + } + + for (i = 0; i < bno; ++i) { + mix_device_write (console, block[i]); + } + + + return EXIT_SUCCESS; +} diff --git a/mixlib/testsuite/mix_ins_t.c b/mixlib/testsuite/mix_ins_t.c new file mode 100644 index 0000000..a84d63c --- /dev/null +++ b/mixlib/testsuite/mix_ins_t.c @@ -0,0 +1,79 @@ +/*----------------------- mix_ins_t.c ------------------------------- + * Tests for mix_ins.h + *------------------------------------------------------------------- +** Copyright (C) 1999 jose antonio ortega ruiz <jaortega@acm.org> +** +** 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. +** +*/ + +#include <stdlib.h> +#include <mix_ins.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + + +int +main(int argc, const char**argv) +{ + mix_word_t words[6]; + mix_ins_t ins[3]; + guint k; + + INIT_TEST; + + g_print("\n...ok.\nTesting mix_ins_id_t properties...\n"); + for ( k = 0; k < mix_INVALID_INS; ++k ) + { + mix_opcode_t c = mix_get_opcode_from_id(k); + mix_fspec_t f = mix_get_fspec_from_id(k); + mix_ins_id_t id = mix_get_ins_id(c,f); + + g_print("%02d:%s (%1d:%1d), ", + c, mix_get_string_from_id(k), + mix_fspec_left(f), mix_fspec_right(f)); + if ( (k+1)%3 == 0 ) g_print("\n"); + + g_assert(id==k); + } + + g_print("\n...ok.\nTesting mix_ins_t properties...\n"); + for ( k = 1; k < mix_INVALID_INS; ++k ) + { + g_print("%d ",k); + mix_ins_fill_from_id(ins[0], k); + g_assert(mix_ins_id_from_ins(ins[0]) == k); + ins[0].address = 0x0123; + ins[0].index = mix_I2; + words[2] = mix_ins_to_word(ins); + g_assert(ins[0].address == mix_get_ins_address(words[2])); + g_assert(ins[0].index == mix_get_ins_index(words[2])); + g_assert(ins[0].fspec == mix_get_ins_fspec(words[2])); + g_assert(ins[0].opcode == mix_get_ins_opcode(words[2])); + g_assert(mix_word_to_ins(words[2],ins+1) == k); + g_assert(ins[0].address == ins[1].address); + g_assert(ins[0].index == ins[1].index); + g_assert(ins[0].fspec == ins[1].fspec); + g_assert(ins[0].opcode == ins[1].opcode); + } + + g_print("\n...ok.\n"); + + + + return EXIT_SUCCESS; +} diff --git a/mixlib/testsuite/mix_parser_t.c b/mixlib/testsuite/mix_parser_t.c new file mode 100644 index 0000000..6a7bece --- /dev/null +++ b/mixlib/testsuite/mix_parser_t.c @@ -0,0 +1,85 @@ +/* -*-c-*- -------------- mix_parser_t.c : + * Test of mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + + +#include <stdlib.h> +#include <mix_parser.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +static const gchar * const FILES_[] = { "test1" , "taocp145" +}; + +static const size_t FILE_NO_ = sizeof(FILES_)/sizeof(FILES_[0]); + +static void +test_code_(const gchar *name) +{ + mix_parser_t *parser = mix_parser_new(name); + mix_parser_err_t err; + mix_code_file_t *code; + mix_ins_desc_t ins; + + g_assert(parser); + err = mix_parser_compile(parser); + if ( err != MIX_PERR_OK ) { + g_print(mix_parser_err_string(err)); + g_print("\n"); + } + g_assert(err == MIX_PERR_OK); + err = mix_parser_write_code(parser, name, FALSE); + code = mix_code_file_new_read(name); + g_assert(code); + g_message("%s: Version: %d.%d", name, mix_code_file_major_version(code), + mix_code_file_minor_version(code)); + mix_short_print(mix_code_file_get_start_addr(code), "Start address: "); + g_print("\n"); + while ( mix_code_file_get_ins(code, &ins) ) { + mix_ins_t i; + mix_word_to_ins_uncheck(ins.ins, i); + mix_short_print(ins.address, "addr: "); + g_print(" : "); + mix_ins_print(&i); + g_print("\n"); + } + + mix_parser_delete(parser); + mix_code_file_delete(code); +} + +int +main(int argc, char **argv) +{ + size_t k; + + INIT_TEST; + + for (k = 0; k < FILE_NO_; ++k) + // test_code_(FILES_[k]); + ; + + + return EXIT_SUCCESS; +} + diff --git a/mixlib/testsuite/mix_types_t.c b/mixlib/testsuite/mix_types_t.c new file mode 100644 index 0000000..ad8bab7 --- /dev/null +++ b/mixlib/testsuite/mix_types_t.c @@ -0,0 +1,361 @@ +/*----------------------- mix_types_t.c ----------------------------- + * Tests for mix_types.h + * ------------------------------------------------------------------ +* +** Copyright (C) 1999 jose antonio ortega ruiz <jaortega@acm.org> +** +** 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. +** +*/ + + +#include <stdlib.h> +#include <mix_types.h> + +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +/* compare two words */ +static gboolean +word_compare_(mix_word_t w1, mix_word_t w2) +{ + if ( mix_word_magnitude(w1) == 0 ) + return ( mix_word_magnitude(w2) == 0 ); + else + return ( w1 == w2 ); +} + + +/* create a word from an array of bytes and check the result */ +static void +test_word_from_bytes_(mix_word_t *word, + mix_byte_t *bytes, + unsigned byteno, + const char *message) +{ + mix_byte_t r; + unsigned int k; + + *word = mix_bytes_to_word(bytes,byteno); + mix_word_print(*word,message); + g_print("\n"); + for ( k = 5-byteno; k < 5; ++k ) { + PRINT_BYTE(r = mix_word_get_byte(*word,k+1)); + g_print(" (k = %d)\n",k); + g_assert( r == bytes[k-5+byteno] ); + } +} + + +/* test field access */ +static void +test_field_access_(mix_fspec_t l, mix_fspec_t r, + mix_word_t from, mix_word_t to) +{ + mix_fspec_t f = mix_fspec_new(l,r); + mix_word_t result; + + PRINT_BYTE(l); g_print(", "); + PRINT_BYTE(r); g_print(", "); + PRINT_BYTE(f); g_print("\n "); + mix_word_print(from, "from: "); + mix_word_print(to, " to: "); + g_assert( mix_fspec_left(f) == l ); + g_assert( mix_fspec_right(f) == r ); + result = mix_word_set_field(f,from,to); + mix_word_print(result,"\n\tresult: "); + g_assert( mix_word_get_field(f,from) == mix_word_get_field(f,result) ); + g_print("\n"); +} + +/* test word addition */ +static void +test_word_add_(mix_word_t w1, mix_word_t w2) +{ + mix_word_t r; + + r = mix_word_add(w1,w2); + mix_word_print(w1,"\n"); + mix_word_print(w2,NULL); + mix_word_print(r," = "); + g_assert( word_compare_(mix_word_sub(r,w1), w2) ); + g_assert( word_compare_(mix_word_sub(r,w2), w1) ); + /* while asserting the following, take into account that 0 != -0 + for mix words, although they are logically equivalent + */ + g_assert( word_compare_(mix_word_sub(w1,r), mix_word_negative(w2)) ); + g_assert( word_compare_(mix_word_sub(w2,r), mix_word_negative(w1)) ); + g_assert( word_compare_(mix_word_add(w2,w1), r) ); +} + +/* test word multiplication */ +static void +test_word_mul_(mix_word_t w1, mix_word_t w2) +{ + mix_word_t h, l, q, r = 0; + mix_word_mul(w1,w2,&h,&l); + mix_word_print(w1,"\n"); + mix_word_print(w2,"*"); + mix_word_print(h,"\n ="); + mix_word_print(l,NULL); + if ( w1 != 0 ) { + g_assert( mix_word_div(h,l,w1,&q,&r) == FALSE ); + g_assert( mix_word_magnitude(r) == 0 ); + g_assert( q == w2 ); + } else { + g_assert( mix_word_magnitude(l) == 0 && mix_word_magnitude(h) == 0 ); + } + if ( w2 != 0 ) { + g_assert( mix_word_div(h,l,w2,&q,&r) == FALSE ); + g_assert( mix_word_magnitude(r) == 0 ); + g_assert( q == w1 ); + } else { + g_assert( mix_word_magnitude(l) == 0 && mix_word_magnitude(h) == 0 ); + } + +} + +/* test word division */ +static void +test_word_div_(mix_word_t h, mix_word_t l, mix_word_t by) +{ + mix_word_t q,r; + gboolean overflow; + + overflow = mix_word_div(h,l,by,&q,&r); + + mix_word_print(h,"\n\n"); + mix_word_print(l,NULL); + mix_word_print(by,"\n div by "); + + if ( !overflow ) { + mix_word_t h1, l1, h2; + mix_word_print(q,"\n q = "); + mix_word_print(r," r = "); + mix_word_mul(by,q,&h1,&l1); + mix_word_add_and_carry(l1,r,&h2,&l1); + h1 = mix_word_add(h1,h2); + g_assert( mix_word_magnitude(r) < mix_word_magnitude(by) ); + g_assert( word_compare_(h1,h) ); + g_assert( mix_word_magnitude(l1) == mix_word_magnitude(l) ); + } else + g_print("\n\t = overflow"); + +} + +static void +test_mix_char_(void) +{ + mix_char_t mchar; + guchar achar; + guint k; + g_print("\nTesting mix_char_t. Table of mix_chars:\n"); + + for (k = 0; k < MIX_CHAR_MAX + 1; ++k) { + mchar = k; + achar = mix_char_to_ascii(mchar); + g_print("%02d: %c, ",k,achar); + if ( (k+1)%5 == 0 ) g_print("\n"); + g_assert( mchar == mix_ascii_to_char(achar) ); + } + g_print("\n"); +} + + +/* main test driver for mix_types.h/c */ + +int main(int argc, char **argv) +{ + unsigned int j,k; + mix_byte_t bytes[5] = { 0, 3, 20, 30, 40 }; + mix_byte_t r; + mix_short_t ss[6]; + mix_word_t words[6]; + + INIT_TEST; + + g_print("Testing mix_byte_t arithmetics...\n"); + PRINT_BYTE(bytes[0]); g_print(", "); + PRINT_BYTE(bytes[1]); g_print(", "); + PRINT_BYTE(bytes[2]); g_print(", "); + PRINT_BYTE(bytes[3]); g_print(", "); + PRINT_BYTE(bytes[4]); g_print("\n"); + PRINT_BYTE(r = mix_byte_add(bytes[1],bytes[2])); + g_print("\n"); g_assert(r == 23); + PRINT_BYTE(r = mix_byte_add(bytes[3],bytes[4])); + g_print("\n"); g_assert(r == 6); + PRINT_BYTE(r = mix_byte_sub(bytes[0],bytes[1])); + g_print("\n"); g_assert(r == 61); + PRINT_BYTE(r = mix_byte_sub(bytes[4],bytes[3])); + g_print("\n"); g_assert(r == 10); + PRINT_BYTE(r = mix_byte_sub(bytes[1],bytes[4])); + g_print("\n"); g_assert(r == 27); + PRINT_BYTE(r = mix_byte_mul(bytes[0],bytes[1])); + g_print("\n"); g_assert(r == 0); + PRINT_BYTE(r = mix_byte_mul(bytes[1],bytes[2])); + g_print("\n"); g_assert(r == 60); + PRINT_BYTE(r = mix_byte_mul(bytes[1],bytes[4])); + g_print("\n"); g_assert(r == 56); + PRINT_BYTE(r = mix_byte_mul(bytes[4],bytes[1])); + g_print("\n"); g_assert(r == 56); + PRINT_BYTE(r = mix_byte_div(bytes[4],bytes[2])); + g_print("\n"); g_assert(r == 2); + PRINT_BYTE(r = mix_byte_div(bytes[3],bytes[2])); + g_print("\n"); g_assert(r == 1); + + test_mix_char_(); + + g_print("\nTesting word<->short conversions..."); + words[0] = mix_bytes_to_word(bytes+1,5); + words[1] = mix_word_negative(words[0]); + ss[0] = mix_word_to_short(words[0]); + ss[1] = mix_word_to_short(words[1]); + mix_word_print(words[0],"\nwords[0]="); + mix_word_print(words[1],"\nwords[1]="); + mix_short_print(ss[0],"\nss[0]="); + mix_short_print(ss[1],"\nss[1]="); + g_assert(mix_short_is_positive(ss[0])); + g_assert(mix_short_is_negative(ss[1])); + words[2] = mix_short_to_word(ss[0]); + words[3] = mix_short_to_word(ss[1]); + mix_word_print(words[2],"\nwords[2]="); + mix_word_print(words[3],"\nwords[3]="); + g_assert(mix_word_sign(words[0]) == mix_word_sign(words[2])); + g_assert(mix_word_sign(words[1]) == mix_word_sign(words[3])); + g_assert(mix_short_magnitude(ss[0]) == mix_word_magnitude(words[2])); + g_assert(mix_short_magnitude(ss[1]) == mix_word_magnitude(words[3])); + g_assert(mix_word_get_byte(words[0],4) == mix_word_get_byte(words[2],4)); + g_assert(mix_word_get_byte(words[0],5) == mix_word_get_byte(words[2],5)); + g_assert(mix_word_get_byte(words[1],4) == mix_word_get_byte(words[3],4)); + g_assert(mix_word_get_byte(words[1],5) == mix_word_get_byte(words[3],5)); + words[4] = mix_word_extract_field(mix_fspec_new(4,5),words[0]); + words[5] = mix_word_extract_field(mix_fspec_new(4,5),words[1]); + mix_word_reverse_sign(words[5]); + g_assert(words[4] == words[2]); + g_assert(words[5] == words[3]); + + g_print("Testing mix_word_t creation and byte access...\n"); + test_word_from_bytes_(words,bytes,5,"word[0] created from bytes[0-4]"); + test_word_from_bytes_(words+1,bytes,4,"\nword[1] created from bytes[0-3]"); + test_word_from_bytes_(words+2,bytes,3,"\nword[2] created from bytes[0-2]"); + words[3] = mix_word_negative(words[2]); + g_assert( mix_word_negative(words[3]) == words[2] ); + g_assert( mix_word_is_negative(words[3]) && !mix_word_is_negative(words[2])); + mix_word_print(words[3],"\nword[3] created from -word[2]"); + test_word_from_bytes_(words+4,bytes+2,2,"\nword[2] created from bytes[2-3]"); + + g_print("\nTesting mix_word_t field access...\n"); + mix_word_set_byte(words+3,1,12); + mix_word_set_byte(words+3,2,58); + g_assert( mix_word_get_byte(words[3],1) == 12 ); + g_assert( mix_word_get_byte(words[3],2) == 58 ); + test_field_access_(0,5,words[3],words[4]); + test_field_access_(1,5,words[3],words[4]); + test_field_access_(2,5,words[3],words[4]); + test_field_access_(3,5,words[3],words[4]); + test_field_access_(4,5,words[3],words[4]); + test_field_access_(5,5,words[3],words[4]); + test_field_access_(0,0,words[3],words[4]); + + g_print("\n\nTesting mix_word_t arithmetics...\n"); + words[0] = MIX_WORD_MAX; + words[1] = mix_word_negative(words[0]); + for ( k = 1; k < 6; ++k ) { + mix_word_set_byte(words+2,k,5*k); + mix_word_set_byte(words+4,k,10*(5-k)); + mix_word_set_byte(words+3,k,21 + 3*k); + } + words[5] = 0; + + g_print("\n***addition***"); + for ( k = 0; k < 6; ++k ) + for ( j = 0; j <= k; ++j ) { + test_word_add_(words[k],mix_word_negative(words[j])); + test_word_add_(words[k],words[j]); + } + g_print("\n***product***"); + for ( k = 0; k < 6; ++k ) + for ( j = 0; j <= k; ++j ) { + test_word_mul_(words[k],words[j]); + } + g_print("\n***division***"); + for ( k = 0; k < 6; ++k ) { + test_word_div_(words[k],0,words[0]); + for ( j = 0; j <= k; ++j ) { + test_word_div_(k,words[j],words[j]); + test_word_div_(0,mix_word_add(mix_word_magnitude(words[j]),j),words[j]); + test_word_div_(mix_word_negative(k),words[j],words[j]); + } + } + + g_print("\nTesting shift operations...\n"); + for ( k = 0; k < 10; ++k ) + mix_word_set_byte(words+(k/5),1+(k%5),k+1); + + mix_word_print(words[0],"A = "); + mix_word_print(words[1],"X = "); + for ( k = 0; k < 11; ++k ) { + mix_word_t A, X; + unsigned int m; + + mix_word_shift_left(words[0],words[1],k,&A,&X); + g_print("\nShift left %d:\n",k); + mix_word_print(A,"A "); + mix_word_print(X,"X "); + for ( m = 0; m < 10 - k; ++m ) + g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == + mix_word_get_byte(words[(m+k)/5], ((m+k)%5)+1) ); + for ( ; m < 10; ++m ) + g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == 0 ); + + mix_word_shift_right(words[0],words[1],k,&A,&X); + g_print("\nShift right %d:\n",k); + mix_word_print(A,"A "); + mix_word_print(X,"X "); + for ( m = 0; m < k; ++m ) + g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == 0 ); + for ( ; m < 10; ++m ) + g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == + mix_word_get_byte(words[(m-k)/5], ((m-k)%5)+1) ); + + mix_word_shift_left_circular(words[0],words[1],k,&A,&X); + g_print("\nShift left circular %d:\n",k); + mix_word_print(A,"A "); + mix_word_print(X,"X "); + for ( m = 0; m < 10 - k; ++m ) + g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == + mix_word_get_byte(words[(m+k)/5], ((m+k)%5)+1) ); + for ( ; m < 10; ++m ) + g_assert( mix_word_get_byte( m < 5 ? A:X, (m%5)+1 ) == + mix_word_get_byte(words[(m-10+k)/5], 1+((m-10+k)%5)) ); + mix_word_shift_right_circular(A, X, k, &A, &X); + g_print("\nRe-shiftting right...\n"); + mix_word_print(A, "A "); + mix_word_print(X, "X "); + g_assert(A == words[0]); + g_assert(X == words[1]); + } + + + g_print("\n"); + return EXIT_SUCCESS; +} + + + + + + diff --git a/mixlib/testsuite/mix_vm_ins_t.c b/mixlib/testsuite/mix_vm_ins_t.c new file mode 100644 index 0000000..7f9d001 --- /dev/null +++ b/mixlib/testsuite/mix_vm_ins_t.c @@ -0,0 +1,500 @@ +/* ---------------------- mix_vm_ins_t.c : + * Tests for the virtual machine instruction handlers. + * ------------------------------------------------------------------ +** Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> +** +** 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. +** +*/ + + +#include <stdlib.h> +/*#define VERBOSE_TEST*/ +#include "test.h" +#include "mix_vm.h" +#include "mix_vm_dump.h" + +typedef struct +{ + mix_word_t rA_b, rA_a; + mix_word_t rX_b, rX_a; + mix_short_t rJ_b, rJ_a; + mix_short_t rI_b[6], rI_a[6]; + gboolean over_b, over_a; + mix_cmpflag_t cmp_b, cmp_a; + mix_address_t begin, end; + mix_word_t *cells_b, *cells_a; + const mix_ins_t *ins; +} test_desc_t; + +static void +set_cells_(test_desc_t *t, mix_address_t begin, mix_address_t end) +{ + g_assert(begin <= end); + t->begin = begin; + t->end = end; + t->cells_b = g_new(mix_word_t,end-begin); + t->cells_a = g_new(mix_word_t,end-begin); +} + +static void +free_cells_(test_desc_t *t) +{ + g_assert(t); + g_free(t->cells_a); + g_free(t->cells_b); + t->cells_a = t->cells_b = NULL; + t->begin = t->end = 0; +} + + +static void +fill_test_desc_(test_desc_t *t, const mix_vm_t *vm, const mix_ins_t *ins) +{ + guint k; + g_assert(t); + g_assert(vm); + + t->rA_b = t->rA_a = mix_vm_get_rA(vm); + t->rX_b = t->rX_a = mix_vm_get_rX(vm); + t->rJ_b = t->rJ_a = mix_vm_get_rJ(vm); + for ( k = 0; k < 6; ++k ) + t->rI_b[k] = t->rI_a[k] = mix_vm_get_rI(vm,k+1); + t->cmp_b = t->cmp_a = mix_vm_get_cmpflag(vm); + t->over_b = t->over_a = mix_vm_get_overflow(vm); + + for (k = 0; k < t->end-t->begin; ++k) + t->cells_a[k] = t->cells_b[k] = + mix_vm_get_addr_contents(vm,t->begin+k); + t->ins = ins; +} + + +static void +run_test_(test_desc_t *t, mix_vm_t *vm, mix_dump_context_t *dc) +{ + guint k; + g_assert(t); + g_assert(vm); + + mix_vm_set_rA(vm, t->rA_b); + mix_vm_set_rX(vm, t->rX_b); + mix_vm_set_rJ(vm, t->rJ_b); + for (k = 0; k < 6; ++k) mix_vm_set_rI(vm, k+1, t->rI_b[k]); + for (k = t->begin; k < t->end; ++k) + mix_vm_set_addr_contents(vm, k, t->cells_b[k-t->begin]); + mix_vm_set_cmpflag(vm, t->cmp_b); + mix_vm_set_overflow(vm, t->over_b); + + mix_ins_print(t->ins); + if (dc) { + mix_dump_context_range(dc, t->begin, t->end); + mix_vm_dump(vm,dc); + } + k = mix_vm_exec_ins(vm, t->ins); + if (dc) mix_vm_dump(vm, dc); + g_assert(k == TRUE); + g_assert(mix_vm_get_rA(vm) == t->rA_a); + g_assert(mix_vm_get_rX(vm) == t->rX_a); + for (k = 0; k < 6; ++k) g_assert(mix_vm_get_rI(vm, k+1) == t->rI_a[k]); + g_assert(mix_vm_get_cmpflag(vm) == t->cmp_a); + g_assert(mix_vm_get_overflow(vm) == t->over_a); + for (k = t->begin; k < t->end; ++k) + g_assert(mix_vm_get_addr_contents(vm, k) == t->cells_a[k-t->begin]); +} + + + +static void +test_arithmetics_(mix_vm_t *vm, mix_dump_context_t *dc) +{ + test_desc_t test; + mix_ins_t ins; + + g_print("\nTesting arithmetic instructions...\n"); + mix_vm_reset(vm); + mix_ins_fill_from_id(ins,mix_ADD); + ins.index = 0; + ins.address = 1000; + mix_vm_set_rA(vm,mix_word_new_b(19,18,1,2,22)); + mix_vm_set_addr_contents(vm,1000,mix_word_new_b(1,36,5,0,50)); + set_cells_(&test,1000,1001); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(20,54,6,3,8); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins,mix_SUB); + mix_vm_set_rA(vm,mix_word_new_bn(19,18,0,0,9)); + mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(31,16,2,22,0)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(11,62,2,21,55); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins,mix_MUL); + mix_vm_set_rA(vm,mix_word_new_b(1,1,1,1,1)); + mix_vm_set_addr_contents(vm,1000, mix_word_new_b(1,1,1,1,1)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(0,1,2,3,4); + test.rX_a = mix_word_new_b(5,4,3,2,1); + run_test_(&test, vm, dc); + + ins.fspec = mix_fspec_new(1,1); + mix_vm_set_rA(vm,mix_word_new_bn(0,0,0,1,48)); + mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(2,16,2,22,0)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = MIX_WORD_MINUS_ZERO; + test.rX_a = mix_word_new_bn(0,0,0,3,32); + run_test_(&test, vm, dc); + + mix_vm_set_rA(vm,mix_word_new_bn(0,0,0,1,48)); + mix_vm_set_addr_contents(vm,1000,mix_word_new_b(2,0,34,33,1)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = MIX_WORD_MINUS_ZERO; + test.rX_a = mix_word_new_bn(0,0,0,3,32); + run_test_(&test, vm, dc); + + ins.fspec = mix_fspec_new(0,5); + mix_vm_set_rA(vm,mix_word_new_bn(50,0,1,48,4)); + mix_vm_set_addr_contents(vm,1000,mix_word_new_bn(2,0,0,0,0)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(1,36,0,3,32); + test.rX_a = mix_word_new_b(8,0,0,0,0); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins,mix_DIV); + mix_vm_set_rA(vm,MIX_WORD_ZERO); + mix_vm_set_rX(vm,mix_word_new_b(0,0,0,0,17)); + mix_vm_set_addr_contents(vm,1000, mix_word_new_b(0,0,0,0,3)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(0,0,0,0,5); + test.rX_a = mix_word_new_b(0,0,0,0,2); + run_test_(&test, vm, dc); + + mix_vm_set_rA(vm,MIX_WORD_ZERO); + mix_vm_set_rX(vm,mix_word_new_bn(0,0,0,0,17)); + mix_vm_set_addr_contents(vm,1000, mix_word_new_b(0,0,0,0,3)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(0,0,0,0,5); + test.rX_a = mix_word_new_b(0,0,0,0,2); + run_test_(&test, vm, dc); + + mix_vm_set_rA(vm, MIX_WORD_MINUS_ZERO); + mix_vm_set_rX(vm, mix_word_new_b(19,19,0,3,1)); + mix_vm_set_addr_contents(vm,1000, mix_word_new_bn(0,0,0,2,0)); + fill_test_desc_(&test,vm,&ins); + test.rA_a = mix_word_new_b(0,9,41,32,1); + test.rX_a = mix_word_new_bn(0,0,0,1,1); + run_test_(&test, vm, dc); + + free_cells_(&test); +} + +static void +test_shift_(mix_vm_t *vm, mix_dump_context_t *dc) +{ + test_desc_t test; + mix_ins_t ins; + + g_print("Testing shift instructions...\n"); + mix_vm_reset(vm); + set_cells_(&test,0,0); + fill_test_desc_(&test,vm,&ins); + mix_ins_fill_from_id(ins,mix_SRAX); + ins.index = 0; + ins.address = 1; + test.rA_b = mix_word_new_b(1,2,3,4,5); + test.rX_b = mix_word_new_bn(6,7,8,9,10); + test.rA_a = mix_word_new_b(0,1,2,3,4); + test.rX_a = mix_word_new_bn(5,6,7,8,9); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_SLA); + ins.address = 2; + fill_test_desc_(&test, vm, &ins); + test.rA_a = mix_word_new_b(2,3,4,0,0); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_SRC); + ins.address = 4; + fill_test_desc_(&test, vm, &ins); + test.rA_a = mix_word_new_b(6,7,8,9,2); + test.rX_a = mix_word_new_bn(3,4,0,0,5); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_SRA); + ins.address = 2; + fill_test_desc_(&test, vm, &ins); + test.rA_a = mix_word_new_b(0,0,6,7,8); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_SLC); + ins.address = 501; + fill_test_desc_(&test, vm, &ins); + test.rA_a = mix_word_new_b(0,6,7,8,3); + test.rX_a = mix_word_new_bn(4,0,0,5,0); + run_test_(&test, vm, dc); +} + +static void +test_spc_(mix_vm_t *vm, mix_dump_context_t *dc) +{ + test_desc_t test; + mix_ins_t ins; + + g_print("Testing special instructions...\n"); + mix_vm_reset(vm); + set_cells_(&test,0,0); + fill_test_desc_(&test,vm,&ins); + mix_ins_fill_from_id(ins,mix_NUM); + ins.index = 0; + ins.address = 0; + test.rA_b = mix_word_new_bn(0,0,31,32,39); + test.rX_b = mix_word_new_b(37,57,47,30,30); + test.rA_a = mix_word_negative(12977700); + test.rX_a = test.rX_b; + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_INCA); + ins.address = 1; + fill_test_desc_(&test, vm, &ins); + test.rA_a = mix_word_negative(12977699); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_CHAR); + fill_test_desc_(&test, vm, &ins); + test.rA_a = mix_word_new_bn(30,30,31,32,39); + test.rX_a = mix_word_new_b(37,37,36,39,39); + run_test_(&test, vm, dc); + + mix_ins_fill_from_id(ins, mix_HLT); + fill_test_desc_(&test, vm, &ins); + run_test_(&test, vm, dc); + g_assert(mix_vm_is_halted(vm)); + +} + +static void +test_move_(mix_vm_t *vm, mix_dump_context_t *dc) +{ + test_desc_t test; + mix_ins_t ins; + guint k; + + g_print("Testing move instruction...\n"); + mix_vm_reset(vm); + set_cells_(&test,0,10); + fill_test_desc_(&test,vm,&ins); + mix_ins_fill_from_id(ins,mix_MOVE); + + ins.index = 0; + ins.address = 0; + ins.fspec = 5; + for ( k = 0; k < 5; ++k ) + test.cells_b[k] = test.cells_a[k+5] = test.cells_a[k] =mix_word_new(100*k); + + test.rI_b[0] = 5; + test.rI_a[0] = 10; + run_test_(&test,vm,dc); + + free_cells_(&test); +} + + + +static void +test_load_(mix_vm_t *vm, mix_dump_context_t *dc) +{ + test_desc_t test; + mix_ins_t ins; + mix_ins_id_t ids[4] = {mix_LDA, mix_LDX, mix_LDAN, mix_LDXN}; + mix_word_t r_a[14] = { mix_word_new_bn(1,16,3,5,4), + mix_word_new_b(1,16,3,5,4), + mix_word_new_b(0,0,3,5,4), + mix_word_new_bn(0,0,1,16,3), + mix_word_new_b(0,0,0,0,5), + MIX_WORD_MINUS_ZERO, + mix_word_new_b(0,0,0,0,1), + mix_word_new_b(1,16,3,5,4), + mix_word_new_b(1,16,3,5,4), + mix_word_new_b(0,0,3,5,4), + mix_word_new_b(0,0,1,16,3), + mix_word_new_b(0,0,0,0,5), + MIX_WORD_ZERO, + mix_word_new_b(0,0,0,0,1)}; + mix_fspec_t fs[11] = {5,13,29,3,36,0,9,0,0,0,0}; + mix_address_t a_a[11] = { MIX_SHORT_MINUS_ZERO, + mix_short_new_bn(0,1), + mix_short_new_bn(1,16), + mix_short_new_bn(16,3), + mix_short_new_bn(3,5), + mix_short_new_bn(5,4), + mix_short_new_b(1,16), + mix_short_new_b(16,3), + mix_short_new_b(5,4), + mix_short_new_b(5,4), + mix_short_new_b(3,5)}; + mix_word_t val = mix_word_new_bn(1,16,3,5,4); + gint j; + + g_print("Testing load instructions...\n"); + set_cells_(&test,2000,2001); + ins.index = 1; + ins.address = mix_short_negative(50); + + mix_vm_reset(vm); + mix_vm_set_addr_contents(vm, 2000, val); + + for (j = 0; j < 4; ++j) + { + gint k; + mix_ins_fill_from_id(ins,ids[j]); + for ( k = 0; k < 7; ++k ) { + fill_test_desc_(&test,vm,&ins); + ins.fspec = fs[k]; + switch (ids[j]) + { + case mix_LDA: test.rA_a = r_a[k]; break; + case mix_LDX: test.rX_a = r_a[k]; break; + case mix_LDAN: test.rA_a = r_a[k+7]; break; + case mix_LDXN: test.rX_a = r_a[k+7]; break; + default: g_assert_not_reached(); + } + test.rI_b[0] = test.rI_a[0] = 2050; + run_test_(&test, vm, dc); + } + } + ins.index = 0; + ins.address = 2000; + fs[0] = 0; fs[1] = 1; fs[2] = 2; fs[3] = 3; fs[4] = 4; fs[5] = 5; + fs[6] = 10; fs[7] = 11; fs[8] = 37; fs[9] = 29; fs[10] = 12; + + mix_vm_reset(vm); + mix_vm_set_addr_contents(vm, 2000, val); + for ( j = 0; j < 14; j++ ) + { + guint k; + if (j == 6 || j == 7 ) continue; /* mix_LDX, mix_LDAN */ + mix_ins_fill_from_id(ins, mix_LD1 + j); + for (k = 0; k < 11; ++k) + { + fill_test_desc_(&test, vm, &ins); + ins.fspec = fs[k]; + if ( j < 6 ) + test.rI_a[j] = a_a[k]; + else /* mix_LDiN */ + test.rI_a[j-8] = mix_short_magnitude(a_a[k]); + run_test_(&test, vm, dc); + } + } + + free_cells_(&test); +} + + +static void +test_store_(mix_vm_t *vm, mix_dump_context_t *dc) +{ + test_desc_t test; + mix_ins_t ins; + mix_word_t reg = mix_word_new_b(6,7,8,9,0); + mix_word_t add = mix_word_new_bn(1,2,3,4,5); + mix_word_t addr[6] = { mix_word_new_b(6,7,8,9,0), + mix_word_new_bn(6,7,8,9,0), + mix_word_new_bn(1,2,3,4,0), + mix_word_new_bn(1,0,3,4,5), + mix_word_new_bn(1,9,0,4,5), + mix_word_new_b(0,2,3,4,5)}; + mix_word_t addri[6] = { mix_word_new_b(0,0,0,9,0), + mix_word_new_bn(0,0,0,9,0), + mix_word_new_bn(1,2,3,4,0), + mix_word_new_bn(1,0,3,4,5), + mix_word_new_bn(1,9,0,4,5), + mix_word_new_b(0,2,3,4,5)}; + mix_word_t addrz[6] = { mix_word_new_b(0,0,0,0,0), + mix_word_new_bn(0,0,0,0,0), + mix_word_new_bn(1,2,3,4,0), + mix_word_new_bn(1,0,3,4,5), + mix_word_new_bn(1,0,0,4,5), + mix_word_new_b(0,2,3,4,5)}; + mix_fspec_t fs[6] = {5,13,45,18,19,1}; + gint i,j; + + g_print("Testing store instructions...\n"); + + set_cells_(&test,2000,2001); + ins.index = 0; + ins.address = 2000; + + mix_vm_reset(vm); + fill_test_desc_(&test,vm,&ins); + test.rA_a = test.rA_b = test.rX_a = test.rX_b = reg; + test.rJ_a = test.rJ_b = mix_word_to_short(reg); + for (j = 0; j < 6; ++j) + test.rI_a[j] = test.rI_b[j] = test.rJ_a; + test.cells_b[0] = add; + + for (i = 0; i < 10; ++i) + { + mix_ins_fill_from_id(ins,mix_STA+i); + for (j = 0; j < 6; ++j) + { + ins.fspec = fs[j]; + if (i == 0 || i == 7 ) /* mix_STA, mix_STX */ + test.cells_a[0] = addr[j]; + else if ( i < 9 ) /* mix_STi, mix_STJ */ + test.cells_a[0] = addri[j]; + else /* mix_STZ */ + test.cells_a[0] = addrz[j]; + run_test_(&test,vm,dc); + } + } + + free_cells_(&test); +} + + + +int +main(int argc, const char **argv) +{ + mix_vm_t *vm; + mix_dump_context_t *dc; + + INIT_TEST; + + vm = mix_vm_new(); + +#ifdef VERBOSE_TEST + dc = mix_dump_context_new(MIX_DUMP_DEF_CHANNEL, 0, 0, MIX_DUMP_ALL); +#else + dc = NULL; +#endif + + test_arithmetics_(vm, dc); + test_shift_(vm, dc); + test_spc_(vm,dc); + test_move_(vm,dc); + test_load_(vm,dc); + test_store_(vm,dc); + + mix_vm_delete(vm); + +#ifdef VERBOSE_TEST + mix_dump_context_delete(dc); +#endif + + return EXIT_SUCCESS; +} + diff --git a/mixlib/testsuite/test.h b/mixlib/testsuite/test.h new file mode 100644 index 0000000..f71feff --- /dev/null +++ b/mixlib/testsuite/test.h @@ -0,0 +1,44 @@ +/* +** Copyright (C) 1999 jose antonio ortega ruiz <jaortega@acm.org> +** +** 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. +** +*/ + +/* Common definitions for test programs */ + +#ifndef TEST_H +#define TEST_H + +#include <glib.h> +#include <mix.h> + +#define PRINT_BYTE(byte) g_print("%s = %02d",#byte,byte) + +#ifdef VERBOSE_TEST /* get printed information */ +#define INIT_TEST \ + do { g_set_print_handler(NULL); mix_init_lib(); } while(FALSE); +#else /* no printed information */ +static void +dummy_print_f_(const gchar *m) +{ + /* no output */ +} +#define INIT_TEST \ +do { g_set_print_handler(dummy_print_f_); mix_init_lib(); } while(FALSE); +#endif /* VERBOSE_TEST */ + + +#endif /* TEST_H */ diff --git a/mixlib/xmix_io.c b/mixlib/xmix_io.c new file mode 100644 index 0000000..3c997c9 --- /dev/null +++ b/mixlib/xmix_io.c @@ -0,0 +1,57 @@ +/* -*-c-*- ------------------ xmix_io.c : + * Implementation of the functions declared in xmix_io.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include "xmix_io.h" + +const char *io_OPENTYPE_[5] = { "r", "w", "w+", "a", "a+" }; + + +/* initialise a mix_iochannel from a file descriptor */ +gboolean +io_init_from_fdesc_(mix_iochannel_t *ioc, int fdesc) +{ + FILE *file; + mix_fmode_t mode; + int flags = fcntl(fdesc, F_GETFL); + + if ( (flags&O_RDONLY) == O_RDONLY ) + mode = mix_io_READ; + else if ( (flags&O_WRONLY) == O_WRONLY ) + mode = mix_io_WRITE; + else if ( (flags&O_RDWR) == O_RDWR ) + mode = mix_io_RDWRT; + else + return FALSE; + + file = fdopen(fdesc, fmode_to_type_(mode)); + g_return_val_if_fail(file != NULL, FALSE); + + io_init_from_file_(ioc, file); + + return TRUE; +} + + + diff --git a/mixlib/xmix_io.h b/mixlib/xmix_io.h new file mode 100644 index 0000000..ca57a4b --- /dev/null +++ b/mixlib/xmix_io.h @@ -0,0 +1,64 @@ +/* -*-c-*- ------------------ xmix_io.h : + * Implementation of mix_iochannel_t and mix_file_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef XMIX_IOCHANNEL_H +#define XMIX_IOCHANNEL_H + +#include <stdio.h> +#include "mix_io.h" + +/* the actual definition of mix_iochannel_t */ +struct mix_iochannel_t +{ + FILE *file; +}; + + +extern const char * io_OPENTYPE_[5]; + +#define fmode_to_type_(mode) ( (mode) < 6 ? io_OPENTYPE_[(mode)]:NULL ) + +/* initialisation */ +extern gboolean +io_init_from_fdesc_(mix_iochannel_t *ioc, int fdesc); + +#define io_init_from_file_(ioc,f) (ioc)->file = f + +#define io_close_(ioc) fclose((ioc)->file) + +/* write/read data */ +#define write_data_(ioc,data,no) \ + ( (no) == fwrite((const void*)(data), sizeof(*(data)), (no), (ioc)->file) ) + +#define read_data_(ioc,data,no) \ + ( (no) == fread((void*)(data), sizeof(*(data)), (no), (ioc)->file) ) + +/* state */ +#define is_eof_(ioc) ( feof((ioc)->file) != 0 ) +#define is_ready_(ioc) ( ferror((ioc)->file) == 0 ) + +/* conversions */ +#define io_get_FILE_(ioc) (MIX_IOCHANNEL(ioc))->file + + +#endif /* XMIX_IOCHANNEL_H */ + diff --git a/mixlib/xmix_parser.h b/mixlib/xmix_parser.h new file mode 100644 index 0000000..fee385c --- /dev/null +++ b/mixlib/xmix_parser.h @@ -0,0 +1,96 @@ +/* -*-c-*- ---------------- xmix_parser.h : + * Declarations for the implementation of mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef XMIX_PARSER_H +#define XMIX_PARSER_H + +#include "mix_ins.h" +#include "mix_file.h" +#include "mix_symbol_table.h" +#include "mix_parser.h" + +/* mix_parser_t definition */ +struct mix_parser_t +{ + mix_file_t *in_file; /* the source file to be compiled */ + mix_symbol_table_t *symbol_table; + mix_symbol_table_t *ls_table; /* literal strings symbols */ + guint cur_ls; /* current literal string symbol */ + GHashTable *future_refs; /* a map from symbol name to list of addresses */ + GTree *ins_table; /* a table of compiled instructions */ + mix_address_t loc_count; /* current memory location during compilation */ + mix_parser_err_t status; /* outcome of compilation */ + guint err_line; /* line of the last error */ + guint err_count; /* no. of errors during compilation */ + guint warn_count; /* no. of warnings during compilation */ + mix_address_t start; /* start address of the compiled code */ +}; + +/* each node of the ins_table stores a mix_word_t with the instruction + and a source code line (for debugging and listing) +*/ +typedef struct ins_node_ +{ + mix_word_t ins; + guint lineno; +} ins_node_; + + +/* functions to manipulate mix_parser_t during compilation */ +/* symbol table */ + +/* Define a new symbol with value equal to the current loc_count + * and update previously set refs to this symbol + */ +extern mix_parser_err_t +mix_parser_define_symbol_here(mix_parser_t *parser, const gchar *name); + +/* Set a reference to future symbol here */ +extern void +mix_parser_set_future_ref(mix_parser_t *parser, const gchar *name); + +/* Redefine the value of a local symbol as the current loc_count */ +extern void +mix_parser_manage_local_symbol(mix_parser_t *parser, const gchar *name); + +/* Literal strings symbols */ +extern void +mix_parser_define_ls (mix_parser_t *parser, mix_word_t value); + +/* Compilation */ +/* Add instruction with address the current loc_count */ +extern void +mix_parser_add_ins(mix_parser_t *parser, const mix_ins_t *new_ins, + guint lineno); +extern void +mix_parser_add_raw(mix_parser_t *parser, mix_word_t word, guint lineno); + +/* Error handling */ +extern void +mix_parser_log_error(mix_parser_t *parser, mix_parser_err_t error, + gint lineno, const gchar *comment, gboolean warn); + + + + +#endif /* XMIX_PARSER_H */ + diff --git a/mixlib/xmix_vm.c b/mixlib/xmix_vm.c new file mode 100644 index 0000000..3fc32ab --- /dev/null +++ b/mixlib/xmix_vm.c @@ -0,0 +1,568 @@ +/* ---------------------- xmix_vm.c : + * Implementation of the functions declared in xmix_vm.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + + +#include "xmix_vm.h" + +/* auxiliar functions */ +G_INLINE_FUNC mix_address_t +get_M_(const mix_vm_t *vm, const mix_ins_t *ins); +G_INLINE_FUNC mix_word_t +get_V_(const mix_vm_t *vm, const mix_ins_t *ins); +G_INLINE_FUNC mix_device_t * +get_dev_ (mix_vm_t *vm, mix_fspec_t type); + +G_INLINE_FUNC mix_address_t +get_M_(const mix_vm_t *vm, const mix_ins_t *ins) +{ + if ( ins->index == 0 ) + return ins->address; + else + return mix_short_add(ins->address, + mix_word_to_short_fast(get_rI_(vm, ins->index))); +} + +G_INLINE_FUNC mix_word_t +get_V_(const mix_vm_t *vm, const mix_ins_t *ins) +{ + return mix_word_get_field(ins->fspec, get_cell_(vm, get_M_(vm,ins))); +} + +G_INLINE_FUNC mix_device_t * +get_dev_ (mix_vm_t *vm, mix_fspec_t type) +{ + if (type >= BD_NO_) return NULL; + if (vm->devices[type] == NULL) + vm->devices[type] = mix_device_new (type); + return vm->devices[type]; +} + +/* Instruction handlers */ + +static gboolean +nop_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert(ins->opcode == mix_opNOP); + inc_loc_(vm); + return TRUE; +} + +static gboolean +add_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_word_t val = get_V_(vm, ins); + g_assert(ins->opcode == mix_opADD || ins->opcode == mix_opSUB); + if ( ins->opcode == mix_opSUB ) mix_word_reverse_sign(val); + if ( mix_word_add_and_carry(get_rA_(vm), val, NULL, &get_rA_(vm)) ) + set_over_(vm,TRUE); + inc_loc_(vm); + return TRUE; +} + + +static gboolean +mul_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert(ins->opcode == mix_opMUL); + mix_word_mul(get_rA_(vm), get_V_(vm,ins), &get_rA_(vm), &get_rX_(vm)); + inc_loc_(vm); + return TRUE; +} + +static gboolean +div_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert(ins->opcode == mix_opDIV); + if ( mix_word_div(get_rA_(vm), get_rX_(vm), get_V_(vm,ins), + &get_rA_(vm), &get_rX_(vm)) ) + set_over_(vm,TRUE); + inc_loc_(vm); + return TRUE; +} + +static gboolean +spc_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert(ins->opcode == mix_opSPC); + + switch (mix_ins_id_from_ins(*ins)) { + case mix_HLT: halt_(vm, TRUE); break; + case mix_CHAR: + { + guint32 num = mix_word_magnitude(get_rA_(vm)); + mix_char_t z = mix_ascii_to_char('0'); + guint i; + for (i = 5; 0 < i; --i, num /= 10) + mix_word_set_byte(&get_rX_(vm), i, z + num % 10); + for (i = 5; 0 < i; --i, num /= 10) + mix_word_set_byte(&get_rA_(vm), i, z + num % 10); + break; + } + case mix_NUM: + { + guint i; + mix_word_t num = MIX_WORD_ZERO; + mix_word_t ten = 10; + for (i = 1; i <= 5; ++i) { + mix_word_mul(ten, num, NULL, &num); + mix_word_add_and_carry(num, mix_word_get_byte(get_rA_(vm),i)%10, + NULL, &num); + } + for (i = 1; i <= 5; ++i) { + mix_word_mul(ten, num, NULL, &num); + mix_word_add_and_carry(num, mix_word_get_byte(get_rX_(vm),i)%10, + NULL, &num); + } + set_rA_(vm, + mix_word_is_negative(get_rA_(vm)) ? mix_word_negative(num):num); + break; + } + default: return FALSE; + } + inc_loc_(vm); + return TRUE; +} + +static gboolean +sla_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_short_t n = get_M_(vm,ins); + + g_assert(ins->opcode == mix_opSLx); + g_return_val_if_fail(mix_short_is_positive(n), FALSE); + + switch ( mix_ins_id_from_ins(*ins) ) { + case mix_SLA: + mix_word_shift_left(get_rA_(vm), MIX_WORD_ZERO, n, &get_rA_(vm), NULL); + break; + case mix_SRA: + mix_word_shift_right(get_rA_(vm), MIX_WORD_ZERO, n, &get_rA_(vm), NULL); + break; + case mix_SLAX: + mix_word_shift_left(get_rA_(vm), get_rX_(vm), n, + &get_rA_(vm), &get_rX_(vm)); + break; + case mix_SRAX: + mix_word_shift_right(get_rA_(vm), get_rX_(vm), n, + &get_rA_(vm), &get_rX_(vm)); + break; + case mix_SLC: + mix_word_shift_left_circular(get_rA_(vm), get_rX_(vm), n, + &get_rA_(vm), &get_rX_(vm)); + break; + case mix_SRC: + mix_word_shift_right_circular(get_rA_(vm), get_rX_(vm), n, + &get_rA_(vm), &get_rX_(vm)); + break; + default: + return FALSE; + } + + inc_loc_(vm); + return TRUE; +} + +static gboolean +mov_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_short_t from = get_M_(vm,ins), + to = mix_word_to_short_fast(get_rI_(vm,1)); + guint k, delta = ins->fspec; + + g_assert(ins->opcode == mix_opMOVE); + g_return_val_if_fail(mix_short_is_positive(from), FALSE); + g_return_val_if_fail(mix_short_is_positive(to), FALSE); + g_return_val_if_fail(MEMOK_(from + delta -1), FALSE); + g_return_val_if_fail(MEMOK_(to + delta - 1), FALSE); + + for (k = 0; k < delta; ++k) + set_cell_(vm, to+k, get_cell_(vm, from+k)); + set_rI_(vm, 1, to+delta); + inc_loc_(vm); + return TRUE; +} + +static gboolean +lda_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + gint r = 0; + mix_word_t val; + mix_ins_id_t id = mix_ins_id_from_ins(*ins); + + g_assert(id >= mix_LDA && id <= mix_LDXN); + + val = get_V_(vm, ins); + if ( id > mix_LDX && mix_fspec_left(ins->fspec) == 0) + mix_word_reverse_sign(val); + if ( (id > mix_LDA && id < mix_LDX) || (id > mix_LDAN && id < mix_LDXN) ) + /* Bytes 1-3 of I regs are always null */ + val = mix_word_set_field(mix_fspec_new(1,3),MIX_WORD_ZERO,val); + + switch (id) { + case mix_LDA: case mix_LDAN: r = A_; break; + case mix_LDX: case mix_LDXN: r = X_; break; + case mix_LD1: case mix_LD1N: r = I1_; break; + case mix_LD2: case mix_LD2N: r = I2_; break; + case mix_LD3: case mix_LD3N: r = I3_; break; + case mix_LD4: case mix_LD4N: r = I4_; break; + case mix_LD5: case mix_LD5N: r = I5_; break; + case mix_LD6: case mix_LD6N: r = I6_; break; + default: g_assert_not_reached(); + } + set_reg_(vm, r, val); + inc_loc_(vm); + return TRUE; +} + + +static gboolean +sta_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_address_t addr = get_M_(vm, ins); + mix_ins_id_t id = mix_ins_id_from_ins(*ins); + mix_word_t from; + + g_assert(id >= mix_STA && id <= mix_STZ); + switch (id) { + case mix_STA: from = get_rA_(vm); break; + case mix_STX: from = get_rX_(vm); break; + case mix_STJ: from = get_rJ_(vm); break; + case mix_STZ: from = MIX_WORD_ZERO; break; + default: from = get_rI_(vm, id - mix_ST1 + 1); break; + } + set_cell_(vm, addr, + mix_word_store_field(ins->fspec, from, get_cell_(vm, addr))); + inc_loc_(vm); + return TRUE; +} + +static gboolean +jbs_handler_ (mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert (ins->opcode == mix_opJBUS); + g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); + g_return_val_if_fail (get_dev_ (vm, ins->fspec) != NULL, TRUE); + if ( mix_device_busy (get_dev_ (vm, ins->fspec)) ) { + set_rJ_(vm, get_loc_ (vm)); + set_loc_ (vm, get_M_ (vm, ins)); + } else inc_loc_ (vm); + return TRUE; +} + +static gboolean +ioc_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_address_t addr; + mix_device_t *dev; + gboolean result; + + g_assert(ins->opcode == mix_opIOC); + addr = get_M_ (vm, ins); + g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); + dev = get_dev_ (vm, ins->fspec); + g_return_val_if_fail (dev != NULL, TRUE); + result = + mix_device_ioc (dev, addr); + + inc_loc_(vm); + return result; +} + +static gboolean +inp_handler_ (mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_address_t addr; + mix_device_t *dev; + gboolean result; + + g_assert(ins->opcode == mix_opIN); + addr = get_M_ (vm, ins); + g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); + g_return_val_if_fail (MEMOK_(addr), TRUE); + dev = get_dev_ (vm, ins->fspec); + g_return_val_if_fail ( dev != NULL, TRUE); + g_return_val_if_fail (MEM_CELLS_NO_ - addr > mix_device_block_size(dev), + TRUE); + result = + mix_device_read (dev, get_cell_ptr_ (vm, addr)); + + inc_loc_(vm); + return result; +} + +static gboolean +out_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_address_t addr; + mix_device_t *dev; + gboolean result; + + g_assert(ins->opcode == mix_opOUT); + addr = get_M_ (vm, ins); + g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); + g_return_val_if_fail (MEMOK_(addr), TRUE); + dev = get_dev_ (vm, ins->fspec); + g_return_val_if_fail ( dev != NULL, TRUE); + g_return_val_if_fail (MEM_CELLS_NO_ - addr > mix_device_block_size(dev), + TRUE); + result = + mix_device_write (dev, get_cell_ptr_ (vm, addr)); + + inc_loc_(vm); + return result; +} + +static gboolean +jrd_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert(ins->opcode == mix_opJRED); + g_return_val_if_fail (ins->fspec < BD_NO_, TRUE); + g_return_val_if_fail (get_dev_ (vm, ins->fspec) != NULL, TRUE); + if ( mix_device_busy (get_dev_ (vm, ins->fspec)) ) + inc_loc_ (vm); + else { + set_rJ_(vm, get_loc_(vm)); + set_loc_ (vm, get_M_ (vm, ins)); + } + + return TRUE; +} + +static gboolean +jmp_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + gboolean jump = FALSE; + mix_address_t addr = get_M_(vm, ins); + mix_ins_id_t id = mix_ins_id_from_ins(*ins); + + g_assert(ins->opcode == mix_opJMP); + g_return_val_if_fail(MEMOK_(addr), FALSE); + switch ( id ) { + case mix_JMP: + case mix_JSJ: + jump = TRUE; + break; + case mix_JOV: + jump = get_over_(vm); + if (jump) set_over_(vm, FALSE); + break; + case mix_JNOV: + jump = !get_over_(vm); + set_over_(vm, FALSE); + break; + case mix_JL: + jump = ( get_cmp_(vm) == mix_LESS ); + break; + case mix_JE: + jump = ( get_cmp_(vm) == mix_EQ ); + break; + case mix_JG: + jump = ( get_cmp_(vm) == mix_GREAT ); + break; + case mix_JGE: + jump = ( get_cmp_(vm) != mix_LESS ); + break; + case mix_JNE: + jump = ( get_cmp_(vm) != mix_EQ ); + break; + case mix_JLE: + jump = ( get_cmp_(vm) != mix_GREAT ); + break; + default: + return FALSE; + } + + inc_loc_(vm); + if ( jump ) { + if ( id != mix_JSJ ) set_rJ_(vm, get_loc_(vm)); + set_loc_(vm, addr); + } + return TRUE; +} + +static gboolean +jpx_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + gboolean jump = FALSE; + mix_address_t addr = get_M_(vm, ins); + mix_ins_id_t id = mix_ins_id_from_ins(*ins); + mix_word_t val; + + g_assert(ins->opcode >= mix_opJAx || ins->opcode <= mix_opJXx); + g_return_val_if_fail(MEMOK_(addr), FALSE); + + switch (ins->opcode) { + case mix_opJAx: val = get_rA_(vm); break; + case mix_opJXx: val = get_rX_(vm); break; + default: val = get_rI_(vm, ins->opcode - mix_opJAx); + } + + switch (id) { + case mix_JAN: case mix_JXN: + case mix_J1N: case mix_J2N: case mix_J3N: + case mix_J4N: case mix_J5N: case mix_J6N: + jump = mix_word_is_negative(val) && val != MIX_WORD_MINUS_ZERO; + break; + case mix_JAZ: case mix_JXZ: + case mix_J1Z: case mix_J2Z: case mix_J3Z: + case mix_J4Z: case mix_J5Z: case mix_J6Z: + jump = mix_word_magnitude(val) == MIX_WORD_ZERO; + break; + case mix_JAP: case mix_JXP: + case mix_J1P: case mix_J2P: case mix_J3P: + case mix_J4P: case mix_J5P: case mix_J6P: + jump = mix_word_is_positive(val) && val != MIX_WORD_ZERO; + break; + case mix_JANN: case mix_JXNN: + case mix_J1NN: case mix_J2NN: case mix_J3NN: + case mix_J4NN: case mix_J5NN: case mix_J6NN: + jump = mix_word_magnitude(val) == MIX_WORD_ZERO + || mix_word_is_positive(val); + break; + case mix_JANZ: case mix_JXNZ: + case mix_J1NZ: case mix_J2NZ: case mix_J3NZ: + case mix_J4NZ: case mix_J5NZ: case mix_J6NZ: + jump = mix_word_magnitude(val) != MIX_WORD_ZERO; + break; + case mix_JANP: case mix_JXNP: + case mix_J1NP: case mix_J2NP: case mix_J3NP: + case mix_J4NP: case mix_J5NP: case mix_J6NP: + jump = mix_word_magnitude(val) == MIX_WORD_ZERO + || mix_word_is_negative(val); + break; + default: + return FALSE; + } + + inc_loc_(vm); + if ( jump ) { + set_rJ_(vm, get_loc_(vm)); + set_loc_(vm, addr); + } + return TRUE; +} + +static gboolean +ina_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + mix_word_t val = mix_short_to_word_fast(get_M_(vm, ins)); + mix_ins_id_t id = mix_ins_id_from_ins(*ins); + gint r; + + g_assert(id >= mix_INCA && id <= mix_ENNX); + + switch (ins->opcode) { + case mix_opINCA: r = A_; break; + case mix_opINCX: r = X_; break; + default: r = I1_ + ins->opcode - mix_opINC1; + } + + switch (id) { + case mix_ENTA: case mix_ENTX: + break; + case mix_ENT1: case mix_ENT2: case mix_ENT3: + case mix_ENT4: case mix_ENT5: case mix_ENT6: + val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); + break; + case mix_INCA: case mix_INCX: + if ( mix_word_add_and_carry(val, get_reg_(vm, r), NULL, &val) ) + set_over_(vm, TRUE); + break; + case mix_INC1: case mix_INC2: case mix_INC3: + case mix_INC4: case mix_INC5: case mix_INC6: + mix_word_add_and_carry(val, get_reg_(vm,r), NULL, &val); + val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); + break; + case mix_DECA: case mix_DECX: + if ( mix_word_add_and_carry(mix_word_negative(val), get_reg_(vm, r), + NULL, &val) ) + set_over_(vm, TRUE); + break; + case mix_DEC1: case mix_DEC2: case mix_DEC3: + case mix_DEC4: case mix_DEC5: case mix_DEC6: + mix_word_add_and_carry(mix_word_negative(val), get_reg_(vm,r), NULL, &val); + val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); + break; + case mix_ENN1: case mix_ENN2: case mix_ENN3: + case mix_ENN4: case mix_ENN5: case mix_ENN6: + val = mix_word_set_field(mix_fspec_new(1,3), MIX_WORD_ZERO, val); + /* fallthrough */ + case mix_ENNA: case mix_ENNX: + mix_word_reverse_sign(val); + break; + default: + return FALSE; + } + set_reg_(vm, r, val); + inc_loc_(vm); + return TRUE; +} + +static gboolean +cmp_handler_(mix_vm_t *vm, const mix_ins_t *ins) +{ + g_assert(ins->opcode >= mix_opCMPA && ins->opcode <= mix_opCMPX); + + if ( ins->fspec == 0 ) { /* shortcut: +0 == -0 */ + set_cmp_(vm, mix_EQ); + } else { + mix_word_t v = get_V_(vm, ins); + mix_word_t reg; + mix_cmpflag_t flag; + + switch (ins->opcode) { + case mix_opCMPA: + reg = get_rA_(vm); + break; + case mix_opCMPX: + reg = get_rX_(vm); + break; + default: + reg = get_rI_(vm, ins->opcode - mix_opCMPA); + break; + } + reg = mix_word_get_field(ins->fspec, reg); + mix_word_add_and_carry(reg, mix_word_negative(v), NULL, ®); + if ( mix_word_magnitude(reg) == MIX_WORD_ZERO ) flag = mix_EQ; + else if ( mix_word_is_positive(reg) ) flag = mix_GREAT; + else flag = mix_LESS; + set_cmp_(vm, flag); + } + inc_loc_(vm); + return TRUE; +} + +ins_handler_t_ ins_handlers_[MIX_BYTE_MAX + 1] = { + nop_handler_, add_handler_, add_handler_, mul_handler_, div_handler_, + spc_handler_, sla_handler_, mov_handler_, lda_handler_, lda_handler_, + lda_handler_, lda_handler_, lda_handler_, lda_handler_, lda_handler_, + lda_handler_, lda_handler_, lda_handler_, lda_handler_, lda_handler_, + lda_handler_, lda_handler_, lda_handler_, lda_handler_, sta_handler_, + sta_handler_, sta_handler_, sta_handler_, sta_handler_, sta_handler_, + sta_handler_, sta_handler_, sta_handler_, sta_handler_, jbs_handler_, + ioc_handler_, inp_handler_, out_handler_, jrd_handler_, jmp_handler_, + jpx_handler_, jpx_handler_, jpx_handler_, jpx_handler_, jpx_handler_, + jpx_handler_, jpx_handler_, jpx_handler_, ina_handler_, ina_handler_, + ina_handler_, ina_handler_, ina_handler_, ina_handler_, ina_handler_, + ina_handler_, cmp_handler_, cmp_handler_, cmp_handler_, cmp_handler_, + cmp_handler_, cmp_handler_, cmp_handler_, cmp_handler_, +}; diff --git a/mixlib/xmix_vm.h b/mixlib/xmix_vm.h new file mode 100644 index 0000000..ea2db61 --- /dev/null +++ b/mixlib/xmix_vm.h @@ -0,0 +1,111 @@ +/* ---------------------- xmix_vm.h : + * This file contains internal declarations used in the implementation + * of the mix_vm_t type. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef XMIX_VM_H +#define XMIX_VM_H + +#include "mix_symbol_table.h" +#include "mix_device.h" +#include "mix_vm.h" + +/* The mix_vm_t type */ +enum {IREG_NO_ = 6, BD_NO_ = 21, MEM_CELLS_NO_ = MIX_VM_CELL_NO}; +struct mix_vm_t +{ + mix_word_t reg[IREG_NO_+3]; + mix_word_t cell[MEM_CELLS_NO_]; + gboolean overflow; + mix_cmpflag_t cmpflag; + mix_short_t loc_count; + gboolean is_halted; + mix_device_t * devices[BD_NO_]; + mix_address_t start_addr; /* start address of loaded file */ + GTree *line_table; /* source line no -> address */ + gint8 bp[MEM_CELLS_NO_/8]; /* each bit signals a break point */ + mix_symbol_table_t *symbol_table; +}; + +/* Macros for accessing/modifying the above structure. + * Warning: the arguments of these macros must not have side-effects. + */ +#define IOK_(idx) ( (idx) > 0 && (idx) < IREG_NO_+1 ) +#define MEMOK_(addr) ( mix_short_is_positive(addr) && (addr) < MEM_CELLS_NO_ ) +#define REGOK_(r) ( (r) >= 0 && (r) < IREG_NO_ + 3 ) + +enum { A_ = 0, X_, J_, I1_, I2_, I3_, I4_, I5_, I6_ }; + +#define get_reg_(vm, r) ((vm)->reg[r]) +#define get_rA_(vm) get_reg_(vm, A_) +#define get_rX_(vm) get_reg_(vm, X_) +#define get_rJ_(vm) get_reg_(vm, J_) +#define get_rI_(vm,idx) get_reg_(vm, I1_ + (idx) - 1) +#define get_cell_(vm,addr) ( MEMOK_(addr) ? vm->cell[addr] : MIX_WORD_ZERO ) +#define get_cell_ptr_(vm,addr) ( MEMOK_(addr) ? (vm->cell) + addr : NULL ) +#define get_cmp_(vm) (vm->cmpflag) +#define get_over_(vm) (vm->overflow) +#define get_loc_(vm) (vm->loc_count) + +#define set_reg_(vm,r,x) \ +do { \ + if ( REGOK_(r) ) vm->reg[r] = (x); \ +} while (FALSE) + +#define set_rA_(vm,x) set_reg_(vm,A_,x) +#define set_rX_(vm,x) set_reg_(vm,X_,x) +#define set_rJ_(vm,x) set_reg_(vm,J_,(x)&MIX_SHORT_MAX) +#define set_rI_(vm,idx,x) set_reg_(vm,(idx) + I1_ - 1,x) + +#define set_cell_(vm,addr,x) \ +do { \ + if ( MEMOK_(addr) ) (vm)->cell[addr] = (x); \ +} while (FALSE) + +#define set_cmp_(vm,x) (vm)->cmpflag = (x) +#define set_over_(vm,x) (vm)->overflow = (x) +#define set_loc_(vm,x) (vm)->loc_count = (x)&MIX_SHORT_MAX + +#define inc_loc_(vm) \ +do { \ + vm->loc_count++; \ + vm->loc_count &= MIX_SHORT_MAX; \ +} while(FALSE) + +#define is_halted_(vm) ((vm)->is_halted) +#define halt_(vm,val) ((vm)->is_halted = (val)) +#define set_start_(vm,val) ((vm)->start_addr = (val)) +#define reset_loc_(vm) set_loc_ (vm, vm->start_addr) + +/* Breakpoints handling */ +#define bp_clear_all_(vm) memset (vm->bp, 0, MEM_CELLS_NO_/8) +#define bp_set_(vm,addr) vm->bp[(addr)>>3] |= 1 << ((addr)&7) +#define bp_clear_(vm,addr) vm->bp[(addr)>>3] &= ~(1 << ((addr)&7)) +#define bp_is_set_(vm,addr) vm->bp[(addr)>>3] & (1 << ((addr)&7)) + +/* Instruction handlers */ +typedef gboolean (*ins_handler_t_)(mix_vm_t *,const mix_ins_t *); + +extern ins_handler_t_ ins_handlers_[MIX_BYTE_MAX + 1]; + + +#endif /* XMIX_VM_H */ + diff --git a/mixutils/.cvsignore b/mixutils/.cvsignore new file mode 100644 index 0000000..349354d --- /dev/null +++ b/mixutils/.cvsignore @@ -0,0 +1,6 @@ +.deps +Makefile +Makefile.in +mixasm +mixcmp +mixvm diff --git a/mixutils/Makefile.am b/mixutils/Makefile.am new file mode 100644 index 0000000..710cc51 --- /dev/null +++ b/mixutils/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 jose antonio ortega ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +INCLUDES = -I$(includedir) +LDADD = $(top_builddir)/mixlib/libmix.a + +bin_PROGRAMS = mixasm mixvm +mixasm_SOURCES = mixasm.c mixasm_comp.h mixasm_comp.c +mixvm_SOURCES = mixvm.c mixvm_loop.c mixvm_command.h mixvm_command.c diff --git a/mixutils/mixasm.c b/mixutils/mixasm.c new file mode 100644 index 0000000..935e5d1 --- /dev/null +++ b/mixutils/mixasm.c @@ -0,0 +1,126 @@ +/* -*-c-*- -------------- mixasm.c: + * Main function of mixasm, the mix assembler + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include <mixlib/mix.h> + +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> + +#include "mixasm_comp.h" + +enum { + VER_OPT = 'v', + HELP_OPT = 'h', + USAGE_OPT = 'u', + OUT_OPT = 'o', + LIST_OPT = 'l', + DEBUG_OPT = 'g' +}; + + +static struct option long_options_[] = +{ + {"version", no_argument, 0, VER_OPT}, + {"help", no_argument, 0, HELP_OPT}, + {"usage", no_argument, 0, USAGE_OPT}, + {"output", required_argument, 0, OUT_OPT}, + {"list", optional_argument, 0, VER_OPT}, + {"debug", no_argument, 0, DEBUG_OPT}, + {0, 0, 0, 0} +}; + +static const gchar *USAGE_ = +N_("Usage: %s [-vhulg] [-o OUTPUT_FILE] [--version] [--help]\n" + "\t[--usage] [--debug] [--output=OUTPUT_FILE] [--list[=LIST_FILE]] file\n"); + + +int +main (int argc, char **argv) +{ + int c; + const char *prog_name = argv[0]; + const char *src = NULL, *out = NULL, *list = NULL; + gboolean use_list = FALSE, debug = FALSE; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + while (1) + { + c = getopt_long (argc, argv, "vhuo:lg", long_options_, (int*)0); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) + { + case HELP_OPT: case USAGE_OPT: + fprintf (stderr, _(USAGE_), prog_name); + return EXIT_SUCCESS; + case VER_OPT: + fprintf (stderr, _("%s %s, MIX compiler.\n"), prog_name, VERSION); + fprintf (stderr, MIX_GPL_LICENSE); + return EXIT_SUCCESS; + case OUT_OPT: + out = optarg; + break; + case LIST_OPT: + use_list = TRUE; + list = optarg; + break; + case DEBUG_OPT: + debug = TRUE; + break; + case '?': + /* getopt already handles the output of a warning message */ + fprintf (stderr, _("(Try: %s -h)\n"), prog_name); + return EXIT_FAILURE; + default: + g_assert_not_reached (); + } + } + + if ( optind == argc ) + { + fprintf (stderr, _("*** Error: Missing source file.\n")); + return EXIT_FAILURE; + } + if ( optind < argc-1 ) + { + fprintf (stderr, _("*** Error: Too many input files.\n")); + return EXIT_FAILURE; + } + src = argv[optind]; + + + mix_init_lib (); + + c = mix_asm_compile (src, out, use_list, list, debug); + + mix_release_lib (); + + return c; + +} + diff --git a/mixutils/mixasm_comp.c b/mixutils/mixasm_comp.c new file mode 100644 index 0000000..3a31363 --- /dev/null +++ b/mixutils/mixasm_comp.c @@ -0,0 +1,72 @@ +/* -*-c-*- -------------- mixasm_comp.c : + * Implementation of the functions declared in mixasm_comp.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + +#include <mixlib/mix.h> +#include <stdlib.h> +#include <stdio.h> +#include <mixlib/mix_parser.h> +#include "mixasm_comp.h" + +int +mix_asm_compile(const gchar *src, const gchar *out, gboolean use_list, + const gchar *list, gboolean debug) +{ + int result = EXIT_SUCCESS; + mix_parser_t *parser; + mix_parser_err_t error; + + if ( (parser = mix_parser_new(src)) == NULL ) + { + fprintf(stderr, _("*** Unable to open source file %s\n"), src); + return EXIT_FAILURE; + } + if ( mix_parser_compile(parser) == MIX_PERR_OK ) + { + guint k; + if ( ( k = mix_parser_warning_count(parser) ) != 0 ) + fprintf(stderr, _("(%d warning(s))\n"), k); + if ( (error = mix_parser_write_code(parser, out, debug)) != MIX_PERR_OK ) + { + fprintf(stderr, _("*** Error writing output code file: %s\n"), + mix_parser_err_string(error)); + result = EXIT_FAILURE; + } + else if ( use_list + && (error = mix_parser_write_listing(parser, list)) != + MIX_PERR_OK) + { + fprintf(stderr, _("*** Error writing listing file: %s\n"), + mix_parser_err_string(error)); + result = EXIT_FAILURE; + } + } + else + { + fprintf(stderr, _("(%d warning(s), %d error(s))\n"), + mix_parser_warning_count(parser), mix_parser_err_count(parser)); + result = EXIT_FAILURE; + } + + mix_parser_delete(parser); + return result; +} + + diff --git a/mixutils/mixasm_comp.h b/mixutils/mixasm_comp.h new file mode 100644 index 0000000..74c0474 --- /dev/null +++ b/mixutils/mixasm_comp.h @@ -0,0 +1,35 @@ +/* -*-c-*- ---------------- mixasm_comp.h : + * Declarations of functions used to compile mix source files. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIXASM_COMP_H +#define MIXASM_COMP_H + +#include <glib.h> + +extern int +mix_asm_compile(const gchar *src, const gchar *out, gboolean use_list, + const gchar *list, gboolean debug); + + + +#endif /* MIXASM_COMP_H */ + diff --git a/mixutils/mixvm.c b/mixutils/mixvm.c new file mode 100644 index 0000000..207eca8 --- /dev/null +++ b/mixutils/mixvm.c @@ -0,0 +1,148 @@ +/* -*-c-*- -------------- mixvm.c : + * Main function for mixvm, the mix vm simulator + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + + +#include <mixlib/mix.h> +#include <mixlib/mix_vm.h> +#include <mixlib/mix_vm_dump.h> + +#include <stdlib.h> +#include <stdio.h> +#include <getopt.h> + +extern void +mix_vmloop (const gchar *code_file); + +static void +mix_vmrun (const gchar *code_file, gboolean dump); + +enum { + VER_OPT = 'v', + HELP_OPT = 'h', + USAGE_OPT = 'u', + RUN_OPT = 'r', + DUMP_OPT = 'd' +}; + +static const char *options_ = "vhurd"; + +static struct option long_options_[] = +{ + {"version", no_argument, 0, VER_OPT}, + {"help", no_argument, 0, HELP_OPT}, + {"usage", no_argument, 0, USAGE_OPT}, + {"run", required_argument, 0, RUN_OPT}, + {"dump", no_argument, 0, DUMP_OPT}, + {0, 0, 0, 0} +}; + +static const gchar *USAGE_ = +N_("Usage: %s [-vhurd] [--version] [--help] [--usage] [--run] [--dump] [MIX_FILE]\n"); + + +int +main (int argc, char **argv) +{ + int c; + const char *prog_name = argv[0]; + const char *in = NULL; + gboolean run = FALSE; + gboolean dump = FALSE; + + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); + + while (1) + { + c = getopt_long (argc, argv, options_, long_options_, (int*)0); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) + { + case HELP_OPT: case USAGE_OPT: + fprintf (stderr, _(USAGE_), prog_name); + return EXIT_SUCCESS; + case VER_OPT: + fprintf (stderr, _("%s %s, MIX Virtual Machine.\n"), + prog_name, VERSION); + fprintf (stderr, MIX_GPL_LICENSE); + return EXIT_SUCCESS; + case RUN_OPT: + in = optarg; + run = TRUE; + break; + case DUMP_OPT: + dump = TRUE; + break; + case '?': + /* getopt already handles the output of a warning message */ + fprintf (stderr, _("(Try: %s -h)\n"), prog_name); + return EXIT_FAILURE; + default: + g_assert_not_reached (); + } + } + + if ( optind < argc-1 ) + { + fprintf (stderr, _("*** Error: Too many input files.\n")); + return EXIT_FAILURE; + } + + if (!in) in = argv[optind]; + + mix_init_lib (); + + if (run) mix_vmrun(in, dump); + else mix_vmloop (in); + + mix_release_lib (); + + return EXIT_SUCCESS; + +} + + +static void +mix_vmrun (const gchar *code_file, gboolean dump) +{ + mix_vm_t *vm = mix_vm_new (); + if (!mix_vm_load_file (vm, code_file)) { + fprintf (stderr, _("Error loading %s file\n"), code_file); + return; + } + mix_vm_run (vm); + if (dump) { + mix_dump_context_t *dc = mix_dump_context_new (MIX_DUMP_DEF_CHANNEL, + 0, 0, + MIX_DUMP_ALL_NOMEM); + mix_vm_dump (vm, dc); + mix_dump_context_delete (dc); + } + mix_vm_delete (vm); +} + + diff --git a/mixutils/mixvm_command.c b/mixutils/mixvm_command.c new file mode 100644 index 0000000..e03dcfd --- /dev/null +++ b/mixutils/mixvm_command.c @@ -0,0 +1,867 @@ +/* -*-c-*- -------------- mixvm_command.c : + * Implementation of the functions declared in mixvm_command.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#include <mixlib/mix.h> + +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <readline/readline.h> +#include <readline/history.h> + +#include <mixlib/mix_vm.h> +#include <mixlib/mix_vm_dump.h> +#include "mixvm_command.h" + +/* The names of functions that actually do the manipulation. */ +#define DEC_FUN(name) \ +static int cmd_##name (char *arg) + +DEC_FUN (help_); +DEC_FUN (shell_); +DEC_FUN (load_); +DEC_FUN (run_); +DEC_FUN (next_); +DEC_FUN (pc_); +DEC_FUN (psym_); +DEC_FUN (preg_); +DEC_FUN (pflags_); +DEC_FUN (pall_); +DEC_FUN (pmem_); +DEC_FUN (sreg_); +DEC_FUN (scmp_); +DEC_FUN (sover_); +DEC_FUN (smem_); +DEC_FUN (sbp_); +DEC_FUN (sbpa_); +DEC_FUN (cbp_); +DEC_FUN (cbpa_); +DEC_FUN (cabp_); +DEC_FUN (compile_); +DEC_FUN (edit_); +DEC_FUN (quit_); + +/* A structure which contains information on the commands this program + can understand. */ +typedef struct { + const char *name; /* User printable name of the function. */ + Function *func; /* Function to call to do the job. */ + const char *doc; /* Documentation for this function. */ + const char *usage; /* Usage */ +} COMMAND; + +COMMAND commands[] = { + { "help", cmd_help_, N_("Display this text"), "help [COMMAND]" }, + { "?", cmd_help_, N_("Synonym for `help'"), "? [COMMAND]" }, + { "!", cmd_shell_, N_("Execute shell command"), "! COMMAND" }, + { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME" }, + { "run", cmd_run_, N_("Run loaded or given MIX code file"), + "run [FILENAME]" }, + { "next", cmd_next_, N_("Execute next instruction(s)"), + "next [NO_OF_INS]"}, + { "pc", cmd_pc_, N_("Print program counter value"), "pc" }, + { "psym", cmd_psym_, N_("Print symbol value"), "psym [SYMBOLNAME]" }, + { "preg", cmd_preg_, N_("Print register value"), + "preg [A | X | J | I[1-6]]" }, + { "pflags", cmd_pflags_, N_("Print comparison and overflow flags"), + "pflags" }, + { "pall", cmd_pall_, N_("Print all registers and flags"), "pall" }, + { "pmem", cmd_pmem_, N_("Print memory contents in address range"), + "pmem FROM[-TO]" }, + { "sreg", cmd_sreg_, N_("Set register value"), + "preg A | X | J | I[1-6] VALUE" }, + { "scmp", cmd_scmp_, N_("Set comparison flag value"), "scmp L | E | G" }, + { "sover", cmd_sover_, N_("Set overflow flag value"), "sover T | F" }, + { "smem", cmd_smem_, N_("Set memory contents in given address"), + "smem ADDRESS VALUE" }, + { "sbp", cmd_sbp_, N_("Set break point at given line"), "sbp LINENO" }, + { "cbp", cmd_cbp_, N_("Clear break point at given line"), "cbp LINENO" }, + { "sbpa", cmd_sbpa_, N_("Set break point at given address"), + "sbpa ADDRESS" }, + { "cbpa", cmd_cbpa_, N_("Clear break point at given address"), + "cbpa ADDRESS" }, + { "cabp", cmd_cabp_, N_("Clear all breakpoints"), "cabp" }, + { "compile", cmd_compile_, N_("Compile a source file"), "compile FILENAME"}, + { "edit", cmd_edit_, N_("Edit a source file"), "edit FILENAME"}, + { "quit", cmd_quit_, N_("Quit the program"), "quit" }, + { (char *)NULL, (Function *)NULL, (char *)NULL } +}; + + +/* readline functions */ +static char * +mixvm_cmd_generator_ (char *text, int state); + + +/* Attempt to complete on the contents of TEXT. START and END bound the + region of rl_line_buffer that contains the word to complete. TEXT is + the word to complete. We can use the entire contents of rl_line_buffer + in case we want to do some simple parsing. Return the array of matches, + or NULL if there aren't any. */ +static char ** +mixvm_cmd_completion_ (char *text, int start, int end) +{ + char **matches; + + matches = (char **)NULL; + + /* If this word is at the start of the line, then it is a command + to complete. Otherwise it is the name of a file in the current + directory. */ + if (start == 0) + matches = completion_matches (text, mixvm_cmd_generator_); + + return (matches); +} + +/* Generator function for command completion. STATE lets us know whether + to start from scratch; without any state (i.e. STATE == 0), then we + start at the top of the list. */ +static char * +mixvm_cmd_generator_ (char *text, int state) +{ + static int list_index, len; + const char *name; + + /* If this is a new word to complete, initialize now. This includes + saving the length of TEXT for efficiency, and initializing the index + variable to 0. */ + if (!state) + { + list_index = 0; + len = strlen (text); + } + + /* Return the next name which partially matches from the command list. */ + while ( (name = commands[list_index].name) != NULL) + { + list_index++; + + if (strncmp (name, text, len) == 0) + return (g_strdup (name)); + } + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +} + + +/* command functions */ +static COMMAND * +find_command_ (const char *name) +{ + int i; + + for (i = 0; commands[i].name; i++) + if (strcmp (name, commands[i].name) == 0) + return (&commands[i]); + + return ((COMMAND *)NULL); +} + + +/* the virtual machine and dump context */ +static mix_vm_t *vm_ = NULL; +static mix_dump_context_t *dc_ = NULL; + +static int +cmd_help_ (char *arg) +{ + static const int NO_OF_COLS = 6; + + int i; + int printed = 0; + + for (i = 0; commands[i].name; i++) + { + if (!*arg || (strcmp (arg, commands[i].name) == 0)) + { + printf (_("%s\t\t%s. Usage: %s\n"), commands[i].name, + _(commands[i].doc), commands[i].usage); + printed++; + } + } + + if (!printed) + { + printf (_("No commands match `%s'. Possibilities are:\n"), arg); + + for (i = 0; commands[i].name; i++) + { + if (printed == NO_OF_COLS) + { + printed = 0; + printf ("\n"); + } + + printf ("%s\t", commands[i].name); + printed++; + } + + if (printed) + printf ("\n"); + } + return TRUE; +} + +static int +cmd_load_ (char *arg) +{ + errno = 0; + if (arg == NULL || *arg == '\0') + fputs (_("Missing file name\n"), stderr); + else if (!mix_vm_load_file (vm_, arg) ) + { + fprintf (stderr, _("Cannot load %s: "), arg); + if ( errno == 0 ) + fputs (_("Wrong file format\n"), stderr); + else + perror (NULL); + return TRUE + 1; + } + fprintf (stderr, _("Program loaded. Start address: %d\n"), + mix_vm_get_prog_count (vm_)); + + return TRUE; +} + +static int +cmd_run_ (char *arg) +{ + if (arg != NULL && *arg != '\0' && cmd_load_ (arg) != TRUE) + return TRUE; + puts (_("Running ...")); + switch (mix_vm_run (vm_)) + { + case MIX_VM_HALT: + puts (_("... done")); + break; + case MIX_VM_BREAK: + { + gulong line = mix_vm_get_break_lineno (vm_); + if (line != 0) + printf (_("... stopped: breakpoint at line %ld (address %d)\n"), + line, mix_vm_get_prog_count (vm_)); + else + printf (_("... stopped: breakpoint at address %d\n"), + mix_vm_get_prog_count (vm_)); + } + break; + case MIX_VM_ERROR: + puts (_("... error executing loaded file")); + break; + default: + g_assert_not_reached (); + break; + } + return TRUE; +} + +static int +cmd_next_ (char *arg) +{ + int ins_no = 1; + if ( strlen (arg) != 0 ) + { + int k = 0; + while (isdigit (arg[k])) + k++; + if (arg[k] != '\0') + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_ ("next"); + } + ins_no = atoi (arg); + } + + while ( ins_no-- > 0 ) + { + int k = mix_vm_exec_next (vm_); + if (k == MIX_VM_HALT) + { + fprintf (stderr, _("End of program reached at address %d\n"), + mix_vm_get_prog_count (vm_)); + break; + } + else if (k == MIX_VM_ERROR) + { + fprintf (stderr, _("Error at address %d\n"), + mix_vm_get_prog_count (vm_)); + break; + } + } + + return TRUE; +} + +static int +cmd_quit_ (char *arg) +{ + puts ("Quitting ..."); + if ( vm_ ) mix_vm_delete (vm_); + if ( dc_ ) mix_dump_context_delete (dc_); + return FALSE; +} + +static int +cmd_pc_ (char *arg) +{ + printf ("Current address: %d\n", mix_vm_get_prog_count (vm_)); + return TRUE; +} + +static int +cmd_psym_ (char *arg) +{ + const mix_symbol_table_t *table = mix_vm_get_symbol_table (vm_); + if ( table == NULL ) + fputs (_("Symbol table not available\n"), stderr); + else if (arg != NULL && *arg != '\0') + { + if ( mix_symbol_table_is_defined (table, arg) ) + { + mix_word_print (mix_symbol_table_value (table, arg), NULL); + puts ("\n"); + } + else + printf (_("%s: symbol not defined\n"), arg); + } + else + mix_symbol_table_print (table, MIX_SYM_ROWS, stdout); + + return TRUE; +} + +static int +cmd_preg_ (char *arg) +{ + mix_dump_context_set_opt (dc_, MIX_DUMP_NONE); + if ( strlen (arg) == 0 ) + mix_dump_context_add_opt (dc_, MIX_DUMP_rALL); + else switch (*arg) + { + case 'A': + mix_dump_context_add_opt (dc_, MIX_DUMP_rA); + break; + case 'X': + mix_dump_context_add_opt (dc_, MIX_DUMP_rX); + break; + case 'J': + mix_dump_context_add_opt (dc_, MIX_DUMP_rJ); + break; + case 'I': + { + if ( strlen (arg) == 1 ) + mix_dump_context_add_opt (dc_, MIX_DUMP_rIa); + else + { + static gint32 opt[] = { MIX_DUMP_rI1, MIX_DUMP_rI2, + MIX_DUMP_rI3, MIX_DUMP_rI4, + MIX_DUMP_rI5, MIX_DUMP_rI6 + }; + int i = arg[1] - '1'; + if ( i < 0 || i > 5 ) + { + fprintf (stderr, _("Invalid I index: %d"), i); + return TRUE; + } + mix_dump_context_add_opt (dc_, opt[i]); + } + } + break; + default: + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return TRUE; + } + mix_vm_dump (vm_, dc_); + return TRUE; +} + +static int +cmd_pflags_ (char *arg) +{ + mix_dump_context_set_opt (dc_, MIX_DUMP_CMP | MIX_DUMP_OVER); + mix_vm_dump (vm_, dc_); + return TRUE; +} + +static int +cmd_pall_ (char *arg) +{ + mix_dump_context_set_opt (dc_, MIX_DUMP_ALL_NOMEM); + mix_vm_dump (vm_, dc_); + return TRUE; +} + +static int +cmd_pmem_ (char *arg) +{ + glong begin = MIX_SHORT_ZERO, end = MIX_SHORT_ZERO; + int i = 0; + gboolean error = FALSE; + + if ( strlen (arg) == 0 ) + { + fputs (_("Missing memory address\n"), stderr); + return TRUE; + } + while (isdigit (arg[i])) + i++; + while (isspace (arg[i])) + i++; + if (arg[i] == '\0') + begin = end = atol (arg); + else if (arg[i] == '-') + { + arg[i++] = '\0'; + begin = atol (arg); + arg = arg + i; + i = 0; + while (isdigit (arg[i])) + i++; + while (isspace (arg[i])) + i++; + if (arg[i] != '\0') + error = TRUE; + else + end = atol (arg); + } + else + error = TRUE; + + if (error) + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_("pmem"); + } + if ( end < begin || end > MIX_VM_CELL_NO - 1 ) + { + fprintf (stderr, _("Invalid range: %ld-%ld\n"), begin, end); + return TRUE; + } + + mix_dump_context_set_opt (dc_, MIX_DUMP_CELLS); + mix_dump_context_range (dc_, mix_short_new (begin), mix_short_new (end + 1)); + mix_vm_dump (vm_, dc_); + + return TRUE; +} + +static int +cmd_sreg_ (char *arg) +{ + int i = 0; + char reg = arg[0]; + gboolean ok = TRUE; + long value; + + i = (reg == 'I') ? 2 : 1; + ok = strlen (arg) > 2 && isspace (arg[i]); + if (ok) + { + while (isspace (arg[i])) i++; + ok = isdigit (arg[i]) || arg[i] == '+' || arg[i] == '-'; + if (ok) + { + value = atol (arg + i); + if (arg[i] == '+' || arg[i] == '-') i++; + while (isdigit (arg[i])) i++; + ok = (arg[i] == '\0'); + if (ok) + switch (reg) + { + case 'A': + mix_vm_set_rA (vm_, mix_word_new (value)); + break; + case 'X': + mix_vm_set_rX (vm_, mix_word_new (value)); + break; + case 'J': + if ( value >= 0 ) + mix_vm_set_rJ (vm_, mix_short_new (value)); + else + ok = FALSE; + break; + case 'I': + { + guint k = arg[1] - '0'; + if ( k < 7 ) + mix_vm_set_rI (vm_, k, mix_short_new (value)); + else + ok = FALSE; + } + break; + default: + ok = FALSE; + } + } + } + if (!ok) + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + cmd_help_ ("sreg"); + } + + return TRUE; +} + +static int +cmd_scmp_ (char *arg) +{ + gboolean ok = (strlen (arg) == 1); + if (ok) switch (arg[0]) + { + case 'L': + mix_vm_set_cmpflag (vm_, mix_LESS); + break; + case 'E': + mix_vm_set_cmpflag (vm_, mix_EQ); + break; + case 'G': + mix_vm_set_cmpflag (vm_, mix_GREAT); + break; + default: + ok = FALSE; + } + if (!ok) + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + cmd_help_ ("scmp"); + } + + return TRUE; +} + +static int +cmd_sover_ (char *arg) +{ + gboolean ok = (strlen (arg) == 1); + if (ok) switch (arg[0]) + { + case 'T': + mix_vm_set_overflow (vm_, TRUE); + break; + case 'F': + mix_vm_set_overflow (vm_, FALSE); + break; + default: + ok = FALSE; + } + if (!ok) + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + cmd_help_ ("sover"); + } + + return TRUE; +} + +static int +cmd_smem_ (char *arg) +{ + gboolean ok = (strlen (arg) > 2 && isdigit (arg[0])); + gulong addr; + glong value; + int k = 0; + + if (ok) + { + while (isdigit (arg[k])) k++; + ok = isspace (arg[k]); + if (ok) + { + arg[k++] = '\0'; + addr = atol (arg); + ok = addr < MIX_VM_CELL_NO; + } + if (ok) + { + while (isspace (arg[k])) k++; + value = atol (arg + k); + if ( arg[k] == '+' || arg[k] == '-' ) k++; + while (isdigit (arg[k])) k++; + ok = arg[k] == '\0'; + } + } + + if (ok) + mix_vm_set_addr_contents (vm_, mix_short_new (addr), mix_word_new (value)); + else + { + fprintf (stderr, "Invalid argument: %s\n", arg); + cmd_help_ ("smem"); + } + + return TRUE; +} + +static int +cmd_sbp_ (char *arg) +{ + glong lineno; + glong k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_ ("sbp"); + } + lineno = atol (arg); + switch (k = mix_vm_set_breakpoint (vm_, lineno)) + { + case MIX_VM_BP_INV_LINE: + fprintf (stderr, _("Line number %ld too high\n"), lineno); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not set breakpoint. Internal error\n"), stderr); + break; + case MIX_VM_BP_NDEBUG: + fputs (_("Could not set breakpoint. No debug info available\n"), stderr); + break; + default: + fprintf (stderr, _("Breakpoint set at line %ld\n"), k); + break; + } + return TRUE; +} + +static int +cmd_sbpa_ (char *arg) +{ + glong address; + glong k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_ ("sbpa"); + } + address = atol (arg); + switch (mix_vm_set_breakpoint_address (vm_, address)) + { + case MIX_VM_BP_INV_ADDRESS: + fprintf (stderr, _("Invalid address %ld\n"), address); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not set breakpoint. Internal error\n"), stderr); + break; + default: + fprintf (stderr, _("Breakpoint set at address %ld\n"), address); + break; + } + return TRUE; +} + +static int +cmd_cbp_ (char *arg) +{ + glong lineno; + int k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_ ("cbp"); + } + lineno = atol (arg); + switch (mix_vm_clear_breakpoint (vm_, lineno)) + { + case MIX_VM_BP_INV_LINE: + fprintf (stderr, _("No breakpoint set at line %ld\n"), lineno); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not set breakpoint. Internal error\n"), stderr); + break; + case MIX_VM_BP_NDEBUG: + fputs (_("No debug info available\n"), stderr); + break; + case MIX_VM_BP_OK: + fprintf (stderr, _("Breakpoint cleared at line %ld\n"), lineno); + break; + default: + g_assert_not_reached (); + break; + } + return TRUE; +} + +static int +cmd_cbpa_ (char *arg) +{ + glong address; + glong k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_ ("cbpa"); + } + address = atol (arg); + switch (mix_vm_clear_breakpoint_address (vm_, address)) + { + case MIX_VM_BP_INV_ADDRESS: + fprintf (stderr, _("Invalid address %ld\n"), address); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not clear breakpoint. Internal error\n"), stderr); + break; + default: + fprintf (stderr, _("Breakpoint cleared at address %ld\n"), address); + break; + } + return TRUE; +} + + +static int +cmd_cabp_ (char *arg) +{ + if (strlen (arg) != 0) + { + fprintf (stderr, _("Invalid argument: %s\n"), arg); + return cmd_help_ ("cabp"); + } + mix_vm_clear_all_breakpoints (vm_); + return TRUE; +} + +static int +cmd_shell_ (char *arg) +{ + system (arg); + return TRUE; +} + +static int +cmd_compile_ (char *arg) +{ + gchar *line; + + if ( strlen (arg) == 0 ) + return cmd_help_ ("compile"); + + line = g_strconcat ("mixasm -g ", arg, NULL); + if ( system (line) == EXIT_SUCCESS ) + fputs (_("Successful compilation\n"), stderr); + g_free (line); + + return TRUE; +} + +static int +cmd_edit_ (char *arg) +{ + static const gchar * envars[] = { "MDK_EDITOR", "X_EDITOR", "EDITOR", + "VISUAL" + }; + static const guint s = sizeof (envars) / sizeof (envars[0]); + static const gchar *editor = NULL; + + if ( strlen (arg) == 0 ) + return cmd_help_ ("edit"); + + if (!editor) + { + int k; + for (k = 0; k < s; k++) + if ( (editor = getenv (envars[k])) != NULL ) break; + } + if (!editor) + { + int k; + fputs ("Cannot find editor (", stderr); + for (k = 0; k < s; k++) + fprintf (stderr, "%s ", envars[k]); + fputs ("undefined)\n", stderr); + } + else + { + gchar *line = g_strconcat (editor, " ", arg, NULL); + system (line); + g_free (line); + } + + return TRUE; +} + + +/* external interface */ +void +mixvm_cmd_init (char *arg) +{ + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = (CPPFunction *)mixvm_cmd_completion_; + /* initialise the vm */ + vm_ = mix_vm_new (); + dc_ = mix_dump_context_new (MIX_DUMP_DEF_CHANNEL, + MIX_SHORT_ZERO, MIX_SHORT_ZERO, + MIX_DUMP_ALL); + if ( vm_ == NULL || dc_ == NULL ) + g_error (_("Failed initialisation (no memory resources)")); + if (arg) + cmd_load_ (arg); +} + +gboolean +mixvm_cmd_exec (char *line) +{ + int i; + COMMAND *command; + char *word; + + if (!line) return cmd_quit_(NULL); + + /* strip white space */ + line = g_strstrip(line); + + /* Isolate the command word. */ + i = 0; + while (line[i] && isspace (line[i])) + i++; + word = line + i; + + while (line[i] && !isspace (line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + command = find_command_ (word); + + if (!command) + { + fprintf (stderr, _("%s: No such command. Try \'help\'\n"), word); + return TRUE; + } + + /* Get argument to command, if any. */ + while (isspace (line[i])) + i++; + + word = line + i; + + /* Call the function. */ + return ((*(command->func)) (word)); +} + + diff --git a/mixutils/mixvm_command.h b/mixutils/mixvm_command.h new file mode 100644 index 0000000..663aa41 --- /dev/null +++ b/mixutils/mixvm_command.h @@ -0,0 +1,38 @@ +/* -*-c-*- ---------------- mixvm_command.h : + * Declarations for commands accepted by the mix virtual machine + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + +#ifndef MIXVM_COMMAND_H +#define MIXVM_COMMAND_H + +#include <glib.h> + +extern void +mixvm_cmd_init (char *arg); + +extern gboolean +mixvm_cmd_exec (char *line); + + + + +#endif /* MIXVM_COMMAND_H */ + diff --git a/mixutils/mixvm_loop.c b/mixutils/mixvm_loop.c new file mode 100644 index 0000000..309c492 --- /dev/null +++ b/mixutils/mixvm_loop.c @@ -0,0 +1,66 @@ +/* -*-c-*- -------------- mixvm_loop.c : + * Implementation of mix vm command loop. + * ------------------------------------------------------------------ + * Copyright (C) 2000 jose antonio ortega ruiz <jaortega@acm.org> + * + * 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. + * + */ + + + +#include <mixlib/mix.h> +#include <stdio.h> +#include <readline/readline.h> +#include <readline/history.h> +#include "mixvm_command.h" + +/* A static variable for holding the line. */ +static char *line_read = (char *)NULL; +static const char *PROMPT = N_("MIX > "); + +/* Read a string, and return a pointer to it. Returns NULL on EOF. */ +static char * +rl_gets () +{ + /* If the buffer has already been allocated, return the memory + to the free pool. */ + if (line_read) + { + g_free (line_read); + line_read = (char *)NULL; + } + + /* Get a line from the user. */ + line_read = readline ((char *)PROMPT); + + /* If the line has any text in it, save it on the history. */ + if (line_read && *line_read) + add_history (line_read); + + return (line_read); +} + + +/* The main command loop of the virtual machine */ +void +mix_vmloop (const gchar *file) +{ + mixvm_cmd_init ((char *)file); + while ( mixvm_cmd_exec (rl_gets ()) ) + ; +} + + diff --git a/po/.cvsignore b/po/.cvsignore new file mode 100644 index 0000000..c697044 --- /dev/null +++ b/po/.cvsignore @@ -0,0 +1,7 @@ +Makefile +Makefile.in +POTFILES +ca.gmo +cat-id-tbl.c +mdk.pot +stamp-cat-id diff --git a/po/ChangeLog b/po/ChangeLog new file mode 100644 index 0000000..7af10c3 --- /dev/null +++ b/po/ChangeLog @@ -0,0 +1,3 @@ +2000-02-08 jose antonio ortega ruiz <jaortega@retemail.es> + + * ca.po: New file diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..8087956 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1,10 @@ +# List of source files containing translatable strings. +# Package source files +mixutils/mixasm.c +mixutils/mixasm_comp.c +mixutils/mixvm.c +mixutils/mixvm_command.c + +mixlib/mix_parser.c +mixlib/mix_vm_dump.c + diff --git a/po/ca.po b/po/ca.po new file mode 100644 index 0000000..32631da --- /dev/null +++ b/po/ca.po @@ -0,0 +1,506 @@ +# file ca.po Catalan MIX translation +# Copyright (C) 2000 jose antonio ortega ruiz <jaortega@retemail.es> +# +msgid "" +msgstr "" +"Project-Id-Version: mdk 0.1\n" +"POT-Creation-Date: 2000-10-23 00:07+0200\n" +"PO-Revision-Date: 2000-02-28 01:37+01:00\n" +"Last-Translator: jose antonio ortega ruiz <jaortega@retemail.es>\n" +"Language-Team: jose antonio ortega ruiz <jaortega@retemail.es>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=iso-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +#: mixutils/mixasm.c:52 +#, c-format +msgid "" +"Usage: %s [-vhulg] [-o OUTPUT_FILE] [--version] [--help]\n" +"\t[--usage] [--debug] [--output=OUTPUT_FILE] [--list[=LIST_FILE]] file\n" +msgstr "" +"Ús: %s [-vhulg] [-o FIXTER_SORTIDA] [--version] [--help]\n" +" [--usage] [--debug] [--output=FITXER_SORTIDA] [--list[=FITXER_LLISTAT]] " +"FITXER\n" + +#: mixutils/mixasm.c:82 +#, c-format +msgid "%s %s, MIX compiler.\n" +msgstr "%s %s, Compilador de MIX.\n" + +#. getopt already handles the output of a warning message +#: mixutils/mixasm.c:97 mixutils/mixvm.c:102 +#, c-format +msgid "(Try: %s -h)\n" +msgstr "(Proveu: %s -h)\n" + +#: mixutils/mixasm.c:106 +msgid "*** Error: Missing source file.\n" +msgstr "*** Error: Fitxer font no trobat.\n" + +#: mixutils/mixasm.c:111 mixutils/mixvm.c:111 +msgid "*** Error: Too many input files.\n" +msgstr "*** Error: Només es pot indicar un fitxer font.\n" + +#: mixutils/mixasm_comp.c:38 +#, c-format +msgid "*** Unable to open source file %s\n" +msgstr "*** Error obrint el fitxer font %s\n" + +#: mixutils/mixasm_comp.c:45 +#, c-format +msgid "(%d warning(s))\n" +msgstr "(%d advertències)\n" + +#: mixutils/mixasm_comp.c:48 +#, c-format +msgid "*** Error writing output code file: %s\n" +msgstr "*** Error obrint el fitxer de codi de sortida: %s\n" + +#: mixutils/mixasm_comp.c:56 +#, c-format +msgid "*** Error writing listing file: %s\n" +msgstr "*** Error obrint el fitxer de llistat: %s\n" + +#: mixutils/mixasm_comp.c:63 +#, c-format +msgid "(%d warning(s), %d error(s))\n" +msgstr "(%d advertències, %d errors)\n" + +#: mixutils/mixvm.c:59 +#, fuzzy, c-format +msgid "" +"Usage: %s [-vhurd] [--version] [--help] [--usage] [--run] [--dump] " +"[MIX_FILE]\n" +msgstr "Ús: %s [-vhu] [--version] [--help] [--usage] [FITXER_CODI]\n" + +#: mixutils/mixvm.c:89 +#, c-format +msgid "%s %s, MIX Virtual Machine.\n" +msgstr "%s %s, Màquina virtual de MIX.\n" + +#: mixutils/mixvm.c:134 +#, fuzzy, c-format +msgid "Error loading %s file\n" +msgstr "*** Error: Fitxer font no trobat.\n" + +#: mixutils/mixvm_command.c:74 +msgid "Display this text" +msgstr "Aquest text" + +#: mixutils/mixvm_command.c:75 +msgid "Synonym for `help'" +msgstr "Sinònim de help" + +#: mixutils/mixvm_command.c:76 +msgid "Execute shell command" +msgstr "Executar comanda de shell" + +#: mixutils/mixvm_command.c:77 +msgid "Load a MIX code file" +msgstr "Carregar en memòria un fitxer compilat" + +#: mixutils/mixvm_command.c:78 +msgid "Run loaded or given MIX code file" +msgstr "Executar un fitxer de codi ja carregat o un donat" + +#: mixutils/mixvm_command.c:80 +msgid "Execute next instruction(s)" +msgstr "Executar la següent instrucció" + +#: mixutils/mixvm_command.c:82 +msgid "Print program counter value" +msgstr "Mostrar el valor actual del contador de programa" + +#: mixutils/mixvm_command.c:83 +msgid "Print symbol value" +msgstr "Mostrar el valor d'un símbol donat" + +#: mixutils/mixvm_command.c:84 +msgid "Print register value" +msgstr "Mostrar el valor d'un registre" + +#: mixutils/mixvm_command.c:86 +msgid "Print comparison and overflow flags" +msgstr "Mostrar el valor dels flags de comparació i overflow" + +#: mixutils/mixvm_command.c:88 +msgid "Print all registers and flags" +msgstr "Mostrar els valors de tots els registres i flags" + +#: mixutils/mixvm_command.c:89 +msgid "Print memory contents in address range" +msgstr "Mostrar el contingut de la memòria en un rang d'adreces" + +#: mixutils/mixvm_command.c:91 +msgid "Set register value" +msgstr "Donar un valor a un registre" + +#: mixutils/mixvm_command.c:93 +msgid "Set comparison flag value" +msgstr "Donar un valor al flag de comparació" + +#: mixutils/mixvm_command.c:94 +msgid "Set overflow flag value" +msgstr "Donar un valor al flag d'overflow" + +#: mixutils/mixvm_command.c:95 +msgid "Set memory contents in given address" +msgstr "Donar un valor al contingut d'una adreça de memòria" + +#: mixutils/mixvm_command.c:97 +msgid "Set break point at given line" +msgstr "Establir un punt de ruptura" + +#: mixutils/mixvm_command.c:98 +msgid "Clear break point at given line" +msgstr "Esborrar un punt de ruptura" + +#: mixutils/mixvm_command.c:99 +#, fuzzy +msgid "Set break point at given address" +msgstr "Establir un punt de ruptura" + +#: mixutils/mixvm_command.c:101 +#, fuzzy +msgid "Clear break point at given address" +msgstr "Esborrar un punt de ruptura" + +#: mixutils/mixvm_command.c:103 +msgid "Clear all breakpoints" +msgstr "Esborrar tots els punts de ruptura" + +#: mixutils/mixvm_command.c:104 +msgid "Compile a source file" +msgstr "Compilar un fitxer font" + +#: mixutils/mixvm_command.c:105 +msgid "Edit a source file" +msgstr "Editar un fitxer font" + +#: mixutils/mixvm_command.c:106 +msgid "Quit the program" +msgstr "Sortir" + +#: mixutils/mixvm_command.c:199 +#, c-format +msgid "%s\t\t%s. Usage: %s\n" +msgstr "%s %s. Ús: %s\n" + +#: mixutils/mixvm_command.c:207 +#, c-format +msgid "No commands match `%s'. Possibilities are:\n" +msgstr "Cap comanda amb nom %s. Les possibilitats són:\n" + +#: mixutils/mixvm_command.c:232 +msgid "Missing file name\n" +msgstr "Especifiqueu nom de fitxer\n" + +#: mixutils/mixvm_command.c:235 +#, c-format +msgid "Cannot load %s: " +msgstr "No es pot carregar %s: " + +#: mixutils/mixvm_command.c:237 +msgid "Wrong file format\n" +msgstr "El fitxer no té un format correcte\n" + +#: mixutils/mixvm_command.c:242 +#, c-format +msgid "Program loaded. Start address: %d\n" +msgstr "Programa carregat. Adreça d'inici: %d\n" + +#: mixutils/mixvm_command.c:253 +msgid "Running ..." +msgstr "Executant programa ..." + +#: mixutils/mixvm_command.c:257 +msgid "... done" +msgstr "... fet" + +#: mixutils/mixvm_command.c:263 +#, c-format +msgid "... stopped: breakpoint at line %ld (address %d)\n" +msgstr "... interromput: put de ruptura a la línia %ld (adreça %d)\n" + +#: mixutils/mixvm_command.c:266 +#, fuzzy, c-format +msgid "... stopped: breakpoint at address %d\n" +msgstr "... interromput: put de ruptura a la línia %ld (adreça %d)\n" + +#: mixutils/mixvm_command.c:271 +msgid "... error executing loaded file" +msgstr "... error executant el fitxer carregat" + +#: mixutils/mixvm_command.c:291 mixutils/mixvm_command.c:393 +#: mixutils/mixvm_command.c:454 mixutils/mixvm_command.c:521 +#: mixutils/mixvm_command.c:548 mixutils/mixvm_command.c:572 +#: mixutils/mixvm_command.c:626 mixutils/mixvm_command.c:656 +#: mixutils/mixvm_command.c:683 mixutils/mixvm_command.c:716 +#: mixutils/mixvm_command.c:741 +#, c-format +msgid "Invalid argument: %s\n" +msgstr "Argument no vàlid: %s\n" + +#: mixutils/mixvm_command.c:302 +#, c-format +msgid "End of program reached at address %d\n" +msgstr "Fi del programa a l'adreça %d\n" + +#: mixutils/mixvm_command.c:308 +#, c-format +msgid "Error at address %d\n" +msgstr "Error a l'adreça: %d\n" + +#: mixutils/mixvm_command.c:338 +msgid "Symbol table not available\n" +msgstr "Taula de símbols no disponible\n" + +#: mixutils/mixvm_command.c:347 +#, c-format +msgid "%s: symbol not defined\n" +msgstr "El símbol %s no està definit\n" + +#: mixutils/mixvm_command.c:385 +#, c-format +msgid "Invalid I index: %d" +msgstr "Camp d'índex %d no vàlid" + +#: mixutils/mixvm_command.c:425 +msgid "Missing memory address\n" +msgstr "Especifiqueu l'adreça de memòria\n" + +#: mixutils/mixvm_command.c:459 +#, c-format +msgid "Invalid range: %ld-%ld\n" +msgstr "Rang %ld-%ld no vàlid\n" + +#: mixutils/mixvm_command.c:633 +#, c-format +msgid "Line number %ld too high\n" +msgstr "Número de línia %ld massa alt\n" + +#: mixutils/mixvm_command.c:636 mixutils/mixvm_command.c:666 +#: mixutils/mixvm_command.c:693 +msgid "Could not set breakpoint. Internal error\n" +msgstr "Error intern intentant establir un punt de ruptura\n" + +#: mixutils/mixvm_command.c:639 +msgid "Could not set breakpoint. No debug info available\n" +msgstr "No es pot establir el punt de ruptura. No hi ha informació de debug\n" + +#: mixutils/mixvm_command.c:642 +#, c-format +msgid "Breakpoint set at line %ld\n" +msgstr "Punt de ruptura a la línia %ld establert\n" + +#: mixutils/mixvm_command.c:663 mixutils/mixvm_command.c:723 +#, fuzzy, c-format +msgid "Invalid address %ld\n" +msgstr "camp d'adreça no vàlid" + +#: mixutils/mixvm_command.c:669 +#, fuzzy, c-format +msgid "Breakpoint set at address %ld\n" +msgstr "Punt de ruptura a la línia %ld establert\n" + +#: mixutils/mixvm_command.c:690 +#, c-format +msgid "No breakpoint set at line %ld\n" +msgstr "No hi havia cap punt de ruptura a la línia %ld\n" + +#: mixutils/mixvm_command.c:696 +msgid "No debug info available\n" +msgstr "No hi ha informació de debug disponible\n" + +#: mixutils/mixvm_command.c:699 +#, c-format +msgid "Breakpoint cleared at line %ld\n" +msgstr "Punt de ruptura esborrat a la línia %ld\n" + +#: mixutils/mixvm_command.c:726 +#, fuzzy +msgid "Could not clear breakpoint. Internal error\n" +msgstr "Error intern intentant establir un punt de ruptura\n" + +#: mixutils/mixvm_command.c:729 +#, fuzzy, c-format +msgid "Breakpoint cleared at address %ld\n" +msgstr "Punt de ruptura esborrat a la línia %ld\n" + +#: mixutils/mixvm_command.c:765 +msgid "Successful compilation\n" +msgstr "La compilació s'ha completat amb éxit\n" + +#: mixutils/mixvm_command.c:820 +msgid "Failed initialisation (no memory resources)" +msgstr "Error inicialitzant programa (no hi ha memòria)" + +#: mixutils/mixvm_command.c:853 +#, c-format +msgid "%s: No such command. Try 'help'\n" +msgstr "La comanda %s no existeix. Proveu 'help'\n" + +#: mixlib/mix_parser.c:35 +msgid "successful compilation" +msgstr "La compilació s'ha completat amb éxit" + +#: mixlib/mix_parser.c:36 +msgid "file not yet compiled" +msgstr "el fitxer encara no està compilat" + +#: mixlib/mix_parser.c:37 +msgid "internal error" +msgstr "error intern" + +#: mixlib/mix_parser.c:38 +msgid "unable to open MIX source file" +msgstr "no s'ha pogut obrir el fitxer font" + +#: mixlib/mix_parser.c:39 +msgid "unable to open MIX output file" +msgstr "no s'ha pogut obrir el fitxer per a escritura" + +#: mixlib/mix_parser.c:40 +msgid "unexpected end of file" +msgstr "fi de fitxer inesperat" + +#: mixlib/mix_parser.c:41 +msgid "invalid location field" +msgstr "invalid camp 'location'" + +#: mixlib/mix_parser.c:42 +msgid "duplicated symbol" +msgstr "símbol duplicat" + +#: mixlib/mix_parser.c:43 +msgid "symbol too long" +msgstr "símbol massa llarg" + +#: mixlib/mix_parser.c:44 +msgid "missing operator field" +msgstr "falta l'indicador d'operació" + +#: mixlib/mix_parser.c:45 +msgid "unexpected location symbol" +msgstr "símbol local inesperat" + +#: mixlib/mix_parser.c:46 +msgid "invalid address field" +msgstr "camp d'adreça no vàlid" + +#: mixlib/mix_parser.c:47 +msgid "invalid index field" +msgstr "camp d'índex no vàlid" + +#: mixlib/mix_parser.c:48 +msgid "invalid f-specification" +msgstr "especificació de camp ('f-spec') no vàlida" + +#: mixlib/mix_parser.c:49 +msgid "invalid operation field" +msgstr "camp d'operació no vàlid" + +#: mixlib/mix_parser.c:50 +msgid "invalid expression" +msgstr "expressió errònia" + +#: mixlib/mix_parser.c:51 +msgid "undefined symbol" +msgstr "símbol no definit" + +#: mixlib/mix_parser.c:52 +msgid "mismatched parenthesis" +msgstr "paréntesi sense tancar" + +#: mixlib/mix_parser.c:53 +msgid "unexpected f-specfication" +msgstr "especificació de camp ('f-spec') inesperada" + +#: mixlib/mix_parser.c:54 +msgid "missing symbol name" +msgstr "nom del símbol absent" + +#: mixlib/mix_parser.c:55 +msgid "symbol is an instruction name" +msgstr "el nom de símbol coincideix amb un nom d'operació" + +#: mixlib/mix_parser.c:56 +msgid "failed write access to code file" +msgstr "error mentre s'escrivia el fitxer de codi" + +#: mixlib/mix_parser.c:57 +msgid "operand of ALF pseudo instruction has less than 5 chars" +msgstr "" + +#: mixlib/mix_parser.c:58 +msgid "operand of ALF pseudo instruction has more than 5 chars" +msgstr "" + +#: mixlib/mix_parser.c:121 mixlib/mix_parser.c:139 +msgid "No system resources" +msgstr "no hi ha recursos al sistema" + +#: mixlib/mix_parser.c:324 +#, c-format +msgid "\t%s\t(line %d)\n" +msgstr " %s (línia %d)\n" + +#: mixlib/mix_parser.c:343 +#, c-format +msgid "" +"*** %s%s: compilation summary ***\n" +"\n" +msgstr "" +"*** %s%s: resum de la compilació\n" +"\n" + +#: mixlib/mix_parser.c:346 +msgid "*** Address / Compiled word / Symbolic rep / Source file line\n" +msgstr "*** Adreça / Paraula compilada / Repr. simbólica / Núm. línia\n" + +#: mixlib/mix_parser.c:350 +#, c-format +msgid "" +"\n" +"*** Start address: %d\n" +msgstr "" +"\n" +"*** Adreça d'inici: %d\n" + +#: mixlib/mix_parser.c:352 +msgid "" +"\n" +"*** Symbol table\n" +msgstr "" +"\n" +"*** Taula de símbols\n" + +#: mixlib/mix_parser.c:354 +msgid "" +"\n" +"*** End of summary ***\n" +msgstr "" +"\n" +"*** Fi del resum ***\n" + +#: mixlib/mix_parser.c:484 +msgid "Unable to allocate memory" +msgstr "Memòria dinàmica insuficient" + +#: mixlib/mix_parser.c:512 +msgid "warning" +msgstr "advertència" + +#: mixlib/mix_parser.c:512 +msgid "error" +msgstr "error" + +#: mixlib/mix_vm_dump.c:155 +#, c-format +msgid "Overflow: %s\n" +msgstr "Overflow: %s\n" + +#: mixlib/mix_vm_dump.c:179 +#, c-format +msgid "Cmp: %s\n" +msgstr "Cmp: %s\n" diff --git a/samples/.cvsignore b/samples/.cvsignore new file mode 100644 index 0000000..4e88a5a --- /dev/null +++ b/samples/.cvsignore @@ -0,0 +1,25 @@ +Makefile +Makefile.in +cardwr.dev +disk0.dev +disk1.dev +disk2.dev +disk3.dev +disk4.dev +disk5.dev +disk6.dev +disk7.dev +hello.mix +hello.mls +paper.dev +primes.mix +primes.mls +printer.dev +tape0.dev +tape1.dev +tape2.dev +tape3.dev +tape4.dev +tape5.dev +tape6.dev +tape7.dev diff --git a/samples/Makefile.am b/samples/Makefile.am new file mode 100644 index 0000000..64b7e09 --- /dev/null +++ b/samples/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Jose Antonio Ortega Ruiz <jaortega@retemail.es> +# +# This file is free software; as a special exception the author gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +EXTRA_DIST =*.mix + diff --git a/samples/hello.mixal b/samples/hello.mixal new file mode 100644 index 0000000..6a4c3c1 --- /dev/null +++ b/samples/hello.mixal @@ -0,0 +1,11 @@ +* mixal hello world +* +TERM EQU 19 + ORIG 3000 +START OUT MSG(TERM) + HLT +MSG ALF "MIXAL" + ALF " HELL" + ALF "O WOR" + ALF "LD " + END START diff --git a/samples/primes.mixal b/samples/primes.mixal new file mode 100644 index 0000000..d2de8c0 --- /dev/null +++ b/samples/primes.mixal @@ -0,0 +1,53 @@ +* table of primes (taopc p. 148) +* +L EQU 500 +OUTDEV EQU 20 the paper tape +PRIME EQU -1 +BUF0 EQU 2000 +BUF1 EQU BUF0+25 + ORIG 3000 +START IOC 0(OUTDEV) + LD1 =1-L= + LD2 =3= +2H INC1 1 + ST2 PRIME+L,1 + J1Z 2F +4H INC2 2 + ENT3 2 +6H ENTA 0 + ENTX 0,2 + DIV PRIME,3 + JXZ 4B + CMPA PRIME,3 + INC3 1 + JG 6B + JMP 2B +2H OUT TITLE(OUTDEV) + ENT4 BUF1+10 + ENT5 -50 +2H INC5 L+1 +4H LDA PRIME,5 + CHAR + STX 0,4(1:4) + DEC4 1 + DEC5 50 + J5P 4B + OUT 0,4(OUTDEV) + LD4 24,4 + J5N 2B + HLT +* initial contents + ORIG PRIME+1 + CON 2 + ORIG BUF0-5 +TITLE ALF "FIRST" + ALF " FIVE" + ALF " HUND" + ALF "RED P" + ALF "RIMES" + ORIG BUF0+24 + CON BUF1+10 + ORIG BUF1+24 + CON BUF0+10 + END START + |