From 1c345e559710ec6200f7d508629bd24457a20a80 Mon Sep 17 00:00:00 2001 From: Jose Antonio Ortega Ruiz Date: Thu, 22 Mar 2001 03:01:01 +0000 Subject: initial import (sf 0.3beta) --- .cvsignore | 18 + AUTHORS | 6 + COPYING | 339 ++++++++ ChangeLog | 0 INSTALL | 309 +++++++ Makefile.am | 20 + NEWS | 69 ++ README | 44 + THANKS | 22 + TODO | 9 + acconfig.h | 10 + aclocal.m4 | 1082 +++++++++++++++++++++++++ autogen.sh | 91 +++ configure.in | 118 +++ doc/.cvsignore | 12 + doc/Makefile.am | 28 + doc/gpl.texi | 400 +++++++++ doc/mdk.texi | 213 +++++ doc/mdk_bugs.texi | 16 + doc/mdk_emixvm.texi | 25 + doc/mdk_gmixvm.texi | 118 +++ doc/mdk_gstart.texi | 433 ++++++++++ doc/mdk_index.texi | 10 + doc/mdk_install.texi | 180 +++++ doc/mdk_intro.texi | 48 ++ doc/mdk_mixasm.texi | 79 ++ doc/mdk_mixvm.texi | 478 +++++++++++ doc/mdk_tut.texi | 1259 +++++++++++++++++++++++++++++ doc/ss_devices.png | Bin 0 -> 16621 bytes doc/ss_mix.png | Bin 0 -> 12642 bytes doc/ss_mix.txt | 31 + doc/ss_mixal.png | Bin 0 -> 14536 bytes doc/ss_worddlg.png | Bin 0 -> 15050 bytes misc/.cvsignore | 2 + misc/Makefile.am | 14 + misc/mixvm.el | 157 ++++ mixgtk/.cvsignore | 7 + mixgtk/Makefile.am | 31 + mixgtk/mixgtk.c | 91 +++ mixgtk/mixgtk.glade | 1703 +++++++++++++++++++++++++++++++++++++++ mixgtk/mixgtk_cmd_dispatcher.c | 314 ++++++++ mixgtk/mixgtk_cmd_dispatcher.h | 55 ++ mixgtk/mixgtk_device.c | 155 ++++ mixgtk/mixgtk_device.h | 42 + mixgtk/mixgtk_gen_handlers.c | 95 +++ mixgtk/mixgtk_gen_handlers.h | 46 ++ mixgtk/mixgtk_input.c | 189 +++++ mixgtk/mixgtk_input.h | 49 ++ mixgtk/mixgtk_mixal.c | 213 +++++ mixgtk/mixgtk_mixal.h | 60 ++ mixgtk/mixgtk_mixvm.c | 423 ++++++++++ mixgtk/mixgtk_mixvm.h | 84 ++ mixgtk/mixgtk_widgets.c | 112 +++ mixgtk/mixgtk_widgets.h | 80 ++ mixlib/.cvsignore | 7 + mixlib/Makefile.am | 33 + mixlib/mix.c | 63 ++ mixlib/mix.h | 65 ++ mixlib/mix_code_file.c | 326 ++++++++ mixlib/mix_code_file.h | 106 +++ mixlib/mix_device.c | 163 ++++ mixlib/mix_device.h | 151 ++++ mixlib/mix_eval.c | 191 +++++ mixlib/mix_eval.h | 110 +++ mixlib/mix_eval_scanner.l | 265 ++++++ mixlib/mix_file.c | 140 ++++ mixlib/mix_file.h | 61 ++ mixlib/mix_ins.c | 269 +++++++ mixlib/mix_ins.h | 195 +++++ mixlib/mix_io.c | 219 +++++ mixlib/mix_io.h | 123 +++ mixlib/mix_parser.c | 525 ++++++++++++ mixlib/mix_parser.h | 110 +++ mixlib/mix_scanner.l | 532 ++++++++++++ mixlib/mix_src_file.c | 157 ++++ mixlib/mix_src_file.h | 57 ++ mixlib/mix_symbol_table.c | 196 +++++ mixlib/mix_symbol_table.h | 109 +++ mixlib/mix_types.c | 566 +++++++++++++ mixlib/mix_types.h | 291 +++++++ mixlib/mix_vm.c | 562 +++++++++++++ mixlib/mix_vm.h | 204 +++++ mixlib/mix_vm_clock.c | 68 ++ mixlib/mix_vm_clock.h | 55 ++ mixlib/mix_vm_command.c | 1167 +++++++++++++++++++++++++++ mixlib/mix_vm_command.h | 160 ++++ mixlib/mix_vm_dump.c | 147 ++++ mixlib/mix_vm_dump.h | 91 +++ mixlib/testsuite/.cvsignore | 28 + mixlib/testsuite/Makefile.am | 28 + mixlib/testsuite/mix_device_t.c | 76 ++ mixlib/testsuite/mix_eval_t.c | 119 +++ mixlib/testsuite/mix_ins_t.c | 79 ++ mixlib/testsuite/mix_parser_t.c | 85 ++ mixlib/testsuite/mix_types_t.c | 361 +++++++++ mixlib/testsuite/mix_vm_ins_t.c | 500 ++++++++++++ mixlib/testsuite/test.h | 44 + mixlib/xmix_device.c | 131 +++ mixlib/xmix_device.h | 77 ++ mixlib/xmix_eval.h | 55 ++ mixlib/xmix_io.c | 57 ++ mixlib/xmix_io.h | 64 ++ mixlib/xmix_parser.h | 107 +++ mixlib/xmix_vm.c | 567 +++++++++++++ mixlib/xmix_vm.h | 117 +++ mixutils/.cvsignore | 6 + mixutils/Makefile.am | 18 + mixutils/mixasm.c | 126 +++ mixutils/mixasm_comp.c | 72 ++ mixutils/mixasm_comp.h | 35 + mixutils/mixvm.c | 155 ++++ mixutils/mixvm_command.c | 367 +++++++++ mixutils/mixvm_command.h | 35 + mixutils/mixvm_loop.c | 86 ++ po/.cvsignore | 7 + po/ChangeLog | 3 + po/POTFILES.in | 10 + samples/.cvsignore | 36 + samples/Makefile.am | 14 + samples/hello.mixal | 11 + samples/primes.mixal | 54 ++ samples/primes.result | 51 ++ samples/stress1.mixal | 9 + samples/stress2.mixal | 14 + samples/stress4.mixal | 7 + 125 files changed, 20484 insertions(+) create mode 100644 .cvsignore create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 THANKS create mode 100644 TODO create mode 100644 acconfig.h create mode 100644 aclocal.m4 create mode 100755 autogen.sh create mode 100644 configure.in create mode 100644 doc/.cvsignore create mode 100644 doc/Makefile.am create mode 100644 doc/gpl.texi create mode 100644 doc/mdk.texi create mode 100644 doc/mdk_bugs.texi create mode 100644 doc/mdk_emixvm.texi create mode 100644 doc/mdk_gmixvm.texi create mode 100644 doc/mdk_gstart.texi create mode 100644 doc/mdk_index.texi create mode 100644 doc/mdk_install.texi create mode 100644 doc/mdk_intro.texi create mode 100644 doc/mdk_mixasm.texi create mode 100644 doc/mdk_mixvm.texi create mode 100644 doc/mdk_tut.texi create mode 100644 doc/ss_devices.png create mode 100644 doc/ss_mix.png create mode 100644 doc/ss_mix.txt create mode 100644 doc/ss_mixal.png create mode 100644 doc/ss_worddlg.png create mode 100644 misc/.cvsignore create mode 100644 misc/Makefile.am create mode 100644 misc/mixvm.el create mode 100644 mixgtk/.cvsignore create mode 100644 mixgtk/Makefile.am create mode 100644 mixgtk/mixgtk.c create mode 100644 mixgtk/mixgtk.glade create mode 100644 mixgtk/mixgtk_cmd_dispatcher.c create mode 100644 mixgtk/mixgtk_cmd_dispatcher.h create mode 100644 mixgtk/mixgtk_device.c create mode 100644 mixgtk/mixgtk_device.h create mode 100644 mixgtk/mixgtk_gen_handlers.c create mode 100644 mixgtk/mixgtk_gen_handlers.h create mode 100644 mixgtk/mixgtk_input.c create mode 100644 mixgtk/mixgtk_input.h create mode 100644 mixgtk/mixgtk_mixal.c create mode 100644 mixgtk/mixgtk_mixal.h create mode 100644 mixgtk/mixgtk_mixvm.c create mode 100644 mixgtk/mixgtk_mixvm.h create mode 100644 mixgtk/mixgtk_widgets.c create mode 100644 mixgtk/mixgtk_widgets.h create mode 100644 mixlib/.cvsignore create mode 100644 mixlib/Makefile.am create mode 100644 mixlib/mix.c create mode 100644 mixlib/mix.h create mode 100644 mixlib/mix_code_file.c create mode 100644 mixlib/mix_code_file.h create mode 100644 mixlib/mix_device.c create mode 100644 mixlib/mix_device.h create mode 100644 mixlib/mix_eval.c create mode 100644 mixlib/mix_eval.h create mode 100644 mixlib/mix_eval_scanner.l create mode 100644 mixlib/mix_file.c create mode 100644 mixlib/mix_file.h create mode 100644 mixlib/mix_ins.c create mode 100644 mixlib/mix_ins.h create mode 100644 mixlib/mix_io.c create mode 100644 mixlib/mix_io.h create mode 100644 mixlib/mix_parser.c create mode 100644 mixlib/mix_parser.h create mode 100644 mixlib/mix_scanner.l create mode 100644 mixlib/mix_src_file.c create mode 100644 mixlib/mix_src_file.h create mode 100644 mixlib/mix_symbol_table.c create mode 100644 mixlib/mix_symbol_table.h create mode 100644 mixlib/mix_types.c create mode 100644 mixlib/mix_types.h create mode 100644 mixlib/mix_vm.c create mode 100644 mixlib/mix_vm.h create mode 100644 mixlib/mix_vm_clock.c create mode 100644 mixlib/mix_vm_clock.h create mode 100644 mixlib/mix_vm_command.c create mode 100644 mixlib/mix_vm_command.h create mode 100644 mixlib/mix_vm_dump.c create mode 100644 mixlib/mix_vm_dump.h create mode 100644 mixlib/testsuite/.cvsignore create mode 100644 mixlib/testsuite/Makefile.am create mode 100644 mixlib/testsuite/mix_device_t.c create mode 100644 mixlib/testsuite/mix_eval_t.c create mode 100644 mixlib/testsuite/mix_ins_t.c create mode 100644 mixlib/testsuite/mix_parser_t.c create mode 100644 mixlib/testsuite/mix_types_t.c create mode 100644 mixlib/testsuite/mix_vm_ins_t.c create mode 100644 mixlib/testsuite/test.h create mode 100644 mixlib/xmix_device.c create mode 100644 mixlib/xmix_device.h create mode 100644 mixlib/xmix_eval.h create mode 100644 mixlib/xmix_io.c create mode 100644 mixlib/xmix_io.h create mode 100644 mixlib/xmix_parser.h create mode 100644 mixlib/xmix_vm.c create mode 100644 mixlib/xmix_vm.h create mode 100644 mixutils/.cvsignore create mode 100644 mixutils/Makefile.am create mode 100644 mixutils/mixasm.c create mode 100644 mixutils/mixasm_comp.c create mode 100644 mixutils/mixasm_comp.h create mode 100644 mixutils/mixvm.c create mode 100644 mixutils/mixvm_command.c create mode 100644 mixutils/mixvm_command.h create mode 100644 mixutils/mixvm_loop.c create mode 100644 po/.cvsignore create mode 100644 po/ChangeLog create mode 100644 po/POTFILES.in create mode 100644 samples/.cvsignore create mode 100644 samples/Makefile.am create mode 100644 samples/hello.mixal create mode 100644 samples/primes.mixal create mode 100644 samples/primes.result create mode 100644 samples/stress1.mixal create mode 100644 samples/stress2.mixal create mode 100644 samples/stress4.mixal diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..117e735 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,18 @@ +.emacs.desktop +Makefile +Makefile.in +blah +config.cache +config.h +config.h.in +config.log +config.status +configure +intl +mdk-0.1.1.tar.gz +mdk-0.1.tar.gz +mdk-0.2.tar.gz +stamp-h +stamp-h.in +test +mixmvc diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..fadc4e2 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ +Authors of GNU MDK. +See also the files THANKS and ChangeLog. + +Jose A. Ortega Ruiz designed and implemented mdk. + +Philip E. King designed and implemented mixvm.el. \ No newline at end of file diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..a43ea21 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..0e5eb99 --- /dev/null +++ b/INSTALL @@ -0,0 +1,309 @@ +1. Installing MDK + + 1.1 Download the source tarball + 1.2 Requirements + 1.3 Basic installation + 1.4 Emacs support + 1.5 Special configure flags + 1.6 Generic configure help + +1.1 Download the source tarball +------------------------------- + +GNU MDK is distributed as a source tarball available for download in the +following URLs: + + * ftp://ftp.gnu.org/pub/gnu/mdk (or one of its mirrors) + * http://sourceforge.net/project/showfiles.php?group_id=13897 + +The above sites contain the latest stable releases of MDK. The development +branch is available at: + + * http://sourceforge.net/cvs/?group_id=13897 + +After you have downloaded the source tarball, unpack it in a directory of +your choice using the command: + + tar xfvz mdk-X.Y.tar.gz + +where X.Y stands for the downloaded version (the current stable release +being version ). + + +1.2 Requirements +---------------- + +In order to build and install MDK, you will need the following libraries +installed in your system: + + * GLIB 1.2.0 (required) + * GNU Flex 2.3 (required) + * GTK+ 1.2.0 (optional) + * libglade (optional) + * GNU readline and history libraries (optional) + +If present, readline and history are used to provide command completion and +history management to the command line MIX virtual machine, mixvm GTK+ and +libglade are needed if you want to build the graphical interface to the MIX +virtual machine, gmixvm. + +Please note: you need both the libraries and the headers; this means both +the library package and the `-dev' package if you do not compile your +libraries yourself (ex: installing `libgtk1.2' and `libgtk1.2-dev' on +Debian). + + +1.3 Basic installation +---------------------- + +MDK uses GNU Autoconf and Automake tools, and, therefore, should be built +and installed without hassle using the following commands inside the source +directory: + + ./configure + make + make install + +where the last one must be run as root. + +The first command, configure, will setup the makefiles for your system. In +particular, configure will look for GTK+ and libglade, and, if they are +present, will generate the appropiate makefiles for building the gmixvm +graphical user interface. Upon completion, you should see a message with the +configuration results like the following: + + *** GNU MDK 0.3 has been successfully configured. *** + + Type make to build the following utilities: + - mixasm (MIX assembler) + - mixvm (MIX virtual machine, with readline support) + - gmixvm (mixvm GTK+ GUI) + +where the last line may be missing if you lack the above mentioned +libraries. + +The next command, make, will actually build the MDK programs in the +following locations: + + * `mixutils/mixasm' + * `mixutils/mixvm' + * `mixgtk/gmixvm' + +You can run these programs from within their directories, but I recommend +you to install them in proper locations using make install from a root +shell. + +1.4 Emacs support +----------------- + +mixvm can be run within an Emacs GUD buffer using the elisp +program misc/mixvm.el, kindly contributed by Philip King. + +mixvm.el provides an interface between mdk's mixvm +and Emacs, via GUD. Place this file in your load-path, +optionally adding the following line to your .emacs file: + +(autoload 'mixvm "mixvm" "mixvm/gud interaction" t) + + +1.5 Special configure flags +--------------------------- + +You can fine tunning the configuration process using the following switches +with configure: + +User Option: --enable-gui[=yes|no] +User Option: --disable-gui + Enables/disables the built of the MIX virtual machine GUI (gmixvm). If + the required libraries are missing (see section 1.2 Requirements) the + configure script with automatically disable this feature. + +User Option: --with-readline[=yes|no] +User Option: --without-readline + Enables/disables the GNU Readline support for mixvm. If the required + libraries are missing (see section 1.2 Requirements) the configure + script with automatically disable this feature. + + +1.6 Generic configure help +-------------------------- + +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..d216294 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,20 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000, 2001 Free Software Foundation, Inc. +# +# 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 mixgtk misc samples + +docdir = $(top_builddir)/doc + +html: + echo Making html in $(docdir) + cd $(docdir) && make html diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..b3ea3bb --- /dev/null +++ b/NEWS @@ -0,0 +1,69 @@ +GNU MDK -- History of visible changes. + +Copyright (C) 2000, 2001, Free Software Foundation, Inc. +See the end for copying conditions. + +Please send mdk bug reports to jaortega@acm.org. + +*Version 0.2.1 + +** MDK is now an official GNU packaga. + +*Version 0.2 (07/01/01) + +** mixvm provides virtual execution time statistics after each + invocation of run or next. + +** mixvm can trace instructions as they are executed. tron/troff + commands turn off/off instruction tracing. + +** mixvm accepts a new command, w2d, which computes the + decimal value of a MIX word given as a series of + bytes (e.g. - 01 00 34 32 22). + +** symbols can be defined at the mixvm prompt with the + new command ssym. + +** mixvm accepts a new command, weval, which allows the + evaluation of MIXAL w-expressions. + +** expressions containing strings of successive '*' are now + correctly evaluated. + +** When using block devices in mixvm, the buffers are now + flushed after each OUT operation. + +*Version 0.1.1 (18/11/00) + +** MDK is now compilable in rpm-based linuxes. +** MDK fully compliant with Knuth's specification. In particular, + local symbols are now properly handled in special cases such as + 3H ORIG 3B + instructions. See samples/stress{1,2}.mixal. +** Future references affected by unary minus are accepted + with a warning (they are banned in Knuth's specification). + Also future refs in EQU directives are now properly handled. + See samples/stress{3,4}.mixal. +** When mixvm executes a program and reaches the end of the + available memory without encountering a HALT instruction, + it halts anyway. + +*Version 0.1 (31/10/00) + +** Initial version + +------------------------------------------------------- +Copying information: + +Copyright (C) 2000, Free Software Foundation, Inc. + + 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. + diff --git a/README b/README new file mode 100644 index 0000000..af4447e --- /dev/null +++ b/README @@ -0,0 +1,44 @@ +Welcome to GNU MDK. + +GNU MDK is an official GNU package [0]. + +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, which is programmed using +MIXAL, the MIX assembly language. + +MDK includes a MIXAL assembler (mixasm) and a MIX virtual machine +(mixvm) with a command line interface. In addition, a GTK+ GUI to +mixvm, called gmixvm, is provided; and, in case you are an Emacs guy, +you can try misc/mixvm.el, which allows running mixvm inside an Emacs +GUD buffer. + +Using these interfaces, you can debug your MIXAL programs at source +code level, and read/modify the contents of all the components of the +MIX computer (including block devices, which are simultated using the +file system). + + +URLs: + +Project homepage: http://mdk.sourceforge.net +Download: http://download.sourceforge.net/mdk/ + +GNU 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[1]. + +-- +[0] To learn more about GNU, the FSF and its goals, please visit + http://www.gnu.org. + +[1] New translations are welcome. If you'd like to contribute one, + please contact the author, jao@gnu.org. diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..0b46932 --- /dev/null +++ b/THANKS @@ -0,0 +1,22 @@ +GNU MDK THANKS file + +GNU MDK is an official GNU package. +It 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. + +* Richard Stallman kindly suggested various improvements + to the documentation. + +* Philip Ellis King kindly provided MIXAL test programs + pinpointing bugs in the first MDK release, and useful discussions as well. + +* Agustin Navarro kindly tested the installation on + Mandrake and discovered a bug in the configuration process. + +* Vasilij kindly pointed out a bug in JRED. + +* MDK was inspired by Darius Bacon's MIXAL program + which can be installed in Debian 2.3 as the package "mixal". + diff --git a/TODO b/TODO new file mode 100644 index 0000000..ecbd427 --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ +- allow MIXAL instructions as commands at the mixvm prompt + (e.g. MIX > exec LDA 2000) +- improve detection of pseudoinstructions in mixasm listing files + +* 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..240d7b7 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1082 @@ +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>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; 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 +#include +#include +#include +/* 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 , 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 ], [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 in the installed 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 " + else + INCLUDE_LOCALE_H="\ +/* The system does not provide the header . 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 , 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 . +# Ulrich Drepper , 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 ], [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 +#include +#include + +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 +#include +], [ 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 +]) + +# Configure paths for GTK+ +# Owen Taylor 97-11-3 + +dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) +dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS +dnl +AC_DEFUN(AM_PATH_GTK, +[dnl +dnl Get the cflags and libraries from the gtk-config script +dnl +AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], + gtk_config_prefix="$withval", gtk_config_prefix="") +AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], + gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") +AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + + for module in . $4 + do + case "$module" in + gthread) + gtk_config_args="$gtk_config_args gthread" + ;; + esac + done + + if test x$gtk_config_exec_prefix != x ; then + gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config + fi + fi + if test x$gtk_config_prefix != x ; then + gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_prefix/bin/gtk-config + fi + fi + + AC_PATH_PROG(GTK_CONFIG, gtk-config, no) + min_gtk_version=ifelse([$1], ,0.99.7,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + no_gtk="" + if test "$GTK_CONFIG" = "no" ; then + no_gtk=yes + else + GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` + GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` + gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_gtktest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$GTK_LIBS $LIBS" +dnl +dnl Now check if the installed GTK is sufficiently new. (Also sanity +dnl checks the results of gtk-config to some extent +dnl + rm -f conf.gtktest + AC_TRY_RUN([ +#include +#include +#include + +int +main () +{ + int major, minor, micro; + char *tmp_version; + + system ("touch conf.gtktest"); + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = g_strdup("$min_gtk_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + + if ((gtk_major_version != $gtk_config_major_version) || + (gtk_minor_version != $gtk_config_minor_version) || + (gtk_micro_version != $gtk_config_micro_version)) + { + printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", + $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf ("*** was found! If gtk-config was correct, then it is best\n"); + printf ("*** to remove the old version of GTK+. 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 gtk-config was wrong, set the environment variable GTK_CONFIG\n"); + printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } +#if defined (GTK_MAJOR_VERSION) && defined (GTK_MINOR_VERSION) && defined (GTK_MICRO_VERSION) + else if ((gtk_major_version != GTK_MAJOR_VERSION) || + (gtk_minor_version != GTK_MINOR_VERSION) || + (gtk_micro_version != GTK_MICRO_VERSION)) + { + printf("*** GTK+ header files (version %d.%d.%d) do not match\n", + GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); + printf("*** library (version %d.%d.%d)\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + } +#endif /* defined (GTK_MAJOR_VERSION) ... */ + else + { + if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GTK+ 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 gtk-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); + printf("*** correct copy of gtk-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_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_gtk" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$GTK_CONFIG" = "no" ; then + echo "*** The gtk-config script installed by GTK could not be found" + echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GTK_CONFIG environment variable to the" + echo "*** full path to gtk-config." + else + if test -f conf.gtktest ; then + : + else + echo "*** Could not run GTK test program, checking why..." + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GTK or finding the wrong" + echo "*** version of GTK. If it is not finding GTK, 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 GTK was incorrectly installed" + echo "*** or that you have moved GTK since it was installed. In the latter case, you" + echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + rm -f conf.gtktest +]) + +# a macro to get the libs/cflags for libglade +# serial 1 + +dnl AM_PATH_LIBGLADE([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]) +dnl Test to see if libglade is installed, and define LIBGLADE_CFLAGS, LIBS +dnl +AC_DEFUN(AM_PATH_LIBGLADE, +[dnl +dnl Get the cflags and libraries from the libglade-config script +dnl +AC_ARG_WITH(libglade-config, +[ --with-libglade-config=LIBGLADE_CONFIG Location of libglade-config], +LIBGLADE_CONFIG="$withval") + +module_args= +for module in . $3; do + case "$module" in + gnome) + module_args="$module_args gnome" + ;; + bonobo) + module_args="$module_args bonobo" + ;; + gnomedb) + module_args="$module_args gnomedb" + ;; + esac +done + +AC_PATH_PROG(LIBGLADE_CONFIG, libglade-config, no) +AC_MSG_CHECKING(for libglade) +if test "$LIBGLADE_CONFIG" = "no"; then + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) +else + if $LIBGLADE_CONFIG --check $module_args; then + LIBGLADE_CFLAGS=`$LIBGLADE_CONFIG --cflags $module_args` + LIBGLADE_LIBS=`$LIBGLADE_CONFIG --libs $module_args` + AC_MSG_RESULT(yes) + ifelse([$1], , :, [$1]) + else + echo "*** libglade was not compiled with support for $module_args" 1>&2 + AC_MSG_RESULT(no) + ifelse([$2], , :, [$2]) + fi +fi +AC_SUBST(LIBGLADE_CFLAGS) +AC_SUBST(LIBGLADE_LIBS) +]) 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..c27cde4 --- /dev/null +++ b/configure.in @@ -0,0 +1,118 @@ +# Copyright (C) 2000, 2001 Free Software Foundation, Inc. +# +# 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.3) + +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="" +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_ARG_WITH(readline, +[ --with-readline build mixvm with readline support], +[case "${withval}" in + yes) readl=true ;; + no) readl=false ;; + *) AC_MSG_ERROR(bad value ${withval} for --with-readline) ;; +esac], [readl=true]) + +if test x$readl = xtrue; then + AC_CHECK_LIB(ncurses, initscr, , + [AC_MSG_WARN(Cannot find ncurses lib) readl=false]) +fi + +if test x$readl = xtrue; then + AC_CHECK_LIB(readline, readline, , + [AC_MSG_WARN(Cannot find GNU readline lib) readl=false]) +fi + +if test x$readl = xtrue; then +AC_CHECK_LIB(history, add_history, , + [AC_MSG_WARN(Cannot find GNU history lib) readl=false]) +fi + +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" ) + +dnl Check if the gtk gui is required +AC_ARG_ENABLE(gui, +[ --enable-gui build the GTK+ GUI for mixvm (gmixvm)], +[case "${enableval}" in + yes) gui=true ;; + no) gui=false ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-gui) ;; +esac],[gui=true]) + +dnl Check for gtk+ +if test x$gui = xtrue; then + AM_PATH_GTK(1.2.0, + [LIBS="$LIBS $GTK_LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS"], + [AC_MSG_WARN(Cannot find GTK+: the GUI shall not be built) gui=false], + "gmodule" ) +fi + +dnl Check for libglade +if test x$gui = xtrue; then + AM_PATH_LIBGLADE([LIBS="$LIBS $LIBGLADE_LIBS" + CFLAGS="$CFLAGS $LIBGLADE_CFLAGS"], + [AC_MSG_WARN(Cannot find GTK+: the GUI shall not be built) gui=false]) +fi + +AM_CONDITIONAL(MAKE_GUI, test x$gui = xtrue) + +CFLAGS="$CFLAGS -Wall" +AC_SUBST(CFLAGS) + +AC_OUTPUT( +Makefile +doc/Makefile +doc/html/Makefile +mixlib/Makefile +mixlib/testsuite/Makefile +mixutils/Makefile +mixgtk/Makefile +misc/Makefile +intl/Makefile +samples/Makefile +po/Makefile.in +) + +if test x$readl = xtrue; then + addinfo=", with readline support" +fi + +echo +echo "*** GNU MDK $VERSION has been successfully configured. ***" +echo +echo "Type make to build the following utilities:" +echo " - mixasm (MIX assembler${addinfo})" +echo " - mixvm (MIX virtual machine)" +if test x$gui = xtrue; then +echo " - gmixvm (mixvm GTK+ GUI)" +fi +echo diff --git a/doc/.cvsignore b/doc/.cvsignore new file mode 100644 index 0000000..cad9468 --- /dev/null +++ b/doc/.cvsignore @@ -0,0 +1,12 @@ +Makefile +Makefile.in +mdk-0.1 +mdk-doc-html-0.2.tar.gz +mdk-doc.tar.gz +mdk.html +mdk.info +mdk.info-1 +mdk.info-2 +mdk.info-3 +stamp-vti +version.texi diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..42953a8 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,28 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# 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 +SUFFIXES = .html + + +info_TEXINFOS = mdk.texi +mdk_TEXINFOS = gpl.texi mdk_intro.texi mdk_tut.texi mdk_gstart.texi \ + mdk_mixvm.texi mdk_emixvm.texi mdk_mixasm.texi mdk_bugs.texi \ + mdk_index.texi + +html_docs = mdk.html + +.texi.html: + $(MAKEINFO) --html $< + +.PHONY: html +html: version.texi gpl.texi $(html_docs) \ No newline at end of file diff --git a/doc/gpl.texi b/doc/gpl.texi new file mode 100644 index 0000000..361504a --- /dev/null +++ b/doc/gpl.texi @@ -0,0 +1,400 @@ +@node Copying, Problems, mixasm, Top +@chapter Copying +@lowersections + +@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. + +@raisesections diff --git a/doc/mdk.texi b/doc/mdk.texi new file mode 100644 index 0000000..ba5b94f --- /dev/null +++ b/doc/mdk.texi @@ -0,0 +1,213 @@ +\input texinfo +@c %**start of header +@setfilename mdk.info +@settitle GNU MIX Development Kit (mdk) +@finalout +@setchapternewpage odd +@c %**end of header + +@set UPDATED 20 February 2001 +@set EDITION 0.3 +@set VERSION 0.3 +@set JAO Jos@'e Antonio Ortega Ruiz +@set PHILIP Philip E. King +@footnotestyle separate + +@ifinfo +This file documents the the GNU @sc{mdk} utilities for developing +programs using Donald Knuth's MIX language. + +Copyright (C) 2000, 2001 Free Software Foundation, Inc. + +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 GNU MDK +@subtitle GNU MIX Development Kit +@subtitle Edition @value{EDITION}, for GNU @sc{mdk} Version @value{VERSION} +@subtitle @value{UPDATED} +@author by @value{JAO} + +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 2000, 2001 Free Software Foundation, Inc. + +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 GNU @sc{mdk} utilities to develop, run and debug +programs written in the MIXAL programming language. MIXAL is an +assembler-like language for programming a virtual computer called +MIX. They were created by Donald Knuth in the first volume of @cite{The +Art of Computer Programming} (Addison Wesley, 1997). + +GNU @sc{mdk} is an official GNU package. + +GNU @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 improve it. + +@value{PHILIP} has contributed to this package development with many +helpful discussions, as well as actual code (@pxref{mixvm.el}). + +@end ifinfo + +@menu +* Introduction:: +* Installing MDK:: +* MIX and MIXAL tutorial:: Learn the innards of MIX and MIXAL. +* Getting started:: Basic usage of the @sc{mdk} tools. +* mixvm.el:: Using @code{mixvm} within Emacs. +* mixvm:: Invoking and using the MIX virtual machine. +* gmixvm:: +* mixasm:: Invoking the MIXAL assembler. +* Copying:: @sc{mdk} licensing terms. +* Problems:: Reporting bugs. +* Concept Index:: Index of concepts. + + + + + + + + +@detailmenu + --- The Detailed Node Listing --- + +Installing @sc{mdk} + +* Download:: +* Requirements:: +* Basic installation:: +* Emacs support:: +* Special configure flags:: + +MIX and MIXAL tutorial + +* 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 + +* Instruction structure:: +* Loading operators:: +* Storing operators:: +* Arithmetic operators:: +* Address transfer operators:: +* Comparison operators:: +* Jump operators:: +* Input-output operators:: +* Conversion operators:: +* Shift operators:: +* Miscellaneous operators:: +* Execution times:: + +MIXAL + +* Basic structure:: Writing basic MIXAL programs. +* MIXAL directives:: Assembler directives. +* Expressions:: Evaluation of expressions. +* W-expressions:: Evaluation of w-expressions. +* Local symbols:: Special symbol table entries. +* Literal constants:: Specifying an immediate operand. + +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. + +Interactive commands + +* File commands:: Loading and executing programs. +* Debug commands:: Debugging programs. +* State commands:: Inspecting the virtual machine state. + +gmixvm + +* Invoking @code{gmixvm}:: +* MIX virtual machine:: +* Menu and status bars:: + +@code{mixasm}, the MIXAL assembler + +* Invoking @code{mixasm}:: @code{mixasm} options + +@end detailmenu +@end menu + +@include mdk_intro.texi +@include mdk_install.texi +@include mdk_tut.texi +@include mdk_gstart.texi +@include mdk_emixvm.texi +@include mdk_mixvm.texi +@include mdk_gmixvm.texi +@include mdk_mixasm.texi +@include gpl.texi +@include mdk_bugs.texi +@include mdk_index.texi + + +@shortcontents +@contents +@bye diff --git a/doc/mdk_bugs.texi b/doc/mdk_bugs.texi new file mode 100644 index 0000000..7531daa --- /dev/null +++ b/doc/mdk_bugs.texi @@ -0,0 +1,16 @@ +@node Problems, Concept Index, Copying, Top +@chapter Reporting Bugs +@cindex bugs +@cindex problems +@cindex questions +@cindex suggestions + +If you have any questions, comments or suggestions, please send +electronic mail to @email{jao@@gnu.org, the author}. + +If you find a bug in @sc{mdk}, please send electronic mail to +@email{bug-mdk@@gnu.org, the @sc{mdk} bug list}. + +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. diff --git a/doc/mdk_emixvm.texi b/doc/mdk_emixvm.texi new file mode 100644 index 0000000..8fcbf55 --- /dev/null +++ b/doc/mdk_emixvm.texi @@ -0,0 +1,25 @@ +@node mixvm.el, mixvm, Getting started, Top +@comment node-name, next, previous, up +@chapter mixvm.el + +If you are an Emacs user and write your MIXAL programs using this +editor, you will find the elisp program @file{mixvm.el} quite +useful@footnote{@file{mixvm.el} has been kindly contributed by +@value{PHILIP}. @file{mixvm.el} is based on a study of gdb, perldb, and +pdb as found in @file{gud.el}, and @file{rubydb3x.el} distributed with +the source code to the Ruby language.}. @file{mixvm.el} allows running +the MIX virtual machine @code{mixvm} (@pxref{mixvm}) inside an Emacs +@acronym{GUD} buffer, while visiting the MIXAL source file in another +buffer. + +After installing @file{mixvm.el} (@pxref{Emacs support}), you can +initiate an @sc{mdk}/@acronym{GUD} session inside Emacs with the command + +@example +M-x mixvm +@end example + +@noindent +and you will have a @code{mixvm} prompt inside a newly created +@acronym{GUD} buffer. @acronym{GUD} will reflect the current line in the +corresponding source file buffer. diff --git a/doc/mdk_gmixvm.texi b/doc/mdk_gmixvm.texi new file mode 100644 index 0000000..f3ed33b --- /dev/null +++ b/doc/mdk_gmixvm.texi @@ -0,0 +1,118 @@ +@node gmixvm, mixasm, mixvm, Top +@comment node-name, next, previous, up +@chapter gmixvm +@cindex @code{gmixvm} +@cindex GUI +@cindex GTK+ + +@menu +* Invoking @code{gmixvm}:: Invoking the GTK+ interface. +* MIX virtual machine:: The MIX virtual machine window. +* Menu and status bars:: Available menu commands. +@end menu + +@node Invoking @code{gmixvm}, MIX virtual machine, gmixvm, gmixvm +@comment node-name, next, previous, up +@section Invoking @code{gmixvm} + +If you have built @sc{mdk} with GTK+ support (@pxref{Installing MDK}), a +graphical front-end for the MIX virtual machine will be available in +your system. You can invoke it by typing + +@example +gmixvm @kbd{RET} +@end example + +@noindent +at your command prompt. The @code{gmixvm} main window will appear, +offering you a graphical interface to run and debug your MIX programs. + +@image{ss_mix} + +Apart from the menu and status bars, we can distinguish two zones (or +halves) in this main window. In the upper half of @code{gmixvm}'s main +window there is a notebook with three pages, namely, + +@itemize +@item +a MIX virtual machine view, which shows you the registers, flags, memory +contents and time statistics of the virtual machine; +@item +a MIXAL source view, which shows the MIXAL file and lets you manage +breakpoints; +@item +a Devices view, which shows you the output to character based MIX block +devices. +@end itemize + +@noindent +On the other hand, the main window's lower half presents you a +@code{mixvm} command prompt and a logging area where results of the +issued commands are presented. + +The following sections describe the above mentioned components of +@code{gmixvm}. + +@node MIX virtual machine, Menu and status bars, Invoking @code{gmixvm}, gmixvm +@comment node-name, next, previous, up +@section MIX virtual machine + +The first notebook's page displays the current status of the virtual +machine. There you can find the registers' contents, the value of the +comparison and overflow flags, the location pointer, a list with all MIX +memory cells and their contents, and the time statistics (including +total uptime, elapsed time since the last run command and total +execution time for the currently loaded MIX program). + +Clicking any register entry, you will be prompted for a new register's +contents +@ifnotinfo +(as shown in the next figure). +@image{ss_worddlg} +@end ifnotinfo + +In the same manner, click on any address of the memory cells list to be +prompted for the new contents of the clicked cell. If you click the +address column's title, a dialog asking you for a memory address will +appear; if you introduce a valid address, this will be the first cell +displayed in the scrollable list after you click the OK button. + + +@node Menu and status bars, , MIX virtual machine, gmixvm +@comment node-name, next, previous, up +@section Menu and status bars + +The menu bar gives you access to the following commands: + +@deffn File Load... +Opens a file dialog that lets you specify a binary MIX file to be loaded +in the virtual machine's memory. It is equivalent to the @code{mixvm}'s +@code{load} command (@pxref{File commands}). +@end deffn + +@deffn File Exit +Exits the application. +@end deffn + +@deffn Debug Run +Runs the currently loaded MIX program, up to the next breakpoint. It is +equivalent to the @code{mixvm}'s @code{run} command (@pxref{Debug +commands}). +@end deffn + +@deffn Debug Next +Executes the next MIX instruction. It is equivalent to the +@code{mixvm}'s @code{next} command (@pxref{Debug commands}). +@end deffn + +@deffn Debug Clear breakpoints +Clears all currently set breakpoints. It is equivalent to the +@code{mixvm}'s @code{cabp} command. +@end deffn + +@deffn Help About... +Shows information about @code{gmixvm}'s version and copyright. +@end deffn + +On the other hand, the status bar displays the name of the last loaded +MIX file. diff --git a/doc/mdk_gstart.texi b/doc/mdk_gstart.texi new file mode 100644 index 0000000..bde4160 --- /dev/null +++ b/doc/mdk_gstart.texi @@ -0,0 +1,433 @@ +@node Getting started, mixvm.el, MIX and MIXAL tutorial, 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 tutorial}. + +@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 tutorial}, 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 +** Execution time: 11 +@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. Note also that the virtual machine reports +the execution time of the program, according to the (virtual) time spent +in each of the binary instructions (@pxref{Execution times}). + +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 +** Execution time: 11 +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 and execution +time, 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 +Elapsed time: 11 /Total program time: 11 (Total uptime: 11) +MIX > +@end example + +@noindent Note that now the timing statistics are richer. You obtain the +elapsed execution time (i.e., the time spent executing instructions +since the last breakpoint), the total execution time for the program up +to now (which in our case coincides with the elapsed time, since there +were no breakpoints), and the total uptime for the virtual machine (you +can load and run more than one program in the same session). 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 +Elapsed time: 1 /Total program time: 1 (Total uptime: 1) +MIX > pc +Current address: 3001 +MIX > next +End of program reached at address 3002 +Elapsed time: 10 /Total program time: 11 (Total uptime: 11) +MIX > pc +Current address: 3002 +MIX > next +MIXAL HELLO WORLD +Elapsed time: 1 /Total program time: 1 (Total uptime: 12) +MIX > +MIX > run +Running ... +... done +Elapsed time: 10 /Total program time: 11 (Total uptime: 22) +MIX > @end example +@noindent +(As an aside, the above sample also shows how the virtual machine +handles cummulative time statistics and automatic program restart). + +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) +Elapsed time: 1 /Total program time: 1 (Total uptime: 23) +MIX > run +Running ... +... done +Elapsed time: 10 /Total program time: 11 (Total uptime: 33) +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 + +Other useful commands for debugging are @code{tron} (which turns on +tracing of executed intructions) and @code{weval} (which evaluates +w-expressions on the fly). For a complete description of all available +MIX commands, @xref{mixvm}. diff --git a/doc/mdk_index.texi b/doc/mdk_index.texi new file mode 100644 index 0000000..cb752f0 --- /dev/null +++ b/doc/mdk_index.texi @@ -0,0 +1,10 @@ +@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 diff --git a/doc/mdk_install.texi b/doc/mdk_install.texi new file mode 100644 index 0000000..78690ba --- /dev/null +++ b/doc/mdk_install.texi @@ -0,0 +1,180 @@ +@node Installing MDK, MIX and MIXAL tutorial, Introduction, Top +@comment node-name, next, previous, up +@chapter Installing @sc{mdk} + +@menu +* Download:: +* Requirements:: +* Basic installation:: +* Emacs support:: +* Special configure flags:: +@end menu + +@node Download, Requirements, Installing MDK, Installing MDK +@comment node-name, next, previous, up +@section Download the source tarball + +GNU @sc{mdk} is distributed as a source tarball available for download in +the following @acronym{URL}s: + +@itemize @bullet +@item +@url{ftp://ftp.gnu.org/pub/gnu/mdk} (or one of +@uref{http://www.gnu.org/prep/ftp.html, its mirrors}) +@item +@uref{http://sourceforge.net/project/showfiles.php?group_id=13897} +@end itemize + +The above sites contain the latest stable releases of @sc{mdk}. The +development branch is available at: + +@itemize @bullet +@item +@uref{http://sourceforge.net/cvs/?group_id=13897} +@end itemize + +After you have downloaded the source tarball, unpack it in a directory +of your choice using the command: + +@example +tar xfvz mdk-X.Y.tar.gz +@end example + +@noindent +where @var{X.Y} stands for the downloaded version (the current stable +release being version @value{VERSION}). + +@node Requirements, Basic installation, Download, Installing MDK +@comment node-name, next, previous, up +@section Requirements + +In order to build and install @sc{mdk}, you will need the following +libraries installed in your system: + +@itemize @minus +@item +@uref{http://www.gtk.org, GLIB 1.2.0} (required) +@item +@uref{http://www.gnu.org/software/flex/flex.html, GNU Flex 2.3} (required) +@item +@uref{http://www.gtk.org, GTK+ 1.2.0} (optional) +@item +@uref{ftp://ftp.gnome.org/pub/GNOME/stable/sources/libglade/, libglade} +(optional) +@item +GNU readline and history libraries (optional) +@end itemize + +If present, readline and history are used to provide command completion +and history management to the command line MIX virtual machine, @code{mixvm} +GTK+ and libglade are needed if you want to build the graphical +interface to the MIX virtual machine, @code{gmixvm}. + +@strong{Please note}: you need both the libraries @emph{and} the +headers; this means both the library package and the @file{-dev} package +if you do not compile your libraries yourself (ex: installing +@file{libgtk1.2} and @file{libgtk1.2-dev} on Debian). + +@node Basic installation, Emacs support, Requirements, Installing MDK +@comment node-name, next, previous, up +@section Basic installation + +@sc{mdk} uses GNU Autoconf and Automake tools, and, therefore, should +be built and installed without hassle using the following commands +inside the source directory: + +@example +./configure +make +make install +@end example + +@noindent +where the last one must be run as root. + +The first command, @code{configure}, will setup the makefiles for your +system. In particular, @code{configure} will look for GTK+ and libglade, +and, if they are present, will generate the appropiate makefiles for +building the @code{gmixvm} graphical user interface. Upon completion, +you should see a message with the configuration results like the +following: + +@example +*** GNU MDK 0.3 has been successfully configured. *** + +Type make to build the following utilities: + - mixasm (MIX assembler) + - mixvm (MIX virtual machine, with readline support) + - gmixvm (mixvm GTK+ GUI) +@end example + +@noindent +where the last line may be missing if you lack the above mentioned +libraries. + +The next command, @code{make}, will actually build the @sc{mdk} programs +in the following locations: + +@itemize @minus +@item +@file{mixutils/mixasm} +@item +@file{mixutils/mixvm} +@item +@file{mixgtk/gmixvm} +@end itemize + +You can run these programs from within their directories, but I +recommend you to install them in proper locations using @code{make +install} from a root shell. + +@node Emacs support, Special configure flags, Basic installation, Installing MDK +@comment node-name, next, previous, up +@section Emacs support + +@code{mixvm} can be run within an Emacs GUD buffer using the elisp +program @file{misc/mixvm.el}, kindly contributed by @value{PHILIP}. + +@file{mixvm.el} provides an interface between @sc{mdk}'s @code{mixvm} +and Emacs, via @acronym{GUD}. Place this file in your load-path, +optionally adding the following line to your @file{.emacs} file: + +@lisp +(autoload 'mixvm "mixvm" "mixvm/gud interaction" t) +@end lisp + + + +@node Special configure flags, , Emacs support, Installing MDK +@comment node-name, next, previous, up +@section Special configure flags + +You can fine tunning the configuration process using the following +switches with configure: + +@defopt --enable-gui[=yes|no] +@defoptx --disable-gui +Enables/disables the built of the MIX virtual machine GUI +(@code{gmixvm}). If the required libraries are missing +(@pxref{Requirements}) the configure script with automatically disable +this feature. +@end defopt + +@defopt --with-readline[=yes|no] +@defoptx --without-readline +Enables/disables the GNU Readline support for @code{mixvm}. If the +required libraries are missing (@pxref{Requirements}) the configure +script with automatically disable this feature. +@end defopt + +For additional, boilerplate configure options, see the @file{INSTALL} +file, or run + +@example +configure --help +@end example + + + + + diff --git a/doc/mdk_intro.texi b/doc/mdk_intro.texi new file mode 100644 index 0000000..2a3f95d --- /dev/null +++ b/doc/mdk_intro.texi @@ -0,0 +1,48 @@ +@node Introduction, Installing MDK, 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 +CISC CPUs, and the MIX assembly language (MIXAL) 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 learn or improve your programming skills, 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 mixasm +MIXAL assembler. Assembler which translates MIXAL source files into +programs that can be run (and debugged) by @code{mixvm} or @code{gmixvm}. +@item mixvm +MIX virtual machine. Emulation of the MIX computer with a @acronym{CLI}. +@item gmixvm +A GTK+ GUI for the MIX virtual machine. Provides all of @code{mixvm} +functionality accessible through a graphical interface. +@item mixvm.el +This elisp program allows running @code{mixvm} inside an Emacs GUD +buffer, allowing concurrent edition and debugging of MIXAL programs. +@end table + +@code{mixvm} and @code{gmixvm} implement 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 tutorial of MIX and MIXAL, and a thorough +description of the use of the @sc{mdk} utilities. diff --git a/doc/mdk_mixasm.texi b/doc/mdk_mixasm.texi new file mode 100644 index 0000000..753aa33 --- /dev/null +++ b/doc/mdk_mixasm.texi @@ -0,0 +1,79 @@ +@node mixasm, Copying, gmixvm, 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 diff --git a/doc/mdk_mixvm.texi b/doc/mdk_mixvm.texi new file mode 100644 index 0000000..8289472 --- /dev/null +++ b/doc/mdk_mixvm.texi @@ -0,0 +1,478 @@ +@node mixvm, gmixvm, mixvm.el, 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 which are +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 + +@menu +* File commands:: Loading and executing programs. +* Debug commands:: Debugging programs. +* State commands:: Inspecting the virtual machine state. +@end menu + +@node File commands, Debug commands, Commands, Commands +@comment node-name, next, previous, up +@subsection File commands + +You have at your disposal a series of commands that let you load and +execute MIX executable files, 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{MDK_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 + + +@node Debug commands, State commands, File commands, Commands +@comment node-name, next, previous, up +@subsection Debug commands + +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 + +The virtual machine can also show you the instructions it is executing, +using the following commands: + +@deffn {debug command} tron +@deffnx troff +@code{tron} enables instruction tracing. When tracing is enabled, each +time the virtual machine executes an instruction (due to your issuing a +@code{run} or @code{next} command), it is printed in its canonical form +(that is, with all expressions evaluated to their numerical values) and, +if the program was compiled with debug information, as it was originally +typed in the MIXAL source file. Instruction tracing is disable with the +@code{troff} command. A typical tracing session could be like this: + +@example +MIX > tron +Instruction tracing has been turned ON. +MIX > next +3000: [OUT 3002,0(2:3)] START OUT MSG(TERM) +MIXAL HELLO WORLD +Elapsed time: 1 /Total program time: 1 (Total uptime: 1) +MIX > next +3001: [HLT 0,0] HLT +End of program reached at address 3002 +Elapsed time: 10 /Total program time: 11 (Total uptime: 11) +MIX > troff +Instruction tracing has been turned OFF. +MIX > +@end example +@noindent +The executed instruction, as it was translated, is shown between square +brackets after the memory address, and, following it, you can see the +actual MIXAL code that was compiled into the executed instruction. +@end deffn + +@code{mixvm} is also able of evaluating w-expressions +(@pxref{W-expressions}) using the following command: + +@deffn {debug command} weval WEXP +Evaluates the given w-expression, @var{WEXP}. The w-expression can +contain any currently defined symbol. For instance: + +@example +MIX > psym START ++ 00 00 00 46 56 (0000003000) +MIX > weval START(0:1),START(3:4) ++ 56 00 46 56 00 (0939716096) +MIX > +@end example +@end deffn + +New symbols can be defined using the @code{ssym} command: +@deffn {debug command} ssym SYM WEXP +Defines the symbol named @var{SYM} with the value resulting from +evaluating @var{WEXP}, an w-expression. The newly defined symbol can be +used in subsequent @code{weval} commands, as part of the expression to +be evaluated. E.g., + +@example +MIX > ssym S 2+23*START ++ 00 00 18 19 56 (0000075000) +MIX > psym S ++ 00 00 18 19 56 (0000075000) +MIX > weval S(3:4) ++ 00 00 19 56 00 (0000081408) +MIX > +@end example +@end deffn + +Finally, if you want to discover which is the decimal value of a MIX +word expressed as five bytes plus sign, you can use + +@deffn {debug command} w2d WORD +Computes the decimal value of the given word. @var{WORD} must be +expressed as a sign (+/-) followed by five space-delimited, two-digit +decimal values representing the five bytes composing the word. The +reverse operation (showing the word representation of a decimal value) +can be accomplished with @code{weval}. For instance: + +@example +MIX > w2d - 01 00 00 02 02 +-16777346 +MIX > weval -16777346 +- 01 00 00 02 02 (0016777346) +MIX > +@end example +@end deffn + +@node State commands, , Debug commands, Commands +@comment node-name, next, previous, up +@subsection State commands + +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 } {filename[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 diff --git a/doc/mdk_tut.texi b/doc/mdk_tut.texi new file mode 100644 index 0000000..12bfb42 --- /dev/null +++ b/doc/mdk_tut.texi @@ -0,0 +1,1259 @@ +@node MIX and MIXAL tutorial, Getting started, Installing MDK, Top +@comment node-name, next, previous, up +@chapter MIX and MIXAL tutorial +@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) to illustrate +the algorithms and skills that every serious programmer should +master. 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. In the following subsections you will find a tutorial +on these topics, which will teach you the basics of the MIX architecture +and how to program a MIX computer using MIXAL. + +@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 tutorial, MIX and MIXAL tutorial +@comment node-name, next, previous, up +@section The MIX computer + +In this section, you will find a 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 from 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 +@noindent +Sample MIX words are @samp{- 12 00 11 01 63} and @samp{+ 12 11 34 43 +00}. + +You can refer to subfields within a word using a @dfn{field +specification} or @dfn{fspec} of the form ``(@var{l}:@var{r})'', where +@var{l} denotes the first byte, and @var{r} the last byte of the +subfield. +When @var{l} is zero, the subfield includes the word's +sign. An fspec can also be represented as a single value @code{F}, given +by @code{F = 8*L + R} (thus the fspec @samp{(1:3)}, denoting the first +three bytes of a word, is represented by the integer 11). + +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: + +@cindex rA +@cindex rX +@cindex rJ +@cindex rIn +@cindex register + +@table @asis +@item @code{rA} +A register. General purpose register holding a word. Usually its +contents serves as the operand of arithmetic and storing instructions. +@item @code{rX} +X register. General purpose register holding a word. Often it acts as an +extension or a replacement of @samp{rA}. +@item @code{rJ} +J (jump) register. This register stores positive two-byte values, +usually representing a jump address. +@item @code{rI1}, @code{rI2}, @code{rI3}, @code{rI4}, @code{rI5}, @code{rI6} +Index registers. These six registers can store a signed two-byte +value. Their contents is used as indexing values for the computation of +effective memory addresses. +@end table + +@cindex @sc{ov} +@cindex @sc{cm} +@cindex @code{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}, and its possible values are abbreviated as @dfn{E}, @dfn{G} and +@dfn{L}. +@item +Input-output block devices. Each device is labelled as @code{un}, where +@code{n} runs from 0 to 20. In Knuth's definition, @code{u0} through +@code{u7} are magnetic tape units, @code{u8} through @code{15} are disks +and drums, @code{u16} is a card reader, @code{u17} is a card writer, +@code{u18} is +a line printer and, @code{u19} is a typewriter terminal, and @code{u20}, +a paper tape. Our implementation maps these devices to disk files, +except for @code{u19}, which represents the standard output. +@end itemize + +As noted above, the MIX computer communicates with the external world by +a set of input-output devices which can be ``connected'' to it. The +computer interchanges information using blocks of words whose length +depends on the device at hand (@pxref{Devices}). These words are +interpreted by the device either as binary information (for devices +0-16), or as representing printable characters (devices 17-20). In the +last case, each MIX byte is mapped onto a character according to the +following table: + +@multitable {00} {C} {00} {C} {00} {C} {00} {C} +@item 00 @tab @tab 01 @tab A @tab 02 @tab B @tab 03 @tab C +@item 04 @tab D @tab 05 @tab E @tab 06 @tab F @tab 07 @tab G +@item 08 @tab H @tab 09 @tab I @tab 10 @tab d @tab 11 @tab J +@item 12 @tab K @tab 13 @tab L @tab 14 @tab M @tab 15 @tab N +@item 16 @tab O @tab 17 @tab P @tab 18 @tab Q @tab 19 @tab R +@item 20 @tab s @tab 21 @tab p @tab 22 @tab S @tab 23 @tab T +@item 24 @tab U @tab 25 @tab V @tab 26 @tab W @tab 27 @tab X +@item 28 @tab Y @tab 29 @tab Z @tab 30 @tab 0 @tab 31 @tab 1 +@item 32 @tab 2 @tab 33 @tab 3 @tab 34 @tab 4 @tab 35 @tab 5 +@item 36 @tab 6 @tab 37 @tab 7 @tab 38 @tab 8 @tab 39 @tab 9 +@item 40 @tab . @tab 41 @tab , @tab 42 @tab ( @tab 43 @tab ) +@item 44 @tab + @tab 45 @tab - @tab 46 @tab * @tab 47 @tab / +@item 48 @tab = @tab 49 @tab $ @tab 50 @tab < @tab 51 @tab > +@item 52 @tab @@ @tab 53 @tab ; @tab 54 @tab : @tab 55 @tab ' +@end multitable +@noindent +The value 0 represents a whitespace. Lowercase letters (d, s, p) +correspond to symbols not representable as ASCII characters (uppercase +delta, sigma and gamma, respectively), and byte values 56-63 have no +associated character. + +Finally, the MIX computer features a virtual CPU which controls the +above components, and which is able to execute a rich set of +instructions (constituting its machine language, similar to those +commonly found in real CPUs), including arithmetic, logical, storing, +comparison and jump instructions. Being a typical von Neumann computer, +the MIX CPU fetchs binary instructions from memory sequentially (unless +a jump instruction is found), and stores the address of the next +instruction to be executed in an internal register called @dfn{location +counter} (also known as program counter in other architectures). + +The next section, @xref{MIX instruction set}, gives a complete description +of the available MIX binary 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 fully describe the instruction set of the MIX +computer. We begin with a description of the structure of binary +instructions and the notation used to refer to their subfields. The +remaininig subsections are devoted to describing the actual instructions +available to the MIX programmer. + +@menu +* Instruction structure:: +* Loading operators:: +* Storing operators:: +* Arithmetic operators:: +* Address transfer operators:: +* Comparison operators:: +* Jump operators:: +* Input-output operators:: +* Conversion operators:: +* Shift operators:: +* Miscellaneous operators:: +* Execution times:: +@end menu + +@node Instruction structure, Loading operators, MIX instruction set, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Instruction structure + +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 + +For a given instruction, @samp{M} stands for +the memory address obtained after indexing the ADDRESS subfield +(using its INDEX byte), and @samp{V} is the contents of the +subfield indicated by MOD of the memory cell with address @samp{M}. For +instance, suppose that we have the following contents of MIX registers +and memory cells: + +@example +[rI2] = + 00 63 +[31] = - 10 11 00 11 22 +@end example +@noindent +where @samp{[n]} denotes the contents of the nth memory cell and +@samp{[rI2]} the contents of register @samp{rI2}@footnote{In general, +@samp{[X]} will denote the contents of entity @samp{X}; thus, by +definition, @w{@samp{V = [M](MOD)}}.}. Let us consider the binary +instruction @w{@samp{I = - 00 32 02 11 10}}. For this instruction we +have: + +@example +ADDRESS = - 00 32 = -32 +INDEX = 02 = 2 +MOD = 11 = (1:3) +OPCODE = 10 + +M = ADDRESS + [rI2] = -32 + 63 = 31 +V = [M](MOD) = (- 10 11 00 11 22)(1:3) = + 00 00 10 11 00 +@end example + +In the following subsections, we will assing to each MIX instruction a +mnemonic, or symbolic name. For instance, the mnemonic of @samp{OPCODE} +10 is @samp{LD2}. Thus we can rewrite the above instruction as + +@example +LD2 -32,2(1:3) +@end example +@noindent +or, for a generic instruction: + +@example +MNEMONIC ADDRESS,INDEX(MOD) +@end example +@noindent +Some instructions are identified by both the OPCODE and the MOD +fields. In these cases, the MOD will not appear in the above symbolic +representation. Also when ADDRESS or INDEX are zero, they can be +omitted. Finally, MOD defaults to (0:5) (meaning the +whole word). + +@node Loading operators, Storing operators, Instruction structure, 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 +Put in rA the contents of cell no. M. +OPCODE = 8, MOD = fspec. @code{rA <- V}. +@item LDX +Put in rX the contents of cell no. M. +OPCODE = 15, MOD = fspec. @code{rX <- V}. +@item LDi +Put in rIi the contents of cell no. M. +OPCODE = 8 + i, MOD = fspec. @code{rIi <- V}. +@item LDAN +Put in rA the negative contents of cell no. M. +OPCODE = 16, MOD = fspec. @code{rA <- -V}. +@item LDXN +Put in rX the negative contents of cell no. M. +OPCODE = 23, MOD = fspec. @code{rX <- -V}. +@item LDiN +Put in rIi the negative contents of cell no. M. +OPCODE = 16 + i, MOD = fspec. @code{rIi <- -V}. +@end ftable + +In all the above load instructions the @samp{MOD} field selects the +bytes of the memory cell with address @samp{M} which are loaded into the +requisite register (indicated by the @samp{OPCODE}). For instance, the +word @w{@samp{+ 00 13 01 27 11}} represents the instruction + +@example +LD3 13,1(3:3) + ^ ^ ^ ^ + | | | | + | | | --- MOD = 27 = 3*8 + 7 + | | --- INDEX = 1 + | --- ADDRESS = 00 13 + --- OPCODE = 11 +@end example +Let us suppose that, prior to this instruction execution, the state of +the MIX computer is the following: + +@example +[rI1] = - 00 01 +[rI3] = + 24 12 +[12] = - 01 02 03 04 05 +@end example +@noindent +As, in this case, @w{@samp{M = 13 + [rI1] = 12}}, we have +@w{@samp{V = [M](3:3) = (- 01 02 03 04 05)(3:3) = + 00 00 00 00 03}} +(note that the specified subfield is left-padded with null bytes to +complete a word). Hence, the MIX state, after the instruction execution, +will be + +@example +[rI1] = - 00 01 +[rI3] = + 00 03 +[12] = - 01 02 03 04 05 +@end example + +To further illustrate loading operators, the following table shows the +contents of @samp{rX} after different @samp{LDX} instructions: + +@table @samp +@item LDX 12(0:0) [rX] = - 00 00 00 00 00 +@item LDX 12(0:1) [rX] = - 00 00 00 00 01 +@item LDX 12(3:5) [rX] = + 00 00 03 04 05 +@item LDX 12(3:4) [rX] = + 00 00 00 03 04 +@item LDX 12(0:5) [rX] = - 01 02 03 04 05 +@end table + + +@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 the inverse of the load +operations: they are used to store a subfield of a register +into a memory location. Here, MOD represents the subfield of the memory +cell that is to be overwritten with bytes from a register. These bytes +are taken beginning by the rightmost side of the register. + +@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 + +By way of example, consider the instruction @samp{STA 1200(2:3)}. It +causes the MIX to fetch bytes no. 4 and 5 of register A and copy them to +bytes 2 and 3 of memory cell no. 1200 (remember that, for these +instructions, MOD specifies a subfield of @emph{the memory +address}). The others bytes of the memory cell retain their +values. Thus, if prior to the instruction execution we have + +@example +[1200] = - 20 21 22 23 24 +[rA] = + 01 02 03 04 05 +@end example +@noindent +we will end up with + +@example +[1200] = - 20 04 05 23 24 +[rA] = + 01 02 03 04 05 +@end example + +As a second example, @samp{ST2 1000(0)} will set the sign of +@samp{[1000]} to that of @samp{[rI2]}. + +@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. +@w{@code{rA <- rA +V}}. +@item SUB +Sub and set OV if overflow. OPCODE = 2, MOD = fspec. +@w{@code{rA <- rA - V}}. +@item MUL +Multiply V times rA and store the 10-bytes product in rAX. +OPCODE = 3, MOD = fspec. @w{@code{rAX <- rA x V}}. +@item DIV +rAX is considered a 10-bytes number, and it is divided by V. +OPCODE = 4, MOD = fspec. @w{@code{rA <- rAX / V}}, @code{rX} <- reminder. +@end ftable + +In all the above instructions, @samp{[rA]} is one of the operands +of the binary arithmetic operation, the other being @samp{V} (that is, +the specified subfield of the memory cell with address @samp{M}), padded +with zero bytes on its left-side to complete a word. In multiplication +and division, the register @samp{X} comes into play as a right-extension +of the register @samp{A}, so that we are able to handle 10-byte numbers +whose more significant bytes are those of @samp{rA} (the sign of this +10-byte number is that of @samp{rA}: @samp{rX}'s sign is ignored). + +Addition and substraction of MIX words can give rise to overflows, since +the result is stored in a register with room to only 5 bytes (plus +sign). When this occurs, the operation result modulo @w{1,073,741,823} +(the maximum value storable in a MIX word) is stored in @samp{rA}, and +the overflow toggle is set to TRUE. + +@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, @samp{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 + +In the above instructions, the subfield @samp{ADDRESS} acts as an +immediate (indexed) operand, and allow us to set directly the contents +of the MIX registers without an indirection to the memory cells (in a +real CPU this would mean that they are faster that the previously +discussed instructions, whose operands are fetched from memory). So, if +you want to store in @samp{rA} the value -2000 (- 00 00 00 31 16), you +can use the binary instruction @w{+ 31 16 00 03 48}, or, symbolically, + +@example +ENNA 2000 +@end example +@noindent +Used in conjuction with the store operations (@samp{STA}, @samp{STX}, +etc.), these instructions also allow you to set memory cells contents to +concrete values. + +Note that in these address transfer operators, the @samp{MOD} field is +not a subfield specificator, but serves to define (together with +@samp{OPCODE}) the concrete operation to be performed. + +@node Comparison operators, Jump operators, Address transfer operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Comparison operators +@cindex comparison operators + +So far, we have learned how to move values around between the MIX +registers and its memory cells, and also how to perform arithmetic +operations using these values. But, in order to write non-trivial +programs, other functionalities are needed. One of the most common is +the ability to compare two values, which, combined with jumps, will +allow the execution of conditional statements. +The following instructions compare the value of a register with @samp{V}, and +set the @sc{cm} indicator to the result of the comparison (i.e. to +@samp{E}, @samp{G} or @samp{L}, equal, greater or lesser respectively). + +@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 + +As explained above, these instructions modify the value of the MIX +comparison indicator; but maybe you are asking yourself how do you use +this value: enter jump operators, in the next subsection. + +@node Jump operators, Input-output operators, Comparison operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Jump operators +@cindex jump operators + +The MIX computer has an internal register, called the @dfn{location +counter}, which stores the address of the next instruction to be fetched +and executed by the virtual CPU. You cannot directly modify the contents +of this internal register with a load instruction: after fetching the +current instruction from memory, it is automatically increased in one +unit by the MIX. However, the is a set of instructions (which we call +jump instructions) which can alter the contents of the location counter +provided some condition is met. When this occurs, the value of the next +instruction address that would have been fetched in the absence of the +jump is stored in @samp{rJ} (except for @code{JSJ}), and the location +counter is set to the value of @samp{M} (so that the next instruction is +fetched from this new address). Later on, you can return to the point +when the jump occurred reading the address stored in @samp{rJ}. + +The MIX computer provides the following jump instructions: +With these instructions you force a jump to the specified address. Use +@samp{JSJ} if you do not care about the return address. + +@ftable @code +@item JMP +Unconditional jump. OPCODE = 39, MOD = 0. +@item JSJ +Unconditional jump, but rJ is not modified. OPCODE = 39, MOD = 1. +@end ftable + +These instructions check the overflow toggle to decide whether to jump +or not. + +@ftable @code +@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. +@end ftable + +In the following instructions, the jump is conditioned to the contents of the +comparison flag: + +@ftable @code +@item JL +Jump if @w{@code{[CM] = L}}. OPCODE = 39, MOD = 4. +@itemx JE +Jump if @w{@code{[CM] = E}}. OPCODE = 39, MOD = 5. +@itemx JG +Jump if @w{@code{[CM] = G}}. OPCODE = 39, MOD = 6. +@itemx JGE +Jump if @code{[CM]} does not equal @code{L}. OPCODE = 39, MOD = 7. +@itemx JNE +Jump if @code{[CM]} does not equal @code{E}. OPCODE = 39, MOD = 8. +@itemx JLE +Jump if @code{[CM]} does not equal @code{G}. OPCODE = 39, MOD = 9. +@end ftable + +You can also jump conditioned to the value stored in the MIX registers, +using the following instructions: + +@ftable @code +@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 Input-output operators, Conversion operators, Jump operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Input-output operators +@cindex input-output operators + +As explained in previous sections (@pxref{MIX architecture}), the MIX +computer can interact with a series of block devices. To that end, you +have at your disposal the following instructions: + +@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 +@noindent +In all the above instructions, the @samp{MOD} subfile must be in the +range 0-20, since it denotes the operation's target device. The +@samp{IOC} instruction only makes sense for tape devices (@samp{MOD} = +0-7 or 20): it shifts the read/write pointer by the number of words +given by @samp{M} (if it equals zero, the tape is rewound)@footnote{In +Knuth's original definition, there are other control operations +available, but they do not make sense when implementing the block +devices as disk files (as we do in @sc{mdk} simulator). For the same +reason, @sc{mdk} devices are always ready, since all input-output +operations are performed using synchronous system calls.}. + + +@node Conversion operators, Shift 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 +@noindent +Digits are represented in MIX by the range of values 30-39 (digits +9-0). Thus, if the contents of @samp{rA} and @samp{rX} is, for instance, + +@example +[rA] = + 30 30 31 32 33 +[rX] = + 31 35 39 30 34 +@end example +@noindent +the represented number is 0012315904, and @samp{NUM} will store this +value in @samp{rA} (i.e., we end up with @samp{[rA]} = @w{+ 0 46 62 52 +0} = 12315904. @samp{CHAR} performs the inverse operation. + +@node Shift operators, Miscellaneous operators, Conversion operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Shift operators +@cindex shift +@cindex shift operators + +The following instructions perform byte-wise shifts of the contents of +@samp{rA} and @samp{rX}. + +@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. +@end ftable +@noindent +If we begin with, say, @samp{[rA]} = @w{- 01 02 03 04 05}, we would +have the following modifications to @samp{rA} contents when performing +the instructions on the left column: + +@multitable {SLA 00} {[rA] = - 00 00 00 00 00} +@item SLA 2 @tab [rA] = - 03 04 05 00 00 +@item SRA 1 @tab [rA] = - 00 01 02 03 04 +@item SLC 3 @tab [rA] = - 04 05 01 02 03 +@item SRC 24 @tab [rA] = - 05 01 02 03 04 +@end multitable +@noindent +Note that the sign is unaffected by shift operations. On the other hand, +@samp{SLAX} and @samp{SRAX} treat @samp{rA} and @samp{rX} as a single +10-bytes register (ignoring again the signs), so that, if we begin with +@samp{[rA]} = @w{+ 01 02 03 04 05} and @samp{[rX]} = @w{- 06 07 08 09 +10}, executing @samp{SLAX 3} would yield: + +@example +[rA] = + 04 05 06 07 08 [rX] = - 09 10 00 00 00 +@end example + +@node Miscellaneous operators, Execution times, Shift operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Miscellaneous operators +@cindex miscellaneous operators + +Finally, we list in the following table three miscellaneous MIX +instructions which do not fit in any of the previous subsections: + +@ftable @code +@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 +@noindent +The only effect of executing @samp{NOP} is increasing the location +counter, while @samp{HLT} usually marks program termination. + +@node Execution times, , Miscellaneous operators, MIX instruction set +@comment node-name, next, previous, up +@subsubsection Execution times + +@cindex exection time +@cindex time + +When writing MIXAL programs (or any kind of programs, for that matter), +whe shall often be interested in their execution time. Loosely speaking, +we will interested in the answer to the question: how long takes a +program to execute? Of course, this execution time will be a function of +the input size, and the answer to our question is commonly given as the +asymptotic behaviour as a function of the input size. At any rate, to +compute this asymptotic behaviour, we need a measure of how long +execution of a single instruction takes in our (virtual) CPU. Therefore, +each MIX instruction will have an associated execution time, given in +arbitrary units (in a real computer, the value of this unit will depend +on the hardware configuration). When our MIX virtual machine executes +programs, it will give you the value of their execution time based upon +the execution time of each single instruction. + +In the following table, the execution times (in the above mentioned +arbitrary units) of the MIX instructions are given. + +@multitable {INSSSS} {01} {INSSSS} {01} {INSSSS} {01} {INSSSS} {01} +@item @code{NOP} @tab 1 @tab @code{ADD} @tab 2 @tab @code{SUB} +@tab 2 @tab @code{MUL} @tab 10 +@item @code{DIV} @tab 12 @tab @code{NUM} @tab 10 @tab @code{CHAR} +@tab 10 @tab @code{HLT} @tab 10 +@item @code{SLx} @tab 2 @tab @code{SRx} @tab 2 @tab @code{LDx} +@tab 2 @tab @code{STx} @tab 2 +@item @code{JBUS} @tab 1 @tab @code{IOC} @tab 1 @tab @code{IN} +@tab 1@tab @code{OUT} @tab 1 +@item @code{JRED} @tab 1 @tab @code{Jx} @tab 1 @tab @code{INCx} +@tab 1 @tab @code{DECx} @tab 1 +@item @code{ENTx} @tab 1 @tab @code{ENNx} @tab 1 @tab @code{CMPx} +@tab 1 @tab @code{MOVE} @tab 1+F +@end multitable + +In the above table, 'F' stands for the number of blocks to be moved +(given by the @code{FSPEC} subfield of the instruction); @code{SLx} and +@code{SRx} are a short cut for the byte-shifting operations; @code{LDx} +denote all the loading operations; @code{STx} are the storing +operations; @code{Jx} stands for all the jump operations, and so on with +the rest of abbreviations. + +@node MIXAL, , The MIX computer, MIX and MIXAL tutorial +@comment node-name, next, previous, up +@section MIXAL +@cindex MIXAL +@cindex MIX assembly language +@cindex assembly + +In the previous sections we have listed all the available MIX binary +instructions. As we have shown, each instruction is represented by a +word which is fetched from memory and executed by the MIX virtual +CPU. As is the case with real computers, the MIX knows how to decode +instructions in binary format (the so--called machine language), but a +human programmer would have a tough time if she were to write her +programs in machine language. Fortunately, 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 source files are translated +to machine language by a MIX assembler, which produces a binary file (the +actual MIX program) which can be directly loaded into the MIX memory and +subsequently executed. + +In this section, we describe MIXAL, the MIX assembly language. The +implementation of the MIX assembler program and MIX computer simulator +provided by @sc{mdk} are described later on (@pxref{Getting started}). + +@menu +* Basic structure:: Writing basic MIXAL programs. +* MIXAL directives:: Assembler directives. +* Expressions:: Evaluation of expressions. +* W-expressions:: Evaluation of w-expressions. +* Local symbols:: Special symbol table entries. +* Literal constants:: Specifying an immediate operand. +@end menu + +@node Basic structure, MIXAL directives, MIXAL, MIXAL +@comment node-name, next, previous, up +@subsection Basic program structure + +The MIX assembler reads MIXAL files line by line, producing, when +required, a binary instruction, which is associated to a predefined +memory address. To keep track of the current address, the assembler +maintains an internal location counter which is incremented each time an +instruction is compiled. In addition to MIX instructions, you can +include in MIXAL file assembly directives (or pseudoinstructions) +addressed at the assembler itself (for instance, telling it where the +program starts and ends, or to reposition the location counter; see below). + +MIX instructions and assembler directives@footnote{We shall call them, +collectively, MIXAL instructions.} are written in MIXAL (one per +source file line) according to the following pattern: + +@example +[LABEL] MNEMONIC [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 current +value of the location counter, and can be used in subsequent +expressions. +@item MNEMONIC +Is a literal denoting the operation code of the instruction +(e.g. @code{LDA}, @code{STA}; see @pxref{MIX instruction set}) 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.}. + +We have already listed the mnemonics associated will each MIX +instructions; sample MIXAL instructions representing MIX instructions +are: +@example +HERE LDA 2000 HERE represents the current location counter + LDX HERE,2(1:3) this is a comment + JMP 1234 +@end example + +@node MIXAL directives, Expressions, Basic structure, MIXAL +@comment node-name, next, previous, up +@subsection MIXAL directives + +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 + +The operand of @code{ORIG}, @code{EQU}, @code{CON} and @code{END} can be +any expression evaluating to a constant MIX word, i.e., either a simple +MIXAL expression (composed of numbers, symbols and binary operators, +@pxref{Expressions}) or a w-expression (@pxref{W-expressions}). + +All MIXAL programs must contain an @code{END} directive, with a twofold +end: first, it marks the end of the assembler job, and, in the second +place, its (mandatory) operand indicates the start address for the +compiled program (that is, the address at which the virtual MIX machine +must begin fetching instructions after loading the program). It is also +very common (although not mandatory) to include at least an @code{ORIG} +directive to mark the initial value of the assembler's location counter +(remember that it stores the address associated with each compiled MIX +instruction). Thus, a minimal MIXAL program would be + +@example + ORIG 2000 set the initial compilation adress + NOP this instruction will be loaded at adress 2000 + HLT and this one at address 2001 + END 2000 end of program; execution will start at address 2000 +this line is not parsed by the assembler +@end example +@noindent +The assembler will generate two binary instructions (@code{NOP} (@w{+ 00 +00 00 00 00}) and @code{HLT} (+ 00 00 02 05)), which will be loaded at +addresses 2000 and 2001. Execution of the program will begin at address +2000. Every MIXAL program should also include a @code{HLT} instruction, +which will mark the end of program execution (but not of program +compilation). + +The @code{EQU} directive allows the definition of symbolic names for +specific values. For instance, we could rewrite the above program as +follows: + +@example +START EQU 2000 + ORIG START + NOP + HLT + END START +@end example +@noindent +which would give rise to the same compiled code. Symbolic constants (or +symbols, for short) can also be implicitly defined placing them in the +@code{LABEL} field of a MIXAL instruction: in this case, the assembler +assigns to the symbol the value of the location counter before compiling +the line. Hence, a third way of writing our trivial program is + +@example + ORIG 2000 +START NOP + HLT + END START +@end example + +The @code{CON} directive allows you to directly specify the contents of +the memory address pointed by the location counter. For instance, when +the assembler encounters the following code snippet + +@example + ORIG 1150 + CON -1823473 +@end example +@noindent +it will assign to the memory cell number 1150 the contents @w{- 00 06 61 +11 49} (which corresponds to the decimal value -1823473). + +Finally, the @code{ALF} directive let's you specify the memory contents +as a set of five (quoted) characters, which are translated by the +assembler to their byte values, conforming in that way the binary word +that is to be stored in the corresponding memory cell. This directive +comes in handy when you need to store printable messages in a memory +address, as in the following example: + +@example + OUT MSG MSG is not yet defined here (future reference) +MSG ALF "THIS " MSG gets defined here + ALF "IS A " + ALF "MESSA" + ALF "GE. " +@end example +@noindent +The above snippet also shows the use of a @dfn{future reference}, that +is, the usage of a symbol (@code{MSG} in the example) prior of its actual +definition. The MIXAL assembler is able to handle future references +subject to some limitations which are described in the following section +(@pxref{Expressions}). + +@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 +@code{MNEMONIC} 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, W-expressions, MIXAL directives, 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. + +The special binary operator @code{:} has the same meaning as in fspecs, +i.e., + +@example +A:B = 8*A + B +@end example +@noindent +while @code{A//B} stands for the quotient of the ten-byte number @w{@code{A} 00 +00 00 00 00} (that is, A right-padded with 5 null bytes or, what amounts +to the same, multiplied by 64 to the fifth power) divided by +@code{B}. Sample expressions are: + +@example +18-8*3 = 30 +14/3 = 4 +1+3:11 = 4:11 = 43 +1//64 = (01 00 00 00 00 00)/(00 00 00 01 00) = (01 00 00 00 00 00) +@end example +@noindent +Note that all MIXAL expressions evaluate to a MIX word (by definition). + +All symbols appearing within an expression must be previously 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 W-expressions, Local symbols, Expressions, MIXAL +@comment node-name, next, previous, up +@subsection W-expressions +@cindex w-expressions + +Besides expressions, as described above (@pxref{Expressions}), the MIXAL +assembler is able to handle the so called @dfn{w-expressions} as the +operands of the directives @code{ORIG}, @code{EQU}, @code{CON} and +@code{END} (@pxref{MIXAL directives}). The general form of a +w-expression is the following: + +@example + WEXP = EXP[(EXP)][,WEXP] +@end example +@noindent +where @code{EXP} stands for an expression and square brackets denote +optional items. Thus, a w-expression is made by a regular expression +followed by an optional expression between parenthesis, followed by any +number of similar constructs separated by commas. Sample w-expressions +are: + +@example +2000 +235(3) +S1+3(S2),3000 +S1,S2(3:5),23 +@end example + +W-expressions are evaluated as follows. First, all expressions are +evaluated according to the rules given in the previous section. Thus, if +we start with, say, @samp{S1+2(2:4)} where @samp{S1} equals 265230, we +have @samp{265232(2:4)}. The expression between parenthesis must be a +valid f-spec, for it specifies the bytes to be taken from the preceding +word. In our example, we must take 3 bytes of the word @w{@samp{+ 00 01 +00 48 16}} (which is 265232), and store them in positions 2, 3 and 4 of +the result, resulting in the new word @w{@samp{+ 00 00 48 16 00}} (i.e., +the decimal value 197632). When we have two expressions separated with a +comma, we take, for each one, the subfield specified and compose the +word to obtain the result. For instance, in the w-expression + +@example +1(1:2),66(4:5) +@end example +@noindent +we first take two bytes from 1 (00 and 01) and store them as bytes 1 and +2 of the result (obtaining @w{@samp{+ 00 01 00 00 00}}) and, afterwards, +take two bytes from 66 (01 and 02) and store them as bytes 4 and 5 of +the result, obtaining @w{@samp{+ 00 01 00 01 02}} (262210). The process +is repeated for each new comma-separated example. For instance: + +@example +1(1:1),2(2:2),3(3:3),4(4:4) = 01 02 03 04 00 +@end example + +As stated before, w-expressions can only appear as the operands of MIXAL +directives taking a constant value (@code{ORIG}, @code{EQU}, @code{CON} +and @code{END}). Future references are @emph{not} allowed within +w-expressions (i.e., all symbols appearing in a w-expression must be +defined before they are used). + +@node Local symbols, Literal constants, W-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 + +Note that a @code{B} local symbol never refers to a definition in its +own line, that is, in the following program: + +@example + ORIG 1999 +ST NOP +3H EQU 69 +3H ENTA 3B local symbol 3B refers to 3H in previous line + HLT + END ST +@end example +@noindent +the contents of @samp{rA} is set to 69 and @emph{not} to 2001. An +specially tricky case occurs when using local symbols in conjunction +with @code{ORIG} pseudoinstructions. To wit@footnote{The author wants to +thank Philip E. King for pointing these two special cases of local +symbol usage to him.}, + +@example + ORIG 1999 +ST NOP +3H CON 10 + ENT1 * + LDA 3B +** rI1 is 2001, rA is 10. So far so good! +3H ORIG 3B+1000 +** at this point 3H equals 2003 +** and the location counter equals 3000. + ENT2 * + LDX 3B +** rI2 contains 3000, rX contains 2003. + HLT + END ST +@end example + +@node Literal constants, , Local symbols, MIXAL +@comment node-name, next, previous, up +@subsection Literal constants +@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{=wexp=}, where +@code{exp} is an w-expression (@pxref{W-expressions}). 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 + diff --git a/doc/ss_devices.png b/doc/ss_devices.png new file mode 100644 index 0000000..bb2ee83 Binary files /dev/null and b/doc/ss_devices.png differ diff --git a/doc/ss_mix.png b/doc/ss_mix.png new file mode 100644 index 0000000..9d0e6b6 Binary files /dev/null and b/doc/ss_mix.png differ diff --git a/doc/ss_mix.txt b/doc/ss_mix.txt new file mode 100644 index 0000000..757026e --- /dev/null +++ b/doc/ss_mix.txt @@ -0,0 +1,31 @@ +|-----------------------------------------------------------| +| Menu | +|-----------------------------------------------------------| +| | +| | +| | +| | +| MIXVM / MIXAL / Devices | +| | +| | +| | +| | +| | +| | +|-----------------------------------------------------------| +| | +| Command output | +| | +| | +| | +|-----------------------------------------------------------| +| Command prompt | +|-----------------------------------------------------------| +| Status bar | +|-----------------------------------------------------------| + + + + + + diff --git a/doc/ss_mixal.png b/doc/ss_mixal.png new file mode 100644 index 0000000..506a170 Binary files /dev/null and b/doc/ss_mixal.png differ diff --git a/doc/ss_worddlg.png b/doc/ss_worddlg.png new file mode 100644 index 0000000..be6e7f2 Binary files /dev/null and b/doc/ss_worddlg.png differ diff --git a/misc/.cvsignore b/misc/.cvsignore new file mode 100644 index 0000000..282522d --- /dev/null +++ b/misc/.cvsignore @@ -0,0 +1,2 @@ +Makefile +Makefile.in diff --git a/misc/Makefile.am b/misc/Makefile.am new file mode 100644 index 0000000..bf21fc6 --- /dev/null +++ b/misc/Makefile.am @@ -0,0 +1,14 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2001 Free Software Foundation, Inc. +# +# 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 = mixvm.el + diff --git a/misc/mixvm.el b/misc/mixvm.el new file mode 100644 index 0000000..71e1fb5 --- /dev/null +++ b/misc/mixvm.el @@ -0,0 +1,157 @@ +;;; mixvm.el --- mdk's mixvm / Emacs gud interaction +;; Copyright (C) 2001 Free Software Foundation, Inc. + +;; Author: Philip Ellis King +;; Maintainer: Philip Ellis King +;; Created: 12 Feb 2001 +;; Version: 0.2 +;; Keywords: tools + + +;;; Commentary: +;; mixvm.el provides an interface between mdk's mixvm and Emacs, +;; via gud. Place this file in your load-path, optionally adding +;; the following line to your .emacs file: +;; (autoload 'mixvm "mixvm" "mixvm/gud interaction" t) +;; Initiate a mdk/gud session with the command mixvm, gud will +;; reflect the current line in the source file buffer. + +;; (mixvm.el is based on a study of gdb, perldb, and pdb as found +;; in gud.el, and rubydb3x.el distributed with the source code to +;; the Ruby language. + +;;; Change Log: +;; Version 0.2 +;; Initial release + + +;;; Code: +(require 'gud) +(provide 'mixvm) + +;;; History of argument lists passed to mixvm. +(defvar gud-mixvm-history nil) + +;; rubydb3x provided good examples of xemacs/emacs +;; compatibility (not interested at the moment) +(defun gud-mixvm-massage-args (file args) + (cons "--emacs" args)) + +;; There's no guarantee that Emacs will hand the filter the entire +;; marker at once; it could be broken up across several strings. We +;; might even receive a big chunk with several markers in it. If we +;; receive a chunk of text which looks like it might contain the +;; beginning of a marker, we save it here between calls to the +;; filter. +(defvar gud-mixvm-marker-acc "") +(make-variable-buffer-local 'gud-mixvm-marker-acc) + +(defun gud-mixvm-marker-filter (string) + (setq gud-mixvm-marker-acc (concat gud-mixvm-marker-acc string)) + (let ((output "")) + + ;; Process all the complete markers in this chunk. + (while (string-match "\032\032mixvm:\\([^:]+\\):\\([0-9]+\\)" + gud-mixvm-marker-acc) + (setq + + ;; Extract the frame position from the marker. + gud-last-frame + (cons (substring gud-mixvm-marker-acc (match-beginning 1) (match-end 1)) + (string-to-int (substring gud-mixvm-marker-acc + (match-beginning 2) + (match-end 2)))) + + ;; Append any text before the marker to the output we're going + ;; to return - we don't include the marker in this text. + output (concat output + (substring gud-mixvm-marker-acc 0 (match-beginning 0))) + + ;; Set the accumulator to the remaining text. + gud-mixvm-marker-acc (substring gud-mixvm-marker-acc (match-end 0)))) + + ;; Does the remaining text look like it might end with the + ;; beginning of another marker? If it does, then keep it in + ;; gud-mixvm-marker-acc until we receive the rest of it. Since we + ;; know the full marker regexp above failed, it's pretty simple to + ;; test for marker starts. + ;; (note: \\' matches the end of the string (Perl's '$')) + (if (string-match "\032.*\\'" gud-mixvm-marker-acc) + (progn + ;; Everything before the potential marker start can be output. + (setq output (concat output (substring gud-mixvm-marker-acc + 0 (match-beginning 0)))) + + ;; Everything after, we save, to combine with later input. + (setq gud-mixvm-marker-acc + (substring gud-mixvm-marker-acc (match-beginning 0)))) + + (setq output (concat output gud-mixvm-marker-acc) + gud-mixvm-marker-acc "")) + + output)) + +;; See gdb for more comprehensive example +;; pek: it bugs me that this is run for EVERY interactive +;; mixvm command, should we cache some info somewhere? +(defun gud-mixvm-find-file (file) + (save-excursion + (let* ((buf (find-file-noselect file))) + (set-buffer buf) + (gud-make-debug-menu) + buf))) + + +(defvar mixvm-minibuffer-local-map nil + "Keymap for minibuffer prompting of mixvm startup command.") +(if mixvm-minibuffer-local-map + () + (setq mixvm-minibuffer-local-map (copy-keymap minibuffer-local-map)) + (define-key + mixvm-minibuffer-local-map "\C-i" 'comint-dynamic-complete-filename)) + + +(defcustom gud-mixvm-command-name "mixvm" + "File name for executing the mixvm debugger. +This should be an executable on your path, or an absolute file name." + :type 'string + :group 'gud) + + +;;;###autoload +(defun mixvm (command-line) + "Run mixvm on program FILE in buffer `*gud-FILE*'. +The directory containing FILE becomes the initial working directory +and source-file directory for your debugger." + (interactive + (list (read-from-minibuffer "Run mixvm (like this): " + (if (consp gud-mixvm-history) + (car gud-mixvm-history) + (concat gud-mixvm-command-name " ")) + mixvm-minibuffer-local-map nil + '(gud-mixvm-history . 1)))) + + (gud-common-init command-line 'gud-mixvm-massage-args + 'gud-mixvm-marker-filter 'gud-mixvm-find-file) + + (gud-def gud-break "sbp %l" "\C-b" "Set breakpoint at current line.") + (gud-def gud-remove "cbp %l" "\C-d" "Remove breakpoint at current line") + (gud-def gud-step "next" "\C-s" "Step one source line with display.") + (gud-def gud-next "next" "\C-n" "Step one line.") + (gud-def gud-stepi "next" "\C-i" "Step one line.") + (gud-def gud-cont "run" "\C-r" "Continue with display.") + (gud-def gud-finish "run" "\C-f" "Finish executing current function.") + (gud-def gud-print "weval %e" "\C-p" "Evaluate expression at point.") +; (gud-def gud-up "up" "<" "Up one stack frame.") +; (gud-def gud-down "down" ">" "Down one stack frame.") +; ;; Is this right? +; (gud-def gud-statement "! %e" "\C-e" "Execute Python statement at point.") + +; (local-set-key [menu-bar debug finish] '("Finish Function" . gud-finish)) +; (local-set-key [menu-bar debug up] '("Up Stack" . gud-up)) +; (local-set-key [menu-bar debug down] '("Down Stack" . gud-down)) + (setq comint-prompt-regexp "^MIX > ") + (set (make-local-variable 'paragraph-start) comint-prompt-regexp) + (run-hooks 'mixvm-mode-hook)) + +;;; mixvm.el ends here diff --git a/mixgtk/.cvsignore b/mixgtk/.cvsignore new file mode 100644 index 0000000..12ed8c2 --- /dev/null +++ b/mixgtk/.cvsignore @@ -0,0 +1,7 @@ +.deps +Makefile +Makefile.in +gmixvm +hello.mix +mixgtk +paper.dev diff --git a/mixgtk/Makefile.am b/mixgtk/Makefile.am new file mode 100644 index 0000000..f8b1bcf --- /dev/null +++ b/mixgtk/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2001 Free Software Foundation, Inc. +# +# 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 = mixgtk.glade +INCLUDES = -I$(includedir) -DGLADE_FILE=\""$(pkgdatadir)/mixgtk.glade"\"\ + -DLOCAL_GLADE_FILE=\"mixgtk.glade\" +LDADD = $(top_builddir)/mixlib/libmix.a + +if MAKE_GUI +pkgdata_DATA = mixgtk.glade +bin_PROGRAMS = gmixvm +gmixvm_SOURCES = mixgtk.c mixgtk_gen_handlers.h mixgtk_gen_handlers.c \ + mixgtk_cmd_dispatcher.h mixgtk_cmd_dispatcher.c \ + mixgtk_widgets.h mixgtk_widgets.c \ + mixgtk_device.h mixgtk_device.c \ + mixgtk_mixvm.h mixgtk_mixvm.c \ + mixgtk_mixal.h mixgtk_mixal.c \ + mixgtk_input.h mixgtk_input.c +endif + + + diff --git a/mixgtk/mixgtk.c b/mixgtk/mixgtk.c new file mode 100644 index 0000000..1bbc175 --- /dev/null +++ b/mixgtk/mixgtk.c @@ -0,0 +1,91 @@ +/* -*-c-*- -------------- mixgtk.c : + * Main function of the mix gtk front-end + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/14 23:08:50 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include +#include +#include "mixgtk_widgets.h" +#include "mixgtk_cmd_dispatcher.h" +#include "mixgtk_device.h" +#include "mixgtk_mixvm.h" +#include "mixgtk_mixal.h" +#include "mixgtk_input.h" + +int +main(int argc, char *argv[]) +{ + mix_vm_t *vm; + + gtk_init(&argc, &argv); + + mix_init_lib (); + + if (!mixgtk_widget_factory_init (GLADE_FILE) + && !mixgtk_widget_factory_init (LOCAL_GLADE_FILE)) + { + g_error ("Unable to initialise application (using %s and %s)\n", + GLADE_FILE, LOCAL_GLADE_FILE); + return EXIT_FAILURE; + } + + if (!mixgtk_cmd_dispatcher_init ()) + { + g_error ("Unable to initialise application (command dispatcher)\n"); + return EXIT_FAILURE; + } + + vm = mixgtk_cmd_dispatcher_get_vm (); + + if (!mixgtk_device_init (GTK_NOTEBOOK + (mixgtk_widget_factory_get (MIXGTK_WIDGET_DEVICE)), + vm)) + { + g_error ("Unable to initialise application (devices)\n"); + return EXIT_FAILURE; + } + + if (!mixgtk_mixvm_init (vm)) + { + g_error ("Unable to initialise application (mixvm widgets)\n"); + return EXIT_FAILURE; + } + + if (!mixgtk_mixal_init (vm)) + { + g_error ("Unable to initialise application (mixal widgets)\n"); + return EXIT_FAILURE; + } + + if (!mixgtk_input_init ()) + { + g_error ("Unable to initialise application (word input widgets)\n"); + return EXIT_FAILURE; + } + + + gtk_main(); + + mix_release_lib (); + + return EXIT_SUCCESS; +} diff --git a/mixgtk/mixgtk.glade b/mixgtk/mixgtk.glade new file mode 100644 index 0000000..ced029b --- /dev/null +++ b/mixgtk/mixgtk.glade @@ -0,0 +1,1703 @@ + + + + + mixgtk + mixgtk + + src + pixmaps + C + False + False + True + False + False + + + + GtkWindow + main_window + + destroy + on_main_window_destroy + Tue, 20 Feb 2001 21:58:29 GMT + + gmixvm + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 650 + 500 + False + True + True + + + GtkVBox + main_vbox + 2 + False + 2 + + + GtkMenuBar + mainmenubar + GTK_SHADOW_OUT + + 0 + False + True + + + + GtkMenuItem + file + + False + + + GtkMenu + file_menu + + + GtkMenuItem + file_open + Load a MIX file + + GDK_MOD1_MASK + GDK_F3 + activate + + + activate + on_file_open_activate + Tue, 20 Feb 2001 22:37:58 GMT + + + False + + + + GtkMenuItem + file_exit + Exit application + + GDK_MOD1_MASK + GDK_Q + activate + + + activate + on_file_exit_activate + Tue, 20 Feb 2001 22:37:58 GMT + + + False + + + + + + GtkMenuItem + debug + + False + + + GtkMenu + debug_menu + + + GtkMenuItem + debug_run + + GDK_MOD1_MASK + GDK_R + activate + + + activate + on_debug_run_activate + Sat, 10 Mar 2001 11:35:16 GMT + + + False + + + + GtkMenuItem + debug_next + + GDK_MOD1_MASK + GDK_N + activate + + + activate + on_debug_next_activate + Sat, 10 Mar 2001 11:35:16 GMT + + + False + + + + GtkMenuItem + clear_breakpoints + Clear all set breakpoints + + GDK_MOD1_MASK + GDK_C + activate + + + activate + on_clear_breakpoints_activate + Thu, 15 Mar 2001 23:26:49 GMT + + + False + + + + + + GtkMenuItem + help + + True + + + GtkMenu + help_menu + + + GtkMenuItem + about + + activate + on_about_activate + Tue, 13 Mar 2001 01:37:20 GMT + + + True + + + + + + + GtkToolbar + main_toolbar + GTK_ORIENTATION_HORIZONTAL + GTK_TOOLBAR_ICONS + 5 + GTK_TOOLBAR_SPACE_LINE + GTK_RELIEF_NORMAL + True + + 1 + False + False + + + + Placeholder + + + + Placeholder + + + + Placeholder + + + + + GtkVBox + inner_vbox + False + 0 + + 0 + True + True + + + + GtkNotebook + main_notebook + True + True + True + GTK_POS_TOP + False + 2 + 2 + False + + 0 + False + True + + + + GtkFixed + mixvm_widget + 375 + 287 + + + GtkEntry + rJ_entry + 304 + 88 + 60 + 24 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:45:00 GMT + + False + True + 0 + + + + + GtkEntry + rA_entry + 40 + 24 + 120 + 24 + True + + button_press_event + on_register_click + Mon, 12 Mar 2001 23:09:49 GMT + + False + True + 0 + + + + + GtkEntry + rX_entry + 248 + 24 + 120 + 24 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:43:29 GMT + + False + True + 0 + + + + + GtkEntry + rI2_entry + 40 + 144 + 60 + 22 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:45:39 GMT + + False + True + 0 + + + + + GtkEntry + rI1_entry + 40 + 88 + 60 + 24 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:43:44 GMT + + False + True + 0 + + + + + GtkEntry + rI3_entry + 40 + 200 + 60 + 22 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:46:37 GMT + + False + True + 0 + + + + + GtkEntry + rI4_entry + 168 + 88 + 60 + 24 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:44:21 GMT + + False + True + 0 + + + + + GtkEntry + rI6_entry + 168 + 200 + 60 + 22 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:46:58 GMT + + False + True + 0 + + + + + GtkLabel + label100 + 8 + 91 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label102 + 8 + 200 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label101 + 8 + 144 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label103 + 136 + 88 + 32 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label104 + 136 + 144 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label105 + 136 + 200 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label98 + 216 + 24 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label97 + 8 + 24 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkVSeparator + vseparator2 + 0 + 8 + 16 + 263 + + + + GtkHSeparator + hseparator3 + 6 + 1 + 627 + 16 + + + + GtkVSeparator + vseparator3 + 626 + 8 + 16 + 267 + + + + GtkLabel + label99 + 272 + 88 + 31 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkHSeparator + hseparator2 + 6 + 265 + 627 + 16 + + + + GtkLabel + label159 + 8 + 248 + 64 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label158 + 128 + 248 + 64 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label157 + 256 + 248 + 48 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkVSeparator + vseparator1 + 376 + 10 + 16 + 263 + + + + GtkEntry + rI5_entry + 168 + 144 + 60 + 22 + True + + button_press_event + on_register_click + Sun, 11 Mar 2001 11:46:05 GMT + + False + True + 0 + + + + + GtkEntry + loc_entry + 300 + 200 + 40 + 22 + True + False + True + 0 + + + + + GtkLabel + label167 + 256 + 200 + 48 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkButton + loc_arrow + 346 + 202 + 29 + 18 + True + + clicked + on_loc_arrow_clicked + Fri, 09 Mar 2001 20:18:22 GMT + + + GTK_RELIEF_NONE + + + + GtkHSeparator + hseparator1 + 8 + 232 + 377 + 16 + + + + GtkLabel + program_label + 184 + 248 + 56 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + elapsed_label + 64 + 248 + 48 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + uptime_label + 296 + 248 + 72 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkCheckButton + over_toggle + 288 + 168 + 88 + 16 + True + + toggled + on_overflow_toggled + Tue, 06 Mar 2001 21:32:39 GMT + + + False + True + + + + GtkRadioButton + lesser_radio + 264 + 128 + 35 + 24 + Comparison flag: lesser + True + + toggled + on_cmp_l_toggled + Tue, 06 Mar 2001 21:21:51 GMT + + + False + True + cmp_group + + + + GtkRadioButton + equal_radio + 304 + 128 + 31 + 24 + Comparison flag: equal + True + + toggled + on_cmp_e_toggled + Tue, 06 Mar 2001 21:22:04 GMT + + + False + True + cmp_group + + + + GtkRadioButton + greater_radio + 336 + 128 + 32 + 24 + Comparison flag: greater + True + + toggled + on_cmp_g_toggled + Tue, 06 Mar 2001 21:21:40 GMT + + + False + True + cmp_group + + + + GtkScrolledWindow + memory_scroll + 398 + 16 + 225 + 248 + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + + GtkCList + memory_cells + 195 + 248 + Click cell to change value + True + + select_row + on_memory_cells_select_row + True + Tue, 13 Mar 2001 07:38:52 GMT + + + click_column + on_memory_cells_click_column + Wed, 14 Mar 2001 14:18:57 GMT + + 2 + 53,135 + GTK_SELECTION_SINGLE + True + GTK_SHADOW_IN + + + GtkLabel + CList:title + label165 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CList:title + label166 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + + GtkLabel + Notebook:tab + label105 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkScrolledWindow + mixal_scrol + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + + GtkCList + mixal_clist + Click to toggle breakpoint + True + + select_row + on_mixal_select_row + True + Sun, 11 Mar 2001 01:15:28 GMT + + 2 + 152,80 + GTK_SELECTION_SINGLE + True + GTK_SHADOW_IN + + + GtkLabel + CList:title + label213 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + CList:title + label214 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + GtkLabel + Notebook:tab + label106 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkNotebook + devices_notebook + 404 + 254 + True + True + True + GTK_POS_RIGHT + True + 2 + 2 + True + + + Placeholder + + + + GtkLabel + Notebook:tab + label156 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + GtkLabel + Notebook:tab + devices_label + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + GtkScrolledWindow + scrolledwindow25 + 2 + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkViewport + viewport1 + GTK_SHADOW_IN + + + GtkVBox + prompt_vbox + False + 0 + + + GtkScrolledWindow + mixlog_scrolledwindow + GTK_POLICY_NEVER + GTK_POLICY_ALWAYS + GTK_UPDATE_CONTINUOUS + GTK_UPDATE_CONTINUOUS + + 0 + True + True + + + + GtkText + command_log + False + + + + + + GtkEntry + command_prompt + Enter MIXVM command here + True + True + + activate + on_mixvm_cmd_entry_activate + Thu, 22 Feb 2001 23:26:28 GMT + + True + True + 0 + + + 0 + False + False + + + + + + + + + GtkStatusbar + main_statusbar + + 0 + False + False + + + + + + + GtkDialog + word_dialog + False + + destroy + gtk_widget_hide + Tue, 13 Mar 2001 00:53:39 GMT + + + destroy_event + gtk_widget_hide + Tue, 13 Mar 2001 00:55:38 GMT + + + delete_event + gtk_widget_hide + Tue, 13 Mar 2001 00:56:33 GMT + + Enter value + GTK_WINDOW_DIALOG + GTK_WIN_POS_MOUSE + True + 250 + False + False + False + + + GtkVBox + Dialog:vbox + dialog-vbox5 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area5 + 10 + 250 + True + 5 + + 0 + False + False + GTK_PACK_END + + + + GtkHButtonBox + hbuttonbox5 + 250 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + False + False + + + + GtkButton + word_reset + True + True + + clicked + on_word_reset_clicked + Mon, 12 Mar 2001 22:40:33 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + word_ok + True + True + + clicked + on_word_ok_clicked + Mon, 12 Mar 2001 22:40:45 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + word_cancel + True + True + + clicked + on_word_cancel_clicked + Mon, 12 Mar 2001 23:18:49 GMT + + + GTK_RELIEF_NORMAL + + + + + + GtkFixed + word_layout + 250 + 97 + + 0 + False + False + + + + GtkEntry + word_decimal + 88 + 32 + 143 + 22 + True + True + + key_press_event + on_word_dec_key_press + True + Mon, 12 Mar 2001 22:37:13 GMT + + True + True + 11 + 0 + + + + GtkEntry + word_b2 + 136 + 64 + 22 + 22 + True + + key_press_event + on_word_byte_key_press + True + Mon, 12 Mar 2001 22:38:56 GMT + + True + True + 3 + 00 + + + + GtkEntry + word_b3 + 160 + 64 + 22 + 22 + True + + key_press_event + on_word_byte_key_press + True + Mon, 12 Mar 2001 22:39:26 GMT + + True + True + 3 + 00 + + + + GtkEntry + word_b4 + 184 + 64 + 22 + 22 + True + + key_press_event + on_word_byte_key_press + True + Mon, 12 Mar 2001 22:39:50 GMT + + True + True + 3 + 00 + + + + GtkEntry + word_b5 + 208 + 64 + 22 + 22 + True + + key_press_event + on_word_byte_key_press + True + Mon, 12 Mar 2001 22:40:09 GMT + + True + True + 3 + 00 + + + + GtkEntry + word_b1 + 112 + 64 + 22 + 22 + True + True + + key_press_event + on_word_byte_key_press + True + Mon, 12 Mar 2001 22:38:24 GMT + + True + True + 3 + 00 + + + + GtkEntry + word_sign + 88 + 64 + 16 + 24 + True + + key_press_event + on_word_sign_key_press + Tue, 13 Mar 2001 00:15:28 GMT + + True + True + 1 + + + + + + GtkLabel + label61 + 22 + 67 + 41 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + word_label + 16 + 8 + 216 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label60 + 16 + 34 + 67 + 20 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + + + + GtkWindow + about_dialog + 368 + 99 + False + + delete_event + gtk_widget_hide + Tue, 13 Mar 2001 13:13:42 GMT + + + destroy_event + gtk_widget_hide + Tue, 13 Mar 2001 13:14:02 GMT + + + destroy + gtk_widget_hide + Tue, 13 Mar 2001 13:14:25 GMT + + MDK + GTK_WINDOW_DIALOG + GTK_WIN_POS_CENTER + True + False + False + False + + + GtkLayout + layout1 + 375 + 190 + 200 + 120 + 0 + 0 + + + GtkLabel + label222 + 56 + 16 + 247 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + version_label + 152 + 40 + 56 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkLabel + label224 + 0 + 64 + 358 + 16 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + + + GtkHSeparator + hseparator4 + 8 + 0 + 356 + 16 + + + + GtkHSeparator + hseparator5 + 8 + 80 + 356 + 16 + + + + GtkVSeparator + vseparator4 + 0 + 7 + 16 + 83 + + + + GtkVSeparator + vseparator5 + 352 + 8 + 16 + 83 + + + + + + GtkDialog + goto_dialog + 190 + 116 + False + + destroy_event + gtk_widget_hide + Wed, 14 Mar 2001 14:39:17 GMT + + + delete_event + gtk_widget_hide + Wed, 14 Mar 2001 14:39:41 GMT + + + destroy + gtk_widget_hide + Wed, 14 Mar 2001 14:40:15 GMT + + Go to memory cell + GTK_WINDOW_DIALOG + GTK_WIN_POS_MOUSE + True + False + False + False + + + GtkVBox + Dialog:vbox + dialog-vbox6 + False + 0 + + + GtkHBox + Dialog:action_area + dialog-action_area6 + 10 + True + 5 + + 0 + False + True + GTK_PACK_END + + + + GtkHButtonBox + hbuttonbox6 + GTK_BUTTONBOX_DEFAULT_STYLE + 30 + 85 + 27 + 7 + 0 + + 0 + True + True + + + + GtkButton + goto_cancel + True + True + + clicked + on_goto_cancel_clicked + Wed, 14 Mar 2001 14:24:59 GMT + + + GTK_RELIEF_NORMAL + + + + GtkButton + goto_ok + True + True + + clicked + on_goto_ok_clicked + Wed, 14 Mar 2001 14:25:23 GMT + + + GTK_RELIEF_NORMAL + + + + + + GtkVBox + vbox1 + 12 + False + 0 + + 0 + False + False + + + + GtkLabel + label225 + + GTK_JUSTIFY_CENTER + False + 0.5 + 0.5 + 0 + 0 + + 0 + True + True + + + + + GtkEntry + goto_entry + 44 + True + True + + activate + on_goto_ok_clicked + Wed, 14 Mar 2001 14:52:26 GMT + + True + True + 4 + + + 10 + False + False + + + + + + + diff --git a/mixgtk/mixgtk_cmd_dispatcher.c b/mixgtk/mixgtk_cmd_dispatcher.c new file mode 100644 index 0000000..11acc1d --- /dev/null +++ b/mixgtk/mixgtk_cmd_dispatcher.c @@ -0,0 +1,314 @@ +/* -*-c-*- -------------- mixgtk_cmd_dispatcher.c : + * Implementation of the functions declared in mixgtk_cmd_dispatcher.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/15 16:01:43 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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. + * + */ + +#define _GNU_SOURCE 1 + +#include +#include +#include +#include "mixgtk_cmd_dispatcher.h" +#include "mixgtk_mixvm.h" +#include "mixgtk_mixal.h" + + +/* a mix vm command dispatcher */ +struct mixgtk_dispatch_ +{ + mix_vm_cmd_dispatcher_t *dispatcher; + FILE *out; + char *out_buffer; + size_t out_buffer_size; + GtkWidget *prompt; + GtkWidget *log; + GtkWidget *status; + guint context; + GCompletion *completions; +}; + +static struct mixgtk_dispatch_ dis_data_ = {NULL}; + +/* completions */ +static void +init_completions_ (void) +{ + GList *cmds = NULL; + gint k; + + dis_data_.completions = g_completion_new (NULL); + for (k = 0; k < MIX_CMD_INVALID; ++k) + cmds = g_list_append (cmds, (gpointer) mix_vm_command_to_string (k)); + g_completion_add_items (dis_data_.completions, cmds); +} + +/* global hooks for the command dispatcher */ +static void +global_pre_hook_ (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg, gpointer data) +{ + if (cmd < MIX_CMD_INVALID) + { + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + "MIX> ", -1); + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + mix_vm_command_to_string (cmd), -1); + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + " ", -1); + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + arg, -1); + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + "\n", -1); + } + else + { + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + _("\n*** Invalid command ***\n"), -1); + } +} + +static void +global_post_hook_ (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg, gpointer data) +{ + fflush (dis_data_.out); + if (cmd < MIX_CMD_INVALID) + { + gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, + dis_data_.out_buffer, dis_data_.out_buffer_size); + } + rewind (dis_data_.out); + mixgtk_mixvm_update_vm_widgets (); +} + +static void +load_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, + gpointer data) +{ + static glong id = -1; + + if (mix_vm_cmd_dispatcher_get_last_result (dis)) + { + gchar *file = g_strdup (arg); + mixgtk_mixal_load_file (); + mixgtk_mixal_update (); + + if (id != -1) + gtk_statusbar_remove (GTK_STATUSBAR (dis_data_.status), + dis_data_.context, (guint)id); + id = + gtk_statusbar_push (GTK_STATUSBAR (dis_data_.status), dis_data_.context, + file); + } +} + +static void +run_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, + gpointer data) +{ + mixgtk_mixal_update (); +} + +static void +next_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, + gpointer data) +{ + mixgtk_mixal_update (); +} + +static void +linebp_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, + gpointer data) +{ + if (arg && strlen (arg)) mixgtk_mixal_update_bp_at_line (atoi (arg)); +} + +static void +addrbp_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, + gpointer data) +{ + if (arg && strlen (arg)) mixgtk_mixal_update_bp_at_address (atoi (arg)); +} + +static void +allbp_post_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, + gpointer data) +{ + mixgtk_mixal_update_bp_all (); +} + + +static void +install_hooks_ (void) +{ + mix_vm_cmd_dispatcher_global_pre_hook (dis_data_.dispatcher, + global_pre_hook_, NULL); + mix_vm_cmd_dispatcher_global_post_hook (dis_data_.dispatcher, + global_post_hook_, NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_LOAD, load_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_RUN, run_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_NEXT, next_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_SBP, linebp_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_CBP, linebp_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_SBPA, addrbp_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_CBPA, addrbp_post_hook_, + NULL); + mix_vm_cmd_dispatcher_post_hook (dis_data_.dispatcher, + MIX_CMD_CABP, allbp_post_hook_, + NULL); +} + + +/* initialise the command dispatcher */ +gboolean +mixgtk_cmd_dispatcher_init (void) +{ + if (!dis_data_.prompt) + { + dis_data_.prompt = mixgtk_widget_factory_get (MIXGTK_WIDGET_PROMPT); + g_return_val_if_fail (dis_data_.prompt != NULL, FALSE); + dis_data_.log = mixgtk_widget_factory_get (MIXGTK_WIDGET_LOG); + g_return_val_if_fail (dis_data_.log != NULL, FALSE); + } + + if (!dis_data_.dispatcher) + { + FILE *out = open_memstream (&(dis_data_.out_buffer), + &(dis_data_.out_buffer_size)); + g_return_val_if_fail (out != NULL, FALSE); + dis_data_.out = out; + dis_data_.dispatcher = mix_vm_cmd_dispatcher_new (out, out); + mix_vm_cmd_dispatcher_print_time (dis_data_.dispatcher, FALSE); + install_hooks_ (); + } + + if (!dis_data_.status) + { + dis_data_.status = mixgtk_widget_factory_get (MIXGTK_WIDGET_STATUSBAR); + g_return_val_if_fail (dis_data_.status != NULL, FALSE); + dis_data_.context = gtk_statusbar_get_context_id (GTK_STATUSBAR + (dis_data_.status), + "cmd_dis_context"); + } + + if (!dis_data_.completions) init_completions_ (); + + return TRUE; +} + +/* dispatch an externally provided command */ +void +mixgtk_cmd_dispatcher_dispatch (const gchar *command) +{ + GtkWidget *entry = dis_data_.prompt; + g_return_if_fail (command != NULL); + g_assert (entry != NULL); + gtk_entry_set_text (GTK_ENTRY (entry), command); + on_mixvm_cmd_entry_activate (entry, NULL); +} + +/* get times */ +void +mixgtk_cmd_dispatcher_get_times (gint *uptime, gint *progtime, gint *laptime) +{ + if (uptime != NULL) + *uptime = mix_vm_cmd_dispatcher_get_uptime (dis_data_.dispatcher); + if (progtime != NULL) + *progtime = mix_vm_cmd_dispatcher_get_progtime (dis_data_.dispatcher); + if (laptime != NULL) + *laptime = mix_vm_cmd_dispatcher_get_laptime (dis_data_.dispatcher); +} + +/* get the underlying vm */ +extern mix_vm_t * +mixgtk_cmd_dispatcher_get_vm (void) +{ + return (mix_vm_t *) mix_vm_cmd_dispatcher_get_vm (dis_data_.dispatcher); +} + +/* process new command */ +void +on_mixvm_cmd_entry_activate (GtkWidget *w, gpointer e) +{ + gchar *text; + GList *cmds = NULL; + gchar *prefix = NULL; + + text = gtk_entry_get_text (GTK_ENTRY (w)); + + if (mix_vm_command_from_string (g_strchomp (text)) != MIX_CMD_INVALID) + { + mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text); + gtk_entry_set_text (GTK_ENTRY (w), ""); + return; + } + + cmds = g_completion_complete (dis_data_.completions, text, &prefix); + + if (prefix != NULL) + { + gtk_entry_set_text (GTK_ENTRY (w), prefix); + g_free (prefix); + if (g_list_length (cmds) > 1) + { + gint k = 0; + gtk_text_insert (GTK_TEXT (dis_data_.log), + NULL, NULL, NULL, "Completions:\n", -1); + while (cmds) + { + ++k; + gtk_text_insert (GTK_TEXT (dis_data_.log), + NULL, NULL, NULL, + (gchar *)(cmds->data), -1); + gtk_text_insert (GTK_TEXT (dis_data_.log), + NULL, NULL, NULL, " ", -1); + if (k%5 == 0) + gtk_text_insert (GTK_TEXT (dis_data_.log), + NULL, NULL, NULL, "\n", -1); + + cmds = cmds->next; + } + if (k%5 != 0) + gtk_text_insert (GTK_TEXT (dis_data_.log), + NULL, NULL, NULL, "\n", -1); + } + else + gtk_entry_append_text (GTK_ENTRY (w), " "); + } + else + { + mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text); + gtk_entry_set_text (GTK_ENTRY (w), ""); + } +} diff --git a/mixgtk/mixgtk_cmd_dispatcher.h b/mixgtk/mixgtk_cmd_dispatcher.h new file mode 100644 index 0000000..686ba4d --- /dev/null +++ b/mixgtk/mixgtk_cmd_dispatcher.h @@ -0,0 +1,55 @@ +/* -*-c-*- ---------------- mixgtk_cmd_dispatcher.h : + * functions to access the command dispatcher + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/09 22:08:08 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_CMD_DISPATCHER_H +#define MIXGTK_CMD_DISPATCHER_H + +#include +#include "mixgtk_widgets.h" + +/* initialise the command dispatcher */ +extern gboolean +mixgtk_cmd_dispatcher_init (void); + +/* dispatch an externally provided command */ +extern void +mixgtk_cmd_dispatcher_dispatch (const gchar *command); + +/* get times */ +extern void +mixgtk_cmd_dispatcher_get_times (gint *uptime, gint *progtime, gint *laptime); + +/* get the underlying vm */ +extern mix_vm_t * +mixgtk_cmd_dispatcher_get_vm (void); + +/* make gtk signal callbacks accessible to glade */ +/* new command handler */ +extern void +on_mixvm_cmd_entry_activate (GtkWidget *w, gpointer e); + + + +#endif /* MIXGTK_CMD_DISPATCHER_H */ + diff --git a/mixgtk/mixgtk_device.c b/mixgtk/mixgtk_device.c new file mode 100644 index 0000000..2e231a4 --- /dev/null +++ b/mixgtk/mixgtk_device.c @@ -0,0 +1,155 @@ +/* -*-c-*- ---------------- mixgtk_device.c : + * actual types for mixgtk devices + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/05 01:13:40 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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. + * + */ + + +#define _GNU_SOURCE 1 + +#include +#include +#include "mixgtk_device.h" + +/* device container */ +static GtkNotebook *container_ = NULL; +/* virtual machine */ +static mix_vm_t *vm_ = NULL; + +/* a mixgtk device */ +struct mixgtk_device_t +{ + mix_device_t device; + char *buffer; + size_t buffer_len; + GtkText *widget; + gint pos; +}; + +/* callbacks for output devices */ +static gboolean +write_out_ (mix_device_t *dev, const mix_word_t *block) +{ + struct mixgtk_device_t *gtkdev; + + if (!((DEF_DEV_VTABLE_->write) (dev, block))) return FALSE; + gtkdev = (struct mixgtk_device_t *) dev; + if (gtkdev->buffer_len > 0) + { + gtk_text_insert (gtkdev->widget, NULL, NULL, NULL, + gtkdev->buffer, gtkdev->buffer_len); + rewind (mix_io_to_FILE (gtkdev->device.file)); + gtk_notebook_set_page (container_, gtkdev->pos); + gtk_widget_draw (GTK_WIDGET (container_), NULL); + } + return TRUE; +} + +static mix_device_vtable_t MIXGTK_OUT_VTABLE_; + +/* create a new mixgtk device */ +static struct mixgtk_device_t * +mixgtk_device_new_ (mix_device_type_t type) +{ + struct mixgtk_device_t *dev = NULL; + + g_return_val_if_fail (type < mix_dev_INVALID, NULL); + + if (MODES_[type] == mix_dev_CHAR && FMODES_[type] == mix_io_WRITE) + { + FILE *f; + dev = g_new (struct mixgtk_device_t, 1); + f = open_memstream (&(dev->buffer), &(dev->buffer_len)); + g_assert (f); + dev->device.file = mix_io_new (f); + dev->device.type = type; + dev->device.vtable = &MIXGTK_OUT_VTABLE_; + dev->widget = (GtkText *)gtk_text_new (NULL, NULL); + g_assert (dev->widget); + gtk_text_set_editable (dev->widget, FALSE); + } + return dev; +} + +/* connect a device */ +static void +mixgtk_device_connect_ (struct mixgtk_device_t *dev) +{ + static gint last_pos = 0; + GtkWidget *label = gtk_label_new (DEF_NAMES_[dev->device.type]); + GtkWidget *box = gtk_hbox_new (0, 0); + GtkWidget *scroll = gtk_vscrollbar_new (dev->widget->vadj); + g_assert (label); + g_assert (box); + gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET (dev->widget), + TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (box), scroll, FALSE, FALSE, 0); + dev->pos = last_pos++; + gtk_notebook_insert_page (container_, box, label, dev->pos); + gtk_widget_show (box); + gtk_widget_show (label); + gtk_widget_show (scroll); + gtk_widget_show (GTK_WIDGET (dev->widget)); + gtk_widget_draw (GTK_WIDGET (container_), NULL); + (void) mix_vm_connect_device (vm_, (mix_device_t *)dev); +} + +/* init default devices */ +gboolean +mixgtk_device_init (GtkNotebook *container, mix_vm_t *vm) +{ + static mix_device_type_t def_types[] = { + mix_dev_CONSOLE, mix_dev_PRINTER, mix_dev_PAPER_TAPE, mix_dev_INVALID + }; + + gint k = 0; + + g_return_val_if_fail (container != NULL, FALSE); + g_return_val_if_fail (vm != NULL, FALSE); + container_ = container; + vm_ = vm; + + /* remove dummy page from container */ + gtk_notebook_remove_page (container_, 0); + + /* initialise vtables */ + MIXGTK_OUT_VTABLE_.write = write_out_; + MIXGTK_OUT_VTABLE_.read = DEF_DEV_VTABLE_->read; + MIXGTK_OUT_VTABLE_.ioc = DEF_DEV_VTABLE_->ioc; + MIXGTK_OUT_VTABLE_.busy = DEF_DEV_VTABLE_->busy; + + /* connect default devices */ + while (def_types[k] != mix_dev_INVALID) + { + struct mixgtk_device_t *dev = mixgtk_device_new_ (def_types[k]); + if (dev != NULL) + mixgtk_device_connect_ (dev); + ++k; + } + + /* set to first page */ + gtk_notebook_set_page (container_, 0); + + return TRUE; +} + +/* connect a new (file-based) device */ +gboolean +mixgtk_device_connect (mix_device_type_t type, const gchar *name); diff --git a/mixgtk/mixgtk_device.h b/mixgtk/mixgtk_device.h new file mode 100644 index 0000000..7c21238 --- /dev/null +++ b/mixgtk/mixgtk_device.h @@ -0,0 +1,42 @@ +/* -*-c-*- ---------------- mixgtk_device.h : + * Block devices used by mixgtk + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/04 23:43:59 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_DEVICE_H +#define MIXGTK_DEVICE_H + +#include +#include +#include + +/* init default devices */ +extern gboolean +mixgtk_device_init (GtkNotebook *container, mix_vm_t *vm); + + +/* connect a new (file-based) device */ +extern gboolean +mixgtk_device_connect (mix_device_type_t type, const gchar *name); + +#endif /* MIXGTK_DEVICE_H */ + diff --git a/mixgtk/mixgtk_gen_handlers.c b/mixgtk/mixgtk_gen_handlers.c new file mode 100644 index 0000000..9f23310 --- /dev/null +++ b/mixgtk/mixgtk_gen_handlers.c @@ -0,0 +1,95 @@ +/* -*-c-*- -------------- mixgtk_gen_handlers.c : + * Implementation of the functions declared in mixgtk_gen_handlers.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/16 00:30:40 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include "mixgtk_gen_handlers.h" +#include "mixgtk_cmd_dispatcher.h" + +void +on_main_window_destroy (GtkWidget *w, gpointer data) +{ + gtk_main_quit (); +} + +static void +on_file_open_ok_ (GtkWidget *w, gpointer fs) +{ + const gchar *file = gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs)); + gchar *command = g_strdup_printf ("%s %s", + mix_vm_command_to_string (MIX_CMD_LOAD), + file); + gtk_widget_destroy (GTK_WIDGET (fs)); + mixgtk_cmd_dispatcher_dispatch (command); + g_free (command); +} + +static void +on_file_open_destroy_ (GtkWidget *w, gpointer data) +{ + gtk_grab_remove (GTK_WIDGET (w)); +} + +void +on_file_open_activate (GtkWidget *w, gpointer data) +{ + GtkWidget *file = gtk_file_selection_new ("Open program"); + gtk_signal_connect (GTK_OBJECT (file), "destroy", + (GtkSignalFunc) on_file_open_destroy_, + GTK_OBJECT (file)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file)->ok_button), + "clicked", (GtkSignalFunc) on_file_open_ok_, + GTK_OBJECT (file)); + gtk_signal_connect_object (GTK_OBJECT (GTK_FILE_SELECTION + (file)->cancel_button), + "clicked", (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (file)); + gtk_widget_show (file); + gtk_grab_add (file); +} + +void +on_debug_run_activate (GtkWidget *w, gpointer p) +{ + mixgtk_cmd_dispatcher_dispatch (mix_vm_command_to_string (MIX_CMD_RUN)); +} + +void +on_debug_next_activate (GtkWidget *w, gpointer p) +{ + mixgtk_cmd_dispatcher_dispatch (mix_vm_command_to_string (MIX_CMD_NEXT)); +} + + +void +on_file_exit_activate (GtkWidget *w, gpointer data) +{ + gtk_main_quit (); +} + + +void +on_clear_breakpoints_activate (GtkWidget *w, gpointer data) +{ + mixgtk_cmd_dispatcher_dispatch (mix_vm_command_to_string (MIX_CMD_CABP)); +} + diff --git a/mixgtk/mixgtk_gen_handlers.h b/mixgtk/mixgtk_gen_handlers.h new file mode 100644 index 0000000..6e0a45d --- /dev/null +++ b/mixgtk/mixgtk_gen_handlers.h @@ -0,0 +1,46 @@ +/* -*-c-*- ---------------- mixgtk_gen_handlers.h : + * general signal handlers declarations + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/16 00:29:45 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_GEN_HANDLERS_H +#define MIXGTK_GEN_HANDLERS_H + +#include + +extern void +on_main_window_destroy (GtkWidget *w, gpointer data); + +extern void +on_file_open_activate (GtkWidget *w, gpointer data); + +extern void +on_file_exit_activate (GtkWidget *w, gpointer data); + +extern void +on_clear_breakpoints_activate (GtkWidget *w, gpointer data); + + + + +#endif /* MIXGTK_GEN_HANDLERS_H */ + diff --git a/mixgtk/mixgtk_input.c b/mixgtk/mixgtk_input.c new file mode 100644 index 0000000..fa98056 --- /dev/null +++ b/mixgtk/mixgtk_input.c @@ -0,0 +1,189 @@ +/* -*-c-*- -------------- mixgtk_input.c : + * Implementation of the functions declared in mixgtk_input.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/13 08:31:20 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include +#include "mixgtk_widgets.h" +#include "mixgtk_input.h" + +enum { + MSG_, SIGN_, B1_, B2_, B3_, B4_, B5_, DEC_, RESET_, OK_, SIZE_ +}; + +static const gchar *WGT_NAMES_[SIZE_] = { + "word_label", "word_sign", "word_b1", "word_b2", "word_b3", + "word_b4", "word_b5", "word_decimal", "word_reset", "word_ok" +}; + +static GtkDialog *dialog_; +static GtkWidget *childs_[SIZE_]; +static input_callback_t callback_; +static gpointer data_; + +/* init */ +extern gboolean +mixgtk_input_init (void) +{ + gint k; + + dialog_ = GTK_DIALOG (mixgtk_widget_factory_get (MIXGTK_WIDGET_WORD_DIALOG)); + g_return_val_if_fail (dialog_ != NULL, FALSE); + for (k = 0; k < SIZE_; ++k) + { + childs_[k] = mixgtk_widget_factory_get_by_name (WGT_NAMES_[k]); + g_return_val_if_fail (childs_[k] != NULL, FALSE); + } + return TRUE; + +} + +static void +set_word_ (mix_word_t word) +{ + enum {SIZE = 50}; + static gchar BUFFER[SIZE] = {0}; + gint k; + gint val = mix_word_magnitude (word); + gboolean neg = mix_word_is_negative (word); + snprintf (BUFFER, SIZE, "%s%d", neg ? "-" : "", val); + gtk_entry_set_text (GTK_ENTRY (childs_[DEC_]), BUFFER); + gtk_entry_set_text (GTK_ENTRY (childs_[SIGN_]), neg ? "-" : "+"); + for (k = 1; k < 6; ++k) + { + mix_byte_t b = mix_word_get_byte (word, k); + snprintf (BUFFER, SIZE, "%d", (int)b); + gtk_entry_set_text (GTK_ENTRY (childs_[SIGN_ + k]), BUFFER); + } +} + + +/* get a word */ +void +mixgtk_input_word (const gchar *message, mix_word_t def, + input_callback_t cb, gpointer data) +{ + gtk_label_set_text (GTK_LABEL (childs_[MSG_]), message); + set_word_ (def); + callback_ = cb; + data_ = data; + gtk_widget_show (childs_[B1_]); + gtk_widget_show (childs_[B2_]); + gtk_widget_show (childs_[B3_]); + gtk_widget_show (GTK_WIDGET (dialog_)); +} + +/* get a short */ +void +mixgtk_input_short (const gchar *message, mix_short_t def, + input_callback_t cb, gpointer data) +{ + gtk_label_set_text (GTK_LABEL (childs_[MSG_]), message); + set_word_ (mix_word_to_short_fast (def)); + callback_ = cb; + data_ = data; + gtk_widget_show (GTK_WIDGET (dialog_)); + gtk_widget_hide (childs_[B1_]); + gtk_widget_hide (childs_[B2_]); + gtk_widget_hide (childs_[B3_]); +} + +#include + +/* dec and bytes input handler */ +gboolean +on_word_dec_key_press (GtkWidget *dec, GdkEvent *event, gpointer *data) +{ + GdkEventKey *key = (GdkEventKey *)event; + if (key->string && strlen (key->string) > 0 && !iscntrl (key->string[0])) + { + gchar *text = gtk_entry_get_text (GTK_ENTRY (childs_[DEC_])); + gint val = atoi (text); + set_word_ (mix_word_new (val)); + } + return FALSE; +} + +gboolean +on_word_byte_key_press (GtkWidget *widget, GdkEvent *event, gpointer *data) +{ + GdkEventKey *key = (GdkEventKey *)event; + if (key->string && strlen (key->string) > 0 && !iscntrl (key->string[0])) + { + mix_byte_t bytes[5]; + gint k; + gchar *s; + mix_word_t w; + + for (k = 0; k < 5; ++k) + { + gchar *text = gtk_entry_get_text (GTK_ENTRY (childs_[B1_ + k])); + bytes[k] = mix_byte_new (atoi (text)); + } + w = mix_bytes_to_word (bytes, 5); + s = gtk_entry_get_text (GTK_ENTRY (childs_[SIGN_])); + if (s && s[0] == '-') mix_word_reverse_sign (w); + set_word_ (w); + } + return FALSE; +} + +gboolean +on_word_sign_key_press (GtkWidget *widget, GdkEvent *event, gpointer *data) +{ + GdkEventKey *key = (GdkEventKey *)event; + if (key->string && strlen (key->string) > 0 && !iscntrl (key->string[0])) + { + gchar s = key->string[0]; + gchar *txt = gtk_entry_get_text (GTK_ENTRY (childs_[SIGN_])); + gchar c = txt ? txt[0] : '+'; + if ( (s == '+' || s == '-') && s != c) + { + mix_word_t w = + mix_word_new (atoi + (gtk_entry_get_text (GTK_ENTRY (childs_[DEC_])))); + set_word_ (mix_word_negative (w)); + } + } + return FALSE; +} + +void +on_word_ok_clicked (GtkWidget *widget, gpointer *data) +{ + const gchar *text = gtk_entry_get_text (GTK_ENTRY (childs_[DEC_])); + mix_word_t w = mix_word_new (atoi (text)); + callback_ (w, data_); + gtk_widget_hide (GTK_WIDGET (dialog_)); +} + +void +on_word_cancel_clicked (GtkWidget *widget, gpointer *data) +{ + gtk_widget_hide (GTK_WIDGET (dialog_)); +} + +void +on_word_reset_clicked (GtkWidget *w, gpointer *data) +{ + set_word_ (MIX_WORD_ZERO); +} diff --git a/mixgtk/mixgtk_input.h b/mixgtk/mixgtk_input.h new file mode 100644 index 0000000..275894d --- /dev/null +++ b/mixgtk/mixgtk_input.h @@ -0,0 +1,49 @@ +/* -*-c-*- ---------------- mixgtk_input.h : + * Declaration of functions for user input + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/12 23:35:14 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_INPUT_H +#define MIXGTK_INPUT_H + +#include + +/* callback function type */ +typedef void (*input_callback_t)(mix_word_t result, gpointer data); + +/* init */ +extern gboolean +mixgtk_input_init (void); + +/* get a word */ +extern void +mixgtk_input_word (const gchar *message, mix_word_t def, + input_callback_t cb, gpointer data); + +/* get a short */ +extern void +mixgtk_input_short (const gchar *message, mix_short_t def, + input_callback_t cb, gpointer data ); + + +#endif /* MIXGTK_INPUT_H */ + diff --git a/mixgtk/mixgtk_mixal.c b/mixgtk/mixgtk_mixal.c new file mode 100644 index 0000000..b59688d --- /dev/null +++ b/mixgtk/mixgtk_mixal.c @@ -0,0 +1,213 @@ +/* -*-c-*- -------------- mixgtk_mixal.c : + * Implementation of the functions declared in mixgtk_mixal.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/12 23:48:29 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include "mixgtk_widgets.h" +#include "mixgtk_mixal.h" + + +static mix_vm_t *vm_; +static GtkCList *clist_; +static GdkColor sel_color_; +static GdkColor break_color_; +static GdkColor plain_color_; +static gulong lineno_; + +#define SEL_COLOR_ "lightgrey" +#define BREAK_COLOR_ "red" +#define PLAIN_COLOR_ "white" + +static gboolean +init_color_ (GdkColor *c, const gchar *name) +{ + static GdkColormap *cmap = NULL; + if (!cmap) cmap = gtk_widget_get_colormap (GTK_WIDGET (clist_)); + return (gdk_color_parse (name, c) && + gdk_colormap_alloc_color (cmap, c, FALSE, TRUE)); +} + +/* initialise the mixal widgets */ +gboolean +mixgtk_mixal_init (mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, FALSE); + vm_ = vm; + clist_ = GTK_CLIST (mixgtk_widget_factory_get (MIXGTK_WIDGET_MIXAL)); + g_return_val_if_fail (clist_ != NULL, FALSE); + + /* allocate colors */ + g_return_val_if_fail (init_color_ (&sel_color_, SEL_COLOR_), FALSE); + g_return_val_if_fail (init_color_ (&break_color_, BREAK_COLOR_), FALSE); + g_return_val_if_fail (init_color_ (&plain_color_, PLAIN_COLOR_), FALSE); + + return TRUE; +} + +/* load the corresponding mixal file */ +void +mixgtk_mixal_load_file (void) +{ + enum {ADDR_SIZE = 20, CONT_SIZE = 200}; + static gchar ADDR[ADDR_SIZE], CONT[CONT_SIZE]; + static gchar *TEXT[] = {ADDR, CONT}; + static gchar *NULL_TEXT[] = {NULL, NULL}; + + const mix_src_file_t *file; + + g_assert (vm_); + g_assert (clist_); + + gtk_clist_clear (clist_); + + file = mix_vm_get_src_file (vm_); + if (file != NULL) + { + gint k; + mix_address_t addr; + + lineno_ = mix_src_file_get_line_no (file); + + gtk_clist_freeze (clist_); + for (k = 0; k < lineno_; ++k) + { + const gchar *line = mix_src_file_get_line (file, k + 1); + snprintf (CONT, CONT_SIZE, "%03d: %s", k + 1, line); + addr = mix_vm_get_lineno_address (vm_, k + 1); + if (addr != MIX_VM_CELL_NO) + { + sprintf (ADDR, "%04d: ", mix_short_magnitude (addr)); + mix_word_print_to_buffer (mix_vm_get_addr_contents (vm_, addr), + ADDR + strlen (ADDR)); + } + else + ADDR[0] = '\0'; + gtk_clist_append (clist_, TEXT); + gtk_clist_set_row_data (clist_, k, GINT_TO_POINTER + (mix_short_magnitude (addr))); + } + gtk_clist_append (clist_, NULL_TEXT); + gtk_clist_set_row_data (clist_, k, GINT_TO_POINTER (MIX_VM_CELL_NO)); + gtk_clist_unselect_row (clist_, 0, 0); + gtk_clist_thaw (clist_); + } + else + lineno_ = 0; +} + + +/* update the widgets */ +static void +reset_bg_ (gint row) +{ + gint addr = GPOINTER_TO_INT (gtk_clist_get_row_data (clist_, row)); + gboolean isset = mix_vm_has_breakpoint_at_address (vm_, addr); + gtk_clist_set_background (clist_, row, + isset ? &break_color_ : &plain_color_); +} + +static void +select_row_ (gint row) +{ + static gint last = -1; + + gtk_clist_set_background (clist_, row, &sel_color_); + if (gtk_clist_row_is_visible (clist_, row) != GTK_VISIBILITY_FULL) + gtk_clist_moveto (clist_, row, 0, 0.25, 0); + if (last != -1 && last != row) reset_bg_ (last); + last = row; +} + +void +mixgtk_mixal_update (void) +{ + gint addr = 0; + gint k = 0; + + g_assert (vm_); + g_assert (clist_); + + addr = mix_short_magnitude (mix_vm_get_prog_count (vm_)); + k = gtk_clist_find_row_from_data (clist_, GINT_TO_POINTER (addr)); + select_row_ (k); +} + +/* breakpoints */ +void +mixgtk_mixal_update_bp_at_address (guint addr) +{ + gint k; + + g_assert (vm_); + g_assert (clist_); + + k = gtk_clist_find_row_from_data (clist_, GINT_TO_POINTER (addr)); + reset_bg_ (k); +} + +void +mixgtk_mixal_update_bp_at_line (guint line) +{ + if ( line < 1 ) return; + + while (line < lineno_) + { + gint addr = GPOINTER_TO_INT (gtk_clist_get_row_data (clist_, line - 1)); + if (addr != MIX_VM_CELL_NO) break; + ++line; + } + reset_bg_ (line - 1); +} + +void +mixgtk_mixal_update_bp_all () +{ + gint k, addr; + for (k = 0; k < lineno_; ++k) reset_bg_ (k); + addr = mix_vm_get_prog_count (vm_); + k = gtk_clist_find_row_from_data (clist_, GINT_TO_POINTER (addr)); + select_row_ (k); +} + +/* callbacks */ +void +on_mixal_select_row (GtkWidget *w, gint row, gint col, GdkEventButton *e, + gpointer data) +{ + gboolean isset; + gint addr, pc; + + gtk_clist_unselect_row (clist_, row, col); + addr = GPOINTER_TO_INT (gtk_clist_get_row_data (clist_, row)); + pc = mix_vm_get_prog_count (vm_); + if (addr < MIX_VM_CELL_NO && addr != pc) + { + isset = mix_vm_has_breakpoint_at_address (vm_, addr); + if (isset) + mix_vm_clear_breakpoint_address (vm_, addr); + else + mix_vm_set_breakpoint_address (vm_, addr); + reset_bg_ (row); + } +} + diff --git a/mixgtk/mixgtk_mixal.h b/mixgtk/mixgtk_mixal.h new file mode 100644 index 0000000..819819a --- /dev/null +++ b/mixgtk/mixgtk_mixal.h @@ -0,0 +1,60 @@ +/* -*-c-*- ---------------- mixgtk_mixal.h : + * Declarations for functions displaying the mixal source file + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/11 00:19:30 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_MIXAL_H +#define MIXGTK_MIXAL_H + +#include +#include + +/* initialise the mixal widget */ +extern gboolean +mixgtk_mixal_init (mix_vm_t *vm); + +/* load the corresponding mixal file */ +extern void +mixgtk_mixal_load_file (void); + +/* update the widget */ +extern void +mixgtk_mixal_update (void); + +/* breakpoints */ +extern void +mixgtk_mixal_update_bp_at_address (guint addr); + +extern void +mixgtk_mixal_update_bp_at_line (guint line); + +extern void +mixgtk_mixal_update_bp_all (void); + + +/* callbacks */ +extern void +on_mixal_select_row (GtkWidget *w, gint row, gint col, GdkEventButton *e, + gpointer data); + +#endif /* MIXGTK_MIXAL_H */ + diff --git a/mixgtk/mixgtk_mixvm.c b/mixgtk/mixgtk_mixvm.c new file mode 100644 index 0000000..9c5d9bd --- /dev/null +++ b/mixgtk/mixgtk_mixvm.c @@ -0,0 +1,423 @@ +/* -*-c-*- -------------- mixgtk_mixvm.c : + * Implementation of the functions declared in mixgtk_mixvm.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/14 16:34:31 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include +#include "mixgtk_widgets.h" +#include "mixgtk_mixvm.h" +#include "mixgtk_cmd_dispatcher.h" +#include "mixgtk_input.h" + +/* register widgets */ +#define REGISTER_NO_ (MIXGTK_WIDGET_rI6 - MIXGTK_WIDGET_rA + 1) + +static GtkEntry *reg_entries_[REGISTER_NO_]; +static GtkTooltips *tips_; +static GtkEntry *loc_entry_; +static GtkWidget *goto_; +static GtkEntry *goto_entry_; +static GtkToggleButton *over_button_; +static GtkToggleButton *cmp_buttons_[3]; +static GtkCList *memory_; +static GtkLabel *laptime_; +static GtkLabel *progtime_; +static GtkLabel *uptime_; +static mix_vm_t *vm_; + +#define GOTO_ENTRY_NAME_ "goto_entry" + +static void +update_register_ (mixgtk_widget_id_t reg) +{ + static gchar BUFFER[20]; + mix_word_t tipval = MIX_WORD_ZERO; + switch (reg) + { + case MIXGTK_WIDGET_rA: + tipval = mix_vm_get_rA (vm_); + mix_word_print_to_buffer (tipval, BUFFER); + break; + case MIXGTK_WIDGET_rX: + tipval = mix_vm_get_rX (vm_); + mix_word_print_to_buffer (tipval, BUFFER); + break; + case MIXGTK_WIDGET_rJ: + tipval = mix_short_to_word_fast (mix_vm_get_rJ (vm_)); + mix_short_print_to_buffer (mix_vm_get_rJ (vm_), BUFFER); + break; + case MIXGTK_WIDGET_rI1: + case MIXGTK_WIDGET_rI2: + case MIXGTK_WIDGET_rI3: + case MIXGTK_WIDGET_rI4: + case MIXGTK_WIDGET_rI5: + case MIXGTK_WIDGET_rI6: + { + gint k = reg - MIXGTK_WIDGET_rI1 + 1; + tipval = mix_short_to_word_fast (mix_vm_get_rI (vm_, k)); + mix_short_print_to_buffer (mix_vm_get_rI (vm_, k), BUFFER); + } + break; + default: + g_assert_not_reached (); + } + gtk_entry_set_text (reg_entries_[reg - MIXGTK_WIDGET_rA], BUFFER); + snprintf (BUFFER, 20, "%s%ld", mix_word_is_negative (tipval)? "-" : "", + mix_word_magnitude (tipval)); + gtk_tooltips_set_tip (tips_, + GTK_WIDGET (reg_entries_[reg - MIXGTK_WIDGET_rA]), + BUFFER, NULL); + +} + + +static void +on_mem_adj_change_ (GtkAdjustment *adj) +{ + mixgtk_mixvm_update_cells (); +} + + +/* initialise the mixvm widgets */ +gboolean +mixgtk_mixvm_init (mix_vm_t *vm) +{ + int k; + gchar *text[] = {"", ""}; + GtkWidget *scrol; + GtkAdjustment *adj; + + g_return_val_if_fail (vm != NULL, FALSE); + vm_ = vm; + + tips_ = gtk_tooltips_new (); + + for (k = 0; k < REGISTER_NO_; ++k) + { + reg_entries_[k] = + GTK_ENTRY (mixgtk_widget_factory_get (MIXGTK_WIDGET_rA + k)); + g_return_val_if_fail (reg_entries_[k] != NULL, FALSE); + } + + loc_entry_ = GTK_ENTRY (mixgtk_widget_factory_get (MIXGTK_WIDGET_LOC)); + g_return_val_if_fail (loc_entry_ != NULL, FALSE); + + uptime_ = GTK_LABEL (mixgtk_widget_factory_get (MIXGTK_WIDGET_UPTIME)); + g_return_val_if_fail (uptime_ != NULL, FALSE); + + progtime_ = GTK_LABEL (mixgtk_widget_factory_get (MIXGTK_WIDGET_PROGTIME)); + g_return_val_if_fail (progtime_ != NULL, FALSE); + + laptime_ = GTK_LABEL (mixgtk_widget_factory_get (MIXGTK_WIDGET_LAPTIME)); + g_return_val_if_fail (laptime_ != NULL, FALSE); + + over_button_ = + GTK_TOGGLE_BUTTON (mixgtk_widget_factory_get (MIXGTK_WIDGET_OVER)); + g_return_val_if_fail (over_button_ != NULL, FALSE); + + for (k = 0; k < 3; ++k) + { + cmp_buttons_[k] = + GTK_TOGGLE_BUTTON (mixgtk_widget_factory_get (MIXGTK_WIDGET_CMP_L +k)); + g_return_val_if_fail (cmp_buttons_[k] != NULL, FALSE); + } + + memory_ = GTK_CLIST (mixgtk_widget_factory_get (MIXGTK_WIDGET_CELLS)); + g_return_val_if_fail (memory_ != NULL, FALSE); + gtk_clist_set_column_justification (memory_, 0, GTK_JUSTIFY_CENTER); + gtk_clist_set_column_justification (memory_, 1, GTK_JUSTIFY_CENTER); + gtk_clist_freeze (memory_); + for (k = 0; k< MIX_VM_CELL_NO; ++k) + { + gchar buffer[20]; + sprintf (buffer, "%04d", k); + text[0] = buffer; + gtk_clist_append (memory_, text); + } + gtk_clist_thaw (memory_); + + scrol = mixgtk_widget_factory_get (MIXGTK_WIDGET_CELLS_SCROLL); + g_return_val_if_fail (scrol != NULL, FALSE); + adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrol)); + gtk_signal_connect (GTK_OBJECT (adj), "value_changed", + GTK_SIGNAL_FUNC (on_mem_adj_change_), NULL); + + goto_ = mixgtk_widget_factory_get (MIXGTK_WIDGET_GOTO_DIALOG); + g_return_val_if_fail (goto_ != NULL, FALSE); + + goto_entry_ = GTK_ENTRY (mixgtk_widget_factory_get_by_name + (GOTO_ENTRY_NAME_)); + g_return_val_if_fail (goto_entry_ != NULL, FALSE); + + mixgtk_mixvm_update_vm_widgets (); + + return TRUE; +} + + +/* update register widgets */ +void +mixgtk_mixvm_update_registers (void) +{ + gint k; + for (k = MIXGTK_WIDGET_rA; k <= MIXGTK_WIDGET_rI6; ++k) + update_register_ (k); +} + +/* update the overflow toggle */ +void +mixgtk_mixvm_update_over_toggle (void) +{ + g_assert (over_button_); + gtk_toggle_button_set_active (over_button_, + mix_vm_get_overflow (vm_)); +} + +/* update the comparison flag */ +void +mixgtk_mixvm_update_cmp (void) +{ + gint toggle; + + g_assert (cmp_buttons_); + + toggle = mix_vm_get_cmpflag (vm_); + gtk_toggle_button_set_active (cmp_buttons_[toggle], TRUE); +} + + +/* update the memory cells */ +void +mixgtk_mixvm_update_cells (void) +{ + static gchar BUFFER[20]; + gint k = 0; + + g_assert (memory_); + + gtk_clist_freeze (memory_); + + while (gtk_clist_row_is_visible (memory_, k) == GTK_VISIBILITY_NONE) ++k; + while (gtk_clist_row_is_visible (memory_, k) != GTK_VISIBILITY_NONE) + { + mix_word_print_to_buffer (mix_vm_get_addr_contents (vm_, k), BUFFER); + gtk_clist_set_text (memory_, k, 1, BUFFER); + ++k; + } + + gtk_clist_thaw (memory_); +} + +void +mixgtk_mixvm_update_cells_to_address (gint address) +{ + g_assert (memory_); + g_return_if_fail (address < MIX_VM_CELL_NO); + + gtk_clist_freeze (memory_); + gtk_clist_moveto (memory_, address, 0, 0, 0); + gtk_clist_thaw (memory_); + mixgtk_mixvm_update_cells (); +} + +/* update the loc pointer */ +void +mixgtk_mixvm_update_loc (void) +{ + enum {SIZE = 10 }; + static gchar BUFFER[SIZE]; + mix_short_t locval; + + g_assert (loc_entry_); + + locval = mix_vm_get_prog_count (vm_); + snprintf (BUFFER, SIZE, "%04d", mix_short_magnitude (locval)); + gtk_entry_set_text (loc_entry_, BUFFER); +} + +/* update times */ +void +mixgtk_mixvm_update_times (void) +{ + enum {SIZE = 20 }; + static gchar BUFFER[SIZE]; + gint uptime, progtime, laptime; + + g_assert (uptime_ && progtime_ && laptime_); + mixgtk_cmd_dispatcher_get_times (&uptime, &progtime, &laptime); + snprintf (BUFFER, SIZE, "%d", uptime); + gtk_label_set_text (uptime_, BUFFER); + snprintf (BUFFER, SIZE, "%d", progtime); + gtk_label_set_text (progtime_, BUFFER); + snprintf (BUFFER, SIZE, "%d", laptime); + gtk_label_set_text (laptime_, BUFFER); +} + + +/* update all mixvm widgets */ +void +mixgtk_mixvm_update_vm_widgets (void) +{ + mixgtk_mixvm_update_registers (); + mixgtk_mixvm_update_loc (); + mixgtk_mixvm_update_over_toggle (); + mixgtk_mixvm_update_cmp (); + mixgtk_mixvm_update_cells (); + mixgtk_mixvm_update_times (); +} + + +/* update cmp flag */ +void +on_cmp_e_toggled (GtkWidget *widget, gpointer data) +{ + if (GTK_TOGGLE_BUTTON (widget)->active) + mix_vm_set_cmpflag (vm_, mix_EQ); +} + +void +on_cmp_l_toggled (GtkWidget *widget, gpointer data) +{ + if (GTK_TOGGLE_BUTTON (widget)->active) + mix_vm_set_cmpflag (vm_, mix_LESS); +} + +void +on_cmp_g_toggled (GtkWidget *widget, gpointer data) +{ + if (GTK_TOGGLE_BUTTON (widget)->active) + mix_vm_set_cmpflag (vm_, mix_GREAT); +} + +void +on_overflow_toggled (GtkWidget *widget, gpointer data) +{ + mix_vm_set_overflow (vm_, GTK_TOGGLE_BUTTON (widget)->active); +} + + +void +on_loc_arrow_clicked (GtkWidget *widget, gpointer data) +{ + gint address = mix_short_magnitude (mix_vm_get_prog_count (vm_)); + mixgtk_mixvm_update_cells_to_address (address); +} + + +static void +register_AX_ (mix_word_t w, gpointer reg) +{ + gint k = GPOINTER_TO_INT (reg); + if (k == 0) + mix_vm_set_rA (vm_, w); + else + mix_vm_set_rX (vm_, w); + update_register_ (MIXGTK_WIDGET_rA + k); +} + +static void +register_j_ (mix_word_t w, gpointer data) +{ + if (mix_word_is_negative (w)) mix_word_reverse_sign (w); + mix_vm_set_rJ (vm_, mix_word_to_short_fast (w)); + update_register_ (MIXGTK_WIDGET_rJ); +} + +static void +register_i_ (mix_word_t w, gpointer reg) +{ + mix_vm_set_rI (vm_, GPOINTER_TO_INT (reg), mix_word_to_short_fast (w)); + update_register_ (MIXGTK_WIDGET_rI1 - 1 + GPOINTER_TO_INT (reg)); +} + +gboolean +on_register_click (GtkWidget *w, GdkEvent *e, gpointer data) +{ + enum {SIZE = 20}; + static gchar BUFFER[SIZE]; + gint k; + + if (w == GTK_WIDGET (reg_entries_[0])) + mixgtk_input_word ("Register A", mix_vm_get_rA (vm_), + register_AX_, GINT_TO_POINTER (0)); + else if (w == GTK_WIDGET (reg_entries_[1])) + mixgtk_input_word ("Register X", mix_vm_get_rX (vm_), + register_AX_, GINT_TO_POINTER(1)); + else if (w == GTK_WIDGET (reg_entries_[2])) + mixgtk_input_short ("Register J", mix_vm_get_rJ (vm_), register_j_, NULL); + else for (k = 1; k < 7; ++k) + { + if (w == GTK_WIDGET (reg_entries_[2 + k])) + { + snprintf (BUFFER, SIZE, "Register I%d", k); + mixgtk_input_short (BUFFER, mix_vm_get_rI (vm_, k), + register_i_, GINT_TO_POINTER (k)); + break; + } + } + return FALSE; +} + +static void +mem_cell_ (mix_word_t w, gpointer a) +{ + mix_short_t addr = mix_short_new (GPOINTER_TO_INT (a)); + mix_vm_set_addr_contents (vm_, addr, w); + mixgtk_mixvm_update_cells (); +} + +void +on_memory_cells_select_row (GtkCList *w, gint row, gint col, + GdkEvent *e, gpointer data) +{ + enum {SIZE = 20}; + static gchar BUFFER[SIZE]; + snprintf (BUFFER, SIZE, "Memory cell no. %d", row); + mixgtk_input_word (BUFFER, + mix_vm_get_addr_contents (vm_, mix_short_new (row)), + mem_cell_, GINT_TO_POINTER (row)); +} + +void +on_memory_cells_click_column (GtkCList *w, gint row, gpointer data) +{ + gtk_widget_show (goto_); +} + +void +on_goto_cancel_clicked (GtkWidget *w, gpointer data) +{ + gtk_widget_hide (goto_); +} + +void +on_goto_ok_clicked (GtkWidget *w, gpointer data) +{ + gchar *txt = gtk_entry_get_text (goto_entry_); + mix_short_t addr = mix_short_new (atoi (txt)); + if (addr < MIX_VM_CELL_NO) + { + gtk_widget_hide (goto_); + mixgtk_mixvm_update_cells_to_address (addr); + } +} + diff --git a/mixgtk/mixgtk_mixvm.h b/mixgtk/mixgtk_mixvm.h new file mode 100644 index 0000000..8207d91 --- /dev/null +++ b/mixgtk/mixgtk_mixvm.h @@ -0,0 +1,84 @@ +/* -*-c-*- ---------------- mixgtk_mixvm.h : + * Functions dealing with the mixvm widgets + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/09 22:12:04 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_MIXVM_H +#define MIXGTK_MIXVM_H + +#include + +/* initialise the mixvm widgets */ +extern gboolean +mixgtk_mixvm_init (mix_vm_t *vm); + +/* update register widgets */ +extern void +mixgtk_mixvm_update_registers (void); + +/* update the overflow toggle */ +extern void +mixgtk_mixvm_update_over_toggle (void); + +/* update the comparison flag */ +extern void +mixgtk_mixvm_update_cmp (void); + +/* update the memory cells */ +extern void +mixgtk_mixvm_update_cells (void); + +extern void +mixgtk_mixvm_update_cells_to_address (gint address); + +/* update the loc pointer */ +extern void +mixgtk_mixvm_update_loc (void); + +/* update times */ +extern void +mixgtk_mixvm_update_times (void); + +/* update all mixvm widgets */ +extern void +mixgtk_mixvm_update_vm_widgets (void); + +/* callbacks */ +extern void +on_cmp_e_toggled (GtkWidget *widget, gpointer data); + +extern void +on_cmp_g_toggled (GtkWidget *widget, gpointer data); + +extern void +on_cmp_l_toggled (GtkWidget *widget, gpointer data); + +extern void +on_overflow_toggled (GtkWidget *widget, gpointer data); + +extern void +on_loc_arrow_clicked (GtkWidget *widget, gpointer data); + + + +#endif /* MIXGTK_MIXVM_H */ + diff --git a/mixgtk/mixgtk_widgets.c b/mixgtk/mixgtk_widgets.c new file mode 100644 index 0000000..165da81 --- /dev/null +++ b/mixgtk/mixgtk_widgets.c @@ -0,0 +1,112 @@ +/* -*-c-*- -------------- mixgtk_widgets.c : + * Implementation of the functions declared in mixgtk_widgets.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/15 14:42:37 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include +#include "mixgtk_widgets.h" + +/* the glade spec */ +static GladeXML *xml_ = NULL; + +/* widget names */ +static const gchar *names_[] = { + "main_window", + "main_statusbar", + "word_dialog", + "about_dialog", + "goto_dialog", + "command_prompt", + "command_log", + "mixal_clist", + "rA_entry", + "rX_entry", + "rJ_entry", + "rI1_entry", + "rI2_entry", + "rI3_entry", + "rI4_entry", + "rI5_entry", + "rI6_entry", + "lesser_radio", + "equal_radio", + "greater_radio", + "over_toggle", + "memory_cells", + "memory_scroll", + "devices_notebook", + "loc_entry", + "elapsed_label", + "program_label", + "uptime_label", + NULL +}; + +#define WIDGET_NO_ (sizeof (names_) / sizeof (names_[0])) + +#define VERSION_LABEL_ "version_label" +#define GPL_TEXT_ "gpl_text" + +GtkWidget *about_; + +/* create a new factory from an xml glade file */ +gboolean +mixgtk_widget_factory_init (const char *glade_file) +{ + GtkWidget *label; + glade_init (); + xml_ = glade_xml_new (glade_file, NULL); + if (!xml_) return FALSE; + glade_xml_signal_autoconnect (xml_); + + about_ = mixgtk_widget_factory_get (MIXGTK_WIDGET_ABOUT_DIALOG); + g_return_val_if_fail (about_ != NULL, FALSE); + label = mixgtk_widget_factory_get_by_name (VERSION_LABEL_); + g_return_val_if_fail (label != NULL, FALSE); + gtk_label_set_text (GTK_LABEL(label), VERSION); + gtk_widget_show (label); + return TRUE; +} + +/* get a widget */ +GtkWidget * +mixgtk_widget_factory_get (mixgtk_widget_id_t widget) +{ + g_return_val_if_fail (widget < WIDGET_NO_, NULL); + return glade_xml_get_widget (xml_, names_[widget]); +} + +/* Get a widget by name */ +GtkWidget * +mixgtk_widget_factory_get_by_name (const gchar *name) +{ + return glade_xml_get_widget (xml_, name); +} + +/* about box */ +void +on_about_activate (GtkWidget *w, gpointer data) +{ + gtk_widget_show (about_); +} diff --git a/mixgtk/mixgtk_widgets.h b/mixgtk/mixgtk_widgets.h new file mode 100644 index 0000000..f20ddc3 --- /dev/null +++ b/mixgtk/mixgtk_widgets.h @@ -0,0 +1,80 @@ +/* -*-c-*- ---------------- mixgtk_widgets.h : + * glade-based factory of mixvm widgets + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/15 14:42:13 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 MIXGTK_WIDGETS_H +#define MIXGTK_WIDGETS_H + +#include +#include + +/* enumeration of mixvm widget ids */ +typedef enum { + MIXGTK_WIDGET_MAIN, /* main app window */ + MIXGTK_WIDGET_STATUSBAR, + MIXGTK_WIDGET_WORD_DIALOG, /* input dialog for a mix word */ + MIXGTK_WIDGET_ABOUT_DIALOG, + MIXGTK_WIDGET_GOTO_DIALOG, + MIXGTK_WIDGET_PROMPT, /* command prompt */ + MIXGTK_WIDGET_LOG, /* command output */ + MIXGTK_WIDGET_MIXAL, /* mixal source file */ + MIXGTK_WIDGET_rA, + MIXGTK_WIDGET_rX, + MIXGTK_WIDGET_rJ, + MIXGTK_WIDGET_rI1, + MIXGTK_WIDGET_rI2, + MIXGTK_WIDGET_rI3, + MIXGTK_WIDGET_rI4, + MIXGTK_WIDGET_rI5, + MIXGTK_WIDGET_rI6, + MIXGTK_WIDGET_CMP_L, + MIXGTK_WIDGET_CMP_E, + MIXGTK_WIDGET_CMP_G, + MIXGTK_WIDGET_OVER, + MIXGTK_WIDGET_CELLS, + MIXGTK_WIDGET_CELLS_SCROLL, + MIXGTK_WIDGET_DEVICE, + MIXGTK_WIDGET_LOC, + MIXGTK_WIDGET_LAPTIME, + MIXGTK_WIDGET_PROGTIME, + MIXGTK_WIDGET_UPTIME, + MIXGTK_WIDGET_NONE +} mixgtk_widget_id_t; + + +/* create a new factory from an xml glade file */ +extern gboolean +mixgtk_widget_factory_init (const char *glade_file); + + +/* get a widget */ +extern GtkWidget * +mixgtk_widget_factory_get (mixgtk_widget_id_t widget); + +/* Get a widget by name */ +extern GtkWidget * +mixgtk_widget_factory_get_by_name (const gchar *name); + + +#endif /* MIXGTK_WIDGETS_H */ + diff --git a/mixlib/.cvsignore b/mixlib/.cvsignore new file mode 100644 index 0000000..71b540f --- /dev/null +++ b/mixlib/.cvsignore @@ -0,0 +1,7 @@ + +.deps +Makefile +Makefile.in +lex.yy.c +mix_eval_scanner.c +mix_scanner.c diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am new file mode 100644 index 0000000..5091e88 --- /dev/null +++ b/mixlib/Makefile.am @@ -0,0 +1,33 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# 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 xmix_device.h xmix_device.c \ + mix_eval.h mix_eval.c xmix_eval.h mix_eval_scanner.l \ + mix_src_file.c mix_src_file.h \ + mix_vm_clock.c mix_vm_clock.h \ + mix_vm_command.c mix_vm_command.h + + diff --git a/mixlib/mix.c b/mixlib/mix.c new file mode 100644 index 0000000..305bb65 --- /dev/null +++ b/mixlib/mix.c @@ -0,0 +1,63 @@ +/* -*-c-*- -------------- mix.c : + * Implementation of the functions declared in mix.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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, 2001 Free Software Foundation, Inc.\n" +"GNU MDK 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" +"GNU MDK 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..42eb4c9 --- /dev/null +++ b/mixlib/mix.h @@ -0,0 +1,65 @@ +/* -*-c-*- ---------------- mix.h : + * Initialisation of the mix library + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 +#else +# warning "config.h not found, package misconfigured." +# define PACKAGE "mdk" +# define VERSION "0.0" +#endif + +#ifdef HAVE_LOCALE_H +# include +#endif + +#ifdef HAVE_GETTEXT +# include +# define gettext_noop(String) (String) +#else +# include +#endif + +#define _(String) gettext (String) +#define N_(String) gettext_noop (String) + +#include + +/* 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..604f3cd --- /dev/null +++ b/mixlib/mix_code_file.c @@ -0,0 +1,326 @@ +/* -*-c-*- -------------- mix_code_file.c : + * Implementation of the functions declared in mix_code_file.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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, TRUE); + 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; +} + +/* get details about the source file */ +const gchar * +mix_code_file_get_source_path (const mix_code_file_t *file) +{ + g_return_val_if_fail (file != NULL, NULL); + return file->source_path; +} diff --git a/mixlib/mix_code_file.h b/mixlib/mix_code_file.h new file mode 100644 index 0000000..0678910 --- /dev/null +++ b/mixlib/mix_code_file.h @@ -0,0 +1,106 @@ +/* -*-c-*- ---------------- mix_code_file.h : + * Declaration of mix_code_file_t, a file containing compiled mix + * instructions. + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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); + +/* get details about the source file */ +extern const gchar * +mix_code_file_get_source_path (const mix_code_file_t *file); + + +#endif /* MIX_CODE_FILE_H */ + diff --git a/mixlib/mix_device.c b/mixlib/mix_device.c new file mode 100644 index 0000000..13e7150 --- /dev/null +++ b/mixlib/mix_device.c @@ -0,0 +1,163 @@ +/* -*-c-*- -------------- mix_device.c : + * Implementation of the functions declared in mix_device.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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 "xmix_device.h" + +mix_device_t * +mix_device_new (mix_device_type_t type) +{ + mix_device_t *result = NULL; + g_return_val_if_fail (type < mix_dev_INVALID, NULL); + result = g_new (mix_device_t, 1); + 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); + result->vtable = DEF_DEV_VTABLE_; + return result; +} + + + +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, NULL); + g_return_val_if_fail (type < mix_dev_INVALID, NULL); + result = g_new (mix_device_t, 1); + 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); + } + result->vtable = DEF_DEV_VTABLE_; + return result; +} + +/* + Create a new device with a given type and stream +*/ +mix_device_t * +mix_device_new_with_file (mix_device_type_t type, FILE *file) +{ + mix_device_t *result = NULL; + g_return_val_if_fail (file != NULL, NULL); + g_return_val_if_fail (type < mix_dev_INVALID, NULL); + result = g_new (mix_device_t, 1); + result->type = type; + result->file = mix_io_new (file); + result->vtable = DEF_DEV_VTABLE_; + 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_type_t +mix_device_type (const mix_device_t *dev) +{ + g_return_val_if_fail (dev != NULL, mix_dev_INVALID); + return dev->type; +} + +const char * +mix_device_get_name (const 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 (const 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 (const 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) +{ + g_return_val_if_fail (dev != NULL, FALSE); + g_return_val_if_fail (block != NULL, FALSE); + g_assert (dev->vtable != NULL); + return (dev->vtable->write) (dev, block); +} + +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); + g_assert (dev->vtable != NULL); + return (dev->vtable->read) (dev, block); +} + +gboolean +mix_device_ioc (mix_device_t *dev, mix_short_t arg) +{ + g_return_val_if_fail (dev != NULL, FALSE); + g_assert (dev->vtable != NULL); + return (dev->vtable->ioc) (dev, arg); +} + +gboolean +mix_device_busy (const mix_device_t *dev) +{ + g_return_val_if_fail (dev != NULL, FALSE); + return (dev->vtable->busy) (dev); + +} diff --git a/mixlib/mix_device.h b/mixlib/mix_device.h new file mode 100644 index 0000000..7248d72 --- /dev/null +++ b/mixlib/mix_device.h @@ -0,0 +1,151 @@ +/* -*-c-*- ---------------- mix_device.h : + * Declaration of mix_device_t and associated methods. + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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 +#include +#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_dev_INVALID +} 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); + +/* + Create a new device with a given type and stream +*/ +extern mix_device_t * +mix_device_new_with_file (mix_device_type_t type, FILE *file); + +/* + Delete a device. +*/ +extern void +mix_device_delete(mix_device_t *dev); + + +/* + Get a device type +*/ +extern mix_device_type_t +mix_device_type (const mix_device_t *dev); + + +/* + Get a device name +*/ +extern const char * +mix_device_get_name (const mix_device_t *dev); + +/* + Get the device block size +*/ +extern size_t +mix_device_block_size (const mix_device_t *dev); + +/* + Get the device io mode +*/ +extern mix_device_mode_t +mix_device_mode (const 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 (const mix_device_t *dev); + +#endif /* MIX_DEVICE_H */ + diff --git a/mixlib/mix_eval.c b/mixlib/mix_eval.c new file mode 100644 index 0000000..b629852 --- /dev/null +++ b/mixlib/mix_eval.c @@ -0,0 +1,191 @@ +/* -*-c-*- -------------- mix_eval.c : + * Implementation of the functions declared in mix_eval.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/02/20 00:23:58 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_eval.h" + + +static const gchar *errors_[] = { + N_("Successful evaluation"), + N_("Syntax error in expression"), + N_("Out of range F-specification"), + N_("Mismatched parenthesis"), + N_("Undefined symbol"), + N_("Internal error") +}; + + +/* create a new evaluator */ +mix_eval_t * +mix_eval_new (void) +{ + mix_eval_t *result = g_new (mix_eval_t, 1); + result->table = mix_symbol_table_new (); + if (result->table == NULL) { + g_free (result); + return NULL; + } + result->towner = TRUE; + result->value = MIX_WORD_ZERO; + result->errpos = 0; + return result; +} + +/* create a new evaluator with an external symbol table */ +mix_eval_t * +mix_eval_new_with_table (mix_symbol_table_t *table) +{ + mix_eval_t *result = g_new (mix_eval_t, 1); + result->table = table; + result->towner = FALSE; + result->value = MIX_WORD_ZERO; + result->errpos = 0; + return result; +} + +/* delete */ +void +mix_eval_delete (mix_eval_t *eval) +{ + g_return_if_fail (eval); + if (eval->table && eval->towner) { + mix_symbol_table_delete (eval->table); + } + g_free (eval); +} + +/* eval an expression */ +mix_eval_result_t +mix_eval_expression_with_loc (mix_eval_t *eval, const gchar *expr, + mix_short_t loc) +{ + mix_eval_data_ data; + + if (expr == NULL || eval == NULL) + return MIX_EVAL_INTERN; + data.expr = g_strdup_printf ("%s\n", expr); + data.table = eval->table; + data.errpos = eval->errpos; + data.value = eval->value; + data.loc = loc; + eval->result = mix_eval_expr (&data); + if (eval->result == MIX_EVAL_OK) { + eval->value = data.value; + eval->errpos = -1; + } else { + eval->errpos = data.errpos; + } + g_free (data.expr); + + return eval->result; +} + +/* get the result of the last evaluation */ +mix_word_t +mix_eval_value (const mix_eval_t *eval) +{ + g_return_val_if_fail (eval != NULL, MIX_WORD_ZERO); + return eval->value; +} + +/* get the last eval result code */ +mix_eval_result_t +mix_eval_last_error (const mix_eval_t *eval) +{ + g_return_val_if_fail (eval != NULL, MIX_EVAL_INTERN); + return eval->result; +} + +/* get the last error string */ +const gchar* +mix_eval_last_error_string (const mix_eval_t *eval) +{ + g_return_val_if_fail (eval != NULL, errors_[MIX_EVAL_INTERN]); + return errors_[eval->result]; +} + +/* get the position of last error */ +guint +mix_eval_last_error_pos (const mix_eval_t *eval) +{ + g_return_val_if_fail (eval != NULL, 0); + return eval->errpos; +} + +/* add, or redefine, a symbol. see mix_symbol_table.h for + possible outcomes. */ +gint +mix_eval_set_symbol (mix_eval_t *eval, const gchar *symbol, + mix_word_t value) +{ + g_return_val_if_fail (eval != NULL && eval->table != NULL, + MIX_SYM_FAIL); + return mix_symbol_table_insert (eval->table, symbol, value); +} + +void +mix_eval_remove_symbol (mix_eval_t *eval, const gchar *symbol) +{ + g_return_if_fail (eval != NULL && eval->table != NULL); + mix_symbol_table_remove (eval->table, symbol); +} + +void +mix_eval_use_symbol_table (mix_eval_t *eval, + mix_symbol_table_t *table) +{ + g_return_if_fail (eval != NULL); + if (eval->table != NULL && eval->towner) + mix_symbol_table_delete (eval->table); + eval->table = table; + eval->towner = FALSE; +} + +const mix_symbol_table_t * +mix_eval_symbol_table (const mix_eval_t *eval) +{ + g_return_val_if_fail (eval != NULL, NULL); + return eval->table; +} + +gboolean +mix_eval_set_symbols_from_table (mix_eval_t *eval, + const mix_symbol_table_t *table) +{ + g_return_val_if_fail (eval != NULL, FALSE); + if (eval->table != NULL) + return mix_symbol_table_merge_table (eval->table, table); + else + return FALSE; +} + +gboolean +mix_eval_remove_symbols_from_table (mix_eval_t *eval, + const mix_symbol_table_t *table) +{ + g_return_val_if_fail (eval != NULL, FALSE); + if (eval->table != NULL) + return mix_symbol_table_substract_table (eval->table, table); + else + return FALSE; +} diff --git a/mixlib/mix_eval.h b/mixlib/mix_eval.h new file mode 100644 index 0000000..a7f961f --- /dev/null +++ b/mixlib/mix_eval.h @@ -0,0 +1,110 @@ +/* -*-c-*- ---------------- mix_eval.h : + * mix_eval_t is an evaluator of MIX W-expressions + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_EVAL_H +#define MIX_EVAL_H + +#include "mix.h" +#include "mix_types.h" +#include "mix_symbol_table.h" + +/* the evaluator type */ +typedef struct mix_eval_t mix_eval_t; + +/* possible evaluation outcomes*/ +typedef enum { + MIX_EVAL_OK, /* sucess*/ + MIX_EVAL_SYNTAX, /* syntax error */ + MIX_EVAL_INV_FSPEC, /* out of range fspec */ + MIX_EVAL_MIS_PAREN, /* mismatched parenthesis */ + MIX_EVAL_UNDEF_SYM, /* undefined symbol */ + MIX_EVAL_INTERN /* internal error */ +} mix_eval_result_t; + +/* create a new evaluator */ +extern mix_eval_t * +mix_eval_new (void); + +/* create a new evaluator with an external symbol table */ +extern mix_eval_t * +mix_eval_new_with_table (mix_symbol_table_t *table); + +/* delete */ +extern void +mix_eval_delete (mix_eval_t *eval); + +/* provide a new symbol table to be used */ +extern void +mix_eval_use_symbol_table (mix_eval_t *eval, + mix_symbol_table_t *table); + +extern const mix_symbol_table_t * +mix_eval_symbol_table (const mix_eval_t *eval); + +/* eval an expression providing a value for loc counter */ +extern mix_eval_result_t +mix_eval_expression_with_loc (mix_eval_t *eval, const gchar *expr, + mix_short_t loc); +/* eval an expression with null loc*/ +#define mix_eval_expression (eval,expr) \ + mix_eval_expression_with_loc (eval, expr, MIX_SHORT_ZERO) + + +/* get the result of the last evaluation */ +extern mix_word_t +mix_eval_value (const mix_eval_t *eval); + +/* get the last eval result code */ +extern mix_eval_result_t +mix_eval_last_error (const mix_eval_t *eval); + +/* get the last error string */ +extern const gchar* +mix_eval_last_error_string (const mix_eval_t *eval); + +/* get the position of last error */ +extern guint +mix_eval_last_error_pos (const mix_eval_t *eval); + +/* add, or redefine, a symbol. see mix_symbol_table.h for + possible outcomes. */ +extern gint +mix_eval_set_symbol (mix_eval_t *eval, const gchar *symbol, + mix_word_t value); + +extern gboolean +mix_eval_set_symbols_from_table (mix_eval_t *eval, + const mix_symbol_table_t *table); + +extern void +mix_eval_remove_symbol (mix_eval_t *eval, const gchar *symbol); + +extern gboolean +mix_eval_remove_symbols_from_table (mix_eval_t *eval, + const mix_symbol_table_t *table); + + + +#endif /* MIX_EVAL_H */ + diff --git a/mixlib/mix_eval_scanner.l b/mixlib/mix_eval_scanner.l new file mode 100644 index 0000000..abf1879 --- /dev/null +++ b/mixlib/mix_eval_scanner.l @@ -0,0 +1,265 @@ +/* -*-c-*- ------------------ mix_eval_scanner.l : + * scanner used by mix_eval_t + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_eval.h" + +#define YY_DECL \ + mix_eval_result_t mix_eval_expr (mix_eval_data_ *data) + + /* keep track of current position in buffer */ +#define YY_USER_ACTION yypos += yyleng; + +#define RETURN_STATE(err) \ + do { \ + done = TRUE; \ + state = err; \ + BEGIN (INITIAL); \ + } while (FALSE) + +#define CLEAN_UP() \ + do { \ + yy_delete_buffer (buffer); \ + g_free (expr_cp); \ + } while (FALSE) + +static mix_word_t + eval_binop_ (const gchar *op, mix_word_t x, mix_word_t y); + +static int + 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 EVAL +%s WEVAL + +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]* +binops "+"|"-"|"/"|"//"|":" +binop {binops}|"*" +atexpr {digit}+|{symbol}|\* +expr [+-]?{atexpr}({binop}{1}{atexpr})* +fpart \({expr}\) +wexpr {expr}({fpart})?(,{expr}({fpart})?)* + + +%% + +%{ + YY_BUFFER_STATE buffer; + mix_word_t expr_val = MIX_WORD_ZERO, wexpr_val = MIX_WORD_ZERO; + mix_word_t wexpr_val_tmp = MIX_WORD_ZERO; + mix_eval_result_t state = MIX_EVAL_OK; + gchar *expr_cp; + gint yypos = -22; /* to account for padding */ + gboolean is_fp = FALSE, done = FALSE; + g_assert (data != NULL && data->expr != NULL); + /* make room enough to unput computed values */ + expr_cp = g_strdup_printf ("%-20s%s"," ", data->expr); + buffer = yy_scan_string (expr_cp); + data->errpos = -1; +%} + + +<*><> { + CLEAN_UP (); + return MIX_EVAL_INTERN; +} + +{ + {ws} /* eat whitespace */ + . { + if (!done && state == MIX_EVAL_OK) { + yypos -= yyleng; yyless (0); + yy_push_state (WEVAL); + } else { + CLEAN_UP (); + if (state == MIX_EVAL_OK) return (MIX_EVAL_SYNTAX); + data->errpos = yypos; + return state; + } + } + "\n" { + CLEAN_UP(); + if (state == MIX_EVAL_OK) + data->value = wexpr_val; + else + data->errpos = yypos; + return state; + } +} + +{ + {number}"(" { + is_fp = TRUE; + wexpr_val_tmp = mix_word_new (atol (yytext)); + } + {number}")" { + glong val = atol (yytext); + if ( !is_fp ) { + RETURN_STATE (MIX_EVAL_MIS_PAREN); + } else if ( val < 0 || val > MIX_BYTE_MAX + || !mix_fspec_is_valid (mix_byte_new (val)) ) { + RETURN_STATE (MIX_EVAL_INV_FSPEC); + } else { + is_fp = FALSE; + wexpr_val = mix_word_store_field (mix_byte_new (val), + wexpr_val_tmp, + wexpr_val); + } + } + {number}/({ws}*\n)|[,()] { + wexpr_val = mix_word_new (atol (yytext)); + } + {expr}/({ws}*\n)|[,()] { + if (yytext[0] != '*') + { + yypos -= yyleng; + yyless (0); + } + else + { + yypos -= yyleng - 1; + expr_val = mix_short_to_word_fast (data->loc); + yyless (1); + } + yy_push_state (EVAL); + } + ,/{expr} /* eat comma if followed by expression */ + [\t\n ] { /* ok if not inside an f-part */ + if ( is_fp ) { + RETURN_STATE (MIX_EVAL_MIS_PAREN); + } + unput (yytext[yyleng-1]); --yypos; + done = TRUE; + yy_pop_state (); + } + . RETURN_STATE (MIX_EVAL_SYNTAX); +} + +{ + {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 (data->table, s) ) { + RETURN_STATE (MIX_EVAL_UNDEF_SYM); + } + expr_val = eval_binop_ (yytext, expr_val, + mix_symbol_table_value (data->table, s)); + } + {binop}"*" { + expr_val = eval_binop_ (yytext, expr_val, + mix_short_to_word_fast (data->loc)); + } + "*" yypos -= unput_word_ (mix_short_to_word_fast (data->loc)); + {number} expr_val = mix_word_new (atol (yytext)); + {symbol} { + if ( !mix_symbol_table_is_defined (data->table, yytext) ) { + RETURN_STATE (MIX_EVAL_UNDEF_SYM); + } + expr_val = mix_symbol_table_value (data->table, yytext); + } + [,)(\n\t ] { + unput (yytext[0]); --yypos; + yypos -= unput_word_ (expr_val); + yy_pop_state (); + } + + . RETURN_STATE (MIX_EVAL_SYNTAX); +} + + +%% + +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 int +unput_word_ (mix_word_t word) +{ + gchar *value; + gint k, result; + value = g_strdup_printf ("%s%ld", + mix_word_is_negative (word)? "-":"+", + mix_word_magnitude (word)); + result = strlen (value); + for (k = result - 1; k >= 0; --k) + unput (value[k]); + g_free (value); + return result; +} diff --git a/mixlib/mix_file.c b/mixlib/mix_file.c new file mode 100644 index 0000000..023f4ef --- /dev/null +++ b/mixlib/mix_file.c @@ -0,0 +1,140 @@ +/* -*-c-*- -------------- mix_file.c : + * Implementation of the functions declared in mix_file.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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; + + result = g_new(mix_file_t, 1); + file = fopen(name, fmode_to_type_(mode)); + if ( file == NULL ) { + g_free (result); + 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..22bed74 --- /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 Free Software Foundation, Inc. + * + * 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..2c5df08 --- /dev/null +++ b/mixlib/mix_ins.c @@ -0,0 +1,269 @@ +/* -*-c-*- ------------------ mix_ins.c : + * Implementation of the functions declared in mix_ins.h + * ------------------------------------------------------------------ + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * 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" + + +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; +} + +extern void +mix_ins_to_string_in_buffer (const mix_ins_t *ins, gchar *buf, guint len) +{ + gboolean needs_f; + mix_ins_id_t id; + + g_return_if_fail (ins != NULL); + g_return_if_fail (buf != NULL); + id = mix_ins_id_from_ins(*ins); + needs_f = ins->fspec != id_to_desc_[id].def_fspec; + if ( needs_f ) + g_snprintf (buf, len, "%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 + g_snprintf(buf, len, "%s\t%s%d,%d", + mix_get_string_from_id(id), + mix_short_is_negative(ins->address)?"-":"", + mix_short_magnitude(ins->address), ins->index); +} + + + +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..7746e8c --- /dev/null +++ b/mixlib/mix_ins.h @@ -0,0 +1,195 @@ +/* -*-c-*- -------------------- mix_ins.h: + * This file declares types and functions for manipulating MIX + * instructions + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_add_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_to_string_in_buffer (const mix_ins_t *ins, gchar *buf, guint len); + +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..704a5c0 --- /dev/null +++ b/mixlib/mix_io.c @@ -0,0 +1,219 @@ +/* -*-c-*- --------------- mix_io.c : + * Implementation of the functions declared in mix_io.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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); + 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..a63bda6 --- /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 Free Software Foundation, Inc. + * + * 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 +#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..6a58f3e --- /dev/null +++ b/mixlib/mix_parser.c @@ -0,0 +1,525 @@ +/* -*-c-*- -------------- mix_parser.c : + * Implementation of the functions declared in mix_parser.h and + * xmix_parser.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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); + 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_value_ (mix_parser_t *parser, const gchar *name, + mix_short_t value) +{ + 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); + if (mix_get_ins_address (node->ins) == 1) { + value = mix_short_negative (value); + node->ins = mix_word_set_field (node->ins, + MIX_WORD_ZERO, + mix_fspec_new (1,2)); + } + mix_word_add_address (node->ins, value); + 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); + } +} + +#define update_future_refs_(parser,name) \ + update_future_refs_value_(parser, name, (parser)->loc_count); + +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, TRUE); + 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); + return mix_parser_define_symbol_value (parser, name, value); +} + +mix_parser_err_t +mix_parser_define_symbol_value (mix_parser_t *parser, const gchar *name, + mix_word_t value) +{ + 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_value_ (parser, name, value); + 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, + mix_short_t value) +{ + 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_value_ (parser, ref, value); + ref[1] = 'B'; + mix_symbol_table_insert (parser->symbol_table, ref, + mix_short_to_word_fast (value)); + 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); + 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..f371430 --- /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 Free Software Foundation, Inc. + * + * 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 +#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..f961fe6 --- /dev/null +++ b/mixlib/mix_scanner.l @@ -0,0 +1,532 @@ +/* ------------------ mix_scanner.l : + * Lexical scanner used by mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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; \ + } \ + if (lsymbol != NULL) \ + { \ + g_free (lsymbol); \ + lsymbol = NULL; \ + } \ + } while (FALSE) + +#define NEXT() \ + do { \ + if (lsymbol != NULL) \ + mix_parser_manage_local_symbol (parser,lsymbol, \ + loc); \ + 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 { \ + if (yytext[0] != '*') \ + { \ + expr_val = MIX_WORD_ZERO; \ + yyless (0); \ + } \ + else \ + { \ + expr_val = mix_short_to_word_fast (parser->loc_count); \ + yyless (1); \ + } \ + 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, *lsymbol = NULL; + mix_address_t loc = MIX_SHORT_ZERO; + 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); + +%} + + +<*><> { + mix_parser_log_error (parser, MIX_PERR_UNEX_EOF, lineno, NULL, FALSE); + return MIX_PERR_UNEX_EOF; +} + +{ + ^\*.* /* eat comments */ + . { + if ( end ) return parser->status; + yyless (0); + BEGIN (LOC); + } + \n { + ++lineno; + if ( end ) return parser->status; + } +} + +{ + {ws}+ BEGIN (OP); /* LOC field is empty */ + {locsymbol} { /* manage local symbol */ + loc = get_ploc_ (parser); + lsymbol = g_strdup (yytext); + if ( lsymbol == NULL ) { + mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE); + return MIX_PERR_INTERNAL; + } + BEGIN (OP); + } + {locsymbol}/({ws}+EQU) {/* local symbol with value */ + loc = get_ploc_ (parser); + symbol = g_strdup (yytext); + lsymbol = g_strdup (yytext); + if ( symbol == NULL || lsymbol == NULL) { + mix_parser_log_error (parser, MIX_PERR_INTERNAL, lineno, NULL, FALSE); + return MIX_PERR_INTERNAL; + } + symbol[1] = 'B'; /* this will be referred as nB afterwards */ + 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 */ +} + +{ + {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); +} + + +{ + {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); + } +} + +{ + {number}{ws}*\n | + {number}{ws}+.*\n { + mix_word_t value = mix_word_new (atol (yytext)); + mix_word_to_ins_uncheck (value, ins); + ADD_INS (); + } +} + +{ + {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_parser_define_symbol_value (parser, 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); + } +} + +{ + {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; + } +} + +{ + {wexpr} ENTER_WEVAL (); + . RETURN_ERROR (MIX_PERR_INV_OP, yytext); +} + + +{locsymbol} RETURN_ERROR (MIX_PERR_UNEX_LOC, yytext); + +
{ + =/[+-]?{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); + if (neg) + mix_parser_log_error (parser, MIX_PERR_UNDEF_SYM, lineno, s, TRUE); + unput (neg? '1':'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); +} + + +{ + {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); +} + +{ + {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); +} + + +{ + {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); +} + +{ + {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}/[,()\n\t ] wexpr_val = mix_word_new (atol (yytext)); + {expr}/[,()\n\t ] 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_src_file.c b/mixlib/mix_src_file.c new file mode 100644 index 0000000..4e1489b --- /dev/null +++ b/mixlib/mix_src_file.c @@ -0,0 +1,157 @@ +/* -*-c-*- -------------- mix_src_file.c : + * Implementation of the functions declared in mix_src_file.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/10 15:23:46 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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 +#include +#include +#include +#include "mix_src_file.h" + +/* the MIXAL source file type */ +struct mix_src_file_t +{ + gchar *path; /* the path to the disk file */ + GPtrArray *lines; /* an array of the file lines */ + guint lineno; /* the number of lines */ +}; + +/* format a source line */ +static gchar * +format_line_ (gchar *line) +{ + const gchar *label, *op, *rest; + gint k = 0; + + if (!line) return line; + if (line[0] == '*' || strlen(line) == 0) + return g_strdup (line); + + if (isspace (line[0])) + { + label = " "; + while (line[k] && isspace (line[k])) ++k; + } + else + { + label = line; + while (line[k] && !isspace (line[k])) ++k; + while (line[k] && isspace (line[k])) ++k; + } + + if (line[k]) + { + line[k - 1] = 0; + op = line + k; + while (line[k] && !isspace (line[k])) ++k; + while (line[k] && isspace (line[k])) ++k; + line[k - 1] = 0; + rest = (line[k]) ? line + k: ""; + } + else + { + op = rest = ""; + } + + + return g_strdup_printf ("%-11s %-5s %s", label, op, rest); +} + +/* load the source file lines into memory */ +static gboolean +load_file_ (mix_src_file_t *file) +{ + mix_file_t *mf = mix_file_new_with_def_ext (file->path, + mix_io_READ, + MIX_SRC_DEFEXT); + if (mf != NULL) + { + enum {BUFFER_SIZE = 256}; + static gchar BUFFER[BUFFER_SIZE]; + + FILE *f = mix_file_to_FILE (mf); + file->lines = g_ptr_array_new (); + file->lineno = 0; + + while (fgets (BUFFER, BUFFER_SIZE, f) == BUFFER) + { + g_ptr_array_add (file->lines, (gpointer) format_line_ (BUFFER)); + file->lineno++; + } + + mix_file_delete (mf); + return TRUE; + } + return FALSE; +} + +/* create a new src file from an existing disk file */ +mix_src_file_t * +mix_src_file_new_for_read (const gchar *path) +{ + mix_src_file_t *result = g_new (mix_src_file_t, 1); + result->lines = NULL; + result->path = g_strdup (path); + result->lineno = 0; + return result; +} + +/* destroy a src file object */ +void +mix_src_file_delete (mix_src_file_t *src) +{ + g_return_if_fail (src != NULL); + if (src->lines) g_ptr_array_free (src->lines, TRUE); + g_free (src->path); + g_free (src); +} + +/* get the source file path */ +const gchar * +mix_src_file_get_path (const mix_src_file_t *src) +{ + g_return_val_if_fail (src != NULL, NULL); + return src->path; +} + +/* get a given line of the source file */ +const gchar * +mix_src_file_get_line (const mix_src_file_t *src, guint lineno) +{ + g_return_val_if_fail (src != NULL, NULL); + if (src->lines == NULL && !load_file_ ((mix_src_file_t*)src)) + return NULL; + if (lineno > src->lineno || lineno == 0) + return NULL; + return (gchar *)g_ptr_array_index (src->lines, lineno - 1); +} + +/* get the total no. of lines in the file */ +guint +mix_src_file_get_line_no (const mix_src_file_t *src) +{ + g_return_val_if_fail (src != NULL, 0); + if (src->lines == NULL && !load_file_ ((mix_src_file_t*)src)) + return 0; + return src->lineno; +} + diff --git a/mixlib/mix_src_file.h b/mixlib/mix_src_file.h new file mode 100644 index 0000000..1392df2 --- /dev/null +++ b/mixlib/mix_src_file.h @@ -0,0 +1,57 @@ +/* -*-c-*- ---------------- mix_src_file.h : + * Declaration of mix_src_file_t, a type representing a MIXAL source + * file. + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_SRC_FILE_H +#define MIX_SRC_FILE_H + +#include "mix_file.h" + +/* the MIXAL source file type */ +typedef struct mix_src_file_t mix_src_file_t; + +/* create a new src file from an existing disk file */ +extern mix_src_file_t * +mix_src_file_new_for_read (const gchar *path); + +/* destroy a src file object */ +extern void +mix_src_file_delete (mix_src_file_t *src); + +/* get the source file path */ +extern const gchar * +mix_src_file_get_path (const mix_src_file_t *src); + +/* get a given line of the source file */ +extern const gchar * +mix_src_file_get_line (const mix_src_file_t *src, guint lineno); + +/* get the total no. of lines in the file */ +extern guint +mix_src_file_get_line_no (const mix_src_file_t *src); + + + +#endif /* MIX_SRC_FILE_H */ + diff --git a/mixlib/mix_symbol_table.c b/mixlib/mix_symbol_table.c new file mode 100644 index 0000000..33874ea --- /dev/null +++ b/mixlib/mix_symbol_table.c @@ -0,0 +1,196 @@ +/* -*-c-*- -------------- mix_symbol_table.c : + * Implementation of the functions declared in mix_symbol_table.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 /* isdigit */ +#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 from other table */ +static void +add_symbol_(gpointer symbol, gpointer value, gpointer target) +{ + mix_symbol_table_t *t = (mix_symbol_table_t *)target; + gchar *s = (gchar *)symbol; + mix_word_t v = mix_word_new(GPOINTER_TO_UINT(value)); + mix_symbol_table_insert (t, s, v); +} + +static void +remove_symbol_(gpointer symbol, gpointer value, gpointer target) +{ + mix_symbol_table_t *t = (mix_symbol_table_t *)target; + gchar *s = (gchar *)symbol; + mix_symbol_table_remove (t, s); +} + +gboolean +mix_symbol_table_merge_table (mix_symbol_table_t *table, + const mix_symbol_table_t *from) +{ + g_return_val_if_fail (table != NULL, FALSE); + if (from != NULL) + { + mix_symbol_table_foreach ((gpointer)from, add_symbol_, table); + } + return TRUE; +} + +gboolean +mix_symbol_table_substract_table (mix_symbol_table_t *table, + const mix_symbol_table_t *other) +{ + g_return_val_if_fail (table != NULL, FALSE); + if (other != NULL) + { + mix_symbol_table_foreach ((gpointer)other, remove_symbol_, table); + } + return TRUE; +} + + +/* 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 */ +#define is_local_sym_(sym) \ + ((sym) && (strlen(sym)==2) && (sym[1] == 'B') && isdigit(sym[0])) + +static gboolean skip_ = FALSE; + +static void +print_sym_rows_(gpointer symbol, gpointer value, gpointer file) +{ + char *s = (char *)symbol; + if (skip_ && !is_local_sym_(s)) { + mix_word_t word = (mix_word_t)GPOINTER_TO_UINT(value); + fprintf((FILE *)file, "%s: %s%ld\n", s, + mix_word_is_negative(word)? "-":"", + mix_word_magnitude(word)); + } +} + +static void +print_sym_line_(gpointer symbol, gpointer value, gpointer file) +{ + char *s = (char *)symbol; + if (skip_ && !is_local_sym_(s)) { + mix_word_t word = (mix_word_t)GPOINTER_TO_UINT(value); + fprintf((FILE *)file, ",%s =%s%ld", s, + mix_word_is_negative(word)? "-":"", + mix_word_magnitude(word)); + } +} + +void +mix_symbol_table_print(const mix_symbol_table_t *table, gint mode, + FILE *file, gboolean skiplocal) +{ + GHFunc func = (mode == MIX_SYM_LINE)? print_sym_line_ : print_sym_rows_; + skip_ = skiplocal; + 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..4a22444 --- /dev/null +++ b/mixlib/mix_symbol_table.h @@ -0,0 +1,109 @@ +/* -*-c-*- ---------------- mix_symbol_table.h : + * Type mix_symbol_table_t and functions to manipulate it. + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 +#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 from other table */ +extern gboolean +mix_symbol_table_merge_table (mix_symbol_table_t *table, + const mix_symbol_table_t *from); + +extern gboolean +mix_symbol_table_substract_table (mix_symbol_table_t *table, + const mix_symbol_table_t *other); + +/* 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, gboolean skiplocal); + + +#endif /* MIX_SYMBOL_TABLE_H */ + diff --git a/mixlib/mix_types.c b/mixlib/mix_types.c new file mode 100644 index 0000000..40246cd --- /dev/null +++ b/mixlib/mix_types.c @@ -0,0 +1,566 @@ +/* -*-c-*- ------------------ mix_types.c : + * Implementation file for mix_types.h declarations. + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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 +#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_to_file (mix_word_t word, const char *message, FILE *f) +{ + guint k; + if ( message ) fprintf (f, "%s ", message); + fprintf (f, "%s ", mix_word_sign (word) == 0 ? "+" : "-"); + for ( k = 1; k < 6; ++k ) { + fprintf (f, "%02d ", mix_word_get_byte (word,k)); + } + fprintf (f, "(%010ld)", mix_word_magnitude (word)); +} + +void +mix_word_print_to_buffer (mix_word_t word, gchar *buf) +{ + g_return_if_fail (buf != NULL); + sprintf (buf, "%s %02d %02d %02d %02d %02d", + mix_word_sign (word) == 0 ? "+" : "-", + mix_word_get_byte (word, 1), + mix_word_get_byte (word, 2), + mix_word_get_byte (word, 3), + mix_word_get_byte (word, 4), + mix_word_get_byte (word, 5)); +} + +/* 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)); +} + +void +mix_short_print_to_buffer (mix_short_t s, gchar *buf) +{ + g_return_if_fail (buf != NULL); + sprintf (buf, "%s %02d %02d", + mix_short_sign (s) == 0 ? "+" : "-", + 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..918046e --- /dev/null +++ b/mixlib/mix_types.h @@ -0,0 +1,291 @@ +/* -*-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, 2001 Free Software Foundation, Inc. + * + * 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 +#include "mix.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 */ +#define mix_word_print(word,message) \ + mix_word_print_to_file (word, message, stdout) + +extern void +mix_word_print_to_file (mix_word_t word, const char *message, FILE *f); + +extern void +mix_word_print_to_buffer (mix_word_t word, gchar *buf); + + +/*----------------- 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); + +extern void +mix_short_print_to_buffer (mix_short_t s, gchar *buf); + + + +#endif /* MIX_TYPES_H */ + + + + diff --git a/mixlib/mix_vm.c b/mixlib/mix_vm.c new file mode 100644 index 0000000..9a39247 --- /dev/null +++ b/mixlib/mix_vm.c @@ -0,0 +1,562 @@ +/* -*-c-*- ------------------ mix_vm.c : + * Implementation of the functions declared in mix_vm.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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; + } + if (vm->address_table != NULL) + { + g_tree_destroy (vm->address_table); + vm->address_table = NULL; + } + if (vm->src_file != NULL) + { + mix_src_file_delete (vm->src_file); + vm->src_file = 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); + vm->line_table = NULL; + vm->address_table = NULL; + vm->symbol_table = NULL; + + for (i = 0; i < BD_NO_; ++i) + vm->devices[i] = NULL; + + vm->clock = mix_vm_clock_new (); + + vm_reset_ (vm); + return vm; +} + + +void +mix_vm_delete (mix_vm_t * vm) +{ + int i; + + g_return_if_fail (vm != NULL); + + if (vm->line_table != NULL) g_tree_destroy (vm->line_table); + if (vm->address_table != NULL) g_tree_destroy (vm->address_table); + if (vm->symbol_table != NULL) mix_symbol_table_delete (vm->symbol_table); + if (vm->src_file != NULL) mix_src_file_delete (vm->src_file); + for (i = 0; i < BD_NO_; ++i) + mix_device_delete (vm->devices[i]); + mix_vm_clock_delete (vm->clock); + g_free (vm); +} + +/* connect devices to a virtual machine */ +mix_device_t * +mix_vm_connect_device (mix_vm_t *vm, mix_device_t *device) +{ + mix_device_t *old; + mix_device_type_t type; + + g_return_val_if_fail (vm != NULL, NULL); + g_return_val_if_fail (device != NULL, NULL); + + type = mix_device_type (device); + old = vm->devices[type]; + vm->devices[type] = device; + + return old; +} + +/* 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 and address tables tree */ +static gint +cmp_uint_ (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; + const gchar *sp; + + 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_uint_); + vm->address_table = g_tree_new (cmp_uint_); + } + + sp = mix_code_file_get_source_path (file); + if (sp != NULL) + vm->src_file = mix_src_file_new_for_read (sp); + + 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)); + g_tree_insert (vm->address_table, + GUINT_TO_POINTER ((guint)ins.address), + GUINT_TO_POINTER (ins.lineno)); + } + } + 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_src_file_t * +mix_vm_get_src_file (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, NULL); + return vm->src_file; +} + +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); +} + +/* Get the source line number for a given address */ +guint +mix_vm_get_address_lineno (const mix_vm_t *vm, mix_address_t addr) +{ + gpointer gp_addr = GUINT_TO_POINTER ((guint)addr); + guint lineno; + + g_return_val_if_fail (vm != NULL, 0); + g_return_val_if_fail (MEMOK_ (addr), 0); + lineno = GPOINTER_TO_UINT (g_tree_lookup (vm->address_table, gp_addr)); + return lineno; +} + +/* Get the address for a given source line number */ +typedef struct +{ + guint lineno; + mix_address_t result; +} addr_traverse_t; + +static gint +get_address_ (gpointer key, gpointer value, gpointer data) +{ + addr_traverse_t *tr = (addr_traverse_t *)data; + if (GPOINTER_TO_UINT (key) == tr->lineno) + { + tr->result = mix_short_new (GPOINTER_TO_UINT (value)); + return TRUE; + } + return (GPOINTER_TO_UINT (key) < tr->lineno)? FALSE:TRUE; +} + +mix_address_t +mix_vm_get_lineno_address (const mix_vm_t *vm, guint lineno) +{ + addr_traverse_t tr; + + g_return_val_if_fail (vm != NULL, MIX_VM_CELL_NO); + if (!vm->line_table) return MIX_VM_CELL_NO; + tr.lineno = lineno; + tr.result = MIX_VM_CELL_NO; + g_tree_traverse (vm->line_table, get_address_, G_IN_ORDER, (gpointer)&tr); + return tr.result; +} + + +/* Reposition program counter and reset state so that a loaded + program can be restarted. +*/ +void +mix_vm_reset_program (mix_vm_t *vm) +{ + guint k; + g_return_if_fail (vm != NULL); + reset_loc_ (vm); + halt_ (vm, FALSE); + 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); +} + +/* 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); + + 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; + else + update_time_ (vm, &ins); + if (bp_is_set_ (vm, get_loc_ (vm))) + return MIX_VM_BREAK; + if (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE); + } + 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 (get_loc_ (vm) >= MIX_VM_CELL_NO) halt_ (vm, TRUE); + 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; + else + update_time_ (vm, &ins); + if (is_halted_ (vm)) return MIX_VM_HALT; + return bp_is_set_ (vm, get_loc_ (vm)) ? MIX_VM_BREAK : MIX_VM_OK; +} + +/* Breakpoints */ +gulong +mix_vm_get_break_lineno (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, 0); + if (vm->address_table == NULL) + return 0; + else + { + gpointer loc = GUINT_TO_POINTER ((guint)get_loc_ (vm)); + return GPOINTER_TO_UINT (g_tree_lookup (vm->address_table,loc)); + } +} + +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; +} + +gboolean +mix_vm_has_breakpoint_at_address (const mix_vm_t *vm, guint address) +{ + g_return_val_if_fail (vm != NULL, FALSE); + if (address >= MIX_VM_CELL_NO) return FALSE; + return (bp_is_set_ (vm, address)); +} + +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); +} + +/* Get the vm uptime, defined as the time spent executing instructions */ +mix_time_t +mix_vm_get_uptime (const mix_vm_t *vm) +{ + g_return_val_if_fail (vm != NULL, 0); + return mix_vm_clock_get_time (get_clock_ (vm)); +} + diff --git a/mixlib/mix_vm.h b/mixlib/mix_vm.h new file mode 100644 index 0000000..b64e197 --- /dev/null +++ b/mixlib/mix_vm.h @@ -0,0 +1,204 @@ +/* ---------------------- mix_vm.h : + * Types and functions implementing the MIX virtual machine + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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_device.h" +#include "mix_code_file.h" +#include "mix_src_file.h" +#include "mix_symbol_table.h" +#include "mix_vm_clock.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); + +/* connect devices to a virtual machine */ +extern mix_device_t * /* previously connected device */ +mix_vm_connect_device (mix_vm_t *vm, mix_device_t *device); + +/* 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 the source file object corresponding to the last loaded code file */ +extern const mix_src_file_t * +mix_vm_get_src_file (const mix_vm_t *vm); + +/* 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); + +/* Get the source line number for a given address */ +extern guint +mix_vm_get_address_lineno (const mix_vm_t *vm, mix_address_t addr); + +/* Get the address for a given source line number */ +extern mix_address_t +mix_vm_get_lineno_address (const mix_vm_t *vm, guint lineno); + +/* Reposition program counter and reset state so that a loaded + program can be restarted. +*/ +extern void +mix_vm_reset_program (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 */ + MIX_VM_OK /* successful instruction 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 gboolean +mix_vm_has_breakpoint_at_address (const mix_vm_t *vm, guint address); + +extern void +mix_vm_clear_all_breakpoints (mix_vm_t *vm); + +/* Get the vm uptime, defined as the time spent executing instructions */ +extern mix_time_t +mix_vm_get_uptime (const mix_vm_t *vm); + + +#endif /* MIX_VM_H */ + diff --git a/mixlib/mix_vm_clock.c b/mixlib/mix_vm_clock.c new file mode 100644 index 0000000..41e7116 --- /dev/null +++ b/mixlib/mix_vm_clock.c @@ -0,0 +1,68 @@ +/* -*-c-*- -------------- mix_vm_clock.c : + * Implementation of the functions declared in mix_vm_clock.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/02/20 00:23:58 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_vm_clock.h" + +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 +}; + + +/* Create/delete a clock */ +mix_vm_clock_t * +mix_vm_clock_new () +{ + mix_vm_clock_t *result = g_new (mix_vm_clock_t, 1); + result->time = 0; + return result; +} + +void +mix_vm_clock_delete (mix_vm_clock_t *clock) +{ + g_return_if_fail (clock != NULL); +} + +/* Increase time with the units needed to execute ins */ +mix_time_t +mix_vm_clock_add_lapse (mix_vm_clock_t *clock, const mix_ins_t *ins) +{ + mix_time_t t = 0; + g_return_val_if_fail (clock != NULL, 0); + if (ins != NULL) + { + t = exec_times_[ins->opcode]; + if (ins->opcode == mix_MOVE) t += 2 * (ins->fspec); + } + clock->time += t; + return t; +} + diff --git a/mixlib/mix_vm_clock.h b/mixlib/mix_vm_clock.h new file mode 100644 index 0000000..706115e --- /dev/null +++ b/mixlib/mix_vm_clock.h @@ -0,0 +1,55 @@ +/* -*-c-*- ---------------- mix_vm_clock.h : + * Declaration of mix_vm_clock_t, a clock for the MIX virtual machine. + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/02/20 00:23:58 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_CLOCK_H +#define MIX_VM_CLOCK_H + +#include "mix.h" +#include "mix_ins.h" + +/* the type of time unit */ +typedef gulong mix_time_t; + +/* the clock type */ +typedef struct mix_vm_clock_t +{ + mix_time_t time; +} mix_vm_clock_t; + +/* Create/delete a clock */ +extern mix_vm_clock_t * +mix_vm_clock_new (); + +extern void +mix_vm_clock_delete (mix_vm_clock_t *clock); + +/* Increase time with the units needed to execute ins */ +extern mix_time_t /* the added lapse */ +mix_vm_clock_add_lapse (mix_vm_clock_t *clock, const mix_ins_t *ins); + +/* Get the time since creation */ +#define mix_vm_clock_get_time(clock) (clock? clock->time:0) + +#endif /* MIX_VM_CLOCK_H */ + diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c new file mode 100644 index 0000000..9cc0d52 --- /dev/null +++ b/mixlib/mix_vm_command.c @@ -0,0 +1,1167 @@ +/* -*-c-*- -------------- mix_vm_command.c : + * Implementation of the functions declared in mix_vm_command.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/15 15:57:52 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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 +#include +#include +#include +#include + +#include "mix_vm_command.h" +#include "mix_vm.h" +#include "mix_vm_dump.h" +#include "mix_eval.h" + +/* hooks */ +typedef struct +{ + mix_vm_cmd_hook_t func; + gpointer data; +} hook_; + +typedef struct +{ + mix_vm_cmd_global_hook_t func; + gpointer data; +} global_hook_; + +struct mix_vm_cmd_dispatcher_t +{ + mix_vm_t *vm; /* the virtual machine */ + gboolean result; /* last command's outcome */ + gchar *program; /* the name of the last loaded program */ + FILE *out; /* message output file */ + FILE *err; /* error output file */ + mix_dump_context_t *dump; /* dump context for output */ + mix_eval_t *eval; /* evaluator for w-expressions */ + gboolean trace; /* tracing flag */ + gboolean printtime; /* printing times flag */ + mix_time_t uptime; /* total running time */ + mix_time_t laptime; /* last run time */ + mix_time_t progtime; /* current program running time */ + hook_ pre_hooks[MIX_CMD_INVALID]; /* Pre-command hooks */ + hook_ post_hooks[MIX_CMD_INVALID]; /* Post-command hooks */ + global_hook_ global_pre; /* global pre-command hook */ + global_hook_ global_post; /* global post-command hook */ +}; + +/* command handlers */ +typedef gboolean (*Function_)(mix_vm_cmd_dispatcher_t *, const gchar *); +#define DEC_FUN(name) \ + static int cmd_##name (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) + +DEC_FUN (help_); +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 (ssym_); +DEC_FUN (sbp_); +DEC_FUN (sbpa_); +DEC_FUN (cbp_); +DEC_FUN (cbpa_); +DEC_FUN (cabp_); +DEC_FUN (weval_); +DEC_FUN (w2d_); +DEC_FUN (tron_); +DEC_FUN (troff_); + +/* internal command info struct */ +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_; + +/* available commands (in the same order as the type enum) */ + +command_ commands_[] = { + { "help", cmd_help_, N_("Display this text"), "help [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"}, + { "ssym", cmd_ssym_, N_("Set a symbol\'s value"), "ssym SYMBOL WEXPR"}, + { "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"}, + { "weval", cmd_weval_, N_("Evaluate a given W-expression"), "weval WEXPR"}, + { "w2d", cmd_w2d_, N_("Convert a MIX word to its decimal value"), + "w2d WORD"}, + { "tron", cmd_tron_, N_("Turn on instruction tracing."), "tron"}, + { "troff", cmd_troff_, N_("Turn off instruction tracing."), "troff"}, + { NULL, NULL, NULL, NULL}, +}; + + +/* external interface */ + +/* conversion from/to commands to strings */ +const gchar * +mix_vm_command_to_string (mix_vm_command_t cmd) +{ + if (cmd < MIX_CMD_INVALID) return commands_[cmd].name; + else return NULL; +} + +mix_vm_command_t +mix_vm_command_from_string (const gchar *name) +{ + /* inefficient linear search, i know */ + gint cmd = 0; + while (cmd < MIX_CMD_INVALID && strcmp (name, commands_[cmd].name)) + ++cmd; + return cmd; +} + +/* get help string about a command */ +const gchar * +mix_vm_command_help (mix_vm_command_t cmd) +{ + if (cmd < MIX_CMD_INVALID) return commands_[cmd].doc; + else return NULL; +} + +const gchar * +mix_vm_command_usage (mix_vm_command_t cmd) +{ + if (cmd < MIX_CMD_INVALID) return commands_[cmd].usage; + else return NULL; +} + +/* create a new command dispatcher */ +mix_vm_cmd_dispatcher_t * +mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ + FILE *err_fd /* error messages file */) +{ + mix_vm_cmd_dispatcher_t *result = NULL; + int k; + + g_return_val_if_fail (out_fd && err_fd, NULL); + + result = g_new (mix_vm_cmd_dispatcher_t, 1); + result->result = TRUE; + result->out = out_fd; + result->err = err_fd; + result->uptime = result->laptime = result->progtime = 0; + result->printtime = TRUE; + result->trace = FALSE; + result->program = NULL; + result->eval = mix_eval_new (); + result->dump = mix_dump_context_new (out_fd, + MIX_SHORT_ZERO, MIX_SHORT_ZERO, + MIX_DUMP_ALL); + result->vm = mix_vm_new (); + result->global_pre.func = result->global_post.func = NULL; + result->global_pre.data = result->global_post.data = NULL; + for (k =0; k < MIX_CMD_INVALID; ++k) + { + result->pre_hooks[k].func = result->post_hooks[k].func = NULL; + result->pre_hooks[k].data = result->post_hooks[k].data = NULL; + } + + return result; +} + +/* delete (does not close the fds in the constructor) */ +extern void +mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) +{ + g_return_if_fail (dis != NULL); + mix_eval_delete (dis->eval); + mix_dump_context_delete (dis->dump); + mix_vm_delete (dis->vm); + g_free (dis); +} + +/* install hooks */ +void +mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + mix_vm_cmd_hook_t hook, gpointer data) +{ + g_return_if_fail (dis != NULL); + g_return_if_fail (cmd < MIX_CMD_INVALID); + dis->pre_hooks[cmd].func = hook; + dis->pre_hooks[cmd].data = data; +} + +void +mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + mix_vm_cmd_hook_t hook, gpointer data) +{ + g_return_if_fail (dis != NULL); + g_return_if_fail (cmd < MIX_CMD_INVALID); + dis->post_hooks[cmd].func = hook; + dis->post_hooks[cmd].data = data; +} + +void +mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_cmd_global_hook_t hook, + gpointer data) +{ + g_return_if_fail (dis != NULL); + dis->global_pre.func = hook; + dis->global_pre.data = data; +} + +void +mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_cmd_global_hook_t hook, + gpointer data) +{ + g_return_if_fail (dis != NULL); + dis->global_post.func = hook; + dis->global_post.data = data; +} + +/* dispatch a command */ +gboolean /* TRUE if success, FALSE otherwise */ +mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg) +{ + g_return_val_if_fail (dis != NULL, FALSE); + + if (dis->global_pre.func) + (dis->global_pre.func)(dis, cmd, arg, dis->global_pre.data); + + if (cmd < MIX_CMD_INVALID) + { + if (dis->pre_hooks[cmd].func) + (dis->pre_hooks[cmd].func)(dis, arg, dis->pre_hooks[cmd].data); + dis->result = (commands_[cmd].func)(dis, arg); + if (dis->post_hooks[cmd].func) + (dis->post_hooks[cmd].func)(dis, arg, dis->post_hooks[cmd].data); + } + else + { + fprintf (dis->err, "Unknown command. Try: help"); + } + + if (dis->global_post.func) + (dis->global_post.func)(dis, cmd, arg, dis->global_post.data); + + fflush (dis->out); + fflush (dis->err); + return dis->result; +} + +/* dispatch a command in text format */ +gboolean +mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, + const gchar *text) +{ + gchar *cp, *arg = ""; + int k = 0; + gboolean result; + + g_return_val_if_fail (dis != NULL, FALSE); + g_return_val_if_fail (text != NULL, FALSE); + + cp = g_strdup (text); + while (cp[k] && !isspace (cp[k])) ++k; + if (cp[k]) + { + cp[k] = '\0'; ++k; + while (cp[k] && isspace (cp[k])) ++k; + arg = cp + k; + } + + result = mix_vm_cmd_dispatcher_dispatch (dis, + mix_vm_command_from_string (cp), + arg); + g_free (cp); + return result; +} + +/* get the last dispatch's result */ +gboolean +mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, FALSE); + return dis->result; +} + +/* get total uptime */ +mix_time_t +mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return dis->uptime; +} + +/* get program total time */ +mix_time_t +mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return dis->progtime; +} + +/* get time lapse */ +mix_time_t +mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return dis->laptime; +} + +/* toggle time printing */ +void +mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, gboolean print) +{ + g_return_if_fail (dis != NULL); + dis->printtime = print; +} + +/* get the mix vm */ +const mix_vm_t * +mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, NULL); + return dis->vm; +} + + +/* trace current instruction */ +static void +trace_ (mix_vm_cmd_dispatcher_t *dis) +{ + enum {BUFFER_LEN = 128}; + static gchar STRINS[BUFFER_LEN]; + + const mix_src_file_t *file = mix_vm_get_src_file (dis->vm); + const gchar *line = "\n"; + mix_address_t loc = mix_vm_get_prog_count (dis->vm); + mix_word_t ins = mix_vm_get_addr_contents (dis->vm, loc); + mix_ins_t fins; + mix_word_to_ins_uncheck (ins, fins); + mix_ins_to_string_in_buffer (&fins, STRINS, BUFFER_LEN); + + if (file != NULL) + { + gulong b = mix_vm_get_break_lineno (dis->vm); + if (b > 0) line = mix_src_file_get_line (file, b); + } + + fprintf (dis->out, "%d: [%-15s]\t%s", (gint)loc, STRINS, line); +} + +/* run a program tracing executed instructions */ +static int +run_and_trace_ (mix_vm_cmd_dispatcher_t *dis) +{ + int k = MIX_VM_OK; + if (!dis->trace) + return mix_vm_run (dis->vm); + else while (k == MIX_VM_OK) + { + trace_ (dis); + k = mix_vm_exec_next (dis->vm); + } + return k; +} + +/* print time statistics */ +static void +print_time_ (mix_vm_cmd_dispatcher_t *dis) +{ + dis->laptime = mix_vm_get_uptime(dis->vm) - dis->uptime; + dis->uptime += dis->laptime; + dis->progtime += dis->laptime; + if (dis->printtime) + fprintf( dis->out, + _("Elapsed time: %ld /Total program time: %ld (Total uptime: %ld)\n"), + dis->laptime, dis->progtime, dis->uptime); +} + + +/* commands */ + +static gboolean +cmd_help_ (mix_vm_cmd_dispatcher_t *dis, const gchar *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)) + { + fprintf (dis->out ,_("%s\t\t%s. Usage: %s\n"), commands_[i].name, + _(commands_[i].doc), commands_[i].usage); + printed++; + } + } + + if (!printed) + { + fprintf (dis->out, + _("No commands match `%s'. Possibilities are:\n"), arg); + + for (i = 0; commands_[i].name; i++) + { + if (printed == NO_OF_COLS) + { + printed = 0; + fprintf (dis->out, "\n"); + } + + fprintf (dis->out, "%s\t", commands_[i].name); + printed++; + } + + if (printed) + fprintf (dis->out, "\n"); + } + return TRUE; +} + +static gboolean +cmd_load_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + errno = 0; + if (arg == NULL || *arg == '\0') + { + fputs (_("Missing file name\n"), dis->err); + return FALSE; + } + mix_eval_remove_symbols_from_table (dis->eval, + mix_vm_get_symbol_table (dis->vm)); + if (!mix_vm_load_file (dis->vm, arg) ) + { + fprintf (dis->err, _("Cannot load %s: "), arg); + if ( errno == 0 ) + fputs (_("Wrong file format\n"), dis->err); + else + fprintf (dis->err, "%s\n", strerror (errno)); + return FALSE; + } + + if (dis->program != arg) + { + if (dis->program) g_free (dis->program); + dis->program = g_strdup (arg); + } + + mix_eval_set_symbols_from_table (dis->eval, + mix_vm_get_symbol_table (dis->vm)); + + fprintf (dis->out, _("Program loaded. Start address: %d\n"), + mix_vm_get_prog_count (dis->vm)); + + dis->laptime = dis->progtime = 0; + return TRUE; +} + + +static gboolean +cmd_run_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg != NULL && *arg != '\0' && cmd_load_ (dis, arg) != TRUE) + return FALSE; + + if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program); + + fputs (_("Running ...\n"), dis->out); + + switch (run_and_trace_ (dis)) + { + case MIX_VM_HALT: + fputs (_("... done\n"), dis->out); + break; + case MIX_VM_BREAK: + { + gulong line = mix_vm_get_break_lineno (dis->vm); + if (line != 0) + fprintf (dis->out, + _("... stopped: breakpoint at line %ld (address %d)\n"), + line, mix_vm_get_prog_count (dis->vm)); + else + fprintf (dis->out, _("... stopped: breakpoint at address %d\n"), + mix_vm_get_prog_count (dis->vm)); + } + break; + case MIX_VM_ERROR: + fputs (_("... error executing loaded file"), dis->err); + break; + default: + g_assert_not_reached (); + break; + } + print_time_ (dis); + + return TRUE; +} + +static gboolean +cmd_next_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + int ins_no = 1; + int k; + + if ( strlen (arg) != 0 ) + { + int k = 0; + while (isdigit (arg[k])) + k++; + if (arg[k] != '\0') + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "next"); + return FALSE; + } + ins_no = atoi (arg); + } + + if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program); + + while ( ins_no-- > 0 ) + { + if (dis->trace) trace_ (dis); + k = mix_vm_exec_next (dis->vm); + if (k == MIX_VM_HALT) + { + fprintf (dis->err, _("End of program reached at address %d\n"), + mix_vm_get_prog_count (dis->vm)); + break; + } + else if (k == MIX_VM_ERROR) + { + fprintf (dis->err, _("Error at address %d\n"), + mix_vm_get_prog_count (dis->vm)); + break; + } + } + print_time_ (dis); + + return TRUE; +} + +static gboolean +cmd_pc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + fprintf (dis->out, "Current address: %d\n", mix_vm_get_prog_count (dis->vm)); + return TRUE; +} + +static gboolean +cmd_psym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gboolean result = FALSE; + const mix_symbol_table_t *table = mix_eval_symbol_table (dis->eval); + if ( table == NULL ) + fputs (_("Symbol table not available\n"), dis->err); + else if (arg != NULL && *arg != '\0') + { + if ( mix_symbol_table_is_defined (table, arg) ) + { + mix_word_print (mix_symbol_table_value (table, arg), NULL); + putc ('\n', dis->out); + result = TRUE; + } + else + fprintf (dis->out, _("%s: symbol not defined\n"), arg); + } + else + { + mix_symbol_table_print (table, MIX_SYM_ROWS, stdout, TRUE); + result = TRUE; + } + + return result; +} + +static gboolean +cmd_preg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_dump_context_set_opt (dis->dump, MIX_DUMP_NONE); + if ( strlen (arg) == 0 ) + mix_dump_context_add_opt (dis->dump, MIX_DUMP_rALL); + else switch (*arg) + { + case 'A': + mix_dump_context_add_opt (dis->dump, MIX_DUMP_rA); + break; + case 'X': + mix_dump_context_add_opt (dis->dump, MIX_DUMP_rX); + break; + case 'J': + mix_dump_context_add_opt (dis->dump, MIX_DUMP_rJ); + break; + case 'I': + { + if ( strlen (arg) == 1 ) + mix_dump_context_add_opt (dis->dump, 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 (dis->err, _("Invalid I index: %d"), i); + return FALSE; + } + mix_dump_context_add_opt (dis->dump, opt[i]); + } + } + break; + default: + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + return FALSE; + } + mix_vm_dump (dis->vm, dis->dump); + return TRUE; +} + +static gboolean +cmd_pflags_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_dump_context_set_opt (dis->dump, MIX_DUMP_CMP | MIX_DUMP_OVER); + mix_vm_dump (dis->vm, dis->dump); + return TRUE; +} + +static gboolean +cmd_pall_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_dump_context_set_opt (dis->dump, MIX_DUMP_ALL_NOMEM); + mix_vm_dump (dis->vm, dis->dump); + return TRUE; +} + +static gboolean +cmd_pmem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) +{ + glong begin = MIX_SHORT_ZERO, end = MIX_SHORT_ZERO; + int i = 0; + gboolean error = FALSE; + gchar *arg = NULL; + + if ( strlen (carg) == 0 ) + { + fputs (_("Missing memory address\n"), dis->err); + return FALSE; + } + arg = g_strdup (carg); + 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 (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "pmem"); + } + else if ( end < begin || end > MIX_VM_CELL_NO - 1 ) + { + fprintf (dis->err, _("Invalid range: %ld-%ld\n"), begin, end); + error = TRUE; + } + else + { + mix_dump_context_set_opt (dis->dump, MIX_DUMP_CELLS); + mix_dump_context_range (dis->dump, mix_short_new (begin), + mix_short_new (end + 1)); + mix_vm_dump (dis->vm, dis->dump); + } + g_free (arg); + return !error; +} + +static gboolean +cmd_sreg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *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 (dis->vm, mix_word_new (value)); + break; + case 'X': + mix_vm_set_rX (dis->vm, mix_word_new (value)); + break; + case 'J': + if ( value >= 0 ) + mix_vm_set_rJ (dis->vm, mix_short_new (value)); + else + ok = FALSE; + break; + case 'I': + { + guint k = arg[1] - '0'; + if ( k < 7 ) + mix_vm_set_rI (dis->vm, k, mix_short_new (value)); + else + ok = FALSE; + } + break; + default: + ok = FALSE; + } + } + } + if (!ok) + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "sreg"); + } + + return ok; +} + +static gboolean +cmd_scmp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gboolean ok = (strlen (arg) == 1); + if (ok) switch (arg[0]) + { + case 'L': + mix_vm_set_cmpflag (dis->vm, mix_LESS); + break; + case 'E': + mix_vm_set_cmpflag (dis->vm, mix_EQ); + break; + case 'G': + mix_vm_set_cmpflag (dis->vm, mix_GREAT); + break; + default: + ok = FALSE; + } + if (!ok) + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "scmp"); + } + + return ok; +} + +static gboolean +cmd_sover_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gboolean ok = (strlen (arg) == 1); + if (ok) switch (arg[0]) + { + case 'T': + mix_vm_set_overflow (dis->vm, TRUE); + break; + case 'F': + mix_vm_set_overflow (dis->vm, FALSE); + break; + default: + ok = FALSE; + } + if (!ok) + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "sover"); + } + + return ok; +} + +static gboolean +cmd_smem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) +{ + gboolean ok = (strlen (carg) > 2 && isdigit (carg[0])); + gulong addr; + glong value; + int k = 0; + gchar *arg = NULL; + + if (ok) + { + arg = g_strdup (carg); + 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 (dis->vm, mix_short_new (addr), + mix_word_new (value)); + else + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "smem"); + } + g_free (arg); + + return ok; +} + +static gboolean +cmd_ssym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gboolean result = FALSE; + if (arg == NULL || strlen(arg) == 0) + { + fprintf (dis->err, _("Missing arguments\n")); + cmd_help_ (dis, "ssym"); + } + else + { + gchar *a = g_strdup (arg); + gchar *s = strtok (a, " \t"); + gchar *w = strtok (NULL, " \t"); + if (w != NULL && strtok (NULL, " \t") == NULL) + { + cmd_weval_ (dis, w); + if (mix_eval_last_error (dis->eval) == MIX_EVAL_OK) { + mix_eval_set_symbol (dis->eval, s, mix_eval_value (dis->eval)); + result = TRUE; + } + } + else + { + fprintf (dis->err, _("Wrong argument number\n")); + cmd_help_ (dis, "ssym"); + } + g_free (a); + } + return result; +} + +static gboolean +cmd_sbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + glong lineno; + glong k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "sbp"); + return FALSE; + } + lineno = atol (arg); + switch (k = mix_vm_set_breakpoint (dis->vm, lineno)) + { + case MIX_VM_BP_INV_LINE: + fprintf (dis->err, _("Line number %ld too high\n"), lineno); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not set breakpoint. Internal error\n"), dis->err); + break; + case MIX_VM_BP_NDEBUG: + fputs (_("Could not set breakpoint. No debug info available\n"), + dis->err); + break; + default: + fprintf (dis->err, _("Breakpoint set at line %ld\n"), k); + return TRUE; + } + return FALSE; +} + +static gboolean +cmd_sbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + glong address; + glong k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "sbpa"); + return FALSE; + } + address = atol (arg); + switch (mix_vm_set_breakpoint_address (dis->vm, address)) + { + case MIX_VM_BP_INV_ADDRESS: + fprintf (dis->err, _("Invalid address %ld\n"), address); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not set breakpoint. Internal error\n"), dis->err); + break; + default: + fprintf (dis->err, _("Breakpoint set at address %ld\n"), address); + return TRUE; + } + return FALSE; +} + +static gboolean +cmd_cbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + glong lineno; + int k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "cbp"); + return FALSE; + } + lineno = atol (arg); + switch (mix_vm_clear_breakpoint (dis->vm, lineno)) + { + case MIX_VM_BP_INV_LINE: + fprintf (dis->err, _("No breakpoint set at line %ld\n"), lineno); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not set breakpoint. Internal error\n"), dis->err); + break; + case MIX_VM_BP_NDEBUG: + fputs (_("No debug info available\n"), dis->err); + break; + case MIX_VM_BP_OK: + fprintf (dis->err, _("Breakpoint cleared at line %ld\n"), lineno); + return TRUE; + default: + g_assert_not_reached (); + break; + } + return FALSE; +} + +static gboolean +cmd_cbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + glong address; + glong k = 0; + while (isdigit (arg[k])) k++; + if (arg[k] != '\0') + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "cbpa"); + return FALSE; + } + address = atol (arg); + switch (mix_vm_clear_breakpoint_address (dis->vm, address)) + { + case MIX_VM_BP_INV_ADDRESS: + fprintf (dis->err, _("Invalid address %ld\n"), address); + break; + case MIX_VM_BP_ERROR: + fputs (_("Could not clear breakpoint. Internal error\n"), dis->err); + break; + default: + fprintf (dis->err, _("Breakpoint cleared at address %ld\n"), address); + return TRUE; + } + return FALSE; +} + + +static gboolean +cmd_cabp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (strlen (arg) != 0) + { + fprintf (dis->err, _("Invalid argument: %s\n"), arg); + cmd_help_ (dis, "cabp"); + return FALSE; + } + mix_vm_clear_all_breakpoints (dis->vm); + return TRUE; +} + +static gboolean +cmd_weval_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if ( strlen (arg) == 0 ) + { + cmd_help_ (dis, "weval"); + return FALSE; + } + + if (mix_eval_expression_with_loc (dis->eval, arg, + mix_vm_get_prog_count (dis->vm)) == + MIX_EVAL_OK) + { + mix_word_print_to_file (mix_eval_value (dis->eval), NULL, dis->out); + putc ('\n', dis->out); + return TRUE; + } + else + { + gint pos = mix_eval_last_error_pos (dis->eval); + gint k, len = strlen (arg); + g_assert(pos > -1 && pos <= len); + for (k = 0; kerr); + fputc ('\n', dis->err); + for (k = 0; kerr); + for (k = pos; k < len; ++k) fputc (arg[k], dis->err); + fprintf (dis->err, _("\nEvaluation error: %s\n"), + mix_eval_last_error_string (dis->eval)); + return FALSE; + } +} + +static gboolean +cmd_w2d_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if ( strlen (arg) == 0 ) + { + cmd_help_ (dis, "w2d"); + return FALSE; + } + else + { + gchar *cp = g_strdup (arg), *a = cp; + mix_byte_t bytes[5] = {0, 0, 0, 0, 0}; + gchar *b; + guint k = 0; + gboolean is_n = (a[0] == '-'), success = TRUE; + if (a[0] == '+' || a[0] == '-') ++a; + b = strtok (a, " \t"); + while (b != NULL && k < 5) + { + if (strlen (b) != 2 || !isdigit(b[0]) || !isdigit(b[1])) + { + fprintf (dis->err, _("Incorrect byte specification: %s\n"), b); + success = FALSE; + b = NULL; + } + else + { + bytes[k++] = mix_byte_new (atoi (b)); + b = strtok (NULL, " \t"); + } + } + if (success) + { + if (strtok (NULL, "\t") != NULL) + { + fprintf (dis->err, + _("The expression %s does not fit in a word\n"), arg); + success = FALSE; + } + else + { + mix_word_t w = mix_bytes_to_word (bytes, k); + fprintf (dis->out, "%s%ld\n", is_n? "-":"+", + mix_word_magnitude (w)); + } + } + g_free (cp); + + return success; + } +} + +static gboolean +cmd_tron_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + dis->trace = TRUE; + fprintf (dis->out, _("Instruction tracing has been turned ON.\n")); + return TRUE; +} + +static gboolean +cmd_troff_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + dis->trace = FALSE; + fprintf (dis->out, _("Instruction tracing has been turned OFF.\n")); + return TRUE; +} diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h new file mode 100644 index 0000000..856c2d5 --- /dev/null +++ b/mixlib/mix_vm_command.h @@ -0,0 +1,160 @@ +/* -*-c-*- ---------------- mix_vm_command.h : + * declarations for mix_vm_command_t, describing commands issued to a vm + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/15 15:57:36 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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_COMMAND_H +#define MIX_VM_COMMAND_H + +#include +#include "mix.h" +#include "mix_vm.h" + +/* mix_vm_cmd_dispatcher encapsulates a virtual machine and helper + objects, providing a command driven interface with output to + provided files (in the posix sense). +*/ +typedef struct mix_vm_cmd_dispatcher_t mix_vm_cmd_dispatcher_t; + +/* mix_vm_cmd_dispatcher understands the commands of this type */ +typedef enum { + MIX_CMD_HELP = 0, /* echo help message */ + MIX_CMD_LOAD, /* load a mix program */ + MIX_CMD_RUN, /* run a loaded program */ + MIX_CMD_NEXT, /* run next instruction */ + MIX_CMD_LOC, /* print location pointer */ + MIX_CMD_PSYM, /* print symbol */ + MIX_CMD_PREG, /* print registry */ + MIX_CMD_PFLAGS, /* print comp and overf flags */ + MIX_CMD_PALL, /* print all registers and flags */ + MIX_CMD_PMEM, /* print memory cells */ + MIX_CMD_SREG, /* set register value */ + MIX_CMD_SCMP, /* set comparison flag value */ + MIX_CMD_SOVER, /* set overflow toggle value */ + MIX_CMD_SMEM, /* set memory cell value */ + MIX_CMD_SSYM, /* set symbol value */ + MIX_CMD_SBP, /* set breakpoint at lineno */ + MIX_CMD_CBP, /* clear breakpoint at lineno */ + MIX_CMD_SBPA, /* set breakpoint at address */ + MIX_CMD_CBPA, /* clear breakpoint at address */ + MIX_CMD_CABP, /* clear all breakpoints */ + MIX_CMD_WEVAL, /* evaluate a w-expression */ + MIX_CMD_W2D, /* print word in decimal notation */ + MIX_CMD_TRON, /* enable instruction traces */ + MIX_CMD_TROFF, /* disble instruction traces */ + MIX_CMD_INVALID, /* invalid command identifier */ +} mix_vm_command_t; + +/* hook functions, to be invoked before and/or after command execution */ +typedef void (*mix_vm_cmd_hook_t)(mix_vm_cmd_dispatcher_t *dis, + const gchar *arg, gpointer data); + +/* global hook functions */ +typedef void (*mix_vm_cmd_global_hook_t)(mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + const gchar *arg, gpointer data); + +/* conversion from/to commands to strings */ +extern const gchar * +mix_vm_command_to_string (mix_vm_command_t cmd); + +extern mix_vm_command_t +mix_vm_command_from_string (const gchar *name); + +/* get help string about a command */ +extern const gchar * +mix_vm_command_help (mix_vm_command_t cmd); + +extern const gchar * +mix_vm_command_usage (mix_vm_command_t cmd); + + +/* create a new command dispatcher */ +extern mix_vm_cmd_dispatcher_t * +mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ + FILE *err_fd /* error messages file */); + +/* delete (does not close the fds in the constructor) */ +extern void +mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis); + +/* dispatch a command */ +extern gboolean /* TRUE if success, FALSE otherwise */ +mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg); + +/* dispatch a command in text format */ +extern gboolean +mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, + const gchar *text); + +/* get the last dispatch's result */ +extern gboolean +mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis); + +/* get total uptime */ +extern mix_time_t +mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis); + +/* get program total time */ +extern mix_time_t +mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis); + +/* get time lapse */ +extern mix_time_t +mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis); + +/* toggle time printing */ +extern void +mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, + gboolean print); + +/* install hooks */ +extern void +mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + mix_vm_cmd_hook_t hook, gpointer data); + +extern void +mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + mix_vm_cmd_hook_t hook, gpointer data); + +extern void +mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_cmd_global_hook_t hook, + gpointer data); + +extern void +mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_cmd_global_hook_t hook, + gpointer data); + + + +/* get the mix vm */ +extern const mix_vm_t * +mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis); + + +#endif /* MIX_VM_COMMAND_H */ + diff --git a/mixlib/mix_vm_dump.c b/mixlib/mix_vm_dump.c new file mode 100644 index 0000000..91953fd --- /dev/null +++ b/mixlib/mix_vm_dump.c @@ -0,0 +1,147 @@ +/* ---------------------- mix_vm_dump.c : + * Implementation of the functions declared in mix_vm_dump.h + * ------------------------------------------------------------------ +** Copyright (C) 2000 Free Software Foundation, Inc. +** +** 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 +#include "xmix_vm.h" +#include "mix_vm_dump.h" + +/* Create/destroy a dump context */ +mix_dump_context_t * +mix_dump_context_new(FILE *fd, mix_address_t begin, mix_address_t end, + guint32 options) +{ + mix_dump_context_t *result = NULL; + + g_return_val_if_fail (fd != NULL, NULL); + + if ( begin > end ) begin = end; + if ( end >= MEM_CELLS_NO_ ) end = MEM_CELLS_NO_; + + result = g_new (mix_dump_context_t,1); + result->options = options; + result->begin = begin; + result->end = end; + result->channel = fd; + + return result; +} + +void +mix_dump_context_delete (mix_dump_context_t *dc) +{ + g_return_if_fail (dc != NULL); + g_free (dc); +} + +/* 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) + +void +mix_vm_dump (const mix_vm_t *vm, const mix_dump_context_t *dc) +{ + guint j, i; + FILE *f; + + g_return_if_fail (vm != NULL); + g_return_if_fail (dc != NULL); + + f = dc->channel; + + if ( (dc->options & MIX_DUMP_rA) == MIX_DUMP_rA ) + { + mix_word_t rA = get_rA_ (vm); + fprintf (f, "rA: " WORD_FMT_ "\n", WORD_ARGS_ (rA)); + } + + if ( (dc->options & MIX_DUMP_rX) == MIX_DUMP_rX ) + { + mix_word_t rX = get_rX_ (vm); + fprintf (f, "rX: " WORD_FMT_ "\n", WORD_ARGS_ (rX)); + } + + if ( (dc->options & MIX_DUMP_rJ) == MIX_DUMP_rJ ) + { + mix_short_t rJ = get_rJ_ (vm); + fprintf (f, "rJ: " SHORT_FMT_ "\n", SHORT_ARGS_ (rJ)); + } + + for (j = 0, i = 0; j < IREG_NO_; ++j) + { + if ( (dc->options & (MIX_DUMP_rI1<options & MIX_DUMP_OVER) == MIX_DUMP_OVER ) + { + fprintf (f, _("Overflow: %s\n"), get_over_ (vm)? "T":"F"); + } + + if ( (dc->options & MIX_DUMP_CMP) == MIX_DUMP_CMP ) + { + 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; + } + fprintf (f, _("Cmp: %s\n"), val); + } + + 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); + fprintf (f, "%04d: " WORD_FMT_ "\n", j, WORD_ARGS_ (cell)); + } + } + fflush (f); +} + diff --git a/mixlib/mix_vm_dump.h b/mixlib/mix_vm_dump.h new file mode 100644 index 0000000..8c5e1bd --- /dev/null +++ b/mixlib/mix_vm_dump.h @@ -0,0 +1,91 @@ +/* ---------------------- mix_vm_dump.h : + * This file declares types and functions for dumping the contents + * of a mix virtual machine. + * ------------------------------------------------------------------ +** Copyright (C) 2000, 2001 Free Software Foundation, Inc. +** +** 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 +#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 */ + FILE *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 (stdout) + +/* Create/destroy a dump context */ +extern mix_dump_context_t * +mix_dump_context_new (FILE *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) + + +/* 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..c936d6c --- /dev/null +++ b/mixlib/testsuite/.cvsignore @@ -0,0 +1,28 @@ +.deps +Makefile +Makefile.in +cardwr.dev +disk0.dev +disk1.dev +disk2.dev +disk3.dev +disk4.dev +disk5.dev +disk6.dev +disk7.dev +mixdevtest +mixevaltest +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..6e771c4 --- /dev/null +++ b/mixlib/testsuite/Makefile.am @@ -0,0 +1,28 @@ +# Copyright (C) 1999 Free Software Foundation, Inc. +# +# 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 mixevaltest +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 +mixevaltest_SOURCES = test.h mix_eval_t.c + + + + + + diff --git a/mixlib/testsuite/mix_device_t.c b/mixlib/testsuite/mix_device_t.c new file mode 100644 index 0000000..da4c8f9 --- /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 Free Software Foundation, Inc. + * + * 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 +#include + +/* 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_eval_t.c b/mixlib/testsuite/mix_eval_t.c new file mode 100644 index 0000000..83f9a5d --- /dev/null +++ b/mixlib/testsuite/mix_eval_t.c @@ -0,0 +1,119 @@ +/* -*-c-*- -------------- mix_eval_t.c : + * Test of mix_eval_t + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/02/20 00:26:15 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 +#include +/* Define VERBOSE_TEST if you want to get prints of the test */ +/* #define VERBOSE_TEST */ +#include "test.h" + +typedef struct test_case_t +{ + const gchar *expr; + gint value; + mix_eval_result_t result; +} test_case_t; + +#define ok_case(exp,val) {exp, val, MIX_EVAL_OK} +#define err_case(exp,err) {exp, 0, err} + +typedef struct sym_val_t +{ + const gchar *sym; + mix_word_t value; +} sym_val_t; + +#define new_symbol(sym,val) {sym, mix_word_new (val)} + +int +main(int argc, char **argv) +{ + size_t k; + mix_eval_t *eval; + mix_short_t loc = mix_short_new (30); + sym_val_t symbols[] = { + new_symbol ("s0", 43), + new_symbol ("s1", -1234), + new_symbol ("s2", 0), + new_symbol ("s3", -20), + new_symbol (NULL, 0) + }; + + test_case_t cases[] = { + ok_case ("2343", 2343), + ok_case ("-890", -890), + ok_case ("15+1015", 1030), + ok_case ("1-481", -480), + ok_case ("2300/10", 230), + ok_case ("24*3", 72), + ok_case ("2:5", 21), + ok_case ("1//3", 357913941), + ok_case ("12+*", 42), + ok_case ("***", 900), + ok_case ("1:3*2-4", 18), + ok_case ("-1+5*20/6", 13), + ok_case ("-1000(0,2),1", 1), + ok_case ("s0-s2*3", 129), + ok_case ("s3**", -600), + ok_case ("s3(3:5)", 20), + ok_case ("-s1", 1234), + ok_case ("s1/10+s0", 166), + err_case ("foo", MIX_EVAL_UNDEF_SYM), + err_case ("11--2", MIX_EVAL_SYNTAX), + err_case ("s2*foo*3", MIX_EVAL_UNDEF_SYM), + err_case ("12/32),1", MIX_EVAL_MIS_PAREN), + err_case ("2000(88)", MIX_EVAL_INV_FSPEC), + ok_case (NULL, 0) + }; + + INIT_TEST; + g_print ("Entering mix_eval test..."); + eval = mix_eval_new (); + + for (k = 0; symbols[k].sym; ++k) + mix_eval_set_symbol (eval, symbols[k].sym, symbols[k].value); + + for (k = 0; cases[k].expr; ++k) { + mix_eval_result_t r = cases[k].result, s; + g_print ("Evaluating \"%s\" = %d ...", + cases[k].expr, cases[k].value); + + s = mix_eval_expression_with_loc (eval, cases[k].expr, loc); + g_assert (s == r); + if ( s == MIX_EVAL_OK ) { + mix_word_print (mix_eval_value (eval), "... "); + g_print ("\n"); + g_assert (mix_eval_value (eval) == mix_word_new(cases[k].value)); + } else { + g_print ("\n------->%s, at pos %d\n", + mix_eval_last_error_string (eval), + mix_eval_last_error_pos (eval)); + } + } + mix_eval_delete (eval); + + 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..f643b47 --- /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 Free Software Foundation, Inc. +** +** 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 +#include + +/* 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..7bfa9d0 --- /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 Free Software Foundation, Inc. + * + * 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 +#include + +/* 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..be9fb46 --- /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 Free Software Foundation, Inc. +** +** 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 +#include + +/* 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..55ce7f3 --- /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 Free Software Foundation, Inc. +** +** 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 +/*#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..6bf6306 --- /dev/null +++ b/mixlib/testsuite/test.h @@ -0,0 +1,44 @@ +/* +** Copyright (C) 1999 Free Software Foundation, Inc. +** +** 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 +#include + +#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_device.c b/mixlib/xmix_device.c new file mode 100644 index 0000000..4754015 --- /dev/null +++ b/mixlib/xmix_device.c @@ -0,0 +1,131 @@ +/* -*-c-*- -------------- xmix_device.c : + * Implementation of the functions declared in xmix_device.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/03/02 23:14:57 jose" + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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_device.h" + +const char *DEV_EXT_ = ".dev"; + +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" +}; + +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 +}; + +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 +}; + +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_WRITE, mix_io_WRITE +}; + +/* + Write a block to the device. +*/ +static gboolean +write_ (mix_device_t *dev, const mix_word_t *block) +{ + gboolean result; + + 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))); + + fflush (mix_io_to_FILE (GET_CHANNEL_ (dev))); + + return result; +} + +static gboolean +read_ (mix_device_t *dev, mix_word_t *block) +{ + 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]); +} + +static gboolean +ioc_ (mix_device_t *dev, mix_short_t arg) +{ + int m; + FILE *file; + + 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; +} + +static gboolean +busy_ (const mix_device_t *dev) +{ + return (!mix_io_is_ready (GET_CHANNEL_(dev))); +} + +static mix_device_vtable_t VTABLE_ = { + write_, read_, ioc_, busy_ +}; + +const mix_device_vtable_t * DEF_DEV_VTABLE_ = &VTABLE_; diff --git a/mixlib/xmix_device.h b/mixlib/xmix_device.h new file mode 100644 index 0000000..45fd7d3 --- /dev/null +++ b/mixlib/xmix_device.h @@ -0,0 +1,77 @@ +/* -*-c-*- ---------------- xmix_device.h : + * Protected declarations for mix_device_t + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/03/02 01:15:22 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2001 Free Software Foundation, Inc. + * + * 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_DEVICE_H +#define XMIX_DEVICE_H + +#include "mix_file.h" +#include "mix_device.h" + +/* table of overridable device operations */ +typedef gboolean (*mix_dev_write_func_t) (mix_device_t *, const mix_word_t *); +typedef gboolean (*mix_dev_read_func_t) (mix_device_t *, mix_word_t *); +typedef gboolean (*mix_dev_ioc_func_t) (mix_device_t *, mix_short_t); +typedef gboolean (*mix_dev_busy_func_t) (const mix_device_t *); + +typedef struct mix_device_vtable_t +{ + mix_dev_write_func_t write; + mix_dev_read_func_t read; + mix_dev_ioc_func_t ioc; + mix_dev_busy_func_t busy; +} mix_device_vtable_t; + +/* default vtable */ +extern const mix_device_vtable_t *DEF_DEV_VTABLE_; + +/* + 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; + const mix_device_vtable_t *vtable; +}; + +#define GET_CHANNEL_(dev) (dev->file) +#define GET_FILE_(dev) ((mix_file_t *)(dev->file)) + +/* default extension for device files */ +extern const char *DEV_EXT_; +/* default names for device files */ +extern const char *DEF_NAMES_[]; +/* block sizes for devices */ +extern const size_t SIZES_[]; +/* io modes for devices */ +extern const mix_device_mode_t MODES_[]; +/* files modes for devices */ +extern const mix_fmode_t FMODES_[]; + + + + +#endif /* XMIX_DEVICE_H */ + diff --git a/mixlib/xmix_eval.h b/mixlib/xmix_eval.h new file mode 100644 index 0000000..b43803a --- /dev/null +++ b/mixlib/xmix_eval.h @@ -0,0 +1,55 @@ +/* -*-c-*- ---------------- xmix_eval.h : + * Definition of opaque types in mix_eval.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/02/20 00:25:14 jose> + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_EVAL_H +#define XMIX_EVAL_H + +#include "mix_eval.h" + +/* the evaluator type */ +struct mix_eval_t +{ + mix_symbol_table_t *table; /* symbol table */ + gboolean towner; /* true if owns the table */ + mix_eval_result_t result; /* last evaluation result */ + gint errpos; /* location of last error */ + mix_word_t value; /* last computed value */ +}; + +/* flex scanner data/result struct */ +typedef struct mix_eval_data_ +{ + gchar *expr; + const mix_symbol_table_t *table; + mix_word_t value; + mix_short_t loc; + gint errpos; +} mix_eval_data_; + +/* flex scanner prototype */ +extern +mix_eval_result_t mix_eval_expr (mix_eval_data_ *data); + +#endif /* XMIX_EVAL_H */ + diff --git a/mixlib/xmix_io.c b/mixlib/xmix_io.c new file mode 100644 index 0000000..7511949 --- /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 Free Software Foundation, Inc. + * + * 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 +#include +#include +#include +#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..19cbe04 --- /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 Free Software Foundation, Inc. + * + * 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 +#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..1915a0d --- /dev/null +++ b/mixlib/xmix_parser.h @@ -0,0 +1,107 @@ +/* -*-c-*- ---------------- xmix_parser.h : + * Declarations for the implementation of mix_parser_t + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 */ + +/* access loc counter */ +#define get_ploc_(parser) ((parser)->loc_count) + +/* symbol table */ +/* Define a new symbol with given value + * and update previously set refs to this symbol + */ +extern mix_parser_err_t +mix_parser_define_symbol_value (mix_parser_t *parser, const gchar *name, + mix_word_t value); + +/* 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, + mix_short_t value); + +/* 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..e614cb4 --- /dev/null +++ b/mixlib/xmix_vm.c @@ -0,0 +1,567 @@ +/* ---------------------- xmix_vm.c : + * Implementation of the functions declared in xmix_vm.h + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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); + inc_loc_ (vm); + if ( !mix_device_busy (get_dev_ (vm, ins->fspec)) ) + { + 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..cfbf65a --- /dev/null +++ b/mixlib/xmix_vm.h @@ -0,0 +1,117 @@ +/* ---------------------- xmix_vm.h : + * This file contains internal declarations used in the implementation + * of the mix_vm_t type. + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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_src_file.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 */ + GTree *address_table; /* adress -> source line no */ + gint8 bp[MEM_CELLS_NO_/8]; /* each bit signals a break point */ + mix_vm_clock_t *clock; /* the vm clock */ + mix_symbol_table_t *symbol_table; + mix_src_file_t *src_file; /* source of last loaded code file */ +}; + +/* 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 get_clock_(vm) (vm->clock) + +#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) +#define update_time_(vm,ins) mix_vm_clock_add_lapse (get_clock_(vm), ins) + +/* 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..2bd03be --- /dev/null +++ b/mixutils/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in + +# Copyright (C) 2000 Free Software Foundation, Inc. +# +# 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..64f0f3d --- /dev/null +++ b/mixutils/mixasm.c @@ -0,0 +1,126 @@ +/* -*-c-*- -------------- mixasm.c: + * Main function of mixasm, the mix assembler + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 + +#include +#include +#include + +#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..87b38be --- /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 Free Software Foundation, Inc. + * + * 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 +#include +#include +#include +#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..0fef0dd --- /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 Free Software Foundation, Inc. + * + * 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 + +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..eafc8a0 --- /dev/null +++ b/mixutils/mixvm.c @@ -0,0 +1,155 @@ +/* -*-c-*- -------------- mixvm.c : + * Main function for mixvm, the mix vm simulator + * ------------------------------------------------------------------ + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * 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 +#include +#include + +#include +#include +#include + +extern void +mix_vmloop (const gchar *code_file, gboolean use_emacs); + +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', + EMACS_OPT = 'e', /* used by mixvm-gud only */ +}; + +static const char *options_ = "vhurd"; /* no short opt for --emacs */ + +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}, + /* pek: yo! */ + {"emacs", no_argument, 0, EMACS_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; + gboolean emacs = 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; + case EMACS_OPT: + emacs = TRUE; + break; + 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, emacs); + + 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); + printf (_("** Execution time: %ld\n"), mix_vm_get_uptime (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..e1c03bf --- /dev/null +++ b/mixutils/mixvm_command.c @@ -0,0 +1,367 @@ +/* -*-c-*- -------------- mixvm_command.c : + * Implementation of the functions declared in mixvm_command.h + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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 + +#include +#include +#include + +#include + +#ifdef HAVE_LIBREADLINE +# include +# include +#else + typedef int Function (); +#endif /* HAVE_LIBREADLINE */ + +#include +#include +#include +#include +#include +#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 (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]" }, + { "shell", cmd_shell_, N_("Execute shell command"), "shell COMMAND" }, + { "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 } +}; + +#define LOCAL_COMANDS_NO_ ((sizeof (commands) / sizeof (commands[0])) - 1) +#define MIX_COMMANDS_NO_ MIX_CMD_INVALID+1 +#define ALL_COMMANDS_NO_ LOCAL_COMANDS_NO_+MIX_COMMANDS_NO_ + +static const char *mix_commands_[ALL_COMMANDS_NO_] = {NULL}; + + + +#ifdef HAVE_LIBREADLINE +/* 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 = mix_commands_[list_index]) != NULL) + { + list_index++; + if (strncmp (name, text, len) == 0) + return (g_strdup (name)); + } + + /* If no names matched, then return NULL. */ + return ((char *)NULL); +} +#endif /* HAVE_LIBREADLINE */ + +/* 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); +} + + +/* mixvm dispatcher */ +static mix_vm_cmd_dispatcher_t *dis_ = NULL; + +/* emacs interface */ +static void +emacs_output_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, gpointer data) +{ + /* pek: probably bad that we snag the src w/every emacs_output_, + however when multiple files are supported then this will + have to be done each time (but the info will be snagged + from elsewhere...) */ + const mix_vm_t *vm = mix_vm_cmd_dispatcher_get_vm (dis); + const mix_src_file_t *src = mix_vm_get_src_file (vm); + const gchar *path = mix_src_file_get_path (src); + + mix_address_t loc = mix_vm_get_prog_count (vm); + guint lineno = mix_vm_get_address_lineno (vm, loc); + + printf ("\032\032mixvm:%s%s:%d\n", path, MIX_SRC_DEFEXT, lineno); + return; +} + +static int +cmd_help_ (char *arg) +{ + 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 > 1) printf ("\n"); + + for (i = LOCAL_COMANDS_NO_ + 1 /* skip help cmd */; mix_commands_[i]; i++) + { + if (!*arg || (strcmp (arg, mix_commands_[i]) == 0)) + { + printf (_("%s\t\t%s. Usage: %s\n"), mix_commands_[i], + mix_vm_command_help (i - LOCAL_COMANDS_NO_), + mix_vm_command_usage (i - LOCAL_COMANDS_NO_)); + printed++; + } + } + + if (!printed) printf ("Command \'%s\' not found\n", arg); + + return TRUE; + +} + +static int +cmd_quit_ (char *arg) +{ + puts ("Quitting ..."); + if ( dis_ ) mix_vm_cmd_dispatcher_delete (dis_); + + /* pek: anything needed here to make the marker disappear??? */ + return FALSE; +} + + +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, gboolean use_emacs) +{ + int k; + /* get local command names */ + for (k = 0; k < LOCAL_COMANDS_NO_; ++k) + mix_commands_[k] = commands[k].name; + /* get external command names */ + for (k = 0; k < MIX_CMD_INVALID; ++k) + mix_commands_[k + LOCAL_COMANDS_NO_] = mix_vm_command_to_string (k); + mix_commands_[ALL_COMMANDS_NO_ - 1] = NULL; + +#ifdef HAVE_LIBREADLINE + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = (CPPFunction *)mixvm_cmd_completion_; +#endif /* HAVE_LIBREADLINE */ + + /* initialise the dispatcher */ + dis_ = mix_vm_cmd_dispatcher_new (stdout, stderr); + + if ( dis_ == NULL) + g_error (_("Failed initialisation (no memory resources)")); + + /* install post hook for emacs interaction */ + if (use_emacs) + { + mix_vm_cmd_dispatcher_post_hook (dis_, MIX_CMD_LOAD, emacs_output_, NULL); + mix_vm_cmd_dispatcher_post_hook (dis_, MIX_CMD_RUN, emacs_output_, NULL); + mix_vm_cmd_dispatcher_post_hook (dis_, MIX_CMD_NEXT, emacs_output_, NULL); + } + + if (arg) + mix_vm_cmd_dispatcher_dispatch (dis_, MIX_CMD_LOAD, arg); +} + +gboolean +mixvm_cmd_exec (char *line) +{ + int i; + COMMAND *command; + char *cmd, *arg; + mix_vm_command_t mix_cmd; + + 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++; + cmd = line + i; + + while (line[i] && !isspace (line[i])) + i++; + + if (line[i]) + line[i++] = '\0'; + + if (cmd == NULL || strlen (cmd) == 0) + return TRUE; + + /* Get argument to command, if any. */ + while (isspace (line[i])) + i++; + + arg = line + i; + + /* try to find local command */ + command = find_command_ (cmd); + if (command) + return ((*(command->func)) (arg)); + + /* try to find mix command */ + mix_cmd = mix_vm_command_from_string (cmd); + + if (mix_cmd == MIX_CMD_INVALID) + fprintf (stderr, _("%s: No such command. Try \'help\'\n"), cmd); + else + mix_vm_cmd_dispatcher_dispatch (dis_, mix_cmd, arg); + + return TRUE; +} + + diff --git a/mixutils/mixvm_command.h b/mixutils/mixvm_command.h new file mode 100644 index 0000000..9741164 --- /dev/null +++ b/mixutils/mixvm_command.h @@ -0,0 +1,35 @@ +/* -*-c-*- ---------------- mixvm_command.h : + * Declarations for commands accepted by the mix virtual machine + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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 + +extern void +mixvm_cmd_init (char *arg, gboolean use_emacs); + +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..a565832 --- /dev/null +++ b/mixutils/mixvm_loop.c @@ -0,0 +1,86 @@ +/* -*-c-*- -------------- mixvm_loop.c : + * Implementation of mix vm command loop. + * ------------------------------------------------------------------ + * Copyright (C) 2000, 2001 Free Software Foundation, Inc. + * + * 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. + * + */ + + +#define _GNU_SOURCE 1 +#include + +#include +#include "mixvm_command.h" + +#ifdef HAVE_LIBHISTORY +# include +#else +# define add_history(x) ((void)0) +#endif + +#ifdef HAVE_LIBREADLINE +# include +#else /* !HAVE_LIBREADLINE */ +static char * +readline (char *prompt) +{ + char *line = NULL; + size_t s = 0; + + printf ("%s", prompt); + getline (&line, &s, stdin); + return line; +} +#endif /* HAVE_LIBREADLINE */ + +/* 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, gboolean use_emacs) +{ + mixvm_cmd_init ((char *)file, use_emacs); + 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 + + * 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/samples/.cvsignore b/samples/.cvsignore new file mode 100644 index 0000000..ebb2d73 --- /dev/null +++ b/samples/.cvsignore @@ -0,0 +1,36 @@ +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 +stress1.mix +stress2.mix +stress2.mls +stress3.mix +stress3.mixal +stress3.mls +stress4.mix +stress4.mls +stress5.mix +stress5.mixal +stress5.mls +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..0d452a1 --- /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 +# +# 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 =*.mixal primes.result + 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..d8e6eef --- /dev/null +++ b/samples/primes.mixal @@ -0,0 +1,54 @@ +* 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 + + \ No newline at end of file diff --git a/samples/primes.result b/samples/primes.result new file mode 100644 index 0000000..1431f77 --- /dev/null +++ b/samples/primes.result @@ -0,0 +1,51 @@ +FIRST FIVE HUNDRED PRIMES + 0002 0233 0547 0877 1229 1597 1993 2371 2749 3187 + 0003 0239 0557 0881 1231 1601 1997 2377 2753 3191 + 0005 0241 0563 0883 1237 1607 1999 2381 2767 3203 + 0007 0251 0569 0887 1249 1609 2003 2383 2777 3209 + 0011 0257 0571 0907 1259 1613 2011 2389 2789 3217 + 0013 0263 0577 0911 1277 1619 2017 2393 2791 3221 + 0017 0269 0587 0919 1279 1621 2027 2399 2797 3229 + 0019 0271 0593 0929 1283 1627 2029 2411 2801 3251 + 0023 0277 0599 0937 1289 1637 2039 2417 2803 3253 + 0029 0281 0601 0941 1291 1657 2053 2423 2819 3257 + 0031 0283 0607 0947 1297 1663 2063 2437 2833 3259 + 0037 0293 0613 0953 1301 1667 2069 2441 2837 3271 + 0041 0307 0617 0967 1303 1669 2081 2447 2843 3299 + 0043 0311 0619 0971 1307 1693 2083 2459 2851 3301 + 0047 0313 0631 0977 1319 1697 2087 2467 2857 3307 + 0053 0317 0641 0983 1321 1699 2089 2473 2861 3313 + 0059 0331 0643 0991 1327 1709 2099 2477 2879 3319 + 0061 0337 0647 0997 1361 1721 2111 2503 2887 3323 + 0067 0347 0653 1009 1367 1723 2113 2521 2897 3329 + 0071 0349 0659 1013 1373 1733 2129 2531 2903 3331 + 0073 0353 0661 1019 1381 1741 2131 2539 2909 3343 + 0079 0359 0673 1021 1399 1747 2137 2543 2917 3347 + 0083 0367 0677 1031 1409 1753 2141 2549 2927 3359 + 0089 0373 0683 1033 1423 1759 2143 2551 2939 3361 + 0097 0379 0691 1039 1427 1777 2153 2557 2953 3371 + 0101 0383 0701 1049 1429 1783 2161 2579 2957 3373 + 0103 0389 0709 1051 1433 1787 2179 2591 2963 3389 + 0107 0397 0719 1061 1439 1789 2203 2593 2969 3391 + 0109 0401 0727 1063 1447 1801 2207 2609 2971 3407 + 0113 0409 0733 1069 1451 1811 2213 2617 2999 3413 + 0127 0419 0739 1087 1453 1823 2221 2621 3001 3433 + 0131 0421 0743 1091 1459 1831 2237 2633 3011 3449 + 0137 0431 0751 1093 1471 1847 2239 2647 3019 3457 + 0139 0433 0757 1097 1481 1861 2243 2657 3023 3461 + 0149 0439 0761 1103 1483 1867 2251 2659 3037 3463 + 0151 0443 0769 1109 1487 1871 2267 2663 3041 3467 + 0157 0449 0773 1117 1489 1873 2269 2671 3049 3469 + 0163 0457 0787 1123 1493 1877 2273 2677 3061 3491 + 0167 0461 0797 1129 1499 1879 2281 2683 3067 3499 + 0173 0463 0809 1151 1511 1889 2287 2687 3079 3511 + 0179 0467 0811 1153 1523 1901 2293 2689 3083 3517 + 0181 0479 0821 1163 1531 1907 2297 2693 3089 3527 + 0191 0487 0823 1171 1543 1913 2309 2699 3109 3529 + 0193 0491 0827 1181 1549 1931 2311 2707 3119 3533 + 0197 0499 0829 1187 1553 1933 2333 2711 3121 3539 + 0199 0503 0839 1193 1559 1949 2339 2713 3137 3541 + 0211 0509 0853 1201 1567 1951 2341 2719 3163 3547 + 0223 0521 0857 1213 1571 1973 2347 2729 3167 3557 + 0227 0523 0859 1217 1579 1979 2351 2731 3169 3559 + 0229 0541 0863 1223 1583 1987 2357 2741 3181 3571 diff --git a/samples/stress1.mixal b/samples/stress1.mixal new file mode 100644 index 0000000..f9bc8c9 --- /dev/null +++ b/samples/stress1.mixal @@ -0,0 +1,9 @@ + ORIG 1999 +ST NOP +3H EQU 69 +3H ENTA 3B +** According to pg 151, rA should be 69, not 2000 +** "An address of 2F or 2B never refers to its own line" + HLT + END ST + diff --git a/samples/stress2.mixal b/samples/stress2.mixal new file mode 100644 index 0000000..4c7250d --- /dev/null +++ b/samples/stress2.mixal @@ -0,0 +1,14 @@ + ORIG 1999 +ST NOP +3H CON 10 + ENT1 * + LDA 3B +** rI1 is 2001, rA is 10. So far so good! +3H ORIG 3B-1000 +** at this point 3H should +** equal 2002, and the location counter should be 1000. + ENT2 * + LDX 3B +** rI2 should be 1000, rX should be 2002 (I think...) + HLT + END ST diff --git a/samples/stress4.mixal b/samples/stress4.mixal new file mode 100644 index 0000000..7bcdd2a --- /dev/null +++ b/samples/stress4.mixal @@ -0,0 +1,7 @@ + ORIG 2000 +ST NOP + ENTA FUT +** Whoa, mdk tells me FUT is never defined... +FUT EQU 69 + HLT + END ST -- cgit v1.2.3