From b9e4111be238d1fdf91a5bbee9b592131907098b Mon Sep 17 00:00:00 2001 From: kg68k <78926718+kg68k@users.noreply.github.com> Date: Sun, 23 Apr 2023 20:06:01 +0900 Subject: [PATCH] major update --- Makefile | 17 +- README.md | 2 +- docs/GPL.TXT | 340 -- docs/README.txt | 1891 +++++------ docs/analysis.txt | 62 + docs/dis_option.txt | 404 --- docs/gpl-3.0.txt | 674 ++++ docs/labelfile.txt | 75 +- docs/tablefile.txt | 203 +- src/Makefile | 186 +- src/analyze.c | 1426 +++++---- src/analyze.h | 75 +- src/analyze2.c | 410 +-- src/avl/avl.c | 956 +++--- src/avl/avl.h | 160 +- src/disasm.c | 5333 +++++++++----------------------- src/disasm.h | 320 +- src/disasmonly.c | 152 - src/ea.c | 1526 +++++++++ src/ea.h | 262 ++ src/eastr.c | 60 + src/eastr.h | 240 ++ src/estruct.h | 230 +- src/etc.c | 231 +- src/etc.h | 181 +- src/eval.c | 968 ++++++ src/eval.h | 59 + src/eval.y | 603 ---- src/fpconv.c | 432 +-- src/fpconv.h | 80 +- src/fpu.c | 663 ++++ src/fpu.h | 30 + src/generate.c | 3742 ++++++++-------------- src/generate.h | 101 +- src/getopt.c | 307 +- src/getopt.h | 28 +- src/global.h | 317 +- src/hex.c | 204 +- src/hex.h | 125 +- src/human.c | 405 +++ src/human.h | 37 + src/include.c | 487 +-- src/include.h | 47 +- src/label.c | 418 +-- src/label.h | 110 +- src/labelcheck.c | 396 +-- src/labelfile.c | 549 ++-- src/labelfile.h | 28 +- src/main.c | 1034 +++---- src/mmu.c | 343 ++ src/mmu.h | 36 + src/offset.c | 203 +- src/offset.h | 40 +- src/opstr.c | 324 ++ src/opstr.h | 300 ++ src/option.c | 1395 +++++---- src/option.h | 27 +- src/osk.c | 754 +++++ src/osk.h | 51 + src/output.c | 677 ++-- src/output.h | 94 +- src/ports/Makefile_Cyg_MinGW | 6 +- src/ports/Makefile_Cygwin | 4 +- src/ports/Makefile_FreeBSD | 2 - src/ports/Makefile_Linux | 2 - src/ports/ports.txt | 181 +- src/search.c | 241 +- src/symbol.c | 663 ++-- src/symbol.h | 88 +- src/table.c | 621 ++-- src/table.h | 94 +- src/version.c | 63 +- src/version.h | 28 + tests/Makefile | 124 + tests/expected/after_str.s | 37 + tests/expected/avoid_q.s | 62 + tests/expected/bd_size.s | 137 + tests/expected/bitfield.s | 51 + tests/expected/bitop.s | 54 + tests/expected/blankline.s | 55 + tests/expected/blankline_B.s | 57 + tests/expected/bra_size.s | 150 + tests/expected/cas.s | 34 + tests/expected/cinvpush.s | 78 + tests/expected/cinvpush_R0.s | 96 + tests/expected/compress.s | 70 + tests/expected/cpu32.s | 46 + tests/expected/cpu32_mcpu32.s | 64 + tests/expected/devhead_loop.s | 62 + tests/expected/ds.s | 57 + tests/expected/ea_abs.s | 38 + tests/expected/ea_label.s | 392 +++ tests/expected/ea_misc.s | 68 + tests/expected/fmovem.s | 90 + tests/expected/fp_imm.s | 128 + tests/expected/fp_undefreg.s | 68 + tests/expected/fsincos.s | 31 + tests/expected/imm.s | 141 + tests/expected/imm_comment.s | 63 + tests/expected/kfactor.s | 35 + tests/expected/lab_in_reltbl.s | 49 + tests/expected/lab_oorange.s | 28 + tests/expected/lab_rw.s | 44 + tests/expected/mmu.s | 143 + tests/expected/mmu_undefreg.s | 51 + tests/expected/movec.s | 73 + tests/expected/pflush040.s | 41 + tests/expected/pflush040_R0.s | 48 + tests/expected/registdata.s | 37 + tests/expected/reglist.s | 1153 +++++++ tests/expected/relbdpc.s | 54 + tests/expected/reltbl.s | 281 ++ tests/expected/scalefactor.s | 37 + tests/expected/split_end.s | 30 + tests/expected/sym_oorange.s | 45 + tests/expected/symbol.s | 45 + tests/expected/tab_depadrs.s | 43 + tests/expected/tab_even.s | 37 + tests/expected/tab_stuck1.s | 0 tests/expected/tab_stuck2.s | 0 tests/src/after_str.s | 13 + tests/src/avoid_q.s | 46 + tests/src/bd_size.s | 57 + tests/src/bitfield.s | 29 + tests/src/bitop.s | 29 + tests/src/blankline.s | 26 + tests/src/bra_size.s | 125 + tests/src/cas.s | 10 + tests/src/cinvpush.s | 67 + tests/src/compress.s | 43 + tests/src/cpu32.s | 47 + tests/src/devhead_loop.s | 35 + tests/src/ds.s | 28 + tests/src/ea_abs.s | 14 + tests/src/ea_label.s | 369 +++ tests/src/ea_misc.s | 50 + tests/src/fmovem.s | 58 + tests/src/fp_imm.s | 109 + tests/src/fp_undefreg.s | 53 + tests/src/fsincos.s | 6 + tests/src/imm.s | 98 + tests/src/imm_comment.s | 48 + tests/src/kfactor.s | 12 + tests/src/lab_in_reltbl.s | 18 + tests/src/lab_oorange.s | 5 + tests/src/lab_rw.lab | 10 + tests/src/lab_rw.s | 21 + tests/src/mmu.s | 118 + tests/src/mmu_undefreg.s | 24 + tests/src/movec.s | 51 + tests/src/pflush040.s | 24 + tests/src/registdata.s | 15 + tests/src/reglist.s | 60 + tests/src/relbdpc.s | 37 + tests/src/reltbl.s | 178 ++ tests/src/scalefactor.s | 12 + tests/src/split_end.s | 8 + tests/src/sym_oorange.s | 21 + tests/src/symbol.s | 21 + tests/src/tab_depadrs.lab | 9 + tests/src/tab_depadrs.s | 17 + tests/src/tab_depadrs.tab | 5 + tests/src/tab_even.lab | 8 + tests/src/tab_even.s | 15 + tests/src/tab_even.tab | 5 + tests/src/tab_stuck1.lab | 8 + tests/src/tab_stuck1.s | 5 + tests/src/tab_stuck1.tab | 3 + tests/src/tab_stuck2.lab | 8 + tests/src/tab_stuck2.s | 5 + tests/src/tab_stuck2.tab | 3 + 171 files changed, 23771 insertions(+), 15665 deletions(-) delete mode 100644 docs/GPL.TXT create mode 100644 docs/analysis.txt delete mode 100644 docs/dis_option.txt create mode 100644 docs/gpl-3.0.txt delete mode 100644 src/disasmonly.c create mode 100644 src/ea.c create mode 100644 src/ea.h create mode 100644 src/eastr.c create mode 100644 src/eastr.h create mode 100644 src/eval.c create mode 100644 src/eval.h delete mode 100644 src/eval.y create mode 100644 src/fpu.c create mode 100644 src/fpu.h create mode 100644 src/human.c create mode 100644 src/human.h create mode 100644 src/mmu.c create mode 100644 src/mmu.h create mode 100644 src/opstr.c create mode 100644 src/opstr.h create mode 100644 src/osk.c create mode 100644 src/osk.h create mode 100644 src/version.h create mode 100644 tests/Makefile create mode 100644 tests/expected/after_str.s create mode 100644 tests/expected/avoid_q.s create mode 100644 tests/expected/bd_size.s create mode 100644 tests/expected/bitfield.s create mode 100644 tests/expected/bitop.s create mode 100644 tests/expected/blankline.s create mode 100644 tests/expected/blankline_B.s create mode 100644 tests/expected/bra_size.s create mode 100644 tests/expected/cas.s create mode 100644 tests/expected/cinvpush.s create mode 100644 tests/expected/cinvpush_R0.s create mode 100644 tests/expected/compress.s create mode 100644 tests/expected/cpu32.s create mode 100644 tests/expected/cpu32_mcpu32.s create mode 100644 tests/expected/devhead_loop.s create mode 100644 tests/expected/ds.s create mode 100644 tests/expected/ea_abs.s create mode 100644 tests/expected/ea_label.s create mode 100644 tests/expected/ea_misc.s create mode 100644 tests/expected/fmovem.s create mode 100644 tests/expected/fp_imm.s create mode 100644 tests/expected/fp_undefreg.s create mode 100644 tests/expected/fsincos.s create mode 100644 tests/expected/imm.s create mode 100644 tests/expected/imm_comment.s create mode 100644 tests/expected/kfactor.s create mode 100644 tests/expected/lab_in_reltbl.s create mode 100644 tests/expected/lab_oorange.s create mode 100644 tests/expected/lab_rw.s create mode 100644 tests/expected/mmu.s create mode 100644 tests/expected/mmu_undefreg.s create mode 100644 tests/expected/movec.s create mode 100644 tests/expected/pflush040.s create mode 100644 tests/expected/pflush040_R0.s create mode 100644 tests/expected/registdata.s create mode 100644 tests/expected/reglist.s create mode 100644 tests/expected/relbdpc.s create mode 100644 tests/expected/reltbl.s create mode 100644 tests/expected/scalefactor.s create mode 100644 tests/expected/split_end.s create mode 100644 tests/expected/sym_oorange.s create mode 100644 tests/expected/symbol.s create mode 100644 tests/expected/tab_depadrs.s create mode 100644 tests/expected/tab_even.s create mode 100644 tests/expected/tab_stuck1.s create mode 100644 tests/expected/tab_stuck2.s create mode 100644 tests/src/after_str.s create mode 100644 tests/src/avoid_q.s create mode 100644 tests/src/bd_size.s create mode 100644 tests/src/bitfield.s create mode 100644 tests/src/bitop.s create mode 100644 tests/src/blankline.s create mode 100644 tests/src/bra_size.s create mode 100644 tests/src/cas.s create mode 100644 tests/src/cinvpush.s create mode 100644 tests/src/compress.s create mode 100644 tests/src/cpu32.s create mode 100644 tests/src/devhead_loop.s create mode 100644 tests/src/ds.s create mode 100644 tests/src/ea_abs.s create mode 100644 tests/src/ea_label.s create mode 100644 tests/src/ea_misc.s create mode 100644 tests/src/fmovem.s create mode 100644 tests/src/fp_imm.s create mode 100644 tests/src/fp_undefreg.s create mode 100644 tests/src/fsincos.s create mode 100644 tests/src/imm.s create mode 100644 tests/src/imm_comment.s create mode 100644 tests/src/kfactor.s create mode 100644 tests/src/lab_in_reltbl.s create mode 100644 tests/src/lab_oorange.s create mode 100644 tests/src/lab_rw.lab create mode 100644 tests/src/lab_rw.s create mode 100644 tests/src/mmu.s create mode 100644 tests/src/mmu_undefreg.s create mode 100644 tests/src/movec.s create mode 100644 tests/src/pflush040.s create mode 100644 tests/src/registdata.s create mode 100644 tests/src/reglist.s create mode 100644 tests/src/relbdpc.s create mode 100644 tests/src/reltbl.s create mode 100644 tests/src/scalefactor.s create mode 100644 tests/src/split_end.s create mode 100644 tests/src/sym_oorange.s create mode 100644 tests/src/symbol.s create mode 100644 tests/src/tab_depadrs.lab create mode 100644 tests/src/tab_depadrs.s create mode 100644 tests/src/tab_depadrs.tab create mode 100644 tests/src/tab_even.lab create mode 100644 tests/src/tab_even.s create mode 100644 tests/src/tab_even.tab create mode 100644 tests/src/tab_stuck1.lab create mode 100644 tests/src/tab_stuck1.s create mode 100644 tests/src/tab_stuck1.tab create mode 100644 tests/src/tab_stuck2.lab create mode 100644 tests/src/tab_stuck2.s create mode 100644 tests/src/tab_stuck2.tab diff --git a/Makefile b/Makefile index 0125572..0a16120 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ U8TOSJ = u8tosj SRC_DIR = src DOC_DIR = docs +INC_DIR = include BLD_DIR = build @@ -15,18 +16,22 @@ SJ_SRCS = $(subst $(SRC_DIR)/,$(BLD_DIR)/,$(SRCS)) DOCS = $(wildcard $(DOC_DIR)/*) SJ_DOCS = $(addprefix $(BLD_DIR)/,$(DOCS)) +INCS = $(wildcard $(INC_DIR)/*) +SJ_INCS = $(addprefix $(BLD_DIR)/,$(INCS)) .PHONY: all directories clean -all: directories $(SJ_DOCS) $(SJ_SRCS) +all: directories $(SJ_DOCS) $(SJ_INCS) $(SJ_SRCS) -directories: $(BLD_DIR) $(BLD_DIR)/docs $(BLD_DIR)/avl +directories: $(BLD_DIR) $(BLD_DIR)/avl $(BLD_DIR)/docs $(BLD_DIR)/include -$(BLD_DIR) $(BLD_DIR)/docs $(BLD_DIR)/avl: +$(BLD_DIR) $(BLD_DIR)/avl $(BLD_DIR)/$(DOC_DIR) $(BLD_DIR)/$(INC_DIR): $(MKDIR_P) $@ +$(BLD_DIR)/$(DOC_DIR)/%: $(DOC_DIR)/% + $(U8TOSJ) < $^ >! $@ -$(BLD_DIR)/docs/%: $(DOC_DIR)/% +$(BLD_DIR)/$(INC_DIR)/%: $(INC_DIR)/% $(U8TOSJ) < $^ >! $@ $(BLD_DIR)/%: $(SRC_DIR)/% @@ -34,8 +39,8 @@ $(BLD_DIR)/%: $(SRC_DIR)/% clean: - -rm -f $(SJ_DOCS) $(SJ_SRCS) - -rmdir $(BLD_DIR)/docs $(BLD_DIR)/avl $(BLD_DIR) + -rm -f $(SJ_INCS) $(SJ_DOCS) $(SJ_SRCS) + -rmdir $(BLD_DIR)/$(INC_DIR) $(BLD_DIR)/$(DOC_DIR) $(BLD_DIR)/avl $(BLD_DIR) # EOF diff --git a/README.md b/README.md index 935ea0a..d936635 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ UTF-8のままでは正しくビルドできませんので注意してくださ ## License -GNU General Public License version 2 or later. +GNU General Public License version 3 or later. ## Author diff --git a/docs/GPL.TXT b/docs/GPL.TXT deleted file mode 100644 index 3912109..0000000 --- a/docs/GPL.TXT +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. diff --git a/docs/README.txt b/docs/README.txt index caf2193..72ca161 100644 --- a/docs/README.txt +++ b/docs/README.txt @@ -1,51 +1,49 @@ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ソースコードジェネレータ for X680x0 version 3.16 - Copyright (C)1989-1992 K.Abe - Copyright (C)1994-1997 R.ShimiZu - Copyright (C)1997-2010 TcbnErik + ソースコードジェネレータ for X680x0 version 4 + Copyright (C)1989-1992 K.Abe + Copyright (C)1994-1997 R.ShimiZu + Copyright (C)1997-2022 TcbnErik +─────────────────────────────────────── -──────────────────────────────────── ● disの概要 - dis は X680x0/Human68k 用の高機能逆アセンブラです。バイナリ形式の実行 -ファイルからアセンブリ言語のソースファイルを生成することができ、ソースコ -ードジェネレータとも呼ばれます。 + dis は X680x0/Human68k 用の高機能逆アセンブラです。バイナリ形式の実行ファイ +ルからアセンブリ言語のソースファイルを生成することができ、ソースコードジェネレ +ータとも呼ばれます。 - dis はまず K.Abe 氏により Oh!X '90 6月号で DIS.X version 1.00d が発表 -され、その Bug fix and version up 版が Free Ware として公開されました。 -同氏により version 2.06β までのバージョンアップが行われ、その時点でサポ -ートが終了しました。 + dis はまず K.Abe 氏により Oh!X '90 6月号で DIS.X version 1.00d が発表され、 +その Bug fix and version up 版が Free Ware として公開されました。同氏により +version 2.06β までのバージョンアップが行われ、その時点でサポートが終了しまし +た。 - その後 R.ShimiZu 氏が dis を 68010-68040 の命令やコプロセッサ命令に対 -応させ、version 2.50 以降が公開されました。同氏は version 2.79 までのバ -ージョンアップを行ない、同じようにサポートを終了しました。 + その後 R.ShimiZu 氏が dis を 68010-68040 の命令やコプロセッサ命令に対応さ +せ、version 2.50 以降が公開されました。同氏は version 2.79 までのバージョンア +ップを行ない、同じようにサポートを終了しました。 - これを私立花が引き継ぎ、68060 の命令に対応させるなどしたものが version -2.80 以降です(それまで作成していた version 2.78 patchlevel 5 のベースを -version 2.79 に変更したものを version 2.80 としました)。 + これを私 TcbnErik が引き継ぎ、68060 の命令に対応させるなどしたものが +version 2.80 以降です(それまで作成していた version 2.78 patchlevel 5 のベース +を version 2.79 に変更したものを version 2.80 としました)。 - version 3.10 以降からは M.Suzuki 氏の協力により、FreeBSD 上でも動作す -るようになりました(Human68k 用の実行ファイルを逆アセンブルします)。 + version 3.10 以降からは M.Suzuki 氏の協力により、FreeBSD 上でも動作するよう +になりました(Human68k 用の実行ファイルを逆アセンブルします)。 ●サポートについて - 上記の通り R.ShimiZu 氏よりサポートを引き継いだので、今後は dis に対す -る要望や不具合の報告は立花宛てにお願いします。 + version 2.80 以降に対する要望や不具合の報告は TcbnErik 宛てにお願いします。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + 著作権及び保証の有無 - 著作権及び保証の有無 +─────────────────────────────────────── -──────────────────────────────────── - - 著作権及び保証については、K.Abe 氏は dis version 2.06β の README.DOC -に以下のように述べています。 + 著作権及び保証については、K.Abe 氏は dis version 2.06β の README.DOC に以下 +のように述べています。 ==== ここから ==== [無保証] @@ -65,8 +63,8 @@ version 2.79 に変更したものを version 2.80 としました)。 願います。 ==== ここまで ==== - また、R.ShimiZu 氏は dis version 2.79 の README2.DOC で以下のように述 -べています。 + また、R.ShimiZu 氏は dis version 2.79 の README2.DOC で以下のように述べてい +ます。 ==== ここから ==== DIS v2.06β に準ずるものとします。したがって無保証です。著作権は、大 @@ -76,410 +74,414 @@ version 2.79 に変更したものを version 2.80 としました)。 本プログラムはフリーウェアとします。 ==== ここまで ==== - dis version 2.80 以降については、GNU General Public Licence の verison -2 に従います。自由、かつ、無保証となります。 + dis version 3.17 以降については、GNU General Public Licence の verison 3 ま +たはそれ以降のバージョンに従います。自由、かつ、無保証となります。  著作権に関しては、dis version 2.06β までに記述された部分を K.Abe 氏が、 -version 2.79 までで変更された部分を R.ShimiZu 氏が所有します。version -2.80 以降及び、その前身である version 2.78 patchlevel 1~5 での変更部分 -は私(立花)が著作権を所持します。また、GNU のパーサジェネレータ Bison を -使用しているので、パーサ部分は GNU の著作物でもあります。 +version 2.79 までで変更された部分を R.ShimiZu 氏が所有します。version 2.80 以 +降及び、その前身である version 2.78 patchlevel 1~5 での変更部分は TcbnErik が +著作権を所持します。 + + なお、このファイルは dis version 2.06β の README.DOC、dis version 2.79 の +README2.DOC を参考にしています。 - なお、このファイルは dis version 2.06β の README.DOC、dis version -2.79 の README2.DOC を参考にしています。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + アーカイブの内容 - アーカイブの内容 +─────────────────────────────────────── -──────────────────────────────────── + Human68k 版の dis の公式配布書庫には以下のファイルが含まれます。 - dis の書庫には以下のファイルが含まれます。 +bin/dis.x dis 本体(Human68k 用、X680x0 全機種対応) -bin/dis.x dis 本体(Human68k 用、X680x0 全機種対応) -bin/dis030.x 〃 (Human68k 用、68020 以降専用) - ※ dis030.x は同梱されない場合があります。 +docs/README.txt このドキュメント +docs/labelfile.txt ラベルファイルの仕様書 +docs/table.txt テーブル記述ファイルに関するドキュメント +docs/tablefile.txt テーブルファイルの仕様書 +docs/analysis.txt コード解析に関する覚書 +docs/gpl-3.0 ライセンス(GNU GENERAL PUBLIC LICENSE Version 3) -src/* dis のソースコード類 -src/avl/* AVL ライブラリのソースコード類 -src/ports/* 移植用 Makefile と解説 -include/* dis 用インクルードファイル - (これ以外のものを使っても勿論構いません) +include/* dis 用インクルードファイル(他のものを使っても構いません)。 + ※dis 2.79 以下では使用できません。 -README.DOC このドキュメント -ChangeLog dis の変更履歴 -dis_option.1 オプションの簡易説明書 -labelfile.5 ラベルファイルの仕様書 -table.doc テーブル記述ファイルに関するドキュメント -tablefile.5 テーブルファイルの仕様書 -GPL.TXT GNU GENERAL PUBLIC LICENSE Version 2 + ソースコードは以下のファイルが同梱されているか、またはライセンスに従い同じ場 +所で配布されています。GitHub のリポジトリから入手することもできます。 +src/* dis のソースコード類 +src/avl/* AVL ライブラリのソースコード類 +src/ports/* 移植用 Makefile と解説 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 準備 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -──────────────────────────────────── + 準備 - 配布に実行ファイルが含まれている場合、dis をパスの通ったディレクトリに -置き、環境変数を設定するだけで使用できるようになります。実行ファイルがな -い場合は各自で make して下さい。 +─────────────────────────────────────── + + 配布に実行ファイルが含まれている場合、dis をパスの通ったディレクトリに置き、 +環境変数を設定するだけで使用できるようになります。実行ファイルがない場合は各自 +で make して下さい。 ●インクルードファイルの設定 - dis は起動するとまず DOS/IOCS/FPACK ファンクションコールの名称を収得す -る為に各コールを定義したインクルードファイルを読み込みます。それぞれのフ -ァイルは doscall.mac/iocscall.mac/fefunc.mac に対応し、必ず存在しないと -逆アセンブルが出来ません。それらの存在するパス名を環境変数 dis_include -若しくは include に設定して下さい。dis_include の方から優先してファイル -が検索されます。 + dis は起動するとまず DOS/IOCS/FPACK ファンクションコールの名称を収得する為に +各コールを定義したインクルードファイルを読み込みます。それぞれのファイルは +doscall.mac/iocscall.mac/fefunc.mac に対応し、必ず存在しないと逆アセンブルがで +きません。それらの存在するパス名を環境変数 dis_include もしくは include に設定 +して下さい。dis_include の方から優先してファイルが検索されます。 - ただし -Y オプションを指定した場合は、それらのパスに先立ってカレントデ -ィレクトリからファイルを検索します。 + ただし -Y オプションを指定した場合は、それらのパスに先立ってカレントディレク +トリからファイルを検索します。 - また、SX-Window 対応モードで起動した場合は SX ファンクションコールの名 -称を収得する為に sxcall.mac も読み込みます。ファイル名をフルパスで環境変 -数 dis_sxmac に設定して下さい。 + また、SX-Window 対応モードで起動した場合は SX ファンクションコールの名称を収 +得するために sxcall.mac も読み込みます。ファイル名をフルパスで環境変数 +dis_sxmac に設定して下さい。 - fefunc.mac は XC ver 1 の fefunc.h に相当します。dis version 2.79 まで -は fefunc.h か、それを fefunc.dis にリネームしたものを参照していましたが、 -XC ver 2 の fefunc.h では使えないなどの混乱が生じた為、fefunc.mac として -提供することにしました。dis のアーカイブに同梱されている include ディレ -クトリの fefunc.mac を前述の環境変数で指定したパスにコピーして下さい。同 -ディレクトリにはその他のインクルードファイルも納めているので、必要ならそ -れらも使って下さい。 + fefunc.mac は XC ver 1 の fefunc.h に相当します。dis version 2.79 までは +fefunc.h か、それを fefunc.dis にリネームしたものを参照していましたが、XC ver +2 の fefunc.h では使えないなどの混乱が生じたため、fefunc.mac として提供するこ +とにしました。dis のアーカイブに同梱されている include ディレクトリの +fefunc.mac を前述の環境変数で指定したパスにコピーして下さい。同ディレクトリに +はその他のインクルードファイルも納めているので、必要ならそれらも使って下さい。 - なお、dis version 2.79 までで使っていた fefunc.h や fefunc.dis も問題 -なく使えるので、リネームするなりリンクを張るなりしても結構です。 + なお、dis version 2.79 までで使っていた fefunc.h や fefunc.dis も問題なく使 +えるので、リネームするなりリンクを張るなりしても結構です。 ●オプションの設定 - dis は以下の環境変数を参照します(変数名は小文字です)。 + dis は以下の環境変数を参照します。 + +DIS_OPT +  dis version 4.00 で追加された環境変数です。DIS_OPT が設定されていない場 + 合は dis_opt を参照します。 + +  デフォルトの dis のオプションを指定します。この環境変数で指定したオプシ + ョンはコマンドラインより先に解釈されます。出力関係のオプション等、常に付け + るオプションを設定しておくと便利でしょう。なお、この環境変数で設定されたオ + プションは、上書き指定が可能なもの(-m 等)を除きコマンドラインからの取り消 + しはできません。 + +  オプションの詳細については後述のオプションの項を参照して下さい。 dis_opt -  デフォルトの dis のオプションを指定します。この環境変数で指定 - したオプションはコマンドラインより先に解釈されます。出力関係のオ - プション等、常に付けるオプションを設定しておくと便利でしょう。な - お、この環境変数で設定されたオプションは、上書き指定が可能なもの - (-m 等)を除きコマンドラインからの取り消しは出来ません。 +  デフォルトの dis のオプションを指定します。環境変数 DIS_OPT が設定されて + いない場合にのみ参照されます。dis version 3.16 までは dis_opt だけを参照し + ていました。 -  オプションの詳細については後述のオプションの項や dis_option.1 - を参照して下さい。 +  dis の旧バージョンを併用する場合、新バージョンで追加されたオプションを + dis_opt に設定してしまうと旧バージョンの実行時にエラーとなってしまいます。 + そこで、新バージョン用のオプションを DIS_OPT に、旧バージョン用のオプショ + ンを dis_opt に設定することで併用を可能にします。併用しない場合は dis_opt + に新バージョン用のオプションを設定しても構いません。 dis_include include -  doscall.mac/iocscall.mac/fefunc.mac/sxcall.mac のあるディレク - トリのパス名を設定しておいて下さい。dis_include の方を先に見ます。 +  doscall.mac、iocscall.mac、fefunc.mac、sxcall.mac のあるディレクトリのパ + ス名を設定しておいて下さい。dis_include の方を先に見ます。 -  --include-XXX-mac=file オプションでコマンドラインから違うファ - イルを読み込むように指定したり、--exclude-XXX-mac オプションでフ - ァイルを読み込まず、ファンクションコールの逆アセンブルも行わない - ようにすることが出来ます。 +  --include-XXX-mac=file オプションでコマンドラインから違うファイルを読み + 込むように指定したり、--exclude-XXX-mac オプションでファイルを読み込まず、 + ファンクションコールの逆アセンブルも行わないようにすることができます。 dis_sxmac -  SX-Window 用のインクルードファイル(アセンブラ用)のファイル名を - フルパスで設定しておけば -u1 オプション指定時に SX-Window の A - line trap を SXCALL name のように出力できます。 +  SX-Window 用のインクルードファイル(アセンブラ用)のファイル名をフルパスで + 設定しておけば -u1 オプション指定時に SX-Window の A line trap を SXCALL + name のように出力できます。 dis_header -  出力ファイルの最初に出力される .include 部を書いたファイルのフ - ァイル名をフルパスで設定しておけば、そのファイルの内容がデフォル - トの .include の代わりに挿入されます。デフォルトの出力内容は - .include doscall.mac - .include iocscall.mac - .include fefunc.mac - です(ファイル名は実際に読み込んだファイルのフルパスになります)。 +  出力ファイルの最初に出力される .include 部を書いたファイルのファイル名を + フルパスで設定しておけば、そのファイルの内容がデフォルトの .include の代わ + りに挿入されます。デフォルトの出力内容は + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + です(ファイル名は実際に読み込んだファイルのフルパスになります)。 -  また、-u1 オプション指定時に環境変数 dis_sxmac を設定している - 場合には - .include $dis_sxmac - も追加されます。 +  また、-u1 オプション指定時に環境変数 dis_sxmac を設定している場合には + .include $dis_sxmac + も追加されます。 -  --header=file オプションでコマンドラインから違うファイルを読み - 込むように指定することが出来ます。 +  --header=file オプションでコマンドラインから違うファイルを読み込むように + 指定することができます。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 使用法 + 使用法 -──────────────────────────────────── +─────────────────────────────────────── - 以下の通りです。出力ファイル名を省略するか、"-" を指定した場合は標準出 -力に出力します。出力ファイル(ソースコード/ラベルファイル両方とも)が既に -存在すると上書きするか問合せます。 + 以下の通りです。出力ファイル名を省略するか、"-" を指定した場合は標準出力に出 +力します。出力ファイル(ソースコード/ラベルファイル両方とも)が既に存在すると上 +書きするか問い合わせます。 - dis [option] 実行ファイル名 [出力ファイル名] + dis [option] 実行ファイル名 [出力ファイル名] -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - オプション解説 + オプション解説 -──────────────────────────────────── +─────────────────────────────────────── - スラッシュ('/')はパスデリミタとして認識されるので、マイナス('-')しか使 -用できません。大文字、小文字は区別されます。 + スラッシュ('/')はパスデリミタとして認識されるので、ハイフン('-')しか使用でき +ません。大文字、小文字は区別されます。 - 省略可能な引数を受け取るオプションに引数を指定する場合は、間にスペース -等を入れないで下さい。オプションの直後に文字が記述されていないと、引数が -省略されたものと見なされます。 + 省略可能な引数を受け取るオプションに引数を指定する場合は、間にスペース等を入 +れないで下さい。オプションの直後に文字が記述されていないと、引数が省略されたも +のと見なされます。 - オプションは環境変数 dis_opt に設定しておくことも出来ます。コマンドラ -インと両方見るので、良く使うオプションを書いておくと便利かも知れません。 + オプションは環境変数 DIS_OPT または dis_opt に設定しておくこともできます。コ +マンドラインと両方見るので、良く使うオプションを書いておくと便利かもしれません。 ●命令セットに関するオプション -m num -  逆アセンブル対象のMPUを指定(num=68000~68060)。 +  逆アセンブル対象の MPU を指定(num=68000~68060)。 -  逆アセンブルする命令セットを選択します。-m68040~68060 指定時 - は内蔵コプロセッサ・MMU 命令も使用可能になります。 +  逆アセンブルする命令セットを選択します。-m68040~68060 指定時は内蔵コプ + ロセッサ・MMU 命令も使用可能になります。 -  -m68000,68030 のように複数の MPU を指定すると、指定した全ての - MPU の命令セットが同時に使用可能になります。また、-m680x0 を指定 - すると選択可能な全ての MPU の命令セットが採用されます。 +  -m68000,68030 のように複数の MPU を指定すると、指定した全ての MPU の命令 + セットが同時に使用可能になります。また、-m680x0 を指定すると選択可能な全て + の MPU の命令セットが採用されます。 -m cpu32 -  CPU32 命令を有効にする。 +  CPU32 命令を有効にする。 -  CPU32 の追加命令 lpstop、tbls(n)、tblu(n) を逆アセンブル出来る - ようにします。.cpu の切り換えは行ないません。 +  CPU32 の追加命令 lpstop、tbls(n)、tblu(n) を逆アセンブルできるようにしま + す。.cpu の切り換えは行ないません。 -m 68851 -  68851 命令を有効にする(-m68020 指定時のみ有効)。 +  68851 命令を有効にする(-m68020 指定時のみ有効)。 -  外付け MMU 命令を逆アセンブル可能にします。 +  外付け MMU 命令を逆アセンブル可能にします。 -  このオプションは -m680*0 オプションによってクリアされるので、 - それより後に指定して下さい。 +  このオプションは -m680*0 オプションによってクリアされるので、それより後 + に指定して下さい。 -m 6888x[,ID] -  有効な FPCP とその ID を指定(68881/68882 ID=[1],2-7)。 +  有効な FPCP とその ID を指定(68881/68882 ID=[1],2-7)。 + +  -m68020~68030 を指定している場合に、外付けコプロセッサ命令を逆アセンブ + ル可能にします。-m68881 と -m68882の機能は全く同じです。 -  -m68020~68030 を指定している場合に、外付けコプロセッサ命令を - 逆アセンブル可能にします。-m68881 と -m68882の機能は全く同じです。 +  ID の指定を省略した場合は1と見なされます。-m68881 -m68882,2 のように複数 + のIDを指定することも出来ます。 -  ID の指定を省略した場合は1と見なされます。-m68881 -m68882,2 の - ように複数のIDを指定することも出来ます。 +  このオプションは -m680*0 オプションによってクリアされるので、それより後 + に指定して下さい。 -  このオプションは -m680*0 オプションによってクリアされるので、 - それより後に指定して下さい。 +--fpsp +  未実装浮動小数点命令を有効にする(デフォルト)。 --P num -  ソフトウェアエミュレーション命令を有効にする(ビット指定、初期 - 値=3)。このオプションは将来アルファベットが足りなくなった時に違 - う機能が割り当てられる可能性があります。なるべく --(no-)fpsp、 - --(no-)isp を使用して下さい。 +--no-fpsp +  未実装浮動小数点命令を無効にする。 - +1 未実装浮動小数点命令を有効にする。 - +2 未実装整数命令を有効にする。 +  通常は、システムによってソフトウェアエミュレーションされることが保証され + ている命令は実在する命令と見なされますが、このオプションを指定した場合は未 + 定義命令と見なします。 ---(no-)fpsp -  未実装浮動小数点命令を[有効](無効)にする。 +--isp +  未実装整数命令を有効にする(デフォルト)。 ---(no-)isp -  未実装整数命令を[有効](無効)にする。 +--no-isp +  未実装整数命令を無効にする。 -  通常は、システムによってソフトウェアエミュレーションされること - が保証されている命令は実在する命令と見なされますが、このオプショ - ンを指定した場合は未定義命令と見なします。 +  通常は、システムによってソフトウェアエミュレーションされることが保証され + ている命令は実在する命令と見なされますが、このオプションを指定した場合は未 + 定義命令と見なします。 --no-fpu -  内蔵FPU命令を無効にする(-m68040~68060の後に指定)。 +  内蔵 FPU 命令を無効にする(-m68040~68060 の後に指定)。 --no-mmu -  内蔵MMU命令を無効にする(-m68030~68060の後に指定)。 +  内蔵 MMU 命令を無効にする(-m68030~68060 の後に指定)。 -  通常は -m680*0 オプションで指定した MPU によっては、自動的に内 - 蔵 FPU/MMU 命令が有効になります。これらのオプションを指定すると - それらの命令を対象命令セットから除外します。 +  通常は -m680*0 オプションで指定した MPU によっては、自動的に内蔵 FPU/MMU + 命令が有効になります。これらのオプションを指定するとそれらの命令を対象命令 + セットから除外します。 -  逆アセンブルするファイルにそれらの命令が含まれていないと分って - いる場合、このオプションを指定することで命令セットを限定し、解析 - の手助けをすることが出来ます。 +  逆アセンブルするファイルにそれらの命令が含まれていないと分っている場合、 + このオプションを指定することで命令セットを限定し、解析の手助けをすることが + できます。 -  このオプションは -m680*0 オプションによってクリアされるので、 - それより後に指定して下さい。 +  このオプションは -m680*0 オプションによってクリアされるので、それより後 + に指定して下さい。 ●解析に関するオプション -h -  データ領域中の $4e75(rts のコード)の次のアドレスに注目する。 +  データ領域中の $4e75(rts のコード)の次のアドレスに注目する。 -  素直でないコーディングをしたプログラムの場合(!?!?)、出力ファイ - ルにデータの塊が残る場合があります。そのような場合はユーザーがラ - ベルファイルを用いて dis の解析の「つっかかり」を与えれば良いの - ですが、このオプションを付けてもたいていのところを解析してくれる - 筈です。 +  素直でないコーディングをしたプログラムの場合(!?!?)、出力ファイルにデータ + の塊が残る場合があります。そのような場合はユーザーがラベルファイルを用いて + dis の解析の「つっかかり」を与えれば良いのですが、このオプションを付けても + たいていのところを解析してくれる筈です。 -i -  分岐先で未定義命令等を発見しても呼び出し側をデータ領域にしない。 +  分岐先で未定義命令等を発見しても呼び出し側をデータ領域にしない。 -  通常は「未定義命令のあるところに飛ぶような奴は俺はプログラムと - 認めねぇ」ですが、このオプションを付けると、「そんなことは俺の知 - ったことじゃねぇ」になります(多分)。 +  通常は「未定義命令のあるところに飛ぶような奴は俺はプログラムと認めねぇ」 + ですが、このオプションを付けると、「そんなことは俺の知ったことじゃねぇ」に + なります(多分)。 -j -  実行時にアドレスエラーの起こるであろう命令を未定義命令と見なさ - ない。 +  実行時にアドレスエラーの起こるであろう命令を未定義命令と見なさない。 -  通常は move.l $00000001,d0 等の、実行時にアドレスエラーが起こ - るであろう命令は未定義命令と見なしますが、このオプションを付ける - とそのチェックをしません。なお、68020 以降の MPU では上に挙げた - 命令はアドレスエラーになりませんが、dis では未定義命令と見なしま - す。普通のプログラムなら、効率的なメモリアクセスの為に偶数アドレ - スに整合しているので問題ないと思います。 +  通常は move.l (1),d0 等の、実行時にアドレスエラーが起こるであろう命令は + 未定義命令と見なしますが、このオプションを付けるとそのチェックをしません。 + なお、68020 以降の MPU では上に挙げた命令はアドレスエラーになりませんが、 + dis では未定義命令と見なします。普通のプログラムなら、効率的なメモリアクセ + スの為に偶数アドレスに整合しているので問題ないと思います。 -k -  命令の中を指すラベルはないものと見なす。 - -  命令の中を指すラベルの存在しないプログラムで、このオプションを - 指定すると生成ファイルの質が良くなる場合があります。しかし存在す - るプログラムで指定すると生成ファイルの質がかなり悪くなります。 - -  このオプションを付けると、label+$?????? と言うラベルを全て解消 - するために、label+$?????? の含まれる領域はデータ領域とされます。 - 例えば、 - - top: bsr label3 - lea.l (label1),a0 - move.w (label2),d0 - rts - label1: .dc.w $0040 ;data - label2: .dc.w $0000 ;data - label3: ............. ;program - -  上のプログラムは -k オプション無しだと - top: bsr label3 - lea.l (label1),a0 - move.w (label1+$000002),d0 - rts - label1: ori.w #$0000,d0 - label3: ............. - -  -k オプションを付けると - top: bsr label3 - lea.l (label1),a0 - move.w (label2),d0 - rts - label1: .dc.b $00,$40 - label2: .dc.w $0000 - label3: ............. - -  とりあえず、-k オプションを付けずにソースジェネレートしてみて - おかしいところがあれば、-k オプションを付けてやってみて、2つを - 比較してみると良いでしょう。 +  命令の中を指すラベルはないものと見なす。 + +  命令の中を指すラベルの存在しないプログラムで、このオプションを指定すると + 生成ファイルの質が良くなる場合があります。しかし存在するプログラムで指定す + ると生成ファイルの質がかなり悪くなります。 + +  このオプションを付けると、label+$?????? と言うラベルを全て解消するため + に、label+$?????? の含まれる領域はデータ領域とされます。例えば、 + + top: bsr label3 + lea.l (label1),a0 + move.w (label2),d0 + rts + label1: .dc.w $0040 ;data + label2: .dc.w $0000 ;data + label3: ............. ;program + +  上のプログラムは -k オプション無しだと + top: bsr label3 + lea.l (label1),a0 + move.w (label1+$000002),d0 + rts + label1: ori.w #$0000,d0 + label3: ............. + +  -k オプションを付けると + top: bsr label3 + lea.l (label1),a0 + move.w (label2),d0 + rts + label1: .dc.b $00,$40 + label2: .dc.w $0000 + label3: ............. + +  とりあえず、-k オプションを付けずにソースジェネレートしてみておかしいと + ころがあれば、-k オプションを付けてやってみて、2つを比較してみると良いでし + ょう。 -f -  バイト操作命令の不定バイトのチェックをしない。 +  バイト操作命令の不定バイトのチェックをしない。 -  前述の不定バイトチェック(不定バイトが $00 か $ff かどうかのチ - ェック)をしないようにします。 +  不定バイトチェック(不定バイトが $00 か $ff かどうかのチェック)をしないよ + うにします(不定バイトについては用語解説の項目を参照して下さい)。 -  このオプションを付けた場合、生成ファイルをアセンブルしたものが - 元の実行ファイルと等しくならない場合があります。 +  このオプションを付けた場合、生成ファイルをアセンブルしたものが元の実行フ + ァイルと等しくならない場合があります。 -E -  バイト操作命令の不定バイトの書き換えチェックをしない。 +  バイト操作命令の不定バイトの書き換えチェックをしない。 -  不定バイトに対するラベルが存在した場合、通常は、「不定バイトを - 書き換えるような奴はいないよなぁ」と信じてその命令(不定バイトの - ある)領域をデータ領域にしてしまいますが、-E オプションはこのチェ - ックをしないようにします。 +  不定バイトに対するラベルが存在した場合、通常は、「不定バイトを書き換える + ような奴はいないよなぁ」と信じてその命令(不定バイトのある)領域をデータ領域 + にしてしまいますが、-E オプションはこのチェックをしないようにします。 -u[num] -  A line trap 及び DOS call、浮動小数点演算ドライバ(FLOATn.X)で - 使用されていない F line trap を未定義命令と見なさない。 +  A line trap 及び DOS call、浮動小数点演算ドライバ(FLOATn.X)で使用されて + いない F line trap を未定義命令と見なさない。 -  Mac Emulator や、SX-Window 等の A line trap を使ったプログラム - をソースジェネレートするときに付けて下さい。 +  Mac Emulator や、SX-Window 等の A line trap を使ったプログラムをソースジ + ェネレートするときに付けて下さい。 -  なお、使用されているかどうかの判断は、doscall.mac、fefunc.mac - にシンボルが存在するかどうかによります。 +  なお、使用されているかどうかの判断は、doscall.mac、fefunc.mac にシンボル + が存在するかどうかによります。 -  -u1 の時、SX-Window 対応となります。環境変数 dis_sxmac をセッ - トしておけば、SX-Window のファンクションコールを、SXCALL name の - ような形で出力します。 +  -u1 の時、SX-Window 対応となります。環境変数 dis_sxmac をセットしておけ + ば、SX-Window のファンクションコールを、SXCALL name のような形で出力しま + す。 -y -  「text セクション中の全てのデータ領域をとりあえず逆アセンブル - してみて、おかしくなければそこをプログラム領域と思い込む」ことを - しない。 +  「text セクション中の全てのデータ領域をとりあえず逆アセンブルしてみて、 + おかしくなければそこをプログラム領域と思い込む」ことをしない。 -  dis のデフォルトでは、一通り解析した後、サイズの分からないデー - タは「プログラムちゃうか?」と疑って、片っ端から解析しようと試み - ます。-y オプションを付けると、「片っ端から」ではなく、データの - 終わりがリターン命令、ジャンプ命令等と見受けられるもののみを「プ - ログラムちゃうか?」と疑います。 +  dis のデフォルトでは、一通り解析した後、サイズの分からないデータは「プロ + グラムちゃうか?」と疑って、片っ端から解析しようと試みます。-y オプション + を付けると、「片っ端から」ではなく、データの終わりがリターン命令、ジャンプ + 命令等と見受けられるもののみを「プログラムちゃうか?」と疑います。 -  このオプションをつけると解析の対象となる領域が少なくなる分だけ、 - 解析時間が減ります。しかしプログラム領域をデータ領域として残して - しまうことが多くなるでしょう。しかし付けないと、データ領域をプロ - グラム領域としてしまうこともあるかも知れません。 +  このオプションをつけると解析の対象となる領域が少なくなる分だけ、解析時間 + が減ります。しかしプログラム領域をデータ領域として残してしまうことが多くな + るでしょう。しかし付けないと、データ領域をプログラム領域としてしまうことも + あるかも知れません。 -n num -  文字列として判定する最小の長さ(デフォルトは3)。 +  文字列として判定する最小の長さ(デフォルトは3)。 -  このプログラムでは、文字列領域を自動的に判別します。ただ、文字 - 列判別を完璧に行うのは不可能で、文字列でないところも文字列として - しまう場合があります(特に短い文字列)。このオプションを指定すると、 - それ未満の長さは文字列として判定しません。また、num に 0 を指定 - すると、文字列の自動判別を行いません。 +  このプログラムでは、文字列領域を自動的に判別します。ただ、文字列判別を完 + 璧に行うのは不可能で、文字列でないところも文字列としてしまう場合があります + (特に短い文字列)。このオプションを指定すると、それ未満の長さは文字列として + 判定しません。また、num に 0 を指定すると、文字列の自動判別を行いません。 -D -  データセクション中にもプログラムを認める。 +  データセクション中にもプログラムを認める。 -  dicm.x など、データセクションに分岐するプログラムが存在するこ - とが分かったためにサポートしました。データセクションに分岐してい - れば、"解析中のバックトラックの要因の表示機能" で、"pc が有効な - セクションをを外れた" と表示されるのでわかると思います(他の理由 - でもそう表示されることはありますが)。プログラム領域解析中に "pc - が有効な...." と表示されたらこのオプションを試してみて下さい。 +  dicm.x など、データセクションに分岐するプログラムが存在することが分かっ + たためにサポートしました。データセクションに分岐していれば、「解析中のバッ + クトラックの要因の表示機能"」で、「pc が有効なセクションを外れた」と表示さ + れるのでわかると思います(他の理由でもそう表示されることはありますが)。プロ + グラム領域解析中に「pc が有効な...」と表示されたらこのオプションを試してみ + て下さい。 -R num -  未使用フィールドのチェック項目の指定(ビット指定, 初期値=15)。 +  未使用フィールドのチェック項目の指定(ビット指定, 初期値=15)。 - +1 mulu.l、muls.l、ftst.x における未使用レジスタフィール - ドのチェック。 - +2 拡張アドレッシングでのサプレスされたレジスタフィール - ドのチェック。 - +4 サプレスされたインデックスレジスタに対するスケーリン - グのチェック。 - +8 サプレスされたインデックスレジスタに対するサイズ指定 - (.l)のチェック。 + +1 未使用レジスタフィールド(mul[us].l, ftst.x, c{inv,push}a)のチェック。 + +2 拡張アドレッシングでのサプレスされたレジスタフィールドのチェック。 + +4 サプレスされたインデックスレジスタに対するスケーリングのチェック。 + +8 サプレスされたインデックスレジスタに対するサイズ指定(.l)のチェック。 -G -  サブルーチンコール命令の直後に引数を置くプログラムを解析する。 +  サブルーチンコール命令の直後に引数を置くプログラムを解析する。 + +  ROMDB などサブルーチンコール命令の直後に引数を置く古い手法が使われている + プログラムの場合、dis は命令とデータの区別を自動的にすることは出来ない為 + に、その一帯を全てデータ領域にしてしまいます。このオプションを指定すると、 + jsr、bsr などサブルーチンコール命令の直後にデータラベルがあった場合、その + 時点でプログラムの解析を打ち切り、正しいプログラムと認めます。自動的にデー + タラベルが登録されることはないので、ユーザによるラベルファイルの修正が必須 + となります。 -  ROMDB などサブルーチンコール命令の直後に引数を置く古い手法が使 - われているプログラムの場合、dis は命令とデータの区別を自動的にす - ることは出来ない為に、その一帯を全てデータ領域にしてしまいます。 - このオプションを指定すると、jsr、bsr などサブルーチンコール命令 - の直後にデータラベルがあった場合、その時点でプログラムの解析を打 - ち切り、正しいプログラムと認めます。自動的にデータラベルが登録さ - れることはないので、ユーザによるラベルファイルの修正が必須となり - ます。 +  ラベルファイルを読み込まない初回の逆アセンブル時は -G オプションは指定し + ないで下さい。正しく解析が行われない可能性があります。 -  ラベルファイルを読み込まない初回の逆アセンブル時は -G オプショ - ンは指定しないで下さい。正しく解析が行われない可能性があります。 + ・ラベルファイルの修正方法 - ・ラベルファイルの修正方法 +  まず一度 -e オプションを指定して逆アセンブルし、ラベルファイルを作成しま + す(この時 -G オプションは指定しないこと)。次に、不完全なソースコードを自分 + で解析しながら、サブルーチンコール命令の直後にある引数を探します。そのデー + タのアドレスを計算し、ラベルファイルに追加します。 -  まず一度 -e オプションを指定して逆アセンブルし、ラベルファイル - を作成します(この時 -G オプションは指定しないこと)。次に、不完全 - なソースコードを自分で解析しながら、サブルーチンコール命令の直後 - にある引数を探します。そのデータのアドレスを計算し、ラベルファイ - ルに追加します。 +  今度は -g、-G オプションを指定して逆アセンブルします。ラベルファイルの指 + 定が正しければ、追加したアドレスの直前までがプログラムとして、追加したアド + レス以降がデータとして解析される筈です。 -  今度は -g、-G オプションを指定して逆アセンブルします。ラベルフ - ァイルの指定が正しければ、追加したアドレスの直前までがプログラム - として、追加したアドレス以降がデータとして解析される筈です。 +--reltbl-zero=num +  リラティブオフセットテーブルのオフセット値として0を認めるかどうかを指定 + します。 + + --reltbl-zero=0 0を認めません。 + --reltbl-zero=1 先頭のみ認めます(デフォルト)。 + --reltbl-zero=2 テーブル全域で認めます。 ●ファンクションコールに関するオプション @@ -487,754 +489,845 @@ dis_header --exclude-doscall-mac --exclude-iocscall-mac --exclude-fefunc-mac -  それぞれ DOS コール、IOCS コール、FEFUNC コールを認識しないよ - うにします。DOS/FEFUNC コールは全て未定義命令か .dc 疑似命令(-u - 指定時)に、IOCS コールは moveq + trap #15 で出力されます。 +  それぞれ DOS コール、IOCS コール、FEFUNC コールを認識しないようにしま + す。DOS/FEFUNC コールは全て未定義命令か .dc 疑似命令(-u 指定時)に、IOCS + コールは moveq + trap #15 で出力されます。 -  このオプションは X680x0/Human68k 以外の環境の実行ファイルを逆 - アセンブルする時に、余計な解釈を行わないようにする為に使用します。 +  このオプションは X680x0/Human68k 以外の環境の実行ファイルを逆アセンブル + する時に、余計な解釈を行わないようにする為に使用します。 --include-doscall-mac=file --include-iocscall-mac=file --include-fefunc-mac=file -  それぞれ DOS コール、IOCS コール、FEFUNC コールのマクロ/ファン - クションコール番号を定義したファイルを指定します。file にファイ - ル名を記述して下さい。無指定時は環境変数 dis_include か include - で指定したディレクトリにあるファイルが読み込まれます。 +  それぞれ DOS コール、IOCS コール、FEFUNC コールのマクロ/ファンクションコ + ール番号を定義したファイルを指定します。file にファイル名を記述して下さ + い。無指定時は環境変数 dis_include か include で指定したディレクトリにある + ファイルが読み込まれます。 -  このオプションは環境変数 dis_include、include よりも優先されま - す。 +  このオプションは環境変数 dis_include、include よりも優先されます。 ●出力ファイルに関するオプション -b num -  分岐命令のサイズを以下のようにする(分岐命令のサイズとは Bcc 等 - の .s/.w.l のことです)。 +  分岐命令のサイズを以下のようにする(分岐命令のサイズとは Bcc 等の .s/.w.l + のことです)。 - -b0 ショートブランチで済むのにワードブランチをしている、 - またはワードブランチで済むのみロングワードブランチを - している場合(デフォルト)。 - -b1 サイズを常に省略します。 - -b2 サイズを常に付けます。 + -b0 ショートブランチで済むのにワードブランチをしている、またはワードブラン + チで済むのみロングワードブランチをしている場合(デフォルト)。 + -b1 サイズを常に省略します。 + -b2 サイズを常に付けます。 -o num -  文字列領域の桁数(デフォルトは 60)。 +  文字列領域の桁数(デフォルトは 60)。 -  ソースファイルに出力する文字列領域の桁数を指定します。 +  ソースファイルに出力する文字列領域の桁数を指定します。 -w num -  データ領域の横バイト数(デフォルトは8)。 +  データ領域の横バイト数(デフォルトは8)。 -  データ領域の横バイト数を指定します。デフォルトでは - .dc.b $??,$??,$??,$??,$??,$??,$??,$?? - のように横は8バイトです。データの多いプログラムでは16にした方が - 良いかも知れません。 +  データ領域の横バイト数を指定します。デフォルトでは + .dc.b $??,$??,$??,$??,$??,$??,$??,$?? + のように横は8バイトです。データの多いプログラムでは16にした方が良いかもし + れません。 -a[num] -  num 行ごとにアドレスをコメントで出力。 +  num 行ごとにアドレスをコメントで出力。 -  num を省略すると5行ごと。ラベルファイル(後述)を編集する時等は - 便利かも知れません。 +  num を省略すると5行ごと。ラベルファイル(後述)を編集する時等は便利かもし + れません。 -r -  文字列に16進数のコメントを付ける。 +  文字列に16進数のコメントを付ける。 -x -  オペコードに16進数のコメントを付ける。 +  オペコードに16進数のコメントを付ける。 - (例) - ori.b #xx,d0 ;$0000,$00xx - rts ;$4e75 - のようになります。 + (例) + ori.b #xx,d0 ;$0000,$00xx + rts ;$4e75 + のようになります。 -s[num] -  外部定義シンボルについて、定数の定義行及びアドレス値の外部宣言 - 行を出力する。 - -  実行ファイルにシンボルテーブルが付属している場合、シンボル名と - アドレス値または定数が得られます。これらの情報は再アセンブルの再 - にはなくても問題ありませんが、シンボルテーブルまで再現するには外 - 部定義しなければなりません。アドレス値についてはラベルを "::" で - 定義するのでシンボルテーブルに出力されますが、定数は .equ 疑似命 - 令で定義しなければなりません。このオプションは定数を定義するかを - 指定します。 - -  また、アドレス値はラベル定義時に同時に外部定義されるのですが、 - シンボルテーブルに現われる順番と、実際にソースコードに現われる順 - 番が違うとシンボルテーブルが一致しません。そのような場合、シンボ - ルテーブルに現われる順番通りに .xref 疑似命令でラベルを宣言する - と順番まで再現されます。このオプションでは宣言を行うかどうかも指 - 定できます。 - -  定数の定義は「name:: .equ 値」、ラベルの宣言は「 .xref name」 - という形式でソースコードの先頭部分に出力されます。なお、'*'+フ - ァイル名+'*' という形式のアドレス境界情報のシンボルはアセンブラ - で扱う事が出来ないので、常に無視されます。 - - 数値を省略した場合は -s0 と見なします。標準設定は -s1 です。 - - -s0 外部定義シンボルの定義行を出力しません。 - ただし、アドレス値については各セクションで定義される時に - 外部定義されるので、-C0 や -C1 オプションを指定しない限 - り常に外部定義になります。 - - -s1 定数のみ定義行を出力します。定数の外部定義シンボルについ - ては、定義される順番も含めてシンボルテーブルが再現されま - す。 - - -s2 アドレス値についても、.xdef 疑似命令による外部定義を出力 - します。全てのシンボルについて、定義される順番も含めてシ - ンボルテーブルがほぼ完全に再現されます。 - - ただし、スタックセクション(属性 0x0204)及びコモンセクシ - ョンのシンボル(同 0x0003)は再現できず、BSS のシンボル(同 - 0x0203)となってしまいます。 - -  -e オプションで出力されたラベルファイルのシンボル名を書き換え - て -g オプションで読み込ませる場合は、-s2 は指定しないで下さい。 - .xdef で宣言されるシンボル名は実行ファイルに付属するシンボルテー - ブルそのままであるのに対し、ソース中で定義/参照されるのはラベル - ファイルで変更されたシンボル名なので、アセンブルしようとするとエ - ラーになってしまいます。 +  外部定義シンボルについて、定数の定義行及びアドレス値の外部宣言行を出力す + る。 + +  実行ファイルにシンボルテーブルが付属している場合、シンボル名とアドレス値 + または定数が得られます。これらの情報は再アセンブルの際にはなくても問題あり + ませんが、シンボルテーブルまで再現するには外部定義しなければなりません。ア + ドレス値についてはラベルを "::" で定義するのでシンボルテーブルに出力されま + すが、定数は .equ 疑似命令で定義しなければなりません。このオプションは定数 + を定義するかを指定します。 + +  また、アドレス値はラベル定義時に同時に外部定義されるのですが、シンボルテ + ーブルに現われる順番と、実際にソースコードに現われる順番が違うとシンボルテ + ーブルが一致しません。そのような場合、シンボルテーブルに現われる順番通りに + .xref 疑似命令でラベルを宣言すると順番まで再現されます。このオプションでは + 宣言を行うかどうかも指定できます。 + +  定数の定義は「name:: .equ 値」、ラベルの宣言は「 .xref name」という形式 + でソースコードの先頭部分に出力されます。なお、'*'+ファイル名+'*' という形 + 式のアドレス境界情報のシンボルはアセンブラで扱う事が出来ないので、常に無視 + されます。 + + 数値を省略した場合は -s0 と見なします。標準設定は -s1 です。 + + -s0 外部定義シンボルの定義行を出力しません。 + ただし、アドレス値については各セクションで定義される時に外部定義される + ので、-C0 や -C1 オプションを指定しない限り常に外部定義になります。 + + -s1 定数のみ定義行を出力します。定数の外部定義シンボルについては、定義され + る順番も含めてシンボルテーブルが再現されます。 + + -s2 アドレス値についても、.xdef 疑似命令による外部定義を出力します。全ての + シンボルについて、定義される順番も含めてシンボルテーブルがほぼ完全に再 + 現されます。 + + ただし、スタックセクション(属性 0x0204)及びコモンセクションのシンボル + (同 0x0003)は再現できず、BSS のシンボル(同 0x0203)となってしまいます。 + +  -e オプションで出力されたラベルファイルのシンボル名を書き換えて -g オプ + ションで読み込ませる場合は、-s2 は指定しないで下さい。.xdef で宣言されるシ + ンボル名は実行ファイルに付属するシンボルテーブルそのままであるのに対し、ソ + ース中で定義/参照されるのはラベルファイルで変更されたシンボル名なので、ア + センブルしようとするとエラーになってしまいます。 -F -  dbra、fdbra を dbf、fdbf として出力する。 +  dbra、fdbra を dbf、fdbf として出力する。 -X -  16進数を大文字化する。 +  16進数を大文字化する。 -U -  オペコード等を大文字化する。 +  オペコード等を大文字化する。 -Z[num] -  16進数をゼロサプレスする。 +  16進数をゼロサプレスする。 - -Z0 普通にゼロサプレスする。 - -Z1 ゼロサプレスした時省略可能な '$' を省略する。 + -Z0 普通にゼロサプレスする。 + -Z1 ゼロサプレスした時省略可能な '$' を省略する。 -  num を省略した場合は -Z0 と同じになります。 +  num を省略した場合は -Z0 と同じになります。 -N -  デフォルトのサイズならサイズを出力しない。 +  デフォルトのサイズならサイズを出力しない。 - (例) - move.w #$1234,d0 (default) - ↓ - move #$1234,d0 + (例) + move.w #$1234,d0 (default) + ↓ + move #$1234,d0 -K char -  コメントキャラクタを変更。 +  コメントキャラクタを変更。 -  コメントの先頭には通常 ';' がつきますが、それを変更出来ます。'#' - にしたければ、-K# と指定して下さい。 +  コメントの先頭には通常 ';' がつきますが、それを変更出来ます。'#' にした + ければ、-K# と指定して下さい。 -L char -  ラベルの先頭文字を変更。 +  ラベルの先頭文字を変更。 -  ラベルの先頭には通常 'L' がつきますが、それを変更出来ます。'_' - にしたければ、-L_ と指定して下さい。 +  ラベルの先頭には通常 'L' がつきますが、それを変更出来ます。'_' にしたけ + れば、-L_ と指定して下さい。 -C -  ラベルの後のコロン(:)を出力するかどうか。 +  ラベルの後のコロン(:)を出力するかどうか。 - -C0 ラベルの後にコロンを付けない。 - -C1 ラベルの後にコロンを1つ付ける。 - -C2 ローカルラベルにはコロンを1つ、外部定義ラベルにはコ - ロンを2つ付ける(デフォルト)。 - -C3 すべてのラベルの後にコロンを2つ付ける。 + -C0 ラベルの後にコロンを付けない。 + -C1 ラベルの後にコロンを1つ付ける。 + -C2 ローカルラベルにはコロンを1つ、外部定義ラベルにはコロンを2つ付ける(デ + フォルト)。 + -C3 すべてのラベルの後にコロンを2つ付ける。 -A -  cmpi、movea 等を cmp、move 等にする。 +  cmpi、movea 等を cmp、move 等にする。 -  ただし、演算先がデータレジスタの cmpi、ori、andi、subi、addi、 - eori は "i" なしの命令とオブジェクトコードが異なるので、そのまま - で出力されます。また、addi と subi で即値が 1 ~ 8 の場合、addq - や subq に最適化されるのを防ぐ為、即値にサイズが付きます。 +  ただし、演算先がデータレジスタの cmpi、ori、andi、subi、addi、eori は + "i" なしの命令とオブジェクトコードが異なるので、そのままで出力されます。ま + た、addi と subi で即値が 1~8 の場合、addqや subq に最適化されるのを防ぐ + ため、即値にサイズが付きます。 -S[num] -  出力ファイルを分割して出力する。 +  出力ファイルを分割して出力する。 -  実行ファイルの(ほぼ)num KByte ごとに出力ファイルを分割します。 - 数100 KByte の実行ファイルをソースジェネレートする時に付けると、 - あとから見易いかも知れません(そのままではアセンブル出来ませんが)。 +  実行ファイルの(ほぼ)num KByte ごとに出力ファイルを分割します。数100KByte + の実行ファイルをソースジェネレートする時に付けると、あとから見易いかも知れ + ません(そのままではアセンブル出来ませんが)。 -  分割されたファイル名は以下のようになります。 - text section は、拡張子が以下のようになります。 - .000 .001 ..... .009 .00a .00f .010 ..... +  分割されたファイル名は以下のようになります。 + text section は、拡張子が以下のようになります。 + .000 .001 ... .009 .00a .00f .010 ... - data section、bss は拡張子がそれぞれ - .dat .bss になります。 + data section、bss は拡張子がそれぞれ .dat .bss になります。 -  num を省略すると 64KByte ごとに分割します。ファイルの分割は空 - 行で行われるので、サブルーチンの途中で切れたりと言うことはそんな - には無いと思います。 +  num を省略すると 64KByte ごとに分割します。ファイルの分割は空行で行われ + るので、サブルーチンの途中で切れたりと言うことはそんなには無いと思います。 -B -  bra の後でも改行する。 +  bra の後でも改行する。 -  デフォルトでは、rts、rte、rtr、jmp、DOS _EXIT、DOS _EXIT2、DOS - _KEEPPR、SXCALL ExitToShell の後で一行空行を入れますが、このオプ - ションをつけると bra の後でも空行を入れるようになります。 +  既定ではリターン命令およびプログラムを終了させるファンクションコールの後 + に一行空行が入りますが、このオプションを指定すると bra および fbra の後に + も空行を入れます。 + + リターン命令: rte rtd rts rtr + DOS コール: _EXIT _EXIT2 _KEEPPR _KILL_PR + SXCALL: __TSExit (ExitToShell) -M -  cmpi、move、addi.b、subi.b #imm および pack、unpk にコメントを - 付ける。 +  cmpi、move、addi.b、subi.b #imm および pack、unpk にコメントを付ける。 -  num が表示可能な ASCII code の場合に以下のようなコメントを入れ - ます。解析には便利でしょう。 +  num が表示可能な ASCII code の場合に以下のようなコメントを入れます。解析 + には便利でしょう。 - cmp.b #$40,d0 ;'@' + cmp.b #$40,d0 ;'@' -W num -  同一データを .dcb で出力する最小バイト数。0なら圧縮しない(初期 - 値=64)。 +  同一データを .dcb で出力する最小バイト数。0なら圧縮しない(初期値=64)。 -  データを .dc.? で出力する場合、全てのデータが同一の値であれば - .dcb.? により圧縮して出力されますが、一定のサイズより小さい領域 - は例え同一値であっても圧縮されません。このオプションでそのサイズ - の閾値を変更出来ます。 +  データを .dc.? で出力する場合、全てのデータが同一の値であれば .dcb.? に + より圧縮して出力されますが、一定のサイズより小さい領域は例え同一値であって + も圧縮されません。このオプションでそのサイズの閾値を変更できます。 --a7 -  a7 レジスタを'a7'と表記する(デフォルト)。 +  a7 レジスタを 'a7' と表記する(デフォルト)。 -  --sp オプションを取り消します。 +  --sp オプションを取り消します。 --sp -  a7 レジスタを'sp'と表記する。 +  a7 レジスタを 'sp' と表記する。 -  通常、スタックポインタは'a7'と表記されますが、このオプションを - 指定すると'sp'と表記されるようになります。 +  通常、スタックポインタは 'a7' と表記されますが、このオプションを指定する + と 'sp' と表記されるようになります。 --new-syntax -  アドレッシングを新表記で出力する。 +  アドレッシングを新表記で出力する(デフォルト)。 -  --old-syntaxを打ち消します。 +  --old-syntax を打ち消します。 --old-syntax -  アドレッシングを旧表記で出力する(標準では--new-syntax)。 +  アドレッシングを旧表記で出力する(標準では --new-syntax)。 + +  通常は 68020 以降で定められたアドレッシング表記で出力しますが、このオプ + ションを指定した場合は 68000 の表記で出力します。ただし、68020 以降でしか + 使用できないアドレッシングでは常に新しい表記で出力します。 -  通常は 68020 以降で定められたアドレッシング表記で出力しますが、 - このオプションを指定した場合は 68000 の表記で出力します。ただし、 - 68020 以降でしか使用できないアドレッシングでは常に新しい表記で出 - 力します。 +--real +  浮動小数点を実数表記で出力する(デフォルト)。 ---(in)real -  浮動小数点を[実数表記](内部表現)で出力する。 +  命令のオペランドやデータとして浮動小数点を出力する場合の表記を選択しま + す。--real を指定すると「0f1.23e+10」といった実数表記で出力します。 -  命令のオペランドやデータとして浮動小数点を出力する場合の表記を - 選択します。--real を指定すると「0f1.23e+10」といった実数表記、 - --inreal を指定すると「!4048f5c3」といった内部表現で出力します。 +  非数や無限大、非正規化数、未使用ビットがセットされているデータの場合は実 + 数表記が不可能なので、常に内部表現で出力されます。 -  非数や無限大、非正規化数、未使用ビットがセットされているデータ - の場合は実数表記が不可能なので常に内部表現で出力されます。 + --inreal を打ち消します。 -  標準状態では --real が指定されています。 +--inreal +  浮動小数点を内部表現で出力する。 + +  命令のオペランドやデータとして浮動小数点を出力する場合の表記を選択しま + す。--inreal を指定すると「!4048f5c3」といった内部表現で出力します。 + + --real を打ち消します。 --overwrite -  ファイルを無条件で上書きする。 +  ファイルを無条件で上書きする。 -  通常、指定した出力ファイルが既に存在した場合、上書きするかどう - かを問い合わせますが、このオプションを指定すると問い合わせせずに - 強制的に上書きします。 +  通常、指定した出力ファイルが既に存在した場合、上書きするかどうかを問い合 + わせますが、このオプションを指定すると問い合わせずに強制的に上書きします。 --header=file -  出力ファイルの最初に出力される .include 部を書いたファイルを - file に指定すると、そのファイルの内容がデフォルトの .include の - 代わりに挿入されます。環境変数 dis_header より優先されます。 +  出力ファイルの最初に出力される .include 部を書いたファイルを file に指定 + すると、そのファイルの内容がデフォルトの .include の代わりに挿入されます。 + 環境変数 dis_header より優先されます。 + +--strip-include-path +  .include にパス名を付けず、ファイル名のみを出力します。 ●実行ファイルに関するオプション -d -  デバイスドライバの時に指定。 +  デバイスドライバの時に指定。 -  実行ファイルがデバイスドライバの時は必ず指定して下さい。ほんの - 僅かに生成ファイルの質が良くなります。デバイスドライバでないとき - は指定しないで下さい。妙なことが起こるかもしれません。 +  実行ファイルがデバイスドライバの時は必ず指定して下さい。ほんの僅かに生成 + ファイルの質が良くなります。デバイスドライバでないときは指定しないで下さ + い。妙なことが起こるかもしれません。 + +  -g オプション指定時はこのオプションは無視されます。 -z base,exec -  指定した実行ファイルを単なるバイナリファイルと見なす。その際、 - そのファイルは base から読み込まれて exec から実行されるものとす - る。base、exec は16進数のみ。 +  指定した実行ファイルを単なるバイナリファイルと見なす。その際、そのファイ + ルは base から読み込まれて exec から実行されるものとする。 + base、exec は16進数のみ。 -  例えば、2HD disk の IPL 部を読み出して解析するのなら、 - dis 2hdipl 2hdipl.s -z2000,2000 - 等と指定する。ROM の IPL/IOCS を解析するのなら、 - dis rom rom.s -zff0000,ff0010 - 等と指定する(-h をつけた方が良いかも知れない)。 +  例えば、2HD disk の IPL 部を読み出して解析するのなら、 + dis 2hdipl 2hdipl.s -z2000,2000 + 等と指定する。ROM の IPL/IOCS を解析するのなら、 + dis rom rom.s -zff0000,ff0010 + 等と指定する(-h をつけた方が良いかも知れない)。 - (当然 IPL 等は db.x 等で Human68k のファイルに落としておかねばな - りません) + (当然 IPL 等は db.x 等で Human68k のファイルに落としておかねばなりません) -  少なくとも base は分かっていなければなりません。exec が分から - なければ base と同じにしておいて、-h オプション等を付ければなん - とか見れるソースになると思います。 +  少なくとも base は分かっていなければなりません。exec が分からなければ + base と同じにしておいて、-h オプション等を付ければなんとか見れるソースにな + ると思います。 ●ラベルファイルに関するオプション -e[filename] -  ラベルファイルの出力。 +  ラベルファイルの出力。 -  ファイル名を指定しなければ、出力ファイルの拡張子を .lab に変更 - した名称のファイルを作る。 +  ファイル名を指定しなければ、出力ファイルの拡張子を .lab に変更した名称の + ファイルを作る。 -g[filename] -  ラベルファイルの読み込み。 +  ラベルファイルの読み込み。 -  ファイル名を指定しなければ、出力ファイルの拡張子を .lab に変更 - した名称のファイルを読み込む。 +  ファイル名を指定しなければ、出力ファイルの拡張子を .lab に変更した名称の + ファイルを読み込む。 ●テーブル記述ファイルに関するオプション -T[filename] -  テーブル記述ファイルの読み込み。 +  テーブル記述ファイルの読み込み。 -  ファイル名を指定しなければ、出力ファイルの拡張子を .tab に変更 - した名称のファイルを読み込む。 +  ファイル名を指定しなければ、出力ファイルの拡張子を .tab に変更した名称の + ファイルを読み込む。 ●その他のオプション -q[num] -  解析中/出力中のメッセージ( > 分岐命令等で、解析の深さが深くなった。 - < リターン命令等で、解析の深さが浅くなった。 - ? 未定義命令等を発見して、解析の深さが浅くなった。 - # データ。 - s 文字列。 - ! ラベルチェックで、命令の中のラベルを発見した。 - * ラベルチェックで、命令の中のラベルを解消した。 - 。ラベル1つ。 - - そのままではプログラム領域からデータ領域に突入してしま - う所を発見/修正した。 - + ラベルチェックでプログラム領域中に未定義命令等を発見し - た。 - r リラティブオフセットテーブル。 - R リラティブオフセットテーブル(ロングワード)。 - z ロングワードテーブル。 - t ユーザー指定のテーブル。 - $ BSS ラベル1つ。 +  解析中/出力中のメッセージ( > 分岐命令等で、解析の深さが深くなった。 + < リターン命令等で、解析の深さが浅くなった。 + ? 未定義命令等を発見して、解析の深さが浅くなった。 + # データ。 + s 文字列。 + ! ラベルチェックで、命令の中のラベルを発見した。 + * ラベルチェックで、命令の中のラベルを解消した。 + . ラベル1つ。 + - そのままではプログラム領域からデータ領域に突入してしまう所を発見/修 + 正した。 + + ラベルチェックでプログラム領域中に未定義命令等を発見した。 + r リラティブオフセットテーブル。 + R リラティブオフセットテーブル(ロングワード)。 + z ロングワードテーブル。 + t ユーザー指定のテーブル。 + $ BSS ラベル1つ。 + +  なお、解析中に出力される {数値} というメッセージは解析で見つけたプログラ + ム領域などの数です。これは -q オプションを付けても出力されます。 -v -  単なる逆アセンブルリストを出力する。 +  単なる逆アセンブルリストを出力する。 -  このオプションはおまけです。db.x の出力をリダイレクトするより - は見易いかな… +  このオプションはおまけです。db.x の出力をリダイレクトするよりは見易いか + な… --V num -  解析中のバックトラックの要因の表示。 +-I +  ラベルチェック中に、修正したアドレスを表示する。 - -V0 出力しない(version 1.13 以前と同じ)。 - -V1 プログラム領域の筈のところでのバックトラックの要因を - 表示(デフォルト)。 - -V2 全ての領域でのバックトラックの要因を表示。 + 命令の中を差すラベル(X -> Y+?) +  アドレス X が命令の中にあってラベルを振ることができないために、Y+? + にするという意味。 -  表示されるのは、dis がプログラムと認めなかった理由、およびその - アドレス等です。作者にしか意味が分からないかも知れません(^_^;) + 命令の中を差すラベル(X)データ領域に変更しました(Y-X) +  -k オプションを使用している、あるいはアドレス X が不定バイトの上にあ + るために、Y から X までをデータ領域に変更したという意味。この領域が本 + 当にプログラムのようであれば -E オプションを試してみると良いかもしれな + い。 --I -  ラベルチェック中に、修正したアドレスを表示する。 +-Q +  環境変数 DIS_OPT、dis_opt を参照しない。 + +  通常はコマンドラインを解釈する前に環境変数 DIS_OPT または dis_opt に設定 + したオプションを解釈しますが、このオプションを指定するとこれらを参照しませ + ん。 - 命令の中を差すラベル(X -> Y+?) +  コマンドラインの先頭に指定する必要があります。 -  アドレス X が命令の中にあってラベルを振ることができ - ないために、Y+? にするという意味。 +-V num +  解析中のバックトラックの要因の表示。 - 命令の中を差すラベル(X)データ領域に変更しました(Y-X) + -V0 出力しない(version 1.13 以前と同じ)。 + -V1 プログラム領域の筈のところでのバックトラックの要因を表示(デフォルト)。 + -V2 全ての領域でのバックトラックの要因を表示。 -  -k オプションを使用している、あるいはアドレス X が不定 - バイトの上にあるために、Y から X までをデータ領域に変更 - したという意味。この領域が本当にプログラムのようであれば - -E オプションを試してみると良いかもしれない。 +  表示されるのは、dis がプログラムと認めなかった理由、およびそのアドレス等 + です。作者にしか意味が分からないかも知れません(^_^;) -Y -  カレントディレクトリからも include ファイルを検索する。 +  カレントディレクトリからも include ファイルを検索する。 + +  通常は環境変数 dis_include や include で指定されたパスにあるインクルード + ファイルを読み込みますが、このオプションを指定するとカレントディレクトリに + あるファイルを優先して読み込みます。カレントになければ環境変数で指定された + パスを検索します。 + +--deterministic +  決定論的逆アセンブルを行う。 - 通常は環境変数 dis_include や include で指定されたパスに - あるインクルードファイルを読み込みますが、このオプション - を指定するとカレントディレクトリにあるファイルを優先して - 読み込みます。カレントになければ環境変数で指定されたパス - を検索します。 +  入力ファイルの内容が同じなら、いつどこで実行しても同じ出力ファイルを生成 + するようになります。 + 環境変数 dis_header を参照しません。 + ソースコードに実行ファイルのタイムスタンプと実行日時を出力しません。 + ソースコードに出力する dis の実行ファイル名を "dis" 固定にします。 + +  同時に以下のオプションが指定されます。 + -Q -h -q -N -Z1 --sp --strip-include-path + +  コマンドラインの先頭に指定する必要があります。 ●無用なオプション(バグがあったりして) -c -  ラベルチェックを行わない。 +  ラベルチェックを行わない。 -  ラベルチェックとは主に「命令の中を指すラベルを捜す」作業です。 - -c オプションを付けると、この作業を行いません。付ける必要はあり - ません。付けると命令の中を指すラベルが存在する場合、正常なソース - が出力されない場合があります。 +  ラベルチェックとは主に「命令の中を指すラベルを捜す」作業です。-c オプシ + ョンを付けると、この作業を行いません。付ける必要はありません。付けると命令 + の中を指すラベルが存在する場合、正常なソースが出力されない場合があります。 -l -  プログラム領域が見つからなくなるまで何度も捜すことをしない。 +  プログラム領域が見つからなくなるまで何度も捜すことをしない。 -  このプログラムではデータ領域からプログラム領域が見つからなくな - るまで捜しますが、-l オプションをつけると一度しか捜しません。付 - ける必要はありません。 +  このプログラムではデータ領域からプログラム領域が見つからなくなるまで捜し + ますが、-l オプションをつけると一度しか捜しません。付ける必要はありませ + ん。 -p -  データ領域中のプログラム領域を判別しない。 +  データ領域中のプログラム領域を判別しない。 -  一通り解析してプログラム領域とデータ(と思われる)領域に分けます - が、データ(と思われる)領域の中にもプログラム領域がたいてい埋もれ - ています。-p オプションを付けると、データ(と思われる)領域からプ - ログラム領域を捜しません。付ける必要はまずありません。 +  一通り解析してプログラム領域とデータ(と思われる)領域に分けますが、データ + (と思われる)領域の中にもプログラム領域がたいてい埋もれています。-p オプシ + ョンを付けると、データ(と思われる)領域からプログラム領域を捜しません。付け + る必要はまずありません。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - テーブル記述ファイルについて + テーブル記述ファイルについて -──────────────────────────────────── +─────────────────────────────────────── - dis はリラティブオフセットテーブルを除き、自動ではテーブルを認識するこ -とは出来ません。そこで、テーブルの形をユーザーが記述して dis に教えてや -ろうというのがテーブル記述ファイルです。詳細は tablefile.5 及び -table.doc を参照して下さい(後者には間違いがいくつかあります)。 + dis はリラティブオフセットテーブルを除き、自動ではテーブルを認識することはで +きません。そこで、テーブルの形をユーザーが記述して dis に教えてやろうというの +がテーブル記述ファイルです。詳細は tablefile.txt 及び table.txt を参照して下さ +い(後者には間違いがいくつかあります)。 - dis version 2.83 以降では、限定的ながらもテーブルで浮動小数点を出力で -きます。使用できるのは以下の識別子です。 + dis version 2.83 以降では、限定的ながらもテーブルで浮動小数点を出力できま +す。使用できるのは以下の識別子です。 - dc.s (.dc.s) - dc.d (.dc.d) - dc.x (.dc.x) - dc.p (.dc.p) + dc.s (.dc.s) + dc.d (.dc.d) + dc.x (.dc.x) + dc.p (.dc.p) - dc.?[ 式 ] という形式も可能ですが、オペランド表現式は一切指定できませ -ん。これらの命令は単に pc のデータを出力します。 + dc.?[ 式 ] という形式も可能ですが、オペランド表現式は一切指定できません。こ +れらの命令は単に pc のデータを出力します。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ラベルファイルについて + ラベルファイルについて -──────────────────────────────────── +─────────────────────────────────────── - ラベルファイルは、各ラベル(=アドレス)の属性、シンボルネームを示すもの -で、-e オプションで出力させることが出来ます。ラベルファイルを書き換えて、 -次に -g オプションで、書き換えたラベルファイルを読み込ませることによって -ラベルファイルに従ったソースファイルを生成することが出来ます。 + ラベルファイルは、各ラベル(=アドレス)の属性、シンボルネームを示すもので、-e +オプションで出力させることが出来ます。ラベルファイルを書き換えて、次に -g オプ +ションで、書き換えたラベルファイルを読み込ませることによってラベルファイルに従 +ったソースファイルを生成することができます。 - なお、ラベルの属性を変える、ラベルを増やすのは構いませんが、減らすと正 -常なソースが出来ないと思います。そのラベルはどこかで参照されていると思わ -れるからです。 + なお、ラベルの属性を変える、ラベルを増やすのは構いませんが、減らすと正常なソ +ースが出来ないと思います。そのラベルはどこかで参照されていると思われるからで +す。 - ラベルファイルを妙な風に書き換えると、dis の動作が変になるかも知れませ -ん。ご注意下さい。 + ラベルファイルを妙な風に書き換えると、dis の動作が変になるかも知れません。ご +注意下さい。 - ラベルファイルのファイル名は -e/-g オプションの後に特に指定しなければ、 -実行ファイル名の拡張子を .lab に変えたものになります。-e/-g オプションは -同時に使用出来ます。 + ラベルファイルのファイル名は -e/-g オプションの後に特に指定しなければ、実行 +ファイル名の拡張子を .lab に変えたものになります。-e/-g オプションは同時に使用 +できます。 - ラベルファイルの書式については labelfile.5 を参照して下さい。 + ラベルファイルの書式については labelfile.txt を参照して下さい。 ●備考 - D の後に F という文字が付く場合があります。これは「絶対」を意味してい -て、D?F なら「絶対にデータ」ということです。つまり、そこから解析してみて -プログラムと見なし得なかったことを示します。 + D の後に F という文字が付く場合があります。これは「絶対」を意味していて、D?F +なら「絶対にデータ」ということです。つまり、そこから解析してみてプログラムと見 +なし得なかったことを示します。 - ユーザーが書き加える/書き変える属性文字列で、「絶対にデータ」と言うの -なら f を書いて下さい。f を書かないと、DIS はそこから「プログラムちゃう -か?」と思ってしまうかも知れません。反対に単なる解析のつっかかりを与える -のであれば、du のみ書いて下さい。dis はそこから「プログラムちゃうか?」 -と疑って調べてくれます。dis の出力した F は別に消しても問題ない筈です。 + ユーザーが書き加える/書き変える属性文字列で、「絶対にデータ」と言うのなら f +を書いて下さい。f を書かないと、DIS はそこから「プログラムちゃうか?」と思って +しまうかも知れません。反対に単なる解析のつっかかりを与えるのであれば、du のみ +書いて下さい。dis はそこから「プログラムちゃうか?」と疑って調べてくれます。 +dis の出力した F は別に消しても問題ない筈です。 - (重要)dis が出力する属性文字列は大文字ですが、ユーザーの書き加える属性 -文字列は全て小文字でなければなりません。小文字にしないと、例えば P の場 -合、そのアドレスからは解析済みと見なしてしまいます。小文字にするとそこか -ら解析するので、うまくいきます。 D の場合も同様です。 + (重要) dis が出力する属性文字列は大文字ですが、ユーザーの書き加える属性文字 +列は全て小文字でなければなりません。小文字にしないと、例えば P の場合、そのア +ドレスからは解析済みと見なしてしまいます。小文字にするとそこから解析するので、 +うまくいきます。 D の場合も同様です。 - 属性文字列の DZ は、.z ファイルや IOCS ROM 等でロングワードのテーブル -をユーザーが指定するためにあります(.x ファイルではロングワードのテーブル -は自動的に認識します)。後の "IOCS ROM をソースジェネレートする方法" を参 -考にして下さい。(注)この機能はテーブル記述ファイルで代用出来ます。 + 属性文字列の DZ は、.z ファイルや IOCS ROM 等でロングワードのテーブルをユー +ザーが指定するためにあります(.x ファイルではロングワードのテーブルは自動的に認 +識します)。後の "IOCS ROM をソースジェネレートする方法" を参考にして下さい。 +(注) この機能はテーブル記述ファイルで代用できます。 - ラベルファイル中のシンボル名を変更すれば、出力ソースの中でも変更されま -す。シンボル名を新たに書き加えれば、そのアドレスは全てシンボル名に置換さ -れます。シンボル名の最初が * ならばコメントと見なされてシンボル名にはな -りません。 + ラベルファイル中のシンボル名を変更すれば、出力ソースの中でも変更されます。シ +ンボル名を新たに書き加えれば、そのアドレスは全てシンボル名に置換されます。シン +ボル名の最初が * ならばコメントと見なされてシンボル名にはなりません。  C で doslib や iocslib 等を使うと、シンボルテーブルが残っていた場合、 -doscall.mac や iocscall.mac に定義されているのと同名のラベルが出てくると -きがよくあります(アセンブルすると redifinition error がでる)。そういうと -きはラベルファイルを出力して、同名のラベルを適当な違うラベル名に書き換え -れば良い筈です。 +doscall.mac や iocscall.mac に定義されているのと同名のラベルが出てくるときがよ +くあります(アセンブルすると redifinition error がでる)。そういうときはラベルフ +ァイルを出力して、同名のラベルを適当な違うラベル名に書き換えれば良い筈です。 ●リラティブオフセットテーブル - リロケータブルなプログラムでテーブルを作る時に良く用いられます。テーブ -ルにはテーブルの先頭番地からのオフセットが符号付1ワードで書かれます。分 -岐テーブルに良く用いられますが、データテーブルにももちろん使用可能です。 -gcc がテーブルを作るときは大抵このようになっているようです。 + リロケータブルなプログラムでテーブルを作る時に良く用いられます。テーブルには +テーブルの先頭番地からのオフセットが符号付1ワードで書かれます。分岐テーブルに +良く用いられますが、データテーブルにももちろん使用可能です。GCC がテーブルを作 +るときは大抵このようになっているようです。 -(例) - add.w d0,d0 ;*2 - move.w (table,pc,d0.w),d0 - jmp (table,pc,d0.w) -table: - .dc.w label1-table - .dc.w label2-table - .dc.w label3-table - .dc.w label4-table + (例) + add.w d0,d0 ;*2 + move.w (table,pc,d0.w),d0 + jmp (table,pc,d0.w) + table: + .dc.w label1-table + .dc.w label2-table + .dc.w label3-table + .dc.w label4-table - DIS は大抵のリラティブオフセットテーブルを自動的に認識しますが、少し手 -を抜いているので、認識しなければラベルファイルを書き変えなければならない -場合があるでしょう。データテーブルに使用した場合は自動的には全く認識でき -ません。 + DIS は大抵のリラティブオフセットテーブルを自動的に認識しますが、少し手を抜い +ているので、認識しなければラベルファイルを書き変えなければならない場合があるで +しょう。データテーブルに使用した場合は自動的には全く認識できません。 ● IOCS ROM をソースジェネレートする方法 - まず、db.x で IOCS ROM のイメージファイルを作ります(ROM は 87年05月07 -日 version を基にしています)。 + まず、db.x で IOCS ROM のイメージファイルを作ります(ROM は 1987年05月07日 +version を基にしています)。 - db.x - -wromimage,ff0000 ffdcff #この ffdcff はかなりいい加減 - -q + db.x + -wromimage,ff0000 ffdcff #この ffdcff はかなりいい加減 + -q  とりあえず、ソースジェネレートします。 - dis romimage rom.s -zff0000,ff0010 -e -h -q + dis romimage rom.s -zff0000,ff0010 -e -h -q - IOCS ROM の中の IOCS call のテーブルを dis に認識させるため、 -romimage.lab を書き変えます。 + IOCS ROM の中の IOCS call のテーブルを dis に認識させるため、romimage.lab を +書き変えます。 - ff1b32 DUF -> ff1b32 dzf #この f はいまのところ意味が無い + ff1b32 DUF -> ff1b32 dzf #この f はいまのところ意味が無い - また、次のところをプログラムと見なしてしまうので、そこも書き変えます。 -ff05ca が P でなければ書き変える必要はありません。 + また、次のところをプログラムと見なしてしまうので、そこも書き変えます。ff05ca +が P でなければ書き変える必要はありません。 - ff05ca P -> ff05ca duf #この f は絶対必要 + ff05ca P -> ff05ca duf #この f は絶対必要  もういちどソースジェネレートします(-e は付けなくても良い)。 - dis romimage rom.s -zff0000,ff0010 -g -e -h -q + dis romimage rom.s -zff0000,ff0010 -g -e -h -q - これで rom.s が出来ました。dis で簡単に出来るのはここまででしょう。-e -オプションを付けていれば、ラベルファイルが更新されている筈ですので、そこ -からまたラベルファイルに変更を加えてソースジェネレートすることも出来ます。 + これで rom.s が出来ました。dis で簡単にできるのはここまででしょう。-e オプシ +ョンを付けていれば、ラベルファイルが更新されているはずですので、そこからまたラ +ベルファイルに変更を加えてソースジェネレートすることもできます。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - プログラムの解析について + プログラムの解析について -──────────────────────────────────── +─────────────────────────────────────── ●未使用レジスタフィールド - mulu.l ,Dn - muls.l ,Dn - ftst.x FPn + mulu.l ,Dn + muls.l ,Dn + ftst.x FPn - これらの命令コードには、レジスタを指定する為のフィールドが二つあるので -すが、片方のみ使用して、もう片方は未使用となっています。 + これらの命令コードには、レジスタを指定する為のフィールドが二つあるのですが、 +片方のみ使用して、もう片方は未使用となっています。  mulu.l ,Dn の第二ワードは下のようなコードです。 - 0???000000000??? - | | - | +--- 未使用 - +--------------- レジスタ番号(Dn) + 0???000000000??? + | | + | +--- 未使用 + +--------------- レジスタ番号(Dn) - この未使用なフィールド(本来レジスタペア用のもの)は、巷のアセンブラでは -レジスタ番号と同じ数値が入るようです。例えば、mulu.l ,d5 ならば、第 -二ワードは、 - 0101000000000101 - ~~~ ~~~ + この未使用なフィールド(本来レジスタペア用のもの)は、巷のアセンブラではレジス +タ番号と同じ数値が入るようです。例えば、mulu.l ,d5 ならば、第二ワードは、 + 0101000000000101 + ~~~ ~~~ となるようです。  ftst.x FPn の第二ワードは - 000???_???0111010 - | | - | +--------- 未使用 - +------------- レジスタ番号(FPn) + 000???_???0111010 + | | + | +--------- 未使用 + +------------- レジスタ番号(FPn) - こちらの未使用フィールドは has や fas,db などでは 0 が入るようですが、 -libc のライブラリの中には何故かレジスタ番号と同じ数値が入ったものもある -ようです。結局、例えば ftst.x fp5 の第二ワードは、 - 000101_0000111010 (has,fas,db) - ~~~ ~~~ + こちらの未使用フィールドは HAS や fas,db などでは 0 が入るようですが、libc +のライブラリの中には何故かレジスタ番号と同じ数値が入ったものもあるようです。結 +局、例えば ftst.x fp5 の第二ワードは、 + 000101_0000111010 (HAS,fas,db) + ~~~ ~~~ もしくは、 - 000101_1010111010 (??? libc のライブラリ内に見られる) - ~~~ ~~~ + 000101_1010111010 (??? libc のライブラリ内に見られる) + ~~~ ~~~ となります。 - これらより、(素直に)アセンブルされたこれらのコードの未使用レジスタフィ -ールドは - ・もう片方のレジスタフィールドと同じ値 - ・0 + これらより、(素直に)アセンブルされたこれらのコードの未使用レジスタフィールド +は + ・もう片方のレジスタフィールドと同じ値 + ・0 の、どちらかであると思われます。 - さて、この未定義レジスタフィールドを上の2つのどちらかであろうと決めつ -け、それ以外であれば未定義命令としてしまえば、データ領域とプログラム領域 -の判別に役立ちます。そのためのオプションが -R オプションです。 + さて、この未定義レジスタフィールドを上の2つのどちらかであろうと決めつけ、そ +れ以外であれば未定義命令としてしまえば、データ領域とプログラム領域の判別に役立 +ちます。そのためのオプションが -R オプションです。 + + -R に続く数値の第0ビットが1ならば、 これらの命令について上記のようなチェック +を行い、おかしければデータ領域と見なします。 + - -R に続く数値の第0 bit が1ならば、mul[us].l ,Dn / ftst.x FPn につ -いて上記のようなチェックを行い、おかしければデータ領域と見なします。 +●未使用レジスタフィールド(cinva, cpusha) + + CINV、CPUSH 命令にはアドレスレジスタを指定する為のフィールドがありますが、 +cinv[lp]、cpush[lp] 命令でのみ使用され、cinva、cpusha 命令では未使用となってい +ます。 + + この未使用フィールドには通常0が入るため、前述の ftst.x FPn などと同様のチェ +ックが行えます。 + + オプションの指定も共通で、-R に続く数値の第0ビットが1ならば、 これらの命令に +ついてチェックを行い、おかしければデータ領域と見なします。 ●サプレスされたレジスタ - 拡張アドレッシングは、ベースディスプレースメント、アウタディスプレース -メント、ベースレジスタ、インデックスレジスタを任意にサプレス(省略)するこ -とが出来ます サプレスされたレジスタについては、レジスタ名の前に'z'を付け -ることで表現します。 + 拡張アドレッシングは、ベースディスプレースメント、アウタディスプレースメン +ト、ベースレジスタ、インデックスレジスタを任意にサプレス(省略)することができま +す。サプレスされたレジスタについては、レジスタ名の前に'z'を付けることで表現し +ます。 -例: asm move.l ([label1],label2),([label3,a1],label4) - dis→ move.l ([label1,za0,zd0.w],label2),([label3,a1,zd0.w],label4) + (例) + asm move.l ([label1],label2),([label3,a1],label4) + dis → move.l ([label1,za0,zd0.w],label2),([label3,a1,zd0.w],label4) - asm move.l (d0.l),d1 - dis→ move.l (za0,d0.l),d1 + asm move.l (d0.l),d1 + dis → move.l (za0,d0.l),d1 - ここでも、素直にアセンブルされたコードは、サプレスされたレジスタ番号に -0以外を指定したり、スケーリングやロングワードサイズの指定をしたりするこ -とはないであろうという経験的憶測のもとに、-R スイッチでそれについてのチ -ェックの有無を指定できます。 + ここでも、素直にアセンブルされたコードは、サプレスされたレジスタ番号に0以外 +を指定したり、スケーリングやロングワードサイズの指定をしたりすることはないであ +ろうという経験的憶測のもとに、-R スイッチでそれについてのチェックの有無を指定 +できます。  -R に続く数値の、 - 第1 bit が1ならば、サプレスされたレジスタ番号が 0 以外な場合、未定義命 -令としてデータ領域と見なします。 + 第1ビットが1ならば、サプレスされたレジスタ番号が0以外な場合、未定義命令とし +てデータ領域と見なします。 - 第2 bit が1ならば、サプレスされたインデックスレジスタに対してスケーリ -ングが指定されている場合、未定義命令と見なします。 + 第2ビットが1ならば、サプレスされたインデックスレジスタに対してスケーリングが +指定されている場合、未定義命令と見なします。 - 第3 bit が1ならば、サプレスされたインデックスレジスタに対するサイズ指 -定がロングワード(.l)ならば、未定義命令と見なします。 + 第3ビットが1ならば、サプレスされたインデックスレジスタに対するサイズ指定がロ +ングワード(.l)ならば、未定義命令と見なします。 - これらの3つが指定された場合は、サプレスされたインデックスレジスタは表 -記そのものを省略して出力します。まとめると以下のようになります。 + これらの3つが指定された場合は、サプレスされたインデックスレジスタは表記その +ものを省略して出力します。まとめると以下のようになります。 ・-R 14 (2+4+8=14) な場合 - 命令 code 命令の解釈 dis の出力 + 命令 code 命令の解釈 dis の出力 -([label1,za0,zd0.w],label2) 有効 ([label1,za0],label2) -([label1,za0,zd0.w*2],label2) 無効(scaling) データ領域として出力 -([label1,za0,zd0.l],label2) 無効(size) データ領域として出力 + ([label1,za0,zd0.w],label2) 有効 ([label1,za0],label2) + ([label1,za0,zd0.w*2],label2) 無効(scaling) データ領域として出力 + ([label1,za0,zd0.l],label2) 無効(size) データ領域として出力  このようにインデックスレジスタは表記が省略されます。 ・どれも指定しなかった場合 -([label1,za0,zd0.w],label2) 有効 ([label1,za0,zd0.w],label2) -([label1,za0,zd0.w*2],label2) 有効 ([label1,za0,zd0.w*2],label2) -([label1,za0,zd0.l],label2) 有効 ([label1,za0,zd0.l],label2) + ([label1,za0,zd0.w],label2) 有効 ([label1,za0,zd0.w],label2) + ([label1,za0,zd0.w*2],label2) 有効 ([label1,za0,zd0.w*2],label2) + ([label1,za0,zd0.l],label2) 有効 ([label1,za0,zd0.l],label2)  このよーなひねくれた(^^;)表現で出力します。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 備考 + ソースコードの再現性 -──────────────────────────────────── +─────────────────────────────────────── -● dis の生成したソースファイルに関して + アセンブルしてリンクした後、fc などのバイナリファイル比較ツールで比べてみる +ことをお勧めします。 + + dis の制限またはオプション指定により違いが出ることがあります。それ以外で違い +があれば、それは dis のバグです。作者に報告して下さい。 + + +●シンボルテーブル + + シンボルテーブルは -s1 オプションを指定するよりも -s2 を指定した方が再現性が +高くなりますが、それでも完全には再現できないため違いが生じることがあります。 + + +●ソースコードデバッガ情報 + + ソースコードデバッガ情報は全く再現できません。 + + +●ワードサイズの再配置情報 + + 実行ファイルの再配置情報は普通ロングワード単位での処理を行いますが、実はワー +ド単位で処理を行う形式も用意されています。しかし、dis はそのようなワード単位の +再配置情報には対応していません。一応通常のロングワードサイズのそれと同じように +解釈し、また、最悪の場合でもアドレスエラーにはならないようにはしています。現在 +のところワード単位の再配置情報を処理できるのは Human68k の DOS _EXEC ファンク +ションコールのコードだけで、アセンブラやリンカに対応しているものがないので、 +dis が対応していなくても特に問題はないと思います。 + + +●不定バイト(-f オプション指定時) + + 不定バイトが $00 または $ff でない場合、それをアセンブラに指定する方法がない +ため再現できません。 + + +●未使用レジスタフィールド(-R 第0ビット=0) + + 未使用レジスタフィールドが0でない場合、それをアセンブラに指定する方法がない +ため再現できません。 + + +●アドレッシングモード (bd,An,Xn), (bd,PC,Xn) + + 実効アドレスがインデックス付きアドレス・レジスタ間接(ベース・ディスプレース +メント)モードでベース・ディスプレースメントが省略されている場合、インデックス +付きアドレス・レジスタ間接(8ビット・ディスプレースメント)モードとして出力され +ます。ベースレジスタが PC の場合も同様です。 - dis の生成したソースファイルの著作権は、元の実行ファイルの著作者にある -と思われるので取り扱いには十分注意して下さい。 + ベース・ディスプレースメントの省略を HAS 系統のアセンブラに指定する方法がな +いため再現できません。 + (例) + .dc $3030,$0000 ;move ($00,a0,d0.w),d0 + .dc $3030,$0110 ;move ([BD省略],a0,d0.w),d0 + .dc $303b,$0000 ;move ($00,pc,d0.w),d0 + .dc $303b,$0110 ;move ([BD省略],pc,d0.w),d0 + ↓ + move (a0,d0.w),d0 + move (a0,d0.w),d0 + move (Lxxxxxx+2,pc,d0.w),d0 + move (pc,d0.w),d0 -●忠実度 - アセンブルしてリンクした後、fc で比べてみることをお勧めします。シンボ -ルテーブルが残っていない限り違いはない筈です(dis はシンボルテーブルは完 -全には再現出来ません)。また、ソースコードデバッガ情報は全く再現出来ませ -ん。上記以外で違いがあれば、それは dis のバグです。作者に報告して下さい。 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + 備考 + +─────────────────────────────────────── + +● dis の生成したソースファイルに関して + + dis の生成したソースファイルの著作権は、元の実行ファイルの著作者にあると思わ +れるので取り扱いには十分注意して下さい。 ●バインドファイルについて - 実行ファイルがバインドされている場合、警告を出力して終了します。ソース -ジェネレートするためには unbind でバインドファイルを展開して下さい。 + 実行ファイルがバインドされている場合、警告を出力して終了します。ソースジェネ +レートするためには unbind でバインドファイルを展開して下さい。 ●スタックオーバーフロー - dis は関数の再帰呼び出しを多用した解析処理を行いますが、その途中でスタ -ックが足りなくなった場合は「libc: stack overflow.」と表示して強制終了し -ます。オプションに -+-s:524288 などとやってみて下さい(デフォルトは 256 -KB です)。 + dis は関数の再帰呼び出しを多用した解析処理を行いますが、その途中でスタックが +足りなくなった場合は「libc: stack overflow.」(X680x0 版の実行ファイルの場合)と +表示して強制終了します。オプションに -+-s:524288 などとやってみて下さい(デフォ +ルトは 256KB です)。 ●特殊な状況 - 素直にプログラムとして認識できない実行ファイルの場合、「xxxxxx : PC が -有効なセクションを外れた」というメッセージが繰り返し表示されて先に進まな -いように見えることがあります。そのような場合でも、無限ループにはなってい -ない筈なので、しばらくの間待ってみて下さい。dis が気の済むまで出力した後、 -正常に終了すると思います。 + 素直にプログラムとして認識できない実行ファイルの場合、「xxxxxx : PC が有効な +セクションを外れた」というメッセージが繰り返し表示されて先に進まないように見え +ることがあります。そのような場合でも、無限ループにはなっていないはずなので、し +ばらくの間待ってみて下さい。dis が気の済むまで出力した後、正常に終了すると思い +ます。 - もし長時間待ってみても終了しないようなら、それは dis の不具合です。サ -ポート担当者に報告して下さい。 + もし長時間待ってみても終了しないようなら、それは dis の不具合です。サポート +担当者に報告して下さい。 ●浮動小数点 - 拡張精度浮動小数点を実数表記で出力する場合は、大量の浮動小数点演算を行 -っているので非常に処理時間が掛かります。演算は常にソフトウェアでエミュレ -ートしているので、FPU を使用できる環境であってもあまり速くはなりません。 + 拡張精度浮動小数点を実数表記で出力する場合は、大量の浮動小数点演算を行ってい +るので非常に処理時間が掛かります。演算は常にソフトウェアでエミュレートしている +ので、FPU を使用できる環境であってもあまり速くはなりません。 - 処理の遅さに我慢できないようであれば、--inreal オプションを指定して全 -て内部表記で出力するようにして下さい。 + 処理の遅さに我慢できないようであれば、--inreal オプションを指定して全て内部 +表記で出力するようにして下さい。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 仕様(メモとも言う) + 仕様(メモとも言う) -──────────────────────────────────── +─────────────────────────────────────── ●対応プロセッサ - 68000/68008/68010/68020/68030/68040/68060 - 68881/68882 - 68040 内蔵 FPU - 68060 内蔵 FPU - 68851 - 68030 内蔵 MMU - 68040 内蔵 MMU - 68060 内蔵 MMU - 040FPSP - 060ISP/060FPSP - CPU32 + 68000/68008/68010/68020/68030/68040/68060 + 68881/68882 + 68040 内蔵 FPU + 68060 内蔵 FPU + 68851 + 68030 内蔵 MMU + 68040 内蔵 MMU + 68060 内蔵 MMU + 040FPSP + 060ISP/060FPSP + CPU32 - ※-m68008 指定時は -m68000 が指定されたものとして扱われます。ま - た、Target MPU に表示されることはありません。-mcpu32 は CPU32 - の追加命令を認識するだけで、アドレッシングモード等は -m680*0 - の指定が採用されます。こちらも Target MPU には表示されません。 + ※-m68008 指定時は -m68000 が指定されたものとして扱われます。また、Target + MPU に表示されることはありません。-mcpu32 は CPU32 の追加命令を認識する + だけで、アドレッシングモード等は -m680*0 の指定が採用されます。こちらも + Target MPU には表示されません。 ●実行形式の判別 - 指定されたファイルがどの種類の実行ファイルかの判別は以下の順で行われる。 + 指定されたファイルがどの種類の実行ファイルかの判別は以下の順で行われます。 - 1) -z オプション指定時 R形式 - 2) *.r 〃 - 3) ファイルの先頭 2 バイトが 'HU' X形式 - 4) 〃 0x601a Z形式 - 5) 上記条件に一致しない エラー + 1) -z オプション指定時 R形式 + 2) *.r R形式 + 3) ファイルの先頭2バイトが 'HU' X形式 + 4) ファイルの先頭2バイトが 0x601a Z形式 + 5) 上記条件に一致しない エラー ●参照されないラベル @@ -1243,221 +1336,177 @@ KB です)。  C コンパイラの出力で、 - static char ary[100]; - int index, a = ary[ index - 10 ]; + static char ary[100]; + int index, a = ary[ index - 10 ]; -などの時、gcc などは +などの時、GCC などは - lea.l (_ary-10),a0 - move.b (a0,d0.l),d0 ;d0 = index; - ext.w d0 - ext.l d0 + lea.l (_ary-10),a0 + move.b (a0,d0.l),d0 ;d0 = index; + ext.w d0 + ext.l d0 -のようなコードを出力しますが、dis はそんなことは知らずに、_ary-10 がどこ -にあろうとそこにラベルを振ろうとします。たまたま _ary-10 がプログラムの -途中だったりすると、命令の中を指すラベルのように見えます。このとき -k オ -プション等を指定しているとそこがデータの塊になったりします。-k オプショ -ンを用いる時は、なるべく -k オプションなしで出力したファイルと比較して、 -ユーザーが適宜選択するようにして下さい。 +のようなコードを出力しますが、dis はそんなことは知らずに、_ary-10 がどこにあろ +うとそこにラベルを振ろうとします。たまたま _ary-10 がプログラムの途中だったり +すると、命令の中を指すラベルのように見えます。このとき -k オプション等を指定し +ているとそこがデータの塊になったりします。-k オプションを用いる時は、なるべく +-k オプションなしで出力したファイルと比較して、ユーザーが適宜選択するようにし +て下さい。 - また、gcc でコンパイルされたものはデータとプログラムが入り混じっている -ので、データをプログラムと誤認することがしばしばあります。 + また、GCC でコンパイルされたものはデータとプログラムが入り混じっているので、 +データをプログラムと誤認することがしばしばあります。 ●dis の限界 - データ領域がたまたまプログラム領域としても認識できる値の場合、周辺を巻 -き込んでプログラム領域にしてしまうことがあります。具体的には + データ領域がたまたまプログラム領域としても認識できる値の場合、周辺を巻き込ん +でプログラム領域にしてしまうことがあります。具体的には - lea (crlf,pc),a0 - bsr foo - rts -crlf: .dc.b 13,10 - .even -foo: - nop - rts + lea (crlf,pc),a0 + bsr foo + rts + crlf: .dc.b 13,10 + .even + foo: + nop + rts というコードを -L000000: - lea (L000008,pc),a0 - bsr L000008+2 - rts + L000000: + lea (L000008,pc),a0 + bsr L000008+2 + rts -L000008: - movep ($4e71,a2),d6 - rts + L000008: + movep ($4e71,a2),d6 + rts -と逆アセンブルしてしまいます。この時、foo は命令の中を指すラベルとして -crlf+2 に置換されています。これは、「crlf がデータで foo がプログラム」 -なのか「crlf がプログラムで foo は命令中を指すラベル」なのか dis には判 -別できない為に起こります。これもまた dis の限界ですが、この場合はラベル -ファイルで +と逆アセンブルしてしまいます。この時、foo は命令の中を指すラベルとして crlf+2 +に置換されています。これは、「crlf がデータで foo がプログラム」なのか「crlf +がプログラムで foo は命令中を指すラベル」なのか dis には判別できないために起こ +ります。これもまた dis の限界ですが、この場合はラベルファイルで -000008 dsf -00000a pf +000008 dsf +00000a pf と指定すれば期待通りに逆アセンブルされます。 -●ワードサイズの再配置情報 - - 実行ファイルの再配置情報は普通ロングワード単位での処理を行いますが、実 -はワード単位で処理を行う形式も用意されています。しかし、dis はそのような -ワード単位の再配置情報には対応していません。一応通常のロングワードサイズ -のそれと同じように解釈し、また、最悪の場合でもアドレスエラーにはならない -ようにはしています。現在のところワード単位の再配置情報を処理できるのは -Human68k の DOS _EXEC ファンクションコールのコードだけで、アセンブラやリ -ンカに対応しているものがないので、dis が対応していなくても特に問題はない -と思います。 - - ●その他の細かい仕様 - 解析中の文字列の表示は標準エラー出力へ出力されています。-q option を指 -定すると処理が速くなります。テーブルを多用している場合は -q1 を指定しま -しょう。 + 解析中の文字列の表示は標準エラー出力へ出力されています。-q option を指定する +と処理が速くなります。テーブルを多用している場合は -q1 を指定しましょう。 - 以下のファンクションコールがリターンしないと言うことは(gcc でいう関数 -の volatile 宣言...)Hard Coding してあります。 - DOS EXIT - DOS EXIT2 - DOS KEEPPR - SXCALL ExitToShell + 以下のファンクションコールがリターンしないということは(GCC でいう関数の +noreturn 属性)、ハードコーディングしてあります。 + DOS _EXIT + DOS _EXIT2 + DOS _KEEPPR + DOS _KILLPR + SXCALL ExitToShell  64ビット整数(.q)は倍精度実数の内部表現と同じ形式で出力されます。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 用語解説 + 用語解説 -──────────────────────────────────── +─────────────────────────────────────── 実行ファイル -  アセンブラソースを生成しようとしているファイルで、.x、.r、.z - 形式実行ファイル、単なるバイナリファイルのいずれか。 +  アセンブラソースを生成しようとしているファイルで、.x、.r、.z 形式実行フ + ァイル、単なるバイナリファイルのいずれか。 命令の中を指すラベル -  dis がサポートしている命令の中を指すラベルとは、下のようなもの - です。高速化や省メモリを狙ったプログラムや手抜きプログラム等で用 - いられる手法です(プログラムが分りにくくなるので、そのようなコー - ディングは勧めません)。 +  dis がサポートしている命令の中を指すラベルとは、下のようなものです。高速 + 化や省メモリを狙ったプログラムや手抜きプログラム等で用いられる手法です(プ + ログラムが分りにくくなるので、そのようなコーディングは勧めません)。 - label: - move.w #$0000,d0 - ................. - move.w d1,(label+$000002) + label: + move.w #$0000,d0 + ................. + move.w d1,(label+$000002) -  この場合、dis は下のようなソースを出力します。 +  この場合、dis は下のようなソースを出力します。 - L??????: - move.w #$0000,d0 - ................. - move.w d1,(L??????+2) + L??????: + move.w #$0000,d0 + ................. + move.w d1,(L??????+2) -  少し違いますが、as.x の中では、命令のイミディエイトオペランド - の中へジャンプすると言うテクニックが使われていて、その場合も命 - 令の中を指すラベルが生成されます。 +  少し違いますが、as.x の中では、命令のイミディエイトオペランドの中へジャ + ンプすると言うテクニックが使われていて、その場合も命令の中を指すラベルが生 + 成されます。 不定バイト -  オペレーションサイズがバイト(.b)の命令で、かつソースオペランド - がイミディエイトデータの場合、命令の第3バイトは定義されていませ - ん(不定バイト)。しかし、as.x を使っている限りこの第3バイトは - $00 か $ff のどちらかのようなので、通常 dis はここをチェックして - $00 か $ff のどちらでもなければ未定義命令にしてしまいます。 as.x - では、ソース中でイミディエイトデータを正として扱っているなら不定 - バイトは $00、負なら $ff になるようです。 +  オペレーションサイズがバイト(.b)の命令で、かつソースオペランドがイミディ + エイトデータの場合、命令の第3バイトは定義されていません(不定バイト)。しか + し、as.x を使っている限りこの第3バイトは $00 か $ff のどちらかのようなの + で、通常 dis はここをチェックして $00 か $ff のどちらでもなければ未定義命 + 令にしてしまいます。as.x では、ソース中でイミディエイトデータを正として扱 + っているなら不定バイトは $00、負なら $ff になるようです。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 謝辞 + 謝辞 -──────────────────────────────────── +─────────────────────────────────────── - dis を生み出だした K.Abe 氏と、それを成長させた R.ShimiZu 氏に感謝しま -す。 + dis を生み出だした K.Abe 氏と、それを成長させた R.ShimiZu 氏に感謝します。 - 無限ループのバグを報告し、確実に再現する方法(重要)を提供して下さった -Schmidt 氏に感謝します。 + 無限ループのバグを報告し、確実に再現する方法(重要)を提供して下さった Schmidt +氏に感謝します。 - bf 命令のエンバグの報告と、絶対ショート/ロングアドレッシング表記の情報 -を下さった鎌田氏に感謝します。 + bf 命令のエンバグの報告と、絶対ショート/ロングアドレッシング表記の情報を下さ +った鎌田氏に感謝します。 - XC ver 1.01 のインクルードファイルを送っていただいたラキッ!氏に感謝し -ます。 + XC ver 1.01 のインクルードファイルを送っていただいたラキッ!氏に感謝します。 - 奇数アドレスへの分岐とサブルーチンコール命令の直後の引数への対応は、松 -戸のロイヤルホストでひたすらオレンジジュースを待った三人の会話がきっかけ -で実現しました。 + 奇数アドレスへの分岐とサブルーチンコール命令の直後の引数への対応は、松戸のロ +イヤルホストでひたすらオレンジジュースを待った三人の会話がきっかけで実現しまし +た。 - FreeBSD クロス版のソース差分を送っていただき、ベータ版の動作試験にも協 -力していただいた M.Suzuki 氏に感謝します。 + FreeBSD クロス版のソース差分を送っていただき、ベータ版の動作試験にも協力して +いただいた M.Suzuki 氏に感謝します。 - CygWin への対応にあたって、RuRuRu 氏の Win32 移植版を参考にさせていた -だきました。 + CygWin への対応にあたって、RuRuRu 氏の Win32 移植版を参考にさせていただきま +した。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 開発環境 + 開発環境 -──────────────────────────────────── +─────────────────────────────────────── gcc version 2.6.3 (68k, Human68k, revision 5) - FSF / Charlie / KQ -HAS060 version 3.09+87+15[g2as] Y.Nakamura / M.Kamada / 立花 -HLK evolution version 3.01+14[g2lk] SALT / 立花 -GNU Make version 3.79 human68k-1.2 FSF (自分で移植版) -GNU Bison version 1.28 human68k-1.2 FSF (〃) -GNU diffutils version 2.7 human68k-1.3 FSF (〃) -MicroEMACS j1.43 (rel.5c7-beta4) Sharl 他 - -libc-1.2.20 Release Mimu Project C Library Group / 立花 -libgcc version x.xx patchlevel 7 FSF / Charlie / 立花 -libhdi ver2.9 (改) oo / 立花 -libhmem ver1.10b oo -libld (level 1) 立花 - -(敬称略) - - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - 参考文献 - -──────────────────────────────────── - -ぷにぐらま~ずまにゅある 第七版第二刷 立花@桑島技研 -C 言語による最新アルゴリズム事典 奥村晴彦, 技術評論社 -68000 プログラマーズハンドブック 宍倉幸則, 〃 -Inside X68000 堯野雅彦, SOFT BANK -X68030 Inside/Out 〃 , 〃 -プログラミング言語 C 第二版 B.W.カーニハン / D.M.リッチー - 石田晴久訳, 共立出版 -MC68030 ユーザーズ・マニュアル 日本モトローラ -M68000 FAMILY PROGRAMMER'S REFERENCE MANUAL - MOTOROLA - -has version 3.09 中村祐一 -HAS060 version 3.09+87 鎌田誠 -060turbo.sys version 0.54 〃 -README.DOC (060turbo.sys version 0.44) 〃 -dis.x version 2.78 patchlevel +04 Syo + FSF / Charlie / KQ +HAS060 version 3.09+87+15[g2as] Y.Nakamura / M.Kamada / 立花 +HLK evolution version 3.01+14[g2lk] SALT / 立花 +GNU Make version 3.79 human68k-1.2 FSF (自分で移植版) +GNU diffutils version 2.7 human68k-1.3 FSF (〃) +MicroEMACS j1.43 (rel.5c7-beta4) Sharl 他 + +libc-1.2.20 Release Mimu Project C Library Group / 立花 +libgcc version x.xx patchlevel 7 FSF / Charlie / 立花 +libhdi ver2.9 (改) oo / 立花 +libhmem ver1.10b oo +libld (level 1) 立花 (敬称略) -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - 連絡先 + 連絡先 -──────────────────────────────────── +─────────────────────────────────────── TcbnErik / 立花@桑島技研 https://github.com/kg68k/dis -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/docs/analysis.txt b/docs/analysis.txt new file mode 100644 index 0000000..26a384f --- /dev/null +++ b/docs/analysis.txt @@ -0,0 +1,62 @@ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + コード解析パターン + +─────────────────────────────────────── + + + 以下の命令パターンを相対オフセットテーブルとして検出する。 + + 最後の命令が JMP|JSR の場合は、テーブルの宛先は奇数アドレスに限られる。 + + *s はスケールファクタで*1。68020以降の場合は*2も受け付ける。 + + ADD Dm,Dm はコードを分かりやすくするために書いているだけで、解析対象ではない +(スケールファクタが2の場合はこの命令は不要)。 + + +・MOVE + JMP|JSR + + ADD Dm,Dm + MOVE (table,PC,Dm.[wl]*s),Dn + JMP|JSR (table,PC,Dn.w) + + +・LEA + MOVE + JMP|JSR + + ADD Dm,Dm + LEA (table,pc),An + MOVE (An,Dm.[wl]*s),Dn + JMP|JSR (An,Dn.w) + + +・LEA + MOVE + PEA + + ADD Dm,Dm + LEA (table,pc),An + MOVE (An,Dm.[wl]*s),Dn + PEA (An,Dn.w) + + +・LEA + ADDA + + ADD Dm,Dm + LEA (table,pc),An + ADDA (table,pc,Dm.w*s),An + + +・MOVE + LEA + + ADD Dm,Dm + MOVE (table,PC,Dm.[wl]*s),Dn + LEA (table,PC,Dn.w),An + + +・MOVE + PEA + + ADD Dm,Dm + MOVE (table,PC,Dm.[wl]*s),Dn + PEA (table,PC,Dn.w) + + +─────────────────────────────────────── diff --git a/docs/dis_option.txt b/docs/dis_option.txt deleted file mode 100644 index 7f86a06..0000000 --- a/docs/dis_option.txt +++ /dev/null @@ -1,404 +0,0 @@ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ソースコードジェネレータ オプション一覧 - -──────────────────────────────────── - --a[num] num 行ごとにアドレスをコメントで入れる - (num を省略すると5行ごと) - --b num 相対分岐命令のサイズの出力 - (0:自動 1:常に省略 2:常に付ける) - - 相対分岐命令のオペコードにサイズを付けるかどうかを指定し - ます. - - 通常(-b0 指定時)は、ショートブランチで届く距離をワードブ - ランチ、またはワードブランチで届く距離をロングブランチし - ている場合にサイズを付けます. - - なお、-b2 を指定しても fdbcc 命令には絶対にサイズが付き - ません(アセンブラの仕様によります). - --c ラベルチェックを行わない - - 命令の中を指すラベルを探さないようにします. 通常は指定す - る必要はありません. 指定した場合、正常なソースを出力でき - ない場合があります. - --d デバイスドライバの時に指定 - - デバイスヘッダの構造を認識します. デバイスドライバでなけ - れば指定しないで下さい. - --e[file] ラベルファイルの出力 - - ラベルファイルを出力します. ファイル名を省略した場合はソ - ースファイル名の拡張子を .lab に変更したファイル名で出力 - します. - --f バイト操作命令の不定バイトのチェック($00 or $ff ?)をしな - い - - 通常は、バイトサイズの即値の上位バイトは通常 $00 か $ff - であるので、それ以外であったら未定義命令と見なします(値 - が正なら$00、負なら$ffになります). - - このオプションを指定した場合はそのチェックを行ないません. - 指定した場合は再アセンブルしても同じコードにならない場合 - があります. - --g[file] ラベルファイルを読み込む - - ラベルファイルを読み込みます. ファイル名を省略した場合は - ソースファイル名の拡張子を .lab に変更したファイル名から - 読み込みます. - --h データ領域中の$4e75(rts)の次のアドレスに注目する - - データ領域中に$4e75(rts)を発見した場合、その次のアドレス - を何らかのラベル(大抵はプログラム)として認識します. - --i 分岐先で未定義命令があってもデータ領域と見なさない - - 通常は、未定義命令を含むサブルーチン(と思われるもの)に分 - 岐した場合は分岐元自体がデータ領域と見なします. このオプ - ションを指定すればそのチェックを行わずに無条件に命令と見 - なします. - --j アドレスエラーが起こるであろう命令を未定義命令と見なさな - い - - 通常は実行時にアドレスエラーが起こるであろう命令は未定義 - 命令と見なしますが、このオプションを指定した場合はそのチ - ェックを行ないません. - --k 命令の中を指すラベルはないものと見なす - - 命令の中を示すラベルが見つかった場合、そこは命令ではなく - データと解釈します. 元々命令の中を指すラベルがなければソ - ースの質が良くなる場合がありますが、そのようなラベルがあ - れば逆に悪くなります. - --l プログラム領域が見つからなくなるまで何度も捜すことをしな - い - - 通常はデータ領域からプログラム領域を見つからなくなるまで - 探しますが、このオプションを付けると一度しか探しません. - 付ける必要はありません. - --m 680x0 逆アセンブル対象のMPUを指定(x=[0],1-4,6) - - 逆アセンブルする命令セットを選択します. -m68040~68060 - 指定時は内蔵コプロセッサ・MMU 命令も使用可能になります. - - -m68000,68030 のように複数の MPU を指定すると、指定した - 全ての MPU の命令セットが同時に使用可能になります. また、 - -m680x0 を指定すると選択可能な全ての MPU の命令セットが - 採用されます. - --m 68851 68851命令を有効にする(-m68020 指定時のみ有効) - - 外付けMMU命令を逆アセンブル可能にします. - このオプションは -m680*0 オプションによってクリアされる - ので、それより後に指定して下さい. - --m 6888x[,ID] 有効なFPCPとそのIDを指定(68881/68882 ID=[1],2-7) - - -m68020~68030 を指定している場合に、外付けコプロセッサ - 命令を逆アセンブル可能にします. -m68881 と -m68882の機能 - は全く同じです. - - IDの指定を省略した場合は1と見なされます. - -m68881 -m68882,2 のように複数のIDを指定することも出来ま - す. - - このオプションは -m680*0 オプションによってクリアされる - ので、それより後に指定して下さい. - --n num 文字列として判定する最小の長さ. 0なら判定しない(初期値=3) - - 文字列として判定する最小のバイト数を指定します. 短い文字 - 列の判定に失敗する場合、または判定を行いたくない時に使用 - します. - --o num 文字列領域の桁数(1≦num≦80 初期値=60) - - 文字列領域を出力する際の、ソースファイルの一行あたりの桁 - 数を指定します. - --p データ領域中のプログラム領域を判別しない - - 通常は、一度データ領域と判定した場所からプログラム領域が - なかったか調べますが、このオプションを指定するとそれをし - ません. 付ける必要はありません. - --q[num] メッセージを出力しない - ([0]:通常 1:テーブルに関する情報も出力しない) - - 解析中/ファイル出力中のメッセージを表示しません. 指定す - ればその分処理が速くなります. - --r 文字列に16進数のコメントを付ける - --s[num] シンボルテーブルの出力([0]:しない 1:[通常] 2:全て) - - 外部定義シンボルを再現します. -s1 指定時は定数シンボルの - み、-s2 指定時はアドレス値も出力します. - --u[num] 未使用の A,F line trap を未定義命令と見なさない - (num=1 SX-Window 対応) - - A line trap や doscall.mac 及び fefunc.mac などで定義さ - れなかった F line trap を未定義命令と見なさないようにし - ます. - - -u1 指定時は環境変数 dis_sxmac に設定してある SX-Window - のファンクションコール定義ファイルを読み込み、DOSコール - 等と同様のマクロ出力を行ないます. - --v 単なる逆アセンブルリストの出力 - --w num データ領域の横バイト数(1≦num≦32 初期値=8) - - データ領域を出力する際の、ソースファイルの一行あたりのバ - イト数を指定します. - --x 実際のオペコードを16進数のコメントで付ける - --y 全てのデータ領域をプログラム領域でないか確かめることをし - ない - - 通常は、一度解析した後サイズの分らないデータがプログラム - でないか解析します. - - このオプションを指定すると、データの終わりがリターン命令・ - 分岐命令などである領域のみを解析します. プログラム領域を - データとして残すことが有りますが、逆にデータ領域をプログ - ラムにすることも無くなる可能性もあります. - --z base,exec 実行ファイルを base からのバイナリファイルとみなし、exec - から解析する - - アドレスに依存したバイナリ形式の実行ファイルを解析します. - 実行開始アドレスが分らない時は、ファイル先頭アドレスと同 - じ値を指定してみて下さい. - --A cmpi, movea 等を cmp, move 等にする - - ただし、演算先がデータレジスタの cmpi、ori、andi、subi、 - addi、eori は "i" なしの命令とオブジェクトコードが異なる - ので、そのままで出力されます. また、addi と subi で即値 - が 1 ~ 8 の場合、addq や subq に最適化されるのを防ぐ為、 - 即値にサイズが付きます. - --B bra の後でも改行する - - 通常は rts、rte、rtr、jmp、DOS _EXIT、_EXIT2、_KEEPPR、 - SXCALL __TSExit(ExitToShell)の後に一行空行を入れますが、 - このオプションを指定すると bra の後にも空行を入れます. - --C[num] ラベルの後のコロン - (0:付けない 1:全てに1つ [2]:通常 3:全てに2つ) - - ラベル定義行に付けるコロンの数を指定します. 通常は内部定 - 義(static)のラベルには一個(':')、外部定義(extern)のラベ - ルには二個('::')付きます. - - 内部定義か外部定義かの区別は、実行ファイルのシンボルテー - ブルにラベル定義が出力されているかどうかです. - --D データセクション中にもプログラムを認める - - データセクションに分岐するプログラムに対応します. そのよ - うなプログラムでは「pc が有効なセクションを外れた」と表 - 示されるので、このオプションを指定してみて下さい. - --E バイト操作命令の不定バイトの書き換えチェックをしない - - 通常は、不定バイトを書き換えるような命令は未定義命令と見 - なしますが、このオプションを指定した場合はそのチェックを - 行ないません. - --F dbra, fdbra を dbf, fdbf として出力する - --G サブルーチンコール命令の直後に引数を置くプログラムを解析 - する. - --I 命令の中を差すラベルのアドレスを表示する - - 命令の中を指すラベルが現われた時に、その旨を表示します. - - ・「命令の中を差すラベル(X -> Y+?)」 - アドレス X が命令の中を指していたため、Y+? に置き換えま - した. - - ・「命令の中を差すラベル(X) -> データ領域に変更しました - (Y-X)」 - -k オプションの影響、またはアドレス X が不定バイトを指し - ていた為に Y から X までの領域をデータ領域に変更しました. - そこが本当はプログラム領域であった場合は -E オプションを - 指定してみて下さい. - --K char char をコメントキャラクタとして用いる - --L char char をラベル名の先頭文字として用いる - - 実行ファイルのシンボルテーブルやラベルファイルでラベル名 - が与えられなかったラベルは、'Lxxxxxx'(x は16進数値)とい - う形式でラベル名が生成されますが、先頭文字 'L' を任意の - 文字に変更します. - --M cmpi, move, addi.b, subi.b #imm および pack, unpk にコメ - ントをつける - - imm が表示可能な ASCII 文字の場合にコメントを出力します. - --N サイズがデフォルトなら付けない - --R num 未使用フィールドのチェック項目の指定 - (ビット指定, 初期値=15) - +1 mulu.l, muls.l, ftst.x における未使用レジスタフィールド - +2 拡張アドレッシングでのサプレスされたレジスタフィールド - +4 サプレスされたインデックスレジスタに対するスケーリング - +8 サプレスされたインデックスレジスタに対するサイズ指定(.l) - --S[num] 出力ファイルを num KB ごとに分割する - (num を省略すると 64KB) - - 実行ファイルの約 num KB ごとにソースファイルを分割して出 - 力します. ソースファイルには以下のような拡張子が付加され - ます. - - テキストセクション .000 .001 ~ .009 .00a ... - データセクション .dat - ブロックストレージセクション .bss - --T[file] テーブル記述ファイルを読み込む - - テーブル記述ファイルを読み込みます. ファイル名を省略した - 場合はソースファイル名の拡張子を .tab に変更したファイル - 名から読み込みます. - --U ニーモニックを大文字で出力する - --V num バックトラックの原因の表示 - (0:しない [1]:プログラム領域 2:全ての領域) - - 解析した領域がプログラムと認められなかった時に、その理由 - とアドレスを表示します. - --W num 同一データを .dcb で出力する最小バイト数. - 0なら圧縮しない(初期値=64) - - データを .dc.? で出力する場合、全てのデータが同一の値で - あれば .dcb.? により圧縮して出力されますが、一定のサイズ - より小さい領域は例え同一値であっても圧縮されません. この - オプションでそのサイズの閾値を変更出来ます. - --X 16進数を大文字で出力する - --Y カレントディレクトリからも include ファイルを検索する - - カレントディレクトリにあるインクルードファイルを優先して - 読み込みます. - --Z[num] 16進数をゼロサプレスする([0]:通常 1:省略可能な'$'を省略) - ---include-XXX-mac=file - include ファイルの指定(XXX = doscall,iocscall,fefunc) - - 標準の include ファイルの代わりに file を読み込みます. - ---exclude-XXX-mac - include ファイルを読み込まない - - include ファイルを読み込まず、ファンクションコールの逆ア - センブルも行わないようにします. - ---header=file ヘッダファイルの指定(環境変数 dis_header より優先) - - 標準のヘッダの代わりに file の内容を出力します. - ---(no-)fpsp 未実装浮動小数点命令を[有効](無効)にする ---(no-)isp 未実装整数命令を[有効](無効)にする - - 通常は、システムによってソフトウェアエミュレーションされ - ることが保証されている命令は実在する命令と見なされますが、 - このオプションを指定した場合は未定義命令と見なします. - ---no-fpu 内蔵FPU命令を無効にする(-m68040~68060の後に指定) ---no-mmu 内蔵MMU命令を無効にする(-m68030~68060の後に指定) - - 通常は -m680*0 オプションで指定した MPU によっては、自動 - 的に内蔵 FPU/MMU 命令が有効になります. これらのオプショ - ンを指定するとそれらの命令を対象命令セットから除外します. - - 逆アセンブルするファイルにそれらの命令が含まれていないと - 分っている場合、このオプションを指定することで命令セット - を限定し、解析の手助けをすることが出来ます. - - このオプションは -m680*0 オプションによってクリアされる - ので、それより後に指定して下さい. - ---sp a7 レジスタを'sp'と表記する(標準では --a7) - - オペランド中のレジスタ a7 の表記を sp に変更します. - movem 命令のレジスタリストに表われる a7 は変更されません. - ---old-syntax アドレッシングを旧表記で出力する(標準では --new-syntax) - - 通常は 68020 以降で定められたアドレッシング表記で出力し - ますが、このオプションを指定した場合は 68000 の表記で出 - 力します. ただし、68020 以降でしか使用できないアドレッシ - ングでは常に新しい表記で出力します. - ---(in)real 浮動小数点を[実数表記](内部表現)で出力する - - 命令のオペランドやデータとして浮動小数点を出力する場合の - 表記を選択します. --real を指定すると「0f1.23e+10」といっ - た実数表記、 --inreal を指定すると「!4048f5c3」といった - 内部表現で出力します. - - 非数や無限大、非正規化数、未使用ビットがセットされている - データの場合は実数表記が不可能なので常に内部表現で出力さ - れます. - - 標準状態では --real が指定されています. - ---overwrite ファイルを無条件で上書きする ---version バージョンを表示する ---help 使用法を表示する - - -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - - ソースコードジェネレータ 環境変数一覧 - -──────────────────────────────────── - -dis_opt デフォルトのオプションを指定します. コマンドラインの指定 - より先に解釈されますが、-m680*0 など上書き指定できるもの - を除き取り消すことは出来ません. - -dis_include doscall.mac、iocscall.mac、fefunc.mac を検索するディレク - トリ名を設定します. dis_include で指定されたパスに存在し - なければ環境変数 include を見ます. - -include 環境変数 dis_include で指定されたパスに各ファイルが存在 - しなかった場合に検索するディレクトリ名を設定します. - include で指定されたパスにも存在しなければ dis.x はエラー - 終了します. - -dis_sxmac SX-Window 用のインクルードファイルのファイル名をフルパス - で設定しておけば、-u1 オプション指定時にそのファイルが読 - み込まれます. この環境変数を設定しなければ -u1 を指定し - た時でもファイルが読み込まれないだけで、エラーにはなりま - せん. - -dis_header 出力ファイルの先頭に出力される .include 部分を書いたファ - イルをフルパスで設定しておけば、そのファイルの内容を代わ - りに出力します. - - -──────────────────────────────────── diff --git a/docs/gpl-3.0.txt b/docs/gpl-3.0.txt new file mode 100644 index 0000000..f288702 --- /dev/null +++ b/docs/gpl-3.0.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. 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. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey 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; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + 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. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +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. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 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, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program 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, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU 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 Lesser General +Public License instead of this License. But first, please read +. diff --git a/docs/labelfile.txt b/docs/labelfile.txt index ba4b722..50511ab 100644 --- a/docs/labelfile.txt +++ b/docs/labelfile.txt @@ -1,56 +1,59 @@ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ソースコードジェネレータ ラベルファイル書式 + ソースコードジェネレータ ラベルファイル書式 -──────────────────────────────────── +─────────────────────────────────────── -'*'から始まる行はコメント行. + '*'から始まる行はコメント行。 アドレス (空白) 属性文字列 [(空白) シンボル名] ... [(空白) *コメント] - アドレスは6桁の16進数で、頭に'$'・'0x'などは付かない. - シンボル名は空白で区切って複数記述できる. +  アドレスは6桁の16進数で、頭に'$'・'0x'などは付かない。 +  シンボル名は空白で区切って複数記述できる。 属性文字列 - P プログラム + P プログラム -# RB 相対オフセットテーブル(バイト) **未対応** - RW 〃 (ワード) - RL 〃 (ロングワード) [*] +# RB 相対オフセットテーブル(バイト) **未対応** + RW 相対オフセットテーブル(ワード) + RL 相対オフセットテーブル(ロングワード) [*] - DS 文字列データ - DB バイトデータ - DW ワードデータ - DL ロングワードデータ - DZ ロングワードテーブル [*] + DS 文字列データ + DB バイトデータ + DW ワードデータ + DL ロングワードデータ + DZ ロングワードテーブル [*] - DF 浮動小数点実数データ(単精度) - DD 〃 (倍精度) - DX 〃 (拡張精度) - DP 〃 (パックドデシマル) + DF 浮動小数点実数データ(単精度) + DD 浮動小数点実数データ(倍精度) + DX 浮動小数点実数データ(拡張精度) + DP 浮動小数点実数データ(パックドデシマル) - DU サイズがない/分からないデータ + DU サイズがない/分からないデータ - [*]印付きの属性は dis.x が出力することはなく、ユーザ指定のみ. - 属性の最後が 'F' の場合は、絶対にその属性であることを示す. - dis.x が出力する属性文字列は全て大文字である. ユーザが属性を書き - 換える場合、小文字で記述すればそこから解析を行う. +  上記の後ろに追加の属性が付く場合がある。 + + F 絶対にその属性であることを示す + H ソースコードにラベル行を出力しない(デバイスヘッダで使用される) + + [*]印付きの属性はdisが出力することはなく、ユーザ指定のみ。 + +  disがラベルファイルに出力する属性文字列は全て大文字である。ユーザが属性 + を書き換える場合、小文字で記述すればそこから解析を行う。 シンボル名 - 実行ファイルのシンボルテーブルに含まれる、アドレスを現わすシンボ - ル名が全て出力される. - ラベルファイルを読み込ませた場合はシンボルテーブルに含まれるシン - ボル名は無視されるので、書き換えたり削除・追加することが出来る. +  実行ファイルのシンボルテーブルに含まれる、アドレスを現わすシンボル名が全 + て出力される。 +  ラベルファイルを読み込ませた場合はシンボルテーブルに含まれるシンボル名は + 無視されるので、書き換えたり削除・追加することができる。 - シンボル名が出力されたラベルは外部定義であるが、その行のシンボル - 名を全て削除した場合、そのラベルは内部定義として扱われる. - シンボル名がないラベルにシンボル名を記述しても、外部定義にはなら - ない. +  シンボル名が出力されたラベルは外部定義であるが、その行のシンボル名を全て + 削除した場合、そのラベルは内部定義として扱われる。 +  シンボル名がないラベルにシンボル名を記述しても、外部定義にはならない。 - ソースファイルのラベル行には全てのシンボル名が出力されるが、命令 - 中のオペランドとして使用されるのは先頭に記述されたシンボル名だけ - である. +  ソースファイルのラベル行には全てのシンボル名が出力されるが、命令中のオペ + ランドとして使用されるのは先頭に記述されたシンボル名だけである。 -──────────────────────────────────── +─────────────────────────────────────── diff --git a/docs/tablefile.txt b/docs/tablefile.txt index 09d5e1a..db52190 100644 --- a/docs/tablefile.txt +++ b/docs/tablefile.txt @@ -1,146 +1,143 @@ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - ソースコードジェネレータ テーブルファイル書式 + ソースコードジェネレータ テーブルファイル書式 ──────────────────────────────────── -'#'、'*'、';' から始まる行はコメント行。 + +●基本構文 + + '#'、'*'、';' から始まる行はコメント行。 テーブル開始アドレス - 識別子 [オペランド表現式] - ... + 識別子 [オペランド表現式] + ... テーブル終了マーク -・テーブル開始アドレス +●テーブル開始アドレス - 行頭から 16 進数でテーブルの開始アドレスを記述する。 - '$'や'0x'などは付けない。 + 行頭から16進数でテーブルの開始アドレスを記述する。'$' や '0x' などは付 +けない。 - テーブルが記述できるのはテキスト・データセクション及び、限定的で - はあるが BSS 内である。 + テーブルが記述できるのはテキスト・データセクション及び、限定的ではある +が BSS 内である。 -・識別子 +●識別子 - 次のいずれか。 + 次のいずれか。 - dc.b 1 バイトのデータを .dc.b で出力する。 - dc.w 1 ワードのデータを .dc.w で出力する。 - dc.l 1 ロングワードのデータを .dc.l で出力する。 - dc.s 単精度実数を .dc.s で出力する。 - dc.d 倍精度実数を .dc.d で出力する。 - dc.x 拡張精度実数を .dc.x で出力する。 - dc.p パックドデシマル実数を .dc.p で出力する。 + .dc.b 1バイトのデータを .dc.b で出力する。 + .dc.w 1ワードのデータを .dc.w で出力する。 + .dc.l 1ロングワードのデータを .dc.l で出力する。 + .dc.s 単精度実数を .dc.s で出力する。 + .dc.d 倍精度実数を .dc.d で出力する。 + .dc.x 拡張精度実数を .dc.x で出力する。 + .dc.p パックドデシマル実数を .dc.p で出力する。 - 上記の命令は、オペランド表現式があればその式を、なければ pc(に相 - 当するアドレス)の示す値の出力する。識別子の先頭に'.'を記述しても - よい。 + 上記の命令は、オペランド表現式があればその式を、なければ PC (に相当す +るアドレス)の示す値を出力する。識別子の先頭の '.' は省略できる。 - 奇数アドレスに dc.w 以降の命令を置くことは可能だが、警告が表示さ - れる。 + 複数バイトを出力する識別子(.dc.w 以降)を奇数アドレスに置くことは可能だ +が、警告が表示される。 - byte[式] (式)バイトのバイト列を .dc.b で出力する。 - asciiz 0 で終わる文字列を .dc.b で出力する。 - lascii 文字数 + 文字列を .dc.b で出力する。 - SX-Window で用いられる形式。 - ascii[式] (式)バイトの文字列を .dc.b で出力する。 + byte[式] (式)バイトのバイト列を .dc.b で出力する。 + asciiz 0で終わる文字列を .dc.b で出力する。 + lascii 文字数 + 文字列を .dc.b で出力する。 + SX-Window で用いられる形式。 + ascii[式] (式)バイトの文字列を .dc.b で出力する。 - even .even 疑似命令を出力する。 - cr 改行する。 - break 式 式の値が真(0 以外)ならテーブルを終了する。 + even .even 疑似命令を出力する。 + cr 改行する。 + break 式 式の値が真(0 以外)ならテーブルを終了する。 - byte、ascii、break 以外の識別子の後に [式] を付けた場合、式の値 - だけ識別子を繰り返す。 + byte、ascii、break 以外の識別子の後に [式] を付けた場合、式の値だけ識 +別子を繰り返す。 -・オペランド表現式 +●オペランド表現式 - 式または文字列。','で区切って複数の式または文字列を続けて記述す - ることも出来る。 + 式または文字列。',' で区切って複数の式または文字列を続けて記述すること +もできる。 - 式を { } で囲むと、式をアドレスと見なしてそのアドレスのラベルを - 生成する。ソースコードには L?????? の形式、またはシンボル名に置 - 換されて出力される。{ } で囲まない場合は数値として $?????? の形 - 式で出力される。 + 式を { } で囲むと、式をアドレスとみなしてそのアドレスのラベルを生成す +る。ソースコードには L?????? の形式、またはシンボル名に置換されて出力さ +れる。{ } で囲まない場合は数値として $?????? の形式で出力される。 - 文字列はそのまま出力される。 + 文字列はそのまま出力される。 - 例) - .dc.w {peek.w(pc)+tabletop},"-",{tabletop} - ↓ - .dc.w Lxxxxxx-Lyyyyyy + 例) + .dc.w {peek.w(pc)+tabletop},"-",{tabletop} + ↓ + .dc.w Lxxxxxx-Lyyyyyy - オペランド表現式は、文字列(上記の例で言えば"-")を普通の演算子と - 見なした時の値が peek.?(pc) にならなければならない。 + オペランド表現式は、文字列(上記の例で言えば "-")を普通の演算子とみなし +たときの値が peek.?(pc) にならなければならない。 ・式 - 式は C 言語の演算子のサブセットが使用できる。 - - 算術演算子 - + - * / % - 論理演算子 - == != < <= > >= ! - その他 ( ) - 定数 - tabletop テーブルの先頭アドレス - pc 注目中のアドレス - 関数 - peek.b(式) 式のアドレスの指すバイト値 - *(unsigned char*)式 - peek.w(式) 式のアドレスの指すワード値 - *(unsigned short*)式 - peek.l(式) 式のアドレスの指すロングワード値 - *(unsigned long*)式 - ext.w(式) 式を signed char と見なし、unsigned - short に符号拡張した値を返す - (unsigned short)(signed char)式 - ext.l(式) 式を signed short と見なし、unsigned - long に符号拡張した値を返す - (unsigned long)(signed short)式 - - 定数や関数の返値は全て unsigned long として扱われ、演算も - unsigned long で行われる。よって、peek.?(x) < 0 は常に偽になる。 - - 奇数アドレスからの peek.w()、peek.l() は可能だが警告が表示される。 - BSS に対して peek.?() を使用した場合、その値は 0 になる。 - - 数は 10 進数と、'0x' または '$'から始まる 16 進数が使える。 + 式は C 言語の演算子のサブセットが使用できる。 + + 算術演算子 + + - * / % + 論理演算子 + == != < <= > >= ! + その他 + ( ) + 定数 + tabletop テーブルの先頭アドレス + pc 注目中のアドレス + 関数 + peek.b(式) 式のアドレスの指すバイト値。 + *(unsigned char*)式 + peek.w(式) 式のアドレスの指すワード値。 + *(unsigned short*)式 + peek.l(式) 式のアドレスの指すロングワード値。 + *(unsigned long*)式 + ext.w(式) 式を signed char と見なし、unsigned short に符号 + 拡張した値を返す。 + (unsigned short)(signed char)式 + ext.l(式) 式を signed short と見なし、unsigned long に符号 + 拡張した値を返す。 + (unsigned long)(signed short)式 + + 定数や関数の返値は全て unsigned long として扱われ、演算も unsigned +long で行われる。よって、peek.?(x) < 0 は常に偽になる。 + + 奇数アドレスからの peek.w()、peek.l() は可能だが警告が表示される。BSS +に対して peek.?() を使用した場合、その値は 0 になる。 + + 数は10進数と、'0x' または '$' から始まる16進数が使える。 ・文字列 - "文字列" の形式で文字列を記述する。記号 '"' 自身や制御記号は含め - ることは出来ない。 + "文字列" の形式で文字列を記述する。記号 '"' 自身や制御記号を含めること +はできない。 ・テーブル終了マーク - 行頭から、以下のいずれかを必ず一つ記述する。 - - end 以上のテーブルが一つあることを指定する。 - end[数] 以上のテーブルが記述した数の分だけあることを指定 - する。数は 10 進数のみ。 - end[] 以上のテーブルが複数個あり、テーブルの数は dis - に判断させることを指定する(break 文があればそれ - も考慮する)。 - end[breakonly] 以上のテーブルが複数個あり、テーブルの数は break - 文でのみ判断することを指定する。break 文を書かな - いと止まらないので注意すること。 - - テーブルの数が分かる時はなるべく end[数] を使う。end[] による自 - 動判断はテーブルの次のラベルのアドレスや、アドレスに依存している - 値などを見て判断しているだけなので、間違えることがしばしばある。 - 特に文字列の自動認識時に不要なラベルを作ってしまい、それに引っ掛 - かることが多い。break 文を書いても break する前に dis が勝手にテ - ーブルを終わらせてしまう時は end[breakonly] を使用する。 - - -・正確な文法 - - ソースコードの eval.y を参照すること。 + 行頭から、以下のいずれかを必ず一つ記述する。 + + end 以上のテーブルが一つあることを指定する。 + end[数] 以上のテーブルが記述した数の分だけあることを指定する。 + 数は10進数のみ。 + end[] 以上のテーブルが複数個あり、テーブルの数は dis に判 + 断させることを指定する(break 文があればそれも考慮す + る)。 + end[breakonly] 以上のテーブルが複数個あり、テーブルの数は break 文 + でのみ判断することを指定する。break 文を書かないと止 + まらないので注意すること。 + + テーブルの数が分かる時はなるべく end[数] を使う。end[] による自動判断 +はテーブルの次のラベルのアドレスや、アドレスに依存している値などを見て判 +断しているだけなので、間違えることがしばしばある。特に文字列の自動認識時 +に不要なラベルを作ってしまい、それに引っ掛かることが多い。break 文を書い +ても break する前に dis が勝手にテーブルを終わらせてしまう時は +end[breakonly] を使用する。 ──────────────────────────────────── diff --git a/src/Makefile b/src/Makefile index bc9ff2d..c72f04f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,57 +1,57 @@ -# Makefile for dis (Human68k) +# Makefile for dis -.phony: all clean index install tags - -PROGRAM = dis.x - -YACC = bison -AS = has -CC = gcc2 +TARGET = generic +PROGRAM = dis +CC = gcc +DEFAULTCFLAGS = -Wall -Wextra -Werror -pipe -O3 -funsigned-char +FUNCCFLAGS = LD = $(CC) -LDFLAGS = -Wl,-d_STACK_SIZE=0x40000 -# -Wl,-x +LDFLAGS = +LIBS = -FUNCCFLAGS = -DHAVE_STRTOX -DHAVE_STRUPR -DHAVE_JCTYPE_H -# -DHAVE_STRTOX -# -DHAVE_STRUPR -# -DHAVE_JCTYPE_H -# -DNO_PRINTF_LDBL +# FUNCCFLAGS +# -DHAVE_STRTOX -DHAVE_JCTYPE_H -DNO_PRINTF_LDBL +# -DQUICK_YES_NO -DEFAULTCFLAGS = -Wall -cc1-stack=600000 -# -DQUICK_YES_NO -# -DREAD_FEFUNC_H +ifeq ($(findstring human68k,$(MAKE_VERSION)),human68k) +ifeq ($(notdir $(CURDIR)),src) +$(error do not execute make in src directory) +endif -# gcc 1.xx 用 -#OPTCFLAGS = -O -fstrength-reduce -fomit-frame-pointer -fcombine-regs \ -# -fforce-mem -fforce-addr -finline-functions - -# gcc 2.x.x 用 -OPTCFLAGS = -O2 -fforce-addr - -CFLAGS = $(DEFAULTCFLAGS) $(FUNCCFLAGS) $(OPTCFLAGS) - -#LIBS = -lExtmalloc -lh68unix -lhupair # -lprof -#LIBS = -lExtmalloc -lioctlb +PROGRAM = dis.x +CC = gcc2 +DEFAULTCFLAGS = -cc1-stack=600000 -Wall -W -Werror -O2 -fforce-addr -funsigned-char +FUNCCFLAGS = -DHAVE_STRTOX -DHAVE_JCTYPE_H +LDFLAGS = -Wl,-d_STACK_SIZE=0x40000 LIBS = -lld -lhdi -lhmem +endif + +.phony: all clean index install tags depend -%.o: %.y - $(YACC.y) $< -o $*.c - $(COMPILE.c) $*.c $(OUTPUT_OPTION) +CFLAGS = $(DEFAULTCFLAGS) $(FUNCCFLAGS) HDRS = analyze.h \ disasm.h \ estruct.h \ + ea.h \ + eastr.h \ etc.h \ + eval.h \ fpconv.h \ + fpu.h \ generate.h \ getopt.h \ global.h \ hex.h \ + human.h \ include.h \ label.h \ labelfile.h \ + mmu.h \ offset.h \ + opstr.h \ option.h \ + osk.h \ output.h \ symbol.h \ table.h @@ -59,20 +59,26 @@ HDRS = analyze.h \ SRCS = analyze.c \ analyze2.c \ disasm.c \ - disasmonly.c \ + ea.c \ + eastr.c \ etc.c \ - eval.y \ + eval.c \ fpconv.c \ + fpu.c \ generate.c \ getopt.c \ hex.c \ + human.c \ include.c \ label.c \ labelcheck.c \ labelfile.c \ main.c \ + mmu.c \ offset.c \ + opstr.c \ option.c \ + osk.c \ output.c \ search.c \ symbol.c \ @@ -81,6 +87,10 @@ SRCS = analyze.c \ OBJS = $(addsuffix .o,$(basename $(SRCS))) +DOCS = $(addprefix docs/,gpl-3.0.txt labelfile.txt README.txt table.txt tablefile.txt) + +INCS = $(addprefix include/,doscall.mac fefunc.mac iocscall.mac sxcall.mac) + all: $(PROGRAM) $(PROGRAM): $(OBJS) @@ -90,7 +100,7 @@ install: $(PROGRAM) install -s $(PROGRAM) /usr/local/bin clean: - rm -f $(PROGRAM) $(OBJS) eval.c + rm -f $(PROGRAM) $(OBJS) index: ctags -wx $(HDRS) $(SRCS) @@ -98,51 +108,67 @@ index: tags: $(HDRS) $(SRCS) etags -et $(HDRS) $(SRCS) -### +depend: + $(CC) -MM $(CFLAGS) $(SRCS:.y=.c) -analyze.o: estruct.h global.h label.h analyze.h disasm.h offset.h etc.h -analyze2.o: estruct.h global.h label.h analyze.h disasm.h offset.h etc.h -disasm.o: estruct.h global.h disasm.h fpconv.h hex.h etc.h -disasmonly.o: estruct.h global.h disasm.h generate.h output.h hex.h etc.h -etc.o: estruct.h global.h label.h offset.h symbol.h etc.h -eval.o: estruct.h global.h label.h offset.h generate.h hex.h etc.h \ - labelfile.h table.h disasm.h fpconv.h -fpconv.o: estruct.h fpconv.h hex.h -generate.o: estruct.h disasm.h generate.h global.h fpconv.h hex.h etc.h \ - include.h label.h offset.h output.h symbol.h table.h -getopt.o: getopt.h -hex.o: estruct.h hex.h -include.o: estruct.h disasm.h generate.h global.h include.h etc.h -label.o: estruct.h global.h label.h etc.h avl/avl.c -labelcheck.o: estruct.h global.h label.h disasm.h analyze.h offset.h etc.h -labelfile.o: estruct.h global.h label.h symbol.h analyze.h etc.h -main.o: estruct.h global.h label.h symbol.h analyze.h etc.h \ - disasm.h generate.h include.h labelfile.h offset.h option.h table.h -offset.o: estruct.h global.h offset.h etc.h -option.o: estruct.h global.h generate.h disasm.h analyze.h hex.h etc.h \ - fpconv.h getopt.h include.h option.h output.h symbol.h -output.o: estruct.h global.h disasm.h output.h generate.h hex.h etc.h -search.o: estruct.h global.h label.h offset.h etc.h -symbol.o: estruct.h global.h symbol.h output.h label.h hex.h etc.h -table.o: estruct.h global.h label.h labelfile.h table.h offset.h hex.h etc.h -version.o: - -analyze.h: estruct.h label.h -disasm.h: estruct.h -estruct.h: -etc.h: global.h -fpconv.h: -generate.h: estruct.h -getopt.h: -global.h: estruct.h -hex.h: global.h -include.h: -label.h: -labelfile.h: -offset.h: -option.h: -output.h: -symbol.h: -table.h: etc.h +ifeq ($(findstring human68k,$(MAKE_VERSION)),human68k) +bin: + mkdir $@ + +bin/$(PROGRAM): bin $(PROGRAM) + rm -f $@ + cp $(PROGRAM) $@ + lzx -S $@ + +dis.zip: bin/$(PROGRAM) $(DOCS) $(INCS) + rm -f $@ + zip -9 $@ $^ +endif + +### +analyze.o: analyze.c analyze.h estruct.h label.h disasm.h etc.h global.h opstr.h \ + offset.h osk.h +analyze2.o: analyze2.c analyze.h estruct.h label.h disasm.h etc.h global.h \ + opstr.h offset.h +disasm.o: disasm.c disasm.h estruct.h ea.h eastr.h etc.h global.h opstr.h hex.h \ + fpu.h mmu.h osk.h +ea.o: ea.c ea.h disasm.h estruct.h eastr.h etc.h global.h opstr.h hex.h fpconv.h \ + mmu.h +eastr.o: eastr.c eastr.h estruct.h etc.h global.h disasm.h opstr.h +etc.o: etc.c etc.h estruct.h global.h disasm.h opstr.h label.h offset.h symbol.h +eval.o: eval.c eval.h estruct.h disasm.h etc.h global.h opstr.h fpconv.h \ + generate.h label.h output.h hex.h labelfile.h offset.h table.h +fpconv.o: fpconv.c fpconv.h estruct.h etc.h global.h disasm.h opstr.h hex.h +fpu.o: fpu.c fpu.h disasm.h estruct.h ea.h eastr.h etc.h global.h opstr.h hex.h +generate.o: generate.c generate.h disasm.h estruct.h label.h output.h eastr.h \ + etc.h global.h opstr.h eval.h fpconv.h hex.h include.h mmu.h offset.h osk.h \ + symbol.h table.h +getopt.o: getopt.c getopt.h +hex.o: hex.c hex.h global.h disasm.h estruct.h opstr.h +human.o: human.c human.h estruct.h analyze.h label.h etc.h global.h disasm.h \ + opstr.h generate.h output.h include.h offset.h symbol.h version.h +include.o: include.c include.h estruct.h etc.h global.h disasm.h opstr.h +label.o: label.c label.h estruct.h etc.h global.h disasm.h opstr.h ./avl/avl.h \ + ./avl/avl.c +labelcheck.o: labelcheck.c analyze.h estruct.h label.h disasm.h etc.h global.h \ + opstr.h offset.h +labelfile.o: labelfile.c analyze.h estruct.h label.h etc.h global.h disasm.h \ + opstr.h symbol.h version.h +main.o: main.c analyze.h estruct.h label.h disasm.h eastr.h etc.h global.h opstr.h \ + generate.h output.h human.h labelfile.h option.h osk.h table.h version.h +mmu.o: mmu.c mmu.h disasm.h estruct.h ea.h eastr.h etc.h global.h opstr.h hex.h +offset.o: offset.c offset.h estruct.h global.h disasm.h opstr.h etc.h +opstr.o: opstr.c opstr.h estruct.h etc.h global.h disasm.h +option.o: option.c disasm.h estruct.h etc.h global.h opstr.h generate.h label.h \ + output.h getopt.h hex.h option.h version.h +osk.o: osk.c osk.h disasm.h estruct.h analyze.h label.h etc.h global.h opstr.h \ + generate.h output.h hex.h include.h symbol.h version.h +output.o: output.c disasm.h estruct.h etc.h global.h opstr.h hex.h output.h +search.o: search.c estruct.h etc.h global.h disasm.h opstr.h label.h offset.h +symbol.o: symbol.c symbol.h estruct.h etc.h global.h disasm.h opstr.h hex.h \ + label.h output.h +table.o: table.c table.h etc.h estruct.h global.h disasm.h opstr.h eval.h label.h \ + labelfile.h offset.h +version.o: version.c version.h # EOF diff --git a/src/analyze.c b/src/analyze.c index 17e6860..e0a7691 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1,728 +1,976 @@ -/* $Id: analyze.c,v 1.1 1996/11/07 08:04:58 ryo freeze $ - * - * ソースコードジェネレータ - * 自動解析モジュール - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 自動解析モジュール +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik #include #include -#ifdef __HUMAN68K__ -#ifdef __LIBC__ +#ifdef __HUMAN68K__ #include -#else -extern void __volatile _stack_over (void); -extern void *_SSTA; -#endif #endif #include "analyze.h" #include "disasm.h" #include "estruct.h" -#include "etc.h" /* charout, peek[wl] */ +#include "etc.h" // charout, peek[wl] #include "global.h" -#include "label.h" /* regist_label etc. */ -#include "offset.h" /* depend_address , nearadrs */ +#include "label.h" // regist_label etc. +#include "offset.h" // depend_address , nearadrs +#include "osk.h" + +typedef enum { + FLOW_NO_TRACKING, + FLOW_MOVE_PCIDX, + FLOW_LEA_PCDISP, + FLOW_MOVE_ARIDX, +} CodeFlowPhase; + +typedef struct { + uint8_t phase; // CodeFlowPhase + uint8_t baseReg; + uint8_t ixReg; + uint8_t reserved; + address target; +} CodeFlow; + +// static 関数プロトタイプ +static void printReason(const char* message, address adrs); +static boolean analyzeJump(DisParam* disp, CodeFlow* flow, address start, + analyze_mode mode, address limit); +static int analyzeRelativeTable(address table, opesize size, boolean isProgram); +static void regist_data(disasm*, operand*); +static void unregist_data(disasm*, operand*); + +void setReasonVerbose(uint8_t lv) { + Dis.reasonVerbose = (Dis.backtrackReason >= lv) ? TRUE : FALSE; +} +/* + right_opecode() 下請け -USEOPTION option_i; + アドレスに依存可能なオペランドが依存していれば + neardepend を次の依存アドレスに進める。 + 依存不可能か、依存していなければそのまま。 +*/ +static address skip_depend_ea(address neardepend, disasm* code, operand* op) { + switch (op->ea) { + case AbLong: + if (neardepend == op->eaadrs) return nearadrs(neardepend + 1); + break; + + case IMMED: + if (neardepend == op->eaadrs && + (code->size == LONGSIZE || code->size == SINGLESIZE)) + return nearadrs(neardepend + 1); + break; + + case PCIDXB: + if (op->flags & OPFLAG_PC_RELATIVE) { + break; // (bd.l,pc)のアドレス依存は認めない (bd.l,zpc)なら認める + } + // FALLTHRU + case AregIDXB: + if (neardepend == op->eaadrs && op->exbd == 4) + return nearadrs(neardepend + 1); + break; + + case AregPOSTIDX: + case AregPREIDX: + case PCPOSTIDX: + case PCPREIDX: + if ((op->flags & OPFLAG_PC_RELATIVE) == 0) { + // ([bd.l,pc])のアドレス依存は認めない ([bd.l,zpc])なら認める + if (neardepend == op->eaadrs && op->exbd == 4) + neardepend = nearadrs(neardepend + 1); + } + if (neardepend == op->eaadrs2 && op->exod == 4) + return nearadrs(neardepend + 1); + break; + + default: + break; + } + return neardepend; +} -boolean Reason_verbose; -boolean Arg_after_call = FALSE; +/* + right opecode ? -/* private 関数プロトタイプ */ -private address limitadrs (address); -private boolean branch_job (address, address, address, address, - analyze_mode, address); -private void regist_data (disasm*, operand*); -private boolean prolabel (address); -private void pcix (address, address); -private void unregist_data (operand*); +*/ +static boolean right_opecode(address neardepend, disasm* code, address pc) { + if (pc <= neardepend) return TRUE; + neardepend = skip_depend_ea(neardepend, code, &code->op1); + neardepend = skip_depend_ea(neardepend, code, &code->op2); + neardepend = skip_depend_ea(neardepend, code, &code->op3); + neardepend = skip_depend_ea(neardepend, code, &code->op4); + + return (pc <= neardepend); +} /* - right_opecode()下請け. - アドレスに依存可能なオペランドが依存していれば - neardependを次の依存アドレスに進める. - 依存不可能か、依存していなければそのまま. + + 既に PROLABEL として登録済みかどうか調べる + */ -static INLINE address -skip_depend_ea (address neardepend, disasm* code, operand* op) -{ - switch (op->ea) { - case AbLong: - if (neardepend == op->eaadrs) - neardepend = nearadrs (neardepend + 1); - break; - case IMMED: - if (neardepend == op->eaadrs && code->size == LONGSIZE) - neardepend = nearadrs (neardepend + 1); - break; - case AregIDXB: - if (neardepend == op->eaadrs && op->exbd == 4) - neardepend = nearadrs (neardepend + 1); - break; - case AregPOSTIDX: - case AregPREIDX: - if (neardepend == op->eaadrs && op->exbd == 4) - neardepend = nearadrs (neardepend + 1); - case PCPOSTIDX: - case PCPREIDX: - if (neardepend == op->eaadrs2 && op->exod == 4) - neardepend = nearadrs (neardepend + 1); - break; - default: - break; - } - return neardepend; +static boolean prolabel(address adrs) { + lblbuf* ptr = search_label(adrs); + + return (ptr && isPROLABEL(ptr->mode)) ? TRUE : FALSE; } /* - right opecode ? + 既に DATLABEL として登録済みかどうか調べる */ -static INLINE boolean -right_opecode (address neardepend, disasm* code, address pc) -{ - if (pc <= neardepend) - return TRUE; - - neardepend = skip_depend_ea (neardepend, code, &code->op1); - neardepend = skip_depend_ea (neardepend, code, &code->op2); - neardepend = skip_depend_ea (neardepend, code, &code->op3); - neardepend = skip_depend_ea (neardepend, code, &code->op4); - -#ifdef DEBUG - if (pc > neardepend && (Debug & BREASON)) - printf ("right opecode failed\n"); -#endif - return (pc <= neardepend); +static boolean datlabel(address adrs) { + lblbuf* ptr = search_label(adrs); + + return (ptr && isDATLABEL(ptr->mode)) ? TRUE : FALSE; } +// 指定したアドレスより後のデータラベルのアドレスを返す +// そのようなラベルが無ければ Dis.availableTextEnd を返す +static address limitadrs(address adrs) { + lblbuf* lptr = next(adrs + 1); -/* + return MIN(lptr->label, Dis.availableTextEnd); +} - 既に PROLABEL として登録済みかどうか調べる +static void printUndefinedInstruction(address pc) { + if (Dis.reasonVerbose) { + codeptr ptr = Dis.Ofst + pc; + eprintf("\n" PRI_ADRS ": 未定義命令(" PRI_OPCODE " " PRI_OPCODE ")。", pc, + peekw(ptr), peekw(ptr + 2)); + } +} -*/ -static INLINE boolean -datlabel (address adrs) -{ - lblbuf* ptr = search_label (adrs); +// プログラム領域の終端をラベル登録する +static void foundProgramEnd(address adrs) { + if (search_label(adrs) == NULL) { + regist_label(adrs, DATLABEL | UNKNOWN); + } +} - if (ptr && isDATLABEL (ptr->mode)) - return TRUE; - return FALSE; +// インデックスレジスタが Dn.W*1 か? +static int isIxDnWordScale1(operand* op) { + return (op->ixReg <= 7) && (op->ixSizeScale == 0); } +// インデックスレジスタが Dn.w*1 または Dn.w*2 か? +static int isIxDnWordScale12(operand* op) { + return (op->ixReg <= 7) && (op->ixSizeScale <= 1); +} -/* +// インデックスレジスタが Dn.[wl]*1 または Dn.[wl]*2 か? +static int isIxDnScale12(operand* op) { + return (op->ixReg <= 7) && ((op->ixSizeScale & 3) <= 1); +} - 解析する +static boolean updateCodeFlowMovePCIDX(disasm* code, CodeFlow* flow) { + if (code->size != WORDSIZE || code->op2.ea != DregD) return FALSE; + if (!isIxDnScale12(&code->op1)) return FALSE; - input: - start : analyze start address - mode : ANALYZE_IGNOREFAULT - 分岐先での未定義命令等を無視する - ANALYZE_NORMAL - 分岐先で未定義命令等を見付けたら、呼び出し側はデータ領域 - return: - FALSE : pc からはプログラム領域と認められなかった + // MOVE (d8,PC,Dm.w*s),Dn + flow->phase = FLOW_MOVE_PCIDX; + flow->target = code->op1.opval; + flow->ixReg = code->op2.baseReg; + return TRUE; +} -*/ -#define TRUEret goto trueret -#define FALSEret goto falseret -#define ROUTINE_END(pc) ch_lblmod (pc, DATLABEL | UNKNOWN) - -extern boolean -analyze (address start, analyze_mode mode) -{ - address pc = start, store = start + Ofst; - address limit; - address neardepend; - disasm code; - int orib; /* ori.b #??,d0 = $0000???? */ - -#ifdef DEBUG - if (Debug & (BDEBUG | BREASON)) - printf ("an %x(%d)\n", start, mode); -#endif - charout ('>'); - - if (Available_text_end <= pc) { - if (Reason_verbose) - eprintf ("\n%06x : PC が有効なセクションを外れた\t", pc); - FALSEret; - } else if (depend_address (pc) || depend_address (pc - 2)) { - if (Reason_verbose) - eprintf ("\n%06x : PC がアドレスに依存している\t", pc); - FALSEret; - } else if ((ULONG)pc & 1) { - if (Reason_verbose) - eprintf ("\n%06x : PC が奇数\t", pc); - FALSEret; - } else if (((ULONG)pc & 1) != 0 || *(LONG*)store == 0) { - if (Reason_verbose) - eprintf ("\n%06x : PC が ori.b #0,d0 から始まっている\t", pc); - FALSEret; - } +static boolean updateCodeFlowMoveARIDX(disasm* code, CodeFlow* flow) { + if (flow->phase != FLOW_LEA_PCDISP) return FALSE; - /* the follow 4 lines are omitable, maybe */ -#if 0 - if (prolabel (start)) { - regist_label (start, PROLABEL); - TRUEret; - } -#endif + if (code->size != WORDSIZE || code->op2.ea != DregD) return FALSE; + if (!isIxDnScale12(&code->op1)) return FALSE; + if (flow->baseReg != code->op1.baseReg) return FALSE; - if (!regist_label (start, PROLABEL)) { /* これは ch_lblmod では駄目 */ -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("%x cannot be prolabel\n", pc); -#endif - TRUEret; - } + // MOVE (d8,An,Dm.w*s),Dn + flow->phase = FLOW_MOVE_ARIDX; + flow->ixReg = code->op2.baseReg; + return TRUE; +} - /* スタックチェック */ -#ifdef __HUMAN68K__ - { - register void* sp __asm ("sp"); +static boolean updateCodeFlowMove(disasm* code, CodeFlow* flow) { + switch (code->op1.ea) { + default: + return FALSE; - if (sp < _SSTA) { - eputc ('\n'); - _stack_over (); - } - } -#endif + case PCIDX: + return updateCodeFlowMovePCIDX(code, flow); + case AregIDX: + return updateCodeFlowMoveARIDX(code, flow); + } +} - PCEND = Available_text_end; - orib = 0; - limit = limitadrs (pc); - neardepend = nearadrs (pc); - - while (1) { - address previous_opval, previous_pc; - - if (neardepend == pc) { /* アドレス依存チェック */ - not_program (start, (address) min((ULONG) pc, (ULONG) limit)); - if (Reason_verbose) - eprintf ("\n%06x : PC がアドレスに依存している\t", pc); - FALSEret; - } - - if (*(UWORD*)store == 0) { /* ori.b #??,d0 チェック */ - if (orib >= 2 || *(UWORD*)(store + 2) == 0) { - not_program (start, (address) min ((ULONG) pc, (ULONG) limit)); - if (Reason_verbose) - eprintf ((orib >= 2) ? "\n%06x : ori.b #??,d0 が連続している\t" - : "\n%06x : ori.b #0,d0 を発見\t", pc); - FALSEret; - } - orib++; - } else - orib = 0; - - if (limit == pc && prolabel (limit)) { /* 既に解析済みの領域とぶつかった? */ -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("Already\n"); -#endif - ROUTINE_END (pc); - TRUEret; - } - - if ((pc > limit) || /* 最初は code.op.opval は初期化されないけど大丈夫 */ - (pc <= code.op1.opval && code.op1.opval < limit) || - (pc <= code.op2.opval && code.op2.opval < limit) || - (pc <= code.op3.opval && code.op3.opval < limit) || - (pc <= code.op4.opval && code.op4.opval < limit)) - limit = limitadrs (pc); - - previous_opval = code.op1.ea == PCIDX ? code.op1.opval : (address) -1; - previous_pc = pc; - store += dis (store, &code, &pc); - -#ifdef DEBUG - if (Debug & BTRACE) { - static const char size[10][2] = { - ".b", ".w", ".l", ".q", ".s", ".s", ".d", ".x", ".p", "" - }; - - printf ("%05x:%05x\t%s.2%s", - previous_pc, limit, code.opecode, size[code.size]); - if (code.op1.operand[0]) - printf ("\t%s", code.op1.operand); - if (code.op2.operand[0]) - printf (",%s", code.op2.operand); - if (code.op3.operand[0]) - printf (",%s", code.op3.operand); - if (code.op4.operand[0]) - printf (",%s", code.op4.operand); - printf ("\n"); - } -#endif - /* add '90 Sep 24 */ - if (Available_text_end < pc) { - if (Reason_verbose) - eprintf ("\n%06x : PC が有効なセクションを外れた\t", pc); - not_program (start, (address) min ((ULONG) previous_pc, (ULONG) limit)); - FALSEret; - } - - if (neardepend < pc) { -#ifdef DEBUG - if (Debug & BDEBUG) { - printf ("over neardepend:%x\n", pc); - printf ("size %d ea1 %d ea2 %d ea3 %d ea4 %d" - "op1val %x op2val %x op3val %x op4val %x" - "ea1adrs %x ea2adrs %x ea3adrs %x ea4adrs %s" - "\n", - code.size, code.op1.ea, code.op2.ea, code.op3.ea, code.op4.ea, - code.op1.opval, code.op2.opval, code.op3.opval, code.op4.opval, - code.op1.eaadrs, code.op2.eaadrs, code.op3.eaadrs, code.op4.eaadrs - ); - } -#endif - if (right_opecode (neardepend, &code, pc)) - neardepend = nearadrs (pc); - else { - if (Reason_verbose) - eprintf ("\n%06x : アドレス依存のオペランドが正当でない\t", previous_pc); - not_program (start, (address) min ((ULONG) previous_pc, (ULONG) limit)); - FALSEret; - } - } - - if (code.flag == OTHER - || ((code.flag == JMPOP || code.flag == JSROP) - && AregPOSTIDX <= code.jmpea && code.jmpea != PCIDXB)) { - regist_data (&code, &code.op1); - regist_data (&code, &code.op2); - regist_data (&code, &code.op3); - regist_data (&code, &code.op4); - } - - switch (code.flag) { - case UNDEF: - if (Reason_verbose) - eprintf ("\n%06x : 未定義命令(%04x %04x)\t", previous_pc, - peekw (previous_pc + Ofst), peekw (previous_pc + Ofst + 2)); - not_program (start, (address) min((ULONG) previous_pc, (ULONG) limit)); - FALSEret; - case OTHER: - break; - case JMPOP: - if (!(code.jmp == (address) -1 || - (code.op1.ea == AbLong && !INPROG (code.jmp, code.op1.eaadrs)) || - code.op1.ea == AbShort || - AregIDXB <= code.op1.ea)) { - if (code.op1.ea == PCIDX) - pcix (code.jmp, previous_opval); - else - if (!branch_job (code.jmp, start, pc, previous_pc, mode, limit)) - FALSEret; - } - case RTSOP: - ROUTINE_END (pc); - TRUEret; - case JSROP: - if (!(code.jmp == (address) -1 || - (code.op1.ea == AbLong && !INPROG (code.jmp, code.op1.eaadrs)) || - code.op1.ea == AbShort || - (AregIDXB < code.op1.ea && code.op1.ea != PCIDXB))) { - if (code.op1.ea == PCIDX) - pcix (code.jmp, previous_opval); - else - if (!branch_job (code.jmp, start, pc, previous_pc, mode, limit)) - FALSEret; - } - - /* -G : サブルーチンコールの直後に引数を置くことを認める */ - if (Arg_after_call && datlabel (pc)) - TRUEret; - - break; - case BCCOP: - if (!branch_job (code.jmp, start, pc, previous_pc, mode, limit)) - FALSEret; - break; - } - } +static boolean updateCodeFlowLea(disasm* code, CodeFlow* flow) { + if (code->op1.ea != PCDISP) return FALSE; -trueret: -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("ret\n"); -#endif - charout ('<'); - return TRUE; + // LEA (d16,PC),An + flow->phase = FLOW_LEA_PCDISP; + flow->target = code->op1.opval; + flow->baseReg = code->op2.baseReg; + return TRUE; +} -falseret: - charout ('?'); - ch_lblmod (start, DATLABEL | UNKNOWN | FORCE); - return FALSE; +// 相対オフセットテーブル判別用の情報を更新する +static void updateCodeFlow(disasm* code, CodeFlow* flow) { + switch (code->opecodeOffset) { + default: + break; + + case GET_OPECODE_OFFSET(move): + if (updateCodeFlowMove(code, flow)) return; + break; + case GET_OPECODE_OFFSET(lea): + if (updateCodeFlowLea(code, flow)) return; + break; + } + + flow->phase = FLOW_NO_TRACKING; } +static void analyzeOtherLea(disasm* code, CodeFlow* flow) { + if (code->op1.ea != PCIDX) return; -/* + // 直前の命令が MOVE (table,PC,Dm.w*s),Dn で、 + if (flow->phase != FLOW_MOVE_PCIDX) return; - adrs より後のデータラベルのアドレスを返す - そのようなラベルが無ければ Available_text_end を返す + // 今の命令が LEA (table,PC,Dn.w),An なら、 + if (flow->target != code->op1.opval) return; + if (flow->ixReg != code->op1.ixReg || !isIxDnWordScale1(&code->op1)) return; -*/ -private address -limitadrs (address adrs) -{ - lblbuf* lptr = next (adrs + 1); - -#if 0 - if (lptr->label == adrs && isDATLABEL (lptr->mode)) { - ch_lblmod (adrs, PROLABEL); - return limitadrs (adrs + 1); /* この +1 は何故いるのか? */ + // 相対遷移表を発見 + registerReltblOrder(&Dis.reltblArray, flow->target, RELTABLE, FALSE, + DATLABEL | FORCE); +} + +static void analyzeOtherPeaPCIDX(disasm* code, CodeFlow* flow) { + // 直前の命令が MOVE (talbe,PC,Dm.w*s),Dn で、 + if (flow->phase != FLOW_MOVE_PCIDX) return; + + // 今の命令が PEA (table,PC,Dn.w) なら、 + if (flow->target != code->op1.opval) return; + if (flow->ixReg != code->op1.ixReg || !isIxDnWordScale1(&code->op1)) return; + + // 相対遷移表を発見 + registerReltblOrder(&Dis.reltblArray, flow->target, RELTABLE, FALSE, + DATLABEL | FORCE); +} + +static void analyzeOtherPeaARIDX(disasm* code, CodeFlow* flow) { + // 直前の命令が MOVE (An,Dm.w*s),Dn で、 + if (flow->phase != FLOW_MOVE_ARIDX) return; + + // 今の命令が PEA (An,Dn.w) なら、 + if (code->op1.opval != 0) return; + if (flow->baseReg != code->op1.baseReg) return; + if (flow->ixReg != code->op1.ixReg || !isIxDnWordScale1(&code->op1)) return; + + // 相対遷移表を発見 + registerReltblOrder(&Dis.reltblArray, flow->target, RELTABLE, FALSE, + DATLABEL | FORCE); +} + +static void analyzeOtherPea(disasm* code, CodeFlow* flow) { + switch (code->op1.ea) { + default: + break; + + case PCIDX: + analyzeOtherPeaPCIDX(code, flow); + break; + + case AregIDX: + analyzeOtherPeaARIDX(code, flow); + break; + } +} + +// その他の命令の解析: ADDA +static void analyzeOtherAdda(disasm* code, CodeFlow* flow) { + // 直前の命令が LEA (table,PC),An で、 + if (flow->phase != FLOW_LEA_PCDISP) return; + + // 今の命令が ADDA (table,PC,Dn.w*s),An なら、 + if (code->size != WORDSIZE || code->op1.ea != PCIDX) return; + if (flow->target != code->op1.opval || flow->baseReg != code->op2.baseReg) + return; + if (!isIxDnWordScale12(&code->op1)) return; + + // 相対遷移表を発見 + registerReltblOrder(&Dis.reltblArray, flow->target, RELTABLE, FALSE, + DATLABEL | FORCE); +} + +// その他の命令の解析 +static void analyzeOther(disasm* code, CodeFlow* flow) { + switch (code->opecodeOffset) { + default: + break; + + case GET_OPECODE_OFFSET(lea): + analyzeOtherLea(code, flow); + break; + case GET_OPECODE_OFFSET(pea): + analyzeOtherPea(code, flow); + break; + case GET_OPECODE_OFFSET(adda): + analyzeOtherAdda(code, flow); + break; + } +} + +enum { + OPCODE2_ORI_B_IMM_D0 = 0x0000, +}; +enum { + OPCODE4_ORI_B_IMM0_D0 = 0x00000000, +}; + +// 解析サブ +// プログラム領域と認められる場合はTRUEを返す +// +// 成功条件 +// ・すでにプログラム領域と記録されていた +// ・プログラム領域のラベルに到達した +// ・rtsなどのリターン命令 +// ・-Gオプション指定時に、bsrなどのコール命令直後がデータ領域 +static boolean analyzeInner(address start, analyze_mode mode) { + address limit; + address neardepend; + DisParam disp; + disasm* code = &disp.code; + CodeFlow flow; + int orib = 0; // ori.b #??,d0 = $0000???? + void (*regoplbl)(disasm * code) = Dis.actions->registerOperandLabel; + + if (Dis.availableTextEnd <= start) { + printReason("PCが有効なセクションを外れた。", start); + return FALSE; + } + if (isOdd(start)) { + printReason("PCが奇数。", start); + return FALSE; + } + if (depend_address(start) || depend_address(start - 2)) { + printReason("PCがアドレスに依存している。", start); + return FALSE; + } + if (peekl(start + Dis.Ofst) == OPCODE4_ORI_B_IMM0_D0) { + printReason("PCが ori.b #0,d0 から始まっている。", start); + return FALSE; + } + + if (!regist_label(start, PROLABEL)) { // これは ch_lblmod では駄目 + return TRUE; + } + +// スタックチェック +#ifdef __HUMAN68K__ + { + void* sp; + __asm("move.l sp,%0" : "=g"(sp)); + + if (sp < _SSTA) { + eputc('\n'); + _stack_over(); } + } #endif -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("lmt(%x)=%x\n", adrs, lptr->label); -#endif + flow.phase = FLOW_NO_TRACKING; - return (address) min ((ULONG)lptr->label, (ULONG)Available_text_end); -} + limit = limitadrs(start); + neardepend = nearadrs(start); + setDisParamPcPtr(&disp, start, Dis.Ofst); + disp.pcEnd = Dis.availableTextEnd; -/* + while (1) { + address previous_pc; - 分岐命令等の処理 + if (neardepend == disp.pc) { // アドレス依存チェック + printReason("PCがアドレスに依存している。", disp.pc); + not_program(start, MIN(disp.pc, limit)); + return FALSE; + } -*/ -static void -bra_to_odd (address pre_pc, address opval) -{ - if (Reason_verbose) - eprintf ("\n%06x : 奇数アドレス(%06x)へ分岐\t", pre_pc, opval); -} - -private boolean -branch_job (address opval, address start, address pc, address pre_pc, - analyze_mode mode, address limit) -{ - if (opval == (address)-1) - return TRUE; - - /* 奇数アドレスへの分岐があればプログラム領域ではない */ - if ((LONG)opval & 1) { - if (Disasm_AddressErrorUndefined == FALSE) { - /* -j: 奇数アドレスへの分岐を未定義命令と「しない」 */ - - regist_label (opval, DATLABEL | UNKNOWN); - bra_to_odd (pre_pc, opval); /* 警告は常に出力 */ - return TRUE; - } - ch_lblmod (start, DATLABEL | UNKNOWN | FORCE); - bra_to_odd (pre_pc, opval); - not_program (start, (address)min ((ULONG)pre_pc, (ULONG)limit)); - return FALSE; + if (peekw(disp.ptr) == OPCODE2_ORI_B_IMM_D0) { // ori.b #??,d0 + if (orib >= 2 || peekw(disp.ptr + 2) == OPCODE2_ORI_B_IMM_D0) { + const char* s = (orib >= 2) ? "ori.b #??,d0 が連続している。" + : "ori.b #0,d0 を発見。"; + printReason(s, disp.pc); + not_program(start, MIN(disp.pc, limit)); + return FALSE; + } + orib++; + } else + orib = 0; + + if (limit == disp.pc && prolabel(limit)) { + return TRUE; // 既に解析済みのプログラム領域とぶつかった } - /* 分岐先が既にプログラム領域と判明している */ - if (prolabel (opval)) { - regist_label (opval, PROLABEL); /* to increment label count */ - return TRUE; + if ((disp.pc > limit) || // 最初は code.op.opval は初期化されないけど大丈夫 + (disp.pc <= code->op1.opval && code->op1.opval < limit) || + (disp.pc <= code->op2.opval && code->op2.opval < limit) || + (disp.pc <= code->op3.opval && code->op3.opval < limit) || + (disp.pc <= code->op4.opval && code->op4.opval < limit)) { + limit = limitadrs(disp.pc); } - /* 分岐先の領域を解析する */ - if (!analyze (opval, mode) && mode != ANALYZE_IGNOREFAULT && !option_i) { - /* 分岐先がプログラム領域でなければ、呼び出し元も同じ */ -#ifdef DEBUG - if(Debug & BREASON) - printf ("falseret : %x falseret\n", pc); -#endif - ch_lblmod (start, DATLABEL | UNKNOWN | FORCE); - not_program (start, (address)min ((ULONG)pc, (ULONG)limit)); - return FALSE; + previous_pc = disp.pc; + + dis(&disp); + + if (Dis.availableTextEnd < disp.pc) { + printReason("PCが有効なセクションを外れた。", disp.pc); + not_program(start, MIN(previous_pc, limit)); + return FALSE; } - /* 分岐先はプログラム領域だった */ - return TRUE; -} + if (neardepend < disp.pc) { + if (!right_opecode(neardepend, code, disp.pc)) { + printReason("アドレス依存のオペランドが正当でない。", previous_pc); + not_program(start, MIN(previous_pc, limit)); + return FALSE; + } + neardepend = nearadrs(disp.pc); + } + if (code->opeType == OTHER || + ((code->opeType == JMPOP || code->opeType == JSROP) && + AregPOSTIDX <= code->jmpea && code->jmpea != PCIDXB)) { + regist_data(code, &code->op1); + regist_data(code, &code->op2); + regist_data(code, &code->op3); + regist_data(code, &code->op4); + } -/* + if (regoplbl != NULL) regoplbl(code); - リラティブオフセットテーブルを見破る - move.w Label(pc,d0),d0 - jsr Label(pc,d0) + switch (code->opeType) { + default: + break; - Label dc.w Label1-Label, Label2-Label ,... + case OTHER: + analyzeOther(code, &flow); + break; - BUG: リラティブオフセットテーブルと判断した場合、 - すぐにテーブル中のエントリを登録してしまうので、あとから - not_program といっても残ってしまう。 (滅多にあることではないが) + case JMPOP: // JMP, BRA + if (!analyzeJump(&disp, &flow, start, mode, limit)) return FALSE; + foundProgramEnd(disp.pc); + return TRUE; -*/ -private void -pcix (address table, address popval) -{ -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("pcix : %x %x\n", table, popval); -#endif + case JSROP: // JSR, BSR + if (!analyzeJump(&disp, &flow, start, mode, limit)) return FALSE; - if (table == popval) - relative_table (table); - else - regist_label (table, DATLABEL | UNKNOWN); + if (Dis.argAfterCall && datlabel(disp.pc)) { + // -G : サブルーチンコールの直後に引数を置くことを認める + return TRUE; + } + break; + + case RTSOP: + foundProgramEnd(disp.pc); + return TRUE; + + case BCCOP: // Bcc + if (!analyzeJump(&disp, &flow, start, mode, limit)) return FALSE; + break; + + case UNDEF: + printUndefinedInstruction(previous_pc); + not_program(start, MIN(previous_pc, limit)); + return FALSE; + } + updateCodeFlow(code, &flow); + } } +static void printReason(const char* s, address adrs) { + if (Dis.reasonVerbose) eprintf("\n" PRI_ADRS ": %s", adrs, s); +} -/* +// 解析する +// +// input: +// start : analyze start address +// mode : ANALYZE_IGNOREFAULT +// 分岐先での未定義命令等を無視する +// ANALYZE_NORMAL +// 分岐先で未定義命令等を見付けたら、呼び出し側はデータ領域 +// return: +// FALSE : startからはプログラム領域と認められなかった +boolean analyze(address start, analyze_mode mode) { + boolean success; + charout('>'); + + success = analyzeInner(start, mode); + + if (!success) { + charout('?'); + ch_lblmod(start, DATLABEL | UNKNOWN | FORCE); + return FALSE; + } + charout('<'); + return TRUE; +} - table からリラティブオフセットテーブルとして登録 +// 奇数アドレスへの分岐 +static boolean branchToOdd(DisParam* disp, address start, address limit) { + disasm* code = &disp->code; -*/ -extern void -relative_table (address table) -{ - address ptr = table; - address tableend = next (table + 1)->label; - - regist_label (table, DATLABEL | RELTABLE); - - while (ptr < tableend) { - address label = table + (WORD) peekw (ptr + Ofst); - - if (label < (address) BeginTEXT || (address) Last < label - || (table <= label && label < ptr + 2)) { - regist_label (ptr, DATLABEL | UNKNOWN | FORCE); /* not rel table */ - break; - } -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("lbl %x\n", label); -#endif - regist_label (label, DATLABEL | UNKNOWN); - ptr += 2; - tableend = next (ptr)->label; - } + if (Dis.reasonVerbose) { + eprintf("\n" PRI_ADRS ": 奇数アドレス(" PRI_ADRS ")へ分岐。", code->pc, + code->jmp); + } + + if (Dis.acceptAddressError) { + // -j: 奇数アドレスへの分岐を未定義命令と「しない」 + regist_label(code->jmp, DATLABEL | UNKNOWN); + return TRUE; + } + + // 奇数アドレスへの分岐があればプログラム領域ではない + ch_lblmod(start, DATLABEL | UNKNOWN | FORCE); + not_program(start, MIN(code->pc, limit)); + return FALSE; } +// 分岐命令等の処理 +static boolean branch_job(DisParam* disp, address start, analyze_mode mode, + address limit) { + disasm* code = &disp->code; + address opval = code->jmp; -/* + if (opval == (address)-1) return TRUE; + if (isOdd(opval)) return branchToOdd(disp, start, limit); - table からロングワードなリラティブオフセットテーブルとして登録 + // 分岐先が既にプログラム領域と判明している + if (prolabel(opval)) { + regist_label(opval, PROLABEL); // to increment label count + return TRUE; + } -*/ -extern void -relative_longtable (address table) -{ - address ptr = table; - address tableend = next (table + 1)->label; - - regist_label (table, DATLABEL | RELLONGTABLE); - - while (ptr < tableend) { - address label = table + (LONG) peekl (ptr + Ofst); - - if (label < (address) BeginTEXT || (address) Last < label - || (table <= label && label < ptr + 4)) { - regist_label (ptr, DATLABEL | UNKNOWN | FORCE); /* not rel table */ - break; - } - regist_label (label, DATLABEL | UNKNOWN); - ptr += 4; - tableend = next (ptr)->label; - } + // 分岐先の領域を解析する + if (!analyze(opval, mode) && mode != ANALYZE_IGNOREFAULT && !Dis.i) { + // 分岐先がプログラム領域でなければ、呼び出し元も同じ + ch_lblmod(start, DATLABEL | UNKNOWN | FORCE); + not_program(start, MIN(disp->pc, limit)); + return FALSE; + } + + /* 分岐先はプログラム領域だった */ + return TRUE; } +static void analyzeJumpARIDX(disasm* code, CodeFlow* flow) { + // 直前の命令が MOVE (An,Dm.w*s),Dn で、 + if (flow->phase != FLOW_MOVE_ARIDX) return; -#ifdef OSKDIS -/* + // 今の命令が JMP|JSR (An,Dn.w) なら、 + if (code->op1.opval != 0) return; + if (code->op1.baseReg != flow->baseReg) return; + if (code->op1.ixReg != flow->ixReg || !isIxDnWordScale1(&code->op1)) return; - table からワードテーブルとして登録 + // 相対遷移表(ジャンプテーブル)を発見 + registerReltblOrder(&Dis.reltblArray, flow->target, RELTABLE, TRUE, + DATLABEL | FORCE); +} -*/ -extern void -w_table (address table) -{ - address ptr = table; - address tableend = next (table + 1)->label; +// 相対遷移表(ジャンプテーブル)を発見した場合はTRUEを返す +static boolean analyzeJumpPCIDX(disasm* code, CodeFlow* flow) { + // 直前の命令が MOVE (table,PC,Dm.w*s),Dn で、 + if (flow->phase != FLOW_MOVE_PCIDX) return FALSE; - regist_label (table, DATLABEL | WTABLE); + // 今の命令が JMP|JSR (table,PC,Dn.w) なら、 + if (code->jmp != flow->target) return FALSE; + if (code->op1.ixReg != flow->ixReg || !isIxDnWordScale1(&code->op1)) + return FALSE; - while (ptr < tableend) { - address label = (WORD) peekw (ptr + Ofst); + // 相対遷移表(ジャンプテーブル)を発見 + registerReltblOrder(&Dis.reltblArray, code->jmp, RELTABLE, TRUE, + DATLABEL | FORCE); + return TRUE; +} -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("wlbl %x\n", label); -#endif - regist_label (label, DATLABEL | UNKNOWN); - ptr += 2; - tableend = next (ptr)->label; - } +// 分岐命令(JMP, JSR, BRA, Bcc)の解析 +// プログラム領域と認められる場合はTRUEを返す +static boolean analyzeJump(DisParam* disp, CodeFlow* flow, address start, + analyze_mode mode, address limit) { + disasm* code = &disp->code; + + switch (code->jmpea) { + default: + // 分岐先が得られないなら問題なしとみなす + break; + + case AbLong: // jmp (label) + if (!INPROG(code->jmp, code->op1.eaadrs)) break; + // FALLTHRU + case PCDISP: // jmp (label,pc) や bsr label + return branch_job(disp, start, mode, limit); + + case AregIDX: // jmp (a0,d0.w) など + analyzeJumpARIDX(code, flow); + break; + + case PCIDX: // jmp (label,pc,d0.w) など + if (analyzeJumpPCIDX(code, flow)) break; + + // テーブルでなければ、不明サイズのデータとしてラベル登録する + // 実際の分岐先は実行時のインデックスレジスタの値次第で、ラベルの場所が + // プログラムではない可能性もあるので、解析はせずラベル登録だけに留める。 + // (README.txtの「参照されないラベル」と同様のケース) + regist_label(code->jmp, DATLABEL | UNKNOWN); + break; + } + + return TRUE; } -#endif /* OSKDIS */ +// 相対オフセットテーブルの値として正しいかどうかを返す +static boolean isValidOffset(address table, address label, address ptr, + int bytes, boolean isProgram) { + if (table == label) { + // オフセット値0の場合 + switch (Dis.reltblZero) { + default: + case RELTBL_ZERO_REJECT: + return FALSE; + case RELTBL_ZERO_HEAD: + return table == ptr; // テーブル先頭の項目のみ許可 + case RELTBL_ZERO_ALL: + return TRUE; + } + } -/* + if (isProgram) { + // 相対ジャンプテーブルなら宛先は偶数のみ + if (isOdd(label)) return FALSE; - table から ロングワードテーブルとして登録 + if (label < Dis.beginTEXT || Dis.availableTextEnd < label) return FALSE; + } else { + if (label < Dis.beginTEXT || Dis.LAST < label) return FALSE; + } -*/ -extern void -z_table (address table) -{ - address ptr = table; - address tableend = next (table + 1)->label; + // テーブル内を指すようならオフセット値ではない + if (table <= label && label < (ptr + bytes)) return FALSE; - regist_label (table, DATLABEL | ZTABLE); + return TRUE; +} + +#ifdef DEBUG_RELTBL_ADDRESS +static void printReltblAddress(address table, address ptr, ULONG offs, + address label) { + if (label != DEBUG_RELTBL_ADDRESS) return; + + eprintf("\n%s:%d: table=" PRI_ADRS ", ptr=" PRI_ADRS ", offs=" PRI_ULHEX + ", label=" PRI_ADRS ". ", + __FILE__, __LINE__, table, ptr, offs, label); +} +#endif - while (ptr + 4 <= tableend) { - address label = (address) peekl (ptr + Ofst); +// 相対オフセットテーブルを解析し、登録した宛先アドレス数を返す +// テーブル終了位置の検出 +// 宛先アドレスのラベル登録 +// +// BUG: 相対オフセットテーブルと判断した場合、すぐにテーブル中のエントリを +// 登録してしまうので、あとから not_program といっても残ってしまう。 +// (滅多にあることではないが) +// +static int analyzeRelativeTable(address table, opesize size, + boolean isProgram) { + uint8_t isLong = (size == RELLONGTABLE); + ULONG bytes = isLong ? 4 : 2; + address tableend = next(table + 1)->label; + address ptr = table; + int count; + + for (count = 0; ptr < tableend; ++count) { + ULONG offs = + isLong ? peekl(ptr + Dis.Ofst) : (ULONG)extl(peekw(ptr + Dis.Ofst)); + address label = table + offs; + + if (!isValidOffset(table, label, ptr, bytes, isProgram)) { + // おかしなアドレスを指していればテーブルの項目ではない + // (別のデータ形式かもしれないし、プログラム領域かもしれない) + // ただしアドレス値だけで判定しているので確実とは言えない + if (table == ptr) + regist_label(ptr, DATLABEL | UNKNOWN | FORCE); + else + regist_label(ptr, DATLABEL | UNKNOWN); + break; + } - regist_label (label, DATLABEL | UNKNOWN); -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("zlbl %x\n", label); +#ifdef DEBUG_RELTBL_ADDRESS + printReltblAddress(table, ptr, offs, label); #endif - ptr += 4; - tableend = next (ptr)->label; + if (table != label) { + regist_label(label, DATLABEL | UNKNOWN); } + ptr += bytes; + + // テーブル末尾が以下のような構造の場合に末尾を検出できるように、 + // 毎回「この位置以降で一番近いラベル」を再取得する + // .dc foo-tabletop + // foo: rts + tableend = next(ptr)->label; + } + + return count; } +// 解析する予定の相対オフセットテーブルの情報 +typedef struct { + address table; + uint8_t size; // opesize: RELTABLE, RELLONGTABLE + uint8_t isProgram; +} ReltblOrder; -/* +// 相対オフセットテーブルの記録バッファを初期化する +void initReltblArray(ArrayBuffer* rtbuf) { + initArrayBuffer(rtbuf, sizeof(ReltblOrder)); +} - from から to までの領域をプログラムで無かった事にする +// 指定したアドレスの相対オフセットテーブルのサイズを返す +// テーブルではない場合は 0 を返す +static opesize getReltblOpesize(address table) { + lblbuf* ptr = search_label(table); + if (ptr) { + opesize size = lblbufOpesize(ptr); + if (size == RELTABLE || size == RELLONGTABLE) return size; + } + return (opesize)0; +} -*/ -extern void -not_program (address from, address to) -{ - address store; - address pcend_save = PCEND; - address pc = from; - disasm code; - -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("\nnot_prog %x - %x\n", from, to); -#endif - ch_lblmod (from, DATLABEL | UNKNOWN | FORCE); - store = pc + Ofst; - PCEND = to; - while (pc < to) { - store += dis (store, &code, &pc); - unregist_data (&code.op1); - unregist_data (&code.op2); - unregist_data (&code.op3); - unregist_data (&code.op4); +// 記録した相対オフセットテーブルを全て解析し、登録した宛先アドレス数を返す +// +// addReltblAddress()を呼び出さないこと。 +int analyzeRegisteredReltbl(ArrayBuffer* rtbuf) { + int registered = 0; + size_t count; + ReltblOrder* order = getArrayBufferRawPointer(rtbuf, &count); + + if (order != NULL) { + size_t len = count; + size_t i; + for (i = 0; i < len; ++order, ++i) { + opesize size = getReltblOpesize(order->table); + + if (size == 0) { + eprintf("\n" PRI_ADRS + ": 相対オフセットテーブル以外に変更されています。", + order->table); + continue; + } + + if (size != order->size) { + eprintf("\n" PRI_ADRS + ": 相対オフセットテーブルのサイズが変更されています。", + order->table); + } + registered += analyzeRelativeTable(order->table, size, order->isProgram); } - PCEND = pcend_save; + } -#ifdef DEBUG - if (Debug & BDEBUG) - printf ("end of not_prog\n"); -#endif + freeArrayBuffer(rtbuf); + return registered; +} + +// 相対オフセットテーブルの値を持つアドレスなら真を返す +static int hasReltblData(address table) { + return (Dis.beginTEXT <= table && table < Dis.beginBSS); } +// 相対オフセットテーブルとして登録 +// order->table: テーブルのアドレス +// order->size: RELTABLE, RELLONGTABLE +// order->isProgram: TRUEなら宛先はプログラム +// mode: 0以外ならラベル登録も行う(通常は DATLABEL を指定する) +// +// いますぐ解析するとテーブル以降のデータやプログラムをテーブルの一部として +// 誤認する可能性があるので、ここではテーブルアドレスの記録だけを行う。 +// テーブルの解析は他の解析が終わって判明した限りのラベルが登録されてからとなる。 +void registerReltblOrder(ArrayBuffer* rtbuf, address table, opesize size, + boolean isProgram, lblmode mode) { + if (mode) regist_label(table, mode | size); + + if (hasReltblData(table)) { + ReltblOrder* p = getArrayBufferNewPlace(rtbuf); + *p = (ReltblOrder){table, size, isProgram}; + } +} /* - 既に PROLABEL として登録済みかどうか調べる + table から ロングワードテーブルとして登録 */ -private boolean -prolabel (address adrs) -{ - lblbuf* ptr = search_label (adrs); +extern void z_table(address table) { + address ptr = table; + address tableend = next(table + 1)->label; - if (ptr && isPROLABEL (ptr->mode)) - return TRUE; - return FALSE; + while (ptr + 4 <= tableend) { + address label = (address)peekl(ptr + Dis.Ofst); + + regist_label(label, DATLABEL | UNKNOWN); + ptr += 4; + tableend = next(ptr)->label; + } } +/* + + from から to までの領域をプログラムで無かった事にする + +*/ +extern void not_program(address from, address to) { + DisParam disp; + disasm* code = &disp.code; + + ch_lblmod(from, DATLABEL | UNKNOWN | FORCE); + + setDisParamPcPtr(&disp, from, Dis.Ofst); + disp.pcEnd = to; + + while (disp.pc < to) { + dis(&disp); + + unregist_data(code, &code->op1); + unregist_data(code, &code->op2); + unregist_data(code, &code->op3); + unregist_data(code, &code->op4); + } +} /* データとして登録する */ -private void -regist_data (disasm* code, operand* op) -{ - - if (op->opval != (address)-1) { - if (op->ea == IMMED && code->size2 == LONGSIZE && INPROG (op->opval, op->eaadrs)) - regist_label (op->opval, DATLABEL | UNKNOWN); - - else if (op->ea == PCDISP || op->ea == PCIDX || op->ea == PCIDXB - || (op->ea == AbLong && INPROG (op->opval, op->eaadrs)) - || (op->ea == AregIDXB && INPROG (op->opval, op->eaadrs) && op->exbd == 4)) - regist_label (op->opval, DATLABEL | code->size2); - - else if (op->ea == PCPOSTIDX || op->ea == PCPREIDX) { - if (op->exod == 4 && INPROG (op->opval2, op->eaadrs2)) - regist_label (op->opval2, DATLABEL | code->size2); - regist_label (op->opval, DATLABEL | (op->exbd ? LONGSIZE : code->size2)); - } - - else if (op->ea == AregPOSTIDX || op->ea == AregPREIDX) { - if (op->exbd == 4 && INPROG (op->opval, op->eaadrs)) - regist_label (op->opval, DATLABEL | LONGSIZE); - if (op->exod == 4 && INPROG (op->opval2, op->eaadrs2)) - regist_label (op->opval2, DATLABEL | code->size2); - } - } +static void regist_data(disasm* code, operand* op) { + switch (op->ea) { + default: + break; + + case IMMED: + if (code->size2 == LONGSIZE && INPROG(op->opval, op->eaadrs)) + regist_label(op->opval, DATLABEL | UNKNOWN); + break; + + case AbLong: + if (INPROG(op->opval, op->eaadrs)) + regist_label(op->opval, DATLABEL | code->size2); + break; + + case PCDISP: + case PCIDX: + regist_label(op->opval, DATLABEL | code->size2); + break; + + case AregIDXB: + if (op->exbd == 4 && INPROG(op->opval, op->eaadrs)) + regist_label(op->opval, DATLABEL | code->size2); + break; + + case AregPOSTIDX: + case AregPREIDX: + if (op->exbd == 4 && INPROG(op->opval, op->eaadrs)) + regist_label(op->opval, DATLABEL | LONGSIZE); + if (op->exod == 4 && INPROG(op->opval2, op->eaadrs2)) + regist_label(op->opval2, DATLABEL | code->size2); + break; + + case PCIDXB: + if ((op->flags & OPFLAG_PC_RELATIVE) || + (op->exbd == 4 && INPROG(op->opval, op->eaadrs))) + regist_label(op->opval, DATLABEL | code->size2); + break; + + case PCPOSTIDX: + case PCPREIDX: + if ((op->flags & OPFLAG_PC_RELATIVE) || + (op->exbd == 4 && INPROG(op->opval, op->eaadrs))) + regist_label(op->opval, DATLABEL | LONGSIZE); + if (op->exod == 4 && INPROG(op->opval2, op->eaadrs2)) + regist_label(op->opval2, DATLABEL | code->size2); + break; + } } - /* データラベルとしての登録を取り消す */ -private void -unregist_data (operand* op) -{ - - if (op->opval != (address)-1 && - (op->labelchange1 - || ((op->ea == AbLong || op->ea == IMMED) && INPROG (op->opval, op->eaadrs)) - ) - ) - unregist_label (op->opval); - - if (op->labelchange2 && INPROG (op->opval2, op->eaadrs2)) - unregist_label (op->opval2); +static void unregist_data(disasm* code, operand* op) { + switch (op->ea) { + default: + break; + + case IMMED: + if (code->size2 != LONGSIZE) break; + /* FALLTHRU */ + case AbLong: + if (INPROG(op->opval, op->eaadrs)) unregist_label(op->opval); + break; + + case PCDISP: + case PCIDX: + unregist_label(op->opval); + break; + + case AregIDXB: + if (op->exbd == 4 && INPROG(op->opval, op->eaadrs)) + unregist_label(op->opval); + break; + + case AregPOSTIDX: + case AregPREIDX: + if (op->exbd == 4 && INPROG(op->opval, op->eaadrs)) + unregist_label(op->opval); + if (op->exod == 4 && INPROG(op->opval2, op->eaadrs2)) + unregist_label(op->opval2); + break; + + case PCIDXB: + if ((op->flags & OPFLAG_PC_RELATIVE) || + (op->exbd == 4 && INPROG(op->opval, op->eaadrs))) + unregist_label(op->opval); + break; + + case PCPOSTIDX: + case PCPREIDX: + if ((op->flags & OPFLAG_PC_RELATIVE) || + (op->exbd == 4 && INPROG(op->opval, op->eaadrs))) + unregist_label(op->opval); + if (op->exod == 4 && INPROG(op->opval2, op->eaadrs2)) + unregist_label(op->opval2); + break; + } } - /* 登録済みラベルのモードを変える */ -extern boolean -ch_lblmod (address pc, lblmode mode) -{ - lblbuf* ptr = search_label (pc); - - if (regist_label (pc, mode)) { - if (ptr) - unregist_label (pc); - return TRUE; - } +extern boolean ch_lblmod(address pc, lblmode mode) { + lblbuf* ptr = search_label(pc); - return FALSE; -} + if (regist_label(pc, mode)) { + if (ptr) unregist_label(pc); + return TRUE; + } + return FALSE; +} -/* EOF */ +// EOF diff --git a/src/analyze.h b/src/analyze.h index ef987f7..904689b 100644 --- a/src/analyze.h +++ b/src/analyze.h @@ -1,41 +1,34 @@ -/* $Id: analyze.h,v 1.1 1996/10/24 04:27:42 ryo freeze $ - * - * ソースコードジェネレータ - * 自動解析モジュールヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef ANALYZE_H -#define ANALYZE_H - -#include "estruct.h" /* typedef address, enum boolean */ -#include "label.h" /* typedef lblmode */ - - -typedef enum { - ANALYZE_IGNOREFAULT, - ANALYZE_NORMAL -} analyze_mode; - -extern boolean analyze (address, analyze_mode); -extern void not_program (address, address); -extern boolean ch_lblmod (address, lblmode); -extern void relative_table (address); -extern void relative_longtable (address); -extern void z_table (address); - -extern int research_data (void); -extern void analyze_data (void); -extern void search_adrs_table (void); -extern void search_operand_label (void); -extern int search_string (int); - -extern boolean Reason_verbose; -extern boolean Arg_after_call; - -#endif /* ANALYZE_H */ - -/* EOF */ +// ソースコードジェネレータ +// 自動解析モジュール ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#ifndef ANALYZE_H +#define ANALYZE_H + +#include "estruct.h" +#include "label.h" + +typedef enum { ANALYZE_IGNOREFAULT, ANALYZE_NORMAL } analyze_mode; + +extern void setReasonVerbose(uint8_t lv); +extern boolean analyze(address, analyze_mode); +extern void not_program(address, address); +extern boolean ch_lblmod(address, lblmode); + +extern void initReltblArray(ArrayBuffer* rtbuf); +extern int analyzeRegisteredReltbl(ArrayBuffer* rtbuf); +extern void registerReltblOrder(ArrayBuffer* rtbuf, address table, opesize size, + boolean isProgram, lblmode mode); + +extern void z_table(address); +extern int research_data(boolean tweak); +extern void analyze_data(void); +extern void search_adrs_table(void); +extern void search_operand_label(void); +extern int search_string(int); + +#endif + +// EOF diff --git a/src/analyze2.c b/src/analyze2.c index 7223ae7..ba80247 100644 --- a/src/analyze2.c +++ b/src/analyze2.c @@ -1,91 +1,122 @@ -/* $Id: analyze2.c,v 1.1 1996/11/07 08:02:52 ryo freeze $ - * - * ソースコードジェネレータ - * 自動解析モジュール2 - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 自動解析モジュール2 +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik #include #include "analyze.h" #include "disasm.h" #include "estruct.h" -#include "etc.h" /* charout, peek[wl] */ +#include "etc.h" /* charout, peek[wl] */ #include "global.h" -#include "label.h" /* regist_label etc. */ -#include "offset.h" /* depend_address , nearadrs */ - - -USEOPTION option_y, option_i, option_h; - -/* #define DEBUG */ +#include "label.h" /* regist_label etc. */ +#include "offset.h" /* depend_address , nearadrs */ + +// 指定アドレスの直前でプログラムが終了しているとみなせるか調べる +// 分岐命令、条件分岐命令、サブルーチンコール命令、リターン命令なら終了とみなす。 +// +// -yオプション指定時に使う。注目しているデータ領域の直後のラベル(=データ領域の +// 終了アドレス)を指定することで、その領域がプログラム領域の可能性が高いかどうか +// を簡易的に調べる。 +static boolean isProgramEndsAt(address end) { + DisParam disp; + int len; + + if (isOdd(end)) return FALSE; + + // 2バイト前が2バイト長の命令(rts等)か + // 4バイト前が4バイト長の命令(bra.w label等)か + // 6バイト前が6バイト長の命令(jmp (label).l等)か + for (len = 2; len <= 6; len += 2) { + address pc = end - len; + + if (pc < Dis.beginTEXT) break; + + setDisParamPcPtr(&disp, pc, Dis.Ofst); + disp.pcEnd = Dis.availableTextEnd; + + if (dis(&disp) == len) { + opetype t = disp.code.opeType; + if (t != OTHER && t != UNDEF) return TRUE; + } + } + return FALSE; +} -/* +// 短い文字列の直後にプログラムがある構造を判別する +// +// 例) .dc.b 'a',0 +// .quad +// movem.l d0-d7/a0-a6,-(sp) +// -n1なら文字列化+プログラム検出できるが、文字列化しすぎるので……。 +// +static boolean analyzeProgAfterStr(address pc, address end) { + UBYTE* ptr; + + if ((end - pc) < 8) return FALSE; + + ptr = (UBYTE*)(Dis.Ofst + pc); + if (ptr[0] == 0 || (ptr[2] | ptr[3]) || ptr[4] == 0) return FALSE; + + pc += 4; // ここがプログラムかもしれない + if (!analyze(pc, ANALYZE_NORMAL)) { + unregist_label(pc); + return FALSE; + } + return TRUE; +} - データエリア中のプログラム領域を判別する - プログラムと認識したアドレスの数を返す +// 指定したラベル間がプログラム領域か判別する +// プログラム領域と認識した場合は1を返す +static int analyzeDataAsProgram(lblbuf* start, lblbuf* end, boolean tweak) { + address pc = start->label; + lblmode mode = start->mode; + analyze_mode analyzeMode; + + if (isOdd(pc) || isPROLABEL(mode) || isTABLE(mode)) return 0; + if ((mode & FORCE) && !tweak) return 0; + if (lblmodeOpesize(mode) != UNKNOWN) return 0; + if (depend_address(pc)) return 0; + + if (Dis.y && !isProgramEndsAt(end->label)) return 0; + + if (mode & FORCE) { + // -n3(既定値)で検出できないプログラム領域の判別 + // あまりにも決め打ちすぎるので、オプション化したほうがよいかも + if (analyzeProgAfterStr(pc, end->label)) return 1; + return 0; + } + + if ((ULONG)(end->label - pc) == 2 && isDATLABEL(end->mode) && + peekw(Dis.Ofst + pc) == 0xffff) { + // データ直前の0xffffはDOS _CHANGE_PRではなく-1という値とみなす + return 0; + } + + // 以下の解析により end->mode が変更される可能性があるので注意 + analyzeMode = Dis.i ? ANALYZE_IGNOREFAULT : ANALYZE_NORMAL; + if (analyze(pc, analyzeMode)) return 1; + + return 0; +} -*/ -extern int -research_data (void) -{ - lblbuf* lptr = next (BeginTEXT); - address pc = lptr->label; - lblmode nmode = lptr->mode; /* 次の領域の属性 */ - lblmode mode = PROLABEL; /* 現在の領域の属性 */ - int rc = 0; - -#ifdef DEBUG - printf ("enter research_data\n"); -#endif - - PCEND = Available_text_end; - while (pc < Available_text_end) { - address nlabel; - - mode = nmode; - lptr = Next (lptr); /* lptr = next (pc + 1) */ - nlabel = lptr->label; - nmode = lptr->mode; - -#ifdef DEBUG - printf ("tst %x(%x),%x\n", pc, mode, nlabel); -#endif - if (!((long)pc & 1) && isDATLABEL (mode) && !(mode & FORCE) - && !depend_address (pc) && (mode & 0xff) == UNKNOWN && !isTABLE (mode)) { - address dummy = pc; - disasm code; - - if (!option_y - || (!((ULONG)nlabel & 1) && - ( (dis (nlabel - 2 + Ofst, &code, &dummy), - (code.flag != OTHER && code.flag != UNDEF)) - || (dis (nlabel - 4 + Ofst, &code, &dummy) == 4 - && (code.flag != OTHER && code.flag != UNDEF)) - || (dis (nlabel - 6 + Ofst, &code, &dummy) == 6 - && (code.flag != OTHER && code.flag != UNDEF)) - )) - ) { - if (analyze (pc, option_i ? ANALYZE_IGNOREFAULT : ANALYZE_NORMAL)) { - rc++; -#ifdef DEBUG - printf ("* maybe program %5x - %5x\n", pc, nlabel); -#endif - } - } - } - pc = nlabel; - } +// データエリア中のプログラム領域を判別する +// プログラムと認識したアドレスの数を返す +int research_data(boolean tweak) { + lblbuf* lptr = next(Dis.beginTEXT); + const address pcEnd = Dis.availableTextEnd; + int found = 0; -#ifdef DEBUG - printf ("exit research_data (rc=%d)\n", rc); -#endif + while (lptr->label < pcEnd) { + lblbuf* nextlbl = Next(lptr); + found += analyzeDataAsProgram(lptr, nextlbl, tweak); + lptr = nextlbl; + } - return rc; + return found; } /* @@ -94,184 +125,75 @@ research_data (void) データ領域にある 0x4e75(rts) の次のアドレスを登録する */ -extern void -analyze_data (void) -{ - address data_from, adrs; - address data_to = BeginTEXT; - - do { - data_from = next_datlabel (data_to)->label; - data_to = (address) min ((ULONG) next_prolabel (data_from)->label, - (ULONG) BeginBSS); - charout ('#'); - - /* アドレス依存のデータがあれば、そのアドレスを登録する */ - for (adrs = data_from; - (adrs = nearadrs (adrs)) < data_to && adrs < data_to; - adrs += 4) { -#ifdef DEBUG - printf ("depend_address %x\n", (address) peekl (adrs + Ofst)); -#endif - regist_label ((address) peekl (adrs + Ofst), DATLABEL | UNKNOWN); - } - - /* rts の次のアドレスを登録する */ - if (option_h && data_from < Available_text_end) { - for (adrs = data_from + ((int)data_from & 1); adrs < data_to; adrs += 2) { - if (peekw (adrs + Ofst) == 0x4e75) { -#ifdef DEBUG - printf ("found 0x4e75 in %x\n", (int) adrs); -#endif - regist_label (adrs + 2, DATLABEL | UNKNOWN); - } - -#ifdef OSKDIS - /* link 命令に注目 */ - if ((peekw (adrs + Ofst) & 0xfff8) == 0x4e50) - regist_label (adrs, DATLABEL | UNKNOWN); -#endif /* OSKDIS */ - - } - } - - } while (data_to < BeginBSS && adrs != (address)-1); -} - - -/* - - アドレステーブルを捜す - -*/ -extern void -search_adrs_table (void) -{ - lblbuf* lptr = next (BeginTEXT); - address pc = lptr->label; - lblmode nmode = lptr->mode; - - while (pc < (address) BeginBSS) { - address nlabel; - lblmode mode = nmode; - - lptr = next (pc + 1); - nlabel = lptr->label; - nmode = lptr->mode; -#ifdef DEBUG - printf ("chk1(%x)", pc); -#endif - if (isDATLABEL (mode)) { - address labeltop; - int count; - - pc = (address) min((ULONG) nearadrs (pc), (ULONG) nlabel); -#ifdef DEBUG - printf ("chk2(%x)", pc); -#endif - labeltop = pc; - for (count = 0; depend_address (pc) && pc < nlabel; count++) - pc += 4; -#ifdef DEBUG - printf ("count(%d)\n", count); -#endif - if (count >= 3) { - int i; -#ifdef DEBUG - printf ("* found address table at %6x %d\n", pc - count * 4, count); -#endif - for (i = 0; i < count; i++) { - address label = (address) peekl (labeltop + i * 4 + Ofst); - analyze (label, (option_i ? ANALYZE_IGNOREFAULT : ANALYZE_NORMAL)); - } - } - } - pc = nlabel; +extern void analyze_data(void) { + address data_from, adrs; + address data_to = Dis.beginTEXT; + + do { + data_from = next_datlabel(data_to)->label; + data_to = MIN(next_prolabel(data_from)->label, Dis.beginBSS); + charout('#'); + + /* アドレス依存のデータがあれば、そのアドレスを登録する */ + for (adrs = data_from; (adrs = nearadrs(adrs)) < data_to && adrs < data_to; + adrs += 4) { + regist_label((address)peekl(adrs + Dis.Ofst), DATLABEL | UNKNOWN); } -} - - - - -#ifdef OSKDIS -/* - IDataから初期化データを登録する + if (Dis.h && data_from < Dis.availableTextEnd) { + for (adrs = data_from + ((int)data_from & 1); adrs < data_to; adrs += 2) { + UWORD word1 = peekw(adrs + Dis.Ofst); + + if (word1 == 0x4e75) { + // rts の次のアドレスを登録する + regist_label(adrs + 2, DATLABEL | UNKNOWN); + } + + if (Dis.findLinkW) { + // link 命令に注目 + if ((word1 & 0xfff8) == 0x4e50) + regist_label(adrs, DATLABEL | UNKNOWN); + } + } + } -*/ -extern void -analyze_idata (void) -{ - address offset = (address) (Top - (ULONG) Head.base + (ULONG) HeadOSK.idata); - - BeginDATA = BeginBSS + peekl (offset + 0); - regist_label (BeginDATA, DATLABEL | UNKNOWN); - regist_label (BeginDATA + peekl (offset + 4), DATLABEL | UNKNOWN); + } while (data_to < Dis.beginBSS && adrs != (address)-1); } /* - IRefsを解析 + アドレステーブルを捜す */ -static void -analyze_irefs_sub (int codelbl, ULONG* idatp, ULONG offset, int mode) -{ - if (peekl (idatp) <= offset && offset < (peekl (idatp) + peekl (&idatp[1]))) { - address p = (address) &idatp[2]; - ULONG* w = (ULONG*) (p + offset - peekl (idatp)); - - regist_label (peekl (w) + codelbl ? 0 : BeginBSS, mode); - } -} - -extern void -analyze_irefs (void) -{ - struct REFSTBL { - UWORD base; - UWORD cnt; - } *offset; - ULONG* idatp = (ULONG*) (Top - (ULONG) Head.base + (ULONG) HeadOSK.idata); - - offset = (struct REFSTBL*) (Top - (ULONG) Head.base + (ULONG) HeadOSK.irefs); - - while (ofset->cnt) { /* コードポインタ */ - ULONG wk = BeginBSS + ((ULONG) ofset->base << 16); - UWORD* p = (UWORD*) &ofset[1]; - int i; - - for (i = 0; i < ofset->cnt; i++) { - charout ('#'); -#ifdef DEBUG - eprintf (":regist_label:%08x\n", BeginBSS + wk + peekw (p)); -#endif - regist_label (wk + peekw (p), DATLABEL | LONGSIZE | CODEPTR | FORCE); - regist_label (wk + peekw (p) + 4, DATLABEL | UNKNOWN); - analyze_irefs_sub (TRUE, idatp, peekl (p), DATLABEL | UNKNOWN); - p++; - } - offset = (struct REFSTBL*) p; - } - offset++; - while (ofset->cnt) { /* データポインタ */ - ULONG wk = BeginBSS + ((ULONG) ofset->base << 16); - UWORD* p = (UWORD*) &ofset[1]; - int i; - - for (i = 0; i < ofset->cnt; i++) { - charout ('#'); -#ifdef DEBUG - eprintf (":regist_label:%08x\n", BeginBSS + wk + peekw (p)); -#endif - regist_label (wk + peekw (p), DATLABEL | LONGSIZE | DATAPTR | FORCE); - regist_label (wk + peekw (p) + 4, DATLABEL | UNKNOWN); - analyze_irefs_sub (FALSE, idatp, peekl (p), DATLABEL | UNKNOWN); - p++; - } - offset = (struct REFSTBL*) p; +extern void search_adrs_table(void) { + lblbuf* lptr = next(Dis.beginTEXT); + address pc = lptr->label; + lblmode nmode = lptr->mode; + + while (pc < Dis.beginBSS) { + address nlabel; + lblmode mode = nmode; + + lptr = next(pc + 1); + nlabel = lptr->label; + nmode = lptr->mode; + if (isDATLABEL(mode)) { + address labeltop; + int count; + + pc = MIN(nearadrs(pc), nlabel); + labeltop = pc; + for (count = 0; depend_address(pc) && pc < nlabel; count++) pc += 4; + if (count >= 3) { + int i; + for (i = 0; i < count; i++) { + address label = (address)peekl(labeltop + i * 4 + Dis.Ofst); + analyze(label, (Dis.i ? ANALYZE_IGNOREFAULT : ANALYZE_NORMAL)); + } + } } + pc = nlabel; + } } -#endif /* OSKDIS */ -/* EOF */ +// EOF diff --git a/src/avl/avl.c b/src/avl/avl.c index 317db16..e78e111 100644 --- a/src/avl/avl.c +++ b/src/avl/avl.c @@ -4,12 +4,11 @@ Copyright (C) 1991 K.Abe - E-Mail k-abe@ics.osaka-u.ac.jp - Nifty Serve PDC02373 + E-Mail k-abe@ics.osaka-u.ac.jp + Nifty Serve PDC02373 - - AVL_delete() bugfix patch: - Copyleft 1997 Tachibana Eriko. + Copyright (C) 1997 TcbnErik ... AVL_delete() bugfix patch + Copyright (C) 2023 TcbnErik ... style */ @@ -17,60 +16,43 @@ #include #ifdef AVL_LIBRARY_ONCE - #error You cannot include this file twice. +#error You cannot include this file twice. #endif #define AVL_LIBRARY_ONCE #include "avl.h" #ifndef __GNUC__ - #define inline +#define inline #endif /* __GNUC__ */ - -#if defined( PROFILE ) && defined( __HUMAN68K__ ) - #define avl_private extern +#if defined(PROFILE) && defined(__HUMAN68K__) +#define avl_private extern #else - #define avl_private static +#define avl_private static #endif - -/* avl_private functions prototypes */ -avl_private inline avl_node *avl_create_node(void); -avl_private inline int avl_depth(avl_node *node_ptr); -avl_private inline void avl_calc_node_depth(avl_node *node_ptr); -avl_private void avl_adjust_depth(avl_root_node *root, avl_node *node_ptr); -avl_private avl_node *avl_balance(avl_root_node *root, avl_node *node_ptr); -avl_private inline void avl_adjust_parent(avl_root_node *root, avl_node *node_ptr, - avl_node *rotate_node); -avl_private void avl_print_tree(avl_root_node *root, avl_node *node_ptr, int level); -avl_private int avl_check_tree( avl_root_node* root, avl_node *node_ptr ); - - #ifdef AVL_LIBRARY - /* if compiled as library. */ - #define AVL_COMPARE(data1,data2) (*(root->compare_function))(data1,data2) - #ifndef AVL_NOMACRO - #define AVL_NOMACRO - #endif /* AVL_NOMACRO */ - #define avl_public extern +/* if compiled as library. */ +#define AVL_COMPARE(data1, data2) (*(root->compare_function))(data1, data2) +#ifndef AVL_NOMACRO +#define AVL_NOMACRO +#endif /* AVL_NOMACRO */ +#define avl_public extern #else - /* if included */ - #ifndef AVL_COMPARE - #error You must define AVL_COMPARE before include this file. - #endif /* AVL_COMPARE */ - #define avl_public avl_private +/* if included */ +#ifndef AVL_COMPARE +#error You must define AVL_COMPARE before include this file. +#endif /* AVL_COMPARE */ +#define avl_public avl_private #endif /* AVL_LIBRARY */ -#define AVL_BALANCE(node_ptr) ((node_ptr)->right_depth - (node_ptr)->left_depth) - +#define AVL_BALANCE(node_ptr) ((node_ptr)->right_depth - (node_ptr)->left_depth) #if 0 static char avl_version[] = "Generic AVL-tree Library v0.1 (Copyright (C) 1991 K.Abe)"; #endif - - /* 節点の回転の下請け処理 @@ -83,433 +65,381 @@ static char avl_version[] = "Generic AVL-tree Library v0.1 (Copyright (C) 1991 K (node) (node_ptr) (node) (rotate_node) (node_ptr) */ -avl_private inline void avl_adjust_parent( root , node_ptr , rotate_node ) -avl_root_node *root; -avl_node *node_ptr , *rotate_node; -{ - if( node_ptr->parent == NULL ) - root->avl_tree = rotate_node; - else if( node_ptr->parent->left == node_ptr ) - node_ptr->parent->left = rotate_node; - else - node_ptr->parent->right = rotate_node; +avl_private inline void avl_adjust_parent(avl_root_node *root, + avl_node *node_ptr, + avl_node *rotate_node) { + if (node_ptr->parent == NULL) + root->avl_tree = rotate_node; + else if (node_ptr->parent->left == node_ptr) + node_ptr->parent->left = rotate_node; + else + node_ptr->parent->right = rotate_node; } - /* ある節点を根とした場合の木の高さを返す */ -avl_private inline int avl_depth( node_ptr ) -avl_node *node_ptr; -{ - if( node_ptr == NULL ) - return -1; - return ( node_ptr->left_depth > node_ptr->right_depth ? - node_ptr->left_depth : node_ptr->right_depth ); +avl_private inline int avl_depth(avl_node *node_ptr) { + if (node_ptr == NULL) return -1; + return (node_ptr->left_depth > node_ptr->right_depth ? node_ptr->left_depth + : node_ptr->right_depth); } - /* 節点の左右の部分木の深さを代入する */ -avl_private inline void avl_calc_node_depth( node_ptr ) -avl_node *node_ptr; -{ - if( node_ptr != NULL ) { - node_ptr->left_depth = avl_depth( node_ptr->left ) + 1; - node_ptr->right_depth = avl_depth( node_ptr->right ) + 1; - } +avl_private inline void avl_calc_node_depth(avl_node *node_ptr) { + if (node_ptr != NULL) { + node_ptr->left_depth = avl_depth(node_ptr->left) + 1; + node_ptr->right_depth = avl_depth(node_ptr->right) + 1; + } } - /* - ある節点から親に向かって、左右の部分木の高さを計算し直す - バランスがくずれていたらバランス化する + バランスがくずれた節点をバランス化する */ -avl_private void avl_adjust_depth( root , node_ptr ) -avl_root_node *root; -avl_node *node_ptr; -{ - avl_node *rotate_node; - - for( ; node_ptr != NULL ; node_ptr = node_ptr->parent ) { - avl_calc_node_depth( node_ptr ); - - if( AVL_BALANCE( node_ptr ) == 2 || AVL_BALANCE( node_ptr ) == -2 ) { - if( ( rotate_node = avl_balance( root , node_ptr ) ) != NULL ) { - avl_calc_node_depth( rotate_node->left ); - avl_calc_node_depth( rotate_node->right ); - avl_calc_node_depth( rotate_node ); - } - } +avl_private avl_node *avl_balance(avl_root_node *root, avl_node *node_ptr) { + avl_node *swap; + avl_node *left_node, *right_node; + + if (node_ptr->left_depth > node_ptr->right_depth) { + if (AVL_BALANCE(node_ptr->left) * AVL_BALANCE(node_ptr) > 0) { + avl_adjust_parent(root, node_ptr, node_ptr->left); + node_ptr->left->parent = node_ptr->parent; + swap = node_ptr->left->right; + if (swap) swap->parent = node_ptr; + node_ptr->left->right = node_ptr; + node_ptr->parent = node_ptr->left; + node_ptr->left = swap; + return node_ptr->parent; + } else /* if ( AVL_BALANCE( node_ptr->left ) * AVL_BALANCE( node_ptr ) < 0 ) + */ + { + left_node = node_ptr->left; + left_node->right->parent = node_ptr; + swap = left_node->right->left; + if (swap) swap->parent = left_node; + left_node->right->left = left_node; + left_node->parent = left_node->right; + left_node->right = swap; + node_ptr->left = left_node->parent; + + avl_adjust_parent(root, node_ptr, node_ptr->left); + swap = node_ptr->left->right; + if (swap) swap->parent = node_ptr; + node_ptr->left->right = node_ptr; + node_ptr->left->parent = node_ptr->parent; + node_ptr->parent = node_ptr->left; + node_ptr->left = swap; + return node_ptr->parent; } + } else if (node_ptr->left_depth < node_ptr->right_depth) { + if (AVL_BALANCE(node_ptr->right) * AVL_BALANCE(node_ptr) > 0) { + avl_adjust_parent(root, node_ptr, node_ptr->right); + node_ptr->right->parent = node_ptr->parent; + swap = node_ptr->right->left; + if (swap) swap->parent = node_ptr; + node_ptr->right->left = node_ptr; + node_ptr->parent = node_ptr->right; + node_ptr->right = swap; + return node_ptr->parent; + } else /* if( AVL_BALANCE( node_ptr->right ) * AVL_BALANCE( node_ptr ) < 0 ) + */ + { + right_node = node_ptr->right; + right_node->left->parent = node_ptr; + swap = right_node->left->right; + if (swap) swap->parent = right_node; + right_node->left->right = right_node; + right_node->parent = right_node->left; + right_node->left = swap; + node_ptr->right = right_node->parent; + + avl_adjust_parent(root, node_ptr, node_ptr->right); + swap = node_ptr->right->left; + if (swap) swap->parent = node_ptr; + node_ptr->right->left = node_ptr; + node_ptr->right->parent = node_ptr->parent; + node_ptr->parent = node_ptr->right; + node_ptr->right = swap; + return node_ptr->parent; + } + } + /* NOT REACHED */ + return NULL; } - /* - バランスがくずれた節点をバランス化する + ある節点から親に向かって、左右の部分木の高さを計算し直す + バランスがくずれていたらバランス化する */ -avl_private avl_node *avl_balance( root , node_ptr ) -avl_root_node *root; -avl_node *node_ptr; -{ - avl_node *swap; - avl_node *left_node , *right_node; - - if( node_ptr->left_depth > node_ptr->right_depth ) { - if( AVL_BALANCE( node_ptr->left ) * AVL_BALANCE( node_ptr ) > 0 ) { - avl_adjust_parent( root , node_ptr , node_ptr->left ); - node_ptr->left->parent = node_ptr->parent; - swap = node_ptr->left->right; - if( swap ) swap->parent = node_ptr; - node_ptr->left->right = node_ptr; - node_ptr->parent = node_ptr->left; - node_ptr->left = swap; - return node_ptr->parent; - } else /* if ( AVL_BALANCE( node_ptr->left ) * AVL_BALANCE( node_ptr ) < 0 ) */ { - left_node = node_ptr->left; - left_node->right->parent = node_ptr; - swap = left_node->right->left; - if( swap ) swap->parent = left_node; - left_node->right->left = left_node; - left_node->parent = left_node->right; - left_node->right = swap; - node_ptr->left = left_node->parent; - - avl_adjust_parent( root , node_ptr , node_ptr->left ); - swap = node_ptr->left->right; - if( swap ) swap->parent = node_ptr; - node_ptr->left->right = node_ptr; - node_ptr->left->parent = node_ptr->parent; - node_ptr->parent = node_ptr->left; - node_ptr->left = swap; - return node_ptr->parent; - } - } else if( node_ptr->left_depth < node_ptr->right_depth ) { - if( AVL_BALANCE( node_ptr->right ) * AVL_BALANCE( node_ptr ) > 0 ) { - avl_adjust_parent( root , node_ptr , node_ptr->right ); - node_ptr->right->parent = node_ptr->parent; - swap = node_ptr->right->left; - if( swap ) swap->parent = node_ptr; - node_ptr->right->left = node_ptr; - node_ptr->parent = node_ptr->right; - node_ptr->right = swap; - return node_ptr->parent; - } else /* if( AVL_BALANCE( node_ptr->right ) * AVL_BALANCE( node_ptr ) < 0 ) */ { - right_node = node_ptr->right; - right_node->left->parent = node_ptr; - swap = right_node->left->right; - if( swap ) swap->parent = right_node; - right_node->left->right = right_node; - right_node->parent = right_node->left; - right_node->left = swap; - node_ptr->right = right_node->parent; - - avl_adjust_parent( root , node_ptr , node_ptr->right ); - swap = node_ptr->right->left; - if( swap ) swap->parent = node_ptr; - node_ptr->right->left = node_ptr; - node_ptr->right->parent = node_ptr->parent; - node_ptr->parent = node_ptr->right; - node_ptr->right = swap; - return node_ptr->parent; - } +avl_private void avl_adjust_depth(avl_root_node *root, avl_node *node_ptr) { + avl_node *rotate_node; + + for (; node_ptr != NULL; node_ptr = node_ptr->parent) { + avl_calc_node_depth(node_ptr); + + if (AVL_BALANCE(node_ptr) == 2 || AVL_BALANCE(node_ptr) == -2) { + if ((rotate_node = avl_balance(root, node_ptr)) != NULL) { + avl_calc_node_depth(rotate_node->left); + avl_calc_node_depth(rotate_node->right); + avl_calc_node_depth(rotate_node); + } } - /* NOT REACHED */ - return NULL; + } } - /* ライブラリ側の節点を作る */ -avl_private inline avl_node *avl_create_node() -{ - avl_node *node_ptr; - if( ( node_ptr = malloc( sizeof( avl_node ) ) ) == NULL ) { - fputs( "create_node: malloc failed.\n" , stderr ); - exit( 1 ); - } - node_ptr->left = node_ptr->right = node_ptr->parent = NULL; - node_ptr->left_depth = node_ptr->right_depth = 0; - node_ptr->next = node_ptr->previous = NULL; - node_ptr->data = NULL; - return node_ptr; +avl_private inline avl_node *avl_create_node(void) { + avl_node *node_ptr; + if ((node_ptr = malloc(sizeof(avl_node))) == NULL) { + fputs("create_node: malloc failed.\n", stderr); + exit(1); + } + node_ptr->left = node_ptr->right = node_ptr->parent = NULL; + node_ptr->left_depth = node_ptr->right_depth = 0; + node_ptr->next = node_ptr->previous = NULL; + node_ptr->data = NULL; + return node_ptr; } - #ifdef AVL_NOMACRO /* AVL-tree のノードからユーザーのデータを得る */ -avl_public AVL_USERDATA *AVL_get_data( node_ptr ) -avl_node *node_ptr; -{ - return node_ptr->data; +avl_public AVL_USERDATA *AVL_get_data(avl_node *node_ptr) { + return node_ptr->data; } - /* AVL-tree 中のノードの数を返す */ -avl_public int AVL_data_number( root ) -avl_root_node *root; -{ - return root->data_number; +avl_public int AVL_data_number(avl_root_node *root) { + return root->data_number; } - /* 最小のノードを返す */ -avl_public avl_node *AVL_get_min( root ) -avl_root_node *root; -{ - return root->min; -} - +avl_public avl_node *AVL_get_min(avl_root_node *root) { return root->min; } /* 最大のノードを返す */ -avl_public avl_node *AVL_get_max( root ) -avl_root_node *root; -{ - return root->max; -} - +avl_public avl_node *AVL_get_max(avl_root_node *root) { return root->max; } /* 次の要素を返す */ -avl_public avl_node *AVL_next( node_ptr ) -avl_node *node_ptr; -{ - return node_ptr->next; -} - +avl_public avl_node *AVL_next(avl_node *node_ptr) { return node_ptr->next; } /* 前の要素を返す */ -avl_public avl_node *AVL_previous( node_ptr ) -avl_node *node_ptr; -{ - return node_ptr->previous; +avl_public avl_node *AVL_previous(avl_node *node_ptr) { + return node_ptr->previous; } #endif /* AVL_NOMACRO */ - - /* AVL-tree をつくる */ -avl_public avl_root_node* AVL_create_tree( compare_func , free_func , print_func ) -int (*compare_func)( AVL_USERDATA* , AVL_USERDATA* ); -void (*free_func)( AVL_USERDATA* ); -void (*print_func)( AVL_USERDATA* ); -{ - avl_root_node *root; - if( ( root = malloc( sizeof( avl_root_node ) ) ) == NULL ) { - fputs( "AVL_create_tree: malloc failed.\n" , stderr ); - exit( 1 ); - } +avl_public avl_root_node *AVL_create_tree(int (*compare_func)(AVL_USERDATA *, + AVL_USERDATA *), + void (*free_func)(AVL_USERDATA *), + void (*print_func)(AVL_USERDATA *)) { + avl_root_node *root; + if ((root = malloc(sizeof(avl_root_node))) == NULL) { + fputs("AVL_create_tree: malloc failed.\n", stderr); + exit(1); + } #ifdef AVL_LIBRARY - if( compare_func == NULL ) { - fprintf( stderr , "AVL_create_tree: compare function must not be NULL.\n" ); - exit( 1 ); - } + if (compare_func == NULL) { + fprintf(stderr, "AVL_create_tree: compare function must not be NULL.\n"); + exit(1); + } #endif /* AVL_LIBRARY */ - root->avl_tree = root->min = root->max = NULL; - root->data_number = 0; - root->compare_function = compare_func; - root->free_function = free_func; - root->print_function = print_func; - return root; + root->avl_tree = root->min = root->max = NULL; + root->data_number = 0; + root->compare_function = compare_func; + root->free_function = free_func; + root->print_function = print_func; + return root; } - +#ifndef AVL_NO_DESTROY_TREE /* AVL-tree を壊す */ -avl_public void AVL_destroy_tree( root ) -avl_root_node *root; -{ - avl_node *node_ptr; - avl_node *next; - - for( node_ptr = root->avl_tree ; node_ptr != NULL ; node_ptr = next ) { - next = node_ptr->next; - (*( root->free_function ))( node_ptr->data ); - free( node_ptr ); - } - free( root ); +avl_public void AVL_destroy_tree(avl_root_node *root) { + avl_node *node_ptr; + avl_node *next; + + for (node_ptr = root->avl_tree; node_ptr != NULL; node_ptr = next) { + next = node_ptr->next; + (*(root->free_function))(node_ptr->data); + free(node_ptr); + } + free(root); } - +#endif /* AVL-tree に挿入する */ -avl_public avl_node *AVL_insert( root , data ) -avl_root_node *root; -AVL_USERDATA *data; -{ - avl_node *node_ptr; - avl_node *old_ptr; - avl_node *new_node; - avl_node *last_right_node = NULL; - int comp = 0; - - /* do search */ - old_ptr = NULL; - node_ptr = root->avl_tree; - while( node_ptr != NULL ) { - old_ptr = node_ptr; - comp = AVL_COMPARE( data , node_ptr->data ); - if( comp < 0 ) - node_ptr = node_ptr->left; - else if( comp > 0 ) { - last_right_node = node_ptr; - node_ptr = node_ptr->right; - } else { - /* Already exists. return NULL to caller. */ - return NULL; - } +avl_public avl_node *AVL_insert(avl_root_node *root, AVL_USERDATA *data) { + avl_node *node_ptr; + avl_node *old_ptr; + avl_node *new_node; + avl_node *last_right_node = NULL; + int comp = 0; + + /* do search */ + old_ptr = NULL; + node_ptr = root->avl_tree; + while (node_ptr != NULL) { + old_ptr = node_ptr; + comp = AVL_COMPARE(data, node_ptr->data); + if (comp < 0) + node_ptr = node_ptr->left; + else if (comp > 0) { + last_right_node = node_ptr; + node_ptr = node_ptr->right; + } else { + /* Already exists. return NULL to caller. */ + return NULL; } - /* do insert */ - root->data_number++; - if( old_ptr == NULL ) { - root->avl_tree = new_node = avl_create_node(); - new_node->data = data; - root->min = root->max = new_node; + } + /* do insert */ + root->data_number++; + if (old_ptr == NULL) { + root->avl_tree = new_node = avl_create_node(); + new_node->data = data; + root->min = root->max = new_node; + } else { + if (comp > 0) { + old_ptr->right = new_node = avl_create_node(); /* AVL tree */ + old_ptr->right_depth = 1; + new_node->next = old_ptr->next; /* linked-list */ + new_node->previous = old_ptr; + old_ptr->next = new_node; + if (new_node->next) + new_node->next->previous = new_node; + else + root->max = new_node; } else { - if( comp > 0 ) { - old_ptr->right = new_node = avl_create_node(); /* AVL tree */ - old_ptr->right_depth = 1; - new_node->next = old_ptr->next; /* linked-list */ - new_node->previous = old_ptr; - old_ptr->next = new_node; - if( new_node->next ) - new_node->next->previous = new_node; - else - root->max = new_node; - } else { - old_ptr->left = new_node = avl_create_node(); /* AVL tree */ - old_ptr->left_depth = 1; - new_node->next = old_ptr; /* linked-list */ - new_node->previous = last_right_node; - old_ptr->previous = new_node; - if( last_right_node ) - last_right_node->next = new_node; - else - root->min = new_node; - } - new_node->parent = old_ptr; - new_node->data = data; - avl_adjust_depth( root , old_ptr->parent ); + old_ptr->left = new_node = avl_create_node(); /* AVL tree */ + old_ptr->left_depth = 1; + new_node->next = old_ptr; /* linked-list */ + new_node->previous = last_right_node; + old_ptr->previous = new_node; + if (last_right_node) + last_right_node->next = new_node; + else + root->min = new_node; } - return new_node; + new_node->parent = old_ptr; + new_node->data = data; + avl_adjust_depth(root, old_ptr->parent); + } + return new_node; } - /* AVL-tree から削除 */ -avl_public void AVL_delete( root , delete_node ) -avl_root_node *root; -avl_node *delete_node; -{ - avl_node *swap; - avl_node *adjust; - - if( delete_node == NULL ) { - fputs( "AVL_delete: delete_node nil\n" , stderr ); - exit( 1 ); +avl_public void AVL_delete(avl_root_node *root, avl_node *delete_node) { + avl_node *swap; + avl_node *adjust; + + if (delete_node == NULL) { + fputs("AVL_delete: delete_node nil\n", stderr); + exit(1); + } + + if (delete_node->left == NULL) { + if (delete_node->right == NULL) { + /* 末端の葉 */ + avl_adjust_parent(root, delete_node, NULL); + adjust = delete_node->parent; + } else { + /* 右にだけ枝がある節 */ + avl_adjust_parent(root, delete_node, delete_node->right); + delete_node->right->parent = delete_node->parent; + adjust = delete_node->parent; } - - if( delete_node->left == NULL ) { - if( delete_node->right == NULL ) { - /* 末端の葉 */ - avl_adjust_parent( root , delete_node , NULL ); - adjust = delete_node->parent; - } else { - /* 右にだけ枝がある節 */ - avl_adjust_parent( root , delete_node , delete_node->right ); - delete_node->right->parent = delete_node->parent; - adjust = delete_node->parent; - } + } else { + if (delete_node->right == NULL) { + /* 左にだけ枝がある節 */ + avl_adjust_parent(root, delete_node, delete_node->left); + delete_node->left->parent = delete_node->parent; + adjust = delete_node->parent; } else { - if( delete_node->right == NULL ) { - /* 左にだけ枝がある節 */ - avl_adjust_parent( root , delete_node , delete_node->left ); - delete_node->left->parent = delete_node->parent; - adjust = delete_node->parent; - } else { - /* 左右両方に枝がある節 */ - adjust = swap = delete_node->previous; - if( swap != delete_node->left ) { - swap->parent->right = swap->left; - if( swap->left ) - swap->left->parent = swap->parent; - swap->left = delete_node->left; - swap->left->parent = swap; - adjust = swap->parent; - } - avl_adjust_parent( root , delete_node , swap ); - swap->parent = delete_node->parent; - swap->right = delete_node->right; - swap->right->parent = swap; - } + /* 左右両方に枝がある節 */ + adjust = swap = delete_node->previous; + if (swap != delete_node->left) { + swap->parent->right = swap->left; + if (swap->left) swap->left->parent = swap->parent; + swap->left = delete_node->left; + swap->left->parent = swap; + adjust = swap->parent; + } + avl_adjust_parent(root, delete_node, swap); + swap->parent = delete_node->parent; + swap->right = delete_node->right; + swap->right->parent = swap; } - - if( delete_node->previous == NULL ) - root->min = delete_node->next; - else - delete_node->previous->next = delete_node->next; - if( delete_node->next == NULL ) - root->max = delete_node->previous; - else - delete_node->next->previous = delete_node->previous; - avl_adjust_depth( root , adjust ); - root->data_number--; - (*( root->free_function ))( delete_node->data ); - free( delete_node ); - - return; + } + + if (delete_node->previous == NULL) + root->min = delete_node->next; + else + delete_node->previous->next = delete_node->next; + if (delete_node->next == NULL) + root->max = delete_node->previous; + else + delete_node->next->previous = delete_node->previous; + avl_adjust_depth(root, adjust); + root->data_number--; + (*(root->free_function))(delete_node->data); + free(delete_node); + + return; } - /* AVL-tree から検索する @@ -517,27 +447,23 @@ avl_node *delete_node; 見つからない場合 NULL を返す */ -avl_public avl_node *AVL_search( root , data ) -avl_root_node *root; -AVL_USERDATA *data; -{ - avl_node *node_ptr; - int comp; - - node_ptr = root->avl_tree; - while( node_ptr != NULL ) { - comp = AVL_COMPARE( data , node_ptr->data ); - if( comp < 0 ) - node_ptr = node_ptr->left; - else if( comp > 0 ) - node_ptr = node_ptr->right; - else - return node_ptr; /* found */ - } - return NULL; /* not found */ +avl_public avl_node *AVL_search(avl_root_node *root, AVL_USERDATA *data) { + avl_node *node_ptr; + int comp; + + node_ptr = root->avl_tree; + while (node_ptr != NULL) { + comp = AVL_COMPARE(data, node_ptr->data); + if (comp < 0) + node_ptr = node_ptr->left; + else if (comp > 0) + node_ptr = node_ptr->right; + else + return node_ptr; /* found */ + } + return NULL; /* not found */ } - /* AVL-tree から data の次を検索する @@ -547,35 +473,32 @@ AVL_USERDATA *data; 見つからない場合 NULL を返す */ -avl_public avl_node *AVL_search_next( root , data ) -avl_root_node *root; -AVL_USERDATA *data; -{ - avl_node *node_ptr , *old_ptr = NULL; - int comp = 0; - - node_ptr = root->avl_tree; - while( node_ptr != NULL ) { - old_ptr = node_ptr; - comp = AVL_COMPARE( data , node_ptr->data ); - if( comp < 0 ) - node_ptr = node_ptr->left; - else if( comp > 0 ) - node_ptr = node_ptr->right; - else - return node_ptr; /* found */ - } - /* not found */ - if( old_ptr ) { - if( comp > 0 ) - return old_ptr->next; - else - return old_ptr; - } - return NULL; +avl_public avl_node *AVL_search_next(avl_root_node *root, AVL_USERDATA *data) { + avl_node *node_ptr, *old_ptr = NULL; + int comp = 0; + + node_ptr = root->avl_tree; + while (node_ptr != NULL) { + old_ptr = node_ptr; + comp = AVL_COMPARE(data, node_ptr->data); + if (comp < 0) + node_ptr = node_ptr->left; + else if (comp > 0) + node_ptr = node_ptr->right; + else + return node_ptr; /* found */ + } + /* not found */ + if (old_ptr) { + if (comp > 0) + return old_ptr->next; + else + return old_ptr; + } + return NULL; } - +#ifndef AVL_NO_SEARCH_PREVIOUS /* AVL-tree から data の前を検索する @@ -585,160 +508,143 @@ AVL_USERDATA *data; 見つからない場合 NULL を返す */ -avl_public avl_node *AVL_search_previous( root , data ) -avl_root_node *root; -AVL_USERDATA *data; -{ - avl_node *node_ptr , *old_ptr = NULL; - int comp = 0; - - node_ptr = root->avl_tree; - while( node_ptr != NULL ) { - old_ptr = node_ptr; - comp = AVL_COMPARE( data , node_ptr->data ); - if( comp < 0 ) - node_ptr = node_ptr->left; - else if( comp > 0 ) - node_ptr = node_ptr->right; - else - return node_ptr; /* found */ - } - /* not found */ - if( old_ptr ) { - if( comp > 0 ) - return old_ptr; - else - return old_ptr->previous; - } - return NULL; +avl_public avl_node *AVL_search_previous(avl_root_node *root, + AVL_USERDATA *data) { + avl_node *node_ptr, *old_ptr = NULL; + int comp = 0; + + node_ptr = root->avl_tree; + while (node_ptr != NULL) { + old_ptr = node_ptr; + comp = AVL_COMPARE(data, node_ptr->data); + if (comp < 0) + node_ptr = node_ptr->left; + else if (comp > 0) + node_ptr = node_ptr->right; + else + return node_ptr; /* found */ + } + /* not found */ + if (old_ptr) { + if (comp > 0) + return old_ptr; + else + return old_ptr->previous; + } + return NULL; } +#endif - +#ifndef AVL_NO_CHECK_TREE /* AVL-tree を表示する */ -avl_public void AVL_print_tree( root ) -avl_root_node *root; -{ - avl_print_tree( root , root->avl_tree , 0 ); -} - - -avl_private void avl_print_tree( root , node_ptr , level ) -avl_root_node *root; -avl_node *node_ptr; -int level; -{ - int i; +avl_private void avl_print_tree(avl_root_node *root, avl_node *node_ptr, + int level) { + int i; - if( node_ptr == NULL ) - return; - avl_print_tree( root , node_ptr->right , level + 1 ); - for( i = level * 4 ; i > 0 ; i-- ) - putchar( ' ' ); - (*( root->print_function ))( node_ptr->data ); - printf( "(%d,%d)\n" , node_ptr->left_depth , node_ptr->right_depth ); + if (node_ptr == NULL) return; + avl_print_tree(root, node_ptr->right, level + 1); + for (i = level * 4; i > 0; i--) putchar(' '); + (*(root->print_function))(node_ptr->data); + printf("(%d,%d)\n", node_ptr->left_depth, node_ptr->right_depth); - avl_print_tree( root , node_ptr->left , level + 1 ); + avl_print_tree(root, node_ptr->left, level + 1); } +avl_public void AVL_print_tree(avl_root_node *root) { + avl_print_tree(root, root->avl_tree, 0); +} -#if 0 /* AVL-tree を表示する その2 */ -avl_public void AVL_print_tree2( avl_root_node *root ) -{ - avl_node *node_ptr; +avl_public void AVL_print_tree2(avl_root_node *root) { + avl_node *node_ptr; - printf( "\n" "--------\n" ); + printf( + "\n" + "--------\n"); - for( node_ptr = AVL_get_max( root ); node_ptr != NULL; - node_ptr = AVL_previous( node_ptr ) ) { - - int level; - avl_node *nptr = node_ptr; - - /* node_ptr のレベルを調べる */ - for( level = 0; nptr != NULL; level++ ) - nptr = nptr->parent; - - for( level *= 2; level > 0; level-- ) - putchar(' '); - (*( root->print_function ))( node_ptr->data ); - printf( "(%d,%d)\n", node_ptr->left_depth, node_ptr->right_depth ); - } -} -#endif + for (node_ptr = AVL_get_max(root); node_ptr != NULL; + node_ptr = AVL_previous(node_ptr)) { + int level; + avl_node *nptr = node_ptr; + /* node_ptr のレベルを調べる */ + for (level = 0; nptr != NULL; level++) nptr = nptr->parent; -avl_public void AVL_check_tree( root ) -avl_root_node *root; -{ - avl_check_tree( root , root->avl_tree ); + for (level *= 2; level > 0; level--) putchar(' '); + (*(root->print_function))(node_ptr->data); + printf("(%d,%d)\n", node_ptr->left_depth, node_ptr->right_depth); + } } - -avl_private int avl_check_tree( root , node_ptr ) -avl_root_node *root; -avl_node *node_ptr; -{ - int left_depth , right_depth; - - if( node_ptr == NULL ) - return 0; - - left_depth = avl_check_tree( root , node_ptr->left ); - right_depth = avl_check_tree( root , node_ptr->right ); - if( AVL_BALANCE( node_ptr ) != 0 && - AVL_BALANCE( node_ptr ) != 1 && - AVL_BALANCE( node_ptr ) != -1 ) { - fputs( "AVL_check_tree: tree not balanced\n" , stderr ); - exit( 1 ); - } - if( ( node_ptr->left && AVL_COMPARE( node_ptr->left->data , node_ptr->data ) >= 0 ) || - ( node_ptr->right && AVL_COMPARE( node_ptr->data , node_ptr->right->data ) >= 0 ) ) { - fputs( "AVL_check_tree: order error\n" , stderr ); - if( node_ptr->left ) { - fputs( "left node" , stderr ); - (*( root->print_function ))( node_ptr->left->data ); - } - fputc( ' ' , stderr ); - (*( root->print_function ))( node_ptr->data ); - fputc( ' ' , stderr ); - if( node_ptr->right ) { - fputs( "right node" , stderr ); - (*( root->print_function ))( node_ptr->right->data ); - } - fputc( '\n' , stderr ); - AVL_print_tree( root ); - exit(1); +avl_private int avl_check_tree(avl_root_node *root, avl_node *node_ptr) { + int left_depth, right_depth; + + if (node_ptr == NULL) return 0; + + left_depth = avl_check_tree(root, node_ptr->left); + right_depth = avl_check_tree(root, node_ptr->right); + if (AVL_BALANCE(node_ptr) != 0 && AVL_BALANCE(node_ptr) != 1 && + AVL_BALANCE(node_ptr) != -1) { + fputs("AVL_check_tree: tree not balanced\n", stderr); + exit(1); + } + if ((node_ptr->left && + AVL_COMPARE(node_ptr->left->data, node_ptr->data) >= 0) || + (node_ptr->right && + AVL_COMPARE(node_ptr->data, node_ptr->right->data) >= 0)) { + fputs("AVL_check_tree: order error\n", stderr); + if (node_ptr->left) { + fputs("left node", stderr); + (*(root->print_function))(node_ptr->left->data); } - if( node_ptr->left_depth != left_depth || node_ptr->right_depth != right_depth ) { - fputs( "AVL_check_tree: depth error\n" , stderr ); - exit( 1 ); + fputc(' ', stderr); + (*(root->print_function))(node_ptr->data); + fputc(' ', stderr); + if (node_ptr->right) { + fputs("right node", stderr); + (*(root->print_function))(node_ptr->right->data); } - if( ( node_ptr->left && node_ptr->left->parent != node_ptr ) - || ( node_ptr->right && node_ptr->right->parent != node_ptr ) ) { - fputs( "AVL_check_tree: child error\n" , stderr ); - exit( 1 ); + fputc('\n', stderr); + AVL_print_tree(root); + exit(1); + } + if (node_ptr->left_depth != left_depth || + node_ptr->right_depth != right_depth) { + fputs("AVL_check_tree: depth error\n", stderr); + exit(1); + } + if ((node_ptr->left && node_ptr->left->parent != node_ptr) || + (node_ptr->right && node_ptr->right->parent != node_ptr)) { + fputs("AVL_check_tree: child error\n", stderr); + exit(1); + } + if (node_ptr->parent == NULL) { + if (root->avl_tree != node_ptr) { + fputs("AVL_check_tree: root node mismatch\n", stderr); + exit(1); } - if( node_ptr->parent == NULL ) { - if( root->avl_tree != node_ptr ) { - fputs( "AVL_check_tree: root node mismatch\n" , stderr ); - exit( 1 ); - } - } else { - if( node_ptr->parent->left != node_ptr && node_ptr->parent->right != node_ptr ) { - fputs( "AVL_check_tree: parent error\n" , stderr ); - exit( 1 ); - } + } else { + if (node_ptr->parent->left != node_ptr && + node_ptr->parent->right != node_ptr) { + fputs("AVL_check_tree: parent error\n", stderr); + exit(1); } - return( left_depth > right_depth ? left_depth : right_depth ) + 1; + } + return (left_depth > right_depth ? left_depth : right_depth) + 1; +} + +avl_public void AVL_check_tree(avl_root_node *root) { + avl_check_tree(root, root->avl_tree); } -/* EOF */ +#endif + +// EOF diff --git a/src/avl/avl.h b/src/avl/avl.h index 604b802..e4ae7f4 100644 --- a/src/avl/avl.h +++ b/src/avl/avl.h @@ -4,122 +4,120 @@ Copyright (C) 1991 K.Abe - E-Mail k-abe@ics.osaka-u.ac.jp - Nifty Serve PDC02373 - - - AVL_delete() bugfix patch: - Copyleft 1997 Tachibana Eriko. + E-Mail k-abe@ics.osaka-u.ac.jp + Nifty Serve PDC02373 + Copyright (C) 1997 TcbnErik ... AVL_delete() bugfix patch + Copyright (C) 2022 TcbnErik ... style This file is included 1) to use avl-library - 2) to make avl-library ( #define AVL_LIBRARY ) - 3) to include avl-library ( #define AVL_INCLUDE ) + 2) to make avl-library ( #define AVL_LIBRARY ) + 3) to include avl-library ( #define AVL_INCLUDE ) */ #ifndef __INCLUDE_AVL_H__ #define __INCLUDE_AVL_H__ - -#if defined( PROFILE ) && defined( __HUMAN68K__ ) - #define avl_private extern +#if defined(PROFILE) && defined(__HUMAN68K__) +#define avl_private extern #else - #define avl_private static +#define avl_private static #endif - #ifdef AVL_LIBRARY - /* to make avl-library */ - #define AVL_USERDATA void - #ifndef AVL_NOMACRO - #define AVL_NOMACRO - #endif /* AVL_NOMACRO */ - #define avl_public extern -#elif defined( AVL_INCLUDE ) - /* include avl-library */ - #ifndef AVL_USERDATA - #error You must define AVL_USERDATA before include this file. - #endif /* AVL_USERDATA */ - #define avl_public avl_private +/* to make avl-library */ +#define AVL_USERDATA void +#ifndef AVL_NOMACRO +#define AVL_NOMACRO +#endif /* AVL_NOMACRO */ +#define avl_public extern +#elif defined(AVL_INCLUDE) +/* include avl-library */ +#ifndef AVL_USERDATA +#error You must define AVL_USERDATA before include this file. +#endif /* AVL_USERDATA */ +#define avl_public avl_private #else - /* use avl-library */ - #ifndef AVL_USERDATA - #define AVL_USERDATA void - #endif /* AVL_USERDATA */ - #define avl_public extern +/* use avl-library */ +#ifndef AVL_USERDATA +#define AVL_USERDATA void +#endif /* AVL_USERDATA */ +#define avl_public extern #endif - typedef struct _avl_node { - /* AVL-tree stuff */ - struct _avl_node *left; - struct _avl_node *right; - struct _avl_node *parent; - unsigned short left_depth; - unsigned short right_depth; - /* linked-list stuff */ - struct _avl_node *next; - struct _avl_node *previous; - /* user data */ - AVL_USERDATA *data; + /* AVL-tree stuff */ + struct _avl_node *left; + struct _avl_node *right; + struct _avl_node *parent; + unsigned short left_depth; + unsigned short right_depth; + /* linked-list stuff */ + struct _avl_node *next; + struct _avl_node *previous; + /* user data */ + AVL_USERDATA *data; } avl_node; - typedef struct _avl_root_node { - struct _avl_node *avl_tree; - struct _avl_node *min; - struct _avl_node *max; - int data_number; - int (*compare_function)( AVL_USERDATA* , AVL_USERDATA* ); - void (*free_function)( AVL_USERDATA* ); - void (*print_function)( AVL_USERDATA* ); + struct _avl_node *avl_tree; + struct _avl_node *min; + struct _avl_node *max; + int data_number; + int (*compare_function)(AVL_USERDATA *, AVL_USERDATA *); + void (*free_function)(AVL_USERDATA *); + void (*print_function)(AVL_USERDATA *); } avl_root_node; - #ifdef AVL_NOMACRO -avl_public AVL_USERDATA *AVL_get_data(avl_node *node_ptr); -avl_public int AVL_data_number(avl_root_node *root); -avl_public avl_node *AVL_get_min(avl_root_node *root); -avl_public avl_node *AVL_get_max(avl_root_node *root); -avl_public avl_node *AVL_next(avl_node *node_ptr); -avl_public avl_node *AVL_previous(avl_node *node_ptr); +avl_public AVL_USERDATA *AVL_get_data(avl_node *node_ptr); +avl_public int AVL_data_number(avl_root_node *root); +avl_public avl_node *AVL_get_min(avl_root_node *root); +avl_public avl_node *AVL_get_max(avl_root_node *root); +avl_public avl_node *AVL_next(avl_node *node_ptr); +avl_public avl_node *AVL_previous(avl_node *node_ptr); #endif /* AVL_NOMACRO */ -avl_public avl_root_node *AVL_create_tree( int (*compare_function) - ( AVL_USERDATA* , AVL_USERDATA* ) , - void (*free_function)( AVL_USERDATA* ) , - void (*print_function)( AVL_USERDATA* ) ); -avl_public void AVL_destroy_tree(avl_root_node *root); -avl_public avl_node *AVL_insert(avl_root_node *root, AVL_USERDATA *data); -avl_public void AVL_delete(avl_root_node *root, avl_node *delete_node); -avl_public avl_node *AVL_search(avl_root_node *root, AVL_USERDATA *data); -avl_public avl_node *AVL_search_next(avl_root_node *root, AVL_USERDATA *data); -avl_public avl_node *AVL_search_previous(avl_root_node *root, AVL_USERDATA *data); -avl_public void AVL_print_tree(avl_root_node *root); -avl_public void AVL_check_tree(avl_root_node *root); +avl_public avl_root_node *AVL_create_tree( + int (*compare_function)(AVL_USERDATA *, AVL_USERDATA *), + void (*free_function)(AVL_USERDATA *), + void (*print_function)(AVL_USERDATA *)); +#ifndef AVL_NO_DESTROY_TREE +avl_public void AVL_destroy_tree(avl_root_node *root); +#endif +avl_public avl_node *AVL_insert(avl_root_node *root, AVL_USERDATA *data); +avl_public void AVL_delete(avl_root_node *root, avl_node *delete_node); +avl_public avl_node *AVL_search(avl_root_node *root, AVL_USERDATA *data); +avl_public avl_node *AVL_search_next(avl_root_node *root, AVL_USERDATA *data); +#ifndef AVL_NO_SEARCH_PREVIOUS +avl_public avl_node *AVL_search_previous(avl_root_node *root, + AVL_USERDATA *data); +#endif +#ifndef AVL_NO_CHECK_TREE +avl_public void AVL_print_tree(avl_root_node *root); +avl_public void AVL_check_tree(avl_root_node *root); +#endif #ifndef AVL_NOMACRO -#define AVL_get_data(node_ptr) ((node_ptr)->data) -#define AVL_get_min(root) ((root)->min) -#define AVL_get_max(root) ((root)->max) -#define AVL_data_number(root) ((root)->data_number) -#define AVL_next(node_ptr) ((node_ptr)->next) -#define AVL_previous(node_ptr) ((node_ptr)->previous) +#define AVL_get_data(node_ptr) ((node_ptr)->data) +#define AVL_get_min(root) ((root)->min) +#define AVL_get_max(root) ((root)->max) +#define AVL_data_number(root) ((root)->data_number) +#define AVL_next(node_ptr) ((node_ptr)->next) +#define AVL_previous(node_ptr) ((node_ptr)->previous) #endif - /* AVL_get_data_safely is function rather than macro because macro will evaluate its argument twice. */ static #ifdef __GNUC__ -inline + inline #endif -AVL_USERDATA *AVL_get_data_safely( node_ptr ) -avl_node *node_ptr; -{ - return( node_ptr != NULL ? node_ptr->data : NULL ); + AVL_USERDATA * + AVL_get_data_safely(avl_node *node_ptr) { + return (node_ptr != NULL ? node_ptr->data : NULL); } #undef avl_public diff --git a/src/disasm.c b/src/disasm.c index 21e8a39..95b8752 100644 --- a/src/disasm.c +++ b/src/disasm.c @@ -1,4077 +1,1668 @@ -/* $Id: disasm.c,v 2.76 1995/01/07 11:33:16 ryo Exp $ - * - * ソースコードジェネレータ - * 逆アセンブルモジュール - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 逆アセンブルモジュール +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "disasm.h" #include -#include "disasm.h" +#include "ea.h" #include "estruct.h" -#include "etc.h" /* peek[wl] */ -#include "fpconv.h" +#include "etc.h" /* peek[wl] */ +#include "fpu.h" #include "global.h" #include "hex.h" +#include "mmu.h" +#include "opstr.h" +#include "osk.h" + +#define BYTE1 (*(UBYTE*)ptr) +#define BYTE2 (*(UBYTE*)(ptr + 1)) +#define BYTE3 (*(UBYTE*)(ptr + 2)) +#define BYTE4 (*(UBYTE*)(ptr + 3)) +#define WORD1 (peekw(ptr)) +#define WORD2 (peekw(ptr + 2)) +#define WORD3 (peekw(ptr + 4)) +#define LONG05 (peekl(ptr + 2)) + +static boolean moveope(codeptr ptr, disasm* code, opesize size); +static boolean packope(codeptr ptr, disasm* code); +static boolean addsubope(codeptr ptr, disasm* code, boolean isAdd); +static boolean bcdope(codeptr ptr, disasm* code); + +#define SX_WINDOW_EXIT 0xa352 + +#define DOS_EXIT 0x00 +#define DOS_EXIT2 0x4c +#define DOS_KEEPPR 0x31 +#define DOS_KILL_PR 0xf9 + +#define SETSIZE() (code->size = code->size2 = (WORD1 >> 6) & 3) + +// アドレスレジスタ直接でバイトサイズなら未定義命令 +static boolean reject_bytesize(disasm* code, UWORD word1) { + return (is_areg_direct(word1) && code->size == BYTESIZE) ? TRUE : FALSE; +} -#ifdef OSKDIS -#include "label.h" -#endif /* OSKDIS */ - - -#define BYTE1 (*(unsigned char*) ptr) -#define BYTE2 (*(unsigned char*) (ptr + 1)) -#define BYTE3 (*(unsigned char*) (ptr + 2)) -#define BYTE4 (*(unsigned char*) (ptr + 3)) -#define BYTE5 (*(unsigned char*) (ptr + 4)) -#define BYTE6 (*(unsigned char*) (ptr + 5)) -#define WORD1 (peekw (ptr)) -#define WORD2 (peekw (ptr + 2)) -#define WORD3 (peekw (ptr + 4)) -#define LONG05 (peekl (ptr + 2)) -#define SignBYTE2 (*(signed char *) (ptr + 1)) -#define SignBYTE4 (*(signed char *) (ptr + 3)) -#define SignWORD2 ((WORD) peekw (ptr + 2)) -#define SignWORD3 ((WORD) peekw (ptr + 4)) -#define SignLONG05 ((LONG) peekl (ptr + 2)) - -/* アドレッシングモード (bitmaped) */ -/* - Dn ----------------------------------------------------+ - An ---------------------------------------------------+| - (An) ------------------------------------------------+|| - (An)+ ----------------------------------------------+||| - -(An) ---------------------------------------------+|||| - (d16,An) -----------------------------------------+||||| - (d8,An,ix) --------------------------------------+|||||| - ??? --------------------------------------------+||||||| - (abs).w ---------------------------------------+|||||||| - (abs).l --------------------------------------+||||||||| - (d16,pc) ------------------------------------+|||||||||| - (d8,pc,ix) ---------------------------------+||||||||||| - #imm --------------------------------------+|||||||||||| - - ||||||||||||| */ -#define DATAREG 0x00001 /* -------------------@ */ -#define ADRREG 0x00002 /* ------------------@- */ -#define ADRIND 0x00004 /* -----------------@-- */ -#define POSTINC 0x00008 /* ----------------@--- */ -#define PREDEC 0x00010 /* ---------------@---- */ -#define DISPAREG 0x00020 /* --------------@----- */ -#define IDXAREG 0x00040 /* -------------@------ */ -#define ABSW 0x00100 /* -----------@-------- */ -#define ABSL 0x00200 /* ----------@--------- */ -#define DISPPC 0x00400 /* ---------@---------- */ -#define IDXPC 0x00800 /* --------@----------- */ -#define IMMEDIATE 0x01000 /* -------@------------ */ -#define SRCCR 0x10000 /* ---@---------------- */ -#define MOVEOPT 0x80000 /* @------------------- */ - -#define CHANGE 0x0037f /* ----------@@-@@@@@@@ */ -#define CTRLCHG 0x00364 /* ----------@@-@@--@-- */ -#define CONTROL 0x00f64 /* --------@@@@-@@--@-- */ -#define MEMORY 0x01f7c /* -------@@@@@-@@@@@-- */ -#define DATA 0x01f7d /* -------@@@@@-@@@@@-@ */ -#define ALL 0x01f7f /* -------@@@@@-@@@@@@@ */ - - -#ifdef OSKDIS -#define DC_WORD "dc" -#else -#define DC_WORD ".dc" -#endif - -/* private 関数プロトタイプ */ -private void op00 (address, disasm*); -private void op01 (address, disasm*); -private void op02 (address, disasm*); -private void op03 (address, disasm*); -private void op04 (address, disasm*); -private void op05 (address, disasm*); -private void op06 (address, disasm*); -private void op07 (address, disasm*); -private void op08 (address, disasm*); -private void op09 (address, disasm*); -private void op0a (address, disasm*); -private void op0b (address, disasm*); -private void op0c (address, disasm*); -private void op0d (address, disasm*); -private void op0e (address, disasm*); -private void op0f (address, disasm*); -private void setBitField (operand* op, address ptr); -private void setMMUfc (disasm* code, operand* op, int fc); -private void moveope (address, disasm*); -private void addsubope (address, disasm*, const char*); -private void packope (address, disasm*, const char*); -private void bcdope (address, disasm*, const char*); -private void addsize (char*, opesize); -private void setreglist (char*, address); -private void setIMD (disasm*, operand*, address, opesize); -private void setAnDisp (disasm*, operand*, int, int); -private void setEA (disasm*, operand*, address, int); - - -#ifndef OSKDIS -char** OSlabel; -char** FElabel; -char** SXlabel; /* char* [SXCALL_MAX]へのポインタ */ -char OSCallName[MAX_MACRO_LEN] = "DOS"; -char FECallName[MAX_MACRO_LEN] = "FPACK"; -char SXCallName[MAX_MACRO_LEN] = "SXCALL"; -#endif /* OSKDIS */ - - -/* 奇数の添え字は意味なし. コプロID*2 = 添え字(比較の時のシフトをなくすため) */ -char FPUID_table[16]; - -/* バイト命令の不定バイトのチェック */ -boolean Disasm_Exact = TRUE; - -/* 逆アセンブルされた文字列を返すかどうか */ -boolean Disasm_String = TRUE; - -/* 未使用の Aline , Fline TRAP を未定義とするか */ -boolean Disasm_UnusedTrapUndefined = TRUE; - -/* Address Error の起こる命令を未定義とするか */ -boolean Disasm_AddressErrorUndefined = TRUE; - -/* dbf を dbra として出力するか */ -boolean Disasm_Dbra = TRUE; - -/* ニーモニックを省略して出力 ( cmpi -> cmp etc. ) */ -boolean Disasm_MnemonicAbbreviation = FALSE; - -/* ! Disasm_UnusedTrapUndefined 時に SX-Window を有効に */ -boolean Disasm_SX_Window = FALSE; - -/* CPU32 命令セット対応(デフォルトで対応しない) */ -boolean Disasm_CPU32; - -#ifdef COLDFIRE -/* ColdFire 命令セット対応(デフォルトで対応しない) */ -boolean Disasm_ColdFire; -#endif - -/* 命令セット(デフォルトで 68000) */ -mputypes MPU_types = M000; - -/* MMU 命令セット(デフォルトで未対応) */ -short MMU_type; - -/* FPU 命令セット(デフォルトで未対応) */ -short FPCP_type; - -/* 未使用フィールドの検査(デフォルトで最も厳密に検査) */ -int UndefRegLevel = 0x0f; - -static address PC; - address PCEND; - - -#define SX_WINDOW_EXIT 0xa352 - -#define DOS_EXIT 0x00 -#define DOS_EXIT2 0x4c -#define DOS_KEEPPR 0x31 -#ifdef DOS_KILL_PR_IS_RTSOP -#define DOS_KILL_PR 0xf9 -#endif - - -static const int pow2[16] = { - 1, 2, 4, 8, 16, 32, 64, 128, - 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, -}; - - -#define IfNeedStr if (Disasm_String) -#define SETSIZE() (code->size = code->size2 = (WORD1 >> 6) & 3) -#define OPECODE(op) do { if (Disasm_String) strcpy (code->opecode, op);} while (0) -#define UNDEFINED() (code->flag = UNDEF) -#define REJECTBYTESIZE() \ - do { \ - if ((WORD1 & 0x38) == 0x8 && code->size == BYTESIZE) { \ - UNDEFINED(); return; \ - } \ - } while (0) -#define FPCOND(code, byte) \ - do { \ - if (byte & 0x20) { \ - UNDEFINED(); return; \ - } else \ - setfpcond (code, byte); \ - } while (0) -#define FPOPESET \ - do { \ - if ((ExtensionFlags[WORD2 & 0x7f] & FPCP_type) == 0) { \ - UNDEFINED(); return; \ - } \ - OPECODE (ExtensionField[ WORD2 & 0x7f ]); \ - } while (0) -#define MMUCOND(code, byte) \ - do { \ - if (byte & 0x30) { UNDEFINED(); return; } \ - setmmucond (code, byte); \ - } while (0) - - -/* 指定MPUだけが対象なら未定義命令 */ -#define REJECT(x) \ -(void)({ \ - if ((MPU_types & ~(x)) == 0) { UNDEFINED(); return; } \ - code->mputypes &= ~(x); \ -}) - -/* 68060でISP無しなら未定義命令 */ -#define REJECT060noISP() \ -(void)({ \ - if ((MPU_types & MISP) == 0) { \ - if ((MPU_types & ~M060) == 0) { UNDEFINED(); return; } \ - code->mputypes &= ~M060; \ - } \ -}) - -/* 68040/68060でFPSP無しなら未定義命令(6888xなら常に有効) */ -#define REJECTnoFPSP() \ -(void)({ \ - if ((FPCP_type & (F4SP|F6SP)) == 0) { \ - if ((FPCP_type & ~(F040|F060)) == 0) { UNDEFINED(); return; } \ - code->mputypes &= ~(M040|M060); \ - } \ -}) - -/* 68060でFPSP無しなら未定義命令(6888x/68040なら常に有効) */ -#define REJECT060noFPSP() \ -(void)({ \ - if ((FPCP_type & F6SP) == 0) { \ - if ((FPCP_type & ~F060) == 0) { UNDEFINED(); return; } \ - code->mputypes &= ~M060; \ - } \ -}) - -/* 68851無しなら未定義命令 */ -#define REJECTnoPMMU() \ -(void)({ \ - if ((MMU_type & MMU851) == 0) { UNDEFINED(); return; } \ - code->mputypes = M020; \ -}) - - -/* - - 逆アセンブルモジュール - ptr に(格納)アドレスを与えると、code に逆アセンブル結果が入ってくる - 何バイト命令かを返す - - address *pcptr -> global in this file. - - */ -extern int -dis (address ptr, disasm* code, address* pcptr) -{ - static void (*decode[]) (address, disasm*) = { - op00, op01, op02, op03, op04, op05, op06, op07, - op08, op09, op0a, op0b, op0c, op0d, op0e, op0f - }; - - code->opecode[0] = - code->op1.operand[0] = - code->op2.operand[0] = - code->op3.operand[0] = - code->op4.operand[0] = '\0'; - - code->op1.ea = code->op2.ea = code->op3.ea = code->op4.ea = (adrmode) -1; - - code->op1.opval = code->op2.opval = code->op3.opval = code->op4.opval = - code->op1.opval2 = code->op2.opval2 = code->op3.opval2 = code->op4.opval2 = - code->op1.eaadrs = code->op2.eaadrs = code->op3.eaadrs = code->op4.eaadrs = - code->op1.eaadrs2 = code->op2.eaadrs2 = code->op3.eaadrs2 = code->op4.eaadrs2 = - (address) -1; - - code->op1.exbd = code->op2.exbd = code->op3.exod = code->op4.exod = - code->op1.exod = code->op2.exod = code->op3.exod = code->op4.exod = -1; - - code->op1.labelchange1 = code->op2.labelchange1 = - code->op3.labelchange1 = code->op4.labelchange1 = - code->op1.labelchange2 = code->op2.labelchange2 = /* od用 */ - code->op3.labelchange2 = code->op4.labelchange2 = /* od用 */ - FALSE; - -#ifndef __HUMAN68K__ /* Safe and Normal coding */ - code->size2 = code->size = NOTHING; - code->default_size = WORDSIZE; - code->bytes = 2; - code->flag = OTHER; - code->mputypes = ~0; - code->fpuid = -1; - code->opflags = 0; -#else /* Fast but very DANGEROUS coding. */ - { - long* p = (long*) &code->size; - - *(opesize*) p++ = (opesize) NOTHING; /* size */ - *(opesize*) p++ = (opesize) NOTHING; /* size2 */ - *(opesize*) p++ = (opesize) WORDSIZE; /* default_size */ - *(int*) p++ = (int) 2; /* bytes */ - *(opetype*) p++ = (opetype) OTHER; /* flag */ - *p = (~0 << 24) /* mputypes */ - + (0xff << 16) /* fpuid */ - + (0 << 8) + 0; /* opflags */ - } -#endif +// 68060でISP無しなら未定義命令 +static boolean reject_060_no_isp(disasm* code) { + mputypes mpu = Dis.mpu; + if ((mpu & MISP) == 0) { + if ((mpu & ~M060) == 0) return TRUE; + code->mputypes &= ~M060; + } + return FALSE; +} - PC = *pcptr; +// 内蔵MMUが無効なら未定義命令 +// mputype=M040, mmutype=MMU040 または mputype=M060, mmutype=MMU060 +// の組み合わせで呼び出すこと +static boolean reject_no_mmu(disasm* code, mputypes mputype, uint8_t mmutype) { + if (Dis.mmu & mmutype) { + code->mputypes = mputype; + return FALSE; + } + return TRUE; +} - (decode[BYTE1 >> 4]) (ptr, code); +// 68040/68060のMMUが無効なら未定義命令 +static boolean reject_no_mmu46(disasm* code) { + mputypes m = 0; + mmutypes mmu = Dis.mmu; + if (mmu & MMU040) m |= M040; + if (mmu & MMU060) m |= M060; + if (m == 0) return TRUE; - if ((code->bytes > 2) && (PCEND < (PC + code->bytes))) { + code->mputypes = m; + return FALSE; +} - code->op1.opval = code->op2.opval = code->op3.opval = code->op4.opval - = code->op1.opval2 = code->op2.opval2 = code->op3.opval2 = code->op4.opval2 - = code->op1.eaadrs = code->op2.eaadrs = code->op3.eaadrs = code->op4.eaadrs - = code->op1.eaadrs2 = code->op2.eaadrs2 = code->op3.eaadrs2 = code->op4.eaadrs2 - = (address)-1; +// and or (eor はアドレッシングモードが微妙に異なる) +static boolean logicope(codeptr ptr, disasm* code) { + SETSIZE(); + if (BYTE1 & 1) { + setDn(&code->op1, BYTE1 >> 1); + return setEA(code, &code->op2, ptr, MEMORY & CHANGE); + } else { + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, BYTE1 >> 1); + } + return TRUE; +} - code->flag = UNDEF; - } +// mul, div +static boolean muldivope(codeptr ptr, disasm* code) { + code->size = code->size2 = WORDSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, BYTE1 >> 1); + return TRUE; +} - if (code->flag == UNDEF) { - IfNeedStr { - code->mputypes = ~0; - code->fpuid = -1; +// ロングフォーム mul, div +static boolean longmuldivope(codeptr ptr, disasm* code) { + code->size = code->size2 = LONGSIZE; + code->bytes = 4; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setPairDn(&code->op2, WORD2 & 7, (BYTE3 >> 4) & 7); + return TRUE; +} - code->op1.ea = code->op2.ea = code->op3.ea = code->op4.ea = (adrmode) -1; +// cas, cas2 +static boolean casope(codeptr ptr, disasm* code) { + UWORD word1 = WORD1, word2 = WORD2; + int size = (BYTE1 >> 1) & 3; - code->op1.labelchange1 = code->op2.labelchange1 = - code->op3.labelchange1 = code->op4.labelchange1 = - code->op1.labelchange2 = code->op2.labelchange2 = - code->op3.labelchange2 = code->op4.labelchange2 = FALSE; + if (reject(code, M000 | M010)) return FALSE; - code->op2.operand[0] = - code->op3.operand[0] = - code->op4.operand[0] = '\0'; + // casで使用されないにcas2を割り当てているので、casより先に調べる + if ((word1 & 0xfdff) == 0x0cfc) { + UWORD word3 = WORD3; - strcpy (code->opecode, DC_WORD); - itox4d (code->op1.operand, WORD1); - } - code->bytes = 2; - code->size = code->size2 = code->default_size = WORDSIZE; - } - *pcptr += code->bytes; /* PC += code->bytes */ + if (((word2 | word3) & 0x0e38) != 0) return FALSE; + if (reject_060_no_isp(code)) return FALSE; - return code->bytes; -} + OPECODE(cas2); + setPairDn(&code->op1, word2 & 7, word3 & 7); // Dc1:Dc2 + setPairDn(&code->op2, (word2 >> 6) & 7, (word3 >> 6) & 7); // Du1:Du2 + setPairID(&code->op3, (word2 >> 12) & 15, + (word3 >> 12) & 15); // (Rn1):(Rn2) + code->bytes = 6; + code->size = code->size2 = (size == 2) ? WORDSIZE : LONGSIZE; + return TRUE; + } + if (size != 0 && (word2 & 0xfe38) == 0x0000) { + opesize sz = (size == 1) ? BYTESIZE : (size == 2) ? WORDSIZE : LONGSIZE; -/* inline functions here... */ + OPECODE(cas); + setDn(&code->op1, word2); // Dc + setDn(&code->op2, word2 >> 6); // Du + code->bytes = 4; + code->size = code->size2 = sz; + return setEA(code, &code->op3, ptr, DATA & CHANGE); + } -INLINE static void -setDn (operand* op, int regno) -{ - op->ea = DregD; - IfNeedStr { - op->operand[0] = 'd'; - op->operand[1] = (regno & 7) + '0'; - op->operand[2] = 0; - } + return FALSE; } -INLINE static void -setAn (operand* op, int regno) -{ - op->ea = AregD; - IfNeedStr { - op->operand[0] = 'a'; - op->operand[1] = (regno & 7) + '0'; - op->operand[2] = 0; - } +// moves +static boolean movesope(codeptr ptr, disasm* code) { + if ((WORD2 & 0x07ff) != 0) return FALSE; + if (reject(code, M000)) return FALSE; + + OPECODE(moves); + SETSIZE(); + code->bytes = 4; + if (BYTE3 & 0x08) { + setRn(&code->op1, BYTE3 >> 4); + return setEA(code, &code->op2, ptr, CHANGE ^ DATAREG ^ ADRREG); + } else { + if (!setEA(code, &code->op1, ptr, CHANGE ^ DATAREG ^ ADRREG)) return FALSE; + setRn(&code->op2, BYTE3 >> 4); + return TRUE; + } } +static boolean oriope(codeptr ptr, disasm* code) { + if (!setEA(code, &code->op2, ptr, SRCCR | (DATA & CHANGE))) return FALSE; + // to ccr はバイトサイズ + if (code->op2.ea == CcrSr) code->default_size = code->size; -INLINE static void -setRn (operand* op, int regno) -{ - op->ea = (regno & 8) ? AregD : DregD; - IfNeedStr { - op->operand[0] = (regno & 8) ? 'a' : 'd'; - op->operand[1] = (regno & 7) + '0'; - op->operand[2] = '\0'; - } + OPECODE2(code->op2.ea == DregD, ori, oriAsOr); + return TRUE; } +static boolean andiope(codeptr ptr, disasm* code) { + if (!setEA(code, &code->op2, ptr, SRCCR | (DATA & CHANGE))) return FALSE; + // to ccr はバイトサイズ + if (code->op2.ea == CcrSr) code->default_size = code->size; -INLINE static void -setFPn (operand* op, int regno) -{ - op->ea = FPregD; - IfNeedStr { - char *p = op->operand; - - *p++ = 'f'; - *p++ = 'p'; - *p++ = (regno & 7) + '0'; - *p++ = '\0'; - } + OPECODE2(code->op2.ea == DregD, andi, andiAsAnd); + return TRUE; } +static boolean subiope(codeptr ptr, disasm* code) { + if (!setEA(code, &code->op2, ptr, DATA & CHANGE)) return FALSE; -INLINE static adrmode -setFPCRSRlist (operand* op, int regno) -{ - static char* fpreglist[8] = { - NULL, - "fpiar", - "fpsr", - "fpsr/fpiar", - "fpcr", - "fpcr/fpiar", - "fpcr/fpsr", - "fpcr/fpsr/fpiar" - }; - static adrmode adr[8] = { - 0, - ALL, - DATA, - MEMORY, - DATA, - MEMORY, - MEMORY, - MEMORY - }; - - op->ea = FPCRSR; - IfNeedStr { - strcpy (op->operand, fpreglist[regno & 7]); - } - return adr[regno & 7]; - -} - - -/* レジスタリスト( fmovem ) */ -private void -setFPreglist (char* operandstr, address ptr) -{ - unsigned int field; - boolean flag, already; - int i, start; - - if (!Disasm_String) - return; + OPECODE2(code->op2.ea == DregD, subi, subiAsSub); + if (code->size == BYTESIZE) code->codeflags += CODEFLAG_NEED_COMMENT; - if ((WORD1 & 0x38) == 0x20) /* pre-decrement ? movem とは逆!! */ - field = BYTE4; - else { - int i; - for (field = 0, i = 0; i < 8; i++) - field |= (WORD2 & pow2[i] ? pow2[7 - i] : 0); - } - - start = 0; - for (i = 0, flag = FALSE, already = FALSE; i < 9; i++) { - if (!flag && field & pow2[i]) { - start = i; - flag = TRUE; - } else { - if (flag && (field & pow2[i]) == 0) { - char* p = strend (operandstr); - - if (already) - *p++ = '/'; - *p++ = 'f'; - *p++ = 'p'; - *p++ = start + '0'; - if (start != i - 1) { - *p++ = '-'; - *p++ = 'f'; - *p++ = 'p'; - *p++ = (i - 1) + '0'; - } - *p = '\0'; - already = TRUE; - flag = FALSE; - } - } - } + // 1 <= imm <= 8 なら、最適化抑止のためサイズを付ける + addsize_if_1to8(&code->op1, code->size); + return TRUE; } +static boolean addiope(codeptr ptr, disasm* code) { + if (!setEA(code, &code->op2, ptr, DATA & CHANGE)) return FALSE; + OPECODE2(code->op2.ea == DregD, addi, addiAsAdd); + if (code->size == BYTESIZE) code->codeflags += CODEFLAG_NEED_COMMENT; -/* and or 用 ( eor はアドレッシングモードが微妙に異なる ) */ -INLINE static void -logicope (address ptr, disasm* code) -{ - SETSIZE (); - if (BYTE1 & 1) { - setDn (&code->op1, BYTE1 >> 1); - setEA (code, &code->op2, ptr, MEMORY & CHANGE); - } else { - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, BYTE1 >> 1); - } + // 1 <= imm <= 8 なら、最適化抑止のためサイズを付ける + addsize_if_1to8(&code->op1, code->size); + return TRUE; } +static boolean eoriope(codeptr ptr, disasm* code) { + if (!setEA(code, &code->op2, ptr, SRCCR | (DATA & CHANGE))) return FALSE; + // to ccr はバイトサイズ + if (code->op2.ea == CcrSr) code->default_size = code->size; -/* mul div 用 */ -INLINE static void -muldivope (address ptr, disasm* code) -{ - IfNeedStr { - strcat (code->opecode, (BYTE1 & 1) ? "s" : "u"); - } - code->size = code->size2 = WORDSIZE; - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, BYTE1 >> 1); -} - -/* データレジスタのペア */ -static INLINE void -setPairDn (operand* op, int reg1, int reg2) -{ - op->ea = RegPairD; - IfNeedStr { - strcpy (op->operand, "d0:d0"); - op->operand[1] += reg1; - op->operand[4] += reg2; - } + OPECODE(eori); + return TRUE; } -/* ロングフォーム mul div 用 */ -static INLINE void -longmuldivope (address ptr, disasm* code) -{ - code->size = code->size2 = LONGSIZE; - code->bytes = 4; - setEA (code, &code->op1, ptr, DATA); - setPairDn (&code->op2, WORD2 & 7, (BYTE3 >> 4) & 7); +static boolean cmpiope(codeptr ptr, disasm* code) { + int mode = DATA & CHANGE; + if (extract_ea_basic(WORD1) >= PCDISP && (Dis.mpu & ~(M000 | M010))) { + // PC間接は68020以降専用 + code->mputypes &= ~(M000 | M010); + mode = DATA ^ IMMEDIATE; + } + if (!setEA(code, &code->op2, ptr, mode)) return FALSE; + + OPECODE2(code->op2.ea == DregD, cmpi, cmpiAsCmp); + code->codeflags += CODEFLAG_NEED_COMMENT; + return TRUE; } +static boolean logicaddsub(codeptr ptr, disasm* code) { + SETSIZE(); + if (!setImm(code, &code->op1, ptr, code->size)) return FALSE; -/* cc 条件用 */ -/* IfNeedStr をパスした状態で呼び出すこと */ -INLINE static void -setcond (address ptr, disasm* code) -{ - static const char cond[16][4] = { - "t" , "f" , "hi", "ls", "cc", "cs", "ne", "eq", - "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" - }; - - strcat (code->opecode, cond[BYTE1 & 0xf]); + switch (BYTE1 >> 1) { + default: + break; + case 0: + return oriope(ptr, code); + case 1: + return andiope(ptr, code); + case 2: + return subiope(ptr, code); + case 3: + return addiope(ptr, code); + case 5: + return eoriope(ptr, code); + case 6: + return cmpiope(ptr, code); + } + return FALSE; } +static boolean op00(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; -/* コプロ cc条件用 */ -INLINE static void -setfpcond (disasm* code, unsigned char predicate) -{ - static const char cond[32][5] = { - "f" , "eq" , "ogt" , "oge" , "olt" , "ole" , "ogl" , "or" , - "un" , "ueq" , "ugt" , "uge" , "ult" , "ule" , "ne" , "t" , - "sf" , "seq" , "gt" , "ge" , "lt" , "le" , "gl" , "gle" , - "ngle" , "ngl" , "nle" , "nlt" , "nge" , "ngt" , "sne" , "st" - }; + /* movep */ + if ((word1 & 0x0138) == 0x0108) { + if (reject_060_no_isp(code)) return FALSE; - strcat (code->opecode, cond[predicate & 0x1f]); -} + OPECODE(movep); + code->size = code->size2 = (word1 & 0x40) ? LONGSIZE : WORDSIZE; + if (word1 & 0x80) { + setDn(&code->op1, BYTE1 >> 1); + setAnDisp(code, &code->op2, word1 & 7, WORD2, FALSE); + } else { + setAnDisp(code, &code->op1, word1 & 7, WORD2, FALSE); + setDn(&code->op2, BYTE1 >> 1); + } + return TRUE; + } + /* btst、bchg、bclr、bset */ + { + /* ビット位置が immediate */ + if ((BYTE1 & 0x0f) == 8) { + OPECODE(bit[BYTE2 >> 6]); + code->size = code->default_size = (word1 & 0x38) ? BYTESIZE : LONGSIZE; + code->size2 = UNKNOWN; + if (!setImm(code, &code->op1, ptr, BYTESIZE)) return FALSE; + return setEA(code, &code->op2, ptr, DATA ^ IMMEDIATE); + } -/* 68851 cc条件用 */ -INLINE static void -setmmucond (disasm* code, unsigned char predicate) -{ - static const char cond[16][4] = { - "bs", "bc", "ls", "lc", "ss", "sc", "as", "ac", - "ws", "wc", "is", "ic", "gs", "gc", "cs", "cc" - }; + /* ビット位置が Dn */ + if (BYTE1 & 1) { + OPECODE(bit[BYTE2 >> 6]); + code->size = code->size2 = code->default_size = + (word1 & 0x38) ? BYTESIZE : LONGSIZE; + setDn(&code->op1, BYTE1 >> 1); /* btst 以外は可変 */ + return setEA(code, &code->op2, ptr, + (word1 & 0xc0) ? DATA & CHANGE : DATA); + } - strcat (code->opecode, cond[predicate & 0x0f]); -} + /* どちらでもなければ他の命令 */ + } + // ori, andi, subi, addi, eori, cmpi + if (BYTE1 != 0x0e && BYTE2 < 0xc0) return logicaddsub(ptr, code); + /* cmp2、chk2 */ + if ((word1 & 0x09c0) == 0x00c0 && BYTE1 != 6 && (WORD2 & 0x07ff) == 0x0000) { + if (reject(code, M000 | M010) || reject_060_no_isp(code)) return FALSE; -/* #0 - #7 用 */ -INLINE static void -set07 (operand* op, int num) -{ - op->ea = IMMED; - IfNeedStr { - op->operand[0] = '#'; - op->operand[1] = (num & 7) + '0'; - op->operand[2] = '\0'; - } + OPECODE2(WORD2 & 0x0800, chk2, cmp2); + code->size = code->size2 = (BYTE1 >> 1) & 0x03; + code->bytes = 4; + if (!setEA(code, &code->op1, ptr, CONTROL)) return FALSE; + setRn(&code->op2, BYTE3 >> 4); + return TRUE; + } + + // 0b0000_1ss0_11mm_mrrr: cas, cas2 ss=01,10,11 + if ((word1 & 0x09c0) == 0x08c0) { + return casope(ptr, code); + } + + // 0b0000_1110_ssmm_mrrr: moves ss=00,01,10 + // ss=11のケースはcas/cas2に該当するので、ここではチェック不要 + if ((word1 & 0x0f00) == 0x0e00) { + return movesope(ptr, code); + } + + /* 68020 の callm、rtm */ + if ((word1 & 0x0fc0) == 0x06c0) { + if (reject(code, ~M020)) return FALSE; + + // callm で使えないモードに rtm が詰め込まれている + if ((word1 & 0x0030) == 0) { + OPECODE(rtm); + setRn(&code->op1, word1); + return TRUE; + } + + // rtm でなければ callm + if (BYTE3 != 0x00) { + return FALSE; + } + OPECODE(callm); + if (!setImm(code, &code->op1, ptr, BYTESIZE)) return FALSE; + return setEA(code, &code->op2, ptr, CONTROL); + } + + return FALSE; } - -/* addq , subq , bit操作用 #1 ~ #8 */ -INLINE static void -set18 (operand* op, int num) -{ - op->ea = IMMED; - IfNeedStr { - num &= 7; - op->operand[0] = '#'; - op->operand[1] = num ? (num + '0') : '8'; - op->operand[2] = 0; - } +static boolean op01(codeptr ptr, disasm* code) { + return moveope(ptr, code, BYTESIZE); } -/* 相対分岐用 */ -INLINE static void -setrelative (char* optr, int disp, address* opval) -{ - *opval = PC + 2 + (WORD) disp; - IfNeedStr { - itox8d (optr, (LONG) *opval); - } +static boolean op02(codeptr ptr, disasm* code) { + return moveope(ptr, code, LONGSIZE); } - -/* 相対分岐用(4byteコード(コプロ)用) */ -INLINE static void -setrelative4 (char* optr, int disp, address* opval) -{ - *opval = PC + 4 + (WORD) disp; - IfNeedStr { - itox8d (optr, (LONG) *opval); - } +static boolean op03(codeptr ptr, disasm* code) { + return moveope(ptr, code, WORDSIZE); } +static boolean moveope(codeptr ptr, disasm* code, opesize size) { + UWORD word1 = WORD1; -/* ロングワード版 */ -INLINE static void -setlongrelative (char* optr, int disp, address* opval) -{ - *opval = PC + 2 + disp; - IfNeedStr { - itox8d (optr, (LONG) *opval); - } -} + code->size = code->size2 = size; + if (reject_bytesize(code, word1)) return FALSE; + if (!setEA(code, &code->op1, ptr, ALL)) return FALSE; + // movea + if ((word1 & 0x01c0) == 0x0040) { + if (code->size == BYTESIZE) return FALSE; -/* functions to decode machine instruction op00 - op0f */ + setAn(&code->op2, BYTE1 >> 1); + OPECODE(movea); + // movea.* #imm にはコメントを付ける + if (code->op1.ea == IMMED) code->codeflags += CODEFLAG_NEED_COMMENT; + return TRUE; + } -private void -op00 (address ptr, disasm* code) -{ + if (!setEA(code, &code->op2, ptr, (DATA & CHANGE) | MOVEOPT)) return FALSE; - /* movep */ - if ((WORD1 & 0x0138) == 0x0108) { - char* p; + OPECODE(move); // フロー解析用に解析フェーズでも設定する - REJECT060noISP (); - OPECODE ("movep"); - code->size = code->size2 = (WORD1 & 0x40) ? LONGSIZE : WORDSIZE; - if (WORD1 & 0x80) { - setDn (&code->op1, BYTE1 >> 1); - setAnDisp (code, &code->op2, WORD1 & 7, WORD2); - p = strstr (code->op2.operand, ".w"); - } else { - setAnDisp (code, &code->op1, WORD1 & 7, WORD2); - setDn (&code->op2, BYTE1 >> 1); - p = strstr (code->op1.operand, ".w"); - } - if (p) /* movep (0,an) が (an) に最適化 */ - strcpy (p, p + 2); /* される事はないので ".w" は不要 */ - return; - } + if (Dis.needString) { + // move.* #imm にはコメントを付ける + if (code->op1.ea == IMMED) { + code->codeflags += CODEFLAG_NEED_COMMENT; - /* btst、bchg、bclr、bset */ - { - static const char opcode01[4][5] = { - "btst", "bchg", "bclr", "bset" - }; - - /* ビット位置が immediate */ - if ((BYTE1 & 0x0f) == 8) { - if (BYTE3) { - UNDEFINED(); return; - } - OPECODE (opcode01[BYTE2 >> 6]); - code->size = code->default_size = (WORD1 & 0x38) ? BYTESIZE : LONGSIZE; - code->size2 = UNKNOWN; - setIMD (code, &code->op1, ptr, BYTESIZE); - setEA (code, &code->op2, ptr, DATA ^ IMMEDIATE); - return; - } - - /* ビット位置が Dn */ - if (BYTE1 & 1) { - OPECODE (opcode01[BYTE2 >> 6]); - code->size = code->size2 = code->default_size = - (WORD1 & 0x38) ? BYTESIZE : LONGSIZE; - setDn (&code->op1, BYTE1 >> 1); /* btst 以外は可変 */ - setEA (code, &code->op2, ptr, (WORD1 & 0xc0) ? DATA & CHANGE : DATA); - return; - } - - /* どちらでもなければ他の命令 */ + // move.l #imm,Dn が moveq.l #imm,Dn に化けないように... + if ((word1 & 0x31ff) == 0x203c // move.l #imm,Dn か? + && (LONG05 < 0x80 || 0xffffff80 <= LONG05) // imm が範囲内か? + ) + addsize(&code->op1, LONGSIZE); } + } - /* ori、andi、subi、addi、eori、cmpi */ - if (BYTE1 != 0x0e && BYTE2 < 0xc0) { - SETSIZE (); - setIMD (code, &code->op1, ptr, code->size); - - if (BYTE1 == 0 || BYTE1 == 2 || BYTE1 == 0xa) { - /* ori, andi, eori */ - setEA (code, &code->op2, ptr, SRCCR | (DATA & CHANGE)); - /* to ccr は byte サイズ */ - if (code->op2.ea == SRCCR) - code->default_size = code->size; - } - else if (BYTE1 == 0x0c && MPU_types & ~(M000|M010)) { - /* cmpi */ - if ((WORD1 & 0x3e) == 0x3a) - code->mputypes &= ~(M000|M010); - setEA (code, &code->op2, ptr, DATA ^ IMMEDIATE); - } - else - setEA (code, &code->op2, ptr, DATA & CHANGE); - - IfNeedStr { - static const char opcode00[7][5] = { - "ori", "andi", "subi", "addi", "", "eori", "cmpi" - }; - - strcpy (code->opecode, opcode00[BYTE1 >> 1]); - - /* cmpi.* 及び addi.b、subi.b にはコメントを付ける */ - if (BYTE1 == 0x0c || (code->size == BYTESIZE - && (BYTE1 == 0x06 || BYTE1 == 0x04))) - code->opflags += FLAG_NEED_COMMENT; - - if (Disasm_MnemonicAbbreviation - /* eori か to Dn 以外なら "i" は省略可能 */ - && (BYTE1 == 10 || code->op2.ea != DregD)) { - if (code->opecode[3]) - code->opecode[3] = '\0'; /* xxxi */ - else - code->opecode[2] = '\0'; /* xxi */ - - /* addi/subi で 1 <= imm <= 8 なら */ - /* imm にサイズを付ける(最適化対策) */ - if ((BYTE1 == 4 || BYTE1 == 6) && ((ULONG)code->op1.opval - 1) <= 7) - addsize (code->op1.operand, code->size); - } - } - return; - } + return TRUE; +} - /* cmp2、chk2 */ - if ((WORD1 & 0x09c0) == 0x00c0 && BYTE1 != 6 - && (WORD2 & 0x07ff) == 0x0000) { - - REJECT (M000|M010); - REJECT060noISP (); - OPECODE ((WORD2 & 0x0800) ? "chk2" : "cmp2"); - code->size = code->size2 = (BYTE1 >> 1) & 0x03; - code->bytes = 4; - setEA (code, &code->op1, ptr, CONTROL); - setRn (&code->op2, BYTE3 >> 4); - return; - } +static boolean resetope(disasm* code) { + OPECODE(reset); + return TRUE; +} - /* cas */ - if ((WORD1 & 0x09c0) == 0x08c0 && (BYTE1 & 0x06) != 0 - && (WORD2 & 0xfe38) == 0x0000) { - REJECT (M000|M010); - - IfNeedStr { - strcpy (code->opecode, "cas"); - strcpy (code->op1.operand, "d0"); - strcpy (code->op2.operand, "d0"); - code->op1.operand[1] += WORD2 & 7; - code->op2.operand[1] += (WORD2 >> 6) & 7; - } - code->bytes = 4; - code->op1.ea = code->op2.ea = DregD; - setEA (code, &code->op3, ptr, CHANGE ^ DATAREG ^ ADRREG); - code->size = code->size2 = ((BYTE1 >> 1) & 3) - 1; /* サイズ値が普通と違う */ - return; - } +static boolean nopope(disasm* code) { + OPECODE(nop); + return TRUE; +} - /* cas2 */ - if ((WORD1 & 0x0dff) == 0x0cfc - && ((WORD2 | WORD3) & 0x0e38) == 0x0000) { - REJECT (M000|M010); - REJECT060noISP (); - - IfNeedStr { - strcpy (code->opecode, "cas2"); - strcpy (code->op3.operand, "(r0):(r0)"); - code->op3.operand[1] = ((BYTE3 >> 4) & 8) ? 'a' : 'd'; - code->op3.operand[2] += ((BYTE3 >> 4) & 7); - code->op3.operand[6] = ((BYTE5 >> 4) & 8) ? 'a' : 'd'; - code->op3.operand[7] += ((BYTE5 >> 4) & 7); - } - setPairDn (&code->op1, WORD2 & 7, WORD3 & 7); - setPairDn (&code->op2, (WORD2 >> 6) & 7, (WORD3 >> 6) & 7); - code->op3.ea = RegPairID; - code->bytes = 6; - code->size = code->size2 = (BYTE1 & 0x02) ? LONGSIZE : WORDSIZE; - return; - } +// STOP # Unsized +static boolean stopope(codeptr ptr, disasm* code) { + OPECODE(stop); + return setImm(code, &code->op1, ptr, WORDSIZE); +} - if ((WORD1 & 0x0f00) == 0x0e00 && (WORD2 & 0x07ff) == 0x0000) { - REJECT (M000); - - OPECODE ("moves"); - SETSIZE (); - code->bytes = 4; - if (BYTE3 & 0x08) { - setRn (&code->op1, BYTE3 >> 4); - code->op1.ea = ((BYTE3 >> 4) & 8) ? AregD : DregD; - setEA (code, &code->op2, ptr, CHANGE ^ DATAREG ^ ADRREG); - } - else { - setRn (&code->op2, BYTE3 >> 4); - code->op2.ea = ((BYTE3 >> 4) & 8) ? AregD : DregD; - setEA (code, &code->op1, ptr, CHANGE ^ DATAREG ^ ADRREG); - } - return; - } +static boolean rteope(disasm* code) { + OPECODE(rte); + code->opeType = RTSOP; + return TRUE; +} - /* 68020 の callm、rtm */ - if ((WORD1 & 0x0fc0) == 0x06c0) { - REJECT (~M020); - - if ((WORD1 & 0x0030) == 0) { - OPECODE ("rtm"); - setRn (&code->op1, WORD1); - } - else { - if (BYTE3) { - UNDEFINED(); return; - } - IfNeedStr { - strcpy (code->opecode, "callm"); - code->op1.operand[0] = '#'; - itox2d (code->op1.operand + 1, BYTE4); - } - code->op1.ea = IMMED; - code->op1.opval = (address)(ULONG) BYTE4; - code->bytes += 2; - setEA (code, &code->op2, ptr, CONTROL); - } - return; - } +// RTD # Unsized +static boolean rtdope(codeptr ptr, disasm* code) { + if (reject(code, M000)) return FALSE; - UNDEFINED(); return; + OPECODE(rtd); + code->opeType = RTSOP; + return setImm(code, &code->op1, ptr, WORDSIZE); } - -private void -op01 (address ptr, disasm* code) -{ - code->size = code->size2 = BYTESIZE; - moveope (ptr, code); +static boolean rtsope(disasm* code) { + OPECODE(rts); + code->opeType = RTSOP; + return TRUE; } +static boolean trapvope(disasm* code) { + OPECODE(trapv); + return TRUE; +} -private void -op02 (address ptr, disasm* code) -{ - code->size = code->size2 = LONGSIZE; - moveope (ptr, code); +static boolean rtrope(disasm* code) { + OPECODE(rtr); + code->opeType = RTSOP; + return TRUE; } +static boolean movecope(codeptr ptr, disasm* code) { + int dr = WORD1 & 0x0001; -private void -op03 (address ptr, disasm* code) -{ - code->size = code->size2 = WORDSIZE; - moveope (ptr, code); -} - - -private void -moveope (address ptr, disasm *code) -{ - REJECTBYTESIZE (); - - setEA (code, &code->op1, ptr, ALL); - if (code->flag == UNDEF) - return; - - /* movea */ - if ((WORD1 & 0x1c0) == 0x40) { - if (code->size == BYTESIZE) { - UNDEFINED(); return; - } - - setAn (&code->op2, BYTE1 >> 1); - IfNeedStr { - strcpy (code->opecode, "movea"); - if (Disasm_MnemonicAbbreviation) - code->opecode[4] = '\0'; - /* movea.* #imm にはコメントを付ける */ - if (code->op1.ea == IMMED) - code->opflags += FLAG_NEED_COMMENT; - } - return; - } + if (!setCtrlReg(code, dr ? &code->op2 : &code->op1, WORD2 & 0x0fff)) + return FALSE; - setEA (code, &code->op2, ptr, (DATA & CHANGE) | MOVEOPT); + OPECODE(movec); + code->size = code->size2 = code->default_size = LONGSIZE; + setRn(dr ? &code->op1 : &code->op2, BYTE3 >> 4); + code->bytes += 2; + return TRUE; +} - IfNeedStr { - strcpy (code->opecode, "move"); +static boolean op4e7x(codeptr ptr, disasm* code) { + switch (BYTE2 & 0x0f) { + default: + break; + + case 0x0: + return resetope(code); + case 0x1: + return nopope(code); + case 0x2: + return stopope(ptr, code); + case 0x3: + return rteope(code); + case 0x4: + return rtdope(ptr, code); + case 0x5: + return rtsope(code); + case 0x6: + return trapvope(code); + case 0x7: + return rtrope(code); + case 0xa: + case 0xb: + return movecope(ptr, code); + } + + return FALSE; +} - /* move.* #imm にはコメントを付ける */ - if (code->op1.ea == IMMED) { - code->opflags += FLAG_NEED_COMMENT; +static boolean op4x(codeptr ptr, disasm* code) { + switch ((BYTE1 >> 1) & 3) { + default: + return FALSE; + case 0: + OPECODE(negx); + break; + case 1: + OPECODE(clr); + break; + case 2: + OPECODE(neg); + break; + case 3: + OPECODE(not ); + break; + } - /* move.l #imm,Dn が moveq.l #imm,Dn に化けないように... */ - if ((WORD1 & 0x31ff) == 0x203c /* move.l #imm,Dn か? */ - && (LONG05 < 0x80 || 0xffffff80 <= LONG05) /* imm が範囲内か? */ - ) - strcat (code->op1.operand, ".l"); - } - } + SETSIZE(); + return setEA(code, &code->op1, ptr, DATA & CHANGE); } +// JMP, JSR +static boolean jmpjsrope(codeptr ptr, disasm* code) { + if (!setEA(code, &code->op1, ptr, CONTROL)) return FALSE; -private void -op04 (address ptr, disasm* code) -{ - if ((WORD1 & 0xffc0) == 0x4c00) { - switch (WORD2 & 0x8ff8) { - case 0x0000: - REJECT (M000|M010); - - if ((UndefRegLevel & 1) /* 未定義フィールドが 0 or Dl と同じなら正常 */ - && (WORD2 & 7) != 0 && (WORD2 & 7) != ((BYTE3 >> 4) & 7)) { - UNDEFINED(); return; - } - - OPECODE ("mulu"); - code->bytes = 4; - code->size = code->size2 = LONGSIZE; - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, BYTE3 >> 4); - return; - case 0x0400: - REJECT (M000|M010); - REJECT060noISP (); - OPECODE ("mulu"); - longmuldivope (ptr, code); - return; - case 0x0800: - REJECT (M000|M010); - - if ((UndefRegLevel & 1) /* 未定義フィールドが 0 or Dl と同じなら正常 */ - && (WORD2 & 7) != 0 && (WORD2 & 7) != ((BYTE3 >> 4) & 7)) { - UNDEFINED(); return; - } - - OPECODE ("muls"); - code->bytes = 4; - code->size = code->size2 = LONGSIZE; - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, BYTE3 >> 4); - return; - case 0x0c00: - REJECT (M000|M010); - REJECT060noISP (); - OPECODE ("muls"); - longmuldivope (ptr, code); - return; - default: - break; - } - } + code->jmp = code->op1.opval; + code->jmpea = code->op1.ea; - if ((WORD1 & 0xffc0) == 0x4c40) { - switch (WORD2 & 0x8cf8) { - case 0x0000: - REJECT (M000|M010); - - if ((BYTE3 >> 4) == BYTE4) { - OPECODE ("divu"); - code->bytes = 4; - code->size = code->size2 = LONGSIZE; - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, WORD2); - return; - } else { - OPECODE ("divul"); - longmuldivope (ptr, code); - return; - } - case 0x0400: - REJECT (M000|M010); - REJECT060noISP (); - OPECODE ("divu"); - longmuldivope (ptr, code); - return; - case 0x0800: - REJECT (M000|M010); - - if ((BYTE3 >> 4) == BYTE4) { - OPECODE ("divs"); - code->bytes = 4; - code->size = code->size2 = LONGSIZE; - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, WORD2); - return; - } else { - OPECODE ("divsl"); - longmuldivope (ptr, code); - return; - } - case 0x0c00: - REJECT (M000|M010); - REJECT060noISP (); - OPECODE ("divs"); - longmuldivope (ptr, code); - return; - default: - break; - } - } + OPECODE(jsr); + code->opeType = JSROP; + if (BYTE2 & 0x40) { + OPECODE(jmp); + code->opeType = JMPOP; + } - if ((WORD1 & 0x0ff8) == 0x9c0) { - REJECT (M000|M010); + return TRUE; +} - OPECODE ("extb"); - code->size = code->size2 = LONGSIZE; - setDn (&code->op1, WORD1); - return; - } +static boolean leaope(codeptr ptr, disasm* code) { + OPECODE(lea); + code->size = code->default_size = LONGSIZE; + code->size2 = UNKNOWN; + if (!setEA(code, &code->op1, ptr, CONTROL)) return FALSE; + setAn(&code->op2, BYTE1 >> 1); - if ((WORD1 & 0x1c0) == 0x1c0) { - OPECODE ("lea"); - code->size = code->default_size = LONGSIZE; - code->size2 = UNKNOWN; - setEA (code, &code->op1, ptr, CONTROL); - setAn (&code->op2, BYTE1 >> 1); - return; - } + return TRUE; +} - if ((WORD1 & 0x140) == 0x100) { - OPECODE ("chk"); - if ((WORD1 & 0x80) == 0x80) - code->size = code->size2 = WORDSIZE; - else if ((WORD1 & 0x80) == 0x00) { - REJECT (M000|M010); - code->size = code->size2 = LONGSIZE; - } else { - UNDEFINED(); return; - } - setEA (code, &code->op1, ptr, DATA); - setDn (&code->op2, BYTE1 >> 1); - return; - } +static boolean peaope(codeptr ptr, disasm* code) { + OPECODE(pea); + code->size = code->default_size = LONGSIZE; + code->size2 = UNKNOWN; + if (!setEA(code, &code->op1, ptr, CONTROL)) return FALSE; - if (BYTE1 == 0x4e) { - if (0x70 <= BYTE2 && BYTE2 <= 0x77) { - static const char opecode[8][6] = { - "reset", "nop", "stop", "rte", "rtd", "rts", "trapv", "rtr" - }; - - if (BYTE2 == 0x74) - REJECT (M000); /* rtd は 68010 以降専用 */ - - OPECODE (opecode[BYTE2 & 0x0f]); - if (BYTE2 == 0x72 || BYTE2 == 0x74) - setIMD (code, &code->op1, ptr, WORDSIZE); - if (0x73 <= BYTE2 && BYTE2 != 0x76) { - code->flag = RTSOP; - code->opflags += FLAG_NEED_NULSTR; - } - return; - } - if ((WORD1 & 0xf0) == 0x40) { -#ifdef OSKDIS - if (BYTE2 & 15) { - IfNeedStr { - strcpy (code->opecode, "TCALL"); - itox2d (code->op1.operand, BYTE2 & 15); - itox4d (code->op2.operand, WORD2); - } - code->op1.ea = IMMED; - code->op2.ea = IMMED; - code->op1.opval = (address) (BYTE2 & 15); - code->op2.opval = WORD2; - } - else { - IfNeedStr { - strcpy (code->opecode, "OS9"); - itox4d (code->op1.operand, WORD2); - code->op1.ea = IMMED; - code->op1.opval = WORD2; - } - if (WORD2 == 0x0006 /* F$Exit */ - || WORD2 == 0x001e /* F$RTE */ - || WORD2 == 0x002d) { /* F$NProc */ - code->flag = RTSOP; - code->opflags += FLAG_NEED_NULSTR; - } - } - code->bytes = 4; - return; -#else - IfNeedStr { - strcpy (code->opecode, "trap"); - code->op1.operand[0] = '#'; - itod2 (code->op1.operand + 1, WORD1 & 15); - } - code->op1.ea = IMMED; - code->op1.opval = (address) (WORD1 & 15); - return; -#endif /* OSKDIS */ - } - - if ((WORD1 & 0xf8) == 0x50) { /* ワードリンク */ - code->size = WORDSIZE; - setAn (&code->op1, WORD1); -#if 0 - setIMD (code, &code->op2, ptr, WORDSIZE); -#endif - code->op2.ea = IMMED; - code->bytes += 2; - IfNeedStr { - WORD d16 = WORD2; - char* p = code->op2.operand; - - *p++ = '#'; - if (d16 < 0) { - *p++ = '-'; - d16 = -d16 & 0xffff; - } - itox4d (p, d16); - strcpy (code->opecode, "link"); - } - return; - } - if ((WORD1 & 0xf8) == 0x58) { - OPECODE ("unlk"); - setAn (&code->op1, WORD1); - return; - } - - if ((WORD1 & 0xc0) == 0xc0) { - setEA (code, &code->op1, ptr, CONTROL); - if (code->flag == UNDEF) - return; - IfNeedStr { - strcpy (code->opecode, "jmp"); - code->opflags += FLAG_NEED_NULSTR; - } - code->jmp = code->op1.opval; - code->jmpea = code->op1.ea; - code->flag = JMPOP; - return; - } - - if ((WORD1 & 0xc0) == 0x80) { - OPECODE ("jsr"); - setEA (code, &code->op1, ptr, CONTROL); - if (code->flag == UNDEF) - return; - code->jmp = code->op1.opval; - code->jmpea = code->op1.ea; - code->flag = JSROP; - return; - } - - /* move to/from usp */ - if ((WORD1 & 0xf0) == 0x60) { - OPECODE ("move"); - code->size = code->size2 = code->default_size = LONGSIZE; - if (WORD1 & 8) { - IfNeedStr { - strcpy (code->op1.operand, "usp"); - } - setAn (&code->op2, WORD1); - } else { - setAn (&code->op1, WORD1); - IfNeedStr { - strcpy (code->op2.operand, "usp"); - } - } - return; - } - - if ((WORD1 & 0xfe) == 0x7a) { - static const struct { - mputypes mpu; - char name[7]; - } creg_table[2][9] = { { - { M010|M020|M030|M040|M060, "sfc" }, /* 0x000 */ - { M010|M020|M030|M040|M060, "dfc" }, /* 0x001 */ - { M020|M030|M040|M060, "cacr" }, /* 0x002 */ - { M040|M060, "tc" }, /* 0x003 */ - { M040|M060, "itt0" }, /* 0x004 */ - { M040|M060, "itt1" }, /* 0x005 */ - { M040|M060, "dtt0" }, /* 0x006 */ - { M040|M060, "dtt1" }, /* 0x007 */ - { M060, "buscr" }, /* 0x008 */ - }, { - { M010|M020|M030|M040|M060, "usp" }, /* 0x800 */ - { M010|M020|M030|M040|M060, "vbr" }, /* 0x801 */ - { M020|M030, "caar" }, /* 0x802 */ - { M020|M030|M040, "msp" }, /* 0x803 */ - { M020|M030|M040, "isp" }, /* 0x804 */ - { M040, "mmusr" }, /* 0x805 */ - { M040|M060, "urp" }, /* 0x806 */ - { M040|M060, "srp" }, /* 0x807 */ - { M060, "pcr" }, /* 0x808 */ - } }; - int i = (WORD2 & 0x800) >> 11; - int j = (WORD2 & 0x7ff); - const char* p = creg_table[i][j].name; - - if (j > 8) { - UNDEFINED(); return; - } - REJECT (~creg_table[i][j].mpu); - - OPECODE ("movec"); - code->size = code->size2 = code->default_size = LONGSIZE; - code->bytes += 2; - - if (WORD1 & 1) { - IfNeedStr { - strcpy (code->op2.operand, p); - } - setRn (&code->op1, BYTE3 >> 4); - code->op2.ea = CtrlReg; - } else { - IfNeedStr { - strcpy (code->op1.operand, p); - } - setRn (&code->op2, BYTE3 >> 4); - code->op1.ea = CtrlReg; - } - return; - } - } + return TRUE; +} - if ((WORD1 & 0xfb8) == 0x880) { - OPECODE ("ext"); - code->size = code->size2 = (WORD1 & 0x40 ? LONGSIZE : WORDSIZE); - setDn (&code->op1, WORD1); - return; - } +// TST +static boolean tstope(codeptr ptr, disasm* code) { + int mode = (Dis.mpu & ~(M000 | M010)) ? ALL : DATA & CHANGE; + adrmode ea; + + OPECODE(tst); + SETSIZE(); // size が 0b11 なら tas + if (!setEA(code, &code->op1, ptr, mode)) return FALSE; + + ea = code->op1.ea; + if (ea == AregD || (PCDISP <= ea && ea <= IMMED)) { + // アドレスレジスタ直接、PC相対、即値は68020以降専用 + // (full extension word formatはsetEA()内で処理している) + code->mputypes &= ~(M000 | M010); + } + return TRUE; +} - if ((WORD1 & 0xb80) == 0x880) { - if (WORD2 == 0) { /* register field empty ? */ - UNDEFINED(); return; - } - OPECODE ("movem"); - code->size = code->size2 = (WORD1 & 0x40 ? LONGSIZE : WORDSIZE); - code->bytes = 4; - if (BYTE1 & 4) { - setEA (code, &code->op1, ptr, CONTROL | POSTINC); - setreglist (code->op2.operand, ptr); - } else { - setreglist (code->op1.operand, ptr); - setEA (code, &code->op2, ptr, CTRLCHG | PREDEC); - } - return; +static boolean op04(codeptr ptr, disasm* code) { + if ((WORD1 & 0xffc0) == 0x4c00) { + switch (WORD2 & 0x8ff8) { + case 0x0000: + if (reject(code, M000 | M010)) return FALSE; + + if (Dis.undefReg // 未定義フィールドが 0 or Dl と同じなら正常 + && (WORD2 & 7) != 0 && (WORD2 & 7) != ((BYTE3 >> 4) & 7)) { + return FALSE; + } + + OPECODE(mulu); + code->bytes = 4; + code->size = code->size2 = LONGSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, BYTE3 >> 4); + return TRUE; + case 0x0400: + if (reject(code, M000 | M010) || reject_060_no_isp(code)) return FALSE; + + OPECODE(mulu); + return longmuldivope(ptr, code); + case 0x0800: + if (reject(code, M000 | M010)) return FALSE; + + if (Dis.undefReg // 未定義フィールドが 0 or Dl と同じなら正常 + && (WORD2 & 7) != 0 && (WORD2 & 7) != ((BYTE3 >> 4) & 7)) { + return FALSE; + } + + OPECODE(muls); + code->bytes = 4; + code->size = code->size2 = LONGSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, BYTE3 >> 4); + return TRUE; + case 0x0c00: + if (reject(code, M000 | M010) || reject_060_no_isp(code)) return FALSE; + + OPECODE(muls); + return longmuldivope(ptr, code); + default: + break; + } + } + + if ((WORD1 & 0xffc0) == 0x4c40) { + switch (WORD2 & 0x8cf8) { + case 0x0000: + if (reject(code, M000 | M010)) return FALSE; + + if ((BYTE3 >> 4) == BYTE4) { + OPECODE(divu); + code->bytes = 4; + code->size = code->size2 = LONGSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, WORD2); + return TRUE; + } else { + OPECODE(divul); + return longmuldivope(ptr, code); + } + case 0x0400: + if (reject(code, M000 | M010) || reject_060_no_isp(code)) return FALSE; + + OPECODE(divu); + return longmuldivope(ptr, code); + case 0x0800: + if (reject(code, M000 | M010)) return FALSE; + + if ((BYTE3 >> 4) == BYTE4) { + OPECODE(divs); + code->bytes = 4; + code->size = code->size2 = LONGSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, WORD2); + return TRUE; + } else { + OPECODE(divsl); + return longmuldivope(ptr, code); + } + case 0x0c00: + if (reject(code, M000 | M010) || reject_060_no_isp(code)) return FALSE; + + OPECODE(divs); + return longmuldivope(ptr, code); + default: + break; + } + } + + if ((WORD1 & 0x0ff8) == 0x9c0) { + if (reject(code, M000 | M010)) return FALSE; + + OPECODE(extb); + code->size = code->size2 = LONGSIZE; + setDn(&code->op1, WORD1); + return TRUE; + } + + if ((WORD1 & 0x1c0) == 0x1c0) return leaope(ptr, code); + + if ((WORD1 & 0x140) == 0x100) { + OPECODE(chk); + if ((WORD1 & 0x80) == 0x80) + code->size = code->size2 = WORDSIZE; + else if ((WORD1 & 0x80) == 0x00) { + if (reject(code, M000 | M010)) return FALSE; + code->size = code->size2 = LONGSIZE; + } else { + return FALSE; + } + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setDn(&code->op2, BYTE1 >> 1); + return TRUE; + } + + if (BYTE1 == 0x4e) { + if ((BYTE2 & 0xf0) == 0x70) return op4e7x(ptr, code); + + if ((WORD1 & 0xf0) == 0x40) { + void (*decodeTrap)(codeptr ptr, disasm * code) = Dis.actions->decodeTrap; + + if (decodeTrap != NULL) + decodeTrap(ptr, code); + else { + OPECODE(trap); + setImmEmbed(&code->op1, WORD1 & 15); + } + return TRUE; + } + + if ((WORD1 & 0x00f8) == 0x0050) { // link.w + OPECODE(link); + code->size = WORDSIZE; + setAn(&code->op1, WORD1); + setImmSignedWord(code, &code->op2, ptr); + return TRUE; + } + if ((WORD1 & 0xf8) == 0x58) { + OPECODE(unlk); + setAn(&code->op1, WORD1); + return TRUE; + } + + if ((WORD1 & 0xff80) == 0x4e80) return jmpjsrope(ptr, code); // JMP, JSR + + /* move to/from usp */ + if ((WORD1 & 0xf0) == 0x60) { + OPECODE(move); + code->size = code->size2 = code->default_size = LONGSIZE; + if (WORD1 & 0x0008) { + setUsp(&code->op1); + setAn(&code->op2, WORD1); + } else { + setAn(&code->op1, WORD1); + setUsp(&code->op2); + } + return TRUE; + } + } + + if ((WORD1 & 0xfb8) == 0x880) { + OPECODE(ext); + code->size = code->size2 = (WORD1 & 0x40 ? LONGSIZE : WORDSIZE); + setDn(&code->op1, WORD1); + return TRUE; + } + + if ((WORD1 & 0xb80) == 0x880) { + if (WORD2 == 0) { /* register field empty ? */ + return FALSE; + } + OPECODE(movem); + code->size = code->size2 = (WORD1 & 0x40 ? LONGSIZE : WORDSIZE); + code->bytes = 4; + if (BYTE1 & 4) { + if (!setEA(code, &code->op1, ptr, CONTROL | POSTINC)) return FALSE; + setReglist(&code->op2, WORD2, is_predecrement(WORD1)); + } else { + setReglist(&code->op1, WORD2, is_predecrement(WORD1)); + return setEA(code, &code->op2, ptr, CTRLCHG | PREDEC); } + return TRUE; + } - switch (WORD1 & 0xff8) { + switch (WORD1 & 0xff8) { case 0x840: - OPECODE ("swap"); - code->size = code->size2 = WORDSIZE; - setDn (&code->op1, WORD1); - return; + OPECODE(swap); + code->size = code->size2 = WORDSIZE; + setDn(&code->op1, WORD1); + return TRUE; case 0x848: - REJECT (M000); - - IfNeedStr { - strcpy (code->opecode, "bkpt"); - code->op1.operand[0] = '#'; - code->op1.operand[1] = (WORD1 & 7) + '0'; - code->op1.operand[2] = '\0'; - } - code->op1.ea = IMMED; - code->op1.opval = (address) (WORD1 & 7); - return; - case 0x808: - REJECT (M000|M010); - - code->size = LONGSIZE; /* ロングワードリンク */ - setAn (&code->op1, WORD1); - code->op2.ea = IMMED; - code->bytes += 4; - IfNeedStr { - LONG d32 = LONG05; - char* p = code->op2.operand; - - *p++ = '#'; - if (d32 < 0) { - *p++ = '-'; - d32 = -d32; - } - itox8d (p, d32); - strcpy (code->opecode, "link"); - } - return; - } - - switch (WORD1 & 0xfc0) { + if (reject(code, M000)) return FALSE; + + OPECODE(bkpt); + setImmEmbed(&code->op1, WORD1 & 7); + return TRUE; + case 0x808: // link.l + if (reject(code, M000 | M010)) return FALSE; + + OPECODE(link); + code->size = LONGSIZE; + setAn(&code->op1, WORD1); + setImmSignedLong(code, &code->op2, ptr); + return TRUE; + } + + switch (WORD1 & 0xfc0) { case 0x4c0: - code->size = code->size2 = WORDSIZE; /* move to ccr */ - setEA (code, &code->op1, ptr, DATA); - IfNeedStr { - strcpy (code->opecode, "move"); - strcpy (code->op2.operand, "ccr"); - } - return; + OPECODE(move); // move to ccr + code->size = code->size2 = WORDSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setCcr(&code->op2); + return TRUE; case 0x6c0: - code->size = code->size2 = WORDSIZE; /* move to sr */ - setEA (code, &code->op1, ptr, DATA); - IfNeedStr { - strcpy (code->opecode, "move"); - strcpy (code->op2.operand, "sr"); - } - return; + OPECODE(move); // move to sr + code->size = code->size2 = WORDSIZE; + if (!setEA(code, &code->op1, ptr, DATA)) return FALSE; + setSr(&code->op2); + return TRUE; case 0x0c0: - code->size = code->size2 = WORDSIZE; /* move from sr */ - IfNeedStr { - strcpy (code->opecode, "move"); - strcpy (code->op1.operand, "sr"); - } - setEA (code, &code->op2, ptr, DATA); - return; - case 0x2c0: - REJECT (M000); - - code->size = code->size2 = WORDSIZE; /* move from ccr */ - IfNeedStr { - strcpy (code->opecode, "move"); - strcpy (code->op1.operand, "ccr"); - } - setEA (code, &code->op2, ptr, DATA); - return; + OPECODE(move); // move from sr + code->size = code->size2 = WORDSIZE; + setSr(&code->op1); + return setEA(code, &code->op2, ptr, DATA); + case 0x2c0: // move from ccr + if (reject(code, M000)) return FALSE; + + OPECODE(move); + code->size = code->size2 = WORDSIZE; + setCcr(&code->op1); + return setEA(code, &code->op2, ptr, DATA); case 0x840: - OPECODE ("pea"); - code->size = code->default_size = LONGSIZE; - code->size2 = UNKNOWN; - setEA (code, &code->op1, ptr, CONTROL); - return; + return peaope(ptr, code); case 0xac0: - if (WORD1 == 0x4afc) { - OPECODE ("illegal"); - return; - } - else if (WORD1 == 0x4afa && Disasm_CPU32) { - OPECODE ("bgnd"); - return; - } - OPECODE ("tas"); - code->size = code->size2 = code->default_size = BYTESIZE; - setEA (code, &code->op1, ptr, DATA & CHANGE); - return; + if (WORD1 == 0x4afc) { + OPECODE(illegal); + return TRUE; + } else if (WORD1 == 0x4afa && Dis.cpu32) { + OPECODE(bgnd); + return TRUE; + } + OPECODE(tas); + code->size = code->size2 = code->default_size = BYTESIZE; + return setEA(code, &code->op1, ptr, DATA & CHANGE); case 0x800: - OPECODE ("nbcd"); - code->size = code->size2 = code->default_size = BYTESIZE; - setEA (code, &code->op1, ptr, DATA & CHANGE); - return; - } + OPECODE(nbcd); + code->size = code->size2 = code->default_size = BYTESIZE; + return setEA(code, &code->op1, ptr, DATA & CHANGE); + } - if ((BYTE1 & 1) == 0) { - - /* tst */ - if (BYTE1 == 0x4a) { - OPECODE ("tst"); - SETSIZE (); /* size が 0b11 なら tas */ - setEA (code, &code->op1, ptr, - (MPU_types & ~(M000|M010)) ? ALL : DATA & CHANGE); - /* An 直接、PC 相対、即値は 68020 以降専用 */ - if ((ALL ^ (DATA & CHANGE)) & pow2[code->op1.ea]) - code->mputypes &= ~(M000|M010); - return; - } - - /* negx, clr, neg, not */ - if (BYTE1 <= 0x46) { - static const char opecode[4][5] = { - "negx", "clr", "neg", "not" - }; - - OPECODE (opecode[(BYTE1 & 0x0e) >> 1]); - SETSIZE (); - setEA (code, &code->op1, ptr, DATA & CHANGE); - return; - } - } + if (BYTE1 == 0x4a) return tstope(ptr, code); - UNDEFINED(); return; -} - - -private void -op05 (address ptr, disasm* code) -{ - - /* DBcc */ - if ((BYTE2 >> 3) == 0x19) { - - IfNeedStr { - if (BYTE1 == 0x51 && Disasm_Dbra) - strcpy (code->opecode, "dbra"); /* dbf -> dbra */ - else { - strcpy (code->opecode, "db"); - setcond (ptr, code); - } - } - - setDn (&code->op1, WORD1); - setrelative (code->op2.operand, SignWORD2, &code->op2.opval); - code->jmp = code->op2.opval; - code->jmpea = code->op2.ea = PCDISP; - code->op2.labelchange1 = -1; /* TRUE */ -#ifdef OSKDIS /* OS-9/680x0 のアセンブラ(r68)では DBcc */ - code->size = NOTHING; /* にサイズを付けるとエラーになるため */ -#else - code->size = WORDSIZE; -#endif - code->size2 = WORDSIZE; - code->bytes = 4; - code->flag = BCCOP; - return; - } + if ((BYTE1 & 1) == 0) { + // negx, clr, neg, not + if (BYTE1 <= 0x46) return op4x(ptr, code); + } - /* 68020 以降の trapcc */ - if ((WORD1 & 0xf8) == 0xf8 && (0xfa <= BYTE2) && (BYTE2 <= 0xfc)) { - REJECT (M000|M010); - - IfNeedStr { - strcpy (code->opecode, "trap"); - setcond (ptr, code); - } -#if 0 - code->default_size = NOTHING; -#endif - if (BYTE2 == 0xfa) - setIMD (code, &code->op1, ptr, code->size = WORDSIZE); - else if (BYTE2 == 0xfb) - setIMD (code, &code->op1, ptr, code->size = LONGSIZE); - return; - } + return FALSE; +} - /* Scc */ - if ((WORD1 & 0xc0) == 0xc0) { - IfNeedStr { - code->opecode[0] = 's'; - code->opecode[1] = '\0'; - setcond (ptr, code); - } - code->size = code->size2 = code->default_size = BYTESIZE; - setEA (code, &code->op1, ptr, DATA & CHANGE); - return; - } +static boolean op05(codeptr ptr, disasm* code) { + /* DBcc */ + if ((BYTE2 >> 3) == 0x19) { + OPECODE(dbcc[BYTE1 & 0x0f]); + setDn(&code->op1, WORD1); + setrelative(code, &code->op2, extl(WORD2)); + code->jmp = code->op2.opval; + code->jmpea = code->op2.ea = PCDISP; + code->op2.labelchange1 = LABELCHANGE_LABEL_ONLY; - /* addq、subq */ - { - REJECTBYTESIZE (); - SETSIZE (); - OPECODE ((BYTE1 & 1) ? "subq" : "addq"); - set18 (&code->op1, BYTE1 >> 1); - setEA (code, &code->op2, ptr, CHANGE); - return; - } + code->size = Dis.dbccSize; + code->size2 = WORDSIZE; - /* NOT REACHED */ -} + code->bytes = 4; + code->opeType = BCCOP; + return TRUE; + } + + /* 68020 以降の trapcc */ + if ((WORD1 & 0xf8) == 0xf8 && (0xfa <= BYTE2) && (BYTE2 <= 0xfc)) { + if (reject(code, M000 | M010)) return FALSE; + + OPECODE(trapcc[BYTE1 & 0x0f]); + if (BYTE2 == 0xfa) + return setImm(code, &code->op1, ptr, code->size = WORDSIZE); + else if (BYTE2 == 0xfb) + return setImm(code, &code->op1, ptr, code->size = LONGSIZE); + return TRUE; + } + + /* Scc */ + if ((WORD1 & 0xc0) == 0xc0) { + OPECODE(scc[BYTE1 & 0x0f]); + code->size = code->size2 = code->default_size = BYTESIZE; + return setEA(code, &code->op1, ptr, DATA & CHANGE); + } + // addq, subq + SETSIZE(); + if (reject_bytesize(code, WORD1)) return FALSE; -private void -op06 (address ptr, disasm* code) -{ - switch (BYTE1 & 0x0f) { - case 0: - IfNeedStr { - strcpy (code->opecode, "bra"); - code->opflags += FLAG_NEED_NULSTR; - } - code->flag = JMPOP; - break; - case 1: - OPECODE ("bsr"); - code->flag = JSROP; - break; - default: - IfNeedStr { - code->opecode[0] = 'b'; - code->opecode[1] = '\0'; - setcond (ptr, code); - } - code->flag = BCCOP; - break; - } - if (BYTE2 == 0x00) { - code->bytes = 4; - code->size = code->size2 = WORDSIZE; - setrelative (code->op1.operand, SignWORD2, &code->op1.opval); - } else if (BYTE2 == 0xff && (MPU_types & ~(M000|M010))) { - code->mputypes &= ~(M000|M010); - code->bytes = 6; - code->size = code->size2 = LONGSIZE; - setlongrelative (code->op1.operand, SignLONG05, &code->op1.opval); - } else { - code->size = code->size2 = SHORTSIZE; - setrelative (code->op1.operand, SignBYTE2, &code->op1.opval); - } - code->default_size = NOTHING; - code->jmp = code->op1.opval; - code->jmpea = code->op1.ea = PCDISP; - code->op1.labelchange1 = -1; /* TRUE */ + OPECODE2(BYTE1 & 1, subq, addq); + setImm18(&code->op1, BYTE1 >> 1); + return setEA(code, &code->op2, ptr, CHANGE); } - -private void -op07 (address ptr, disasm* code) -{ - if (BYTE1 & 1) { - UNDEFINED(); return; - } - code->size = code->default_size = LONGSIZE; - code->size2 = UNKNOWN; - IfNeedStr { - strcpy (code->opecode, "moveq"); - code->op1.operand[0] = '#'; - itox2d (code->op1.operand + 1, BYTE2); - /* moveq も -M でコメントを付ける */ - code->opflags += FLAG_NEED_COMMENT; - } - code->op1.ea = IMMED; - code->op1.opval = (address)(ULONG) BYTE2; - setDn (&code->op2, BYTE1 >> 1); +static boolean op06(codeptr ptr, disasm* code) { + UBYTE d8 = BYTE2; + int cc = BYTE1 & 0x0f; + + OPECODE(bcc[cc]); + switch (cc) { + case 0: // BRA + code->codeflags += CODEFLAG_BRAOP; + code->opeType = JMPOP; + break; + case 1: // BSR + code->opeType = JSROP; + break; + default: // Bcc + code->opeType = BCCOP; + break; + } + + if (d8 == 0x00) { + WORD d16 = WORD2; + code->bytes = 4; + code->size = code->size2 = WORDSIZE; + setrelative(code, &code->op1, extl(d16)); + if (-128 <= d16 && d16 <= 128) code->codeflags += CODEFLAG_NEED_OPESIZE; + } else if (d8 == 0xff && (Dis.mpu & ~(M000 | M010))) { + LONG d32 = LONG05; + code->mputypes &= ~(M000 | M010); + code->bytes = 6; + code->size = code->size2 = LONGSIZE; + setrelative(code, &code->op1, d32); + if (-32768 <= d32 && d32 <= 32768) code->codeflags += CODEFLAG_NEED_OPESIZE; + } else { + code->size = code->size2 = SHORTSIZE; + setrelative(code, &code->op1, extbl(d8)); + } + code->default_size = NOTHING; + code->jmp = code->op1.opval; + code->jmpea = code->op1.ea = PCDISP; + code->op1.labelchange1 = LABELCHANGE_LABEL_ONLY; + + return TRUE; } +static boolean op07(codeptr ptr, disasm* code) { + if (BYTE1 & 1) return FALSE; -private void -op08 (address ptr, disasm* code) -{ - if ((WORD1 & 0x1f0) == 0x100) { - bcdope (ptr, code, "sbcd"); - return; - } + code->size = code->default_size = LONGSIZE; + code->size2 = UNKNOWN; + if (Dis.needString) { + OPECODE(moveq); + // moveq も -M でコメントを付ける + code->codeflags += CODEFLAG_NEED_COMMENT; + } + setImmEmbedHex(&code->op1, BYTE2); + setDn(&code->op2, BYTE1 >> 1); - if ((WORD1 & 0x1f0) == 0x140) { - packope (ptr, code, "pack"); - return; - } - if ((WORD1 & 0x1f0) == 0x180) { - packope (ptr, code, "unpk"); - return; - } - - if ((WORD1 & 0xc0) == 0xc0) { - OPECODE ("div"); - muldivope (ptr, code); - return; - } else { - OPECODE ("or"); - logicope (ptr, code); - return; - } - - /* NOT REACHED */ -} - -/* pack, unpack 用 */ -static void -packope (address ptr, disasm* code, const char* opname) -{ - - REJECT (M000|M010); - - code->op1.ea = code->op2.ea = (WORD1 & 8) ? AregIDPD : DregD; - IfNeedStr { - strcpy (code->opecode, opname); - /* pack、unpk にはコメントを付ける */ - code->opflags += FLAG_NEED_COMMENT; - if (WORD1 & 8) { - strcpy (code->op1.operand, "-(a0)"); - strcpy (code->op2.operand, "-(a0)"); - code->op1.operand[3] += WORD1 & 7; - code->op2.operand[3] += (BYTE1 >> 1) & 7; - } - else { - strcpy (code->op1.operand, "d0"); - strcpy (code->op2.operand, "d0"); - code->op1.operand[1] += WORD1 & 7; - code->op2.operand[1] += (BYTE1 >> 1) & 7; - } - } - setIMD (code, &code->op3, ptr, WORDSIZE); + return TRUE; } - -private void -op09 (address ptr, disasm* code) -{ - addsubope (ptr, code, "sub"); +static boolean op08(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; + UWORD w = word1 & 0x01f0; + + if (w == 0x0100) { // 0b1000_yyy1_0000_rxxx + OPECODE(sbcd); + return bcdope(ptr, code); + } + + if (w == 0x0140) { // 0b1000_yyy1_0100_rxxx + OPECODE(pack); + return packope(ptr, code); + } + if (w == 0x0180) { // 0b1000_yyy1_1000_rxxx + OPECODE(unpk); + return packope(ptr, code); + } + + if ((word1 & 0x00c0) == 0x00c0) { + if (word1 & 0x0100) + OPECODE(divs); // 0b1000_rrr1_11mm_mrrr + else + OPECODE(divu); // 0b1000_rrr0_11mm_mrrr + return muldivope(ptr, code); + } + + // 0b1000_dddo_oomm_mrrr + OPECODE(or); + return logicope(ptr, code); } +// pack, unpack +static boolean packope(codeptr ptr, disasm* code) { + int reg_y, reg_x; -private void -op0a (address ptr, disasm* code) -{ + if (reject(code, M000 | M010)) return FALSE; -#ifndef OSKDIS - /* SXlable != NULL なら必ず Disasm_SX_Window == TRUE */ - if (SXlabel && SXlabel[WORD1 & 0xfff]) { - IfNeedStr { - strcpy (code->opecode, SXCallName); - strcpy (code->op1.operand, SXlabel[WORD1 & 0xfff]); - code->opflags += FLAG_CANNOT_UPPER; - } - if (WORD1 == SX_WINDOW_EXIT) { - code->flag = RTSOP; - code->opflags += FLAG_NEED_NULSTR; - } - code->size = code->size2 = code->default_size = NOTHING; - return; - } -#endif /* !OSKDIS */ - - /* 未使用の A-line を未定義命令と見なさない */ - if (!Disasm_UnusedTrapUndefined) { - IfNeedStr { - strcpy (code->opecode, DC_WORD); - itox4d (code->op1.operand, WORD1); - } - code->size = code->size2 = code->default_size = WORDSIZE; - return; - } + reg_y = (BYTE1 >> 1) & 7; + reg_x = WORD1 & 7; + if (WORD1 & 0x0008) { + setAnPredec(&code->op1, reg_x); + setAnPredec(&code->op2, reg_y); + } else { + setDn(&code->op1, reg_x); + setDn(&code->op2, reg_y); + } + if (!setImm(code, &code->op3, ptr, WORDSIZE)) return FALSE; + + // pack、unpk にはコメントを付ける + code->codeflags += CODEFLAG_NEED_COMMENT; + return TRUE; } +static boolean op09(codeptr ptr, disasm* code) { + return addsubope(ptr, code, FALSE); +} -private void -op0b (address ptr, disasm* code) -{ +static boolean op0a(codeptr ptr, disasm* code) { + const char* label = Dis.sxLabel ? Dis.sxLabel[WORD1 & 0xfff] : NULL; - /* cmpa */ - if ((WORD1 & 0xc0) == 0xc0) { - code->size = code->size2 = (BYTE1 & 1) ? LONGSIZE : WORDSIZE; - setEA (code, &code->op1, ptr, ALL); - setAn (&code->op2, BYTE1 >> 1); - IfNeedStr { - strcpy (code->opecode, "cmpa"); - /* cmpa.* #imm にはコメントを付ける */ - if (code->op1.ea == IMMED) - code->opflags += FLAG_NEED_COMMENT; - } - return; + if (label) { + if (Dis.needString) { + OPECODE(sxcall); + strcpy(code->op1.operand, label); } - - /* cmpm */ - if ((WORD1 & 0x138) == 0x108) { - SETSIZE (); - IfNeedStr { - strcpy (code->opecode, "cmpm"); - if (Disasm_MnemonicAbbreviation) - code->opecode[3] = '\0'; - strcpy (code->op1.operand, "(a0)+"); - strcpy (code->op2.operand, "(a0)+"); - code->op1.operand[2] += WORD1 & 7; - code->op2.operand[2] += (BYTE1 >> 1) & 7; - } - code->op1.ea = code->op2.ea = AregIDPI; - return; + if (WORD1 == SX_WINDOW_EXIT) { + code->opeType = RTSOP; } + code->size = code->size2 = code->default_size = NOTHING; + return TRUE; + } - /* cmp */ - if ((BYTE1 & 1) == 0) { - REJECTBYTESIZE (); - SETSIZE (); - setEA (code, &code->op1, ptr, ALL); - setDn (&code->op2, BYTE1 >> 1); - IfNeedStr { - strcpy (code->opecode, "cmp"); - /* cmp.* #imm にはコメントを付ける */ - if (code->op1.ea == IMMED) - code->opflags += FLAG_NEED_COMMENT; - } - return; + if (Dis.acceptUnusedTrap) { + // 未使用の A-line を未定義命令と見なさない + if (Dis.needString) { + OPECODE(dcWord); + itox4d(code->op1.operand, WORD1); } + code->size = code->size2 = code->default_size = WORDSIZE; + return TRUE; + } - /* eor */ - if (BYTE1 & 1) { - OPECODE ("eor"); - SETSIZE (); - setDn (&code->op1, BYTE1 >> 1); - setEA (code, &code->op2, ptr, DATA & CHANGE); - return; - } + return FALSE; +} - UNDEFINED(); return; +static boolean op0b(codeptr ptr, disasm* code) { + // CMPA + if ((WORD1 & 0xc0) == 0xc0) { + code->size = code->size2 = (BYTE1 & 1) ? LONGSIZE : WORDSIZE; + if (!setEA(code, &code->op1, ptr, ALL)) return FALSE; + setAn(&code->op2, BYTE1 >> 1); + OPECODE(cmpa); + + // cmpa.* #imm にはコメントを付ける + if (code->op1.ea == IMMED) code->codeflags += CODEFLAG_NEED_COMMENT; + + return TRUE; + } + + // CMPM + if ((WORD1 & 0x138) == 0x108) { + SETSIZE(); + OPECODE(cmpm); + setAnPostinc(&code->op1, WORD1 & 7); + setAnPostinc(&code->op2, (BYTE1 >> 1) & 7); + return TRUE; + } + + // CMP + if ((BYTE1 & 1) == 0) { + SETSIZE(); + if (reject_bytesize(code, WORD1)) return FALSE; + + if (!setEA(code, &code->op1, ptr, ALL)) return FALSE; + setDn(&code->op2, BYTE1 >> 1); + OPECODE(cmp); + + // cmp.* #imm にはコメントを付ける + if (code->op1.ea == IMMED) code->codeflags += CODEFLAG_NEED_COMMENT; + + return TRUE; + } + + /* eor */ + if (BYTE1 & 1) { + OPECODE(eor); + SETSIZE(); + setDn(&code->op1, BYTE1 >> 1); + return setEA(code, &code->op2, ptr, DATA & CHANGE); + } + + return FALSE; } +static boolean op0c(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; + + if ((word1 & 0x01f0) == 0x0100) { // 0b1100_xxx1_0000_ryyy + OPECODE(abcd); + return bcdope(ptr, code); + } + + // 0b1100_xxx1_oooo_oyyy + { + int tmp = word1 & 0x01f8; + + if (tmp == 0x140 || tmp == 0x148 || tmp == 0x188) { + OPECODE(exg); + code->size = code->size2 = code->default_size = LONGSIZE; + switch (tmp) { + case 0x140: + setDn(&code->op1, BYTE1 >> 1); + setDn(&code->op2, WORD1); + break; + case 0x148: + setAn(&code->op1, BYTE1 >> 1); + setAn(&code->op2, WORD1); + break; + case 0x188: + setDn(&code->op1, BYTE1 >> 1); + setAn(&code->op2, WORD1); + break; + } + return TRUE; + } + } + + if ((word1 & 0x00c0) == 0x00c0) { + if (word1 & 0x0100) + OPECODE(muls); // 0b1100_rrr1_11mm_mrrr + else + OPECODE(mulu); // 0b1100_rrr0_11mm_mrrr + return muldivope(ptr, code); + } + + // 0b1100_dddo_oomm_mrrr + OPECODE(and); + return logicope(ptr, code); +} -private void -op0c (address ptr, disasm* code) -{ +static boolean op0d(codeptr ptr, disasm* code) { + return addsubope(ptr, code, TRUE); +} - if ((WORD1 & 0x1f0) == 0x100) { - bcdope (ptr, code, "abcd"); - return; - } +static boolean bitfieldope(codeptr ptr, disasm* code) { + enum { + BF_ONLY, + BF_DREG, + DREG_BF, + }; + static const uint8_t addressing[] = { + BF_ONLY, // bftst + BF_DREG, // bfextu + BF_ONLY, // bfchg + BF_DREG, // bfexts + BF_ONLY, // bfclr + BF_DREG, // bfffo + BF_ONLY, // bfset + DREG_BF, // bfins + }; + UWORD word2 = WORD2; + + if ((word2 & 0x8000) || reject(code, M000 | M010)) return FALSE; + + code->bytes = 4; + OPECODE(bitfield[BYTE1 & 7]); + + switch (addressing[BYTE1 & 7]) { + case BF_ONLY: // bf... ea{m:n} + if (!setEA(code, &code->op1, ptr, + DATAREG | ((BYTE1 & 7) ? CTRLCHG : CONTROL))) + return FALSE; + setBitField(&code->op2, word2); + break; + case BF_DREG: // bf... ea{m:n},dn + if (!setEA(code, &code->op1, ptr, CONTROL | DATAREG)) return FALSE; + setBitField(&code->op2, word2); + setDn(&code->op3, BYTE3 >> 4); + break; + case DREG_BF: // bf... dn,ea{m:n} + setDn(&code->op1, BYTE3 >> 4); + if (!setEA(code, &code->op2, ptr, CTRLCHG | DATAREG)) return FALSE; + setBitField(&code->op3, word2); + break; + } + + return TRUE; +} - { - int tmp = WORD1 & 0x1f8; - - if (tmp == 0x140 || tmp == 0x148 || tmp == 0x188) { - OPECODE ("exg"); - code->size = code->size2 = code->default_size = LONGSIZE; - switch (tmp) { - case 0x140: - setDn (&code->op1, BYTE1 >> 1); - setDn (&code->op2, WORD1); - break; - case 0x148: - setAn (&code->op1, BYTE1 >> 1); - setAn (&code->op2, WORD1); - break; - case 0x188: - setDn (&code->op1, BYTE1 >> 1); - setAn (&code->op2, WORD1); - break; - } - return; - } - } +static boolean op0e(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; - if ((WORD1 & 0xc0) == 0xc0) { - OPECODE ("mul"); - muldivope (ptr, code); - return; - } else { - OPECODE ("and"); - logicope (ptr, code); - return; - } + if ((word1 & 0xf8c0) == 0xe8c0) return bitfieldope(ptr, code); - /* NOT REACHED */ -} - - -private void -op0d (address ptr, disasm* code) -{ - addsubope (ptr, code, "add"); -} - - -private void -op0e (address ptr, disasm* code) -{ - -#define BF_ONLY 0 -#define BF_DREG 1 -#define DREG_BF 2 - if ((WORD1 & 0xf8c0) == 0xe8c0) { - static const struct { - const char addressing; - const char opname[7]; - } bf_op[8] = { - { BF_ONLY, "bftst" }, - { BF_DREG, "bfextu" }, - { BF_ONLY, "bfchg" }, - { BF_DREG, "bfexts" }, - { BF_ONLY, "bfclr" }, - { BF_DREG, "bfffo" }, - { BF_ONLY, "bfset" }, - { DREG_BF, "bfins" } - }; - - REJECT (M000|M010); - if (BYTE3 & 0x80) { - UNDEFINED(); return; - } - - code->bytes = 4; - OPECODE (bf_op[BYTE1 & 7].opname); - switch (bf_op[BYTE1 & 7].addressing) { - case BF_ONLY: /* bf... ea{m:n} */ - setEA (code, &code->op1, ptr, DATAREG | ((BYTE1 & 7) ? CTRLCHG : CONTROL)); - setBitField (&code->op2, ptr); - break; - case BF_DREG: /* bf... ea{m:n},dn */ - setEA (code, &code->op1, ptr, CONTROL | DATAREG); - setBitField (&code->op2, ptr); - setDn (&code->op3, BYTE3 >> 4); - break; - case DREG_BF: /* bf... dn,ea{m:n} */ - setDn (&code->op1, BYTE3 >> 4); - setEA (code, &code->op2, ptr, CTRLCHG | DATAREG); - setBitField (&code->op3, ptr); - break; - } - return; - } -#undef BF_ONLY -#undef BF_DREG -#undef DREG_BF - - { - static const char sft_op[8][5] = { - "asr", "asl", "lsr", "lsl", "roxr", "roxl", "ror", "rol" - }; - - if ((WORD1 & 0xc0) == 0xc0) { /* op.w */ - code->size = code->size2 = WORDSIZE; - setEA (code, &code->op1, ptr, MEMORY & CHANGE); - OPECODE (sft_op[ BYTE1 & 7 ]); - } else { - SETSIZE(); - if (WORD1 & 0x20) - setDn (&code->op1, BYTE1 >> 1); /* op.* dm,dn */ - else - set18 (&code->op1, BYTE1 >> 1); /* op.* #q,dn */ - setDn (&code->op2, WORD1); - OPECODE (sft_op[((WORD1 & 0x18) >> 2) + (BYTE1 & 1)]); - } - return; - } + // ビットフィールド命令でなければ、シフト・ローテート命令 - /* 未定義のビットパターンは存在しない. */ -} - - -private void -setBitField (operand* op, address ptr) -{ - op->ea = BitField; - IfNeedStr { - char *p = op->operand; - *p++ = '{'; - if (BYTE3 & 0x08) { - *p++ = 'd'; - *p++ = ((WORD2 >> 6) & 7) + '0'; - } else - p = itod2 (p, (WORD2 >> 6) & 0x1f); - *p++ = ':'; - if (WORD2 & 0x20) { - *p++ = 'd'; - *p++ = (WORD2 & 7) + '0'; - } else - p = itod2 (p, (WORD2 & 0x1f) ? : 32); - *p++ = '}'; - *p++ = '\0'; - } + // op.W + if ((word1 & 0x00c0) == 0x00c0) { + OPECODE(shift[BYTE1 & 7]); + code->size = code->size2 = WORDSIZE; + return setEA(code, &code->op1, ptr, MEMORY & CHANGE); + } + + SETSIZE(); + if (word1 & 0x0020) + setDn(&code->op1, BYTE1 >> 1); // op.* dm,dn + else + setImm18(&code->op1, BYTE1 >> 1); // op.* #q,dn + setDn(&code->op2, word1); + OPECODE(shift[((word1 & 0x18) >> 2) + (BYTE1 & 1)]); + return TRUE; } - -static const char* ExtensionField[128] = { - "fmove" , "fint" , "fsinh" , "fintrz" , - "fsqrt" , NULL , "flognp1" , NULL , - "fetoxm1" , "ftanh" , "fatan" , NULL , - "fasin" , "fatanh" , "fsin" , "ftan" , - "fetox" , "ftwotox", "ftentox" , NULL , - "flogn" , "flog10" , "flog2" , NULL , - "fabs" , "fcosh" , "fneg" , NULL , - "facos" , "fcos" , "fgetexp" , "fgetman" , - "fdiv" , "fmod" , "fadd" , "fmul" , - "fsgldiv" , "frem" , "fscale" , "fsglmul" , - "fsub" , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - "fsincos" , "fsincos", "fsincos" , "fsincos" , - "fsincos" , "fsincos", "fsincos" , "fsincos" , - "fcmp" , NULL , "ftst" , NULL , - NULL , NULL , NULL , NULL , - - "fsmove" , "fssqrt" , NULL , NULL , - "fdmove" , "fdsqrt" , NULL , NULL , - NULL , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - "fsabs" , NULL , "fsneg" , NULL , - "fdabs" , NULL , "frneg" , NULL , - "fsdiv" , NULL , "fsadd" , "fsmul" , - "fddiv" , NULL , "fdadd" , "fdmul" , - "fssub" , NULL , NULL , NULL , - "fdsub" , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , - NULL , NULL , NULL , NULL , -}; - - -static const unsigned char ExtensionFlags[128] = { - - F88x|F040|F060, F88x|F4SP|F060, F88x|F4SP|F6SP, F88x|F4SP|F060, - F88x|F040|F060, 0 , F88x|F4SP|F6SP, 0, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, 0, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, 0, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, 0, - F88x|F040|F060, F88x|F4SP|F6SP, F88x|F040|F060, 0, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, - F88x|F040|F060, F88x|F4SP|F6SP, F88x|F040|F060, F88x|F040|F060, - F88x|F4SP|F060, F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F060, - F88x|F040|F060, 0 , 0 , 0, - 0 , 0 , 0 , 0, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, - F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, F88x|F4SP|F6SP, - F88x|F040|F060, 0 , F88x|F040|F060, 0, - 0 , 0 , 0 , 0, - - F040|F060, F040|F060, 0 , 0, - F040|F060, F040|F060, 0 , 0, - 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0, - F040|F060, 0 , F040|F060, 0, - F040|F060, 0 , F040|F060, 0, - F040|F060, 0 , F040|F060, F040|F060, - F040|F060, 0 , F040|F060, F040|F060, - F040|F060, 0 , 0 , 0, - F040|F060, 0 , 0 , 0, - 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0, - 0 , 0 , 0 , 0, -}; - - - -/* - opecode FPm,FPn が有効 +1 fxxx fpm,fpn というformatが存在しない場合 - opecode FPm が有効 +2 fxxx fpn,fpn が fxxx fpn と解釈される場合 - - ex) ftst = 2, fmove = 1, fabs = 1+2 -*/ -static const unsigned char ExtensionFormat[128] = { - 1, 3, 3, 3, - 3, 0, 3, 0, - 3, 3, 3, 0, - 3, 3, 3, 3, - 3, 3, 3, 0, - 3, 3, 3, 0, - 3, 3, 3, 0, - 3, 3, 3, 3, - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 0, 0, 0, - 0, 0, 0, 0, - 1, 1, 1, 1, - 1, 1, 1, 1, - 1, 0, 2, 0, - 0, 0, 0, 0, - - 1, 3, 0, 0, - 1, 3, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 3, 0, 3, 0, - 3, 0, 3, 0, - 1, 0, 1, 1, - 1, 0, 1, 1, - 1, 0, 0, 0, - 1, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0 -}; - - - -/* move16用 */ -INLINE private void -setAbsLong (disasm* code, operand* op, address ptr) -{ - op->opval = (address) peekl (ptr + code->bytes); - - IfNeedStr { - char* p = op->operand; - *p++ = '('; - p = itox8d (p, (LONG) op->opval); - *p++ = ')'; - *p = '\0'; - } - op->ea = AbLong; - op->eaadrs = PC + code->bytes; - code->bytes += 4; +typedef enum { + C_SCOPE_ILLEGAL = 0, + C_SCOPE_LINE = 1, + C_SCOPE_PAGE = 2, + C_SCOPE_ALL = 3, +} CacheScope; + +// 68040/68060 cinv, cpush命令 +static boolean cinvpushope(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; + int regno = word1 & 7; + CacheScope scope = (CacheScope)((word1 >> 3) & 3); + + // cinva, cpushaはレジスタを使用しないので、普通はレジスタ番号が0になる + if (scope == C_SCOPE_ILLEGAL || + (scope == C_SCOPE_ALL && regno != 0 && Dis.undefReg)) { + return FALSE; + } + + code->mputypes &= (M040 | M060); + OPECODE(cache[(word1 >> 3) & 7]); + setCacheKind(&code->op1, (word1 >> 6) & 3); + if (scope != C_SCOPE_ALL) setAnIndirect(&code->op2, regno); + return TRUE; } -INLINE private void -setPMMUreg (disasm* code, operand* op, address ptr) -{ - - op->ea = MMUreg; - code->size = code->size2 = WORDSIZE; - code->bytes = 4; +// 68040/68060 pflush, pflushn, pflusha, pflushan命令 +static boolean pflush46ope(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; + PflushOpMode opmode = (PflushOpMode)((word1 >> 3) & 3); + int regno = word1 & 7; - if (MMU_type & MMU851) { - code->mputypes = M020; - - if ((WORD2 & 0xf9ff) == 0x6000) { - IfNeedStr { - strcpy (op->operand, (BYTE3 & 4) ? "pcsr" : "psr"); - } - return; - } else if ((WORD2 & 0xf9e3) == 0x7000) { - IfNeedStr { - strcpy (op->operand, (BYTE3 & 4) ? "bac0" : "bad0"); - op->operand[3] += (WORD2 >> 2) & 7; - } - return; - } - } + if (reject_no_mmu46(code) || (word1 & 0x0020) || + (opmode >= PFOPMODE_PFLUSHAN && regno != 0 && Dis.undefReg)) { + return FALSE; + } - else if (MMU_type & MMU030) { - /* MC68EC030 では PMOVE to/from ACUSR(実体は同じものらしい) */ - if ((WORD2 & 0xfdff) == 0x6000) { - IfNeedStr { - strcpy (op->operand, "mmusr"); - } - code->mputypes = M030; - return; - } - } + OPECODE(pflush[opmode]); + if (opmode <= PFOPMODE_PFLUSH) setAnIndirect(&code->op1, regno); + return TRUE; +} - UNDEFINED(); return; -} - - -private void -op0f (address ptr, disasm* code) -{ - - if (BYTE1 == 0xf8) { - - if (WORD1 == 0xf800 && WORD2 == 0x01c0) { - if (MPU_types & M060) - REJECT (~M060); /* -m68060,cpu32 なら 68060 を優先 */ - else if (!Disasm_CPU32) { - UNDEFINED(); return; - } - - OPECODE ("lpstop"); - code->bytes = 4; - setIMD (code, &code->op1, ptr + 2, WORDSIZE); - code->size = WORDSIZE; - return; - } - - if (Disasm_CPU32 - && (WORD1 & 0xffc0) == 0xf800 - && (WORD2 & 0x8238) == 0 - && ((WORD2 >> 6) & 3) != 3) { - - IfNeedStr { - strcpy (code->opecode, "tblun"); - if (WORD2 & 0x0800) - code->opecode[3] = 's'; /* Signed */ - if ((WORD2 & 0x0400) == 0) - code->opecode[4] = '\0'; /* Result rounded */ - } - code->bytes = 4; - code->size = code->size2 = (WORD2 >> 6) & 3; - - if (BYTE3 & 1) { /* ,dx */ - /* リファレンスマニュアルには制御可変と書いてあ */ - /* るが表の内容は制御可変ではない. */ - /* おまけに Signed では (an) が使えないとなって */ - /* いる. これは間違いではないのか? */ - int eamode = CONTROL | PREDEC; - if (WORD2 & 0x0800) - eamode &= ~ADRIND; - setEA (code, &code->op1, ptr, eamode); - } else /* dym:dyn,dx */ - setPairDn (&code->op1, WORD1 & 7, WORD2 & 7); - setDn (&code->op2, BYTE3 >> 4); - return; - } - } +// 68040 ptestr, ptestw命令 +static boolean ptest040ope(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; - /* 68040, 68060 only */ - if (MPU_types & (M040|M060)) { - code->mputypes &= (M040|M060); - - switch (BYTE1) { - case 0xf4: - { - static const char cachekind[4][4] = { - "nc", "dc", "ic", "bc" - }; - - IfNeedStr { - strcpy (code->opecode, (WORD1 & 0x20) ? "cpush?" : "cinv?"); - code->opecode[(WORD1 & 0x20) ? 5 : 4] = "?lpa"[(WORD1 >> 3) & 3]; - strcpy (code->op1.operand, cachekind[(WORD1 >> 6) & 3]); - } - code->op1.ea = CtrlReg; - switch ((WORD1>>3) & 3) { - case 0: - UNDEFINED(); return; - case 1: - case 2: - IfNeedStr { - strcpy (code->op2.operand, "(a0)"); - code->op2.operand[2] += WORD1 & 7; - } - code->op2.ea = AregID; - case 3: - break; - } - } - return; - - case 0xf5: - if ((MMU_type & (MMU040|MMU060)) == 0) { - UNDEFINED(); return; - } - - if ((WORD1 & 0xe0) == 0) { - OPECODE ("pflusha"); - if (WORD1 & (1 << 4)) { /* pflusha(n) */ - if (WORD1 & 7) { - UNDEFINED(); return; /* 未定義 reg.field */ - } - } else { /* pflush(n) (an) */ - IfNeedStr { - code->opecode[6] = '\0'; - strcpy (code->op1.operand, "(a0)"); - code->op1.operand[2] += WORD1 & 7; - } - code->op1.ea = AregID; - } - if ((WORD1 & (1 << 3)) == 0) - strcat (code->opecode, "n"); - return; - } - - if ((WORD1 & 0xd8) == 0x48) { - IfNeedStr { - strcpy (code->opecode, "ptestw"); - if (WORD1 & 0x20) - code->opecode[5] = 'r'; - strcpy (code->op1.operand, "(a0)"); - code->op1.operand[2] += WORD1 & 7; - } - code->op1.ea = AregID; - return; - } - if ((WORD1 & 0xb0) == 0x80) { - IfNeedStr { - strcpy (code->opecode, "plpaw"); - if (WORD1 & 0x40) - code->opecode[4] = 'r'; - strcpy (code->op1.operand, "(a0)"); - code->op1.operand[2] += WORD1 & 7; - } - code->op1.ea = AregID; - return; - } - break; - - case 0xf6: - OPECODE ("move16"); - switch ((WORD1 >> 3) & 0x1f) { - case 0: - case 2: - IfNeedStr { - strcpy (code->op1.operand, "(a0)+"); - code->op1.operand[2] += WORD1 & 7; - if (WORD1 & (2 << 3)) - code->op1.operand[4] = '\0'; - } - setAbsLong (code, &code->op2, ptr); - return; - - case 1: - case 3: - IfNeedStr { - strcpy (code->op2.operand, "(a0)+"); - code->op2.operand[2] += WORD1 & 7; - if (WORD1 & (2 << 3)) - code->op2.operand[4] = '\0'; - } - setAbsLong (code, &code->op1, ptr); - return; - - case 4: - if ((WORD2 & 0x8fff) != 0x8000) { - UNDEFINED(); return; - } - IfNeedStr { - strcpy (code->op1.operand, "(a0)+"); - code->op1.operand[2] += WORD1 & 7; - strcpy (code->op2.operand, "(a0)+"); - code->op2.operand[2] += (BYTE3 >> 4) & 7; - } - code->op1.ea = code->op2.ea = AregIDPI; - code->bytes = 4; - return; - - default: - break; - } - - /* 0xf8 は上で処理済み */ - - default: - break; - } - } - code->mputypes = ~0; - - - /* 68020+68851,68030(on chip MMU) */ - if ((MMU_type & (MMU851|MMU030)) && ((WORD1 & 0xffc0) == 0xf000)) { - code->mputypes &= (M020|M030); - - switch ((BYTE3 >> 5) & 7) { - case 1: - { - int pmode = (BYTE3 >> 2) & 7; - - switch (pmode) { - case 0: - if (WORD2 & 0x01e0) { - UNDEFINED(); return; - } - IfNeedStr { - strcpy (code->opecode, "ploadw"); - if (BYTE3 & 2) - code->opecode[5] = 'r'; - } - code->bytes = 4; - setMMUfc (code, &code->op1, WORD2); - setEA (code, &code->op2, ptr, CTRLCHG); - return; - case 1: - if (WORD2 != 0x2400) - break; - OPECODE ("pflusha"); - code->bytes = 4; - return; - case 2: - case 3: - if ((MMU_type & MMU851) == 0) - break; - code->mputypes = M020; /* 68020 + 68851 only */ - - if (pmode == 2) { - if (WORD2 != 0x2800) - break; - code->bytes = 4; - IfNeedStr { - strcpy (code->opecode, "pvalid"); - strcpy (code->op1.operand, "val"); - } - code->op1.ea = MMUreg; - } else { - if ((WORD2 & 0xfff8) != 0x2c00) - break; - code->bytes = 4; - OPECODE ("pvalid"); - setAn (&code->op1, WORD2); - } - setEA (code, &code->op2, ptr, CTRLCHG); - code->size = code->size2 = code->default_size = LONGSIZE; - return; - case 4: - case 6: - if (BYTE3 & 2) - break; - code->bytes = 4; - OPECODE ("pflush"); - setMMUfc (code, &code->op1, WORD2); /* fc */ - setMMUfc (code, &code->op2, (WORD2 >> 5) | 0x10); /* #xx */ - if (pmode == 6) - setEA (code, &code->op3, ptr, CTRLCHG); /* */ - return; - case 5: - case 7: - if (BYTE3 & 2) - break; - REJECTnoPMMU(); - code->bytes = 4; - OPECODE ("pflushs"); - setMMUfc (code, &code->op1, WORD2); /* fc */ - setMMUfc (code, &code->op2, (WORD2 >> 5) | 0x10); /* #xx */ - if (pmode == 7) - setEA (code, &code->op3, ptr, CTRLCHG); /* */ - return; - } - } - break; - - case 0: /* MC68EC030 では P-REGISTER = 000/001 が PMOVE to/from ACx */ - case 2: - if (BYTE4) { - UNDEFINED(); return; - } - - switch (BYTE3 & 3) { - case 0: /* MEMORY to MMUreg with FLUSH */ - case 2: /* MMUreg to MEMORY with FLUSH */ - OPECODE ("pmove"); - break; - case 1: /* MEMORY to MMUreg flush disable */ - if ((MMU_type & MMU030) == 0) - break; - code->mputypes = M030; /* pmovefd is 68030 only */ - - OPECODE ("pmovefd"); - break; - case 3: /* MMUreg to MEMORY flush disable */ - UNDEFINED(); return; - } - - { - static const struct { - mputypes mpu; - char size; - char name[6]; - } mmu_regs[16] = { - { 0, 0, "" }, - { 0, 0, "" }, - { M030, LONGSIZE, "tt0" }, - { M030, LONGSIZE, "tt1" }, - { 0, 0, "" }, - { 0, 0, "" }, - { 0, 0, "" }, - { 0, 0, "" }, - { M020|M030|M040, LONGSIZE, "tc" }, - { M020, QUADSIZE, "drp" }, - { M020|M030|M040, QUADSIZE, "srp" }, - { M020|M030, QUADSIZE, "crp" }, - { M020, BYTESIZE, "cal" }, - { M020, BYTESIZE, "val" }, - { M020, BYTESIZE, "scc" }, - { M020, WORDSIZE, "ac" } - }; - int n = ((BYTE3 >> 2) & 7) + ((BYTE3 >> 3) & 8); - const char* p = mmu_regs[n].name; - - REJECT (~mmu_regs[n].mpu); - code->size = code->size2 = code->default_size = mmu_regs[n].size; - - if (BYTE3 & 2) { /* MMUreg to MEMORY */ - int ea = (WORD1 >> 3) & 7; - - if (ea == 7) - ea = (WORD1 & 7) + 8; - if ((1 << ea) & (CHANGE ^ CTRLCHG)) - REJECTnoPMMU (); - - IfNeedStr { - strcpy (code->op1.operand, p); - } - code->op1.ea = MMUreg; - code->bytes = 4; - n = ((MMU_type & MMU851) ? CHANGE : 0) /* 68851=可変 */ - | ((MMU_type & MMU030) ? CTRLCHG : 0); /* 68030=制御・可変 */ - if (code->size == QUADSIZE) - n &= ~(DATAREG | ADRREG); /* crp,drp,srp -> dn,an は不可 */ - setEA (code, &code->op2, ptr, n); - return; - } else { /* MEMORY to MMUreg */ - int ea = (WORD1 >> 3) & 7; - - if (ea == 7) - ea = (WORD1 & 7) + 8; - if ((1 << ea) & (ALL ^ CTRLCHG)) - REJECTnoPMMU (); - - IfNeedStr { - strcpy (code->op2.operand, p); - } - code->op2.ea = MMUreg; - code->bytes = 4; - n = ((MMU_type & MMU851) ? ALL : 0) /* 68851=全て */ - | ((MMU_type & MMU030) ? CTRLCHG : 0); /* 68030=制御・可変 */ - if (code->size == QUADSIZE) - n &= ~(DATAREG | ADRREG); /* dn,an -> crp,drp,srp は不可 */ - setEA (code, &code->op1, ptr, n); - return; - } - } - case 3: - OPECODE ("pmove"); - setPMMUreg (code, ((BYTE3 & 2) ? &code->op1 : &code->op2), ptr); - setEA (code, ((BYTE3 & 2) ? &code->op2 : &code->op1), ptr, CTRLCHG); - return; - case 4: - IfNeedStr { - strcpy (code->opecode, "ptestw"); - if (BYTE3 & 2) - code->opecode[5] = 'r'; - } - code->bytes = 4; - setMMUfc (code, &code->op1, WORD2); - setEA (code, &code->op2, ptr, CTRLCHG); - set07 (&code->op3, (BYTE3 >> 2)); - if (BYTE3 & 1) - setAn (&code->op4, WORD2 >> 5); - return; - case 5: - if (WORD2 != 0xa000) { - UNDEFINED(); return; - } - if ((MMU_type & MMU851) == 0) - break; - code->mputypes = M020; - - OPECODE ("pflushr"); - code->bytes = 4; - setEA (code, &code->op1, ptr, MEMORY); - return; - case 6: - case 7: - break; - } - } + if ((word1 & 0x0018) != 0x0008 || reject_no_mmu(code, M040, MMU040)) + return FALSE; - /* 68020+68851 */ - if ((MMU_type & MMU851) && (BYTE1 & 0x0e) == 0) { - int temp = (WORD1 >> 6) & 7; - - code->mputypes = M020; - - switch (temp) { - case 0: /* 解析済 */ - break; - case 1: /* PCss, PDBcc, PTRAPcc */ - if (WORD2 & 0xffc0) { - UNDEFINED(); return; - } - switch ((WORD1>>3) & 7) { - case 1: - IfNeedStr { /* PDBcc */ - strcpy (code->opecode, "pdb"); - MMUCOND (code, WORD2); - } - setDn (&code->op1, WORD1); - setrelative4 (code->op2.operand, SignWORD3, &code->op2.opval); - code->jmp = code->op2.opval; - code->jmpea = code->op2.ea = PCDISP; - code->op2.labelchange1 = -1; /* TRUE */ - code->flag = BCCOP; - code->bytes = 6; - code->size = code->size2 = WORDSIZE; /* default_size も word */ - break; - case 7: - code->bytes = 4; /* PTRAPcc */ - - switch (WORD1 & 7) { - case 2: - code->size = WORDSIZE; - setIMD (code, &code->op1, ptr+2, WORDSIZE); - break; - case 3: - code->size = LONGSIZE; - setIMD (code, &code->op1, ptr+2, LONGSIZE); - break; - case 4: - break; - default: - UNDEFINED(); return; - } - IfNeedStr { - strcpy (code->opecode, "ptrap"); - MMUCOND (code, WORD2); - } -#if 0 - code->default_size = NOTHING; -#endif - break; - default: - IfNeedStr { /* PScc */ - strcpy (code->opecode, "ps"); - MMUCOND (code, WORD2); - } - code->bytes = 4; - code->size = code->size2 = code->default_size = BYTESIZE; - setEA (code, &code->op1, ptr, DATA & CHANGE); - break; - } - return; - case 2: - case 3: - IfNeedStr { /* PBcc */ - strcpy (code->opecode, "pb"); - MMUCOND (code, WORD1); - } - switch (temp) { - case 2: - code->bytes = 4; - code->size = code->size2 = WORDSIZE; - setrelative (code->op1.operand, SignWORD2, &code->op1.opval); - break; - case 3: - code->bytes = 6; - code->size = code->size2 = LONGSIZE; - setlongrelative (code->op1.operand, SignLONG05, &code->op1.opval); - break; - } -#if 0 - code->default_size = NOTHING; -#endif - code->jmp = code->op1.opval; - code->jmpea = code->op1.ea = PCDISP; - code->flag = BCCOP; - code->op1.labelchange1 = -1; /* TRUE */ - return; - case 4: - OPECODE ("psave"); - setEA (code, &code->op1, ptr, CTRLCHG | PREDEC); - return; - case 5: - OPECODE ("prestore"); - setEA (code, &code->op1, ptr, CONTROL | POSTINC); - return; - case 6: - case 7: - default: - UNDEFINED(); return; - } - } + OPECODE(ptest[(word1 >> 5) & 1]); + setAnIndirect(&code->op1, word1 & 7); + return TRUE; +} +// 68060 plpaw, plpar命令 +static boolean plpaope(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; + if ((word1 & 0x0038) != 0x0008 || reject_no_mmu(code, M060, MMU060)) + return FALSE; -/* - - 浮動小数点命令 - - FPUID_table[ID*2] が真なら、有効な命令である. - - -m68000/010 指定時には FPCP_type = 0 になるので、FPCP_type が - 真ならば必ず -m68020 以上である. よって、MPU_types の検査は不要. - -*/ - - if (FPCP_type && FPUID_table[BYTE1 & 0x0e]) { - - code->mputypes = ~(M000|M010); - code->fpuid = (BYTE1 & 0x0e) >> 1; - code->default_size = EXTENDSIZE; - - switch ((WORD1 >> 6) & 7) { - case 0: /* type 000(一般命令) */ - switch (BYTE3 >> 5) { /* opclass */ - case 0: /* FPm to FPn */ - if (BYTE2) { - UNDEFINED(); return; - } - - FPOPESET; - code->bytes = 4; - code->size = code->size2 = EXTENDSIZE; - setFPn (&code->op1, BYTE3 >> 2); - - if ((WORD2 & 0x78) == 0x30) { /* fsincos */ - IfNeedStr { - strcpy (code->op2.operand, "fp0:fp0"); - code->op2.operand[2] += WORD2 & 7; - code->op2.operand[6] += (WORD2 >> 7) & 7; - } - return; - } else { - if (ExtensionFormat[WORD2 & 0x7f] & 1) { - if ((ExtensionFormat[ WORD2 & 0x7f ] & 2) - && (((BYTE3 >> 2) & 7) == ((WORD2 >> 7) & 7))) - ; /* f??? fpn */ - /* fxxx fpn,fpn が fxxx fpn となる場合 */ - else - setFPn (&code->op2, WORD2 >> 7); - - } else if ((UndefRegLevel & 1) - && ((WORD2 >> 7) & 7) != 0 - && ((WORD2 >> 7) & 7) != ((BYTE3 >> 2) & 7) - ) { - UNDEFINED(); return; - } - return; - } - case 1: /* undefined, reserved */ - UNDEFINED(); return; - case 2: /* Memory to FPn or movecr */ - if (((BYTE3 >> 2) & 7) == 7) { /* movecr */ - REJECTnoFPSP (); - code->bytes = 4; - code->size = code->size2 = EXTENDSIZE; - IfNeedStr { - strcpy (code->opecode, "fmovecr"); - code->op1.operand[0] = '#'; - itox2d (code->op1.operand + 1, WORD2 & 0x7f); - } - code->op1.ea = IMMED; - code->op1.opval = (address) (WORD2 & 0x7f); - setFPn (&code->op2, WORD2 >> 7); - return; - } else { /* Memory to FPn */ - static const int fpsize2size[7] = { - LONGSIZE , SINGLESIZE, EXTENDSIZE, - PACKEDSIZE, WORDSIZE , DOUBLESIZE, - BYTESIZE - }; - static const int fpsize2sea[7] = { - DATA, DATA, MEMORY, - MEMORY, DATA, MEMORY, - DATA - }; - - FPOPESET; - code->bytes = 4; - code->size = code->size2 = fpsize2size[(BYTE3 >> 2) & 7]; - if (code->size == PACKEDSIZE) - REJECTnoFPSP (); - setEA (code, &code->op1, ptr, fpsize2sea[(BYTE3 >> 2) & 7]); - - if ((WORD2 & 0x78) == 0x30) { /* fsincos */ - IfNeedStr { - strcpy (code->op2.operand, "fp0:fp0"); - code->op2.operand[2] += (WORD2 & 7); - code->op2.operand[6] += ((WORD2 >> 7) & 7); - } - } else { - if (ExtensionFormat[ WORD2 & 0x7f ] & 1) - setFPn (&code->op2, WORD2 >> 7); - else if ((WORD2 >> 7) & 7) { /* should be zero ... */ - UNDEFINED(); return; - } - } - return; - } - case 3: /* move FPn to ... */ - OPECODE ("fmove"); - code->bytes = 4; - setFPn (&code->op1, WORD2 >> 7); - - switch ((BYTE3 >> 2) & 7) { /* destination format */ - case 0: /* Long */ - code->size = code->size2 = LONGSIZE; - setEA (code, &code->op2, ptr, DATA & CHANGE); - break; - case 1: /* Single */ - code->size = code->size2 = SINGLESIZE; - setEA (code, &code->op2, ptr, DATA & CHANGE); - break; - case 2: /* Extend */ - code->size = code->size2 = EXTENDSIZE; - setEA (code, &code->op2, ptr, (DATA & CHANGE) ^ DATAREG); - break; - case 3: /* Packed with Static K-Factor */ - REJECTnoFPSP (); - code->size = code->size2 = PACKEDSIZE; - setEA (code, &code->op2, ptr, (DATA & CHANGE) ^ DATAREG); - code->op3.ea = KFactor; - IfNeedStr { - UWORD factor = WORD2 & 0x7f; - char *p = code->op3.operand; - - *p++ = '{'; - *p++ = '#'; - if (factor > 0x3f) { - *p++ = '-'; - factor = -factor + 0x80; - } - p = itod2 (p, factor); - *p++ = '}'; - *p = '\0'; - } - break; - case 4: /* Word */ - code->size = code->size2 = WORDSIZE; - setEA (code, &code->op2, ptr, DATA & CHANGE); - break; - case 5: /* Double */ - code->size = code->size2 = DOUBLESIZE; - setEA (code, &code->op2, ptr, (DATA & CHANGE) ^ DATAREG); - break; - case 6: /* Byte */ - code->size = code->size2 = BYTESIZE; - setEA (code, &code->op2, ptr, DATA & CHANGE); - break; - case 7: /* Packed with Dynamic K-Factor */ - REJECTnoFPSP (); - code->size = code->size2 = PACKEDSIZE; - setEA (code, &code->op2, ptr, (DATA & CHANGE) ^ DATAREG); - code->op3.ea = KFactor; - IfNeedStr { - strcpy (code->op3.operand, "{d0}"); - code->op3.operand[2] += (WORD2 >> 4) & 7; - } - break; - } - return; - case 4: /* move(m) Mem to FPCR/FPSR,FPIAR */ - { - int regno = (BYTE3 >> 2) & 7; - adrmode addressing = setFPCRSRlist (&code->op2, regno); - - if (addressing == 0 || (WORD2 & 0x03ff) != 0) { - UNDEFINED(); return; - } - IfNeedStr { - strcpy (code->opecode, "fmovem"); - if (regno == 1 || regno == 2 || regno == 4) - code->opecode[5] = '\0'; /* fmovem -> fmove */ - } - code->bytes = 4; - code->size = code->size2 = code->default_size = LONGSIZE; - setEA (code, &code->op1, ptr, addressing); - if (code->op1.ea == IMMED) { - switch (regno) { - case 3: /* fmovem.l #imm,#imm,reg */ - case 5: - case 6: - REJECTnoFPSP (); - setEA (code, &code->op2, ptr, addressing); - setFPCRSRlist (&code->op3, regno); - break; - case 7: /* fmovem.l #imm,#imm,#imm,reg */ - REJECTnoFPSP(); - setEA (code, &code->op2, ptr, addressing); - setEA (code, &code->op3, ptr, addressing); - setFPCRSRlist (&code->op4, regno); - break; - default: - break; - } - } - return; - } - case 5: /* move(m) FPCR/FPSR,FPIAR to Mem */ - { - adrmode addressing = setFPCRSRlist (&code->op1, BYTE3 >> 2); - - if (addressing == 0 || (WORD2 & 0x03ff) != 0) { - UNDEFINED(); return; - } - IfNeedStr { - int mode; - - strcpy (code->opecode, "fmovem"); - if ((mode = (BYTE3 >> 2) & 7) == 1 || mode == 2 || mode == 4) - code->opecode[5] = '\0'; /* fmovem -> fmove */ - } - code->bytes = 4; - code->size = code->size2 = code->default_size = LONGSIZE; - setEA (code, &code->op2, ptr, addressing & CHANGE); - return; - } - case 6: /* fmovem.x Mem to FPCP */ - if ((BYTE3 & 7) == 0) { - OPECODE ("fmovem"); /* from MEMORY to FPCP */ - code->bytes = 4; - code->size = code->size2 = EXTENDSIZE; - - switch ((BYTE3 >> 3) & 3) { - case 0: - case 1: - UNDEFINED(); return; - case 2: - setFPreglist (code->op2.operand, ptr); - break; - case 3: - if (WORD2 & 0x8f) { - UNDEFINED(); return; - } - REJECTnoFPSP (); - setDn (&code->op2, WORD2 >> 4); - } - setEA (code, &code->op1, ptr, CONTROL | POSTINC); - return; - } - break; - case 7: /* fmovem.x FPCP to Mem */ - if ((BYTE3 & 7) == 0) { - OPECODE ("fmovem"); /* from FPCP to MEMORY */ - code->bytes = 4; - code->size = code->size2 = EXTENDSIZE; - switch ((BYTE3 >> 3) & 3) { - case 0: - case 2: - setFPreglist (code->op1.operand, ptr); - break; - case 1: - case 3: - if (WORD2 & 0x8f) { - UNDEFINED(); return; - } - REJECTnoFPSP (); - setDn (&code->op1, WORD2 >> 4); - } - setEA (code, &code->op2, ptr, CTRLCHG | PREDEC); - return; - } - break; - } - - case 1: /* type 001(FDBcc/FScc/FTRAPcc) */ - if (WORD2 & 0xffc0) { - UNDEFINED(); return; - } - REJECT060noFPSP (); /* 68060 のみ Software Emulation */ - - if ((WORD1 & 0x38) == 0x08) { /* FDBcc */ - IfNeedStr { - if (Disasm_Dbra && (WORD2 & 0x1f) == 0) - strcpy (code->opecode, "fdbra"); - else { - strcpy (code->opecode, "fdb"); - FPCOND (code, WORD2); - } - } - setDn (&code->op1, WORD1); - setrelative4 (code->op2.operand, SignWORD3, &code->op2.opval); - code->default_size = NOTHING; - code->jmp = code->op2.opval; - code->jmpea = code->op2.ea = PCDISP; - code->op2.labelchange1 = -1; /* TRUE */ - code->flag = BCCOP; - code->bytes = 6; - return; - } - - if (0x7a < BYTE2) { /* FScc */ - IfNeedStr { - strcpy (code->opecode, "fs"); - FPCOND (code, WORD2); - } - code->bytes = 4; - code->size = code->size2 = code->default_size = BYTESIZE; - setEA (code, &code->op1, ptr, DATA & CHANGE); - return; - } - - if (BYTE2 < 0x7d) { /* FTRAPcc */ - code->bytes = 4; - if ((WORD1 & 7) != 4) { - code->size = ((WORD1 & 7) == 2) ? WORDSIZE : LONGSIZE; - setIMD (code, &code->op1, ptr + 2, code->size); - } - IfNeedStr { - strcpy (code->opecode, "ftrap"); - FPCOND (code, WORD2); - } -#if 0 - code->default_size = NOTHING; -#endif - return; - } - break; - - case 2: /* type 010(FBcc.W) */ - if ((BYTE2 == 0x80) && (WORD2 == 0x00)) { - OPECODE ("fnop"); - code->bytes = 4; - return; - } - /* fall through */ - case 3: /* type 011(FBcc.L) */ - if ((WORD1 & 0x1f) == 15) { - IfNeedStr { - strcpy (code->opecode, "fbra"); - } - code->flag = JMPOP; - } else { - IfNeedStr { - strcpy (code->opecode, "fb"); - FPCOND (code, WORD1); - } - code->flag = BCCOP; - } - if (WORD1 & 0x40) { - code->bytes = 6; - code->size = code->size2 = LONGSIZE; - setlongrelative (code->op1.operand, SignLONG05, &code->op1.opval); - } else { - code->bytes = 4; - code->size = code->size2 = WORDSIZE; - setrelative (code->op1.operand, SignWORD2, &code->op1.opval); - } -#if 0 - code->default_size = NOTHING; -#endif - code->jmp = code->op1.opval; - code->jmpea = code->op1.ea = PCDISP; - code->op1.labelchange1 = -1; /* TRUE */ - return; - - case 4: /* type 100(FSAVE) */ - OPECODE ("fsave"); - setEA (code, &code->op1, ptr, CTRLCHG | PREDEC); - return; - - case 5: /* type 101(FRESTORE) */ - OPECODE ("frestore"); - setEA (code, &code->op1, ptr, CONTROL | POSTINC); - return; - - case 6: /* type 110(未定義命令) */ - case 7: /* type 111(〃) */ - break; - } - UNDEFINED(); return; - } - code->mputypes = ~0; + OPECODE(plpa[(word1 >> 6) & 1]); + setAnIndirect(&code->op1, word1 & 7); + return TRUE; +} +// 68040/68060の拡張命令(コプロセッサID=2) +static boolean cp010(codeptr ptr, disasm* code) { + int optype = (WORD1 >> 6) & 7; -#ifndef OSKDIS - /* F line Emulator($ffxx:DOSコール、$fexx:FPACKコール) */ + switch (optype) { + case 0: + case 1: + case 2: + case 3: + return cinvpushope(ptr, code); + case 4: + return pflush46ope(ptr, code); + case 5: + return ptest040ope(ptr, code); + case 6: + case 7: + return plpaope(ptr, code); + } + + return FALSE; +} - switch (BYTE1) { - case 0xff: - if (OSlabel && OSlabel[BYTE2]) { - if (BYTE2 == DOS_EXIT || BYTE2 == DOS_EXIT2 || BYTE2 == DOS_KEEPPR -#ifdef DOS_KILL_PR_IS_RTSOP - || BYTE2 == DOS_KILL_PR -#endif - ) { - code->flag = RTSOP; - code->opflags += FLAG_NEED_NULSTR; - } - IfNeedStr { - strcpy (code->opecode, OSCallName); - strcpy (code->op1.operand, OSlabel[BYTE2]); - code->opflags += FLAG_CANNOT_UPPER; - } - code->size = code->size2 = code->default_size = NOTHING; - return; - } - break; - case 0xfe: - if (FElabel && FElabel[BYTE2]) { - IfNeedStr { - strcpy (code->opecode, FECallName); - strcpy (code->op1.operand, FElabel[BYTE2]); - code->opflags += FLAG_CANNOT_UPPER; - } - code->size = code->size2 = code->default_size = NOTHING; - return; - } - break; - default: - break; - } -#endif /* !OSKDIS */ +static boolean move16ope(codeptr ptr, disasm* code) { + UWORD word1 = WORD1; - if (Disasm_UnusedTrapUndefined) { - UNDEFINED(); return; /* 未使用のF line及びA lineを未定義命令とする */ - } else { - IfNeedStr { /* そうでなければ無理矢理命令にする */ - strcpy (code->opecode, DC_WORD); - itox4d (code->op1.operand, WORD1); - } - code->size = code->size2 = code->default_size = WORDSIZE; + if (word1 & 0x0020) { + if ((word1 & 0x0018) != 0x0000 || (WORD2 & 0x8fff) != 0x8000) { + return FALSE; } + // (Ax)+,(Ay)+ + OPECODE(move16); + code->mputypes &= (M040 | M060); + setAnPostinc(&code->op1, word1 & 7); + setAnPostinc(&code->op2, (BYTE3 >> 4) & 7); + code->bytes = 4; + return TRUE; + } + + OPECODE(move16); + code->mputypes &= (M040 | M060); + + switch ((word1 >> 3) & 3) { + case 0: // (Ay)+,(xxx).L + setAnPostinc(&code->op1, WORD1 & 7); + setAbsLong(code, &code->op2, ptr, TRUE); + break; + case 1: // (xxx).L,(Ay)+ + setAbsLong(code, &code->op1, ptr, TRUE); + setAnPostinc(&code->op2, WORD1 & 7); + break; + case 2: // (Ay),(xxx).L + setAnIndirect(&code->op1, WORD1 & 7); + setAbsLong(code, &code->op2, ptr, TRUE); + break; + case 3: // (xxx).L,(Ay) + setAbsLong(code, &code->op1, ptr, TRUE); + setAnIndirect(&code->op2, WORD1 & 7); + break; + } + return TRUE; } +// 68040/68060の拡張命令(コプロセッサID=3) +static boolean cp011(codeptr ptr, disasm* code) { + int optype = (WORD1 >> 6) & 7; -private void -setMMUfc (disasm* code, operand* op, int fc) -{ - char* p = op->operand; + if (optype == 0) { + return move16ope(ptr, code); + } - switch ((fc >> 3) & 3) { - case 0: - op->ea = MMUreg; - switch (fc & 7) { - case 0: - IfNeedStr { - strcpy (p, "sfc"); - } - break; - case 1: - IfNeedStr { - strcpy (p, "dfc"); - } - break; - default: - UNDEFINED(); return; - } - break; - case 1: - op->ea = DregD; - IfNeedStr { - *p++ = 'd'; - *p++ = (fc & 7) + '0'; - *p++ = '\0'; - } - break; - case 3: - REJECTnoPMMU (); /* #xx が 8~15 なら 68020 */ - /* fall through */ - case 2: - op->ea = IMMED; - IfNeedStr { - *p++ = '#'; - fc &= 15; - if (fc >= 10) { - *p++ = '1'; - fc -= 10; - } - *p++ = fc + '0'; - *p++ = '\0'; - } - break; - } + return FALSE; } +// CPU32/68060 LPSTOP +static boolean lpstopope(codeptr ptr, disasm* code) { + if (Dis.mpu & M060) { + code->mputypes = M060; // -m68060,cpu32なら.cpu 68060にする + } else if (!Dis.cpu32) { + return FALSE; + } + + OPECODE(lpstop); + code->bytes = 4; + code->size = WORDSIZE; + return setImm(code, &code->op1, ptr, WORDSIZE); +} -/* add sub 用 */ -private void -addsubope (address ptr, disasm* code, const char* opname) -{ - - OPECODE (opname); - - /* adda、suba */ - if ((WORD1 & 0xc0) == 0xc0) { - code->size = code->size2 = (BYTE1 & 1) ? LONGSIZE : WORDSIZE; - setEA (code, &code->op1, ptr, ALL); - setAn (&code->op2, BYTE1 >> 1); - IfNeedStr { - /* バイトサイズは存在しないのでコメントは不要 */ - if (Disasm_MnemonicAbbreviation) { - /* adda/suba #imm で 1 <= imm <= 8 なら */ - /* imm にサイズを付ける(最適化対策) */ - if (code->op1.ea == IMMED && ((ULONG)code->op1.opval - 1) <= 7) - addsize (code->op1.operand, code->size); - } - else - strcat (code->opecode, "a"); - } - return; - } +// CPU32 TBLS, TBLSN, TBLU, TBLUN +static boolean tblope(codeptr ptr, disasm* code) { + if (!Dis.cpu32) return FALSE; + + OPECODE(tbl[(BYTE3 >> 2) & 3]); + code->bytes = 4; + code->size = code->size2 = (BYTE4 >> 6); + + if (BYTE3 & 1) { // ,dx + if (!setEA(code, &code->op1, ptr, CONTROL)) return FALSE; + } else { // dym:dyn,dx + setPairDn(&code->op1, WORD1 & 7, BYTE4 & 7); + } + setDn(&code->op2, BYTE3 >> 4); + return TRUE; +} - /* addx、subx */ - if ((WORD1 & 0x130) == 0x100) { - SETSIZE (); - IfNeedStr { - strcat (code->opecode, "x"); - } - if (WORD1 & 8) { - IfNeedStr { - strcpy (code->op1.operand, "-(a0)"); - strcpy (code->op2.operand, "-(a0)"); - code->op1.operand[3] += WORD1 & 7; - code->op2.operand[3] += (BYTE1 >> 1) & 7; - } - code->op1.ea = code->op2.ea = AregIDPD; - } - else { - setDn (&code->op1, WORD1); - setDn (&code->op2, BYTE1 >> 1); - } - return; - } +// CPU32/68060の拡張命令(コプロセッサID=4) +static boolean cp100(codeptr ptr, disasm* code) { + UWORD word1 = WORD1, word2 = WORD2; - /* add、sub */ - SETSIZE (); - if (BYTE1 & 1) { - setDn (&code->op1, BYTE1 >> 1); - setEA (code, &code->op2, ptr, MEMORY & CHANGE); - } else { - REJECTBYTESIZE (); - setEA (code, &code->op1, ptr, ALL); - setDn (&code->op2, BYTE1 >> 1); - - if (Disasm_String && code->op1.ea == IMMED) { - /* add.b、sub.b #imm にはコメントを付ける */ - if (code->size == BYTESIZE) - code->opflags += FLAG_NEED_COMMENT; - - /* add/sub #imm,dn (1 <= imm <= 8) なら、サイズ */ - /* を明示して addq/subq に最適化されるのを防ぐ */ - if ((code->size == BYTESIZE && (BYTE4 - 1) <= 7) - || (code->size == WORDSIZE && (WORD2 - 1) <= 7) - || (code->size == LONGSIZE && (LONG05 - 1) <= 7)) - addsize (code->op1.operand, code->size); - } - } -} + if (word1 == 0xf800 && word2 == 0x01c0) return lpstopope(ptr, code); + if ((word1 & 0xffc0) == 0xf800 && (word2 & 0x8238) == 0 && + ((word2 >> 6) & 3) != 3) { + return tblope(ptr, code); + } -/* - * 最適化防止用に即値オペランドにサイズを付ける - */ -private void -addsize (char* optr, opesize size) -{ - strcat (optr, (size == BYTESIZE) ? ".b" : - (size == WORDSIZE) ? ".w" : ".l"); + return FALSE; } +// F line Emulator ($ffxx:DOSコール、$fexx:FPACKコール) +static boolean flineHuman(codeptr ptr, disasm* code) { + switch (BYTE1) { + default: + break; -/* bcd 用 */ -private void -bcdope (address ptr, disasm* code, const char* opname) -{ - OPECODE (opname); + case 0xff: + if (Dis.dosLabel && Dis.dosLabel[BYTE2]) { + if (BYTE2 == DOS_EXIT || BYTE2 == DOS_EXIT2 || BYTE2 == DOS_KEEPPR || + BYTE2 == DOS_KILL_PR) { + code->opeType = RTSOP; + } + if (Dis.needString) { + OPECODE(doscall); + strcpy(code->op1.operand, Dis.dosLabel[BYTE2]); + } + code->size = code->size2 = code->default_size = NOTHING; + return TRUE; + } + break; - code->size = code->size2 = code->default_size = BYTESIZE; - if (WORD1 & 8) { - IfNeedStr { - strcpy (code->op1.operand, "-(a0)"); - strcpy (code->op2.operand, "-(a0)"); - code->op1.operand[3] += WORD1 & 7; - code->op2.operand[3] += (BYTE1 >> 1) & 7; - } - code->op1.ea = code->op2.ea = AregIDPD; - } else { - setDn (&code->op1, WORD1); - setDn (&code->op2, BYTE1 >> 1); - } + case 0xfe: + if (Dis.fefuncLabel && Dis.fefuncLabel[BYTE2]) { + if (Dis.needString) { + OPECODE(fefunc); + strcpy(code->op1.operand, Dis.fefuncLabel[BYTE2]); + } + code->size = code->size2 = code->default_size = NOTHING; + return TRUE; + } + break; + } + + return FALSE; } +static boolean op0f(codeptr ptr, disasm* code) { + int cpid = (BYTE1 >> 1) & 7; -/* レジスタリスト (movem) */ -private void -setreglist (char* operandstr, address ptr) -{ - unsigned int field, field2; - boolean flag, already; - int i, start = 0; - - if (!Disasm_String) - return; - - if ((WORD1 & 0x38) == 0x20) { /* pre-decrement ? */ - field = 0; - for (i = 0; i < 16; i++) - field |= (WORD2 & pow2[i]) ? pow2[15 - i] : 0; - } else - field = WORD2; - - field2 = field & 0xff; /* lower 8 bit */ - for (i = 0, flag = FALSE, already = FALSE; i < 9; i++) { - if (!flag && field2 & pow2[i]) { - start = i; - flag = TRUE; - } else { - if (flag && (field2 & pow2[i]) == 0) { - char* p = strend (operandstr); - if (already) - *p++ = '/'; - *p++ = 'd'; - *p++ = start + '0'; - if (start != (i - 1)) { - *p++ = '-'; - *p++ = 'd'; - *p++ = (i - 1) + '0'; - } - *p = '\0'; - already = TRUE; - flag = FALSE; - } - } - } + // コプロセッサ命令 + switch (cpid) { + default: + break; + + case CPID_MMU: + if (Dis.mmu & (MMU851 | MMU030)) return cp000(ptr, code); + break; + case CPID_CACHE_MMU: + if (Dis.mpu & (M040 | M060)) return cp010(ptr, code); + break; + case CPID_MOVE16: + if (Dis.mpu & (M040 | M060)) return cp011(ptr, code); + break; + case CPID_CPU32: + if ((Dis.mpu & M060) || Dis.cpu32) return cp100(ptr, code); + break; + } + if (Dis.fpu && Dis.fpuidTable[cpid]) { + return disfp(ptr, code); // 浮動小数点命令 + } + + // DOSCALL, FEFUNC + if (flineHuman(ptr, code)) return TRUE; + + if (Dis.acceptUnusedTrap) { + // 未使用の F-line を未定義命令と見なさない + if (Dis.needString) { + OPECODE(dcWord); + itox4d(code->op1.operand, WORD1); + } + code->size = code->size2 = code->default_size = WORDSIZE; + return TRUE; + } + + return FALSE; +} - field2 = field >> 8; - for (i = 0, flag = FALSE; i < 9; i++) { - if (!flag && field2 & pow2[i]) { - start = i; - flag = TRUE; - } else { - if (flag && (field2 & pow2[i]) == 0) { - char* p = strend (operandstr); - if (already) - *p++ = '/'; - *p++ = 'a'; - *p++ = start + '0'; - if (start != (i - 1)) { - *p++ = '-'; - *p++ = 'a'; - *p++ = (i - 1) + '0'; - } - *p = '\0'; - already = TRUE; - flag = FALSE; - } - } - } +// ADD, ADDA, ADDX, SUB, SUBA, SUBX +static boolean addsubope(codeptr ptr, disasm* code, boolean isAdd) { + // ADDA, SUBA + if ((WORD1 & 0xc0) == 0xc0) { + code->size = code->size2 = (BYTE1 & 1) ? LONGSIZE : WORDSIZE; + if (!setEA(code, &code->op1, ptr, ALL)) return FALSE; + + OPECODE2(isAdd, adda, suba); // フロー解析用に解析フェーズでも設定する + setAn(&code->op2, BYTE1 >> 1); + + if (Dis.needString) { + // バイトサイズは存在しないのでコメントは不要 + + // adda(suba) #imm,an (1 <= imm <= 8) を add(sub) #imm,an と出力するとき、 + // addq(subq) #imm,dn への最適化を抑止するため即値にサイズを付ける + if (code->op1.ea == IMMED && Dis.mnemonicAbbreviation) { + addsize_if_1to8(&code->op1, code->size); + } + } + return TRUE; + } + + // ADDX, SUBX + if ((WORD1 & 0x130) == 0x100) { + SETSIZE(); + OPECODE2(isAdd, addx, subx); + if (WORD1 & 0x0008) { + setAnPredec(&code->op1, WORD1 & 7); + setAnPredec(&code->op2, (BYTE1 >> 1) & 7); + } else { + setDn(&code->op1, WORD1); + setDn(&code->op2, BYTE1 >> 1); + } + return TRUE; + } + + // ADD, SUB + SETSIZE(); + OPECODE2(isAdd, add, sub); + if (BYTE1 & 1) { + // ADD(SUB) Dn, + setDn(&code->op1, BYTE1 >> 1); + return setEA(code, &code->op2, ptr, MEMORY & CHANGE); + } + // ADD(SUB) ,Dn + if (reject_bytesize(code, WORD1)) return FALSE; + + if (!setEA(code, &code->op1, ptr, ALL)) return FALSE; + setDn(&code->op2, BYTE1 >> 1); + + if (Dis.needString && code->op1.ea == IMMED) { + // add.b、sub.b #imm にはコメントを付ける + if (code->size == BYTESIZE) code->codeflags += CODEFLAG_NEED_COMMENT; + + // add(sub) #imm,dn (1 <= imm <= 8) から addq(subq) #imm,dn + // への最適化を抑止するため、即値にサイズを付ける + addsize_if_1to8(&code->op1, code->size); + } + return TRUE; } +// abcd, sbcd +static boolean bcdope(codeptr ptr, disasm* code) { + code->size = code->size2 = code->default_size = BYTESIZE; + if (WORD1 & 0x0008) { + setAnPredec(&code->op1, WORD1 & 7); + setAnPredec(&code->op2, (BYTE1 >> 1) & 7); + } else { + setDn(&code->op1, WORD1); + setDn(&code->op2, BYTE1 >> 1); + } + + return TRUE; +} -/* - - イミディエイトデータのセット - - */ -private void -setIMD (disasm* code, operand* op, address ptr, opesize size) -{ - char* optr = op->operand; - int byte4 = (int) BYTE4; - - op->ea = IMMED; - op->eaadrs = PC + code->bytes; - - switch (size) { - case BYTESIZE: - code->bytes += 2; - IfNeedStr { - *optr++ = '#'; - if (BYTE3 == 0xff && SignBYTE4 < 0) { - *optr++ = '-'; - byte4 = -byte4 & 0xff; - } - itox2d (optr, byte4); - } - if (BYTE3 && (BYTE3 != 0xff || SignBYTE4 >= 0) && Disasm_Exact) { - UNDEFINED(); return; - } - op->opval = (address)(ULONG) BYTE4; - break; - case WORDSIZE: - code->bytes += 2; - op->opval = (address)(ULONG) WORD2; - IfNeedStr { - *optr++ = '#'; - itox4d (optr, (LONG) op->opval); - } - break; - case LONGSIZE: - code->bytes += 4; - op->opval = (address) peekl (ptr + 2); - IfNeedStr { - *optr++ = '#'; - itox8d (optr, (LONG) op->opval); - } - break; - default: /* reduce warning message */ - break; - } +static void init_opval_eaadrs(operand* op) { + op->opval = (address)-1; + op->opval2 = (address)-1; + op->eaadrs = (address)-1; + op->eaadrs2 = (address)-1; } +static void init_operand(operand* op) { + op->operand[0] = '\0'; + op->ea = (adrmode)-1; + init_opval_eaadrs(op); + op->labelchange1 = LABELCHANGE_DISALLOW; + op->flags = 0; + op->exbd = -1; + op->exod = -1; + op->baseReg = 0; + op->ixReg = 0; +} -private void -setAnDisp (disasm* code, operand* op, int regno, int disp) -{ - WORD d16 = (WORD) disp; - -#ifdef OSKDIS - - if (regno == 6) { - ULONG a6disp = (ULONG) disp; - lblbuf* lptr; - lblmode wkmode; - - switch (HeadOSK.type & 0x0F00) { - case 0x0100: /* Program */ - case 0x0b00: /* Trap */ - a6disp += 0x8000; /* A6 のオフセットを調整 */ - d16 = disp + 0x8000; /* A6 のオフセットを調整 */ -#if 0 - regist_label(BeginBSS + a6disp, DATLABEL | UNKNOWN); -#endif - if ((lptr = search_label(BeginBSS + a6disp)) != NULL) - wkmode = (lptr->mode & (CODEPTR | DATAPTR)); - else - wkmode = DATLABEL; - regist_label(BeginBSS + a6disp, wkmode | code->size2 | FORCE); - op->eaadrs = PC + code->bytes; - op->ea = AregDISP; - code->bytes += 2; - IfNeedStr { - char* p = op->operand; - - *p++ = '('; - *p++ = 'L'; /* ラベル生成手抜き版 */ - *p++ = '0'; /* L00xxxx なラベルを作る */ - *p++ = '0'; /* 値は7行上で登録済 */ - p = strcpy (itox4 (p, BeginBSS + d16), ",a0)"); - p[2] += regno; - } - return; - default: - break; - } - } -#endif /* OSKDIS */ - - op->eaadrs = PC + code->bytes; - op->ea = AregDISP; - code->bytes += 2; - IfNeedStr { - char* p = op->operand; - - *p++ = '('; - if (d16 < 0) { - *p++ = '-'; - d16 = -d16 & 0xffff; - } - p = itox4d (p, d16); - if (d16 == 0) { - *p++ = '.'; - *p++ = 'w'; - } - strcpy (p, ",a0)"); - p[2] += regno; - } +// オペコードの最上位4ビットで分岐 +static boolean decode(codeptr ptr, disasm* code) { + switch (BYTE1 >> 4) { + case 0x0: + return op00(ptr, code); + case 0x1: + return op01(ptr, code); + case 0x2: + return op02(ptr, code); + case 0x3: + return op03(ptr, code); + case 0x4: + return op04(ptr, code); + case 0x5: + return op05(ptr, code); + case 0x6: + return op06(ptr, code); + case 0x7: + return op07(ptr, code); + case 0x8: + return op08(ptr, code); + case 0x9: + return op09(ptr, code); + case 0xa: + return op0a(ptr, code); + case 0xb: + return op0b(ptr, code); + case 0xc: + return op0c(ptr, code); + case 0xd: + return op0d(ptr, code); + case 0xe: + return op0e(ptr, code); + case 0xf: + return op0f(ptr, code); + } + + return FALSE; } +// moveq #imm,d0 + trap #15 を IOCS マクロに変更する +static void moveqTrap15ToIocs(codeptr ptr, disasm* code) { + char* label = Dis.iocsLabel ? Dis.iocsLabel[BYTE2] : NULL; + if (label == NULL) return; + + OPECODE(iocscall); + init_operand(&code->op1); + strcpy(code->op1.operand, label); + code->op2.operand[0] = '\0'; + code->codeflags &= ~CODEFLAG_NEED_COMMENT; // moveq のコメントは付けない + code->bytes = 4; + code->size = code->size2 = code->default_size = NOTHING; +} -/* +// 逆アセンブルモジュール +// 引数 +// disp->ptr: 命令の格納アドレス +// disp->pc: 命令のPC +// 戻り値 +// 命令のバイト数(2以上の偶数) +// disp->ptr: 次の命令の格納アドレス +// disp->pc: 次の命令のPC +// disp->code: 逆アセンブル結果 +// +int dis(DisParam* disp) { + disasm* code = &disp->code; + codeptr ptr = disp->ptr; + boolean success; + + code->opecodeOffset = 0; + code->size2 = code->size = NOTHING; + code->default_size = WORDSIZE; + code->bytes = 2; + code->opeType = OTHER; + code->mputypes = ~0; + code->fpuid = -1; + code->codeflags = 0; + code->pc = disp->pc; + + init_operand(&code->op1); + init_operand(&code->op2); + init_operand(&code->op3); + init_operand(&code->op4); + + success = decode(ptr, code); + if (success) { + // moveq #xx,d0 + trap #15 なら IOCS マクロに変更する + if (BYTE1 == 0x70 && WORD2 == 0x4e4f && Dis.needString && + ((disp->pc + 4) <= disp->pcEnd)) { + moveqTrap15ToIocs(ptr, code); + } + + // 命令列がプログラム終端を越えていたら未定義命令とする + if ((code->bytes > 2) && (disp->pcEnd < (disp->pc + code->bytes))) { + success = FALSE; + init_opval_eaadrs(&code->op1); + init_opval_eaadrs(&code->op2); + init_opval_eaadrs(&code->op3); + init_opval_eaadrs(&code->op4); + } + } + + if (!success) { + code->opeType = UNDEF; + code->bytes = 2; + code->size = code->size2 = code->default_size = WORDSIZE; - 命令の実効アドレス部を解読し、対応する文字列を返す - code->bytes, code->size をセットしてから呼び出すこと - ptr にオペコードのアドレス + if (Dis.needString) { + code->mputypes = ~0; + code->fpuid = -1; -*/ -#define ODDCHECK \ - if (Disasm_AddressErrorUndefined && (long)op->opval & 1 && \ - code->size2 != BYTESIZE && code->size2 != UNKNOWN) { \ - UNDEFINED(); return; \ - } + code->op1.ea = code->op2.ea = code->op3.ea = code->op4.ea = (adrmode)-1; -private void -setEA (disasm* code, operand* op, address ptr, int mode) -{ - int eamode, eareg; /* 実効アドレスモード、実効アドレスレジスタ */ - LONG temp; - char* p = op->operand; + code->op1.labelchange1 = code->op2.labelchange1 = code->op3.labelchange1 = + code->op4.labelchange1 = LABELCHANGE_DISALLOW; - if (mode & MOVEOPT) { /* move 命令の第2オペランドの場合 */ - eamode = (WORD1 >> 6) & 7; - eareg = (BYTE1 >> 1) & 7; - } - else { - eamode = (WORD1 >> 3) & 7; - eareg = WORD1 & 7; - } + code->op2.operand[0] = code->op3.operand[0] = code->op4.operand[0] = '\0'; - if (eamode == 7) { - WORD d16; - - if (((mode >> 8) & pow2[ eareg ]) == 0 - && (!(mode & SRCCR) || ((mode & SRCCR) && eareg != 4))) { - UNDEFINED(); return; - } - op->eaadrs = PC + code->bytes; - op->ea = 8 + eareg; - - switch (eareg) { - case 0: /* (abs).w AbShort */ - d16 = (WORD) peekw (ptr + code->bytes); - op->opval = (address)(LONG) d16; - ODDCHECK; - IfNeedStr { - *p++ = '('; - if (d16 < 0) { - *p++ = '-'; - d16 = -d16 & 0xffff; - } - p = itox4d (p, d16); - *p++ = ')'; -#if 0 - *p++ = '.'; - *p++ = 'w'; -#endif - *p++ = '\0'; - } - code->bytes += 2; - return; - case 1: /* (abs).l AbLong */ - op->opval = (address) peekl (ptr + code->bytes); - ODDCHECK; - IfNeedStr { - *p++ = '('; - p = itox8d (p, (LONG)op->opval); - *p++ = ')'; - if ((LONG)(WORD)(LONG) op->opval == (LONG) op->opval) { - *p++ = '.'; - *p++ = 'l'; - } - *p = '\0'; - } - code->bytes += 4; - return; - case 2: /* (d16,pc) */ - op->labelchange1 = TRUE; - d16 = (WORD) peekw (ptr + code->bytes); - op->opval = PC + code->bytes + d16; - ODDCHECK; - IfNeedStr { - *p++ = '('; - if (d16 < 0) { - *p++ = '-'; - d16 = -d16 & 0xffff; - } - itox4d (p, d16); - strcat (p, ",pc)"); - } - code->bytes += 2; - return; - case 3: /* (d8,pc,ix) */ - op->labelchange1 = TRUE; - temp = peekw (ptr + code->bytes); /* temp = 拡張ワード */ - - /* フルフォーマットの拡張ワード */ - if (temp & 0x0100) { - boolean zreg = FALSE; - int indirect = 0, zareg; - int bdsize = 0, bd = 0; - int odsize = 0, od = 0; - - if (temp & 0x08) { - UNDEFINED(); return; - } - REJECT (M000|M010); - - switch ((temp >> 4) & 3) { - case 0: - UNDEFINED(); return; - case 1: - /* bdsize = 0; */ - break; - case 2: - bdsize = 2; - bd = (WORD) peekw (ptr + code->bytes + 2); - op->eaadrs = PC + code->bytes + 2; - break; - case 3: - bdsize = 4; - bd = (LONG) peekl (ptr + code->bytes + 2); - op->eaadrs = PC + code->bytes + 2; - break; - } - - switch (((temp & 0x40) >> 3) | (temp & 7)) { - case 0x0: - op->ea = PCIDXB; - break; - case 0x1: - op->ea = PCPREIDX; - indirect = 2; - break; - case 0x2: - op->ea = PCPREIDX; - indirect = 2; - odsize = 2; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (WORD) peekw (ptr + code->bytes + 2 + bdsize); - break; - case 0x3: - op->ea = PCPREIDX; - indirect = 2; - odsize = 4; - op->labelchange2 = TRUE; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (LONG) peekl (ptr + code->bytes + 2 + bdsize); - break; - case 0x5: - op->ea = PCPOSTIDX; - indirect = 1; - break; - case 0x6: - op->ea = PCPOSTIDX; - indirect = 1; - odsize = 2; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (WORD) peekw (ptr + code->bytes + 2 + bdsize); - break; - case 0x7: - op->ea = PCPOSTIDX; - indirect = 1; - odsize = 4; - op->labelchange2 = TRUE; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (LONG) peekl (ptr + code->bytes + 2 + bdsize); - break; - case 0x8: - op->ea = PCIDXB; - zreg = TRUE; - break; - case 0x9: - op->ea = PCPREIDX; - indirect = 2; - zreg = TRUE; - break; - case 0xa: - op->ea = PCPREIDX; - indirect = 2; - zreg = TRUE; - odsize = 2; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (WORD) peekw (ptr + code->bytes + 2 + bdsize); - break; - case 0xb: - op->ea = PCPREIDX; - indirect = 2; - zreg = TRUE; - odsize = 4; - op->labelchange2 = TRUE; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (LONG) peekl (ptr + code->bytes + 2 + bdsize); - break; - case 0x4: - case 0xc: - case 0xd: - case 0xe: - case 0xf: - UNDEFINED(); return; - } - - if (zreg) { - /* サプレスされたレジスタNo が 0 じゃない */ - if (((UndefRegLevel & 2) && (temp & 0x7000)) - /* サプレスされたレジスタがスケーリングされてる */ - || ((UndefRegLevel & 4) && (temp & 0x0600)) - /* サプレスされたレジスタが .l 指定されてる */ - || ((UndefRegLevel & 8) && (temp & 0x0800)) - ) { - UNDEFINED(); return; - } - } - - zareg = (temp & 0x80); - if (bdsize) - op->opval = zareg ? (address) bd : PC + bd + code->bytes; - if (odsize == 4) - op->opval2 = (address) od; - op->exbd = bdsize; - op->exod = odsize; - - IfNeedStr { - *p++ = '('; - if (indirect) - *p++ = '['; - - if (bdsize) { - int lim = (bdsize == 2) ? 127 : 32767; - if (bd < 0) { - *p++ = '-'; - bd = -bd; - lim++; - } - - if (bdsize == 2) { - bd &= 0xffff; - p = itox4d (p, bd); - if (bd <= lim && !indirect) { - *p++ = '.'; /* (d8.w,pc,ix) */ - *p++ = 'w'; - } - - } else if (bdsize == 4) { - p = itox8d (p, bd); - if (bd <= lim) { - *p++ = '.'; /* (d16.l,pc,ix) */ - *p++ = 'l'; - } - } - *p++ = ','; - } - - if (zareg) - *p++ = 'z'; /* zpc は省略不可 */ - *p++ = 'p'; - *p++ = 'c'; - - if (indirect == 1) - *p++ = ']'; - - if (!zreg || (UndefRegLevel & 0x0e) != 0x0e) { - int scale; - - *p++ = ','; - if (zreg) - *p++ = 'z'; - *p++ = temp & 0x8000 ? 'a' : 'd'; - *p++ = ((temp >> 12) & 7) + '0'; - *p++ = '.'; - *p++ = temp & 0x0800 ? 'l' : 'w'; - - if ((scale = (temp >> 9) & 3)) { - *p++ = '*'; - *p++ = (scale == 1) ? '2' - : (scale == 2) ? '4' : '8'; - } - } - - if (indirect == 2) - *p++ = ']'; - - if (odsize) { - int lim = 32767; - *p++ = ','; - if (od < 0) { - *p++ = '-'; - od = -od; - lim++; - } - - if (odsize == 2) { - od &= 0xffff; - p = itox4d (p, od); - } - else if (odsize == 4) { - p = itox8d (p, od); - if (od <= lim) { - *p++ = '.'; - *p++ = 'l'; - } - } - } - *p++ = ')'; - *p = '\0'; - } - code->bytes += 2 + bdsize + odsize; - return; - } - - /* 短縮フォーマットの拡張ワード */ - else { - signed char d8 = *(signed char*) (ptr + code->bytes + 1); - - temp = *(UBYTE*) (ptr + code->bytes); /* temp = 拡張ワード */ - op->opval = PC + d8 + code->bytes; - - /* scaling check (68020 未満のチェック) */ - if ((temp >> 1) & 0x03) - REJECT (M000|M010); - - IfNeedStr { - int scale; - - *p++ = '('; - if (d8 < 0) { - *p++ = '-'; - d8 = -d8 & 0xff; - } - p = itox2d (p, d8); - strcpy (p, ",pc,"); - p += 4; - *p++ = temp & 0x80 ? 'a' : 'd'; - *p++ = ((temp >> 4) & 7) + '0'; - *p++ = '.'; - *p++ = temp & 0x08 ? 'l' : 'w'; - - /* scaling (68020 未満のチェック済) */ - if ((scale = (temp >> 1) & 3)) { - *p++ = '*'; - *p++ = (scale == 1) ? '2' - : (scale == 2) ? '4' : '8'; - } - *p++ = ')'; - *p = '\0'; - } - code->bytes += 2; - return; - } - - case 4: - if (mode & SRCCR) { - op->eaadrs = (address)-1; - op->ea = SRCCR; - - if (code->size == BYTESIZE || code->size == WORDSIZE) { - IfNeedStr { - strcpy (op->operand, (code->size == BYTESIZE) ? "ccr" : "sr"); - } - } else { - UNDEFINED(); return; - } - return; - } else { - switch (code->size) { /* #Imm */ - case BYTESIZE: - { - UBYTE undefbyte = *(UBYTE*) (ptr + code->bytes); - op->opval = (address)(ULONG)*(UBYTE*) (ptr + code->bytes + 1); - IfNeedStr { - temp = (LONG)op->opval; - *p++ = '#'; - if (undefbyte == 0xff && (signed char)(int) op->opval < 0) { - *p++ = '-'; - temp = -(UBYTE)temp & 0xff; - } - itox2d (p, temp); - } - if (Disasm_Exact && undefbyte - && (undefbyte != 0xff || (signed char)(int) op->opval >= 0)) { - UNDEFINED(); return; - } - code->bytes += 2; - return; - } - case WORDSIZE: - op->opval = (address)(ULONG) peekw (ptr + code->bytes); - IfNeedStr { - *p++ = '#'; - itox4d (p, (LONG)op->opval); - } - code->bytes += 2; - return; - case LONGSIZE: - op->opval = (address) peekl (ptr + code->bytes); - IfNeedStr { - *p++ = '#'; - itox8d (p, (LONG) op->opval); - } - code->bytes += 4; - return; - case QUADSIZE: /* 8bytes (MMU命令専用) */ - IfNeedStr { - *p++ = '#'; - fpconv_q (p, (quadword*) (ptr + code->bytes)); - } - code->bytes += 8; - return; - case SINGLESIZE: /* 単精度実数(4byte) */ - IfNeedStr { - *p++ = '#'; - fpconv_s (p, (float*) (ptr + code->bytes)); - } - code->bytes += 4; - return; - case DOUBLESIZE: /* 倍精度実数(8byte) */ - IfNeedStr { - *p++ = '#'; - fpconv_d (p, (double*) (ptr + code->bytes)); - } - code->bytes += 8; - return; - case EXTENDSIZE: /* 拡張精度実数(12byte) */ - REJECTnoFPSP (); - IfNeedStr { - *p++ = '#'; - fpconv_x (p, (long double*) (ptr + code->bytes)); - } - code->bytes += 12; - return; - case PACKEDSIZE: /* パックドデシマル(12byte) */ - REJECTnoFPSP (); - IfNeedStr { - *p++ = '#'; - fpconv_p (p, (packed_decimal*) (ptr + code->bytes)); - } - code->bytes += 12; - return; - - default: /* reduce warning message */ - break; - } - } - } + OPECODE(dcWord); + itox4d(code->op1.operand, WORD1); } + } - else { /* eamode != 7 */ - if ((mode & pow2[eamode]) == 0) { - UNDEFINED(); return; - } - op->eaadrs = (address) -1; - op->ea = eamode; - - if (eamode <= 4 && !Disasm_String) - return; - - /* 0~ 4 では 常にオペランド文字列を生成してよい. */ - switch (eamode) { - case 0: - op->operand[0] = 'd'; /* Dn */ - op->operand[1] = (eareg & 7) + '0'; - op->operand[2] = 0; - return; - case 1: - op->operand[0] = 'a'; /* An */ - op->operand[1] = (eareg & 7) + '0'; - op->operand[2] = 0; - return; - case 2: - strcpy (op->operand, "(a0)"); /* (An) */ - op->operand[2] += eareg; - return; - case 3: - strcpy (op->operand, "(a0)+"); /* (An)+ */ - op->operand[2] += eareg; - return; - case 4: - strcpy (op->operand, "-(a0)"); /* -(An) */ - op->operand[3] += eareg; - return; - case 5: /* (d16,An) */ - setAnDisp (code, op, eareg, (WORD) peekw (ptr + code->bytes)); - return; - - case 6: - temp = peekw (ptr + code->bytes); /* temp = 拡張ワード */ - - /* フルフォーマットの拡張ワード */ - if (*(UBYTE*) (ptr + code->bytes) & 1) { - boolean zreg = FALSE; - int indirect = 0, zareg; - int bdsize = 0, bd = 0; - int odsize = 0, od = 0; - - if (temp & 0x08) { - UNDEFINED(); return; - } - REJECT (M000|M010); - - switch ((temp >> 4) & 3) { - case 0: - UNDEFINED(); return; - case 1: - /* bdsize = 0; */ - break; - case 2: - bdsize = 2; - bd = (WORD) peekw (ptr + code->bytes + 2); - op->eaadrs = PC + code->bytes + 2; - break; - case 3: - bdsize = 4; - op->labelchange1 = TRUE; - bd = (LONG) peekl (ptr + code->bytes + 2); - op->eaadrs = PC + code->bytes + 2; - break; - } - - switch (((temp & 0x40) >> 3) | (temp & 7)) { - case 0x0: - op->ea = AregIDXB; - break; - case 0x1: - op->ea = AregPREIDX; - indirect = 2; - break; - case 0x2: - op->ea = AregPREIDX; - indirect = 2; - odsize = 2; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (WORD) peekw (ptr + code->bytes + 2 + bdsize); - break; - case 0x3: - op->ea = AregPREIDX; - indirect = 2; - odsize = 4; - op->labelchange2 = TRUE; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (LONG) peekl (ptr + code->bytes + 2 + bdsize); - break; - case 0x5: - op->ea = AregPOSTIDX; - indirect = 1; - break; - case 0x6: - op->ea = AregPOSTIDX; - indirect = 1; - odsize = 2; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (WORD) peekw (ptr + code->bytes + 2 + bdsize); - break; - case 0x7: - op->ea = AregPOSTIDX; - indirect = 1; - odsize = 4; - op->labelchange2 = TRUE; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (LONG) peekl (ptr + code->bytes + 2 + bdsize); - break; - case 0x8: - op->ea = AregIDXB; - zreg = TRUE; - break; - case 0x9: - op->ea = AregPREIDX; - indirect = 2; - zreg = TRUE; - break; - case 0xa: - op->ea = AregPREIDX; - indirect = 2; - zreg = TRUE; - odsize = 2; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (WORD) peekw (ptr + code->bytes + 2 + bdsize); - break; - case 0xb: - op->ea = AregPREIDX; - indirect = 2; - zreg = TRUE; - odsize = 4; - op->labelchange2 = TRUE; - op->eaadrs2 = PC + code->bytes + 2 + bdsize; - od = (LONG) peekl (ptr + code->bytes + 2 + bdsize); - break; - case 0x4: - case 0xc: - case 0xd: - case 0xe: - case 0xf: - UNDEFINED(); return; - } - - if (zreg) { - /* サプレスされたレジスタNo が 0 じゃない */ - if (((UndefRegLevel & 2) && (temp & 0x7000)) - /* サプレスされたレジスタがスケーリングされてる */ - || ((UndefRegLevel & 4) && (temp & 0x0600)) - /* サプレスされたレジスタが .l 指定されてる */ - || ((UndefRegLevel & 8) && (temp & 0x0800)) - ) { - UNDEFINED(); return; - } - } - - zareg = (temp & 0x80); - if (zareg && (UndefRegLevel & 2) && eareg) { - UNDEFINED(); return; /* サプレスされたレジスタが a0 ではない */ - } - - if (bdsize == 4) - op->opval = (address) bd; - if (odsize == 4) - op->opval2 = (address) od; - op->exbd = bdsize; - op->exod = odsize; - - IfNeedStr { - *p++ = '('; - if (indirect) - *p++ = '['; - - if (bdsize) { - int lim = (bdsize == 2) ? 127 : 32767; - if (bd < 0) { - *p++ = '-'; - bd = -bd; - lim++; - } - - if (bdsize == 2) { - bd &= 0xffff; - p = itox4d (p, bd); - if (bd <= lim && !indirect) { - *p++ = '.'; /* (d8.w,an,ix) */ - *p++ = 'w'; - } - - } else if (bdsize == 4) { - p = itox8d (p, bd); - if (bd <= lim) { - *p++ = '.'; /* (d16.l,an,ix) */ - *p++ = 'l'; - } - } - } - - if (!zareg || (UndefRegLevel & 2) == 0) { - if (bdsize) - *p++ = ','; - if (zareg) - *p++ = 'z'; - *p++ = 'a'; - *p++ = eareg + '0'; - } - - if (indirect == 1) - *p++ = ']'; - - if (!zreg || (UndefRegLevel & 0x0e) != 0x0e) { - int scale; - - if (p != &op->operand[1]) - *p++ = ','; - if (zreg) - *p++ = 'z'; - *p++ = (temp & 0x8000 ? 'a' : 'd'); - *p++ = ((temp >> 12) & 7) + '0'; - *p++ = '.'; - *p++ = (temp & 0x0800 ? 'l' : 'w'); - if ((scale = (temp >> 9) & 3)) { - *p++ = '*'; - *p++ = (scale == 1) ? '2' - : (scale == 2) ? '4' : '8'; - } - } - - if (indirect == 2) - *p++ = ']'; - - if (odsize) { - int lim = 32767; - *p++ = ','; - if (od < 0) { - *p++ = '-'; - od = -od; - lim++; - } - - if (odsize == 2) { - od &= 0xffff; - p = itox4d (p, od); - } else if (odsize == 4) { - p = itox8d (p, od); - if (bd < lim) { - *p++ = '.'; - *p++ = 'l'; - } - } - } - *p++ = ')'; - *p = '\0'; - } - code->bytes += 2 + bdsize + odsize; - return; - } - - /* 短縮フォーマットの拡張ワード */ - else { /* (d8,An,ix) */ - signed char d8 = *(signed char*) (ptr + code->bytes + 1); - - temp = *(UBYTE*) (ptr + code->bytes); - op->eaadrs = PC + code->bytes; - - /* scaling check (68020 未満のチェック) */ - if ((temp >> 1) & 3) - REJECT (M000|M010); - - IfNeedStr { - int scale; - - *p++ = '('; - if (d8) { - if (d8 < 0) { - *p++ = '-'; - d8 = -d8 & 0xff; - } - p = itox2d (p, d8); - *p++ = ','; - } - *p++ = 'a'; - *p++ = eareg + '0'; - *p++ = ','; - *p++ = (temp & 0x80 ? 'a' : 'd'); - *p++ = ((temp >> 4) & 7) + '0'; - *p++ = '.'; - *p++ = (temp & 0x08 ? 'l' : 'w'); - - /* scaling (68020 未満のチェック済) */ - if ((scale = (temp >> 1) & 3)) { - *p++ = '*'; - *p++ = (scale == 1) ? '2' - : (scale == 2) ? '4' : '8'; - } - *p++ = ')'; - *p = '\0'; - } - code->bytes += 2; - return; - } - } - } + disp->ptr += code->bytes; + disp->pc += code->bytes; + return code->bytes; } -/* EOF */ +// EOF diff --git a/src/disasm.h b/src/disasm.h index 379bae0..522af46 100644 --- a/src/disasm.h +++ b/src/disasm.h @@ -1,163 +1,197 @@ -/* $Id: disasm.h,v 1.1 1996/10/24 04:27:42 ryo freeze $ - * - * ソースコードジェネレータ - * 逆アセンブルモジュールヘッダ - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef DISASM_H -#define DISASM_H +// ソースコードジェネレータ +// 逆アセンブルモジュールヘッダ +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik +#ifndef DISASM_H +#define DISASM_H #include "estruct.h" +// mputypes +#define M000 (1 << 0) // 68000 +#define M010 (1 << 1) // 68010 +#define M020 (1 << 2) // 68020 +#define M030 (1 << 3) // 68030 +#define M040 (1 << 4) // 68040 +#define M060 (1 << 6) // 68060 +#define MISP (1 << 7) // 060ISP(software emulation) + +// fputypes +#define F881 (1 << 0) // 68881 +#define F882 (1 << 1) // 68882 +#define F88x (F881 | F882) +#define F040 (1 << 2) // 68040 +#define F4SP (1 << 3) // 040FPSP(software emulation) +#define F060 (1 << 4) // 68060 +#define F6SP (1 << 5) // 060FPSP(software emulation) + +// mmutypes (same bit position as mputypes) +#define MMU851 M020 // 68020 + 68851 +#define MMU030 M030 // 68030 internal MMU +#define MMU040 M040 // 68040 internal MMU +#define MMU060 M060 // 68060 internal MMU + +enum { + CPID_MMU = 0, + CPID_FPU = 1, + CPID_CACHE_MMU = 2, + CPID_MOVE16 = 3, + CPID_CPU32 = 4, +}; + +// 68040以降のFFLUSH命令 +typedef enum { + PFOPMODE_PFLUSHN = 0, + PFOPMODE_PFLUSH = 1, + PFOPMODE_PFLUSHAN = 2, + PFOPMODE_PFLUSHA = 3, +} PflushOpMode; + +// FTRAPcc, PTRAPccのオペランドサイズ +enum { + CPTRAP_WORD = 2, + CPTRAP_LONG = 3, + CPTRAP_UNSIZED = 4, +}; + +typedef uint8_t opetype; +enum { + OTHER, // 普通の命令 + JMPOP, // 分岐命令 + JSROP, // サブルーチンコール命令 + RTSOP, // リターン命令 + BCCOP, // 条件分岐命令 + UNDEF = 15, // 未定義 +}; -#define MAX_MACRO_LEN 16 -#define SXCALL_MAX 0x1000 /* SX Window use 0xa000 - 0xafff */ +typedef enum { + DregD, // データレジスタ直接 + AregD, // アドレスレジスタ直接 + AregID, // アドレスレジスタ間接 + AregIDPI, // ポストインクリメントアドレスレジスタ間接 + AregIDPD, // プリデクリメントアドレスレジスタ間接 + AregDISP, // ディスプレースメント付アドレスレジスタ間接 + AregIDX, // インデックス付アドレスレジスタ間接 + AbShort = 8, // 絶対ショートアドレス + AbLong, // 絶対ロングアドレス + PCDISP, // ディスプレースメント付プログラムカウンタ相対 + PCIDX, // インデックス付プログラムカウンタ相対 + IMMED, // イミディエイトデータ + CcrSr = 16, // CCR / SR 形式 + + AregIDXB, // インデックス&ベースディスプレースメント付きアドレスレジスタ間接 + AregPOSTIDX, // ポストインデックス付きメモリ間接 + AregPREIDX, // プリインデックス付きメモリ間接 + PCIDXB, // インデックス&ベースディスプレースメント付きプログラムカウンタ間接 + PCPOSTIDX, // ポストインデックス付きPCメモリ間接 + PCPREIDX, // プリインデックス付きPCメモリ間接 + + RegList, // レジスタリスト + + CtrlReg, // 制御レジスタ + + RegPairD, // レジスタペア(直接) dx:dy + RegPairID, // レジスタペア(間接) (rx):(ry) + BitField, // ビットフィールドの {offset:width} + + MMUreg, // MMUレジスタ + + FPregD, // FPn + FPCRSR, // FPSR,FPCR,FPIAR + FPPairD, // レジスタペア(直接) FPx:FPy + KFactor, // K-Factor {offset:width} + FPregList, // FP レジスタリスト +} adrmode; -/* MPU_types */ -#define M000 (1<<0) /* 68000 */ -#define M010 (1<<1) /* 68010 */ -#define M020 (1<<2) /* 68020 */ -#define M030 (1<<3) /* 68030 */ -#define M040 (1<<4) /* 68040 */ -#define M060 (1<<6) /* 68060 */ -#define MISP (1<<7) /* 060ISP(software emulation) */ +// operand::flags +enum { + // 直前のオペランドと "," なしで結合する(ビットフィールド、k-factor) + OPFLAG_COMBINE = 0x01, -typedef unsigned char mputypes; + // PC相対のディスプレースメントを持つ + OPFLAG_PC_RELATIVE = 0x80, +}; -/* FPCP_type */ -#define F881 (1<<0) /* 68881 */ -#define F882 (1<<1) /* 68882 */ -#define F88x (F881|F882) -#define F040 (1<<2) /* 68040 */ -#define F4SP (1<<3) /* 040FPSP(software emulation) */ -#define F060 (1<<4) /* 68060 */ -#define F6SP (1<<5) /* 060FPSP(software emulation) */ +// operand::labelchange1 +enum { + LABELCHANGE_DISALLOW = 0, + LABELCHANGE_ALLOW, + LABELCHANGE_DEPEND, // アドレス依存データのみ + LABELCHANGE_LABEL_ONLY = -1, // ラベルのみ(BRA,Bcc,DBcc など) +}; -/* MMU_type */ -#define MMU851 (1<<0) /* 68020 + 68851 */ -#define MMU030 (1<<1) /* 68030 internal MMU */ -#define MMU040 (1<<2) /* 68040 internal MMU */ -#define MMU060 (1<<3) /* 68060 internal MMU */ +typedef struct { + char operand[64]; // オペランド文字列 + adrmode ea; // 実効アドレスモード + address opval; // オペランドの値 + address opval2; // オペランドの値(od用) + address eaadrs; // オペランドの存在アドレス + address eaadrs2; // オペランドの存在アドレス(od用) + int8_t labelchange1; // ラベル化可能 + uint8_t flags; // OPFLAG_xxx + uint8_t exbd; // bd のサイズ(0,2,4) 0ならサプレス + uint8_t exod; // od のサイズ(0,2,4) 0ならサプレス + + // DregD, AregD, AregIDX, PCIDX の場合のみ有効 + uint8_t baseReg; // ベースレジスタ番号(0-7) + uint8_t ixReg; // インデックスレジスタ番号(0-15) + uint8_t ixSizeScale; // インデックスレジスタのサイズとスケールファクタ + + uint8_t reserved[1]; +} operand; +// disasm::codeflags +enum { + // -M オプションでコメントを付ける命令(cmpi, move #imm など) + CODEFLAG_NEED_COMMENT = 0x02, -typedef enum { - OTHER , /* 普通の命令 */ - JMPOP , /* 分岐命令 */ - JSROP , /* サブルーチンコール命令 */ - RTSOP , /* リターン命令 */ - BCCOP , /* 条件分岐命令 */ - UNDEF = 15 , /* 未定義 */ -} opetype; + // JMPOP のうち、-B オプション指定時のみ空行を入れる命令(bra、fbra) + CODEFLAG_BRAOP = 0x04, + // -b0 オプション指定時にサイズを省略できない命令(bra.l d16 など) + CODEFLAG_NEED_OPESIZE = 0x08, +}; -typedef enum { - DregD , /* データレジスタ直接 */ - AregD , /* アドレスレジスタ直接 */ - AregID , /* アドレスレジスタ間接 */ - AregIDPI , /* ポストインクリメントアドレスレジスタ間接 */ - AregIDPD , /* プリデクリメントアドレスレジスタ間接 */ - AregDISP , /* ディスプレースメント付アドレスレジスタ間接 */ - AregIDX , /* インデックス付アドレスレジスタ間接 */ - AbShort = 8 , /* 絶対ショートアドレス */ - AbLong , /* 絶対ロングアドレス */ - PCDISP , /* ディスプレースメント付プログラムカウンタ相対 */ - PCIDX , /* インデックス付プログラムカウンタ相対 */ - IMMED , /* イミディエイトデータ */ - SRCCR = 16 , /* CCR / SR 形式 */ - - AregIDXB, /* インデックス&ベースディスプレースメント付きアドレスレジスタ間接 */ - AregPOSTIDX, /* ポストインデックス付きメモリ間接 */ - AregPREIDX, /* プリインデックス付きメモリ間接 */ - PCIDXB, /* インデックス&ベースディスプレースメント付きプログラムカウンタ間接 */ - PCPOSTIDX, /* ポストインデックス付きPCメモリ間接 */ - PCPREIDX, /* プリインデックス付きPCメモリ間接 */ - - CtrlReg, /* 制御レジスタ */ - - RegPairD, /* レジスタペア(直接) dx:dy */ - RegPairID, /* レジスタペア(間接) (rx):(ry) */ - BitField, /* ビットフィールドの {offset:width} */ - - MMUreg, /* MMUレジスタ */ - - FPregD, /* FPn */ - FPCRSR, /* FPSR,FPCR,FPIAR */ - FPPairD, /* レジスタペア(直接) FPx:FPy */ - KFactor, /* K-Factor {offset:width} */ +typedef struct { + WORD opecodeOffset; // 命令(OpString 上のオフセット) + mputypes mputypes; // この命令を実行可能なMPUの種類(M000|M010|...) + int8_t fpuid; // 浮動小数点命令のコプロセッサID(0-7,-1なら通常命令) + opesize size; // サイズ(lea, pea は long) (0 = .b .w .l .s nothing) + opesize size2; // サイズ(lea, pea, moveq, bset, ... は UNKNOWN) + opesize default_size; // その命令のデフォルトのサイズ + int bytes; // 命令のバイト数 + opetype opeType; // 命令の種類 + uint8_t codeflags; + uint8_t reserved[2]; + + address pc; // 命令の開始PC + address jmp; // ジャンプ先アドレス (分岐命令なら) + adrmode jmpea; // 実効アドレスモード (分岐命令なら) + operand op1; + operand op2; + operand op3; + operand op4; +} disasm; -} adrmode; +typedef struct { + address pc; + address pcEnd; + codeptr ptr; + disasm code; +} DisParam; -typedef struct { - char operand[ 64 ]; /* オペランド文字列 */ - adrmode ea; /* 実効アドレスモード */ - address opval; /* オペランドの値 */ - address opval2; /* オペランドの値(od用) */ - address eaadrs; /* オペランドの存在アドレス */ - address eaadrs2; /* オペランドの存在アドレス(od用) */ - unsigned char labelchange1; /* ラベル化可能 -1なら()なし(bsr用) */ - unsigned char labelchange2; /* ラベル化可能 */ - unsigned char exbd; /* bd のサイズ(0,2,4) 0ならサプレス */ - unsigned char exod; /* od のサイズ(0,2,4) 0ならサプレス */ -} operand; +static inline void setDisParamPcPtr(DisParam* disp, address pc, + codeptr disOfst) { + disp->pc = pc; + disp->ptr = disOfst + pc; +} +extern int dis(DisParam* disp); -typedef struct { - char opecode[ 32 ]; /* 命令 */ - opesize size; /* サイズ ( lea , pea は long ) ( 0 = .b .w .l .s nothing ) */ - opesize size2; /* サイズ ( lea, pea, moveq, bset, ... は UNKNOWN ) */ - opesize default_size; /* その命令のデフォルトのサイズ */ - int bytes; /* 命令のバイト数 */ - opetype flag; /* 命令の種類 ( 0 = other jmp jsr rts bcc undef ) */ - mputypes mputypes; /* この命令を実行可能なMPUの種類(M000|M010|...) */ - char fpuid; /* 浮動小数点命令のコプロセッサID(0-7,-1なら通常命令) */ - char opflags; /* FLAGS_xxx */ - char reserved; /* 予約 */ - address jmp; /* ジャンプ先アドレス ( 分岐命令なら ) */ - adrmode jmpea; /* 実効アドレスモード ( 分岐命令なら ) */ - operand op1; - operand op2; - operand op3; - operand op4; -} disasm; +#endif // DISASM_H -#define FLAG_CANNOT_UPPER 0x01 -#define FLAG_NEED_COMMENT 0x02 -#define FLAG_NEED_NULSTR 0x04 - -#ifndef OSKDIS -extern char** OSlabel; -extern char** FElabel; -extern char** SXlabel; -extern char OSCallName[MAX_MACRO_LEN]; -extern char FECallName[MAX_MACRO_LEN]; -extern char SXCallName[MAX_MACRO_LEN]; -#endif -extern char FPUID_table[16]; -extern boolean Disasm_Exact; -extern boolean Disasm_String; -extern boolean Disasm_UnusedTrapUndefined; -extern boolean Disasm_AddressErrorUndefined; -extern boolean Disasm_Dbra; -extern boolean Disasm_MnemonicAbbreviation; -extern boolean Disasm_SX_Window; -extern boolean Disasm_CPU32; -extern boolean Disasm_ColdFire; -extern mputypes MPU_types; -extern short MMU_type; -extern short FPCP_type; -extern int UndefRegLevel; -extern address PCEND; - -extern int dis (address, disasm*, address*); - - -#endif /* DISASM_H */ - -/* EOF */ +// EOF diff --git a/src/disasmonly.c b/src/disasmonly.c deleted file mode 100644 index 0d35116..0000000 --- a/src/disasmonly.c +++ /dev/null @@ -1,152 +0,0 @@ -/* $Id: disasmonly.c,v 1.1 1996/11/07 08:03:30 ryo freeze $ - * - * ソースコードジェネレータ - * 単なる逆アセンブルモジュール - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#include -#include /* strcmp memcmp strlen */ -#include /* tolower */ - -#include "disasm.h" -#include "estruct.h" -#include "etc.h" -#include "generate.h" -#include "global.h" -#include "hex.h" -#include "output.h" - - -USEOPTION option_x, option_B; - - -static INLINE char* -strcpy2 (char* dst, char* src) -{ - while ((*dst++ = *src++) != 0) - ; - return --dst; -} - - -private int -disasm1line (address pc, address pcend) -{ - char buffer[256]; - address pc0 = pc, store0 = pc + Ofst; - disasm code; - int bytes; - char* ptr; - char* l; - - bytes = dis (store0, &code, &pc); - modify_operand (&code); - - ptr = buffer; - *ptr++ = '\t'; - -#ifdef OSKDIS -#define OS9CALL(n, v, t) (peekw (store0) == (n) && (v) < 0x100 && (l = (t)[(v)])) - if (OS9CALL (0x4e40, code.op1.opval, OS9label)) - strcat (strcpy (ptr, "OS9\t"), l); - else if (OS9CALL (0x4e4d, code.op2.opval, CIOlabel)) - strcat (strcpy (ptr, "TCALL\tCIO$Trap,"), l); - else if (OS9CALL (0x4e4f, code.op2.opval, MATHlabel)) - strcat (strcpy (ptr, "TCALL\tT$Math,"), l); -#else - if (*(UBYTE*)store0 == 0x70 /* moveq #imm,d0 + trap #15 なら */ - && peekw (store0 + 2) == 0x4e4f /* IOCS コールにする */ - && IOCSlabel && (l = IOCSlabel[*(UBYTE*)(store0 + 1)]) != NULL - && (pc < pcend)) { - ptr = strcpy2 (ptr, IOCSCallName); - *ptr++ = '\t'; - strcpy2 (ptr, l); - bytes += 2; - /* pc += 2; */ - } -#endif /* OSKDIS */ - else { - ptr = strcpy2 (ptr, code.opecode); - if (code.size < NOTHING) { - *ptr++ = '.'; - *ptr++ = opsize[code.size]; - } - - if (code.op1.operand[0]) { - *ptr++ = '\t'; - ptr = strcpy2 (ptr, code.op1.operand); - - if (code.op2.operand[0]) { - if ((code.op2.ea != BitField) && (code.op2.ea != KFactor)) - *ptr++ = ','; - ptr = strcpy2 (ptr, code.op2.operand); - - if (code.op3.operand[0]) { - if ((code.op3.ea != BitField) && (code.op3.ea != KFactor)) - *ptr++ = ','; - ptr = strcpy2 (ptr, code.op3.operand); - - if (code.op4.operand[0]) { - if ((code.op4.ea != BitField) && (code.op4.ea != KFactor)) - *ptr++ = ','; - strcpy2 (ptr, code.op4.operand); - } - } - } - } - } - - if (option_x) - byteout_for_xoption (pc0, bytes, buffer); - - outputa (buffer); - newline (pc0); - - /* rts、jmp、bra の直後に空行を出力する */ - /* ただし、-B オプションが無指定なら bra は除く */ - if ((code.opflags & FLAG_NEED_NULSTR) - && (option_B || (code.opecode[0] != 'b' && code.opecode[0] != 'B'))) - outputa (CR); - - return bytes; -} - - -/* - - 単なる逆アセンブル - -*/ -extern void -disasmlist (char* xfilename, char* sfilename, time_t filedate) -{ - address pc = BeginTEXT; -#ifdef OSKDIS - address pcend = BeginBSS; -#else - address pcend = BeginDATA; -#endif /* OSKDIS */ - - if (option_x) - Atab += 2; - - init_output (); - output_file_open (sfilename, 0); - - PCEND = pcend; - while (pc < pcend) { - char adrs[8]; - itox6 (adrs, (ULONG) pc); - outputa (adrs); - pc += disasm1line (pc, pcend); - } - - output_file_close (); -} - - -/* EOF */ diff --git a/src/ea.c b/src/ea.c new file mode 100644 index 0000000..8d11a3f --- /dev/null +++ b/src/ea.c @@ -0,0 +1,1526 @@ +// ソースコードジェネレータ +// 実効アドレス解釈 +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "ea.h" + +#include + +#include "disasm.h" +#include "eastr.h" +#include "estruct.h" +#include "etc.h" +#include "fpconv.h" +#include "hex.h" +#include "mmu.h" + +// IS-I/IS 変換テーブル(未定義の項目は DregD にしている) +// 0 000: No Memory Indirect Action +// 0 001: Indirect Preindexed with Null OD +// 0 010: Indirect Preindexed with Word OD +// 0 011: Indirect Preindexed with Long OD +// 0 100: +// 0 101: Indirect Postindexed with Null OD +// 0 110: Indirect Postindexed with Word OD +// 0 111: Indirect Postindexed with Long OD +// 1 000: No Memory Indirect Action +// 1 001: Memory Indirect with Null OD +// 1 010: Memory Indirect with Word OD +// 1 011: Memory Indirect with Long OD +// 1 100: +// 1 101: +// 1 110: +// 1 111: +static const uint8_t an_i_iis_to_ea_table[16] = { + AregIDXB, AregPREIDX, AregPREIDX, AregPREIDX, DregD, AregPOSTIDX, + AregPOSTIDX, AregPOSTIDX, AregIDXB, AregPREIDX, AregPREIDX, AregPREIDX, + DregD, DregD, DregD, DregD, +}; +static const uint8_t pc_i_iis_to_ea_table[16] = { + PCIDXB, PCPREIDX, PCPREIDX, PCPREIDX, DregD, PCPOSTIDX, + PCPOSTIDX, PCPOSTIDX, PCIDXB, PCPREIDX, PCPREIDX, PCPREIDX, + DregD, DregD, DregD, DregD, +}; + +typedef enum { + BASEREG_A0 = 0, // a0-a7 = 0-7 + BASEREG_PC = -1 +} BaseReg; + +static int is_basereg_pc(BaseReg regno) { return regno < BASEREG_A0; } + +// brief extension word format / full extension word format 共通 +// ex_ix_typenum()、ex_ix_size()、ex_ix_scale() は ea.h にある。 + +// インデックスレジスタが d0 かどうか +static int ex_is_ix_d0(UWORD w) { return (w & 0xf000) == 0x0000; } +// サプレスされたインデックスレジスタが自然な指定(zd0.w*1)か +static int ex_is_well_zix(UWORD w) { return (w & 0xfe00) == 0x0000; } +// 拡張ワードの種類 0=brief 1=full +static int ex_is_full_format(UWORD w) { return (w >> 8) & 1; } + +// full のみ +// ベースレジスタ省略 0=省略しない 1=省略する +static int ex_is_br_suppress(UWORD w) { return (w >> 7) & 1; } +// インデックスレジスタ省略 0=省略しない 1=省略する +static int ex_is_ix_suppress(UWORD w) { return (w >> 6) & 1; } +// ベースディスプレースメントのサイズ 0=予約(未定義) 1=なし 2=ワード 3=ロング +static int ex_bd_size(UWORD w) { return (w >> 4) & 3; } +// Index/Indirect Selection +static int ex_iis(UWORD w) { return w & 7; } +// 未定義ビット +static int ex_reserved_bit(UWORD w) { return w & 0x0008; } + +// an, zan, pc, zpc +static char* write_basereg(char* p, BaseReg regno, UWORD exword) { + if (ex_is_br_suppress(exword)) p = write_suppress_z(p); + return is_basereg_pc(regno) ? write_pc(p) : write_an(p, regno); +} + +static char* write_ix(char* p, UWORD exword) { + int scale; + + p = write_rn(p, ex_ix_typenum(exword)); + p = write_size(p, ex_ix_size(exword) ? LONGSIZE : WORDSIZE); + + scale = ex_ix_scale(exword); + if (scale) { + *p++ = '*'; + *p++ = '0' + (1 << scale); + } + return p; +} + +static char* write_ix_or_zix(char* p, UWORD exword) { + if (ex_is_ix_suppress(exword)) p = write_suppress_z(p); + return write_ix(p, exword); +} + +// 8ビットディスプレースメントを文字列化 +static char* write0_d8(char* p, BYTE d8) { + ULONG ul = d8; + + if (d8 < 0) { + *p++ = '-'; + ul = -d8; + } + return itox2d(p, ul); +} + +// ワードディスプレースメントを文字列化 +static char* write0_d16(char* p, WORD d16) { + ULONG ul = d16; + + if (d16 < 0) { + *p++ = '-'; + ul = -d16; + } + return itox4d(p, ul); +} + +// ワードディスプレースメントを文字列化 +// (最適化抑止) 0 の場合はサイズ .w をつける +static char* write_d16_avoid_null(char* p, WORD d16) { + p = write0_d16(p, d16); + return (d16 == 0) ? write_size(p, WORDSIZE) : p; +} + +// ワードディスプレースメントを文字列化 +// (最適化抑止) d8 で表現できる値はサイズ .w をつける +static char* write_d16_avoid_d8(char* p, WORD d16) { + p = write0_d16(p, d16); + return (-128 <= d16 && d16 <= 128) ? write_size(p, WORDSIZE) : p; +} + +// d32 の値について、d16 で表現できる範囲ならサイズ .l をつける +static char* write_size_l_if_d16(char* p, LONG d32) { + return (-32768 <= d32 && d32 <= 32767) ? write_size(p, LONGSIZE) : p; +} + +// ロングディスプレースメントを文字列化 +// (最適化抑止) d16 で表現できる値はサイズ .l をつける +// $ffff8000-$ffffffff は負数として扱う +static char* write_d32_avoid_d16(char* p, LONG d32) { + if ((ULONG)d32 >= 0xffff8000) { + *p++ = '-'; + p = itox8d(p, (ULONG)-d32); + } else { + p = itox8d(p, (ULONG)d32); + } + return write_size_l_if_d16(p, d32); +} + +static char* write_bd(char* p, operand* op, boolean avoidD8) { + LONG disp = (LONG)op->opval; + + if (op->flags & OPFLAG_PC_RELATIVE) { + // PC相対の場合はアドレスではなくディスプレースメント値で扱う + disp -= (LONG)op->eaadrs - 2; + + if (op->exbd == 2) { + if (avoidD8) + return write_d16_avoid_d8(p, (WORD)disp); + else + return write_d16_avoid_null(p, (WORD)disp); + } else { + if ((ULONG)disp >= 0xffff8000) { + *p++ = '-'; + disp = (ULONG)-disp; + } + p = itox8d(p, (ULONG)disp); + return (-32768 <= disp && disp <= 32768) ? write_size(p, LONGSIZE) : p; + } + } + + return (op->exbd == 2) ? write_d16_avoid_null(p, (WORD)disp) + : write_d32_avoid_d16(p, disp); +} + +static char* write_bd_comma(char* p, operand* op) { + if (op->exbd == 0) return p; + + p = write_bd(p, op, FALSE); + *p++ = ','; + return p; +} + +static char* write_od(char* p, operand* op) { + return (op->exod == 2) ? write_d16_avoid_null(p, (WORD)op->opval2) + : write_d32_avoid_d16(p, (LONG)op->opval2); +} + +static char* write_comma_od(char* p, operand* op) { + if (op->exod == 0) return p; + + *p++ = ','; + return write_od(p, op); +} + +// データレジスタまたはアドレスレジスタ Dn or An +void setRn(operand* op, int regno) { + if (regno & 8) + setAn(op, regno); + else + setDn(op, regno); +} + +static unsigned int bit_reverse(UBYTE n) { + n = (n >> 4) | (n << 4); + n = ((n & 0xcc) >> 2) | ((n & 0x33) << 2); + n = ((n & 0xaa) >> 1) | ((n & 0x55) << 1); + return n; +} + +static char* stringifyRegList(char* p, unsigned int list, adrmode regtype); + +void setReglist(operand* op, UWORD reglist, boolean predec) { + op->ea = RegList; + + if (Dis.needString) { + char* p = op->operand; + + // -(An) のみ |D0|D1|...|D6|D7|A0|A1|...|A6|A7| の並び + unsigned int dreg = predec ? bit_reverse(reglist >> 8) : reglist & 0xff; + unsigned int areg = predec ? bit_reverse(reglist & 0xff) : reglist >> 8; + + p = stringifyRegList(p, dreg, DregD); + if (dreg && areg) *p++ = '/'; + stringifyRegList(p, areg, AregD); + } +} + +// データレジスタのペア Dm:Dn +void setPairDn(operand* op, int reg1, int reg2) { + op->ea = RegPairD; + + if (Dis.needString) { + char* p = op->operand; + p = write_dn(p, reg1); + *p++ = ':'; + *write_dn(p, reg2) = '\0'; + } +} + +// レジスタ間接ペア (Rm):(Rn) +// reg1, reg2 = 0...7 +void setPairID(operand* op, int reg1, int reg2) { + op->ea = RegPairID; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '('; + p = write_rn(p, reg1); + *p++ = ')'; + *p++ = ':'; + *p++ = '('; + p = write_rn(p, reg2); + *p++ = ')'; + *p++ = '\0'; + } +} + +// 浮動小数点レジスタのペア FPm:FPn +void setPairFPn(operand* op, int reg1, int reg2) { + op->ea = FPPairD; + + if (Dis.needString) { + char* p = op->operand; + p = write_fpn(p, reg1); + *p++ = ':'; + *write_fpn(p, reg2) = '\0'; + } +} + +void setFPCRSRlist(operand* op, int reglist) { + op->ea = FPCRSR; + + if (Dis.needString) { + char* p = op->operand; + + if (reglist & 0x04) { + p = write0_fpcrsr(p, 0); + if (reglist & 0x03) *p++ = '/'; + } + if (reglist & 0x02) { + p = write0_fpcrsr(p, 1); + if (reglist & 0x01) *p++ = '/'; + } + if (reglist & 0x01) { + p = write0_fpcrsr(p, 2); + } + } +} + +void setFPreglist(operand* op, UBYTE reglist, boolean predec) { + op->ea = FPregList; + + if (Dis.needString) { + // -(An) 以外は |FP0|FP1|...|FP6|FP7| の並びなので + // |FP7|FP6|...|FP1|FP0| に置き換える + unsigned int list = predec ? reglist : bit_reverse(reglist); + + stringifyRegList(op->operand, list, FPregD); + } +} + +static int count_trailing_one(unsigned int n) { + int c; + for (c = 0; n & 1; n >>= 1) c += 1; + return c; +} + +// レジスタリストを文字列化 +// regtype: DregD, AregD, FPregD +static char* stringifyRegList(char* p, unsigned int list, adrmode regtype) { + int regno; + + for (regno = 0; list != 0;) { + int len; + + if ((list & 1) == 0) { + regno += 1; + list >>= 1; + continue; + } + p = (regtype == DregD) ? write_dn(p, regno) + : (regtype == AregD) ? write_an(p, regno) + : write_fpn(p, regno); + len = count_trailing_one(list); + if (len >= 2) { + int r = regno + len - 1; + *p++ = '-'; + p = (regtype == DregD) ? write_dn(p, r) + : (regtype == AregD) ? write_an(p, r) + : write_fpn(p, r); + } + regno += (len + 1); + list >>= (len + 1); + if (list) *p++ = '/'; + } + + *p = '\0'; + return p; +} + +// dynamic k-factor {Dn} +void setDynamicKFactor(operand* op, int regno) { + op->ea = KFactor; + op->flags |= OPFLAG_COMBINE; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '{'; + p = write_dn(p, regno); + *p++ = '}'; + *p = '\0'; + } +} + +// static k-factor {#Imm} +// kfactor: 7ビット、2の補数表現(0x40...0x7f -> -64...-1) +void setStaticKFactor(operand* op, int kfactor) { + op->ea = KFactor; + op->flags |= OPFLAG_COMBINE; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '{'; + *p++ = '#'; + if (kfactor >= 0x40) { + *p++ = '-'; + kfactor = 0x80 - kfactor; + } + p = itod2(p, kfactor); + *p++ = '}'; + *p = '\0'; + } +} + +// ビットフィールド {offset:width} +void setBitField(operand* op, UWORD bf) { + op->ea = BitField; + op->flags |= OPFLAG_COMBINE; + + if (Dis.needString) { + int offset = (bf >> 6) & 0x1f; + int width = bf & 0x1f; + + char* p = op->operand; + *p++ = '{'; + + p = (bf & 0x0800) ? write_dn(p, offset & 7) : itod2(p, offset); + *p++ = ':'; + p = (bf & 0x0020) ? write_dn(p, width & 7) : itod2(p, width ? width : 32); + + *p++ = '}'; + *p = '\0'; + } +} + +void setUsp(operand* op) { + op->ea = CtrlReg; + + if (Dis.needString) { + write0_ctrlreg(op->operand, CTRLREG_USP); + } +} + +static mputypes get_ctrlreg_mputypes(int regno) { + static const mputypes types00x[9] = { + M010 | M020 | M030 | M040 | M060, // 0x000 sfc + M010 | M020 | M030 | M040 | M060, // 0x001 dfc + M020 | M030 | M040 | M060, // 0x002 cacr + M040 | M060, // 0x003 tc + M040, // 0x004 itt0 + M040, // 0x005 itt1 + M040, // 0x006 dtt0 + M040, // 0x007 dtt1 + M060 // 0x008 buscr + }; + static const mputypes types80x[9] = { + M010 | M020 | M030 | M040 | M060, // 0x800 usp + M010 | M020 | M030 | M040 | M060, // 0x801 vbr + M020 | M030, // 0x802 caar + M020 | M030 | M040, // 0x803 msp + M020 | M030 | M040, // 0x804 isp + M040, // 0x805 mmusr + M040 | M060, // 0x806 urp + M040 | M060, // 0x807 srp + M060 // 0x808 pcr + }; + + if (CTRLREG_SFC <= regno && regno <= CTRLREG_BUSCR) { + return types00x[regno - CTRLREG_SFC]; + } + if (CTRLREG_USP <= regno && regno <= CTRLREG_PCR) { + return types80x[regno - CTRLREG_USP]; + } + return 0; +} + +boolean setCtrlReg(disasm* code, operand* op, int regno) { + mputypes types = get_ctrlreg_mputypes(regno); + + if (types == 0 || reject(code, ~types)) return FALSE; + op->ea = CtrlReg; + + if (Dis.needString) { + write0_ctrlreg(op->operand, regno); + } + + return TRUE; +} + +void setCacheKind(operand* op, int caches) { + op->ea = CtrlReg; + + if (Dis.needString) { + write0_cachekind(op->operand, caches); + } +} + +boolean setMMUfc(disasm* code, operand* op, int fc) { + fc &= 0x1f; + + if (fc == 0 || fc == 1) { + op->ea = MMUreg; + if (Dis.needString) { + int regno = (fc == 0) ? CTRLREG_SFC : CTRLREG_DFC; + write0_ctrlreg(op->operand, regno); + } + return TRUE; + } + if ((fc >> 3) == 1) { // 01RRR + setDn(op, fc); + return TRUE; + } + if (fc & 0x10) { // 1DDDD or 10DDD + if (fc & 0x08) { + // 68020+68851なら0-15を指定できる(1DDDD)が、68030は0-7のみ(10DDD) + if ((Dis.mmu & MMU851) == 0) return FALSE; + + code->mputypes = M020; + } + op->ea = IMMED; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + itod2(p, fc & 0x0f); + } + return TRUE; + } + + return FALSE; +} + +void setMMUregVal(operand* op) { + op->ea = MMUreg; + if (Dis.needString) { + write0_mmureg(op->operand, MMUREG_VAL); + } +} + +static MmuReg get_mmu_regno(UWORD word2) { + int type = word2 >> 13; + int regno = (word2 >> 10) & 7; + + if (type == 2) { + return MMUREG_TC + regno; + } else if (type == 0) { + if (regno == 2) return MMUREG_TT0; + if (regno == 3) return MMUREG_TT1; + } + + return -1; +} + +// MC68851,MC68030 の PMOVE 命令(0b000,0b010) +// ea: 命令の第1ワードに含まれる +// として受け付けるモードを返す(0 なら不正な命令または対象外 MPU) +int setMMUreg(disasm* code, operand* op, UWORD word2, adrmode ea) { + static const struct { + mputypes neg_mpu; + uint8_t size; + } spec[] = { + {~M030, LONGSIZE}, // tt0 + {~M030, LONGSIZE}, // tt1 + {~(M020 | M030 | M040), LONGSIZE}, // tc + {~M020, QUADSIZE}, // drp + {~(M020 | M030 | M040), QUADSIZE}, // srp + {~(M020 | M030), QUADSIZE}, // crp + {~M020, BYTESIZE}, // cal + {~M020, BYTESIZE}, // val + {~M020, BYTESIZE}, // scc + {~M020, WORDSIZE} // ac + }; + int mode = 0; + int pmmu_mode; + UWORD mmu_to_mem = word2 & 0x0200; + MmuReg regno = get_mmu_regno(word2); + + if ((int)regno < 0 || reject(code, spec[regno].neg_mpu)) return 0; + + // が Dn,An,-(An),(An)+,#Imm,PC相対 なら MC68851 のみ + pmmu_mode = mmu_to_mem ? (CHANGE ^ CTRLCHG) : (ALL ^ CTRLCHG); + if (((1 << ea) & pmmu_mode) && reject_no_pmmu(code)) return 0; + + op->ea = MMUreg; + code->size = code->size2 = code->default_size = spec[regno].size; + code->bytes = 4; + + if (Dis.mmu & MMU851) mode |= (mmu_to_mem ? CHANGE : ALL); + if (Dis.mmu & MMU030) mode |= CTRLCHG; + // crp,drp,srp <--> dn,an は不可 + if (code->size == QUADSIZE) mode &= ~(DATAREG | ADRREG); + + if (Dis.needString) { + write0_mmureg(op->operand, regno); + } + + return mode; +} + +// MC68851,MC68030 の PMOVE 命令(0b011) +boolean setPMMUreg(disasm* code, operand* op, UWORD word2) { + int mputypes = 0; + UWORD preg = word2 & 0x1dff; + + if (preg == 0x0000) { + // 0b0110_00d0_0000_0000 ... MC68851 PSR (==MC68030 MMUSR) + + // -m68020,68030 なら 68030 を優先 + if (Dis.mmu & MMU030) { + mputypes = M030; + if (Dis.needString) { + write0_mmusr(op->operand); + } + } else { + mputypes = M020; + if (Dis.needString) { + write0_psr(op->operand); + } + } + } else if (Dis.mmu & MMU851) { + UWORD preg2 = word2 & 0x1de3; + + if (preg == 0x0400) { + // 0b0110_01d0_0000_0000 ... MC68851 PCSR + mputypes = M020; + if (Dis.needString) { + write0_pcsr(op->operand); + } + } else if (preg2 == 0x1000) { + // 0b0110_00d0_000n_nn00 ... MC68851 BADx + mputypes = M020; + if (Dis.needString) { + write0_badn(op->operand, (word2 >> 2) & 7); + } + } else if (preg2 == 0x1400) { + // 0b0110_01d0_000n_nn00 ... MC68851 BACx + mputypes = M020; + if (Dis.needString) { + write0_bacn(op->operand, (word2 >> 2) & 7); + } + } + } + if (mputypes == 0) return FALSE; + + code->mputypes = mputypes; + op->ea = MMUreg; + code->size = code->size2 = WORDSIZE; + code->bytes = 4; + return TRUE; +} + +// Mode=0b010 Reg=An +void setAnIndirect(operand* op, int regno) { + op->ea = AregID; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '('; + p = write_an(p, regno); + *p++ = ')'; + *p = '\0'; + } +} + +// Mode=0b011 Reg=An +void setAnPostinc(operand* op, int regno) { + op->ea = AregIDPI; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '('; + p = write_an(p, regno); + *p++ = ')'; + *p++ = '+'; + *p = '\0'; + } +} + +// Mode=0b100 Reg=An +void setAnPredec(operand* op, int regno) { + op->ea = AregIDPD; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '-'; + *p++ = '('; + p = write_an(p, regno); + *p++ = ')'; + *p = '\0'; + } +} + +// Mode=0b101 Reg=An +// regno = 0...7 +void setAnDisp(disasm* code, operand* op, int regno, WORD d16, boolean size) { + op->ea = AregDISP; + op->eaadrs = code->pc + code->bytes; + op->opval = (address)extl(d16); + op->baseReg = regno; + + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '('; + p = size ? write_d16_avoid_null(p, d16) : write0_d16(p, d16); + *p++ = ','; + p = write_an(p, regno); + *p++ = ')'; + *p = '\0'; + } +} + +// Mode=0b110 Reg=An ... brief extension word format +static boolean setAregIDX(disasm* code, operand* op, int regno, UWORD exword) { + BYTE d8 = ex_brief_d8(exword); + + // 68000-68010 はスケールファクタ 未対応 + int ix_scale = ex_ix_scale(exword); + if (ix_scale != 0 && reject(code, M000 | M010)) return FALSE; + + op->ea = AregIDX; + op->eaadrs = code->pc + code->bytes; + op->opval = (address)extbl(d8); + op->baseReg = regno; + op->ixReg = ex_ix_typenum(exword); + op->ixSizeScale = ex_ix_sizescale(exword); + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + + *p++ = '('; + if (d8) { + p = write0_d8(p, d8); + *p++ = ','; + } + p = write_an(p, regno); + *p++ = ','; + p = write_ix(p, exword); + *p++ = ')'; + *p = '\0'; + } + + return TRUE; +} + +// (bd,an|pc,ix) +// (an|pc,ix) のとき、HASによる (d8,an|pc,ix) への最適化を抑制できない +static void AnPcIDXB_an_ix(operand* op, BaseReg regno, UWORD exword) { + char* p = op->operand; + *p++ = '('; + + if (op->exbd) { + p = write_bd(p, op, TRUE); + *p++ = ','; + } + p = write_basereg(p, regno, exword); + *p++ = ','; + p = write_ix_or_zix(p, exword); + + *p++ = ')'; + *p = '\0'; +} + +// (bd,ill-zan,ix) (bd,an|ill-zan|pc|zpc,ill-zix) +// (bd,zpc,ix) ... (d8,zpc,ix) は存在しないので考慮不要 +static void AnPcIDXB_an_ix_ill(operand* op, BaseReg regno, UWORD exword) { + char* p = op->operand; + *p++ = '('; + + p = write_bd_comma(p, op); + p = write_basereg(p, regno, exword); + *p++ = ','; + p = write_ix_or_zix(p, exword); + + *p++ = ')'; + *p = '\0'; +} + +// (bd,ix) (bd,ill-zix) +static void AnIDXB_zan_ix(operand* op, UWORD exword) { + char* p = op->operand; + *p++ = '('; + + p = write_bd_comma(p, op); + p = write_ix(p, exword); + + *p++ = ')'; + *p = '\0'; +} + +// (bd,an|pc) +static void AnPcIDXB_an_zix(operand* op, BaseReg regno, UWORD exword) { + char* p = op->operand; + *p++ = '('; + + p = write_bd_comma(p, op); + p = write_basereg(p, regno, exword); + + // 最適化抑制のため、省略されたインデックスレジスタをわざと明示する + // (an) --> (an,zix) (d16,an) --> (d16,an,zix) + // (d16,pc) --> (d16,pc,zix) (pc)は最適化不可なので不要 + if (is_basereg_pc(regno) ? op->exbd == 2 : op->exbd != 4) { + *p++ = ','; + p = write_ix_or_zix(p, exword); + } + *p++ = ')'; + *p = '\0'; +} + +// (bd,zan|zpc) +static void AnPcIDXB_zan_zix(operand* op, BaseReg regno, UWORD exword) { + char* p = op->operand; + *p++ = '('; + + p = write_bd_comma(p, op); + p = write_basereg(p, regno, exword); + + *p++ = ')'; + *p = '\0'; +} + +// ベースレジスタ 有効, 省略(za0/zpc), 不自然な省略(za1-za7) +enum { + BRTYPE_AN = 0, + BRTYPE_ZAN = 1, + BRTYPE_ILL_ZAN = 2, +}; +// インデックスレジスタ 有効, 省略(zd0.w), 不自然な省略(zd0.l/zd1-zd7.[wl]) +enum { + IXTYPE_IX = 0, + IXTYPE_ZIX = 3, + IXTYPE_ILL_ZIX = 6, +}; + +static void stringifyAregIDXB(operand* op, BaseReg regno, UWORD exword) { + int brtype = ex_is_br_suppress(exword) + ? (regno == BASEREG_A0) ? BRTYPE_ZAN : BRTYPE_ILL_ZAN + : BRTYPE_AN; + int ixtype = ex_is_ix_suppress(exword) + ? ex_is_well_zix(exword) ? IXTYPE_ZIX : IXTYPE_ILL_ZIX + : IXTYPE_IX; + + switch (ixtype + brtype) { + default: + break; + + case IXTYPE_IX + BRTYPE_AN: + AnPcIDXB_an_ix(op, regno, exword); + break; + + case IXTYPE_IX + BRTYPE_ILL_ZAN: + case IXTYPE_ILL_ZIX + BRTYPE_AN: + case IXTYPE_ILL_ZIX + BRTYPE_ILL_ZAN: + AnPcIDXB_an_ix_ill(op, regno, exword); + break; + + case IXTYPE_IX + BRTYPE_ZAN: + case IXTYPE_ILL_ZIX + BRTYPE_ZAN: + AnIDXB_zan_ix(op, exword); + break; + + case IXTYPE_ZIX + BRTYPE_AN: + AnPcIDXB_an_zix(op, regno, exword); + break; + + case IXTYPE_ZIX + BRTYPE_ZAN: + case IXTYPE_ZIX + BRTYPE_ILL_ZAN: + AnPcIDXB_zan_zix(op, regno, exword); + break; + } +} + +static void stringifyPCIDXB(operand* op, BaseReg regno, UWORD exword) { + int brtype = ex_is_br_suppress(exword) ? BRTYPE_ZAN : BRTYPE_AN; + int ixtype = ex_is_ix_suppress(exword) + ? ex_is_well_zix(exword) ? IXTYPE_ZIX : IXTYPE_ILL_ZIX + : IXTYPE_IX; + + switch (ixtype + brtype) { + default: + break; + + case IXTYPE_IX + BRTYPE_AN: + AnPcIDXB_an_ix(op, regno, exword); + break; + + case IXTYPE_ZIX + BRTYPE_AN: + AnPcIDXB_an_zix(op, regno, exword); + break; + + case IXTYPE_ILL_ZIX + BRTYPE_AN: + AnPcIDXB_an_ix_ill(op, regno, exword); + break; + + case IXTYPE_IX + BRTYPE_ZAN: + case IXTYPE_ILL_ZIX + BRTYPE_ZAN: + AnPcIDXB_an_ix_ill(op, regno, exword); + break; + + case IXTYPE_ZIX + BRTYPE_ZAN: + AnPcIDXB_zan_zix(op, regno, exword); + break; + } +} + +// ([bd,an|zan],ix,od) ([bd,pc|zpc],ix,od) +static void AnPcPOSTIDX(operand* op, BaseReg regno, UWORD exword, int brtype) { + char c = 0; + char* p = op->operand; + *p++ = '('; + + *p++ = '['; + if (op->exbd) { + p = write_bd(p, op, FALSE); + c = ','; + } + if (brtype == BRTYPE_AN) { + if (c) *p++ = c; + p = write_basereg(p, regno, exword); + } + *p++ = ']'; + *p++ = ','; + p = write_ix_or_zix(p, exword); + p = write_comma_od(p, op); + + *p++ = ')'; + *p = '\0'; +} + +static void stringifyAregPOSTIDX(operand* op, BaseReg regno, UWORD exword) { + int brtype = (regno == BASEREG_A0 && ex_is_br_suppress(exword)) ? BRTYPE_ZAN + : BRTYPE_AN; + + // ベースディスプレースメントなしの場合、za0 は省略できない + if (op->exbd == 0) brtype = BRTYPE_AN; + + AnPcPOSTIDX(op, regno, exword, brtype); +} + +static void stringifyPCPOSTIDX(operand* op, BaseReg regno, UWORD exword) { + int brtype = BRTYPE_AN; // pc/zpc は省略できない + + AnPcPOSTIDX(op, regno, exword, brtype); +} + +// ([bd,an|zan,ix],od) ([bd,pc|zpc,ix],od) +static void AnPcPREIDX(operand* op, BaseReg regno, UWORD exword, int brtype, + int ixtype) { + char c = 0; + char* p = op->operand; + *p++ = '('; + + *p++ = '['; + if (op->exbd) { + p = write_bd(p, op, FALSE); + c = ','; + } + if (brtype == BRTYPE_AN) { + if (c) *p++ = c; + p = write_basereg(p, regno, exword); + c = ','; + } + if (ixtype == IXTYPE_IX) { + if (c) *p++ = c; + p = write_ix(p, exword); + } + *p++ = ']'; + p = write_comma_od(p, op); + + *p++ = ')'; + *p = '\0'; +} + +static void stringfyAregPREIDX(operand* op, BaseReg regno, UWORD exword) { + int brtype = (regno == BASEREG_A0 && ex_is_br_suppress(exword)) ? BRTYPE_ZAN + : BRTYPE_AN; + int ixtype = (ex_is_ix_suppress(exword) && ex_is_well_zix(exword)) + ? IXTYPE_ZIX + : IXTYPE_IX; + + // ベースディスプレースメントなし、インデックスレジスタなしの場合、 + // za0 は省略できない + if (op->exbd == 0 && ixtype != IXTYPE_IX) brtype = BRTYPE_AN; + + AnPcPREIDX(op, regno, exword, brtype, ixtype); +} + +static void stringfyPCPREIDX(operand* op, BaseReg regno, UWORD exword) { + int brtype = BRTYPE_AN; // pc/zpc は省略できない + int ixtype = (ex_is_ix_suppress(exword) && ex_is_well_zix(exword)) + ? IXTYPE_ZIX + : IXTYPE_IX; + + AnPcPREIDX(op, regno, exword, brtype, ixtype); +} + +// サプレスされたインデックスレジスタが自然な指定(zd0.w)か +static boolean is_well_formed_ix(UWORD exword) { + if (!ex_is_ix_d0(exword) && Dis.undefExReg) return FALSE; + if (ex_ix_scale(exword) != 0 && Dis.undefExScale) return FALSE; + if (ex_ix_size(exword) != 0 && Dis.undefExSize) return FALSE; + + return TRUE; +} + +// Mode=0b110 Reg=An ... full extension word format +// Mode=0b111 Reg=0b011 (PC indirect) +static boolean setFullExWordFormat(disasm* code, operand* op, codeptr ptr, + BaseReg regno, UWORD exword) { + int br_suppress, ix_suppless, bd_size, iis; + + // 拡張ワードへのオフセット (+PC で実行時アドレス、+ptr で格納メモリ) + int code_bytes; + + if (reject(code, M000 | M010)) return FALSE; + + bd_size = ex_bd_size(exword); // 1=null 2=word 3=long + if (bd_size == 0 || ex_reserved_bit(exword)) return FALSE; + + br_suppress = ex_is_br_suppress(exword); + if (br_suppress && !is_basereg_pc(regno)) { + // サプレスされたベースレジスタが za1-za7 か + if (regno != BASEREG_A0 && Dis.undefExReg) return FALSE; + } + + ix_suppless = ex_is_ix_suppress(exword); + if (ix_suppless && !is_well_formed_ix(exword)) return FALSE; + + iis = ex_iis(exword); + { + const uint8_t* table = + is_basereg_pc(regno) ? pc_i_iis_to_ea_table : an_i_iis_to_ea_table; + uint8_t ea = table[(ix_suppless << 3) + iis]; + + if (ea == DregD) return FALSE; + op->ea = (adrmode)ea; + } + + code_bytes = code->bytes + 2; + op->exbd = 0; + op->exod = 0; + + switch (bd_size) { + default: + break; + + case 2: // Word Displacement + op->eaadrs = code->pc + code_bytes; + op->opval = (address)extl(peekw(ptr + code_bytes)); + code_bytes += (op->exbd = 2); + + if (is_basereg_pc(regno) && !br_suppress) { + // (bd.w,pc) ならラベル化する + op->opval += (ULONG)(code->pc + code->bytes); + op->labelchange1 = LABELCHANGE_ALLOW; + op->flags |= OPFLAG_PC_RELATIVE; + } + break; + + case 3: // Long Displacement + op->eaadrs = code->pc + code_bytes; + op->opval = (address)peekl(ptr + code_bytes); + code_bytes += (op->exbd = 4); + + // (bd.l,an) (bd.l,zan) (bd.l,zpc) はリロケート情報があるときだけラベル化 + op->labelchange1 = LABELCHANGE_DEPEND; + + if (is_basereg_pc(regno)) { + if (!br_suppress) { + // (bd.l,pc) + op->opval += (ULONG)(code->pc + code->bytes); + op->labelchange1 = LABELCHANGE_ALLOW; + op->flags |= OPFLAG_PC_RELATIVE; + } + } + break; + } + + switch (iis) { + default: + break; + + case 2: // Word Displacement + case 6: + case 10: + op->eaadrs2 = code->pc + code_bytes; + op->opval2 = (address)extl(peekw(ptr + code_bytes)); + code_bytes += (op->exod = 2); + break; + + case 3: // Long Displacement + case 7: + case 11: + op->eaadrs2 = code->pc + code_bytes; + op->opval2 = (address)peekl(ptr + code_bytes); + code_bytes += (op->exod = 4); + break; + } + + code->bytes = code_bytes; + + if (!Dis.needString) return TRUE; + // 以下は文字列化処理 + + switch (op->ea) { + default: + break; + + case AregIDXB: + stringifyAregIDXB(op, regno, exword); + break; + case AregPOSTIDX: + stringifyAregPOSTIDX(op, regno, exword); + break; + case AregPREIDX: + stringfyAregPREIDX(op, regno, exword); + break; + + case PCIDXB: + stringifyPCIDXB(op, regno, exword); + break; + case PCPOSTIDX: + stringifyPCPOSTIDX(op, regno, exword); + break; + case PCPREIDX: + stringfyPCPREIDX(op, regno, exword); + break; + } + return TRUE; +} + +// 奇数アドレスへのワード以上アクセスなら未定義命令 +static boolean reject_odd(disasm* code, operand* op) { + if ((ULONG)op->opval & 1 && code->size2 != BYTESIZE && + code->size2 != UNKNOWN && !Dis.acceptAddressError) { + return TRUE; + } + return FALSE; +} + +// Mode=0b111 Reg=0b000 +static boolean setAbsShort(disasm* code, operand* op, codeptr ptr) { + op->ea = AbShort; + op->eaadrs = code->pc + code->bytes; + op->opval = (address)extl(peekw(ptr + code->bytes)); + if (reject_odd(code, op)) return FALSE; + code->bytes += 2; + + if (Dis.needString) { + LONG d32 = op->opval; + char* p = op->operand; + *p++ = '('; + if (d32 < 0) { + *p++ = '-'; + d32 = -d32; // -1...-$8000 + } + p = itox4d(p, (ULONG)d32); + *p++ = ')'; + *p++ = '\0'; + } + return TRUE; +} + +// Mode=0b111 Reg=0b001 +boolean setAbsLong(disasm* code, operand* op, codeptr ptr, boolean move16) { + op->ea = AbLong; + op->eaadrs = code->pc + code->bytes; + op->opval = (address)peekl(ptr + code->bytes); + + // move16 は16バイト(ライン)境界からの転送なので奇数アドレスチェック不要 + if (!move16 && reject_odd(code, op)) return FALSE; + + op->labelchange1 = LABELCHANGE_DEPEND; + code->bytes += 4; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '('; + p = itox8d(p, (ULONG)op->opval); + *p++ = ')'; + + // move16 は (abs).w がないのでサイズ不要 + if (!move16) p = write_size_l_if_d16(p, (LONG)op->opval); + + *p++ = '\0'; + } + return TRUE; +} + +// Mode=0b111 Reg=0b010 +static boolean setPcDisp(disasm* code, operand* op, WORD d16) { + op->ea = PCDISP; + op->eaadrs = code->pc + code->bytes; + op->opval = op->eaadrs + (LONG)d16; + if (reject_odd(code, op)) return FALSE; + op->labelchange1 = LABELCHANGE_ALLOW; + op->flags |= OPFLAG_PC_RELATIVE; + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '('; + + p = write0_d16(p, d16); + *p++ = ','; + p = write_pc(p); + + *p++ = ')'; + *p = '\0'; + } + return TRUE; +} + +// Mode=0b110 Reg=0b011 ... brief extension word format +static boolean setPCIDX(disasm* code, operand* op, UWORD exword) { + BYTE d8 = ex_brief_d8(exword); + + // 68000-68010 はスケールファクタ 未対応 + int ix_scale = ex_ix_scale(exword); + if (ix_scale != 0 && reject(code, M000 | M010)) return FALSE; + + op->ea = PCIDX; + op->eaadrs = code->pc + code->bytes; + op->opval = op->eaadrs + d8; + op->labelchange1 = LABELCHANGE_ALLOW; + op->flags |= OPFLAG_PC_RELATIVE; + op->ixReg = ex_ix_typenum(exword); + op->ixSizeScale = ex_ix_sizescale(exword); + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + + *p++ = '('; + p = write0_d8(p, d8); + *p++ = ','; + p = write_pc(p); + *p++ = ','; + p = write_ix(p, exword); + *p++ = ')'; + *p = '\0'; + } + return TRUE; +} + +// ワードの符号付き即値(link.w) +void setImmSignedWord(disasm* code, operand* op, codeptr ptr) { + WORD d16 = peekw(ptr + code->bytes); + + op->ea = IMMED; + op->eaadrs = code->pc + code->bytes; + op->opval = (address)extl(d16); + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + write0_d16(p, d16); + } +} + +// ロングワードの符号付き即値(link.l) +void setImmSignedLong(disasm* code, operand* op, codeptr ptr) { + LONG d32 = peekl(ptr + code->bytes); + + op->ea = IMMED; + op->eaadrs = code->pc + code->bytes; + op->labelchange1 = LABELCHANGE_DEPEND; + op->opval = (address)d32; + code->bytes += 4; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + if (d32 < 0) { + *p++ = '-'; + d32 = -d32; + } + itox8d(p, (ULONG)d32); + } +} + +static boolean is_ill_formed_undef_byte(UBYTE undefbyte, UBYTE imm) { + if (undefbyte == 0x00) return FALSE; + if (undefbyte == 0xff && imm >= 0x80) return FALSE; + + return TRUE; +} + +static boolean setImmByte(disasm* code, operand* op, codeptr ptr) { + UBYTE* bytes = (UBYTE*)(ptr + code->bytes); + UBYTE undefbyte = bytes[0], imm = bytes[1]; + + // 不定バイト(即値ワードの上位バイト)のチェック + if (!Dis.f && is_ill_formed_undef_byte(undefbyte, imm)) { + return FALSE; + } + + op->opval = (address)(ULONG)imm; + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + if (undefbyte == 0xff && imm >= 0x80) { + *p++ = '-'; // おそらく負数として記述されていたので負数として再現する + imm = -imm; + } + itox2d(p, (ULONG)imm); + } + return TRUE; +} + +boolean setImm(disasm* code, operand* op, codeptr ptr, opesize size) { + op->ea = IMMED; + op->eaadrs = code->pc + code->bytes; + + switch (size) { + default: + break; + + case BYTESIZE: + return setImmByte(code, op, ptr); + + case WORDSIZE: + op->opval = (address)(ULONG)peekw(ptr + code->bytes); + code->bytes += 2; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + itox4d(p, (ULONG)op->opval); + } + return TRUE; + + case LONGSIZE: + op->labelchange1 = LABELCHANGE_DEPEND; + op->opval = (address)peekl(ptr + code->bytes); + code->bytes += 4; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + itox8d(p, (ULONG)op->opval); + } + return TRUE; + + case QUADSIZE: // 8バイト(MMU命令専用) + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + stringifyQuadWord(p, (quadword*)(ptr + code->bytes)); + } + code->bytes += 8; + return TRUE; + + case SINGLESIZE: // 単精度実数(4バイト) + op->labelchange1 = LABELCHANGE_DEPEND; + op->opval = (address)peekl(ptr + code->bytes); + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + fpconv_s(p, ptr + code->bytes); + } + code->bytes += 4; + return TRUE; + + case DOUBLESIZE: // 倍精度実数(8バイト) + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + fpconv_d(p, ptr + code->bytes); + } + code->bytes += 8; + return TRUE; + + case EXTENDSIZE: // 拡張精度実数(12バイト) + if (reject_no_fpsp(code)) return FALSE; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + fpconv_x(p, ptr + code->bytes); + } + code->bytes += 12; + return TRUE; + + case PACKEDSIZE: // パックドデシマル(12バイト) + if (reject_no_fpsp(code)) return FALSE; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + fpconv_p(p, ptr + code->bytes); + } + code->bytes += 12; + return TRUE; + } + + return FALSE; +} + +void setCcr(operand* op) { + op->ea = CcrSr; + + if (Dis.needString) { + write0_ccr(op->operand); + } +} + +void setSr(operand* op) { + op->ea = CcrSr; + + if (Dis.needString) { + write0_sr(op->operand); + } +} + +static boolean setCcrSr(disasm* code, operand* op) { + switch (code->size) { + default: + break; + + case BYTESIZE: + setCcr(op); + return TRUE; + case WORDSIZE: + setSr(op); + return TRUE; + } + + return FALSE; +} + +// Mode=0b111 Reg=mode +static boolean setEAmode111(disasm* code, operand* op, codeptr ptr, int eareg, + int mode) { + switch (eareg) { + default: + break; + + case 0: + if ((mode & ABSW) == 0) break; + return setAbsShort(code, op, ptr); + + case 1: + if ((mode & ABSL) == 0) break; + return setAbsLong(code, op, ptr, FALSE); + + case 2: + if ((mode & DISPPC) == 0) break; + return setPcDisp(code, op, (WORD)peekw(ptr + code->bytes)); + + case 3: + if ((mode & IDXPC) == 0) break; + { + UWORD exword = peekw(ptr + code->bytes); + if (ex_is_full_format(exword)) + return setFullExWordFormat(code, op, ptr, BASEREG_PC, exword); + else + return setPCIDX(code, op, exword); + } + break; + + case 4: + if ((mode & IMMEDIATE) != 0) { + return setImm(code, op, ptr, code->size); + } + if ((mode & SRCCR) != 0) { + return setCcrSr(code, op); + } + break; + } + + return FALSE; +} + +// 命令の実効アドレス部を解読し、対応する文字列を返す +// code->bytes, code->size をセットしてから呼び出すこと +// ptr にオペコードのアドレス +boolean setEA(disasm* code, operand* op, codeptr ptr, int mode) { + int eamod; // 実効アドレスモード + int eareg; // 実効アドレスレジスタ + WORD word1 = peekw(ptr); + UWORD exword; + + if (mode & MOVEOPT) { // move 命令のディスティネーションの場合 + eamod = (word1 >> 6) & 7; + eareg = (word1 >> 9) & 7; + } else { + eamod = (word1 >> 3) & 7; + eareg = (word1 >> 0) & 7; + } + + switch (eamod) { + default: + break; + + case 0: + if ((mode & DATAREG) == 0) break; + setDn(op, eareg); + return TRUE; + + case 1: + if ((mode & ADRREG) == 0) break; + setAn(op, eareg); + return TRUE; + + case 2: + if ((mode & ADRIND) == 0) break; + setAnIndirect(op, eareg); + return TRUE; + + case 3: + if ((mode & POSTINC) == 0) break; + setAnPostinc(op, eareg); + return TRUE; + + case 4: + if ((mode & PREDEC) == 0) break; + setAnPredec(op, eareg); + return TRUE; + + case 5: + if ((mode & DISPAREG) == 0) break; + setAnDisp(code, op, eareg, (WORD)peekw(ptr + code->bytes), TRUE); + return TRUE; + + case 6: + if ((mode & IDXAREG) == 0) break; + exword = peekw(ptr + code->bytes); + if (ex_is_full_format(exword)) + return setFullExWordFormat(code, op, ptr, (BaseReg)eareg, exword); + else + return setAregIDX(code, op, eareg, exword); + + case 7: + return setEAmode111(code, op, ptr, eareg, mode); + } + + return FALSE; +} + +// EOF diff --git a/src/ea.h b/src/ea.h new file mode 100644 index 0000000..93947bd --- /dev/null +++ b/src/ea.h @@ -0,0 +1,262 @@ +// ソースコードジェネレータ +// 実効アドレス解釈 ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef EA_H +#define EA_H + +#include "disasm.h" +#include "eastr.h" +#include "estruct.h" +#include "etc.h" +#include "global.h" +#include "hex.h" + +// アドレッシングモード (bitmaped) +// Dn ----------------------------------------+ +// An ---------------------------------------+| +// (An) ------------------------------------+|| +// (An)+ ----------------------------------+||| +// -(An) ---------------------------------+|||| +// (d16,An) -----------------------------+||||| +// (d8,An,ix) --------------------------+|||||| +// N/A --------------------------------+||||||| +// (abs).w --------------------------+ |||||||| +// (abs).l -------------------------+| |||||||| +// (d16,pc) -----------------------+|| |||||||| +// (d8,pc,ix) --------------------+||| |||||||| +// #imm -------------------------+|||| |||||||| +enum { // ||||| |||||||| + DATAREG = 0x00001, // ------------ -------@ + ADRREG = 0x00002, // ------------ ------@- + ADRIND = 0x00004, // ------------ -----@-- + POSTINC = 0x00008, // ------------ ----@--- + PREDEC = 0x00010, // ------------ ---@---- + DISPAREG = 0x00020, // ------------ --@----- + IDXAREG = 0x00040, // ------------ -@------ + ABSW = 0x00100, // -----------@ -------- + ABSL = 0x00200, // ----------@- -------- + DISPPC = 0x00400, // ---------@-- -------- + IDXPC = 0x00800, // --------@--- -------- + IMMEDIATE = 0x01000, // -------@---- -------- + SRCCR = 0x10000, // ---@-------- -------- + MOVEOPT = 0x80000, // @----------- -------- + CHANGE = 0x0037f, // ----------@@ -@@@@@@@ + CTRLCHG = 0x00364, // ----------@@ -@@--@-- + CONTROL = 0x00f64, // --------@@@@ -@@--@-- + MEMORY = 0x01f7c, // -------@@@@@ -@@@@@-- + DATA = 0x01f7d, // -------@@@@@ -@@@@@-@ + ALL = 0x01f7f, // -------@@@@@ -@@@@@@@ +}; + +extern void setRn(operand* op, int regno); +extern void setReglist(operand* op, UWORD reglist, boolean predec); +extern void setPairDn(operand* op, int reg1, int reg2); +extern void setPairID(operand* op, int reg1, int reg2); +extern void setPairFPn(operand* op, int reg1, int reg2); +extern void setFPCRSRlist(operand* op, int reglist); +extern void setFPreglist(operand* op, UBYTE list, boolean predec); +extern void setDynamicKFactor(operand* op, int regno); +extern void setStaticKFactor(operand* op, int kfactor); +extern void setBitField(operand* op, UWORD bf); +extern void setUsp(operand* op); +extern boolean setCtrlReg(disasm* code, operand* op, int regno); +extern void setCacheKind(operand* op, int caches); +extern boolean setMMUfc(disasm* code, operand* op, int fc); +extern void setMMUregVal(operand* op); +extern int setMMUreg(disasm* code, operand* op, UWORD word2, adrmode ea); +extern boolean setPMMUreg(disasm* code, operand* op, UWORD word2); + +extern void setAnIndirect(operand* op, int regno); +extern void setAnPredec(operand* op, int regno); +extern void setAnPostinc(operand* op, int regno); +extern void setAnDisp(disasm* code, operand* op, int regno, WORD d16, + boolean nosize); +extern boolean setAbsLong(disasm* code, operand* op, codeptr ptr, + boolean move16); +extern void setImmSignedWord(disasm* code, operand* op, codeptr ptr); +extern void setImmSignedLong(disasm* code, operand* op, codeptr ptr); +extern boolean setImm(disasm* code, operand* op, codeptr ptr, opesize size); +extern void setCcr(operand* op); +extern void setSr(operand* op); +extern boolean setEA(disasm* code, operand* op, codeptr ptr, int mode); + +// 指定MPUだけが対象なら未定義命令 +static inline boolean reject(disasm* code, mputypes m) { + if ((Dis.mpu & ~m) == 0) return TRUE; + + code->mputypes &= ~m; + return FALSE; +} + +// 68040/68060でFPSP無しなら未定義命令(6888xなら常に有効) +static inline boolean reject_no_fpsp(disasm* code) { + fputypes fpu = Dis.fpu; + if ((fpu & (F4SP | F6SP)) == 0) { + if ((fpu & ~(F040 | F060)) == 0) return TRUE; + + code->mputypes &= ~(M040 | M060); + } + return FALSE; +} + +// 68851無しなら未定義命令 +static inline boolean reject_no_pmmu(disasm* code) { + if ((Dis.mmu & MMU851) == 0) return TRUE; + + code->mputypes = M020; + return FALSE; +} + +// brief extension word format / full extension word format 共通 +// 他は ec.c にある。 + +// インデックスレジスタの種類(Dn/An)と番号(0-7) +static inline int ex_ix_typenum(UWORD w) { return (w >> 12) & 15; } +// インデックスレジスタのサイズ 0=.w 1=.l +static inline int ex_ix_size(UWORD w) { return (w >> 11) & 1; } +// インデックスレジスタのスケールファクタ 0=*1 1=*2 2=*4 3=*8 +static inline int ex_ix_scale(UWORD w) { return (w >> 9) & 3; } +// インデックスレジスタのサイズとスケールファクタ +static inline int ex_ix_sizescale(UWORD w) { return (w >> 9) & 7; } + +// brief extension word format のみ + +// 8ビットディスプレースメント +static inline BYTE ex_brief_d8(UWORD w) { return (BYTE)(w & 0x00ff); } + +// アドレッシングモードがアドレスレジスタ直接か +// 0bxxxx_xxxx_xx00_1rrr x=命令依存 rrr=レジスタ番号 +static inline boolean is_areg_direct(UWORD word1) { + return ((word1 & 0x0038) == 0x0008) ? TRUE : FALSE; +} + +// アドレッシングモードがプリデクリメントか +// 0bxxxx_xxxx_xx10_0rrr x=命令依存 rrr=レジスタ番号 +static inline boolean is_predecrement(UWORD word1) { + return ((word1 & 0x0038) == 0x0020) ? TRUE : FALSE; +} + +// 命令の第1ワードからをそのまま取り出す +static inline int extract_ea_modreg(UWORD word1) { return word1 & 0x003f; } + +// 命令の第1ワードからを取り出す +// mode=7のときregisterを解釈する。拡張ワードは解釈しない +// 戻り値: DregD...AregIDX, AbShort...IMMED +static inline adrmode extract_ea_basic(UWORD word1) { + int ea = (word1 >> 3) & 7; + return (ea == 7) ? AbShort + (word1 & 7) : ea; +} + +static inline void setDn(operand* op, int regno) { + op->ea = DregD; + op->baseReg = regno & 7; + + if (Dis.needString) { + *write_dn(op->operand, op->baseReg) = '\0'; + } +} + +static inline void setAn(operand* op, int regno) { + op->ea = AregD; + op->baseReg = regno & 7; + + if (Dis.needString) { + *write_an(op->operand, op->baseReg) = '\0'; + } +} + +static inline void setFPn(operand* op, int regno) { + op->ea = FPregD; + if (Dis.needString) { + *write_fpn(op->operand, regno & 7) = '\0'; + } +} + +// 最適化防止用に即値オペランドにサイズを付ける +static inline void addsize(operand* op, opesize size) { + char* p = op->operand; + *write_size(p + strlen(p), size) = '\0'; +} + +// 即値が 1~8 なら最適化防止用にオペランドにサイズを付ける +static inline void addsize_if_1to8(operand* op, opesize size) { + if (((ULONG)op->opval - 1) <= 7) { + addsize(op, size); + } +} + +// 命令固有の方法で即値が埋め込まれている場合用(10進数表記) +static inline void setImmEmbed(operand* op, ULONG imm) { + op->ea = IMMED; + op->opval = (address)imm; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + itod2(p, imm); + } +} + +// 命令固有の方法で即値が埋め込まれている場合用(16進数表記) +static inline void setImmEmbedHex(operand* op, ULONG imm) { + op->ea = IMMED; + op->opval = (address)imm; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + itox2d(p, imm); + } +} + +// 即値 #1~#8 addq/subq/ビット演算 +static inline void setImm18(operand* op, ULONG imm) { + ULONG n = imm & 7; + op->ea = IMMED; + op->opval = (address)n; + + if (Dis.needString) { + char* p = op->operand; + *p++ = '#'; + *p++ = (n == 0) ? '8' : '0' + n; + *p = '\0'; + } +} + +// 相対分岐 +// disp: ロングワードに符号拡張したディスプレースメント +static inline void setrelative(disasm* code, operand* op, LONG disp) { + op->opval = code->pc + 2 + disp; + if (Dis.needString) { + itox8d(op->operand, (ULONG)op->opval); + } +} + +// 相対分岐(4バイトコード・コプロセッサ命令用) +// disp: ロングワードに符号拡張したディスプレースメント +static inline void setrelative4(disasm* code, operand* op, LONG disp) { + op->opval = code->pc + 4 + disp; + if (Dis.needString) { + itox8d(op->operand, (ULONG)op->opval); + } +} + +#endif + +// EOF diff --git a/src/eastr.c b/src/eastr.c new file mode 100644 index 0000000..73f18f1 --- /dev/null +++ b/src/eastr.c @@ -0,0 +1,60 @@ +// ソースコードジェネレータ +// 実効アドレス文字列 +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "eastr.h" + +#include "etc.h" +#include "global.h" + +EAStringTable EAString = { + {"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7"}, + {"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7"}, + "sp", + "bwlqssdxp", + 'z', + "pc", + "ccr", + "sr", + {"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7"}, + {"fpcr", "fpsr", "fpiar"}, + {"sfc", "dfc", "cacr", "tc", "itt0", "itt1", "dtt0", "dtt1", "buscr"}, + {"usp", "vbr", "caar", "msp", "isp", "mmusr", "urp", "srp", "pcr"}, + {"nc", "dc", "ic", "bc"}, + "psr", + "pcsr", + "mmusr", + {"bad0", "bad1", "bad2", "bad3", "bad4", "bad5", "bad6", "bad7"}, + {"bac0", "bac1", "bac2", "bac3", "bac4", "bac5", "bac6", "bac7"}, + {"tt0", "tt1", "tc", "drp", "srp", "crp", "cal", "val", "scc", "ac"} // +}; + +void initEAString(void) { + EAStringTable* eas = &EAString; + + if (Dis.U) toUpperMemory(sizeof(EAStringTable), eas); + + if (Dis.a7ToSp) { + char* a7 = eas->an[7]; + char* sp = eas->sp; + *a7++ = *sp++; + *a7++ = *sp++; + } +} + +// EOF diff --git a/src/eastr.h b/src/eastr.h new file mode 100644 index 0000000..4fd5eda --- /dev/null +++ b/src/eastr.h @@ -0,0 +1,240 @@ +// ソースコードジェネレータ +// 実効アドレス文字列 ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef EASTR_H +#define EASTR_H + +#include + +#include "estruct.h" +#include "etc.h" + +typedef struct { + char dn[8][2]; + char an[8][2]; + char sp[2]; + char size[PACKEDSIZE + 1]; + char suppress_z; + char pc[2]; + char ccr[4]; + char sr[2]; + char fpn[8][4]; + char fpcrsr[3][8]; // null-terminated + char cr00x[9][8]; // null-terminated + char cr80x[9][8]; // null-terminated + char cache[4][2]; + char psr[4]; + char pcsr[4]; + char mmusr[6]; + char badn[8][4]; + char bacn[8][4]; + char mmureg[10][4]; // null-terminated +} EAStringTable; + +extern EAStringTable EAString; + +// 制御レジスタ(movec) +enum { + CTRLREG_SFC = 0x000, + CTRLREG_DFC = 0x001, + CTRLREG_CACR = 0x002, + CTRLREG_TC = 0x003, + CTRLREG_ITT0 = 0x004, + CTRLREG_ITT1 = 0x005, + CTRLREG_DTT0 = 0x006, + CTRLREG_DTT1 = 0x007, + CTRLREG_BUSCR = 0x008, + CTRLREG_USP = 0x800, + CTRLREG_VBR = 0x801, + CTRLREG_CAAR = 0x802, + CTRLREG_MSP = 0x803, + CTRLREG_ISP = 0x804, + CTRLREG_MMUSR = 0x805, + CTRLREG_URP = 0x806, + CTRLREG_SRP = 0x807, + CTRLREG_PCR = 0x808, +}; + +// MMUレジスタ(MC68851,MC68030 pmove) +// EAString.mmureg[] 参照用の通し番号(オペコードとは異なる) +typedef enum { + MMUREG_TT0 = 0, + MMUREG_TT1, + MMUREG_TC, + MMUREG_DRP, + MMUREG_SRP, + MMUREG_CRP, + MMUREG_CAL, + MMUREG_VAL, + MMUREG_SCC, + MMUREG_AC, +} MmuReg; + +extern void initEAString(void); + +static inline char* write_size(char* p, opesize size) { + if (size < sizeof(EAString.size)) { + *p++ = '.'; + *p++ = EAString.size[size]; + } + return p; +} + +static inline char* write_dn(char* p, int regno) { + const char* s = EAString.dn[regno]; + *p++ = *s++; // 'd' + *p++ = *s++; // '0' + return p; +} + +static inline char* write_an(char* p, int regno) { + const char* s = EAString.an[regno]; + *p++ = *s++; // 'a' + *p++ = *s++; // '0' + return p; +} + +static inline char* write_fpn(char* p, int regno) { + const char* s = EAString.fpn[regno]; + *p++ = *s++; // 'f' + *p++ = *s++; // 'p' + *p++ = *s++; // '0' + return p; +} + +static inline char* write_rn(char* p, int regno) { + return (regno & 8) ? write_an(p, regno & 7) : write_dn(p, regno); +} + +static inline char* write_pc(char* p) { + const char* s = EAString.pc; + *p++ = *s++; + *p++ = *s++; + return p; +} + +static inline char* write_suppress_z(char* p) { + *p++ = EAString.suppress_z; + return p; +} + +static inline char* write_zan(char* p, int regno) { + *p++ = EAString.suppress_z; + return write_an(p, regno); +} + +static inline char* write_zpc(char* p) { + *p++ = EAString.suppress_z; + return write_pc(p); +} + +static inline void write0_ccr(char* p) { + const char* s = EAString.ccr; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_sr(char* p) { + const char* s = EAString.sr; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline char* write0_fpcrsr(char* p, int regno) { + char* s = EAString.fpcrsr[regno]; + + while ((*p++ = *s++)) { + // strcpy + } + return p - 1; +} + +static inline void write0_ctrlreg(char* p, int regno) { + int r = regno & 15; + const char* s = + (r == regno) + ? ((r < (int)_countof(EAString.cr00x)) ? EAString.cr00x[r] : "") + : ((r < (int)_countof(EAString.cr80x)) ? EAString.cr80x[r] : ""); + + strcpy(p, s); +} + +static inline void write0_cachekind(char* p, int caches) { + const char* s = EAString.cache[caches]; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_psr(char* p) { + const char* s = EAString.psr; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_pcsr(char* p) { + const char* s = EAString.pcsr; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_mmusr(char* p) { + const char* s = EAString.mmusr; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_badn(char* p, int regno) { + char* s = EAString.badn[regno]; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_bacn(char* p, int regno) { + char* s = EAString.bacn[regno]; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p++ = *s++; + *p = '\0'; +} + +static inline void write0_mmureg(char* p, MmuReg regno) { + const char* s = EAString.mmureg[regno]; + strcpy(p, s); +} + +#endif + +// EOF diff --git a/src/estruct.h b/src/estruct.h index 13629fb..ac12263 100644 --- a/src/estruct.h +++ b/src/estruct.h @@ -1,127 +1,129 @@ -/* $Id: estruct.h,v 1.1 1996/10/24 04:27:44 ryo freeze $ - * - * ソースコードジェネレータ - * 構造体定義ファイル - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef ESTRUCT_H -#define ESTRUCT_H +// ソースコードジェネレータ +// 構造体定義ファイル +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifdef __HUMAN68K__ -#define __attribute__(x) /* NOTHING */ +#ifndef ESTRUCT_H +#define ESTRUCT_H + +#include // size_t + +#ifdef _MSC_VER +#define NORETURN __declspec(noreturn) +#else +#define NORETURN // [[noreturn]] #endif -/* #include */ -typedef unsigned char UBYTE; -typedef short WORD; -typedef unsigned short UWORD; -typedef long LONG; -typedef unsigned long ULONG; +#ifdef __GNUC__ +#define GCC_NORETURN __attribute__((noreturn)) +#define GCC_PRINTF(a, b) __attribute__((format(printf, a, b))) +#else +#define GCC_NORETURN +#define GCC_PRINTF(a, b) +#endif + +#if __GNUC__ >= 3 +#define GCC_UNUSED __attribute__((unused)) +#else +#define GCC_UNUSED +#endif +#if defined(__GNUC__) && defined(__mc68000__) +#define GCC_ALIGN(n) __attribute__((aligned(n))) +#else +#define GCC_ALIGN(n) +#endif -#ifdef TRUE -#undef TRUE +#ifdef __HUMAN68K__ +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned int uintptr_t; + +#define PRIx16 "hx" +#define PRIu32 "u" +#define PRIx32 "x" +#else +#include +#include #endif -#ifdef FALSE -#undef FALSE + +// M680x0 data types +typedef int8_t BYTE; +typedef int16_t WORD; +typedef int32_t LONG; +typedef uint8_t UBYTE; +typedef uint16_t UWORD; +typedef uint32_t ULONG; +typedef uint32_t address; + +#define PRI_OPCODE "$%04" PRIx16 // UWORD -> "$4e71" +#define PRI_ULONG "%" PRIu32 // ULONG -> "123" +#define PRI_ULHEX "$%08" PRIx32 // ULONG -> "$0089abcd" +#define PRI_ADRS "$%08" PRIx32 // address -> "$0089abcd" + +// host data types +typedef uint8_t mputypes; +typedef uint8_t fputypes; +typedef uint8_t mmutypes; + +typedef uint8_t* codeptr; + +#if defined(TRUE) || defined(FALSE) +#error TRUE and FALSE are already defined somewhere. #endif typedef enum { FALSE, TRUE } boolean; typedef enum { - BYTESIZE, /* バイト */ - WORDSIZE, /* ワード */ - LONGSIZE, /* ロングワード */ - QUADSIZE, /* クワッドワード */ - SHORTSIZE, /* ショート( 相対分岐命令 ) */ - - SINGLESIZE, /* 32bit実数型 */ - DOUBLESIZE, /* 64bit実数型 */ - EXTENDSIZE, /* 96bit実数型 */ - PACKEDSIZE, /* 96bitBCD実数型 */ - NOTHING, /* 無し */ - - STRING, /* 文字列 */ - RELTABLE, /* リロケータブルオフセットテーブル */ - RELLONGTABLE, /* ロングワードなリロケータブルオフセットテーブル */ - ZTABLE, /* 絶対番地テーブル */ -#ifdef OSKDIS - WTABLE, /* ワードテーブル */ -#endif /* OSKDIS */ - - EVENID, - CRID, - WORDID, - LONGID, - BYTEID, - ASCIIID, - ASCIIZID, - LASCIIID, - BREAKID, - ENDTABLEID, - UNKNOWN = 128 /* 不明 */ + BYTESIZE, // バイト + WORDSIZE, // ワード + LONGSIZE, // ロングワード + QUADSIZE, // クワッドワード + SHORTSIZE, // ショート(相対分岐命令) + + SINGLESIZE, // 32bit実数型 + DOUBLESIZE, // 64bit実数型 + EXTENDSIZE, // 96bit実数型 + PACKEDSIZE, // 96bit BCD実数型 + NOTHING, // 無し + + STRING, // 文字列 + RELTABLE, // リロケータブルオフセットテーブル + RELLONGTABLE, // ロングワードなリロケータブルオフセットテーブル + ZTABLE, // 絶対番地テーブル + + WTABLE, // OSK ワードテーブル + + EVENID, // テーブルの識別子 + CRID, + BYTEID, + ASCIIID, + ASCIIZID, + LASCIIID, + BREAKID, + + UNKNOWN = 128 // 不明 } opesize; +typedef struct { + void* buffer; + void* write; + size_t capacity; + size_t count; + size_t bytes; + boolean isFrozen; +} ArrayBuffer; + +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +static inline int isEven(address adrs) { return (adrs & 1) ^ 1; } +static inline int isOdd(address adrs) { return (adrs & 1); } + +#endif // ESTRUCT_H -typedef UBYTE* address; - - -typedef struct { /* .x ファイルのヘッダ */ - UWORD head; - char reserve2; - char mode; - address base; - address exec; - ULONG text; - ULONG data; - ULONG bss; - ULONG offset; - ULONG symbol; - char reserve[ 0x1c ]; - ULONG bindinfo; -} __attribute__ ((packed)) xheader; - -typedef struct { /* .z ファイルのヘッダ */ - UWORD header; - ULONG text; - ULONG data; - ULONG bss; - char reserve[8]; - address base; - UWORD pudding; -} __attribute__ ((packed)) zheader; - - -#ifdef OSKDIS -typedef struct { /* OS-9/680x0 モジュールのヘッダ */ - UWORD head; /* +00 $4AFC */ - UWORD sysrev; /* +02 リビジョンID */ - ULONG size; /* +04 モジュールサイズ */ - ULONG owner; /* +08 オーナID */ - address name; /* +0C モジュール名オフセット */ - UWORD accs; /* +10 アクセス許可 */ - UWORD type; /* +12 モジュールタイプ/言語 */ - UWORD attr; /* +14 属性/リビジョン */ - UWORD edition; /* +16 エディション */ - address usage; /* +18 使い方コメントのオフセット */ - address symbol; /* +1C シンボルテーブル */ - char resv[14]; /* +20 予約済み */ - UWORD parity; /* +2E ヘッダパリティ */ - address exec; /* +30 実行オフセット */ - address excpt; /* +34 ユーザトラップエントリ */ - ULONG mem; /* +38 メモリサイズ */ - ULONG stack; /* +3C スタックサイズ */ - address idata; /* +40 初期化データオフセット */ - address irefs; /* +44 初期化参照オフセット */ - address init; /* +48 初期化実行エントリ(TRAPLIB) */ - address term; /* +4C 終了実行エントリ(TRAPLIB) */ -} __attribute__ ((packed)) os9header; -#endif /* OSKDIS */ - - -#endif /* ESTRUCT_H */ - -/* EOF */ +// EOF diff --git a/src/etc.c b/src/etc.c index c932e41..b5ad2d6 100644 --- a/src/etc.c +++ b/src/etc.c @@ -1,178 +1,159 @@ -/* $Id: etc.c,v 1.1 1996/11/07 08:03:32 ryo freeze $ - * - * ソースコードジェネレータ - * 雑用ルーチン - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 雑用ルーチン +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#include -#include /* isxdigit isdigit */ -#include /* exit(), EXIT_FAILURE */ +#include "etc.h" + +#include /* isxdigit isdigit */ #include +#include +#include /* exit(), EXIT_FAILURE */ #include "estruct.h" -#include "etc.h" #include "global.h" #include "label.h" #include "offset.h" #include "symbol.h" +#define ARRAYBUFFER_INITIAL_HALF 32 +#define ARRAYBUFFER_INCREASE_RATIO 2 -/* function in main.c */ -extern void free_load_buffer (void); -extern void print_title (void); - - -extern ULONG -atox (char* p) -{ - ULONG val = 0; - - if (p[0] == (char)'$') - p++; - /* 0x... なら頭の 0x を取り除く */ - else if (p[0] == (char)'0' && p[1] == (char)'x' && p[2]) - p += 2; +// ArrayBufferの内部バッファを解放する +// ArrayBufferは引き続き使用可能 +void freeArrayBuffer(ArrayBuffer* ab) { initArrayBuffer(ab, ab->bytes); } - while (isxdigit (*(unsigned char*)p)) { - unsigned char c = *p++; - val <<= 4; - if (isdigit (c)) - val += c - '0'; - else - val += tolower (c) - 'a' + 10; - } - return val; +// ArrayBufferを初期化する +void initArrayBuffer(ArrayBuffer* ab, size_t bytes) { + ab->buffer = ab->write = NULL; + ab->capacity = ab->count = 0; + ab->bytes = bytes; + ab->isFrozen = FALSE; } +// ArrayBufferの内部バッファを確保または拡大する +void secureArrayBufferCapacity(ArrayBuffer* ab) { + size_t offset; + size_t cap = ab->capacity; -/* フォーマット文字列を表示してエラー終了する. */ -extern void -err (const char* fmt, ...) -{ - va_list ap; + if (ab->isFrozen) internalError(__FILE__, __LINE__, "ArrayBuffer is frozen."); - print_title (); - va_start (ap, fmt); - vfprintf (stderr, fmt, ap); - va_end (ap); + if (cap == 0) cap = ARRAYBUFFER_INITIAL_HALF; + ab->capacity = cap = (cap * ARRAYBUFFER_INCREASE_RATIO); - free_labelbuf (); - free_relocate_buffer (); - free_symbuf (); - free_load_buffer (); - - exit (EXIT_FAILURE); + offset = (char*)ab->write - (char*)ab->buffer; + ab->buffer = Realloc(ab->buffer, cap * ab->bytes); + ab->write = (char*)ab->buffer + offset; } +// ArrayBufferの内部バッファと要素数を取得する +// 内部バッファが確保されていない場合はNULLを返す。 +// +// 呼び出し後は書き込み禁止になり、freeArrayBuffer()で解除される。 +void* getArrayBufferRawPointer(ArrayBuffer* ab, size_t* countPtr) { + freezeArrayBuffer(ab); -/* + *countPtr = ab->count; + return ab->buffer; +} - safe malloc +// ArrayBufferを書き込み禁止にする +// 内部バッファは使用しているサイズに切り詰められる。 +void freezeArrayBuffer(ArrayBuffer* ab) { + size_t size = (char*)ab->write - (char*)ab->buffer; -*/ -extern void* -Malloc (ULONG byte) -{ - void* rc; + ab->isFrozen = TRUE; + ab->capacity = ab->count; + if (ab->capacity) ab->buffer = Realloc(ab->buffer, size); +} - if (byte == 0) - byte = 1; - if ((rc = malloc (byte)) == NULL) - err ("ヒープメモリが不足しています.\n"); +extern ULONG atox(const char* p) { + ULONG val = 0; - return rc; -} + if (p[0] == '$') p++; + /* 0x... なら頭の 0x を取り除く */ + else if (p[0] == '0' && p[1] == 'x' && p[2]) + p += 2; + while (isxdigit(*p)) { + char c = *p++; + val <<= 4; + val += isdigit(c) ? (c - '0') : (tolower(c) - 'a' + 10); + } + return val; +} -#ifndef Mfree /* - safe mfree - - free() は NULL を渡した場合は何もせずに正常終了するので、通常は - #define Mfree(ptr) free(ptr) - としておきます. + safe malloc */ -extern void -Mfree (void* ptr) -{ - if (ptr) - free (ptr); -} -#endif +extern void* Malloc(size_t size) { + void* p = malloc((size == 0) ? 1 : size); + if (p == NULL) notEnoughMemory(); + return p; +} /* safe realloc */ -extern void* -Realloc (void* ptr, int size) -{ - void* rc; - - if ((rc = realloc (ptr, size)) == NULL) - err ("ヒープメモリが不足しています.\n"); - return rc; +extern void* Realloc(void* ptr, size_t size) { + void* rc = realloc(ptr, size); + + if (rc == NULL) notEnoughMemory(); + return rc; } +// 内部エラーを表示してエラー終了する +void internalError(const char* file, int line, const char* s) { + err("内部エラー: %s:%d: %s\n", file, line, s); +} -#ifndef __LIBC__ -extern int -eprintf (const char* fmt, ...) -{ - int cnt; - va_list ap; +// メモリ不足によるエラー終了 +void notEnoughMemory(void) { err("\nヒープメモリが不足しています。\n"); } - va_start (ap, fmt); - cnt = vfprintf (stderr, fmt, ap); - va_end (ap); - return cnt; -} -#endif +// フォーマット文字列を表示してエラー終了する +void err(const char* fmt, ...) { + va_list ap; -/* #define eputc (c) fputc (c, stderr) */ -extern int -eputc (int c) -{ - return fputc (c, stderr); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + errorExit(); } +// エラー終了する +void errorExit(void) { exit(EXIT_FAILURE); } -#ifndef __GNUC__ -extern ULONG -min (ULONG a, ULONG b) -{ - return a < b ? a : b; -} +#ifndef __LIBC__ +extern int eprintf(const char* fmt, ...) { + int cnt; + va_list ap; -extern ULONG -max (ULONG a, ULONG b); -{ - return a > b ? a : b; + va_start(ap, fmt); + cnt = vfprintf(stderr, fmt, ap); + va_end(ap); + return cnt; } #endif +/* #define eputc (c) fputc (c, stderr) */ +extern int eputc(int c) { return fputc(c, stderr); } -#ifndef HAVE_STRUPR -extern char* -strupr (char* str) -{ - unsigned char* p; +// 指定したメモリ内の小文字を大文字化する +void toUpperMemory(size_t len, void* ptr) { + char* p = ptr; + char* end = p + len; - for (p = (unsigned char*) str; *p; p++) { - if (islower (*p)) - *p = toupper (*p); - } - return str; + while (p < end) { + int c = toupper(*p); + *p++ = c; + } } -#endif - /* EOF */ diff --git a/src/etc.h b/src/etc.h index c771be0..e80497c 100644 --- a/src/etc.h +++ b/src/etc.h @@ -1,109 +1,140 @@ -/* $Id: etc.h,v 1.1 1996/10/24 04:27:44 ryo freeze $ - * - * ソースコードジェネレータ - * 雑用ルーチンヘッダファイル - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 雑用ルーチンヘッダファイル +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef ETC_H -#define ETC_H +#ifndef ETC_H +#define ETC_H -#include /* for __byte_swap_* */ +#include // for __byte_swap_* +#include // free() +#include +#include "estruct.h" #include "global.h" - -#if defined (__mc68000__) && !defined (__BIG_ENDIAN__) +#if defined(__mc68000__) && !defined(__BIG_ENDIAN__) #define __BIG_ENDIAN__ 1 #endif -#ifndef __LIBC__ -extern int eprintf (const char*, ...); +#ifndef _countof // stdlib.h +#define _countof(array) (sizeof(array) / sizeof(array[0])) #endif -extern int eputc (int); - -extern ULONG atox (char*); -extern void err (const char*, ...) __attribute__ ((noreturn)); -extern void* Malloc (ULONG); -extern void* Realloc (void*, int); -#ifdef MFREE_NO_MACRO -extern void Mfree (void*); -#else -#include -#define Mfree(ptr) free (ptr) +#if defined(_MSC_VER) +#define strcasecmp _stricmp +#define strncasecmp _strnicmp #endif -#ifndef HAVE_STRUPR -char* strupr (char* str); -#endif +// 可変長配列 +extern void freeArrayBuffer(ArrayBuffer* ab); +extern void initArrayBuffer(ArrayBuffer* ab, size_t bytes); +extern void secureArrayBufferCapacity(ArrayBuffer* ab); +extern void* getArrayBufferRawPointer(ArrayBuffer* ab, size_t* countPtr); +extern void freezeArrayBuffer(ArrayBuffer* ab); -USEOPTION option_q; -#define charout(a) (void)({ if (!option_q) eputc (a); }) +// ArrayBufferに新しい要素を書き込むためのバッファ上のアドレスを返す +static inline void* getArrayBufferNewPlace(ArrayBuffer* ab) { + void* p; + if (ab->capacity == ab->count || ab->isFrozen) secureArrayBufferCapacity(ab); -#ifdef min -#undef min -#endif -#ifdef max -#undef max -#endif + p = ab->write; + ab->count += 1; + ab->write = (char*)p + ab->bytes; + return p; +} -#ifdef __GNUC__ -#define min(a, b) ({ typeof (a) _a = (a), _b = (b); (_a < _b) ? _a : _b; }) -#define max(a, b) ({ typeof (a) _a = (a), _b = (b); (_a > _b) ? _a : _b; }) -#else -extern ULONG min (ULONG, ULONG); -extern ULONG max (ULONG, ULONG); +// エラー終了 +extern NORETURN void internalError(const char* file, int line, + const char* s) GCC_NORETURN; +extern NORETURN void notEnoughMemory(void) GCC_NORETURN; +extern NORETURN void err(const char*, ...) GCC_NORETURN GCC_PRINTF(1, 2); +extern NORETURN void errorExit(void) GCC_NORETURN; + +// メモリ確保 +extern void* Malloc(size_t size); +extern void* Realloc(void* ptr, size_t size); +static inline void Mfree(void* ptr) { free(ptr); } + +// 標準エラー出力 +#ifndef __LIBC__ +extern int eprintf(const char*, ...) GCC_PRINTF(1, 2); #endif +extern int eputc(int); + +static inline void charout(int a) { + if (!Dis.q) eputc(a); +} +// 文字列操作 +extern ULONG atox(const char*); +// 文字列末尾の \n を \0 で埋める +static inline void removeTailLf(char* s) { + if (*s) { + s += strlen(s) - 1; + if (*s == '\n') *s = '\0'; + } +} + +// 書き込んだ文字列の末尾を返すstrcpy() +static inline char* strcpy2(char* dst, const char* src) { + while ((*dst++ = *src++) != 0) + ; + return --dst; +} + +// 文字コード(X680x0 Shift_JIS) #ifdef HAVE_JCTYPE_H #include #else -#define iskanji(c) ((0x81 <= (c) && (c) <= 0x9f) || \ - (0xe0 <= (c) && (c) <= 0xfc)) -#define iskanji2(c) ((0x40 <= (c) && (c) <= 0xfc) && (c) != 0x7f) -#define isprkana(c) ((0x20 <= (c) && (c) <= 0x7e) || \ - (0xa1 <= (c) && (c) <= 0xdf)) - -#endif /* !HAVE_JCTYPE_H */ +#define iskanji(c) \ + ((0x81 <= (c) && (c) <= 0x9f) || (0xe0 <= (c) && (c) <= 0xfc)) +#define iskanji2(c) ((0x40 <= (c) && (c) <= 0xfc) && (c) != 0x7f) +#define isprkana(c) \ + ((0x20 <= (c) && (c) <= 0x7e) || (0xa1 <= (c) && (c) <= 0xdf)) +#endif // !HAVE_JCTYPE_H -#ifdef __BIG_ENDIAN__ -#define peekw(p) (*(unsigned short*) (p)) -#define peekl(p) (*(unsigned long *) (p)) +// メモリ操作 +extern void toUpperMemory(size_t len, void* ptr); -#else /* __LITTLE_ENDIAN__ */ +static inline UBYTE peekb(codeptr ptr) { + uint8_t* p = ptr; + return p[0]; +} -#ifdef __byte_swap_word -#define peekw(p) ((unsigned short) __byte_swap_word (*(unsigned short*) (p))) +static inline UWORD peekw(codeptr ptr) { +#ifdef __BIG_ENDIAN__ + return *(UWORD*)ptr; +#elif defined(__GNUC__) + return __builtin_bswap16(*(uint16_t*)ptr); +#elif defined(__byte_swap_word) + return __byte_swap_word(*(unsigned short*)ptr); #else -static INLINE unsigned short -peekw (const void* ptr) -{ - const unsigned char* p = ptr; - - return (p[0] << 8) + p[1]; -} + uint8_t* p = ptr; + return (p[0] << 8) + p[1]; #endif +} -#ifdef __byte_swap_long -#define peekl(p) ((unsigned long) __byte_swap_long (*(unsigned long*) (p))) +static inline ULONG peekl(codeptr ptr) { +#ifdef __BIG_ENDIAN__ + return *(ULONG*)ptr; +#elif defined(__GNUC__) + return __builtin_bswap32(*(uint32_t*)ptr); +#elif defined(__byte_swap_long) + return __byte_swap_long(*(unsigned long*)ptr); #else -static INLINE unsigned long -peekl (const void* ptr) -{ - const unsigned char* p = ptr; - - return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; -} + uint8_t* p = ptr; + return (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3]; #endif +} -#endif /* !__BIG_ENDIAN__ */ +static inline LONG extbl(UBYTE b) { return (LONG)(BYTE)b; } +static inline LONG extw(UBYTE b) { return (LONG)(UWORD)(BYTE)b; } +static inline LONG extl(UWORD w) { return (LONG)(WORD)w; } -#endif /* ETC_H */ +#endif // ETC_H diff --git a/src/eval.c b/src/eval.c new file mode 100644 index 0000000..612a626 --- /dev/null +++ b/src/eval.c @@ -0,0 +1,968 @@ +// ソースコードジェネレータ +// テーブル行構文解析・評価 +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "eval.h" + +#include +#include +#include + +#include "disasm.h" +#include "estruct.h" +#include "etc.h" +#include "fpconv.h" +#include "generate.h" +#include "hex.h" +#include "label.h" +#include "labelfile.h" +#include "offset.h" +#include "table.h" + +typedef enum { + TOKEN_ERROR = -1, + TOKEN_NUL = 0, + + TOKEN_NUMBER, + TOKEN_STRING, + + TOKEN_SIZEID, + TOKEN_FSIZEID, + TOKEN_BREAK, + TOKEN_PEEK, + TOKEN_EXT, + + TOKEN_EQUAL, + TOKEN_NOT_EQUAL, + TOKEN_LESS_OR_EQUAL, + TOKEN_GREATER_OR_EQUAL, + TOKEN_LOGICAL_OR, + TOKEN_LOGICAL_AND, + + // 1文字の演算子や括弧などは文字コードをそのまま使う + TOKEN_LESS = '<', + TOKEN_GREATER = '>', +} TokenType; + +typedef struct { + TokenType type; + ULONG value; +} Token; + +typedef struct { + char* s; + size_t length; +} StrSpan; + +typedef struct { + char* _p; + const char* _error; + const char* _idstr; + boolean _hasToken; + StrSpan _strSpan; + Token _current; + ULONG* _constValues; // {pc, tabletop} +} Tokenizer; + +typedef enum { + EXPR_ULONG, + EXPR_LABEL, + EXPR_STRING, +} ExprType; + +typedef struct { + ExprType type; + union { + ULONG ul; + StrSpan strSpan; + } value; +} Expr; + +static Expr createExprUlong(ULONG ul) { return (Expr){EXPR_ULONG, {.ul = ul}}; } +static Expr createExprLabel(ULONG ul) { return (Expr){EXPR_LABEL, {.ul = ul}}; } +static Expr createExprString(StrSpan strSpan) { + return (Expr){EXPR_STRING, {.strSpan = strSpan}}; +} + +typedef struct { + Tokenizer tokenizer; + ParseTblResult* result; + const char* error; + char* writePtr; + char* bufferEnd; + address pc; +} Parser; + +static ParseResult parseExprParenExpr(Parser* parser, Expr* result); +static ParseResult parseExpr(Parser* parser, Expr* result); +static ParseResult parseCloseBracket(Parser* parser, TokenType close); +static ParseResult parseSyntaxError(Parser* parser, const char* message); +static ParseResult parseTokenError(Parser* parser); +static ParseResult parseRuntimeError(Parser* parser, const char* message); + +static ParseResult parseSuccess(Parser* parser, opesize id, int count, + int bytes, ULONG value) { + ParseTblResult* result = parser->result; + + result->pr = PARSE_SUCCESS; + result->id = id; + result->count = count; + result->bytes = bytes; + result->value = value; + return PARSE_SUCCESS; +} + +static Tokenizer createTokenizer(char* p, ULONG* constValues); +static Token tokenError(Tokenizer* tokenizer, const char* message); +static const char* getTokenizerError(Tokenizer* tokenizer); +static Token getToken(Tokenizer* tokenizer); +static void consumeToken(Tokenizer* tokenizer); + +static StrSpan getStrSpan(Tokenizer* tokenizer) { return tokenizer->_strSpan; } +static const char* getIdStr(Tokenizer* tokenizer) { return tokenizer->_idstr; } + +// 指定したアドレスに対応する読み込んだファイル上の位置を返す +// アドレスがBBSを指していれば0埋めされたバッファを返す +static codeptr secured(address ptr) { + static const union { + SingleReal sr; + DoubleReal dr; + ExtendedReal xr; + PackedDecimal pd; + } zero; + + return (Dis.beginBSS <= ptr) ? (codeptr)&zero : (codeptr)(ptr + Dis.Ofst); +} + +static void stringifyLong(char* p, address pc) { + ULONG ul = PEEK_LONG(pc); + if (depend_address(pc)) + make_proper_symbol(p, (address)ul); + else + itox8d(p, ul); +} + +static void stringifyDataAtPc(Parser* parser, opesize size) { + address pc = parser->pc; + char* p = parser->writePtr; + + switch (size) { + default: + *p = '\0'; + break; + + case BYTESIZE: + itox2d(p, PEEK_BYTE(pc)); + break; + case WORDSIZE: + itox4d(p, PEEK_WORD(pc)); + break; + case LONGSIZE: + stringifyLong(p, pc); + break; + + case SINGLESIZE: + fpconv_s(p, secured(pc)); + break; + case DOUBLESIZE: + fpconv_d(p, secured(pc)); + break; + case EXTENDSIZE: + fpconv_x(p, secured(pc)); + break; + case PACKEDSIZE: + fpconv_p(p, secured(pc)); + break; + } +} + +static ParseResult stringTooLong(Parser* parser) { + const char* message = "オペランド表現式で生成した文字列が長すぎます。"; + return parseRuntimeError(parser, message); +} + +static ParseResult stringifyExprString(Parser* parser, Expr* expr) { + char* p = parser->writePtr; + size_t rest = parser->bufferEnd - p - 1; + + switch (expr->type) { + default: + *p = '\0'; + break; + + case EXPR_ULONG: + if (rest < 10) return stringTooLong(parser); // strlen("$xxxxxxxx") + + // 技巧的なオペランド表現式の場合、式の値が識別子のサイズより大きくなる + // こともありえるので、dc.b、dc.wでもitox2d()、itox4d()にはしない + p = itox8d(p, expr->value.ul); + break; + + case EXPR_LABEL: + if (rest < 32) return stringTooLong(parser); // 厳密な安全確認ではない + p = make_proper_symbol(p, expr->value.ul); + break; + + case EXPR_STRING: { + size_t len = expr->value.strSpan.length; + if (rest < len) return stringTooLong(parser); + + memcpy(p, expr->value.strSpan.s, len); + p += len; + *p = '\0'; + break; + } + } + parser->writePtr = p; + return PARSE_SUCCESS; +} + +static ParseResult parseStrOrExp(Parser* parser, Expr* result) { + ParseResult pr; + Token token = getToken(&parser->tokenizer); + if (token.type == TOKEN_ERROR) return parseTokenError(parser); + + if (token.type == TOKEN_STRING) { + *result = createExprString(getStrSpan(&parser->tokenizer)); + consumeToken(&parser->tokenizer); + return PARSE_SUCCESS; + } + + if (token.type == '{') { + Expr expr; + consumeToken(&parser->tokenizer); + pr = parseExpr(parser, &expr); + if (pr == PARSE_SUCCESS) pr = parseCloseBracket(parser, '}'); + + if (pr == PARSE_SUCCESS) { + if (expr.type != EXPR_ULONG) + internalError(__FILE__, __LINE__, "type != EXPR_ULONG."); + + if (parser->writePtr == NULL) { + // 解析中ならラベル登録 + // テーブルでないと判定された場合に取り消す処理を追加したほうがよいかも + regist_label((address)expr.value.ul, DATLABEL | UNKNOWN); + } + *result = createExprLabel(expr.value.ul); + } + return pr; + } + + pr = parseExpr(parser, result); + if (pr == PARSE_SUCCESS) { + if (result->type != EXPR_ULONG) + internalError(__FILE__, __LINE__, "type != EXPR_ULONG."); + } + return pr; +} + +static ParseResult parseExprString(Parser* parser) { + while (1) { + TokenType type; + Expr expr; + ParseResult pr = parseStrOrExp(parser, &expr); + if (pr != PARSE_SUCCESS) return pr; + + if (parser->writePtr != NULL) { + pr = stringifyExprString(parser, &expr); + if (pr != PARSE_SUCCESS) return pr; + } + + type = getToken(&parser->tokenizer).type; + if (type == TOKEN_ERROR) return parseTokenError(parser); + if (type == TOKEN_NUL) return PARSE_SUCCESS; + if (type == ',') { + consumeToken(&parser->tokenizer); + continue; + } + return parseSyntaxError(parser, + "オペランド表現式が\",\"で区切られていません。"); + } +} + +static void peek_warning(address adrs, int size) { + if (isOdd(adrs)) { + eprintf("警告: peek.%cの引数が奇数アドレス(" PRI_ADRS ")です。\n", size, + adrs); + } +} + +static ULONG peek(address adrs, opesize size) { + switch (size) { + default: + break; + + case BYTESIZE: + return PEEK_BYTE(adrs); + case WORDSIZE: + peek_warning(adrs, 'w'); + return PEEK_WORD(adrs); + case LONGSIZE: + peek_warning(adrs, 'l'); + return PEEK_LONG(adrs); + } + + return 0; +} + +static ULONG evalFunc(Token token, ULONG ul) { + opesize size = token.value; + + if (token.type == TOKEN_PEEK) { + return peek((address)ul, size); + } + + // TOKEN_EXT + return (size == WORDSIZE) ? extw(ul) : extl(ul); +} + +static ParseResult parseExprElement(Parser* parser, Expr* result) { + Token token = getToken(&parser->tokenizer); + TokenType type = token.type; + if (type == TOKEN_ERROR) return parseTokenError(parser); + if (type == TOKEN_NUL) return parseSyntaxError(parser, "式がありません。"); + if (type == TOKEN_STRING) + return parseSyntaxError(parser, "式に文字列は使えません。"); + + if (type == TOKEN_NUMBER) { + consumeToken(&parser->tokenizer); + *result = createExprUlong(token.value); + return PARSE_SUCCESS; + } + + if (type == '(') { + // ここではconsumeToken()は呼ばない + return parseExprParenExpr(parser, result); + } + + if (type == TOKEN_PEEK || type == TOKEN_EXT) { + ParseResult pr; + + consumeToken(&parser->tokenizer); + pr = parseExprParenExpr(parser, result); + if (pr == PARSE_SUCCESS) { + result->value.ul = evalFunc(token, result->value.ul); + } + return pr; + } + + return parseSyntaxError(parser, "式として解釈できません。"); +} + +static ParseResult parseExprParenExpr(Parser* parser, Expr* result) { + ParseResult pr; + TokenType type = getToken(&parser->tokenizer).type; + if (type == TOKEN_ERROR) return parseTokenError(parser); + + // 関数呼び出しではない"(式)"の場合は呼び出し元で"("を確認しているので + // ここでエラーになることはない + if (type != '(') + return parseSyntaxError(parser, "関数名の直後に\"(\"がありません。"); + consumeToken(&parser->tokenizer); + + pr = parseExpr(parser, result); + if (pr == PARSE_SUCCESS) pr = parseCloseBracket(parser, ')'); + if (pr != PARSE_SUCCESS) return pr; + + return PARSE_SUCCESS; +} + +static ULONG neg(ULONG ul) { + LONG l = (LONG)ul; + return (ULONG)-l; +} + +static ParseResult parseExprFactor(Parser* parser, Expr* result) { + ParseResult pr; + TokenType type = getToken(&parser->tokenizer).type; + + if (type == '-' || type == '!') { + consumeToken(&parser->tokenizer); + + pr = parseExprFactor(parser, result); + if (pr == PARSE_SUCCESS) + result->value.ul = + (type == '-') ? neg(result->value.ul) : !result->value.ul; + return pr; + } + + return parseExprElement(parser, result); +} + +static ParseResult parseExprMul(Parser* parser, Expr* result) { + ParseResult pr = parseExprFactor(parser, result); + if (pr != PARSE_SUCCESS) return pr; + + while (1) { + Expr expr2; + TokenType type = getToken(&parser->tokenizer).type; + + if (type != '*' && type != '/' && type != '%') return PARSE_SUCCESS; + consumeToken(&parser->tokenizer); + + pr = parseExprFactor(parser, &expr2); + if (pr != PARSE_SUCCESS) return pr; + + if (type == '*') { + result->value.ul = (result->value.ul * expr2.value.ul); + } else { + ULONG divisor = expr2.value.ul; + if (divisor == 0) return parseRuntimeError(parser, "0で除算しました。"); + + result->value.ul = (type == '/') ? (result->value.ul / divisor) + : (result->value.ul % divisor); + } + } +} + +static ParseResult parseExprAdditive(Parser* parser, Expr* result) { + ParseResult pr = parseExprMul(parser, result); + if (pr != PARSE_SUCCESS) return pr; + + while (1) { + Expr expr2; + TokenType type = getToken(&parser->tokenizer).type; + + if (type != '+' && type != '-') return PARSE_SUCCESS; + consumeToken(&parser->tokenizer); + + pr = parseExprMul(parser, &expr2); + if (pr != PARSE_SUCCESS) return pr; + + result->value.ul = (type == '+') ? (result->value.ul + expr2.value.ul) + : (result->value.ul - expr2.value.ul); + } +} + +static ParseResult parseExprRelational(Parser* parser, Expr* result) { + ParseResult pr = parseExprAdditive(parser, result); + if (pr != PARSE_SUCCESS) return pr; + + while (1) { + Expr expr2; + TokenType type = getToken(&parser->tokenizer).type; + + if (type != TOKEN_LESS_OR_EQUAL && type != '<' && + type != TOKEN_GREATER_OR_EQUAL && type != '>') + return PARSE_SUCCESS; + consumeToken(&parser->tokenizer); + + pr = parseExprAdditive(parser, &expr2); + if (pr != PARSE_SUCCESS) return pr; + + switch (type) { + default: + break; + + case TOKEN_LESS_OR_EQUAL: + result->value.ul = (result->value.ul <= expr2.value.ul); + break; + case '<': + result->value.ul = (result->value.ul < expr2.value.ul); + break; + case TOKEN_GREATER_OR_EQUAL: + result->value.ul = (result->value.ul >= expr2.value.ul); + break; + case '>': + result->value.ul = (result->value.ul > expr2.value.ul); + break; + } + } +} + +static ParseResult parseExprEquality(Parser* parser, Expr* result) { + ParseResult pr = parseExprRelational(parser, result); + if (pr != PARSE_SUCCESS) return pr; + + while (1) { + Expr expr2; + TokenType type = getToken(&parser->tokenizer).type; + + if (type != TOKEN_EQUAL && type != TOKEN_NOT_EQUAL) return PARSE_SUCCESS; + consumeToken(&parser->tokenizer); + + pr = parseExprRelational(parser, &expr2); + if (pr != PARSE_SUCCESS) return pr; + + result->value.ul = (type == TOKEN_EQUAL) + ? (result->value.ul == expr2.value.ul) + : (result->value.ul != expr2.value.ul); + } +} + +static ParseResult parseExpr(Parser* parser, Expr* result) { + ParseResult pr = parseExprEquality(parser, result); + if (pr != PARSE_SUCCESS) return pr; + + while (1) { + Expr expr2; + TokenType type = getToken(&parser->tokenizer).type; + + if (type != TOKEN_LOGICAL_OR && type != TOKEN_LOGICAL_AND) + return PARSE_SUCCESS; + consumeToken(&parser->tokenizer); + + pr = parseExprEquality(parser, &expr2); + if (pr != PARSE_SUCCESS) return pr; + + result->value.ul = (type == TOKEN_LOGICAL_OR) + ? (result->value.ul || expr2.value.ul) + : (result->value.ul && expr2.value.ul); + } +} + +// ASCIIZ 形式データのサイズ(文字列+"\0"のバイト数)を調べる +static int getAsciizLength(Parser* parser) { + address pc = parser->pc; // BSSの可能性あり(途中からの場合も) + UBYTE c; + + do { + c = PEEK_BYTE(pc); + pc += 1; + } while (c); + + return (int)(pc - parser->pc); +} + +static int opesizeToBytes(opesize size) { + static const uint8_t bytes[] = { + 1, // BYTESIZE + 2, // WORDSIZE + 4, // LONGSIZE + 8, // QUADSIZE, + 0, // SHORTSIZE + 4, // SINGLESIZE + 8, // DOUBLESIZE + 12, // EXTENDSIZE + 12, // PACKEDSIZE + }; + return (size < _countof(bytes)) ? bytes[size] : 0; +} + +static ParseResult evaluateSizeid(Parser* parser, opesize size, int count) { + int bytes = 0; + ULONG value = 0; + + switch (size) { + default: + break; + + case BYTESIZE: + case WORDSIZE: + case LONGSIZE: + case SINGLESIZE: + case DOUBLESIZE: + case EXTENDSIZE: + case PACKEDSIZE: + bytes = opesizeToBytes(size); + break; + + case EVENID: + bytes = parser->pc & 1; + if (bytes) value = PEEK_BYTE(parser->pc); + break; + + case CRID: + break; + + case BYTEID: + case ASCIIID: + bytes = count; // [n]がバイト数の指定になる + count = 1; // 繰り返し回数は1回に固定 + break; + case ASCIIZID: + bytes = getAsciizLength(parser); + break; + case LASCIIID: + bytes = (int)PEEK_BYTE(parser->pc) + 1; + break; + } + + return parseSuccess(parser, size, count, bytes, value); +} + +static ParseResult parseSizeid(Parser* parser, Token idToken) { + ParseResult pr; + opesize id = idToken.value; + int count = 1; //[]省略時は繰り返し回数=1 + + TokenType type = getToken(&parser->tokenizer).type; + + if (type == '[') { + Expr expr; + consumeToken(&parser->tokenizer); + + pr = parseExpr(parser, &expr); + if (pr != PARSE_SUCCESS) return pr; + + if (expr.type != EXPR_ULONG) + return parseSyntaxError(parser, + "識別子の\"[]\"内には値以外は指定できません。"); + + pr = parseCloseBracket(parser, ']'); + if (pr != PARSE_SUCCESS) return pr; + + count = expr.value.ul; + type = getToken(&parser->tokenizer).type; + } + + if (type == TOKEN_NUL) { + // オペランド表現式がなければPCの値を出力する + if (parser->writePtr != NULL) { + stringifyDataAtPc(parser, id); + } + } else { + // オペランド表現式があれば評価して文字列化 + if (idToken.type == TOKEN_FSIZEID) { + return parseSyntaxError( + parser, "識別子dc.[sdxp]にはオペランド表現式を指定できません。"); + } + pr = parseExprString(parser); + if (pr != PARSE_SUCCESS) return pr; + } + + return evaluateSizeid(parser, id, count); +} + +static const char* getNoCloseBracketMessage(TokenType type) { + if (type == ']') return "\"[\"に対応する\"]\"がありません。"; + if (type == ')') return "\"(\"に対応する\")\"がありません。"; + return "\"{\"に対応する\"}\"がありません。"; +} + +static ParseResult parseCloseBracket(Parser* parser, TokenType close) { + TokenType type = getToken(&parser->tokenizer).type; + if (type == TOKEN_ERROR) return parseTokenError(parser); + + if (type != close) + return parseSyntaxError(parser, getNoCloseBracketMessage(close)); + + consumeToken(&parser->tokenizer); + return PARSE_SUCCESS; +} + +static ParseResult parseBreak(Parser* parser) { + Expr expr; + ParseResult pr = parseExpr(parser, &expr); + if (pr != PARSE_SUCCESS) return pr; + + return parseSuccess(parser, BREAKID, 1, 0, expr.value.ul); +} + +static Parser createParser(ParseTblParam* param, ParseTblResult* result) { + Tokenizer tokenizer = createTokenizer(param->text, param->constValues); + return (Parser){ + tokenizer, + result, + NULL, + param->buffer, + param->buffer + param->bufLen, + param->constValues[PARSE_CONST_PC] // + }; +} + +// テーブル内の1行を解析、実行する +ParseResult parseTableLine(ParseTblParam* param, ParseTblResult* result) { + Parser parser = createParser(param, result); + Token token; + + *result = (ParseTblResult){PARSE_SUCCESS, 0, NULL, NULL, 0, 0, 0}; + + token = getToken(&parser.tokenizer); + if (token.type == TOKEN_ERROR) return parseTokenError(&parser); + + switch (token.type) { + default: + return parseSyntaxError(&parser, "行の先頭には識別子が必要です。"); + + case TOKEN_NUL: + break; + + case TOKEN_SIZEID: + case TOKEN_FSIZEID: + result->idstr = getIdStr(&parser.tokenizer); + consumeToken(&parser.tokenizer); + return parseSizeid(&parser, token); + + case TOKEN_BREAK: + consumeToken(&parser.tokenizer); + return parseBreak(&parser); + } + + // 空行の場合 + return parseSyntaxError(&parser, "識別子がありません。"); +} + +static ParseResult parseError(Parser* parser, ParseResult pr, + const char* message) { + ParseTblResult* result = parser->result; + + result->pr = pr; + result->error = message; + return pr; +} + +static ParseResult parseSyntaxError(Parser* parser, const char* message) { + return parseError(parser, PARSE_SYNTAX_ERROR, message); +} + +static ParseResult parseTokenError(Parser* parser) { + const char* message = getTokenizerError(&parser->tokenizer); + return parseError(parser, PARSE_SYNTAX_ERROR, message); +} + +static ParseResult parseRuntimeError(Parser* parser, const char* message) { + return parseError(parser, PARSE_RUNTIME_ERROR, message); +} + +// トークナイザを初期化する +static Tokenizer createTokenizer(char* p, ULONG* constValues) { + Token token = {TOKEN_ERROR, 0}; + Tokenizer tokenizer = {p, NULL, NULL, FALSE, {NULL, 0}, token, constValues}; + + return tokenizer; +} + +typedef struct { + uint8_t length; + char str[13]; + uint8_t type; // TokenType + uint8_t size; // opesize +} Keyword; + +static const Keyword keywords[] = { + {2, "pc", TOKEN_NUMBER, PARSE_CONST_PC}, // + {8, "tabletop", TOKEN_NUMBER, PARSE_CONST_TABLETOP}, // + + {5, ".dc.b", TOKEN_SIZEID, BYTESIZE}, // + {5, ".dc.w", TOKEN_SIZEID, WORDSIZE}, // + {5, ".dc.l", TOKEN_SIZEID, LONGSIZE}, // + {3, ".dc", TOKEN_SIZEID, WORDSIZE}, // + {5, ".byte", TOKEN_SIZEID, BYTEID}, // + {5, ".even", TOKEN_SIZEID, EVENID}, // + + {6, ".break", TOKEN_BREAK, 0}, // + + {6, "peek.b", TOKEN_PEEK, BYTESIZE}, // + {6, "peek.w", TOKEN_PEEK, WORDSIZE}, // + {6, "peek.l", TOKEN_PEEK, LONGSIZE}, // + {5, "ext.w", TOKEN_EXT, WORDSIZE}, // + {5, "ext.l", TOKEN_EXT, LONGSIZE}, // + + {3, ".cr", TOKEN_SIZEID, CRID}, // + {6, ".ascii", TOKEN_SIZEID, ASCIIID}, // + {6, ".asciz", TOKEN_SIZEID, ASCIIZID}, // + {7, ".asciiz", TOKEN_SIZEID, ASCIIZID}, // + {7, ".lascii", TOKEN_SIZEID, LASCIIID}, // + + {5, ".dc.s", TOKEN_FSIZEID, SINGLESIZE}, // + {5, ".dc.d", TOKEN_FSIZEID, DOUBLESIZE}, // + {5, ".dc.x", TOKEN_FSIZEID, EXTENDSIZE}, // + {5, ".dc.p", TOKEN_FSIZEID, PACKEDSIZE}, // + +}; + +static Token getTokenId(Tokenizer* tokenizer, StrSpan span) { + const size_t kwLength = _countof(keywords); + const char dot = (span.s[0] != '.') ? '.' : '\0'; + size_t i; + + for (i = 0; i < kwLength; ++i) { + const Keyword* kw = &keywords[i]; + size_t len = kw->length; + const char* t = kw->str; + + if (t[0] == dot) { + // 入力がドットなし、比較キーワードがドット付きなら、ドットは除外する + t += 1; + len -= 1; + } + if (span.length == len && strncasecmp(span.s, t, len) == 0) { + ULONG value = kw->size; + + // pc、tabletopを現時点の値にする + if (kw->type == TOKEN_NUMBER) value = tokenizer->_constValues[value]; + + tokenizer->_idstr = t; + return (Token){kw->type, value}; + } + } + + return (Token){TOKEN_ERROR, 0}; +} + +static StrSpan getKeywordSpan(char first, char* s) { + const char* p = s; + char c; + + if (isalpha(first) || first == '.') { + while (isalnum(c = *p++) || c == '.') + ; + } + return (StrSpan){s - 1, p - s}; +} + +// キーワード形式のトークン(識別子、定数、関数) +static Token fetchTokenKeyword(Tokenizer* tokenizer, char first) { + StrSpan span = getKeywordSpan(first, tokenizer->_p); + + Token token = getTokenId(tokenizer, span); + if (token.type != TOKEN_ERROR) tokenizer->_p += span.length - 1; + return token; +} + +static Token fetchTokenHex(Tokenizer* tokenizer, int zero_x) { + char* p = tokenizer->_p; + ULONG n = 0; + + p += zero_x; + if (!isxdigit(*p)) { + const char* e = zero_x ? "\"0x\"の後に16進数がありません。" + : "\"$\"の後に16進数がありません。"; + return tokenError(tokenizer, e); + } + + do { + char c = *p++; + c = toupper(c); + n = (n << 4) + (c >= 'A' ? c - 'A' + 10 : c - '0'); + } while (isxdigit(*p)); + tokenizer->_p = p; + + return (Token){TOKEN_NUMBER, n}; +} + +static Token fetchTokenDecimal(Tokenizer* tokenizer, char first) { + char* p = tokenizer->_p; + ULONG n = first - '0'; + + while (isdigit(*p)) { + n = n * 10 + (*p++ - '0'); + } + tokenizer->_p = p; + + return (Token){TOKEN_NUMBER, n}; +} + +static Token fetchTokenString(Tokenizer* tokenizer) { + char* term = strchr(tokenizer->_p, '"'); + + if (term == NULL) + return tokenError(tokenizer, "文字列が'\"'で閉じていません。"); + + // 構文仕様上、複数の文字列を同時に保持する必要はないので + // 情報は Tokenizer 内に一つだけ置く + tokenizer->_strSpan = (StrSpan){tokenizer->_p, term - tokenizer->_p}; + + tokenizer->_p = term + 1; + return (Token){TOKEN_STRING, 0}; +} + +static Token fetchToken(Tokenizer* tokenizer) { + char c, c2; + tokenizer->_error = NULL; + + while ((c = *tokenizer->_p++) == ' ' || c == '\t' || c == '\n') + ; + if (c == '\0') { + tokenizer->_p -= 1; + return (Token){TOKEN_NUL, 0}; + } + c2 = *tokenizer->_p; + + // c -> 文字列の先頭の文字 + // c2 -> 2文字目。tokenizer->_p はこの文字のアドレスを指している + + // 16進数リテラル + if (c == '$') return fetchTokenHex(tokenizer, 0); + if (c == '0' && tolower(c2) == 'x') return fetchTokenHex(tokenizer, 1); + + // 10進数リテラル + if (isdigit(c)) return fetchTokenDecimal(tokenizer, c); + + // 文字列リテラル + if (c == '"') return fetchTokenString(tokenizer); + + // 記号2文字の演算子 + if (c == '!' && c2 == '=') { + tokenizer->_p += 1; + return (Token){TOKEN_NOT_EQUAL, 0}; + } + if (c == '<' && c2 == '=') { + tokenizer->_p += 1; + return (Token){TOKEN_LESS_OR_EQUAL, 0}; + } + if (c == '>' && c2 == '=') { + tokenizer->_p += 1; + return (Token){TOKEN_GREATER_OR_EQUAL, 0}; + } + + if (c == '=') { + if (c2 != c) return tokenError(tokenizer, "\"=\"演算子は使えません。"); + tokenizer->_p += 1; + return (Token){TOKEN_EQUAL, 0}; + } + if (c == '&') { + if (c2 != c) return tokenError(tokenizer, "\"&\"演算子は使えません。"); + tokenizer->_p += 1; + return (Token){TOKEN_LOGICAL_AND, 0}; + } + if (c == '|') { + if (c2 != c) return tokenError(tokenizer, "\"|\"演算子は使えません。"); + tokenizer->_p += 1; + return (Token){TOKEN_LOGICAL_OR, 0}; + } + + // 記号1文字の演算子 + if (strchr("!%()*+,-/<>[]{}", c) != NULL) return (Token){c, 0}; + + // 識別子、定数、関数 + { + Token token = fetchTokenKeyword(tokenizer, c); + if (token.type != TOKEN_ERROR) return token; + } + + return tokenError(tokenizer, "トークンとして解釈できません。"); +} + +static Token tokenError(Tokenizer* tokenizer, const char* message) { + tokenizer->_error = message; + return (Token){TOKEN_ERROR, 0}; +} + +static const char* getTokenizerError(Tokenizer* tokenizer) { + return tokenizer->_error; +} + +// 字句解析してトークンを返す +// トークンは内部に保持して次のgetToken()でも同じものを返す。 +// 取得したトークンが不要になったらconsumeToken()を呼び出すこと。 +static Token getToken(Tokenizer* tokenizer) { + if (tokenizer->_hasToken == FALSE) { + tokenizer->_hasToken = TRUE; + tokenizer->_current = fetchToken(tokenizer); + } + return tokenizer->_current; +} + +// 内部に保持しているトークンを消費済みとする(消去する)。 +static void consumeToken(Tokenizer* tokenizer) { tokenizer->_hasToken = FALSE; } + +// EOF diff --git a/src/eval.h b/src/eval.h new file mode 100644 index 0000000..db71e64 --- /dev/null +++ b/src/eval.h @@ -0,0 +1,59 @@ +// ソースコードジェネレータ +// テーブル行構文解析・評価 ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef EVAL_H +#define EVAL_H + +#include "estruct.h" + +enum { + PARSE_CONST_PC, + PARSE_CONST_TABLETOP, + + PARSE_CONST_NUM +}; + +typedef struct { + char* text; + char* buffer; + int bufLen; + ULONG constValues[PARSE_CONST_NUM]; +} ParseTblParam; + +typedef enum { + PARSE_SUCCESS = 0, + PARSE_SYNTAX_ERROR = 1, + PARSE_RUNTIME_ERROR, +} ParseResult; + +typedef struct { + ParseResult pr; + opesize id; + const char* idstr; + const char* error; + ULONG count; + int bytes; + ULONG value; // 多目的データ受け渡し用 +} ParseTblResult; + +extern ParseResult parseTableLine(ParseTblParam* param, ParseTblResult* result); + +#endif + +// EOF diff --git a/src/eval.y b/src/eval.y deleted file mode 100644 index 2e99977..0000000 --- a/src/eval.y +++ /dev/null @@ -1,603 +0,0 @@ -/* $Id: eval.y,v 1.1 1994/07/09 19:54:20 ryo Exp $ - * - * ソースコードジェネレータ - * ラベルファイルパーサ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -%{ -#include -#include -#include -#include - -#include "disasm.h" -#include "estruct.h" -#include "etc.h" -#include "fpconv.h" -#include "generate.h" /* symset */ -#include "global.h" -#include "hex.h" /* strend */ -#include "label.h" -#include "labelfile.h" -#include "offset.h" /* depend_address */ -#include "table.h" - - -/* -#define YYDEBUG 1 -*/ -#ifdef SELF -extern int yydebug; -#endif - -parse_mode ParseMode; -char* Lexptr; -int Eval_Value; -address Eval_TableTop; -opesize Eval_ID; -address Eval_PC; -int Eval_Bytes; -char Eval_ResultString[256]; -int Eval_Break; -int Eval_Count; - -typedef struct { - boolean isvalue; - boolean registed; - address value; - char* bufptr; -} expbuf; - -static int yylex (void); -static void yyerror (char*); -static void tabledesc (int, opesize); -static unsigned long peek (address, opesize); -static unsigned long extend (unsigned long, opesize); -static expbuf* storestr (char*); -static expbuf* storeexp (address, int); -static expbuf* store (expbuf*); -static void breakjob (unsigned long); -static void itoxd_by_size (char*, ULONG, opesize); - - -#define EXPSTACKSIZE 32 -static expbuf* ExpStack[EXPSTACKSIZE]; -static int ExpStackCounter = 0; - - -%} - -/* - - Begin Grammer - -*/ -%union { - unsigned long val; - char* str; - expbuf* exp; -} -%token _STRING -%token SIZEID FSIZEID -%token NUMBER -%token PEEKB PEEKW PEEKL BREAK EXTW EXTL -%type str_or_exp /* exprstring */ -%type sizeid fsizeid -%type tabledesc -%type expr logical_AND_expr equality_expr relational_expr -%type additive_expr mul_expr factor element -%left '<' LE '>' GE EQUEQU NOTEQU -%left '(' ')' '{' '}' -%left ',' -%left OROR -%left ANDAND -%left '+' '-' -%left '*' '/' -%left '!' -%left UNARYMINUS - -%% - -tabledesc : BREAK expr { breakjob ($2); } - | sizeid { tabledesc ( 1, $1); } - | sizeid '[' expr ']' { tabledesc ($3, $1); } - | sizeid exprstring { tabledesc ( 1, $1); } - | sizeid '[' expr ']' exprstring { tabledesc ($3, $1); } - | fsizeid { tabledesc ( 1, $1); } - | fsizeid '[' expr ']' { tabledesc ($3, $1); } - ; - -sizeid : SIZEID { $$ = $1; } - | '@' SIZEID { $$ = $2; } - ; - -fsizeid : FSIZEID { $$ = $1; } - | '@' FSIZEID { $$ = $2; } - ; - -exprstring : str_or_exp { store ($1); } - | exprstring ',' str_or_exp { store ($3); } - ; - -str_or_exp : _STRING { $$ = storestr ($1); } - | expr { $$ = storeexp ((address) $1, 0); } - | '{' expr '}' { $$ = storeexp ((address) $2, 1); } - ; - -expr : logical_AND_expr { $$ = $1; } - | expr OROR logical_AND_expr { $$ = $1 || $3; } - ; - -logical_AND_expr : equality_expr { $$ = $1; } - | logical_AND_expr ANDAND equality_expr { $$ = $1 && $3; } - ; - -equality_expr : relational_expr { $$ = $1; } - | equality_expr EQUEQU relational_expr { $$ = ($1 == $3); } - | equality_expr NOTEQU relational_expr { $$ = ($1 != $3); } - ; - -relational_expr : additive_expr { $$ = $1; } - | relational_expr '<' additive_expr { $$ = ($1 < $3); } - | relational_expr LE additive_expr { $$ = ($1 <= $3); } - | relational_expr '>' additive_expr { $$ = ($1 > $3); } - | relational_expr GE additive_expr { $$ = ($1 >= $3); } - ; - -additive_expr : mul_expr { $$ = $1; } - | additive_expr '+' mul_expr { $$ = $1 + $3; } - | additive_expr '-' mul_expr { $$ = $1 - $3; } - ; - -mul_expr : factor { $$ = $1; } - | mul_expr '*' factor { $$ = $1 * $3; } - | mul_expr '/' factor { $$ = $1 / $3; } - | mul_expr '%' factor { $$ = $1 % $3; } - ; - -factor : '-' factor %prec UNARYMINUS { $$ = - $2; } - | '!' factor { $$ = ! $2; } - | element { $$ = $1; } - ; - -element : '(' expr ')' { $$ = $2; } - | NUMBER { $$ = $1; } - | PEEKB '(' expr ')' { $$ = peek ((address) $3, BYTESIZE); } - | PEEKW '(' expr ')' { $$ = peek ((address) $3, WORDSIZE); } - | PEEKL '(' expr ')' { $$ = peek ((address) $3, LONGSIZE); } - | EXTW '(' expr ')' { $$ = extend ((unsigned) $3, WORDSIZE); } - | EXTL '(' expr ')' { $$ = extend ((unsigned) $3, LONGSIZE); } - ; -%% - -/* - - End of Grammer - -*/ - -static int -get_token_id (const char* token) -{ - - /* SIZEID, FSIZEID */ - { - struct idpair { - char idstr[8]; - int idnum; - } idbuf[] = { - { "dc.b" , BYTESIZE }, - { "dc.w" , WORDSIZE }, - { "dc.l" , LONGSIZE }, - { "dc" , WORDSIZE }, - { "byte" , BYTEID }, - { "even" , EVENID }, - { "cr" , CRID }, - { "asciz" , ASCIIZID }, - { "asciiz", ASCIIZID }, - { "ascii" , ASCIIID }, - { "lascii", LASCIIID }, -#if 0 - { "long" , LONGID }, - { "word" , WORDID }, -#endif - { "dc.s" , SINGLESIZE }, - { "dc.d" , DOUBLESIZE }, - { "dc.x" , EXTENDSIZE }, - { "dc.p" , PACKEDSIZE }, - { "" , 0 } /* end of list */ - }; - struct idpair* idptr; - const char* t = token; - - if (*t == (char)'.') - t++; /* 先頭のピリオドは無視 */ - for (idptr = idbuf; idptr->idstr[0]; idptr++) { - if (strcasecmp (t, idptr->idstr) == 0) { - yylval.val = (unsigned long) idptr->idnum; - return (SINGLESIZE <= idptr->idnum) ? FSIZEID : SIZEID; - } - } - } - - /* NUMBER */ - if (strcasecmp (token, "tabletop") == 0) { - yylval.val = (unsigned long) Eval_TableTop; - return NUMBER; - } - if (strcasecmp (token, "pc") == 0) { - yylval.val = (unsigned long) Eval_PC; - return NUMBER; - } - - /* BREAK, PEEK*, EXT* */ - if (strcasecmp (token, "break") == 0) return BREAK; - if (strcasecmp (token, "peek.b") == 0) return PEEKB; - if (strcasecmp (token, "peek.w") == 0) return PEEKW; - if (strcasecmp (token, "peek.l") == 0) return PEEKL; - if (strcasecmp (token, "ext.w") == 0) return EXTW; - if (strcasecmp (token, "ext.l") == 0) return EXTL; - - /* トークンではなかった */ - return -1; -} - - -static int -yylex (void) -{ - unsigned char c; - - while ((c = *Lexptr++) == ' ' || c == '\t' || c == '\n') - ; - if (c == '\0') - return 0; - - /* 16 進数 */ - if (c == '$' || (c == '0' && (char) tolower (*(unsigned char*)Lexptr) == 'x')) { - char* p; - - if (c == '0') - Lexptr++; - p = Lexptr; - yylval.val = 0; - while ((c = *Lexptr++), isxdigit (c)) - yylval.val = (yylval.val << 4) - + (toupper (c) >= 'A' ? toupper (c) - 'A' + 10 : c - '0'); - return (--Lexptr == p) ? 1 : NUMBER; - } - /* 10 進数 */ - else if (isdigit (c)) { - yylval.val = c - '0'; - while ((c = *Lexptr++), isdigit (c)) - yylval.val = yylval.val * 10 + c - '0'; - Lexptr--; - return NUMBER; - } - - if (c == '"') { - char* term; - - if ((term = strchr (Lexptr, '"')) == NULL) - return 1; - yylval.str = Malloc (term - Lexptr + 1); - strncpy (yylval.str, Lexptr, term - Lexptr); - yylval.str[term - Lexptr] = '\0'; - Lexptr = term + 1; - return _STRING; - } - if (c == '<') { - if (*Lexptr == '=') { - Lexptr++; - return LE; - } - return c; - } - if (c == '>') { - if (*Lexptr == '=') { - Lexptr++; - return GE; - } - return c; - } - if (c == '|') { - if (*Lexptr == '|') { - Lexptr++; - return OROR; - } - return c; - } - if (c == '&') { - if (*Lexptr == '&') { - Lexptr++; - return ANDAND; - } - return c; - } - if (c == '=') { - if (*Lexptr == '=') { - Lexptr++; - return EQUEQU; - } - return c; - } - if (c == '!') { - if (*Lexptr == '=') { - Lexptr++; - return NOTEQU; - } - return c; - } - - if (isalpha (c) || c == '.') { - char* token = --Lexptr; - unsigned char c; - char next; - int ret; - - while ((c = *Lexptr++), isalnum (c) || c == '.') - ; - next = *--Lexptr; - *Lexptr = '\0'; /* トークンを切り出す */ - ret = get_token_id (token); - *Lexptr = next; - - if (ret >= 0) - return ret; - - /* トークンではなかった */ - Lexptr = token + 1; - } - - return c; -} - - -static void -yyerror (char* s) -{ - eprintf ("%s\n", s); -} - - -static void -fpconv_by_size (char* buf, address ptr, opesize size) -{ - unsigned long val[3]; - - val[0] = PEEK_LONG (ptr); - if (size == SINGLESIZE) { - fpconv_s (buf, (float*) (void*) &val); - return; - } - - ptr += 4; - val[1] = PEEK_LONG (ptr); - if (size == DOUBLESIZE) { - fpconv_d (buf, (double*) (void*) &val); - return; - } - - ptr += 4; - val[2] = PEEK_LONG (ptr); - if (size == EXTENDSIZE) - fpconv_x (buf, (long double*) (void*) &val); - else /* if (size == PACKEDSIZE) */ - fpconv_p (buf, (packed_decimal*) &val); -} - - -static void -tabledesc (int num, opesize id) -{ - int i; - - Eval_ID = id; - if (Eval_Count == 0) { /* easy trick ? */ - if (id == ASCIIID || id == BYTEID -#if 0 - || id == WORDID || id == LONGID -#endif - ) { - Eval_Count = 1; - Eval_Bytes = num; - } else - Eval_Count = num; - } - - - if (ExpStackCounter == 0 && ParseMode == PARSE_GENERATING) { - char* bufptr = strend (Eval_ResultString); - - switch (id) { - case LONGSIZE: - if (depend_address (Eval_PC)) - make_proper_symbol (bufptr, (address) PEEK_LONG (Eval_PC)); - else - itoxd_by_size (bufptr, PEEK_LONG (Eval_PC), id); - break; - case WORDSIZE: - itoxd_by_size (bufptr, PEEK_WORD (Eval_PC), id); - break; - case BYTESIZE: - itoxd_by_size (bufptr, PEEK_BYTE (Eval_PC), id); - break; - - case SINGLESIZE: - case DOUBLESIZE: - case EXTENDSIZE: - case PACKEDSIZE: - fpconv_by_size (bufptr, Eval_PC, id); - break; - - default: /* reduce warning message */ - break; - } - } - for (i = 0; i < ExpStackCounter; i++) { - switch (ParseMode) { - case PARSE_ANALYZING: - if (ExpStack[i]->isvalue == FALSE) - free (ExpStack[i]->bufptr); /* 文字列バッファを解放 */ - free (ExpStack[i]); - break; - case PARSE_GENERATING: - if (ExpStack[i]->isvalue) { - char* bufptr = strend (Eval_ResultString); - address val = ExpStack[i]->value; - - if (ExpStack[i]->registed) - make_proper_symbol (bufptr, val); - else - itoxd_by_size (bufptr, (ULONG) val, Eval_ID); - } else { - strcat (Eval_ResultString, ExpStack[i]->bufptr); - free (ExpStack[i]->bufptr); - } - free (ExpStack[i]); - break; - } - } - ExpStackCounter = 0; -} - - -static expbuf* -storestr (char* s) -{ - expbuf* exp = Malloc (sizeof (expbuf)); - - exp->bufptr = s; - exp->isvalue = FALSE; - - return exp; -} - - -static expbuf* -storeexp (address v, int mode) -{ - expbuf* exp = Malloc (sizeof (expbuf)); - - exp->value = v; - exp->isvalue = TRUE; - - if (mode == 1) { - exp->registed = TRUE; - if (ParseMode == PARSE_ANALYZING - && !regist_label (v, DATLABEL | UNKNOWN)) - printf ("??? address %x\n", (unsigned int) v); - } else - exp->registed = FALSE; - - return exp; -} - - -static expbuf* -store (expbuf* exp) -{ - -#if 0 /* debug */ - if (exp->isvalue == TRUE) - printf ("値 = %d\n", exp->value); - else - printf ("文字列 = %s\n", exp->bufptr); -#endif - - if (ExpStackCounter == EXPSTACKSIZE) - err ("式評価スタックがあふれました\n"); - ExpStack[ExpStackCounter++] = exp; - - return exp; -} - - -static void -itoxd_by_size (char* buf, ULONG n, opesize size) -{ - itoxd (buf, n, (size == LONGSIZE) ? 8 : - (size == WORDSIZE) ? 4 : 2); -} - - -static void -peek_warning (address adrs, int size) -{ - if ((int)adrs & 1) - eprintf ("Warning: peek.%c の引数が奇数アドレス(%x)です\n", size, adrs); -} - -static unsigned long -peek (address adrs, opesize size) -{ - unsigned long rc; - - switch (size) { - case BYTESIZE: - rc = PEEK_BYTE (adrs); - break; - case WORDSIZE: - peek_warning (adrs, 'w'); - rc = PEEK_WORD (adrs); - break; - case LONGSIZE: - peek_warning (adrs, 'l'); - rc = PEEK_LONG (adrs); - break; - default: - rc = 0; - break; - } - /* - printf ("peek.%d(%x) = %x\n", size, (unsigned int)adrs, rc); - */ - return rc; -} - - - -static unsigned long -extend (unsigned long arg, opesize size) -{ - if (size == WORDSIZE) - return (unsigned short)(signed char)arg; - else /* if (size == LONGSIZE) */ - return (unsigned long)(signed short)arg; -} - - -static void -breakjob (unsigned long value) -{ - if (Eval_Count == 0) /* easy trick ? */ - Eval_Count = 1; - Eval_ID = BREAKID; - Eval_Break = value; -} - - -#ifdef SELF -int -main (void) -{ - char buf[256]; - - yydebug = 0; - while (fgets (buf, sizeof buf, stdin)) { - char* p = strchr (buf, '\n'); - if (p) - *p = '\n'; - Lexptr = buf; - yyparse (); - } - return 0; -} -#endif /* SELF */ - - -/* EOF */ diff --git a/src/fpconv.c b/src/fpconv.c index 911de4f..c72b55d 100644 --- a/src/fpconv.c +++ b/src/fpconv.c @@ -1,244 +1,288 @@ -/* - * - * ソースコードジェネレータ - * 浮動小数点実数値文字列変換モジュール - * Copyright (C) 1997-2010 Tachibana - * - */ - -/* System headers */ -#include /* sprintf() */ -#include /* strcpy() */ - -/* Headers */ -#include "estruct.h" /* enum boolean */ +// ソースコードジェネレータ +// 浮動小数点実数値文字列変換モジュール +// Copyright (C) 1997-2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + #include "fpconv.h" -#include "hex.h" /* itox8_without_0supress() */ + +#include +#include // sprintf() + +#include "estruct.h" +#include "etc.h" // strcpy2() +#include "hex.h" // itox8_without_0supress() /* External functions */ -#ifdef HAVE_STRTOX -extern long double strtox (const char* ptr); +#ifdef HAVE_STRTOX +extern long double strtox(const char* ptr); #endif +#if !defined(NO_PRINTF_LDBL) && ((LDBL_MANT_DIG != 64) || (LDBL_DIG != 18)) +#define NO_PRINTF_LDBL +#endif -/* External variables */ -short Inreal_flag = FALSE; - +static inline ULONG peeklv(ULONG ul) { return peekl((codeptr)&ul); } -/* Functions */ -extern void -fpconv_s (char* buf, float* valp) -{ - unsigned short e = *(unsigned short*)valp & 0x7f80; - unsigned long m = *(unsigned long*)valp & 0x007fffff; +static inline int isodd(codeptr ptr) { return (uintptr_t)ptr & 1; } - /* ±0.0を先に処理 */ - if (!Inreal_flag && e == 0 && m == 0) { - strcpy (buf, (*(char*)valp < 0) ? "0f-0" : "0f0"); - return; - } +static SingleReal* alignSingleReal(codeptr valp, SingleReal* buf) { + return isodd(valp) ? memcpy(buf, valp, sizeof(*buf)) : (SingleReal*)valp; +} - if (Inreal_flag || e == 0 || e == 0x7f80) { /* 非正規化数, 無限大、非数 */ - *buf++ = '!'; /* 特殊な値なら内部表現で出力 */ - itox8_without_0supress (buf, *(long*)valp); - } else { - sprintf (buf, "0f%.30g", *valp); - } +static float peekFloat(SingleReal* sr) { +#ifdef __BIG_ENDIAN__ + return *(float*)sr; +#else + SingleReal le = {.ul = peeklv(sr->ul)}; + return *(float*)≤ +#endif } +// Single-Precision Real 文字列化 +char* fpconv_s(char* buf, codeptr valp) { + SingleReal srBuf; + SingleReal* sr = alignSingleReal(valp, &srBuf); -/* Functions */ -extern void -fpconv_d (char* buf, double* valp) -{ - unsigned short e = *(unsigned short*)valp & 0x7ff0; - unsigned long mh = *(unsigned long*)valp & 0x000fffff; - unsigned long ml = *(unsigned long*)valp; + ULONG ul = peeklv(sr->ul); + UWORD e = (ul >> 16) & 0x7f80; + ULONG m = ul & 0x007fffff; - /* ±0.0を先に処理 */ - if (!Inreal_flag && e == 0 && (mh | ml) == 0) { - strcpy (buf, (*(char*)valp < 0) ? "0f-0" : "0f0"); - return; - } + // ±0.0を先に処理 + if (!Dis.inreal && e == 0 && m == 0) { + return strcpy2(buf, ((LONG)ul < 0) ? "0f-0" : "0f0"); + } - if (Inreal_flag || e == 0 || e == 0x7ff0) { /* 非正規化数, 無限大、非数 */ - long* p = (long*)valp; /* 特殊な値なら内部表現で出力 */ + if (Dis.inreal || e == 0 || e == 0x7f80) { // 非正規化数, 無限大、非数 + // 特殊な値なら内部表現で出力 + *buf++ = '!'; + return itox8_without_0supress(buf, ul); + } - *buf++ = '!'; - buf = itox8_without_0supress (buf, *p++); - *buf++ = '_'; - (void)itox8_without_0supress (buf, *p); - } else { - sprintf (buf, "0f%.30g", *valp); - } + return buf + sprintf(buf, "0f%.30g", peekFloat(sr)); } +static DoubleReal* alignDoubleReal(codeptr valp, DoubleReal* buf) { + return isodd(valp) ? memcpy(buf, valp, sizeof(*buf)) : (DoubleReal*)valp; +} + +static double peekDouble(DoubleReal* dr) { +#ifdef __BIG_ENDIAN__ + return *(double*)dr; +#else + DoubleReal le = {.ul = {peeklv(dr->ul[1]), peeklv(dr->ul[0])}}; + return *(double*)≤ +#endif +} -/* File scope functions */ -static void -fpconv_x_inreal (char* buf, long double* valp) -{ - unsigned long* p = (unsigned long*)valp; +// Double-Precision Real 文字列化 +char* fpconv_d(char* buf, codeptr valp) { + DoubleReal drBuf; + DoubleReal* dr = alignDoubleReal(valp, &drBuf); + ULONG ul0 = peeklv(dr->ul[0]); + UWORD e = (ul0 >> 16) & 0x7ff0; + ULONG mh = ul0 & 0x000fffff; + + // ±0.0を先に処理 + if (!Dis.inreal && e == 0 && mh == 0 && dr->ul[1] == 0) { + return strcpy2(buf, ((LONG)ul0 < 0) ? "0f-0" : "0f0"); + } + + if (Dis.inreal || e == 0 || e == 0x7ff0) { // 非正規化数, 無限大、非数 + // 特殊な値なら内部表現で出力 *buf++ = '!'; - buf = itox8_without_0supress (buf, *p++); - *buf++ = '_'; - buf = itox8_without_0supress (buf, *p++); + buf = itox8_without_0supress(buf, ul0); *buf++ = '_'; - (void)itox8_without_0supress (buf, *p++); + return itox8_without_0supress(buf, peeklv(dr->ul[1])); + } + + return buf + sprintf(buf, "0f%.30g", peekDouble(dr)); } -/* Functions */ -extern void -fpconv_x (char* buf, long double* valp) -#ifdef NO_PRINTF_LDBL -{ - /* 常に内部表現で出力 */ - fpconv_x_inreal (buf, valp); +static ExtendedReal* alignExtendedReal(codeptr valp, ExtendedReal* buf) { + return isodd(valp) ? memcpy(buf, valp, sizeof(*buf)) : (ExtendedReal*)valp; } -#else /* !NO_PRINTF_LDBL */ -{ - unsigned short e = *(unsigned short*)valp & 0x7fff; - unsigned long mh = ((unsigned long*)valp)[0]; - unsigned long ml = ((unsigned long*)valp)[1]; - - /* ±0.0を先に処理 */ - if (!Inreal_flag && e == 0 && (mh | ml) == 0) { - strcpy (buf, (*(char*)valp < 0) ? "0f-0" : "0f0"); - return; - } - if (Inreal_flag || e == 0 || e == 0x7fff /* 非正規化数, 無限大、非数 */ - || ((unsigned short*)valp)[1] /* 未使用ビットがセット */ - || ((char*)valp)[4] >= 0 /* 整数ビットが0 */ -#ifndef HAVE_STRTOX - || e <= 64 /* ライブラリに依存 */ +static long double peekExtended(ExtendedReal* xr) { +#ifdef __BIG_ENDIAN__ + return *(long double*)xr; +#else + ExtendedReal le = { + .ul = {peeklv(xr->ul[2]), peeklv(xr->ul[1]), peeklv(xr->ul[0]) >> 16}}; + return *(long double*)≤ #endif - ) { - fpconv_x_inreal (buf, valp); /* 特殊な値なら内部表現で出力 */ - } else { - sprintf (buf, "0f%.30Lg", *valp); +} + +static boolean is_normalized_x(ExtendedReal* xr) { + ULONG ul0 = peeklv(xr->ul[0]); + UWORD e = (ul0 >> 16) & 0x7fff; -#ifdef HAVE_STRTOX - /* 指数が正なら多分正しく変換できている筈 */ - if (e >= 0x3fff) - return; + if (e == 0 || e == 0x7fff) return FALSE; // 非正規化数, 無限大、非数 + if ((ul0 & 0x0000ffff) != 0) return FALSE; // 未使用ビットがセット + if ((int8_t)xr->uc[4] >= 0) return FALSE; // 整数ビットが0 - /* 正しく変換できなかったら、内部表現で出力しなおす */ - if (strtox (buf + 2) != *valp) - fpconv_x_inreal (buf, valp); +#ifndef HAVE_STRTOX + if (e <= 64) return FALSE; // ライブラリに依存 #endif - } + + return TRUE; } -#endif /* !NO_PRINTF_LDBL */ +static char* fpconv_x_inreal(char* buf, ExtendedReal* xr) { + *buf++ = '!'; + buf = itox8_without_0supress(buf, peeklv(xr->ul[0])); + *buf++ = '_'; + buf = itox8_without_0supress(buf, peeklv(xr->ul[1])); + *buf++ = '_'; + return itox8_without_0supress(buf, peeklv(xr->ul[2])); +} -/* File scope functions */ -static boolean -is_normalized_p (packed_decimal* valp) -{ +static inline char* fpconv_x_printf(char* buf, ExtendedReal* xr) { + char* p = buf + sprintf(buf, "0f%.30Lg", peekExtended(xr)); - if ((valp->ul.hi<<1 | valp->ul.mi | valp->ul.lo) == 0) - return TRUE; /* ±0.0 */ +#ifdef HAVE_STRTOX + ULONG ul0 = peeklv(xr->ul[0]); - if ( ((valp->ul.hi & 0x7fff0000) == 0x7fff0000) /* 非数,無限大 */ - || ((valp->ul.hi & 0x3000fff0) != 0) /* 未使用ビットがセット */ -#if 0 - || ((valp->ul.hi & 0x4fff0000) == 0x4fff0000) /* 非正規化数 */ + // 指数が正なら多分正しく変換できているはず + if (((ul0 >> 16) & 0x7fff) >= 0x3fff) return p; + + // 正しく変換できなかったら、内部表現で出力しなおす + if (strtox(buf + 2) != peekExtended(xr)) return fpconv_x_inreal(buf, xr); #endif - || ((valp->ul.hi & 0x0000000f) > 9) ) /* BCD(整数桁)の値が異常 */ - return FALSE; - - { - int i; - unsigned char *ptr = &valp->uc[4]; - for (i = 0; i < 8; i++) { - unsigned char c = *ptr++; - if ((c > (unsigned char)0x99) || ((c & 0x0f) > (unsigned char)0x09)) - return FALSE; /* BCD(小数桁)の値が異常 */ - } - } - return TRUE; + return p; } +// Extended-Precision Real 文字列化 +char* fpconv_x(char* buf, codeptr valp) { + ExtendedReal xrBuf; + ExtendedReal* xr = alignExtendedReal(valp, &xrBuf); -/* Functions */ -extern void -fpconv_p (char* buf, packed_decimal* valp) -{ + ULONG ul0 = peeklv(xr->ul[0]); - if (Inreal_flag || !is_normalized_p (valp)) { - long* p = (long*)valp; /* 特殊な値なら内部表現で出力 */ + // ±0.0を先に処理 + if (!Dis.inreal && (ul0 << 1 | xr->ul[1] | xr->ul[2]) == 0) { + return strcpy2(buf, ((LONG)ul0 < 0) ? "0f-0" : "0f0"); + } - *buf++ = '!'; - buf = itox8_without_0supress (buf, *p++); - *buf++ = '_'; - buf = itox8_without_0supress (buf, *p++); - *buf++ = '_'; - (void)itox8_without_0supress (buf, *p); + if (Dis.inreal || !is_normalized_x(xr)) { + return fpconv_x_inreal(buf, xr); // 特殊な値なら内部表現で出力 + } - } else { - *buf++ = '0'; - *buf++ = 'f'; - if (valp->uc[0] & 0x80) - *buf++ = '-'; - - /* 仮数の整数部 */ - *buf++ = '0' + (valp->ul.hi & 0x0000000f); - *buf++ = '.'; - - /* 仮数の小数部 */ - { - int i; - unsigned char *ptr = &valp->uc[4]; - - for (i = 0; i < 8; i++) { - unsigned char c = *ptr++; - *buf++ = '0' + (c >> 4); - *buf++ = '0' + (c & 0x0f); - } - } - - /* 末尾の'0'を削除 */ - while (*--buf == (char)'0') - ; - if (*buf != (char)'.') - buf++; - - /* 指数 */ - { - int expo = (valp->uc[0] & 0x0f)*100 - + (valp->uc[1] >> 4)*10 - + (valp->uc[1] & 0x0f); - - if ((expo == 0) && !(valp->uc[0] & 0x40)) { - /* "e+0"は省略する */ - *buf = '\0'; - } else { - *buf++ = 'e'; - *buf++ = (valp->uc[0] & 0x40) ? '-' : '+'; - buf += (expo >= 100) + (expo >= 10) + 1; - *buf = '\0'; - do { - *--buf = '0' + (expo % 10); - expo /= 10; - } while (expo); - } - } +#ifdef NO_PRINTF_LDBL + return fpconv_x_inreal(buf, xr); // 常に内部表現で出力 +#else + return fpconv_x_printf(buf, xr); +#endif +} + +static boolean is_normalized_p(PackedDecimal* pd) { + ULONG ul0 = peeklv(pd->ul[0]); + + if ((ul0 << 1 | pd->ul[1] | pd->ul[2]) == 0) return TRUE; // ±0.0 + + if (((ul0 & 0x7fff0000) == 0x7fff0000) // 非数,無限大 + || ((ul0 & 0x3000fff0) != 0) // 未使用ビットがセット +#if 0 + || ((ul0 & 0x4fff0000) == 0x4fff0000) // 非正規化数 +#endif + || ((ul0 & 0x0000000f) > 9)) // BCD(整数桁)の値が異常 + return FALSE; + + { + int i; + uint8_t* ptr = (uint8_t*)&pd->uc[4]; + for (i = 0; i < 8; i++) { + uint8_t c = *ptr++; + if ((c > 0x99) || ((c & 0x0f) > 0x09)) + return FALSE; // BCD(小数桁)の値が異常 } + } + + return TRUE; } +static PackedDecimal* alignPackedDecimal(codeptr valp, PackedDecimal* buf) { + return isodd(valp) ? memcpy(buf, valp, sizeof(*buf)) : (PackedDecimal*)valp; +} -/* Functions */ -extern void -fpconv_q (char* buf, quadword* valp) -{ +// Packed Decimal Real 文字列化 +char* fpconv_p(char* buf, codeptr valp) { + PackedDecimal pdBuf; + PackedDecimal* pd = alignPackedDecimal(valp, &pdBuf); + + if (Dis.inreal || !is_normalized_p(pd)) { + // 特殊な値なら内部表現で出力 *buf++ = '!'; - buf = itox8_without_0supress (buf, valp->ul.hi); + buf = itox8_without_0supress(buf, peeklv(pd->ul[0])); *buf++ = '_'; - (void)itox8_without_0supress (buf, valp->ul.lo); -} + buf = itox8_without_0supress(buf, peeklv(pd->ul[1])); + *buf++ = '_'; + return itox8_without_0supress(buf, peeklv(pd->ul[2])); + } + + *buf++ = '0'; + *buf++ = 'f'; + if ((int8_t)pd->uc[0] < 0) *buf++ = '-'; + + // 仮数の整数部 + *buf++ = '0' + (pd->uc[3] & 0x0f); + *buf++ = '.'; + + // 仮数の小数部 + { + int i; + uint8_t* ptr = &pd->uc[4]; + + for (i = 0; i < 8; i++) { + uint8_t c = *ptr++; + *buf++ = '0' + (c >> 4); + *buf++ = '0' + (c & 0x0f); + } + } + + // 末尾の'0'を削除 + while (*--buf == '0') + ; + if (*buf != '.') buf++; + + // 指数 + { + int expo = + (pd->uc[0] & 0x0f) * 100 + (pd->uc[1] >> 4) * 10 + (pd->uc[1] & 0x0f); + if ((expo == 0) && !(pd->uc[0] & 0x40)) { + *buf = '\0'; // "e+0"は省略する + } else { + char* p; + + *buf++ = 'e'; + *buf++ = (pd->uc[0] & 0x40) ? '-' : '+'; + buf += (expo >= 100) + (expo >= 10) + 1; + *buf = '\0'; + + p = buf; + do { + *--p = '0' + (expo % 10); + expo /= 10; + } while (expo); + } + } + return buf; +} -/* EOF */ +// EOF diff --git a/src/fpconv.h b/src/fpconv.h index 585b588..25ae950 100644 --- a/src/fpconv.h +++ b/src/fpconv.h @@ -1,46 +1,52 @@ -/* - * - * ソースコードジェネレータ - * 浮動小数点実数値文字列変換モジュールヘッダ - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef FPCONV_H -#define FPCONV_H - -#if !defined(__GNUC__) || (__GNUC__ < 2) -#error You lose. This file can be compiled only by GNU-C compiler version 2. -#endif - +// ソースコードジェネレータ +// 浮動小数点実数値文字列変換モジュールヘッダ +// Copyright (C) 1997-2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef FPCONV_H +#define FPCONV_H + +#include "estruct.h" typedef union { - struct { - unsigned long hi; - unsigned long lo; - } ul; - double d; -} quadword; + uint8_t uc[4]; + ULONG ul; +} SingleReal; typedef union { - struct { - unsigned long hi; - unsigned long mi; - unsigned long lo; - } ul; - unsigned char uc[12]; -} packed_decimal; + uint8_t uc[8]; + ULONG ul[2]; +} DoubleReal; +typedef union { + uint8_t uc[12]; + ULONG ul[3]; +} ExtendedReal; -extern void fpconv_s (char* buf, float* valp); -extern void fpconv_d (char* buf, double* valp); -extern void fpconv_x (char* buf, long double* valp); -extern void fpconv_p (char* buf, packed_decimal* valp); -extern void fpconv_q (char* buf, quadword* valp); - -extern short Inreal_flag; +typedef union { + uint8_t uc[12]; + ULONG ul[3]; +} PackedDecimal; +extern char* fpconv_s(char* buf, codeptr valp); +extern char* fpconv_d(char* buf, codeptr valp); +extern char* fpconv_x(char* buf, codeptr valp); +extern char* fpconv_p(char* buf, codeptr valp); -#endif /* FPCONV_H */ +#endif // FPCONV_H -/* EOF */ +// EOF diff --git a/src/fpu.c b/src/fpu.c new file mode 100644 index 0000000..244a5d0 --- /dev/null +++ b/src/fpu.c @@ -0,0 +1,663 @@ +// ソースコードジェネレータ +// 浮動小数点命令逆アセンブル +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "fpu.h" + +#include "disasm.h" +#include "ea.h" +#include "global.h" +#include "opstr.h" + +// 一般命令で受け付けるオペランド形式(!=0なら値はなんでもいい) +enum { + FPM_FPN = 1, + FPN_ONLY = 2, +}; + +typedef struct { + fputypes fputypes; + uint8_t fpm_fpn, fpn_only; + uint8_t opnum; +} Type000Spec; +static Type000Spec type000table[128] = { + {F88x | F040 | F060, FPM_FPN, 0, FPU_T0_FMOVE}, + {F88x | F4SP | F060, FPM_FPN, FPN_ONLY, FPU_T0_FINT}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FSINH}, + {F88x | F4SP | F060, FPM_FPN, FPN_ONLY, FPU_T0_FINTRZ}, + {F88x | F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FSQRT}, + {0, 0, 0, 0}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FLOGNP1}, + {0, 0, 0, 0}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FETOXM1}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FTANH}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FATAN}, + {0, 0, 0, 0}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FASIN}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FATANH}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FSIN}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FTAN}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FETOX}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FTWOTOX}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FTENTOX}, + {0, 0, 0, 0}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FLOGN}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FLOG10}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FLOG2}, + {0, 0, 0, 0}, + {F88x | F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FABS}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FCOSH}, + {F88x | F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FNEG}, + {0, 0, 0, 0}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FACOS}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FCOS}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FGETEXP}, + {F88x | F4SP | F6SP, FPM_FPN, FPN_ONLY, FPU_T0_FGETMAN}, + {F88x | F040 | F060, FPM_FPN, 0, FPU_T0_FDIV}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FMOD}, + {F88x | F040 | F060, FPM_FPN, 0, FPU_T0_FADD}, + {F88x | F040 | F060, FPM_FPN, 0, FPU_T0_FMUL}, + {F88x | F4SP | F060, FPM_FPN, 0, FPU_T0_FSGLDIV}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FREM}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSCALE}, + {F88x | F4SP | F060, FPM_FPN, 0, FPU_T0_FSGLMUL}, + {F88x | F040 | F060, FPM_FPN, 0, FPU_T0_FSUB}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F4SP | F6SP, FPM_FPN, 0, FPU_T0_FSINCOS}, + {F88x | F040 | F060, FPM_FPN, 0, FPU_T0_FCMP}, + {0, 0, 0, 0}, + {F88x | F040 | F060, 0, FPN_ONLY, FPU_T0_FTST}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FSMOVE}, + {F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FSSQRT}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FDMOVE}, + {F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FDSQRT}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FSABS}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FSNEG}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FDABS}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, FPN_ONLY, FPU_T0_FDNEG}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FSDIV}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FSADD}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FSMUL}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FDDIV}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FDADD}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FDMUL}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FSSUB}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {F040 | F060, FPM_FPN, 0, FPU_T0_FDSUB}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, +}; + +// destination format +enum { + DF_LONG = 0, + DF_SINGLE = 1, + DF_EXTEND = 2, + DF_PACKED_STATIC = 3, + DF_WORD = 4, + DF_DOUBLE = 5, + DF_BYTE = 6, + DF_PACKED_DYNAMIC = 7, +}; + +static const uint8_t formats[8] = { + LONGSIZE, + SINGLESIZE, // + EXTENDSIZE, + PACKEDSIZE, // static k-Factor + WORDSIZE, + DOUBLESIZE, // + BYTESIZE, + PACKEDSIZE // dynamic k-Factor +}; + +// が0か調べる(op000専用) +// op000ならbit7-6==0なので省力化している +static boolean is_ea_0(UWORD word1) { + return ((UBYTE)word1 == 0) ? TRUE : FALSE; +} + +// 68060でFPSP無しなら未定義命令(6888x/68040なら常に有効) +static boolean reject_no_060fpsp(disasm* code) { + fputypes fpu = Dis.fpu; + if ((fpu & F6SP) == 0) { + if ((fpu & ~F060) == 0) return TRUE; + code->mputypes &= ~M060; + } + return FALSE; +} + +static boolean reject_fpu(disasm* code, fputypes types) { + fputypes t = types & Dis.fpu; + mputypes m = 0; + + if (t & F88x) m |= (M020 | M030); + if (t & (F040 | F4SP)) m |= M040; + if (t & (F060 | F6SP)) m |= M060; + code->mputypes = m; + + return (m == 0) ? TRUE : FALSE; +} + +// FDBcc, FTRAPcc, FSccの第2ワードが正しいか? +// FBccは第1ワードに埋め込まれているので対象外。 +static boolean is_valid_fpcond(UWORD word2) { + return (word2 & 0xffe0) ? FALSE : TRUE; +} + +static int extract_fpcond(UWORD word1) { return word1 & 0x003f; } + +static int extract_kfactor(UWORD word2) { return word2 & 0x007f; } + +// (R/M==0) Fop.X FPm,FPn +static boolean op000cls001(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + Type000Spec spec = type000table[word2 & 0x007f]; + int src = (word2 >> 10) & 7; + int dst = (word2 >> 7) & 7; + + if (!is_ea_0(word1)) return FALSE; + if (reject_fpu(code, spec.fputypes)) return FALSE; + + // FTST.X FPm は未使用レジスタフィールドが0でないといけない + // (ただし、ソースと同じ値の場合も許容する) + if (!spec.fpm_fpn && Dis.undefReg) { + if (dst != 0 && dst != src) return FALSE; + } + + code->bytes = 4; + code->size = code->size2 = code->default_size = EXTENDSIZE; + OPECODE(fpuType000[spec.opnum]); + setFPn(&code->op1, src); + + if (spec.opnum == FPU_T0_FSINCOS) { + setPairFPn(&code->op2, word2 & 7, dst); + } else if (spec.fpm_fpn) { + if (!spec.fpn_only || src != dst) { + // Fop FPm,FPm を Fop FPm と省略表記できない場合 + setFPn(&code->op2, dst); + } + } + + return TRUE; +} + +static boolean fmovecr(disasm* code, UWORD word1, UWORD word2) { + if (!is_ea_0(word1) || reject_no_fpsp(code)) return FALSE; + + code->bytes = 4; + code->size = code->size2 = code->default_size = EXTENDSIZE; + OPECODE(fmovecr); + setImmEmbedHex(&code->op1, word2 & 0x007f); + setFPn(&code->op2, word2 >> 7); + + return TRUE; +} + +static boolean fop_ea_fpn(codeptr ptr, disasm* code, UWORD word2) { + // fmt==7はfmovecrなので不要 + static const int modes[7] = { + DATA, DATA, MEMORY, MEMORY, DATA, MEMORY, DATA // + }; + + Type000Spec spec = type000table[word2 & 0x007f]; + int fmt = (word2 >> 10) & 7; + int dst = (word2 >> 7) & 7; + opesize size = formats[fmt]; + + if (!spec.fpm_fpn && dst != 0) return FALSE; + if (reject_fpu(code, spec.fputypes)) return FALSE; + if (size == PACKEDSIZE && reject_no_fpsp(code)) return FALSE; + + OPECODE(fpuType000[spec.opnum]); + code->bytes = 4; + code->default_size = EXTENDSIZE; + code->size = code->size2 = size; + if (!setEA(code, &code->op1, ptr, modes[fmt])) return FALSE; + + if (spec.opnum == FPU_T0_FSINCOS) { + setPairFPn(&code->op2, word2 & 7, dst); + } else if (spec.fpm_fpn) { + setFPn(&code->op2, dst); + } + + return TRUE; +} + +// (R/M==1) Fop. ,FPn +static boolean op000cls010(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + int fmt = (word2 >> 10) & 7; + + if (fmt == 7) { + return fmovecr(code, word1, word2); + } + return fop_ea_fpn(ptr, code, word2); +} + +// (R/M==1) FMOVE. FPm, +static boolean fmove_fpm_ea(codeptr ptr, disasm* code) { + static const int modes[8] = { + (DATA & CHANGE), + (DATA & CHANGE), // + (DATA & CHANGE) ^ DATAREG, + (DATA & CHANGE) ^ DATAREG, // + (DATA & CHANGE), + (DATA & CHANGE) ^ DATAREG, // + (DATA & CHANGE), + (DATA & CHANGE) ^ DATAREG // + }; + + UWORD word2 = peekw(ptr + 2); + int fmt = (word2 >> 10) & 7; + int kfactor = extract_kfactor(word2); + + switch (fmt) { + case DF_PACKED_DYNAMIC: + if ((kfactor & 0x0f) != 0) return FALSE; + // FALLTHRU + case DF_PACKED_STATIC: + if (reject_no_fpsp(code)) return FALSE; + break; + default: + if (kfactor != 0) return FALSE; + break; + } + + OPECODE(fpuType000[FPU_T0_FMOVE]); + code->default_size = EXTENDSIZE; + code->size = code->size2 = formats[fmt]; + code->bytes = 4; + setFPn(&code->op1, word2 >> 7); + + if (!setEA(code, &code->op2, ptr, modes[fmt])) return FALSE; + if (fmt == DF_PACKED_STATIC) { + setStaticKFactor(&code->op3, kfactor); + } else if (fmt == DF_PACKED_DYNAMIC) { + setDynamicKFactor(&code->op3, kfactor >> 4); + } + + return TRUE; +} + +static boolean is_valid_fpcrlist(UWORD word2) { + if ((word2 & 0x1c00) == 0) return FALSE; + if (word2 & 0x03ff) return FALSE; + + return TRUE; +} + +// 0-7について、1のビットの数を返す +static int popcount7(unsigned int n) { + unsigned int a = n & 1; + n >>= 1; + return a + n - (n >> 1); +} + +static const int fpcr_modes[8] = { + 0, ALL, DATA, MEMORY, DATA, MEMORY, MEMORY, MEMORY // +}; + +// FMOVE ,fpcr FMOVEM ,fpcrlist +static boolean fmove_to_fpcr(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + int reglist = (word2 >> 10) & 7; + int count = popcount7(reglist); + int mode = fpcr_modes[reglist]; + + if (!is_valid_fpcrlist(word2)) return FALSE; + + code->bytes = 4; + code->size = code->size2 = code->default_size = LONGSIZE; + + if (!setEA(code, &code->op1, ptr, mode)) return FALSE; + if (code->op1.ea == IMMED && count >= 2 && reject_no_fpsp(code)) return FALSE; + + OPECODE2(count == 1, fpuType000[FPU_T0_FMOVE], fmovem); + + if (count == 1 || code->op1.ea != IMMED) { + setFPCRSRlist(&code->op2, reglist); + } else { + if (!setEA(code, &code->op2, ptr, mode)) return FALSE; + if (count == 2) { + // fmovem #imm,#imm,reglist + setFPCRSRlist(&code->op3, reglist); + } else { + // fmovem #imm,#imm,#imm,reglist + if (!setEA(code, &code->op3, ptr, mode)) return FALSE; + setFPCRSRlist(&code->op4, reglist); + } + } + + return TRUE; +} + +// FMOVE fpcr, FMOVEM fpcrlist, +static boolean fmove_from_fpcr(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + int reglist = (word2 >> 10) & 7; + int count = popcount7(reglist); + + if (!is_valid_fpcrlist(word2)) return FALSE; + + code->bytes = 4; + code->size = code->size2 = code->default_size = LONGSIZE; + OPECODE2(count == 1, fpuType000[FPU_T0_FMOVE], fmovem); + setFPCRSRlist(&code->op1, reglist); + return setEA(code, &code->op2, ptr, fpcr_modes[reglist] & CHANGE); +} + +enum { + FMOVEM_DYNAMIC = 1 << 0, + FMOVEM_POSTINC_CTRL = 1 << 1, +}; + +static boolean is_valid_reglist(disasm* code, int mode, UWORD word2) { + if (mode & FMOVEM_DYNAMIC) { + // dynamic register list + if ((word2 & 0x078f) || reject_no_fpsp(code)) return FALSE; + } else { + // static register list + if ((word2 & 0x0700) || (word2 & 0x00ff) == 0) return FALSE; + } + + return TRUE; +} + +// FMOVEM , +static boolean fmovem_ea_fp(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + int mode = (word2 >> 11) & 3; + + // fmovem -(an),list は無いのだから、これも不可のはず(実機未検証) + if ((mode & FMOVEM_POSTINC_CTRL) == 0) return FALSE; + + if (!is_valid_reglist(code, mode, word2)) return FALSE; + + OPECODE(fmovem); + code->bytes = 4; + code->size = code->size2 = EXTENDSIZE; + if (!setEA(code, &code->op1, ptr, CONTROL | POSTINC)) return FALSE; + if (mode & FMOVEM_DYNAMIC) + setDn(&code->op2, word2 >> 4); + else + setFPreglist(&code->op2, word2 & 0x00ff, FALSE); + + return TRUE; +} + +// FMOVEM , +static boolean fmovem_fp_ea(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + int mode = (word2 >> 11) & 3; + + // fmovem list,-(an) は predecrement addressing mode で、それ以外は + // postincrement or control addressing mode のはず(実機未検証) + boolean predec = (mode & FMOVEM_POSTINC_CTRL) ? FALSE : TRUE; + if (is_predecrement(word1) != predec) return FALSE; + + if ((mode & FMOVEM_POSTINC_CTRL) && is_predecrement(word1)) return FALSE; + + if (!is_valid_reglist(code, mode, word2)) return FALSE; + + OPECODE(fmovem); + code->bytes = 4; + code->size = code->size2 = EXTENDSIZE; + if (mode & FMOVEM_DYNAMIC) + setDn(&code->op1, word2 >> 4); + else + setFPreglist(&code->op1, word2 & 0x00ff, is_predecrement(word1)); + return setEA(code, &code->op2, ptr, CONTROL | PREDEC); +} + +// 一般命令 +static boolean op000(codeptr ptr, disasm* code, UWORD word1) { + int opclass = peekb(ptr + 2) >> 5; + + switch (opclass) { + default: + break; + + case 0: + return op000cls001(ptr, code, word1); + case 2: + return op000cls010(ptr, code, word1); + case 3: + return fmove_fpm_ea(ptr, code); + case 4: + return fmove_to_fpcr(ptr, code); + case 5: + return fmove_from_fpcr(ptr, code); + case 6: + return fmovem_ea_fp(ptr, code); + case 7: + return fmovem_fp_ea(ptr, code, word1); + } + + return FALSE; +} + +static boolean fdbcc(codeptr ptr, disasm* code, UWORD word1, int cond) { + OPECODE(fdbcc[cond]); + + // DBcc と違い、FDBcc は Unsized + code->default_size = NOTHING; + + setDn(&code->op1, word1); + setrelative4(code, &code->op2, extl(peekw(ptr + 4))); + code->jmp = code->op2.opval; + code->jmpea = code->op2.ea = PCDISP; + code->op2.labelchange1 = LABELCHANGE_LABEL_ONLY; + code->opeType = BCCOP; + code->bytes = 6; + + return TRUE; +} + +static boolean ftrapcc(codeptr ptr, disasm* code, int mode, int cond) { + OPECODE(ftrapcc[cond]); + code->bytes = 4; + if (mode != CPTRAP_UNSIZED) { + code->size = (mode == CPTRAP_WORD) ? WORDSIZE : LONGSIZE; + return setImm(code, &code->op1, ptr, code->size); + } + + return TRUE; +} + +static boolean fscc(codeptr ptr, disasm* code, int cond) { + OPECODE(fscc[cond]); + code->bytes = 4; + code->size = code->size2 = code->default_size = BYTESIZE; + return setEA(code, &code->op1, ptr, DATA & CHANGE); +} + +// FDBcc, FScc, FTRAPcc +static boolean op001(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + int cond = extract_fpcond(word2); + int eamode, opmode; + + if (!is_valid_fpcond(word2) || reject_no_060fpsp(code)) return FALSE; + + // FScc で未使用のにFDBccとFTRAPccが割り当てられているので先に調べる + eamode = (word1 >> 3) & 7; + if (eamode == 1) { + return fdbcc(ptr, code, word1, cond); + } + opmode = word1 & 7; + if (eamode == 7 && CPTRAP_WORD <= opmode && opmode <= CPTRAP_UNSIZED) { + return ftrapcc(ptr, code, opmode, cond); + } + + return fscc(ptr, code, cond); +} + +static boolean fbcc(codeptr ptr, disasm* code, UWORD word1, opesize size) { + int cond = extract_fpcond(word1); + + if (cond >= FPCOND_NUM) return FALSE; + + OPECODE(fbcc[cond]); + code->opeType = BCCOP; + if (cond == FPCOND_T) { + code->opeType = JMPOP; + code->codeflags += CODEFLAG_BRAOP; + } + code->default_size = NOTHING; + code->size = code->size2 = size; + if (size == WORDSIZE) { + // FBcc.W + code->bytes = 4; + setrelative(code, &code->op1, extl(peekw(ptr + 2))); + } else { + // FBcc.L + LONG d32 = peekl(ptr + 2); + code->bytes = 6; + setrelative(code, &code->op1, d32); + if (-32768 <= d32 && d32 <= 32767) code->codeflags += CODEFLAG_NEED_OPESIZE; + } + code->jmp = code->op1.opval; + code->jmpea = code->op1.ea = PCDISP; + code->op1.labelchange1 = LABELCHANGE_LABEL_ONLY; + + return TRUE; +} + +static boolean fnop(disasm* code) { + OPECODE(fnop); + code->default_size = NOTHING; + code->bytes = 4; + + return TRUE; +} + +static boolean fsave(codeptr ptr, disasm* code) { + OPECODE(fsave); + code->default_size = NOTHING; + return setEA(code, &code->op1, ptr, CTRLCHG | PREDEC); +} + +static boolean frestore(codeptr ptr, disasm* code) { + OPECODE(frestore); + code->default_size = NOTHING; + return setEA(code, &code->op1, ptr, CONTROL | POSTINC); +} + +static boolean decode(codeptr ptr, disasm* code, UWORD word1) { + int optype = (word1 >> 6) & 7; + + switch (optype) { + default: + break; + + case 0: + return op000(ptr, code, word1); + case 1: + return op001(ptr, code, word1); + case 2: + if ((word1 & 0xff) == 0x80 && peekw(ptr + 2) == 0) return fnop(code); + return fbcc(ptr, code, word1, WORDSIZE); + case 3: + return fbcc(ptr, code, word1, LONGSIZE); + case 4: + return fsave(ptr, code); + case 5: + return frestore(ptr, code); + } + + return FALSE; +} + +// 浮動小数点命令(既定でコプロセッサID=1) +boolean disfp(codeptr ptr, disasm* code) { + UWORD word1 = peekw(ptr); + + if (decode(ptr, code, word1)) { + code->mputypes &= ~(M000 | M010); + code->fpuid = (word1 >> 9) & 7; + return TRUE; + } + + return FALSE; +} + +// EOF diff --git a/src/fpu.h b/src/fpu.h new file mode 100644 index 0000000..fd7656e --- /dev/null +++ b/src/fpu.h @@ -0,0 +1,30 @@ +// ソースコードジェネレータ +// 浮動小数点命令逆アセンブル ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef FPU_H +#define FPU_H + +#include "disasm.h" +#include "estruct.h" + +extern boolean disfp(codeptr ptr, disasm* code); + +#endif + +// EOF diff --git a/src/generate.c b/src/generate.c index b7e973e..ce36a5f 100644 --- a/src/generate.c +++ b/src/generate.c @@ -1,808 +1,490 @@ -/* $Id: generate.c,v 1.1 1996/11/07 08:03:36 ryo freeze $ - * - * ソースコードジェネレータ - * ソースコードジェネレートモジュール - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#include /* time ctime */ -#include /* isprint */ +// ソースコードジェネレータ +// ソースコードジェネレートモジュール +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "generate.h" + +#include // isprint +#include #include -#include /* getenv */ +#include // getenv #include -#include +#include // time ctime #include "disasm.h" +#include "eastr.h" // write_size #include "estruct.h" -#include "etc.h" /* charout, strupr, */ +#include "etc.h" // charout, +#include "eval.h" #include "fpconv.h" -#include "generate.h" #include "global.h" #include "hex.h" -#include "include.h" /* Doscall_mac_path , etc. */ -#include "label.h" /* search_label etc. */ -#include "offset.h" /* depend_address, nearadrs */ +#include "include.h" +#include "label.h" // search_label etc. +#include "mmu.h" +#include "offset.h" // depend_address, nearadrs +#include "opstr.h" +#include "osk.h" #include "output.h" -#include "symbol.h" /* symbol_search */ +#include "symbol.h" // symbol_search #include "table.h" -#if defined (__LIBC__) - #include /* char* _comline */ - #define COMMAND_LINE _comline -#else - private char* make_cmdline (char** argv); - #define COMMAND_LINE make_cmdline (argv + 1) - #define NEED_MAKE_CMDLINE -#endif - - /* Macros */ #define MIN_BIT(x) ((x) & -(x)) -#ifdef DEBUG -#define DEBUG_PRINT(arg) eprintf arg -#else -#define DEBUG_PRINT(arg) -#endif +typedef struct { + address adrs; + LONG shift; +} AdrsShift; + +// static 関数プロトタイプ +static address textgen(address, address); +static void byteout_for_xoption(address, ULONG, char*); +static void byteout_for_moption(disasm* code, char* buffer); +static char* operandToLabel(char* p, operand* op); +static void syntax_new_to_old(operand* op); + +static void dataout(address, ULONG, opesize); +static address datagen(address, address, opesize); +static void datagen_sub(address, address, opesize); +static void strgen(address, address); +static void relgen(address, address, opesize); +static void zgen(address, address); +static address tablegen(address pc, int sectType); +static void tablegen_label(address pc, address pcend, lblbuf* lptr, + int sectType); +static void bssgen(address, address, opesize); +static char* mputype_numstr(mputypes m); + +static mputypes Current_Mputype; + +// ラベルorシンボル名(±オフセット)形式のラベル式をバッファに書き込む +// 文字列末尾のアドレスを返す +char* make_proper_symbol(char* buf, address adrs) { + SymbolLabelFormula slfml; + + makeSymLabFormula(&slfml, adrs); + return catSlfml(buf, &slfml); +} +// コメント行を書き出す +void com(const char* fmt, ...) { + char buf[512]; + va_list ap; -USEOPTION option_q, option_r, option_x, - option_B, option_M, option_N, /* option_Q, */ - option_S, option_U; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + otherDirective2(Dis.commentStr, buf); +} -/* main.c */ -extern char CommentChar; +// コメント記号だけの行を書き出す +// com("") で warning: zero-length format string になるのを回避。 +void comBlank(void) { otherDirective(Dis.commentStr); } +// .cpu疑似命令を書き出す +void outputHeaderCpu(void) { + otherDirective2(OpString.cpu, mputype_numstr(Current_Mputype)); +} -/* static 関数プロトタイプ */ -private lblbuf* gen (char* section, address end, lblbuf* lptr, int type); -#ifndef OSKDIS -private lblbuf* gen2(char* section, address end, lblbuf* lptr, int type); -#endif -private void output_file_open_next (int sect); -private address textgen (address, address); -private void labelchange (disasm* code, operand* op); -private void a7toSP (operand*); -private void syntax_new_to_old (operand* op); -private address datagen (address, address, opesize); -private void datagen_sub (address, address, opesize); - -private void dataout (address, ULONG, opesize); -private void byteout (address, ULONG, boolean); -private void wordout (address, ULONG); -private void longout (address, ULONG); -private void quadout (address pc, ULONG byte); -private void floatout (address pc, ULONG byte); -private void doubleout (address pc, ULONG byte); -private void extendout (address pc, ULONG byte); -private void packedout (address pc, ULONG byte); - -private void strgen (address, address); -private void relgen (address, address); -private void rellonggen (address, address); -private void byteout_for_moption (address, char*, int); -private void zgen (address, address); -private address tablegen (address, address, lblmode); -private address tablegen_sub (formula*, address, address, int); -private void tablegen_label (address, address, lblbuf*); -private void tablegen_dc (address, lblbuf*, char*, int); -private void bssgen (address, address, opesize); -private void label_line_out (address adrs, lblmode mode); -private void label_line_out_last (address adrs, lblmode mode); -private void label_op_out (address); -private void output_opecode (char*); -private char* mputype_numstr (mputypes m); -private void makeheader (char*, time_t, char*, char*); - -#ifdef OSKDIS -private void oskdis_gen (void); -private lblbuf* idatagen (address end, lblbuf* lptr); -private void vlabelout (address, lblmode); -private void wgen (address pc, address pcend); -#endif /* OSKDIS */ - - -int SymbolColonNum = 2; -short sp_a7_flag; /* a7 を sp と出力するか? */ -short Old_syntax; - -int Xtab = 7; /* /x option TAB level */ -int Atab = 8; /* /a option TAB level */ -int Mtab = 5; /* /M option TAB level */ - -int Data_width = 8; /* データ領域の横バイト数 */ -int String_width = 60; /* 文字列領域の横バイト数 */ -int Compress_len = 64; /* データ出力をdcb.?にする最小バイト数 */ - -size_mode Generate_SizeMode = SIZE_NORMAL; - -char Label_first_char = 'L'; /* ラベルの先頭文字 */ - -char opsize[] = "bwlqssdxp"; - -static mputypes Current_Mputype; -static UWORD SectionType; - - -#ifdef OSKDIS -char* OS9label [0x100]; /* os9 F$???(I$???) */ -char* MATHlabel[0x100]; /* tcall T$Math,T$??? */ -char* CIOlabel [0x100]; /* tcall CIO$Trap,C$??? */ -#else -char** IOCSlabel; -char IOCSCallName[16] = "IOCS"; -const char* Header_filename; -#endif /* OSKDIS */ +static FILE* open_header_file(void) { + FILE* fp; + const char* fname = Dis.headerFile; + if (fname == NULL || fname[0] == '\0') { + if (!Dis.deterministic) fname = getenv(ENV_dis_header); + } + if (fname == NULL || fname[0] == '\0') { + return NULL; + } -/* 擬似命令 */ + fp = fopen(fname, "rt"); + if (fp == NULL) { + err("\nヘッダ記述ファイルをオープンできません: %s\n", fname); + } -#ifdef OSKDIS -#define PSEUDO "\t" -#define EVEN "align" -#else -#define PSEUDO "\t." -#define EVEN "even" -#define DCB_B "dcb.b\t" -#define DCB_W "dcb.w\t" -#define DCB_L "dcb.l\t" -#define DCB_Q "dcb.d\t" -#define DCB_S "dcb.s\t" -#define DCB_D "dcb.d\t" -#define DCB_X "dcb.x\t" -#define DCB_P "dcb.p\t" -#endif /* !OSKDIS */ - -#define INCLUDE "include\t" -#define CPU "cpu\t" -#define FPID "fpid\t" -#define EQU "equ\t" -#define XDEF "xdef\t" - -#define DC_B "dc.b\t" -#define DC_W "dc.w\t" -#define DC_L "dc.l\t" -#define DC_Q "dc.d\t" -#define DC_S "dc.s\t" -#define DC_D "dc.d\t" -#define DC_X "dc.x\t" -#define DC_P "dc.p\t" - -#define DS_B "ds.b\t" -#define DS_W "ds.w\t" -#define DS_L "ds.l\t" - -#define DEFAULT_FPID 1 - - -/* Inline Functions */ - -static INLINE char* -strcpy2 (char* dst, char* src) -{ - while ((*dst++ = *src++) != 0) - ; - return --dst; + return fp; } - /* - Check displacement of Relative branch - - return FALSE; short で済む displacement が word の場合 - もしくは、short||word で済む displacement が long の場合 - return TRUE; サイズが省略可能な場合. + アセンブリソースを出力する - as.xのバグへの対応は削除(1997/10/10). - jmp,jsrはcode.size==NOTHINGである為、無関係(呼び出しても無害). + input: + xfilename : execute file name + sfilename : output file name + filedate : execute file' time stamp + argc : same to argc given to main() // 現在未使用 + argv : same to argv given to main() */ +extern void generate(char* xfilename, char* sfilename, time_t filedate, + const char* argv0, char* cmdline) { + // ヘッダファイルが存在しない場合に空の出力ファイルが残らないよう、先に開く + FILE* fpHeader = open_header_file(); -static INLINE boolean -check_displacement (address pc, disasm* code) -{ - long dist = (ULONG)code->jmp - (ULONG)pc; - unsigned char c = code->opecode[0]; - - /* bra, bsr, bcc */ - if (c == 'b') { - if (code->size == WORDSIZE) - return ((dist <= 127) && (-dist <= 128 + 2)) ? FALSE : TRUE; - if (code->size == LONGSIZE) - return ((dist <= 32767) && (-dist <= 32768 + 2)) ? FALSE : TRUE; - return TRUE; - } + Current_Mputype = MIN_BIT(Dis.mpu); + Dis.needString = TRUE; + openOutputFile(sfilename, Dis.outputSplitByte, NULL); - /* dbcc, fdbcc, pdbcc : always 16bit displacement */ - if ((c == 'd') || (code->opecode[1] == (char)'d')) { - return TRUE; - } - - /* fbcc, pbcc : 16bit or 32bit displacement */ - { - if (code->size == LONGSIZE) - return ((dist <= 32767) && (-dist <= 32768 + 2)) ? FALSE : TRUE; - return TRUE; - } + Dis.actions->outputHeader(xfilename, filedate, argv0, cmdline, fpHeader); + if (fpHeader) fclose(fpHeader); + Dis.actions->generate(sfilename); - /* NOT REACHED */ + closeOutputFile(TRUE); } +// セクション疑似命令を出力する +static void outputSection(char* section) { + if (section == NULL) return; -/* - - アセンブリソースを出力する + otherDirective(section); + outputBlank(); +} - input: - xfilename : execute file name - sfilename : output file name - filedate : execute file' time stamp - argc : same to argc given to main() // 現在未使用 - argv : same to argv given to main() +// 必要なら出力ファイルを切り換える +static void switchFile(char* sfilename, int type, int* currentType) { + if (Dis.outputSplitByte == 0) return; + if (type == XDEF_TEXT) return; -*/ -extern void -generate (char* xfilename, char* sfilename, - time_t filedate, int argc, char* argv[]) -{ - - /* ニーモニックは必要 */ - Disasm_String = TRUE; - Current_Mputype = MIN_BIT (MPU_types); - - if (option_x) - Atab += 2; - - init_output (); - output_file_open (sfilename, 0); - -#ifdef __LIBC__ - /* 標準出力に書き込む場合、標準エラー出力と出力先が同じ場合は */ - /* ソースコード出力中の表示を抑制する */ - if (is_confuse_output ()) { - eputc ('\n'); - option_q = TRUE; - } -#endif + // .bss -> .stackは切り換えずに同じファイル(".bss")に出力する + if (type == XDEF_STACK && *currentType == XDEF_BSS) return; - makeheader (xfilename, filedate, argv[0], COMMAND_LINE); + closeOutputFile(FALSE); + openOutputFile(sfilename, Dis.outputSplitByte, + (type == XDEF_DATA) ? ".dat" : ".bss"); + *currentType = type; +} -#ifdef OSKDIS - oskdis_gen (); -#else - { - lblbuf* lptr = next (BeginTEXT); +// 空のセクションかどうかを返す +// サイズが0バイト、シンボルが存在しなければ空。 +static boolean isEmptySection(address start, address end, int type) { + if (start != end) return FALSE; + if (symbol_search2(start, type) != NULL) return FALSE; - lptr = gen ("\t.text" CR CR, BeginDATA, lptr, XDEF_TEXT); - lptr = gen ("\t.data" CR CR, BeginBSS, lptr, XDEF_DATA); - lptr = gen2 ("\t.bss" CR CR, BeginSTACK, lptr, XDEF_BSS); - lptr = gen2 ("\t.stack" CR CR, Last, lptr, XDEF_STACK); + return TRUE; +} - /* 末尾にある属性 0 のシンボルを出力する */ - SectionType = (UWORD)0; - label_line_out_last (lptr->label, lptr->mode); +// 1セクションを出力する +// 引数: +// section: セクション疑似命令("\t.text"~"\t.stack")、OSKDISの場合はNULL +// end : 終了アドレス +// lptr : 開始アドレス +// type : セクション番号(XDEF_TEXT~XDEF_STASCK) +lblbuf* generateSection(char* sfilename, char* section, address end, + lblbuf* lptr, int type, int* currentType) { + lblbuf* nextLabel; + uint8_t isBSS; + + // 空のセクションなら、セクション疑似命令も出力しない + if (isEmptySection(lptr->label, end, type)) return lptr; + + outputBlank(); + switchFile(sfilename, type, currentType); + outputSection(section); + + isBSS = (type >= XDEF_BSS); + while (lptr->label < end) { + address pc = lptr->label; + lblmode mode = lptr->mode; - output_opecode (CR "\t.end\t"); - label_op_out (Head.exec); + nextLabel = lptr; + do { + nextLabel = Next(nextLabel); + } while (nextLabel->shift); // 命令の中を指すラベルを飛ばす + + label_line_out(pc, mode, type, FALSE, + isPROLABEL(mode) ? LINETYPE_TEXT : LINETYPE_DATA); + + if (isPROLABEL(mode)) { + textgen(pc, nextLabel->label); + } else if (isTABLE(mode)) { + pc = tablegen(pc, type); + if (pc != nextLabel->label) + internalError(__FILE__, __LINE__, "pc != nextLabel->label."); + } else if (isBSS) { + bssgen(pc, nextLabel->label, lblmodeOpesize(mode)); + } else { + datagen(pc, nextLabel->label, lblmodeOpesize(mode)); } -#endif /* !OSKDIS */ - newline (Last); - output_file_close (); -} + lptr = nextLabel; + } + // セクション末尾のラベル(外部定義シンボルのみ) + label_line_out(lptr->label, lptr->mode, type, TRUE, LINETYPE_OTHER); -/* + return lptr; +} - 1セクションを出力する +// 直後に空行を出力する命令か調べる +// applyToBra: DisVars::B (-B オプションの値) +static boolean isBlankLineNeeded(disasm* code, uint8_t applyToBra) { + switch (code->opeType) { + default: + break; - input: - section : section name ; ".text" or ".data" - end : block end address - lptr : lblbuf* ( contains block start address ) + case JMPOP: + if (applyToBra) return TRUE; + if ((code->codeflags & CODEFLAG_BRAOP) == 0) return TRUE; + break; -*/ -private lblbuf* -gen (char* section, address end, lblbuf* lptr, int type) -{ - address pc = lptr->label; - lblmode nmode = lptr->mode; - - /* 0 バイトのセクションで、かつシンボルが存在しなければ */ - /* セクション疑似命令も出力しない. */ - if (pc == end && !symbol_search2 (pc, type)) - return lptr; - - /* 必要なら出力ファイルを *.dat に切り換える */ - output_file_open_next (type); - - outputa (CR); - output_opecode (section); - SectionType = (UWORD)type; - - while (pc < end) { - lblmode mode = nmode; - address nlabel; - - do { - lptr = Next (lptr); - } while (lptr->shift); - nlabel = lptr->label; - nmode = lptr->mode; - - label_line_out (pc, mode); - - if (isPROLABEL (mode)) { - textgen (pc, nlabel); - pc = nlabel; - } else if (isTABLE (mode)) { - pc = tablegen (pc, nlabel, mode); - lptr = next (pc); - nmode = lptr->mode; - } else { - datagen (pc, nlabel, mode & 0xff); - pc = nlabel; - } - } + case RTSOP: + return TRUE; + } - /* セクション末尾のラベル(外部定義シンボルのみ) */ - label_line_out_last (pc, nmode); + return FALSE; +} - return lptr; +// オペコードに付けるサイズを決定する +static opesize decideOutputSize(disasm* code) { + if (code->opeType == OTHER) { + if (code->size == code->default_size && Dis.N) return NOTHING; + } else if (code->jmpea == PCDISP) { + switch (Dis.branchSize) { + default: + break; + case BRANCH_SIZE_AUTO: // -b0 可能ならサイズ省略 + // JMP, JSRはsize==NOTHINGなので考慮しなくてもNOTHINGが返される + if ((code->codeflags & CODEFLAG_NEED_OPESIZE) == 0) return NOTHING; + break; + case BRANCH_SIZE_OMIT: // -b1 常にサイズ省略 + return NOTHING; + break; + } + } + + return code->size; } -#ifndef OSKDIS -/* +// オペランドをラベル化、旧表記化してバッファに書き込む +static char* operandToOldSyntax(char* p, operand* op) { + char buf[sizeof(op->operand)]; - .bss/.stack を出力する + *operandToLabel(buf, op) = '\0'; + strcpy(op->operand, buf); + syntax_new_to_old(op); + return strcpy2(p, op->operand); +} -*/ -private lblbuf* -gen2 (char* section, address end, lblbuf* lptr, int type) -{ - address pc = lptr->label; - lblmode nmode = lptr->mode; - - /* 0 バイトのセクションで、かつシンボルが存在しなければ */ - /* セクション疑似命令も出力しない. */ - if (pc == end && !symbol_search2 (pc, type)) - return lptr; - - /* 必要なら出力ファイルを *.bss に切り換える */ - output_file_open_next (type); - - outputa (CR); - output_opecode (section); - SectionType = (UWORD)type; - - while (pc < end) { - lblmode mode = nmode; - address nlabel; - - lptr = Next (lptr); - nlabel = lptr->label; - nmode = lptr->mode; - - label_line_out (pc, mode); - - if (isTABLE (mode)) { - pc = tablegen (pc, nlabel, mode); - lptr = next (pc); - nmode = lptr->mode; - } else { - bssgen (pc, nlabel, mode & 0xff); - pc = nlabel; - } - } +// オペランドを結合してバッファに書き込む(旧表記) +static char* buildOperandsOldSyntax(char* p, disasm* code) { + if (code->op1.operand[0] == '\0') return p; + *p++ = '\t'; + p = operandToOldSyntax(p, &code->op1); + + if (code->op2.operand[0] == '\0') return p; + if ((code->op2.flags & OPFLAG_COMBINE) == 0) *p++ = ','; + p = operandToOldSyntax(p, &code->op2); - /* セクション末尾のラベル(外部定義シンボルのみ) */ - label_line_out_last (pc, nmode); + if (code->op3.operand[0] == '\0') return p; + if ((code->op3.flags & OPFLAG_COMBINE) == 0) *p++ = ','; + p = operandToOldSyntax(p, &code->op3); - return lptr; + if (code->op4.operand[0] == '\0') return p; + if ((code->op4.flags & OPFLAG_COMBINE) == 0) *p++ = ','; + return operandToOldSyntax(p, &code->op3); } +// オペランドを結合してバッファに書き込む +static char* buildOperands(char* p, disasm* code) { + if (code->op1.operand[0] == '\0') return p; + *p++ = '\t'; + p = operandToLabel(p, &code->op1); -/* + if (code->op2.operand[0] == '\0') return p; + if ((code->op2.flags & OPFLAG_COMBINE) == 0) *p++ = ','; + p = operandToLabel(p, &code->op2); - 必要なら出力ファイルを切り換える. + if (code->op3.operand[0] == '\0') return p; + if ((code->op3.flags & OPFLAG_COMBINE) == 0) *p++ = ','; + p = operandToLabel(p, &code->op3); -*/ -private void -output_file_open_next (int sect) -{ - static int now = 0; /* 最初は .text */ - int type; - - if (!option_S || sect == XDEF_TEXT) - return; - - /* .data は -1、.bss 及び .stack は -2 */ - type = (sect >= XDEF_BSS) ? -2 : -1; - - if (now != type) { - now = type; - output_file_close (); - output_file_open (NULL, now); - } + if (code->op4.operand[0] == '\0') return p; + if ((code->op4.flags & OPFLAG_COMBINE) == 0) *p++ = ','; + return operandToLabel(p, &code->op4); } -#endif /* !OSKDIS */ +// オペコードとオペランドを結合して出力する +void outputOpcodeAndOperands(disasm* code, const char* header, char* buffer) { + char* p = buffer; + *p++ = '\t'; + p = strcpy2(p, GET_OPECODE(code)); + p = write_size(p, decideOutputSize(code)); -/* - -M、-x オプションのタブ出力 - input: - tabnum : Mtab or Xtab - buffer : pointer to output buffer - return: - pointer to end of output buffer -*/ + p = Dis.oldSyntax ? buildOperandsOldSyntax(p, code) : buildOperands(p, code); + *p = '\0'; -static INLINE char* -tab_out (int tab, char* buf) -{ - int len; - unsigned char c; - - /* 行末までの長さを数える */ - for (len = 0; (c = *buf++) != '\0'; len++) - if (c == '\t') - len |= 7; - buf--; - len /= 8; /* 現在のタブ位置 */ - - /* 最低一個のタブを出力する分、ループ回数を 1 減らす */ - tab--; - - /* now, buffer points buffer tail */ - for (tab -= len; tab > 0; tab--) - *buf++ = '\t'; - - *buf++ = '\t'; - *buf++ = CommentChar; - return buf; -} + if (code->opeType == UNDEF) { + char* u = writeTabAndCommentChar(buffer, Dis.UndefTab); // Dis.Mtab + strcpy(u, "undefined inst."); + } else if ((code->codeflags & CODEFLAG_NEED_COMMENT) && Dis.M) { + byteout_for_moption(code, buffer); + } + if (Dis.x) byteout_for_xoption(code->pc, code->bytes, buffer); + + if (header) { + outputText2(code->pc, header, buffer); + } else { + // -vでない通常モードの処理をすこしでも速くする + outputText(code->pc, buffer); + } + + // rts、jmp、bra の直後に空行を出力する + // ただし、-B オプションが無指定なら bra は除く + if (isBlankLineNeeded(code, Dis.B)) outputBlank(); +} /* テキストブロックを出力する input : - pc : text begin address + from : text begin address pcend : text end address return : pcend */ -private address -textgen (address pc, address pcend) -{ - short made_to_order = (!sp_a7_flag || Old_syntax || option_U); - address store = pc + Ofst; - - charout ('.'); - PCEND = pcend; - - while (pc < pcend) { - static char prev_fpuid = DEFAULT_FPID; - disasm code; - opesize size; - address store0 = store; - address pc0 = pc; - char buffer[128]; - char* ptr; - char* l; /* IOCS コール名 */ - - store += dis (store, &code, &pc); - - /* .cpu 切り換え */ - if ((code.mputypes & Current_Mputype) == 0) { - Current_Mputype = MIN_BIT (code.mputypes & MPU_types); - output_opecode (PSEUDO CPU); - outputa (mputype_numstr (Current_Mputype)); - newline (pc0); - } - - /* .fpid 切り換え */ - if ((code.fpuid >= 0) && (code.fpuid != prev_fpuid)) { - prev_fpuid = code.fpuid; - output_opecode (PSEUDO FPID); - outputfa ("%d", (int)code.fpuid); - newline (pc0); - } - - /* code.size はサイズ省略時に NOTHING に書き換えられるので */ - /* 即値のコメント出力用に、本当のサイズを保存しておく */ - size = code.size; - - if (code.flag == OTHER) { - if (size == code.default_size && option_N) - code.size = NOTHING; - } - else if (code.jmpea == PCDISP) { - if ((Generate_SizeMode == SIZE_NORMAL && size != NOTHING - && check_displacement (pc, &code)) /* -b0: 可能ならサイズ省略 */ - || Generate_SizeMode == SIZE_OMIT) /* -b1: 常にサイズ省略 */ - code.size = NOTHING; - } - - if (made_to_order) - modify_operand (&code); - else { /* "sp"、小文字、新表記なら特別扱い */ - if (code.op1.operand[0]) { - a7toSP (&code.op1); - labelchange (&code, &code.op1); - - if (code.op2.operand[0]) { - a7toSP (&code.op2); - labelchange (&code, &code.op2); - - if (code.op3.operand[0]) { - a7toSP (&code.op3); - labelchange (&code, &code.op3); - - if (code.op4.operand[0]) { - a7toSP (&code.op4); - labelchange (&code, &code.op4); - } - } - } - } - } - - ptr = buffer; - *ptr++ = '\t'; - -#ifdef OSKDIS -#define OS9CALL(n, v, t) (peekw (store0) == (n) && (v) < 0x100 && (l = (t)[(v)])) - if (OS9CALL (0x4e40, code.op1.opval, OS9label)) /* trap #0 (OS9) */ - strcat (strcpy (ptr, "OS9\t"), l); - else if (OS9CALL (0x4e4d, code.op2.opval, CIOlabel)) /* trap #13 (CIO$Trap) */ - strcat (strcpy (ptr, "TCALL\tCIO$Trap,"), l); - else if (OS9CALL (0x4e4f, code.op2.opval, MATHlabel)) /* trap #15 (T$Math) */ - strcat (strcpy (ptr, "TCALL\tT$Math,"), l); -#else - if (*(UBYTE*)store0 == 0x70 /* moveq #imm,d0 + trap #15 なら */ - && peekw (store) == 0x4e4f /* IOCS コールにする */ - && IOCSlabel && (l = IOCSlabel[*(UBYTE*)(store0 + 1)]) != NULL - && (pc < pcend)) { - ptr = strcpy2 (ptr, IOCSCallName); - *ptr++ = '\t'; - strcpy2 (ptr, l); - store += 2; - pc += 2; - code.opflags &= ~FLAG_NEED_COMMENT; /* moveq のコメントは付けない */ - } -#endif /* OSKDIS */ - else { - ptr = strcpy2 (ptr, code.opecode); - if (code.size < NOTHING) { - *ptr++ = '.'; - *ptr++ = opsize[code.size]; - } - - if (code.op1.operand[0]) { - *ptr++ = '\t'; - ptr = strcpy2 (ptr, code.op1.operand); - - if (code.op2.operand[0]) { - if (code.op2.ea != BitField && code.op2.ea != KFactor) - *ptr++ = ','; - ptr = strcpy2 (ptr, code.op2.operand); - - if (code.op3.operand[0]) { - if (code.op3.ea != BitField && code.op3.ea != KFactor) - *ptr++ = ','; - ptr = strcpy2 (ptr, code.op3.operand); - - if (code.op4.operand[0]) { - if (code.op4.ea != BitField && code.op4.ea != KFactor) - *ptr++ = ','; - strcpy2 (ptr, code.op4.operand); - } - } - } - } - } - - if (code.flag == UNDEF) { /* -M と同じ桁に出力 */ - strcpy (tab_out (Mtab, buffer), "undefined inst."); - } - - else if ((code.opflags & FLAG_NEED_COMMENT) && option_M) - byteout_for_moption (pc0, buffer, size); - - if (option_x) - byteout_for_xoption (pc0, pc - pc0, buffer); - - outputa (buffer); - newline (pc0); - - /* rts、jmp、bra の直後に空行を出力する */ - /* ただし、-B オプションが無指定なら bra は除く */ - if ((code.opflags & FLAG_NEED_NULSTR) - && (option_B || (code.opecode[0] != 'b' && code.opecode[0] != 'B'))) - outputa (CR); +static address textgen(address from, address pcend) { + DisParam disp; + disasm* code = &disp.code; + char buffer[128 + sizeof(disp.code.op1.operand) * 4]; - } + charout('.'); - return pcend; -} + setDisParamPcPtr(&disp, from, Dis.Ofst); + disp.pcEnd = pcend; + while (disp.pc < pcend) { + static int8_t prev_fpuid = CPID_FPU; + dis(&disp); -/* - - 出力形式の指定に従ってオペランドを修正する. + // .cpu 切り換え + if ((code->mputypes & Current_Mputype) == 0) { + Current_Mputype = MIN_BIT(code->mputypes & Dis.mpu); + outputDirective2(LINETYPE_TEXT, disp.pc, OpString.cpu, + mputype_numstr(Current_Mputype)); + } - 1)レジスタ名"a7"を"sp"にする("za7"も"zsp"にする). - 2)オペコード及び各オペランドを大文字にする. - 3)ラベルに変更できる数値はラベルにする. - 4)アドレッシング表記を古い書式にする. + // .fpid 切り換え + if ((code->fpuid >= 0) && (code->fpuid != prev_fpuid)) { + char buf[2] = {'0' + code->fpuid, '\0'}; + prev_fpuid = code->fpuid; + outputDirective2(LINETYPE_TEXT, disp.pc, OpString.fpid, buf); + } -*/ + outputOpcodeAndOperands(code, NULL, buffer); + } -extern void -modify_operand (disasm *code) -{ - int upper_flag = (option_U && !(code->opflags & FLAG_CANNOT_UPPER)); - - if (upper_flag) - strupr (code->opecode); - - if (code->op1.operand[0]) { - if (sp_a7_flag) a7toSP (&code->op1); - if (upper_flag) strupr (code->op1.operand); - labelchange (code, &code->op1); - if (Old_syntax) syntax_new_to_old (&code->op1); - - if (code->op2.operand[0]) { - if (sp_a7_flag) a7toSP (&code->op2); - if (upper_flag) strupr (code->op2.operand); - labelchange (code, &code->op2); - if (Old_syntax) syntax_new_to_old (&code->op2); - - if (code->op3.operand[0]) { - if (sp_a7_flag) a7toSP (&code->op3); - if (upper_flag) strupr (code->op3.operand); - labelchange (code, &code->op3); - if (Old_syntax) syntax_new_to_old (&code->op3); - - if (code->op4.operand[0]) { - if (sp_a7_flag) a7toSP (&code->op4); - if (upper_flag) strupr (code->op4.operand); - labelchange (code, &code->op4); - if (Old_syntax) syntax_new_to_old (&code->op4); - } - } - } - } + return pcend; } +// 単なる逆アセンブル出力(-vオプション指定時) +extern void disasmlist(char* sfilename) { + DisParam disp; + address pcend = Dis.beginTEXT + Dis.text; + char buffer[128 + sizeof(disp.code.op1.operand) * 4]; -/* + Dis.needString = TRUE; + openOutputFile(sfilename, Dis.outputSplitByte, NULL); - a7 表記を sp 表記に変える + setDisParamPcPtr(&disp, Dis.beginTEXT, Dis.Ofst); + disp.pcEnd = pcend; -*/ -private void -a7toSP (operand* op) -{ - char *ptr = op->operand; - - switch (op->ea) { - case AregD: - break; - case AregID: - case AregIDPI: - ptr++; - break; - case AregIDPD: - ptr += 2; - break; - case AregDISP: - ptr = strchr (ptr, ',') + 1; - break; - case AregIDX: - ptr = strrchr (ptr, ',') - 2; - if (ptr[1] == '7') { - ptr[0] = 's'; - ptr[1] = 'p'; - } - ptr += 3; - break; - case PCIDX: - ptr = strrchr (ptr, ',') + 1; - break; - - case RegPairID: - ptr++; - if (ptr[0] == 'a' && ptr[1] == '7') { - ptr[0] = 's'; - ptr[1] = 'p'; - } - ptr += 5; - break; - - case PCIDXB: - case PCPOSTIDX: - case PCPREIDX: - case AregIDXB: - case AregPOSTIDX: - case AregPREIDX: - if (*++ptr == '[') - ptr++; - while (1) { - if (*ptr == 'z') - ptr++; - if (ptr[0] == 'a' && ptr[1] == '7') { - *ptr++ = 's'; - *ptr++ = 'p'; - } - if ((ptr = strchr (ptr, ',')) == NULL) - return; - ptr++; - } - return; + while (disp.pc < pcend) { + char adrs[12]; - default: - return; - } - - if (ptr[0] == 'a' && ptr[1] == '7') { - *ptr++ = 's'; - *ptr++ = 'p'; - } + itox6(adrs, (ULONG)disp.pc); + dis(&disp); + outputOpcodeAndOperands(&disp.code, adrs, buffer); + } + closeOutputFile(TRUE); } +// アドレッシング形式を旧式の表記に変える +static void syntax_new_to_old(operand* op) { + char* optr = op->operand; + char* p; + + switch (op->ea) { + case AbShort: /* (abs)[.w] -> abs[.w] */ + case AbLong: /* (abs)[.l] -> abs[.l] */ + p = strchr(optr, ')'); + strcpy(p, p + 1); + strcpy(optr, optr + 1); + break; + + case AregIDX: // (d8,an,ix) -> d8(an,ix) + if ((p = strchr(optr, ',')) == NULL) { + break; // ありえないが念のため + } + if (strchr(p + 1, ',') == NULL) { + break; // (an,ix) ならそのまま + } + *p = '('; + strcpy(optr, optr + 1); + break; + + case AregDISP: // (d16,an) -> d16(an) + case PCIDX: // (d8,pc,ix) -> d8(pc,ix) + case PCDISP: // (d16,pc) -> d16(pc) + if ((p = strchr(optr, ',')) == NULL) { + break; // 相対分岐命令 + } + *p = '('; + strcpy(optr, optr + 1); + break; -/* - - アドレッシング形式を旧式の表記に変える. + default: + break; + } +} -*/ +// opesizeに対応する.dsのサイズと単位バイト数を返す +SizeLength getSizeBytes(opesize size) { + switch (size) { + default: + break; -private void -syntax_new_to_old (operand *op) -{ - char *optr = op->operand; - char *p; - - switch (op->ea) { - case AbShort: /* (abs)[.w] -> abs[.w] */ - case AbLong: /* (abs)[.l] -> abs[.l] */ - p = strchr (optr, ')'); - strcpy (p, p + 1); - strcpy (optr, optr + 1); - break; - - case AregIDX: /* (d8,an,ix) -> d8(an,ix) */ - if (optr[1] == 'a' || optr[1] == 'A') - break; /* ディスプレースメント省略 */ - /* fall through */ - case AregDISP: /* (d16,an) -> d16(an) */ - case PCIDX: /* (d8,pc,ix) -> d8(pc,ix) */ - case PCDISP: /* (d16,pc) -> d16(pc) */ - if ((p = strchr (optr, ',')) == NULL) - break; /* 相対分岐命令 */ - *p = '('; - strcpy (optr, optr + 1); - break; - - default: - break; - } + case WORDSIZE: + case RELTABLE: + return (SizeLength){WORDSIZE, 2}; + case LONGSIZE: + case RELLONGTABLE: + return (SizeLength){LONGSIZE, 4}; + case QUADSIZE: + return (SizeLength){QUADSIZE, 8}; + case SINGLESIZE: + return (SizeLength){SINGLESIZE, 4}; + case DOUBLESIZE: + return (SizeLength){DOUBLESIZE, 8}; + case EXTENDSIZE: + return (SizeLength){EXTENDSIZE, 12}; + case PACKEDSIZE: + return (SizeLength){PACKEDSIZE, 12}; + } + + return (SizeLength){BYTESIZE, 1}; } - +// .dsのサイズと総バイト数から、正規化した.dsのサイズと単位数を返す +SizeLength getSizeLength(SizeLength sb, int bytes) { + if (sb.length >= 2) { + // 単位バイト数の倍数ならそのサイズで出力 + int units = bytes / sb.length; + if (units * sb.length == bytes) return (SizeLength){sb.size, units}; + } + return (SizeLength){BYTESIZE, bytes}; +} /* @@ -817,30 +499,30 @@ syntax_new_to_old (operand *op) pcend */ -private address -datagen (address pc, address pcend, opesize size) -{ - address next_adrs; - - while (pc < pcend) { - if ((next_adrs = nearadrs (pc)) < pcend) { - if (next_adrs != pc) { - datagen_sub (pc, next_adrs, size); - pc = next_adrs; - } - output_opecode (PSEUDO DC_L); - label_op_out ((address) peekl (next_adrs + Ofst)); - newline (next_adrs); - pc += 4; - } - else { - datagen_sub (pc, pcend, size); - pc = pcend; - } +static address datagen(address pc, address pcend, opesize size) { + SymbolLabelFormula slfml; + + while (pc < pcend) { + address next_adrs = nearadrs(pc); + + if (pcend <= next_adrs) { + // ブロック内にアドレス依存データがなければまるごと出力して終わり + datagen_sub(pc, pcend, size); + return pcend; } - return pcend; -} + if (next_adrs != pc) { + // ブロック先頭からアドレス依存データの手前までを出力 + datagen_sub(pc, next_adrs, size); + pc = next_adrs; + } + // アドレス依存データを .dc.l Lxxxxxx として出力 + makeSymLabFormula(&slfml, (address)peekl(next_adrs + Dis.Ofst)); + outputData3(pc, OpString.dc[LONGSIZE], slfml.symbol, slfml.expr); + pc += 4; + } + return pcend; +} /* @@ -853,556 +535,385 @@ datagen (address pc, address pcend, opesize size) size : data size */ -private void -datagen_sub (address pc, address pcend, opesize size) -{ - switch (size) { +static void datagen_sub(address pc, address pcend, opesize size) { + switch (size) { case STRING: - strgen (pc, pcend); - break; + strgen(pc, pcend); + break; case RELTABLE: - relgen (pc, pcend); - break; case RELLONGTABLE: - rellonggen (pc, pcend); - break; + relgen(pc, pcend, size); + break; case ZTABLE: - zgen (pc, pcend); - break; -#ifdef OSKDIS + zgen(pc, pcend); + break; + case WTABLE: - wgen (pc, pcend); - break; -#endif /* OSKDIS */ + Dis.actions->datagenWTable(pc, pcend); + break; + default: - dataout (pc, pcend - pc, size); - break; - } + dataout(pc, pcend - pc, size); + break; + } } - -/* - - データブロックの出力 - - input : - pc : data begin address - byte : number of bytes - size : data size ( UNKNOWN , BYTESIZE , WORDSIZE , LONGSIZE only ) - -*/ -private void -dataout (address pc, ULONG byte, opesize size) -{ - address store = pc + Ofst; - int odd_flag = (int)store & 1; - - DEBUG_PRINT (("dataout : store %x byte %x size %x\n", store, byte, size)); - charout ('#'); - - switch (size) { - case WORDSIZE: - if (odd_flag || (byte % sizeof (UWORD))) - break; - if (byte == sizeof (UWORD)) { - output_opecode (PSEUDO DC_W); -#if 0 - outputax4_without_0supress (peekw (store)); -#else - outputaxd (peekw (store), 4); -#endif - newline (pc); - } else - wordout (pc, byte); - return; - - case LONGSIZE: - if (odd_flag || (byte % sizeof (ULONG))) - break; - if (byte == sizeof (ULONG)) { - output_opecode (PSEUDO DC_L); -#if 0 - outputax8_without_0supress (peekl (store)); -#else - outputaxd (peekl (store), 8); -#endif - newline (pc); - } else - longout (pc, byte); - return; - - case QUADSIZE: - if (odd_flag || (byte % sizeof (quadword))) - break; - quadout (pc, byte); - return; - - case SINGLESIZE: - if (odd_flag || (byte % sizeof (float))) - break; - floatout (pc, byte); - return; - - case DOUBLESIZE: - if (odd_flag || (byte % sizeof (double))) - break; - doubleout (pc, byte); - return; - - case EXTENDSIZE: - if (odd_flag || (byte % sizeof (long double))) - break; - extendout (pc, byte); - return; - - case PACKEDSIZE: - if (odd_flag || (byte % sizeof (packed_decimal))) - break; - packedout (pc, byte); - return; - - case BYTESIZE: - if (byte == sizeof (UBYTE)) { - output_opecode (PSEUDO DC_B); -#if 0 - outputax2_without_0supress (*(UBYTE*)store); -#else - outputaxd (*(UBYTE*)store, 2); -#endif - newline (pc); - return; - } - break; - - default: - break; - } - - byteout (pc, byte, FALSE); +typedef enum { + COMPRESS_NONE, + COMPRESS_DCB, // .dcb.b (同じ値の繰り返し) + COMPRESS_DS, // .ds.b (値がすべて0) +} CompressMode; + +// データ領域が圧縮可能かを調べる(バイト単位) +static CompressMode getCompressModeByte(codeptr ptr, size_t bytes) { + UBYTE value = peekb(ptr); + int i; + + // [1] [2] [3] がすべて [0] と同じ値であることを確認 + bytes -= 1; + for (i = 1; i <= 3; i += 1) { + if (value != peekb(ptr + i)) return COMPRESS_NONE; + if (--bytes == 0) return (value == 0) ? COMPRESS_DS : COMPRESS_DCB; + } + + // 残りがあればロングワード単位で比較する + if (bytes) { + if (memcmp(ptr, ptr + 4, bytes) != 0) return COMPRESS_NONE; + } + return (value == 0) ? COMPRESS_DS : COMPRESS_DCB; } +// データ領域が圧縮可能かを調べる(ワード単位) +static CompressMode getCompressModeWord(codeptr ptr, size_t bytes) { + UWORD value = peekw(ptr); -/* - - データブロックの出力 + // [1] が [0] と同じ値であることを確認 + if (value != peekw(ptr + 2)) return COMPRESS_NONE; - input : - pc : data begin address - byte : number of bytes - roption_flag : hex comment to string flag - ( case this function is used for string output ) - -*/ -private void -byteout (address pc, ULONG byte, boolean roption_flag) -{ - address store = pc + Ofst; - -#ifndef OSKDIS /* OS-9/68K の r68 には dcb に相当する疑似命令が無い */ - if (!roption_flag - && (byte >= 1 * 2) && Compress_len && (byte >= Compress_len)) { - UBYTE* ptr = (UBYTE*) store; - int val = *ptr; - - while (ptr < store + byte && *ptr == val) - ptr++; - if (ptr == store + byte) { - if (val == 0) { - output_opecode (PSEUDO DS_B); - outputfa ("%d", byte); - } else { - output_opecode (PSEUDO DCB_B); - outputfa ("%d,", byte); - outputax2_without_0supress (val); - } - newline (pc); - return; - } - } -#endif /* !OSKDIS */ - - { - ULONG max = (byte - 1) / Data_width; - ULONG mod = (byte - 1) % Data_width; - int i, j; - - for (i = 0; i <= max; i++) { - if (roption_flag) { - static char comment[] = ";\t\t"; - comment[0] = CommentChar; - outputa (comment); - } else - output_opecode (PSEUDO DC_B); - - for (j = 1; j < (i == max ? mod + 1 : Data_width); j++) { - outputax2_without_0supress (*store++); - outputca (','); - } - outputax2_without_0supress (*store++); - newline (pc); - pc += Data_width; - } - } + // 残りがあればロングワード単位で比較する + if (bytes > 4) { + if (memcmp(ptr, ptr + 4, bytes - 4) != 0) return COMPRESS_NONE; + } + return (value == 0) ? COMPRESS_DS : COMPRESS_DCB; } - -private void -wordout (address pc, ULONG byte) -{ - address store = pc + Ofst; - -#ifndef OSKDIS - if ((byte >= sizeof (UWORD) * 2) && Compress_len && (byte >= Compress_len)) { - UWORD* ptr = (UWORD*) store; - int val = peekw (ptr); - - while ((address) ptr < store + byte && peekw (ptr) == val) - ptr++; - if ((address) ptr == store + byte) { - if (val == 0) { - output_opecode (PSEUDO DS_W); - outputfa ("%d", byte / sizeof (UWORD)); - } else { - output_opecode (PSEUDO DCB_W); - outputfa ("%d,", byte / sizeof (UWORD)); - outputax4_without_0supress (val); - } - newline (pc); - return; - } - } -#endif /* !OSKDIS */ - - { - int datawidth = (Data_width + sizeof (UWORD) - 1) / sizeof (UWORD); - ULONG max = (byte / sizeof (UWORD) - 1) / datawidth; - ULONG mod = (byte / sizeof (UWORD) - 1) % datawidth; - int i, j; - - for (i = 0; i <= max; i++) { - output_opecode (PSEUDO DC_W); - for (j = 1; j < (i == max ? mod + 1 : datawidth); j++) { - outputax4_without_0supress (peekw (store)); - store += sizeof (UWORD); - outputca (','); - } - outputax4_without_0supress (peekw (store)); - store += sizeof (UWORD); - newline (pc); - pc += datawidth * sizeof (UWORD); - } - } +// データ領域が圧縮可能かを調べる +// bytesPerUnit == 1、2または4の倍数であること +static CompressMode getCompressMode(codeptr ptr, size_t bytes, int bytesPerUnit, + int units) { + if ((int)bytes < Dis.compressLen || Dis.compressLen == 0) + return COMPRESS_NONE; + if (units < 2) return COMPRESS_NONE; + + if (bytesPerUnit == 1) return getCompressModeByte(ptr, bytes); + if (bytesPerUnit == 2) return getCompressModeWord(ptr, bytes); + + // bytesPerUnit >= 4 + if (memcmp(ptr, ptr + bytesPerUnit, bytes - bytesPerUnit) != 0) + return COMPRESS_NONE; + + // 値が0かどうかを確認する + do { + if (peekl(ptr) != 0) return COMPRESS_DCB; + bytesPerUnit -= 4; + } while (bytesPerUnit); + return COMPRESS_DS; } +// データを文字列化してバッファに書き込む +// 文字列末尾('\0')のアドレスを返す +static char* stringifyData(char* buffer, codeptr store, opesize size) { + char* p = buffer; -private void -longout (address pc, ULONG byte) -{ - address store = pc + Ofst; - -#ifndef OSKDIS - if ((byte >= sizeof (ULONG) * 2) && Compress_len && (byte >= Compress_len)) { - ULONG* ptr = (ULONG*) store; - int val = peekl (ptr); - - while ((address) ptr < store + byte && peekl (ptr) == val ) - ptr++; - if ((address) ptr == store + byte) { - if (val == 0) { - output_opecode (PSEUDO DS_L); - outputfa ("%d", byte / sizeof (ULONG)); - } else { - output_opecode (PSEUDO DCB_L); - outputfa ("%d,", byte / sizeof (ULONG)); - outputax8_without_0supress (val); - } - newline (pc); - return; - } - } -#endif /* !OSKDIS */ + switch (size) { + default: + case BYTESIZE: + *p++ = '$'; + return itox2_without_0supress(p, peekb(store)); - { - int datawidth = (Data_width + sizeof (ULONG) - 1) / sizeof (ULONG); - ULONG max = (byte / sizeof (ULONG) - 1) / datawidth; - ULONG mod = (byte / sizeof (ULONG) - 1) % datawidth; - int i, j; - - for (i = 0; i <= max; i++) { - output_opecode (PSEUDO DC_L); - for (j = 1; j < (i == max ? mod + 1 : datawidth); j++) { - outputax8_without_0supress (peekl(store)); - store += sizeof (ULONG); - outputca (','); - } - outputax8_without_0supress (peekl (store)); - store += sizeof (ULONG); - newline (pc); - pc += datawidth * sizeof (ULONG); - } - } -} + case WORDSIZE: + *p++ = '$'; + return itox4_without_0supress(p, peekw(store)); + case LONGSIZE: + *p++ = '$'; + return itox8_without_0supress(p, peekl(store)); -private void -quadout (address pc, ULONG byte) -{ - quadword* store = (quadword*)(pc + Ofst); - char buf[64]; - int i = (byte / sizeof(quadword)); - -#ifndef OSKDIS - if ((i >= 2) && Compress_len && (byte >= Compress_len) - && (memcmp (store, store + 1, byte - sizeof(quadword)) == 0)) { - fpconv_q (buf, store); - output_opecode (PSEUDO DCB_Q); - outputfa ("%d,%s", i, buf); - newline (pc); - return; - } -#endif + case QUADSIZE: + return stringifyQuadWord(p, (quadword*)store); - do { - fpconv_q (buf, store++); - output_opecode (PSEUDO DC_Q); - outputa (buf); - newline (pc); - pc += sizeof(quadword); - } while (--i); -} + case SINGLESIZE: + return fpconv_s(p, store); + case DOUBLESIZE: + return fpconv_d(p, store); -private void -floatout (address pc, ULONG byte) -{ - float* store = (float*)(pc + Ofst); - char buf[64]; - int i = (byte / sizeof(float)); - -#ifndef OSKDIS - if ((i >= 2) && Compress_len && (byte >= Compress_len) - && (memcmp (store, store + 1, byte - sizeof(float)) == 0)) { - fpconv_s (buf, store); - output_opecode (PSEUDO DCB_S); - outputfa ("%d,%s", i, buf); - newline (pc); - return; - } -#endif + case EXTENDSIZE: + return fpconv_x(p, store); - do { - fpconv_s (buf, store++); - output_opecode (PSEUDO DC_S); - outputa (buf); - newline (pc); - pc += sizeof(float); - } while (--i); + case PACKEDSIZE: + return fpconv_p(p, store); + } } - -private void -doubleout (address pc, ULONG byte) -{ - double* store = (double*)(pc + Ofst); - char buf[64]; - int i = (byte / sizeof(double)); - -#ifndef OSKDIS - if ((i >= 2) && Compress_len && (byte >= Compress_len) - && (memcmp (store, store + 1, byte - sizeof(double)) == 0)) { - fpconv_d (buf, store); - output_opecode (PSEUDO DCB_D); - outputfa ("%d,%s", i, buf); - newline (pc); - return; - } -#endif +// .dc.?を一行文字列化するのに必要なバッファサイズ +#define MAX_DC_B_BUFSIZE (4 * DATA_WIDTH_MAX) // "$xx," +#define MAX_DC_REAL_BUFSIZE (64 * 1) +#define MAX_DC_BUFSIZE MAX(MAX_DC_B_BUFSIZE, MAX_DC_REAL_BUFSIZE) + +// データブロックの出力(.dc.?) +void dataoutDc(address pc, codeptr store, opesize size, ULONG bytes, + ULONG bytesPerUnit) { + ULONG maxBytesPerLine = bytesPerUnit; + char buffer[MAX_DC_BUFSIZE + 16]; + + // バイト、ワード、ロングワードは一行に複数データを出力する + if (size <= LONGSIZE) { + // 他のサイズでも複数データ出力する場合、以下の方法では + // 12バイトサイズの端数切り上げができないので注意。 + ULONG n = (bytesPerUnit - 1); + maxBytesPerLine = (Dis.dataWidth + n) & ~n; + } + + do { + ULONG bytesPerLine = MIN(bytes, maxBytesPerLine); + ULONG rest = bytesPerLine; + char* p = buffer; do { - fpconv_d (buf, store++); - output_opecode (PSEUDO DC_D); - outputa (buf); - newline (pc); - pc += sizeof(double); - } while (--i); + p = stringifyData(p, store, size); + *p++ = ','; + store += bytesPerUnit; + rest -= bytesPerUnit; + } while (rest); + *--p = '\0'; // 末尾のカンマを消す + + outputData2(pc, OpString.dc[size], buffer); + + pc += bytesPerLine; + bytes -= bytesPerLine; + } while (bytes); } - -private void -extendout (address pc, ULONG byte) -{ - long double* store = (long double*)(pc + Ofst); - char buf[64]; - int i = (byte / sizeof(long double)); - -#ifndef OSKDIS - if ((i >= 2) && Compress_len && (byte >= Compress_len) - && (memcmp (store, store + 1, byte - sizeof(long double)) == 0)) { - fpconv_x (buf, store); - output_opecode (PSEUDO DCB_X); - outputfa ("%d,%s", i, buf); - newline (pc); - return; +// データブロックの出力 +static void dataout(address pc, ULONG bytes, opesize size) { + codeptr store = pc + Dis.Ofst; + char buffer[128]; + boolean canCompress; + CompressMode compMode; + int bytesPerUnit; + int units; + + charout('#'); + + // 頻出パターンを優先して処理する + if (size == BYTESIZE || size == UNKNOWN) { + if (bytes == 1) { + itoxd(buffer, peekb(store), 2); + outputData2(pc, OpString.dc[BYTESIZE], buffer); + return; + } + } else if (size == LONGSIZE) { + if (bytes == sizeof(ULONG) && isEven(pc)) { + itoxd(buffer, peekl(store), 8); + outputData2(pc, OpString.dc[LONGSIZE], buffer); + return; + } + } else if (size == WORDSIZE) { + if (bytes == sizeof(UWORD) && isEven(pc)) { + itoxd(buffer, peekw(store), 4); + outputData2(pc, OpString.dc[WORDSIZE], buffer); + return; + } + } + + // BYTESIZEの場合 + canCompress = TRUE; + bytesPerUnit = 1; + units = bytes; + + if (size != BYTESIZE) { + if (isOdd(pc)) { + size = BYTESIZE; + } else { + SizeLength sb = getSizeBytes(size); + SizeLength sl = getSizeLength(sb, bytes); + bytesPerUnit = sb.length; // フォールバックした場合は1に戻すこと + units = sl.length; + size = sl.size; } -#endif - do { - fpconv_x (buf, store++); - output_opecode (PSEUDO DC_X); - outputa (buf); - newline (pc); - pc += sizeof(long double); - } while (--i); + // フォールバックでBYTESIZEになった場合は圧縮しない + if (size == BYTESIZE) { + canCompress = FALSE; + bytesPerUnit = 1; + } + } + + compMode = canCompress ? getCompressMode(store, bytes, bytesPerUnit, units) + : COMPRESS_NONE; + if (compMode == COMPRESS_NONE) { + dataoutDc(pc, store, size, bytes, bytesPerUnit); + } else if (compMode == COMPRESS_DCB) { + char* p = buffer + snprintf(buffer, sizeof(buffer), "%d,", units); + stringifyData(p, store, size); + outputData2(pc, OpString.dcb[size], buffer); + } else { // COMPRESS_DS + snprintf(buffer, sizeof(buffer), "%d", units); + outputData2(pc, OpString.ds[size], buffer); + } } +// -rオプションのコメントの出力(文字列の16進数ダンプ) +static void byteout_for_roption(address pc, codeptr store, ULONG bytes) { + char buffer[MAX_DC_B_BUFSIZE + 16]; + static char comment[] = ";\t\t"; + comment[0] = Dis.commentStr[0]; -private void -packedout (address pc, ULONG byte) -{ - packed_decimal* store = (packed_decimal*)(pc + Ofst); - char buf[64]; - int i = (byte / sizeof(packed_decimal)); - -#ifndef OSKDIS - if ((i >= 2) && (memcmp (store, store + 1, byte - sizeof(packed_decimal)) == 0)) { - fpconv_p (buf, store); - output_opecode (PSEUDO DCB_P); - outputfa ("%d,%s", i, buf); - newline (pc); - return; - } -#endif + do { + ULONG bytesPerLine = MIN(bytes, (size_t)Dis.dataWidth); + ULONG rest = bytesPerLine; + char* p = buffer; do { - fpconv_p (buf, store++); - output_opecode (PSEUDO DC_P); - outputa (buf); - newline (pc); - pc += sizeof(packed_decimal); - } while (--i); + *p++ = '$'; + p = itox2_without_0supress(p, peekb(store)); + *p++ = ','; + store += 1; + rest -= 1; + } while (rest); + *--p = '\0'; // 末尾のカンマを消す + + otherDirective2(comment, buffer); + + pc += bytesPerLine; + bytes -= bytesPerLine; + } while (bytes); } +void otherDirective(const char* s) { + outputDirective(LINETYPE_OTHER, (address)0, s); +} - -/* - - 文字列の出力 - - input : - pc : string begin address - pcend : string end address - -*/ -#ifdef OSKDIS -#define QUOTE_CHAR '\"' -#define QUOTE_STR "\"" -#else -#define QUOTE_CHAR '\'' -#define QUOTE_STR "\'" -#endif /* OSKDIS */ - -#define ENTERSTR() \ - if (!strmode) { \ - if (comma) { outputa ("," QUOTE_STR); column += 2; } \ - else { outputca (QUOTE_CHAR); column++;} \ - strmode = TRUE; \ - } -#define EXITSTR() \ - if (strmode) { \ - outputca (QUOTE_CHAR); \ - column++; \ - strmode = FALSE; \ - } - -static INLINE boolean -is_sb (unsigned char* ptr) -{ - return (isprkana (ptr[0]) && ptr[0] != QUOTE_CHAR); +void otherDirective2(const char* s1, const char* s2) { + outputDirective2(LINETYPE_OTHER, (address)0, s1, s2); } -static INLINE boolean -is_mb_zen (unsigned char* ptr) -{ - return (iskanji (ptr[0]) && iskanji2 (ptr[1])); +#define ENTERSTR() \ + if (!strmode) { \ + if (comma) { \ + *p++ = comma; \ + column += 1; \ + } \ + *p++ = quoteChar; \ + column += 1; \ + strmode = TRUE; \ + } +#define EXITSTR() \ + if (strmode) { \ + *p++ = quoteChar; \ + column++; \ + strmode = FALSE; \ + } + +static boolean is_sb(char* ptr, char quoteChar) { + return (isprkana(ptr[0]) && ptr[0] != quoteChar); } -static INLINE boolean -is_mb_han (unsigned char* ptr) -{ - if (ptr[0] == 0x80 || (0xf0 <= ptr[0] && ptr[0] <= 0xf3)) { - if ((0x20 <= ptr[1] && ptr[1] <= 0x7e) - || (0x86 <= ptr[1] && ptr[1] <= 0xfd)) - return TRUE; - } - return FALSE; +static boolean is_mb_zen(char* ptr) { + return (iskanji(ptr[0]) && iskanji2(ptr[1])); } -private void -strgen (address pc, address pcend) -{ - address store = Ofst + pc; - address stend = Ofst + pcend; - - charout ('s'); - - while (store < stend) { - address store0 = store; - boolean strmode = FALSE; - int column = 0; - char comma = 0; /* 1 なら , を出力する */ - - output_opecode (PSEUDO DC_B); - - while (column < String_width && store < stend) { - - if (is_sb (store)) { - /* ANK 文字 */ - ENTERSTR(); - outputca (*(UBYTE*)store++); - column++; - } else if (is_mb_zen (store) && store + 1 < stend) { - /* 二バイト全角 */ - ENTERSTR(); - outputca (*(UBYTE*)store++); - outputca (*(UBYTE*)store++); - column += 2; - } else if (is_mb_han (store) && store + 1 < stend) { - /* 二バイト半角 */ - ENTERSTR(); - outputca (*(UBYTE*)store++); - outputca (*(UBYTE*)store++); - column++; - } else { - unsigned char c = *(UBYTE*)store++; - EXITSTR(); - if (comma) - outputca (','); - outputax2_without_0supress (c); - column += comma + 3; /* ,$xx */ - - /* \n または NUL なら改行する */ - if (store != stend && (c == '\n' || c == '\0')) { - /* ただし、後に続く NUL は全て一行に納める */ - if (*(UBYTE*)store == '\0') - ; - else - break; /* 改行 */ - } - } - comma = 1; - } - if (strmode) - outputca (QUOTE_CHAR); - - newline (store0 - Ofst); - if (option_r) - byteout (store0 - Ofst, store - store0, TRUE); - } +static boolean is_mb_han(char* ptr) { + if (ptr[0] == 0x80 || (0xf0 <= ptr[0] && ptr[0] <= 0xf3)) { + if ((0x20 <= ptr[1] && ptr[1] <= 0x7e) || + (0x86 <= ptr[1] && ptr[1] <= 0xfd)) + return TRUE; + } + return FALSE; } -#undef ENTERSTR -#undef EXITSTR -#undef QUOTE_CHAR +// 文字列の出力 +// +// input: +// pc : string begin address +// pcend: string end address +static void strgen(address pc, address pcend) { + // 最大消費パターンは、二バイト半角文字が1桁で2バイト + char buffer[STRING_WIDTH_MAX * 2 + 16]; + char* store = (char*)(Dis.Ofst + pc); + char* stend = (char*)(Dis.Ofst + pcend); + char quoteChar = Dis.quoteChar; + + charout('s'); + + while (store < stend) { + codeptr store0 = (codeptr)store; + address line; + boolean strmode = FALSE; + int column = 0; + char comma = 0; // ',' ならカンマを出力する + char* p = buffer; + + while (column < Dis.stringWidth && store < stend) { + if (is_sb(store, quoteChar)) { + // ANK 文字 + ENTERSTR(); + *p++ = *store++; + column += 1; + } else if (is_mb_zen(store) && store + 1 < stend) { + // 二バイト全角 + ENTERSTR(); + *p++ = *store++; + *p++ = *store++; + column += 2; + } else if (is_mb_han(store) && store + 1 < stend) { + // 二バイト半角 + ENTERSTR(); + *p++ = *store++; + *p++ = *store++; + column += 1; + } else { + char c = *store++; + EXITSTR(); + if (comma) { + *p++ = comma; + column += 1; + } + *p++ = '$'; + p = itox2_without_0supress(p, c); + column += 3; // strlen("$xx") + + // \n または NUL なら改行する + if (store != stend && (c == '\n' || c == '\0')) { + // ただし、後に続く NUL は全て一行に納める + if (*store == '\0') + ; + else + break; // 改行 + } + } + comma = ','; + } + if (strmode) *p++ = quoteChar; + *p = '\0'; + + line = (address)(store0 - Dis.Ofst); + outputData2(line, OpString.dc[BYTESIZE], buffer); + + if (Dis.r) + byteout_for_roption(line, store0, (ULONG)(store - (char*)store0)); + } +} +#undef ENTERSTR +#undef EXITSTR + +// 指定範囲を .dc.b で出力する +// データブロックの末尾の半端データの出力用 +void dataoutDcByte(address pc, address pcend) { + ULONG bytes = pcend - pc; + if (bytes) dataoutDc(pc, pc + Dis.Ofst, BYTESIZE, bytes, 1); +} /* @@ -1411,119 +922,53 @@ strgen (address pc, address pcend) input : pc : relative offset table begin address pcend : relative offset table end address + size: RELTABLE or RELLONGTABLE */ -private void -relgen (address pc, address pcend) -{ - char buf[256], tabletop[128]; - char* bufp; - const address pc0 = pc; - - charout ('r'); - - /* 予めバッファの先頭に .dc.w を作成しておく */ - bufp = strend (strcpy (buf, PSEUDO DC_W)); - if (option_U) - strupr (buf); - - /* -Lxxxxxx も作成しておく */ - tabletop[0] = '-'; - make_proper_symbol (&tabletop[1], pc0); - - while (pc < pcend) { - int dif = (int)(signed short) peekw (pc + Ofst); - char* p; - - if ((LONG) (pc0 + dif) < (LONG) BeginTEXT) { - make_proper_symbol (bufp, BeginTEXT); - p = strend (bufp); - *p++ = '-'; - p = itox6d (p, BeginTEXT - (pc0 + dif)); - } else if ((LONG) (pc0 + dif) > (LONG) Last) { - make_proper_symbol (bufp, Last); - p = strend (bufp); - *p++ = '+'; - p = itox6d (p, (pc0 + dif) - Last); - } else { - make_proper_symbol (bufp, pc0 + dif); - p = strend (bufp); - } - - strcpy (p, tabletop); - - /* 相対テーブルも -x でコメントを出力する */ - if (option_x) - byteout_for_xoption (pc, sizeof (WORD), buf); - - outputa (buf); - newline (pc); - - pc += sizeof (WORD); +static void relgen(address tabletop, address pcend, opesize size) { + char buf[256], minusTable[128]; + uint8_t isLong = (size == RELLONGTABLE); + ULONG bytes = isLong ? 4 : 2; + address pc; + + // 相対オフセットテーブル解析後のプログラム領域解析でテーブルの途中に + // ラベルが登録されるとテーブルの大きさが半端になることがある対策 + const address limit = pcend - bytes; + + // あらかじめバッファの先頭に .dc 疑似命令を作成しておく + // -xオプションがあるためOutputData2()で出力することができず、 + // 一行まるごとバッファに書き込む必要がある。 + char* bufp = strcpy2(buf, OpString.dc[isLong ? LONGSIZE : WORDSIZE]); + + // -Lxxxxxx も作成しておく + minusTable[0] = '-'; + make_proper_symbol(&minusTable[1], tabletop); + + charout(isLong ? 'R' : 'r'); + + for (pc = tabletop; pc <= limit; pc += bytes) { + codeptr store = pc + Dis.Ofst; + ULONG offs = isLong ? peekl(store) : (ULONG)extl(peekw(store)); + char* p = bufp; + + if (offs == 0) { + // オフセット値0の場合は .dc 0 にする + *p++ = '0'; + *p = '\0'; + } else { + p = make_proper_symbol(p, tabletop + offs); + strcpy(p, minusTable); } -} + // 相対テーブルも -x でコメントを出力する + if (Dis.x) byteout_for_xoption(pc, bytes, buf); -/* - - ロングワードなリラティブオフセットテーブルの出力 + outputData(pc, buf); + } - input : - pc : relative offset table begin address - pcend : relative offset table end address - -*/ -private void -rellonggen (address pc, address pcend) -{ - char buf[256], tabletop[128]; - char* bufp; - const address pc0 = pc; - - charout ('R'); - - /* 予めバッファの先頭に .dc.l を作成しておく */ - bufp = strend (strcpy (buf, PSEUDO DC_L)); - if (option_U) - strupr (buf); - - /* -Lxxxxxx も作成しておく */ - tabletop[0] = '-'; - make_proper_symbol (&tabletop[1], pc0); - - while (pc < pcend) { - int dif = (int) peekl (pc + Ofst); - char* p; - - if ((LONG) (pc0 + dif) < (LONG) BeginTEXT) { - make_proper_symbol (bufp, BeginTEXT); - p = strend (bufp); - *p++ = '-'; - p = itox6d (p, BeginTEXT - (pc0 + dif)); - } else if ((LONG) (pc0 + dif) > (LONG) Last) { - make_proper_symbol (bufp, Last); - p = strend (bufp); - *p++ = '+'; - p = itox6d (p, (pc0 + dif) - Last); - } else { - make_proper_symbol (bufp, pc0 + dif); - p = strend (bufp); - } - - strcpy (p, tabletop); - - /* 相対テーブルも -x でコメントを出力する */ - if (option_x) - byteout_for_xoption (pc, sizeof (LONG), buf); - - outputa (buf); - newline (pc); - - pc += sizeof (LONG); - } + dataoutDcByte(pc, pcend); // 半端に残ったデータがあれば出力 } - /* ロングワードテーブルの出力 @@ -1533,99 +978,31 @@ rellonggen (address pc, address pcend) pcend : longword table end address */ -private void -zgen (address pc, address pcend) -{ - address store; - address limit = pcend + Ofst - sizeof (ULONG); - - charout ('z'); - - for (store = pc + Ofst; store <= limit; store += sizeof (ULONG)) { - char work[128]; - address label = (address) peekl (store); - char* p; - - if ((LONG) label < (LONG) BeginTEXT) { - make_proper_symbol (work, BeginTEXT); - p = strend (work); - *p++ = '-'; - itox6d (p, (ULONG) (BeginTEXT - label)); - } else if ((LONG) label > (LONG) Last) { - make_proper_symbol (work, Last); - p = strend (work); - *p++ = '+'; - itox6d (p, (ULONG) (label - Last)); - } else - make_proper_symbol (work, label); - - output_opecode (PSEUDO DC_L); - outputa (work); - newline (store - Ofst); - } +static void zgen(address pc, address pcend) { + const address limit = pcend - sizeof(ULONG); - if (store - Ofst != pcend) - dataout (store - Ofst, pcend + Ofst - store, UNKNOWN); -} + charout('z'); + while (pc <= limit) { + SymbolLabelFormula slfml; + makeSymLabFormula(&slfml, (address)peekl(pc + Dis.Ofst)); -/* + outputData3(pc, OpString.dc[LONGSIZE], slfml.symbol, slfml.expr); - ユーザー定義のテーブルの出力 + pc += sizeof(ULONG); + } - input : - pc : user defined table begin address - pcend : user defined table end address( not used ) - mode : table attribute( not used ) - return : - table end address - -*/ -static boolean end_by_break; - -private address -tablegen (address pc, address pcend, lblmode mode) -{ - int loop, i; - table* tableptr; - - DEBUG_PRINT (("enter tablegen\n")); - charout ('t'); - - if ((tableptr = search_table (pc)) == NULL) - err ("Table が無い %06x (!?)\n" , pc); - - end_by_break = FALSE; - pc = tableptr->tabletop; - - for (loop = 0; loop < tableptr->loop; loop++) { /* implicit loop */ - for (i = 0; i < tableptr->lines; i++) { /* line# loop */ - DEBUG_PRINT (("loop=%d i=%d\n", loop, i)); - pc = tablegen_sub (&tableptr->formulaptr[i], - tableptr->tabletop, pc, i + 1 < tableptr->lines); -#if 0 - if ((lptr = search_label (Eval_PC)) != NULL) { - DEBUG_PRINT (("THERE IS LABEL (%x)\n", Eval_PC)); - label_line_out (Eval_PC, FALSE); - } -#endif - if (end_by_break) - goto ret; - } - } - -ret: - DEBUG_PRINT (("exit tablegen\n")); - return pc; + dataoutDcByte(pc, pcend); // 半端に残ったデータがあれば出力 } +static boolean end_by_break; /* ユーザ定義のテーブルの出力 input : - exprptr : ユーザ定義のテーブル1行の構造体 + fml : ユーザ定義のテーブル1行の構造体 tabletop : table top address pc : pointing address notlast : true iff this line is not last line at table @@ -1633,215 +1010,185 @@ tablegen (address pc, address pcend, lblmode mode) next pointing address */ - -private address -tablegen_sub (formula* exprptr, address tabletop, address pc, int notlast) -{ - - ParseMode = PARSE_GENERATING; - Eval_TableTop = tabletop; - Eval_Count = 0; - Eval_PC = pc; - - do { - extern int yyparse (void); - - lblbuf* lptr = next (Eval_PC + 1); - address nextlabel = lptr->label; - int str_length; - boolean pc_inc_inst; - - Eval_ResultString[0] = '\0'; - Lexptr = exprptr->expr; - - DEBUG_PRINT (("parsing %s\n", Lexptr)); - yyparse (); - - /* CRID, BREAKID, EVENID(.even 出力時)以外は全て TRUE */ - pc_inc_inst = TRUE; - - switch (exprptr->id) { - case LONGSIZE: - tablegen_dc (nextlabel, lptr, PSEUDO DC_L, 4); - break; - case WORDSIZE: - tablegen_dc (nextlabel, lptr, PSEUDO DC_W, 2); - break; - case BYTESIZE: - output_opecode (PSEUDO DC_B); - outputa (Eval_ResultString); - newline (Eval_PC); - Eval_PC++; - break; - - case SINGLESIZE: - tablegen_dc (nextlabel, lptr, PSEUDO DC_S, 4); - break; - case DOUBLESIZE: - tablegen_dc (nextlabel, lptr, PSEUDO DC_D, 8); - break; - case EXTENDSIZE: - tablegen_dc (nextlabel, lptr, PSEUDO DC_X, 12); - break; - case PACKEDSIZE: - tablegen_dc (nextlabel, lptr, PSEUDO DC_P, 12); - break; - -#if 0 - case LONGID: - if (nextlabel < Eval_PC + Eval_Bytes*4) - tablegen_label (Eval_PC, Eval_PC + Eval_Bytes * 4, lptr); - else - datagen (Eval_PC, Eval_PC + Eval_Bytes * 4, LONGSIZE); - Eval_PC += Eval_Bytes * 4; - break; - - case WORDID: - if (nextlabel < Eval_PC + Eval_Bytes * 2) - tablegen_label (Eval_PC, Eval_PC + Eval_Bytes * 2, lptr); - else - datagen (Eval_PC, Eval_PC + Eval_Bytes * 2, WORDSIZE); - Eval_PC += Eval_Bytes * 2; - break; -#endif - case BYTEID: - if (nextlabel < Eval_PC + Eval_Bytes) - tablegen_label (Eval_PC, Eval_PC + Eval_Bytes, lptr); - else - datagen (Eval_PC, Eval_PC + Eval_Bytes, BYTESIZE); - Eval_PC += Eval_Bytes; - break; - case ASCIIID: - if (nextlabel < Eval_PC + Eval_Bytes) - tablegen_label (Eval_PC, Eval_PC + Eval_Bytes, lptr); - else - strgen (Eval_PC, Eval_PC + Eval_Bytes); - Eval_PC += Eval_Bytes; - break; - case ASCIIZID: - str_length = strlen ((char*)Eval_PC + Ofst) + 1; - if (nextlabel < Eval_PC + str_length) - tablegen_label (Eval_PC, Eval_PC + str_length, lptr); - else - strgen (Eval_PC, Eval_PC + str_length); - Eval_PC += str_length; - break; - case LASCIIID: - str_length = *(unsigned char*) (Eval_PC + Ofst); - datagen (Eval_PC, Eval_PC + 1, BYTESIZE); - Eval_PC++; - if (nextlabel < Eval_PC + str_length) - tablegen_label (Eval_PC, Eval_PC + str_length, lptr); - else - strgen (Eval_PC, Eval_PC + str_length); - Eval_PC += str_length; - break; - case EVENID: - output_opecode (PSEUDO EVEN); - newline (Eval_PC); - if ((int)Eval_PC & 1) - Eval_PC++; /* pc_inc_inst = TRUE; */ - else - pc_inc_inst = FALSE; - break; - case CRID: - newline (Eval_PC); - pc_inc_inst = FALSE; - break; - case BREAKID: - if (Eval_Break) { - DEBUG_PRINT (("END_BY_BREAK!(%x)\n", (unsigned int) Eval_PC)) - end_by_break = TRUE; - goto tableend; - } - pc_inc_inst = FALSE; - break; - default: /* reduce warning message */ - break; - } - - if ((lptr = search_label (Eval_PC)) != NULL) { - DEBUG_PRINT (("THERE IS LABEL sub (%x)%x\n", - (unsigned int) Eval_PC, lptr->mode)); - -#if 0 /* does not work properly */ - if (isTABLE (lptr->mode) && notlast) - eprintf ("\nEncounter another table in table(%x).\n", Eval_PC); -#endif - if (isENDTABLE (lptr->mode)) { - DEBUG_PRINT (("ENCOUNTER ENDTABLE(%x)", (unsigned int) Eval_PC)); - if (notlast && (exprptr+1)->id == EVENID) { - /* if .even here.... */ - output_opecode (PSEUDO EVEN); - newline (Eval_PC); - Eval_PC += (int)Eval_PC & 1; - } - end_by_break = TRUE; - goto tableend; - } else if (pc_inc_inst) - /* labelout is not required at end of table */ - label_line_out (Eval_PC, FALSE); - } - } while (--Eval_Count > 0); - - tableend: - DEBUG_PRINT (("exit tablegen_sub()\n")); - return Eval_PC; -} - -static void -tablegen_dc (address nextlabel, lblbuf* lptr, char* op, int size) -{ - if (nextlabel < Eval_PC + size) - tablegen_label (Eval_PC, Eval_PC + size, lptr); - else { - output_opecode (op); - outputa (Eval_ResultString); - newline (Eval_PC); - } - Eval_PC += size; +static address tablegen_sub(formula* fml, address tabletop, address pc, + int notlast, int sectType) { + char buffer[256]; + ParseTblParam param = { + .text = NULL, + .buffer = buffer, + .bufLen = sizeof(buffer), + .constValues = {0, tabletop} // + }; + int count = 1; + boolean firstCall = TRUE; + + do { + ParseTblResult result; + + lblbuf* lptr = next(pc + 1); + address nextlabel = lptr->label; + address nextPc; + + // CRID, BREAKID, EVENID(アライン実行時)以外は全て TRUE + boolean pc_inc_inst = TRUE; + + param.text = fml->expr; + param.constValues[PARSE_CONST_PC] = pc; + parseTableLine(¶m, &result); + if (firstCall) { + count = result.count; + firstCall = FALSE; + } + nextPc = pc + result.bytes; + + if ((nextlabel < nextPc) && (result.id != LASCIIID)) { + // 複数バイトのデータ中にラベルがある場合は分割して出力する + tablegen_label(pc, nextPc, lptr, sectType); + } else { + switch (result.id) { + default: + break; + + case BYTESIZE: + case WORDSIZE: + case LONGSIZE: + case SINGLESIZE: + case DOUBLESIZE: + case EXTENDSIZE: + case PACKEDSIZE: + outputData2(pc, OpString.dc[result.id], buffer); + break; + + case BYTEID: + datagen(pc, nextPc, BYTESIZE); + break; + + case LASCIIID: + datagen(pc, pc + 1, BYTESIZE); // .dc.b 文字列長 + pc += 1; + if (nextlabel < nextPc) { + tablegen_label(pc, nextPc, lptr, sectType); + break; + } + // FALLTHRU + case ASCIIID: + case ASCIIZID: + strgen(pc, nextPc); + break; + + case EVENID: + outputDirective(LINETYPE_DATA, pc, OpString.even); + if (result.bytes == 0) pc_inc_inst = FALSE; + break; + + case CRID: + outputDirective(LINETYPE_DATA, pc, ""); + pc_inc_inst = FALSE; + break; + + case BREAKID: + if (result.value) { + end_by_break = TRUE; + goto tableend; + } + pc_inc_inst = FALSE; + break; + } + } + pc = nextPc; + + if ((lptr = search_label(pc)) != NULL) { + // テーブル解析時にテーブル終了と判定したらそのアドレスをラベル登録するので、 + // ここではそのラベルを見てテーブル終了を判断する + if (isENDTABLE(lptr->mode)) { + if (notlast && (fml + 1)->id == EVENID) { + // if .even here... + outputDirective(LINETYPE_DATA, pc, OpString.even); + pc += (pc & 1); + } + end_by_break = TRUE; + goto tableend; + } + + if (pc_inc_inst) { + // labelout is not required at end of table + label_line_out(pc, lptr->mode, sectType, FALSE, LINETYPE_DATA); + } + } + } while (--count > 0); + +tableend: + return pc; } - /* - テーブル中にラベルが存在した場合のデータブロック出力 + ユーザー定義のテーブルの出力 input : - pc : point address - pcend : point address' end address - lptr : テーブル中のラベル + pc : user defined table begin address + pcend : user defined table end address( not used ) + mode : table attribute( not used ) + return : + table end address */ -private void -tablegen_label (address pc, address pcend, lblbuf* lptr) -{ - address nlabel = lptr->label; - lblmode nmode = lptr->mode; +static address tablegen(address pc, int sectType) { + int loop, i; + table* tableptr; - DEBUG_PRINT (("tablegen_label(%x,%x,%x)\n", (unsigned int)pc, - (unsigned int) pcend, (unsigned int) nlabel)); + charout('t'); - pc = datagen (pc, nlabel, nmode & 0xff); - while (pc < pcend) { - lblmode mode = nmode; + if ((tableptr = search_table(pc)) == NULL) + internalError(__FILE__, __LINE__, "テーブルが無い(!?)。"); - lptr = next (pc + 1); - while (lptr->shift) - lptr = Next (lptr); + end_by_break = FALSE; + pc = tableptr->tabletop; - nlabel = lptr->label; - nmode = lptr->mode; + for (loop = 0; loop < tableptr->loop; loop++) { /* implicit loop */ + for (i = 0; i < tableptr->lines; i++) { /* line# loop */ + pc = tablegen_sub(&tableptr->formulaptr[i], tableptr->tabletop, pc, + i + 1 < tableptr->lines, sectType); - label_line_out (pc, mode); - pc = isPROLABEL (mode) ? textgen (pc, min (nlabel, pcend)) - : datagen (pc, min (nlabel, pcend), mode & 0xff); + if (end_by_break) return pc; } + } - DEBUG_PRINT (("exit tablegen_label\n")); + return pc; } +/* + + テーブル中にラベルが存在した場合のデータブロック出力 + + input : + pc : point address + pcend : point address' end address + lptr : テーブル中のラベル +*/ +static void tablegen_label(address pc, address pcend, lblbuf* lptr, + int sectType) { + address nlabel = lptr->label; + lblmode nmode = lptr->mode; + + pc = datagen(pc, nlabel, lblmodeOpesize(nmode)); + while (pc < pcend) { + lblmode mode = nmode; + + lptr = next(pc + 1); + while (lptr->shift) lptr = Next(lptr); + + nlabel = lptr->label; + nmode = lptr->mode; + + label_line_out(pc, mode, sectType, FALSE, + isPROLABEL(mode) ? LINETYPE_TEXT : LINETYPE_DATA); + pc = isPROLABEL(mode) + ? textgen(pc, MIN(nlabel, pcend)) + : datagen(pc, MIN(nlabel, pcend), lblmodeOpesize(mode)); + } +} /* @@ -1852,114 +1199,93 @@ tablegen_label (address pc, address pcend, lblbuf* lptr) buffer : pointer to output buffer */ -#define IMM_B1 (*(unsigned char*) (store + 1)) -#define IMM_W1 (*(unsigned char*) (store + 0)) -#define IMM_W2 (*(unsigned char*) (store + 1)) -#define IMM_L1 (*(unsigned char*) (store + 0)) -#define IMM_L2 (*(unsigned char*) (store + 1)) -#define IMM_L3 (*(unsigned char*) (store + 2)) -#define IMM_L4 (*(unsigned char*) (store + 3)) - -private void -byteout_for_moption (address pc, char* buffer, int size) -{ - char* p; - address store = pc + Ofst; - - /* moveq.l は即値の位置が違う */ - if (size == LONGSIZE && (*(char*) store) >= 0x70) - size = BYTESIZE; - else - store += 2; - - /* 表示可能な文字か調べる */ - if (size == BYTESIZE) { - if (!isprint (IMM_B1)) - return; - } - else if (size == WORDSIZE) { - /* 上位バイトは表示可能もしくは 0 */ - if (IMM_W1 && !isprint (IMM_W1)) - return; - - /* 下位バイトは必ず表示可能 */ - if (!isprint (IMM_W2)) - return; - } - else if (size == LONGSIZE) { - /* 最上位バイトは表示可能もしくは 0 */ - if (IMM_L1 && !isprint (IMM_L1)) - return; - - /* 真ん中の二バイトは必ず表示可能 */ - if (!isprint (IMM_L2) || !isprint (IMM_L3)) - return; - - /* 最下位バイトは表示可能もしくは 0 */ - if (IMM_L4 && !isprint (IMM_L4)) - return; - } - else { /* pack, unpk */ +#define IMM_B1 (*(UBYTE*)(store + 1)) +#define IMM_W1 (*(UBYTE*)(store + 0)) +#define IMM_W2 (*(UBYTE*)(store + 1)) +#define IMM_L1 (*(UBYTE*)(store + 0)) +#define IMM_L2 (*(UBYTE*)(store + 1)) +#define IMM_L3 (*(UBYTE*)(store + 2)) +#define IMM_L4 (*(UBYTE*)(store + 3)) + +static void byteout_for_moption(disasm* code, char* buffer) { + char* p; + codeptr store = code->pc + Dis.Ofst; + opesize size = code->size; + + if (code->size2 == UNKNOWN) + size = BYTESIZE; // MOVEQ.Lは命令コードの下位にバイト値がある + else + store += 2; + + /* 表示可能な文字か調べる */ + if (size == BYTESIZE) { + if (!isprint(IMM_B1)) return; + } else if (size == WORDSIZE) { + /* 上位バイトは表示可能もしくは 0 */ + if (IMM_W1 && !isprint(IMM_W1)) return; + + /* 下位バイトは必ず表示可能 */ + if (!isprint(IMM_W2)) return; + } else if (size == LONGSIZE) { + /* 最上位バイトは表示可能もしくは 0 */ + if (IMM_L1 && !isprint(IMM_L1)) return; + + /* 真ん中の二バイトは必ず表示可能 */ + if (!isprint(IMM_L2) || !isprint(IMM_L3)) return; + + /* 最下位バイトは表示可能もしくは 0 */ + if (IMM_L4 && !isprint(IMM_L4)) return; + } else { /* pack, unpk */ #ifdef PACK_UNPK_LOOSE - /* 上位バイトは表示可能もしくは 0 */ - if (IMM_W1 && !isprint (IMM_W1)) - return; + /* 上位バイトは表示可能もしくは 0 */ + if (IMM_W1 && !isprint(IMM_W1)) return; - /* 下位バイトは表示可能もしくは 0 */ - if (IMM_W2 && !isprint (IMM_W2)) - reutrn; + /* 下位バイトは表示可能もしくは 0 */ + if (IMM_W2 && !isprint(IMM_W2)) reutrn; - /* ただし両方とも 0 ではいけない */ - if (IMM_W1 == 0 && IMM_W2 == 0) - return; + /* ただし両方とも 0 ではいけない */ + if (IMM_W1 == 0 && IMM_W2 == 0) return; #else - /* 二バイトとも必ず表示可能 */ - if (!isprint (IMM_W1) || !isprint (IMM_W2)) - return; + /* 二バイトとも必ず表示可能 */ + if (!isprint(IMM_W1) || !isprint(IMM_W2)) return; #endif + } + + p = writeTabAndCommentChar(buffer, Dis.Mtab); + *p++ = '\''; + + if (size == BYTESIZE) { + *p++ = IMM_B1; + } else if (size == WORDSIZE) { + if (IMM_W1) *p++ = IMM_W1; + *p++ = IMM_W2; + } else if (size == LONGSIZE) { + if (IMM_L1) *p++ = IMM_L1; + *p++ = IMM_L2; + *p++ = IMM_L3; + if (IMM_L4) + *p++ = IMM_L4; + else { + strcpy(p, "'<<8"); + return; } - - p = tab_out (Mtab, buffer); - *p++ = '\''; - - if (size == BYTESIZE) { - *p++ = IMM_B1; - } - else if (size == WORDSIZE) { - if (IMM_W1) - *p++ = IMM_W1; - *p++ = IMM_W2; - } - else if (size == LONGSIZE) { - if (IMM_L1) - *p++ = IMM_L1; - *p++ = IMM_L2; - *p++ = IMM_L3; - if (IMM_L4) - *p++ = IMM_L4; - else { - strcpy (p, "'<<8"); - return; - } - } - else { /* pack, unpk */ + } else { /* pack, unpk */ #ifdef PACK_UNPK_LOOSE - if (IMM_W1) - *p++ = IMM_W1; - if (IMM_W2) - *p++ = IMM_W2; - else { - strcpy (p, "'<<8"); - return; - } + if (IMM_W1) *p++ = IMM_W1; + if (IMM_W2) + *p++ = IMM_W2; + else { + strcpy(p, "'<<8"); + return; + } #else - *p++ = IMM_W1; - *p++ = IMM_W2; + *p++ = IMM_W1; + *p++ = IMM_W2; #endif - } + } - *p++ = '\''; - *p++ = '\0'; + *p++ = '\''; + *p++ = '\0'; } #undef IMM_B1 #undef IMM_W @@ -1970,8 +1296,6 @@ byteout_for_moption (address pc, char* buffer, int size) #undef IMM_L3 #undef IMM_L4 - - /* -x オプションのコメント処理 @@ -1982,26 +1306,19 @@ byteout_for_moption (address pc, char* buffer, int size) buffer : pointer to output buffer */ -extern void -byteout_for_xoption (address pc, ULONG byte, char* buffer) -{ - int i; - char c; - address store = pc + Ofst; - char* p = tab_out (Xtab, buffer); - - for (c = '\0', i = 0; i < byte; i += 2, store += 2) { - if (c) - *p++ = c; /* 二回目からはカンマが必要 */ - *p++ = '$'; - p = itox4_without_0supress (p, peekw (store)); - c = ','; - } +static void byteout_for_xoption(address pc, ULONG byte, char* buffer) { + codeptr store = pc + Dis.Ofst; + char* p = writeTabAndCommentChar(buffer, Dis.Xtab); + ULONG i; + + for (i = 0; i < byte; i += 2, store += 2) { + *p++ = '$'; + p = itox4_without_0supress(p, peekw(store)); + *p++ = ','; + } + *--p = '\0'; // 最後のカンマを消す } - - - /* bss 領域の出力 @@ -2012,837 +1329,220 @@ byteout_for_xoption (address pc, ULONG byte, char* buffer) size : data size */ -private void -bssgen (address pc, address nlabel, opesize size) -{ - ULONG byte; - - charout ('$'); - nlabel = (address) min ((ULONG) nlabel, (ULONG) Last); - byte = nlabel - pc; - - if ((LONG)nlabel >= 0) { - if (size == WORDSIZE && byte == 2) - output_opecode (PSEUDO DS_W "1"); - else if (size == LONGSIZE && byte == 4) - output_opecode (PSEUDO DS_L "1"); - else { - output_opecode (PSEUDO DS_B); - outputfa ("%d", byte); - } - newline (pc); - } -} +static void bssgen(address pc, address nlabel, opesize size) { + char buf[16]; + int bytes = MIN(nlabel, Dis.LAST) - pc; + SizeLength sl; + charout('$'); -/* - - ラベルの付け替え - - input : - code : disassembled opecode - operand : operand ( op1,op2,op3 or op4 ) - - return : - TRUE if output is 'label[+-]??' style ( used to avoid as.x bug ) - (注)as.xには対応しなくなった為、返値は削除. - - Ablong PCDISP IMMED PCIDX - 0 (label) (label,pc) #label (label,pc,ix) - 1 (label-$num) (label-$num,pc) #label-$num (label-$num,pc,ix) - 2 (label+$num) (label+$num,pc) #label+$num (label+$num,pc,ix) - -(odはアドレス依存かつexodが4の時だけlabel化する) - PCIDXB PCPOSTIDX PCPREIDX - (label,pc,ix) ([label,pc],ix,label) ([label,pc,ix],label) - -(bd,odはアドレス依存かつexbd,exodがそれぞれ4の時だけlabel化) - AregIDXB AregPOSTIDX AregPREIDX - (label,an,ix) ([label,an],ix,label) ([label,an,ix],label) - -*/ -private void -labelchange (disasm* code, operand* op) -{ - address arg1; - LONG shift; - - if (op->opval != (address)-1 && - (op->labelchange1 || - ((op->ea == AbLong || ((op->ea == IMMED) && (code->size2 == LONGSIZE))) - && INPROG (op->opval, op->eaadrs)) - ) - ) { - char buff[64]; - char* base = buff; - char* ext_operand = NULL; - - switch (op->ea) { - default: - case IMMED: - break; - - case AbLong: - ext_operand = ")"; - break; - - case AregPOSTIDX: - case AregPREIDX: - if (!INPROG (op->opval, op->eaadrs)) - goto bd_skip; - ext_operand = strpbrk (op->operand, "],"); - break; - - case PCDISP: - if ((char)op->labelchange1 < 0) - break; /* bsr label 等は括弧なし */ - /* fall through */ - case AregIDXB: - case PCIDX: - ext_operand = strchr (op->operand, ','); - break; - case PCIDXB: - ext_operand = strchr (op->operand, ','); - goto check_size; - case PCPOSTIDX: - case PCPREIDX: - ext_operand = strpbrk (op->operand, "],"); -check_size: if (ext_operand[-2] == (char)'.') - ext_operand -= 2; /* サイズ付きなら付け加える */ - break; - } - - if ((LONG)op->opval < (LONG)BeginTEXT) { - arg1 = BeginTEXT; - shift = (LONG)op->opval - (LONG)BeginTEXT; - } else if ((ULONG)op->opval > (ULONG)Last) { - arg1 = Last; - shift = (ULONG)op->opval - (ULONG)Last; - } else { - lblbuf* label_ptr = search_label (op->opval); - - if (!label_ptr) - /* ここで opval より手前のラベルを探して */ - /* ±shift 形式にするべきか?? */ - return; - shift = label_ptr->shift; - arg1 = op->opval - shift; - } - - switch (op->ea) { - default: - break; - case IMMED: - *base++ = '#'; - break; - case PCDISP: - if ((char)op->labelchange1 < 0) - break; /* bsr label 等は括弧なし */ - /* fall through */ - case AbLong: - case PCIDX: - case AregIDXB: - case PCIDXB: - *base++ = '('; - break; - case AregPOSTIDX: - case AregPREIDX: - case PCPOSTIDX: - case PCPREIDX: - *base++ = '('; - *base++ = '['; - break; - } - - base = make_symbol (base, arg1, shift); - - if (ext_operand) - strcpy (base, ext_operand); - - strcpy (op->operand, buff); - } - -bd_skip: - - -/* アウタディスプレースメント用 */ - if (op->labelchange2 && op->opval2 != (address)-1 - && INPROG (op->opval2, op->eaadrs2)) - { - char* ptr; - - if ((LONG)op->opval2 < (LONG)BeginTEXT) { - arg1 = BeginTEXT; - shift = (LONG)op->opval2 - (LONG)BeginTEXT; - } else if ((ULONG)op->opval2 > (ULONG)Last) { - arg1 = Last; - shift = (ULONG)op->opval2 - (ULONG)Last; - } else { - lblbuf* label_ptr = search_label (op->opval2); - - if (!label_ptr) - return; - shift = label_ptr->shift; - arg1 = op->opval2 - shift; - } - - ptr = make_symbol (strrchr (op->operand, ',') + 1, arg1, shift); - *ptr++ = ')'; - *ptr++ = '\0'; - } + sl = getSizeLength(getSizeBytes(size), bytes); + snprintf(buf, sizeof(buf), "%d", sl.length); + outputData2(pc, OpString.ds[sl.size], buf); } +// ラベル化できる場合はラベルを探してTRUEを返す +static boolean getLabel(operand* op, SymbolLabelFormula* slfml) { + if (op->labelchange1 == LABELCHANGE_DISALLOW) return FALSE; -/* ラベル定義行のコロン出力 */ -static INLINE void -add_colon (char* ptr, int xdef) -{ - if (SymbolColonNum) { - *ptr++ = ':'; - /* -C3 又は、-C2 かつ外部定義なら :: */ - if (SymbolColonNum > 2 || (SymbolColonNum == 2 && xdef)) - *ptr++ = ':'; - } - *ptr = '\0'; -} - -/* - - ラベル定義行出力 - - input : - adrs : label address - mode : label mode - - シンボル名が定義されていれば「シンボル名::」、未定義なら「Lxxxxxx:」 - などの形式で出力する(コロンの数やラベル先頭文字はオプションの状態で変わる). - シンボル属性によっては全く出力されないこともある. - -*/ -private void -label_line_out (address adrs, lblmode mode) -{ - char buf[128]; - symbol* symbolptr; - - if (isHIDDEN (mode)) - return; - - if (Exist_symbol && (symbolptr = symbol_search (adrs))) { - symlist* sym = &symbolptr->first; - do { - if (sym->type == SectionType || (sym->type == 0)) { - add_colon (strend (strcpy (buf, sym->sym)), sym->type); - outputa (buf); - newline (adrs); - } - sym = sym->next; - } while (sym); - return; - } - - /* シンボル名が無ければ Lxxxxxx の形式で出力する */ - buf[0] = Label_first_char; - add_colon (itox6_without_0supress (&buf[1], (ULONG)adrs), 0); - outputa (buf); - newline (adrs); -} - -private void -label_line_out_last (address adrs, lblmode mode) -{ - char buf[128]; - symbol* symbolptr; - - if (isHIDDEN (mode)) - return; - - if (Exist_symbol && (symbolptr = symbol_search (adrs))) { - symlist* sym = &symbolptr->first; - do { - /* SectionType == 0 のシンボル名は出力しないこと. */ - /* それは次のセクションの先頭で出力する. */ - if (sym->type == SectionType) { - add_colon (strend (strcpy (buf, sym->sym)), sym->type); - outputa (buf); - newline (adrs); - } - sym = sym->next; - } while (sym); - return; - } - - /* ソースコード最後のラベルは絶対に出力する必要がある. */ - if (SectionType == 0) - label_line_out (adrs, mode); - -} - - - -/* - - オペランドとしてのラベル出力 - - input : - adrs : label address - mode : label mode - - .end及び.dc.l疑似命令のオペランドを作成する為に呼ばれる. - コロンは付かない. - +-shtが付く可能性がある. - -*/ -private void -label_op_out (address adrs) -{ - char buf[128]; - - make_proper_symbol (buf, adrs); - outputa (buf); -} - - -/* - - ラベルシンボルの生成 - - input : - buff : buffer of label symbol - adrs : address - - 最も近いシンボルを探し、同じ値がなければshift値を計算して - make_symbol()を呼び出す. - -*/ -extern void -make_proper_symbol (char* buf, address adrs) -{ - address arg1; - LONG shift; - - if ((LONG)adrs < (LONG)BeginTEXT) { /* must be LONG, not ULONG */ - arg1 = BeginTEXT; - shift = (LONG)adrs - (ULONG)BeginTEXT; - } else if ((ULONG)adrs > (ULONG)Last) { - arg1 = Last; - shift = (ULONG)adrs - (ULONG)Last; - } else { - lblbuf* lblptr = search_label (adrs); - - if (lblptr && (shift = lblptr->shift) != 0) - arg1 = adrs - shift; - else { - arg1 = adrs; - shift = 0; - } - } - make_symbol (buf, arg1, shift); -} - - -/* - - シンボルを生成する - - input : - ptr : symbol buffer - adrs : address - sft : shift count - - return : - pointer to generated symbol' tail - - シンボルテーブルがあれば、adrs はシンボルに置換され、なければ L?????? 形式となる - sft != 0 ならその後に +sft or -sft がつく - - ラベル定義行の生成にはlabel_line_out()を使うこと. - -*/ -extern char* -make_symbol (char* ptr, address adrs, LONG sft) -{ - symbol* symbol_ptr; - - if (Exist_symbol && (symbol_ptr = symbol_search (adrs)) != NULL) { - strcpy (ptr, symbol_ptr->first.sym); - ptr = strend (ptr); - } else { - *ptr++ = Label_first_char; - ptr = itox6_without_0supress (ptr, (ULONG)adrs); - } + if (op->labelchange1 == LABELCHANGE_DEPEND) { + if (!INPROG(op->opval, op->eaadrs)) return FALSE; + } - if (sft == 0) - return ptr; - - if (sft > 0) - *ptr++ = '+'; - else { - *ptr++ = '-'; - sft = -sft; - } - return itox6d (ptr, sft); -} - - -private const char* -ctimez (time_t* clock) -{ - char* p = ctime (clock); - char* n; - - if (p == NULL) - return "(invalid time)"; - - n = strchr (p, '\n'); - if (n) - *n = '\0'; - return p; -} - - -static INLINE FILE* -open_header_file (void) -{ - FILE* fp = NULL; - const char* fname = Header_filename ? : getenv ("dis_header"); - - if (fname && *fname && (fp = fopen (fname, "rt")) == NULL) { -#if 0 - eprintf ("\n" - "ヘッダ記述ファイル \"%s\" がオープン出来ません.\n" - "標準の内容を出力します.\n", file); -#else - eprintf ("\nヘッダ記述ファイルがオープン出来ません.\n"); +#ifdef DEBUG_NO_LABELCHANGE + if (op->labelchange1 != LABELCHANGE_LABEL_ONLY) return FALSE; #endif - } - return fp; + makeSymLabFormula(slfml, op->opval); + return TRUE; } - -/* - - ヘッダを書く - - input : - filename : execute filename - filedate : execute file' time stamp - argv0 : same to argv[0] given to main() - comline : commandline - -*/ -private void -makeheader (char* filename, time_t filedate, char* argv0, char* comline) -{ - char buffer[256]; - char* envptr; - char cc = CommentChar; - - static char op_include[] = PSEUDO INCLUDE; - static char op_cpu[] = PSEUDO CPU; - static char op_equ[] = PSEUDO EQU; - static char op_xdef[] = PSEUDO XDEF; - - if (option_U) { - strupr (op_include); - strupr (op_cpu); - strupr (op_equ); - strupr (op_xdef); - } - - outputf ("%c=============================================" CR, cc); - outputf ("%c Filename %s" CR, cc, filename); - outputf ("%c Time Stamp %s" CR, cc, ctimez (&filedate)); - outputf ("%c" CR, cc); -#ifndef OSKDIS - outputf ("%c Base address %06x" CR, cc, Head.base); - outputf ("%c Exec address %06x" CR, cc, Head.exec); - outputf ("%c Text size %06x byte(s)" CR, cc, Head.text); - outputf ("%c Data size %06x byte(s)" CR, cc, Head.data); - outputf ("%c Bss size %06x byte(s)" CR, cc, Head.bss); -#endif /* !OSKDIS */ - outputf ("%c %d Labels" CR, cc, get_Labelnum ()); - { - time_t t = time (NULL); - outputf ("%c Code Generate date %s" CR, cc, ctimez (&t)); - } - if ((envptr = getenv (DIS_ENVNAME)) != NULL) - outputf ("%c Environment %s" CR, cc, envptr); - - outputf ("%c Commandline %s %s" CR, cc, argv0, comline); - outputf ("%c DIS version %s" CR, cc, Version); - -#ifdef OSKDIS - outputf ("%c********************************************" CR, cc); - - outputf ("%c Revision %04x" CR, cc, HeadOSK.sysrev); - outputf ("%c Module Size %d bytes" CR, cc, HeadOSK.size); - outputf ("%c Owner %d.%d" CR, cc, HeadOSK.owner >> 16, - HeadOSK.owner & 0xffff); - outputf ("%c Name Offset %08x" CR, cc, HeadOSK.name); - outputf ("%c Permit %04x" CR, cc, HeadOSK.accs); - outputf ("%c Type/Lang %04x" CR, cc, HeadOSK.type); - outputf ("%c Attribute %04x" CR, cc, HeadOSK.attr); - outputf ("%c Edition %d" CR, cc, HeadOSK.edition); - outputf ("%c Entry %08x" CR, cc, HeadOSK.exec); - outputf ("%c Excpt %08x" CR, cc, HeadOSK.excpt); - - if ((HeadOSK.type & 0x0F00) == 0x0e00 || /* Driver */ - (HeadOSK.type & 0x0F00) == 0x0b00 || /* Trap */ - (HeadOSK.type & 0x0F00) == 0x0100) { /* Program */ - outputf ("%c Memory Size %d" CR, cc, HeadOSK.mem); - } - if ((HeadOSK.type & 0x0F00) == 0x0100 || /* Program */ - (HeadOSK.type & 0x0F00) == 0x0b00) { /* Trap */ - outputf ("%c Stack Size %d" CR, cc, HeadOSK.stack); - outputf ("%c M$IData %08x" CR, cc, HeadOSK.idata); - outputf ("%c M$IRefs %08x" CR, cc, HeadOSK.irefs); - } - if ((HeadOSK.type & 0x0F00) == 0x0b00) { /* Trap */ - outputf ("%c M$Init %08x" CR, cc, HeadOSK.init); - outputf ("%c M$Term %08x" CR, cc, HeadOSK.term); - } - - outputf ("%c********************************************" CR - "%c" CR, cc, cc); - strcpy (buffer, Top - (ULONG)Head.base + HeadOSK.name); /* モジュール名 */ - switch (HeadOSK.type & 0x0f00) { - case 0x0100: /* Program */ - case 0x0b00: /* Trap */ - outputf ("\tpsect\t%s,$%04x,$%04x,%d,%d,L%06x", - buffer, HeadOSK.type, HeadOSK.attr, - HeadOSK.edition, HeadOSK.stack, HeadOSK.exec); - if (HeadOSK.excpt) - outputf (",L%06x", HeadOSK.excpt); - break; - case 0x0200: /* Subroutine */ - case 0x0c00: /* System */ - case 0x0d00: /* FileMan */ - case 0x0e00: /* Driver */ - outputf ("\tpsect\t%s,$%04x,$%04x,%d,%d,L%06x", - buffer, HeadOSK.type, HeadOSK.attr, - HeadOSK.edition, 0, HeadOSK.exec); - if (HeadOSK.excpt) - outputf (",L%06x", HeadOSK.excpt); - break; - } -#else - outputf ("%c=============================================" CR CR, cc); - - /* dis_header の出力 */ - { - FILE* fp = open_header_file (); - - if (fp) { - while (fgets (buffer, sizeof buffer, fp)) { - char* p = strchr (buffer, '\n'); - if (p) - *p = '\0'; - outputf ("%s" CR, buffer); - } - fclose (fp); - } - else { - if (Doscall_mac_path) - outputf ("%s%s" CR, op_include, Doscall_mac_path); - if (Iocscall_mac_path) - outputf ("%s%s" CR, op_include, Iocscall_mac_path); - if (Fefunc_mac_path) - outputf ("%s%s" CR, op_include, Fefunc_mac_path); - if (Sxcall_mac_path) - outputf ("%s%s" CR, op_include, Sxcall_mac_path); - } - outputf (CR); - } -#endif /* OSKDIS */ - -#ifndef OSKDIS - { /* 外部定義シンボルの出力 */ - char* colon = (SymbolColonNum == 0) ? "" - : (SymbolColonNum == 1) ? ":" : "::"; - if (output_symbol_table (op_equ, op_xdef, colon)) - outputf (CR); - } -#endif /* !OSKDIS */ - - /* .cpu 疑似命令の出力 */ - outputf ("%s%s" CR, op_cpu, mputype_numstr (Current_Mputype)); - -} - - -private char* -mputype_numstr (mputypes m) -{ - if (m & M000) return "68000"; - if (m & M010) return "68010"; - if (m & M020) return "68020"; - if (m & M030) return "68030"; - if (m & M040) return "68040"; - /* if (m & M060) */ - return "68060"; -} - - -/* - - オペコードの出力 - - input : - ptr : buffer of opecode ( like "move.l",0 ) - -*/ -private void -output_opecode (char* ptr) -{ - char buf[32]; - - if (option_U) - ptr = strupr (strcpy (buf, ptr)); - outputa (ptr); -} - - - -/************************************************/ -/* LIBC/XC 以外で使用する関数 */ -/************************************************/ - -#ifdef NEED_MAKE_CMDLINE -private char* -make_cmdline (char** argv) -{ - char* ptr = Malloc (1); - - for (*ptr = '\0'; *argv; argv++) { - ptr = Realloc (ptr, strlen (ptr) + strlen (*argv) + 2); - strcat (strcat (ptr, " "), *argv); - } - - return ptr; +// 文字列の直前にベースディスプレースメントのサイズ(".l")があればそのアドレスを返す +// なければ引数の文字列をそのまま返す +static char* rewindToBDSize(operand* op, char* s) { + return ((op->flags & OPFLAG_PC_RELATIVE) && s[-2] == '.') ? s - 2 : s; } -#endif - - -/************************************************/ -/* 以下は OSKDIS 用の関数 */ -/************************************************/ -#ifdef OSKDIS +// オペランド内のアドレスをラベル化してバッファにコピーする +// 書き込んだ文字列の末尾('\0'は書き込まない)を返す。 +static char* operandToLabel(char* p, operand* op) { + SymbolLabelFormula slfml; -private void -oskdis_gen (lblbuf* lptr) -{ - lblbuf* lptr = gen (CR, BeginBSS, next (BeginTEXT), XDEF_BSS, 0, -1); - lblmode nmode = lptr->mode; - address pc = lptr->label; + switch (op->ea) { + default: + return strcpy2(p, op->operand); - output_opecode (CR "\tvsect" CR CR); - while (pc <= BeginDATA) { - lblmode mode = nmode; - address nlabel; + case AbLong: // ($xxxx_xxxx) -> (label) + if (!getLabel(op, &slfml)) return strcpy2(p, op->operand); - lptr = Next (lptr); - nlabel = lptr->label; - nmode = lptr->mode; + *p++ = '('; + p = catSlfml(p, &slfml); + *p++ = ')'; + return p; - if (pc == BeginDATA) break; /* 泥縄 */ + case PCDISP: // (d16,pc) -> (label,pc) + if (!getLabel(op, &slfml)) return strcpy2(p, op->operand); - vlabelout (pc, mode); - bssgen (pc, nlabel, mode & 0xff); - pc = nlabel; - } + if (op->labelchange1 == LABELCHANGE_LABEL_ONLY) { + // Bcc/DBccなどはラベルだけの表記 $xxxx_xxxx -> label + return catSlfml(p, &slfml); + } + *p++ = '('; + p = catSlfml(p, &slfml); + return strcpy2(p, strchr(op->operand, ',')); - DEBUG_PRINT (("\nTEST=%08x, DATA=%08x, BSS=%08x, LAST=%08x\n", - BeginTEXT, BeginDATA, BeginBSS, Last)); - - lptr = next (BeginDATA); /* vsect の初期化データ領域をポイント */ - switch (HeadOSK.type & 0x0f00) { - case 0x0100: /* Program */ - case 0x0b00: /* Trap */ - { - ULONG* idatsiz = Top - (ULONG) Head.base + (ULONG) HeadOSK.idata + 4; - lptr = idatagen (BeginDATA + *idatsiz, lptr); - } /* vsect の初期化データを出力 */ - break; - default: - lptr = idatagen (Last, lptr); - break; - } - pc = lptr->label; - DEBUG_PRINT (("pc=0x%.8x, last=0x%.8x\n", pc, Last)); + case PCIDX: // (d8,pc,ix) -> (label,pc,ix) + if (!getLabel(op, &slfml)) return strcpy2(p, op->operand); - output_opecode (CR "\tends" CR); /* end vsect */ + *p++ = '('; + p = catSlfml(p, &slfml); + return strcpy2(p, strchr(op->operand, ',')); - if (pc < Last) { - output_opecode (CR "\tvsect\tremote" CR CR); - while (pc <= Last) { - lblmode mode = nmode; - address nlabel; + case IMMED: // #$xxxx_xxxx -> #label + if (!getLabel(op, &slfml)) return strcpy2(p, op->operand); - lptr = Next (lptr); - nlabel = lptr->label; - nmode = lptr->mode; - - if (pc == Last) break; /* 泥縄 */ - - vlabelout (pc, mode); - bssgen (pc, nlabel, mode & 0xff); - pc = nlabel; - } - output_opecode (CR "\tends" CR); /* end vsect remote */ - } + *p++ = '#'; + return catSlfml(p, &slfml); - output_opecode (CR "\tends" CR); /* end psect */ - output_opecode (CR "\tend" CR); + case AregDISP: // (d16,a6) -> (label,a6) + { + char* (*d16AnToLabel)(char* p, operand* op) = Dis.actions->d16AnToLabel; + if (d16AnToLabel != NULL) + return d16AnToLabel(p, op); + else + return strcpy2(p, op->operand); + } + + case AregIDXB: // ($xxxx_xxxx,an,ix) -> (label,an,ix) + if (!getLabel(op, &slfml)) return strcpy2(p, op->operand); + + *p++ = '('; + p = catSlfml(p, &slfml); + return strcpy2(p, strchr(op->operand, ',')); + + case AregPOSTIDX: // ([$xxxx_xxxx,an],ix,od) -> ([label,an],ix,od) + case AregPREIDX: // ([$xxxx_xxxx,an,ix],od) -> ([label,an,ix],od) + // ベースディスプレースメントはロングのみ + if (!getLabel(op, &slfml)) { + p = strcpy2(p, op->operand); + } else { + *p++ = '('; + *p++ = '['; + p = catSlfml(p, &slfml); + p = strcpy2(p, strpbrk(op->operand, "],")); + } + break; + + case PCIDXB: // (bd,pc,ix) -> (label,pc,ix) + if (!getLabel(op, &slfml)) return strcpy2(p, op->operand); + + *p++ = '('; + p = catSlfml(p, &slfml); + // ワード範囲のbd.lに対する最適化抑制のためのサイズ".l"は残す + return strcpy2(p, rewindToBDSize(op, strchr(op->operand, ','))); + + case PCPOSTIDX: // ([bd,pc],ix,od) -> ([label,pc],ix,od) + case PCPREIDX: // ([bd,pc,ix],od) -> ([label,pc,ix],od) + // ベースディスプレースメントはワード(PC相対)、ロング(PC相対)、 + // ロング(リロケート情報あり、zpc)のパターンがある + if (!getLabel(op, &slfml)) { + p = strcpy2(p, op->operand); + } else { + *p++ = '('; + *p++ = '['; + p = catSlfml(p, &slfml); + // ワード範囲のbd.lに対する最適化抑制のためのサイズ".l"は残す + p = strcpy2(p, rewindToBDSize(op, strpbrk(op->operand, "],"))); + } + break; + } + + // アウターディスプレースメント + if (op->exod == 4 && INPROG(op->opval2, op->eaadrs2)) { + makeSymLabFormula(&slfml, op->opval2); + while (*(--p) != ',') + ; + p += 1; + p = catSlfml(p, &slfml); + *p++ = ')'; + } + return p; } -/* - - 初期化データを出力する(下請け) - -*/ -private address -idatagen_sub (address pc, address wkpc, address pcend, lblmode mode) -{ - - while (pc < pcend) { - ULONG byte = pcend - pc; - - switch (mode & 0xff) { - case LONGSIZE: - if (byte != 4) - goto XX; - if (mode & CODEPTR) { - ULONG x = peekl (wkpc); - char* s = (x == 0) ? PSEUDO DC_L "_btext\t* $%08x" CR - : (x == HeadOSK.name) ? PSEUDO DC_L "_bname\t* $%08x" CR - : PSEUDO DC_L "L%06x" CR; - outputf (s, x); - } else if (mode & DATAPTR) - outputf (PSEUDO DC_L "L%06x" CR, peekl (wkpc) + BeginBSS); - else - outputf (PSEUDO DC_L "$%08x" CR, peekl (wkpc)); - break; - - case WORDSIZE: - if (byte != 2) - goto XX; - outputf (PSEUDO DC_W "$%04x" CR, peekw (wkpc)); - break; - - default: -XX: byteout ((ULONG)wkpc - (ULONG)Top + (ULONG)Head.base, byte, FALSE); - } - pc += byte; - wkpc += byte; - } - return wkpc; +// ラベル定義のコロン文字列を得る +// 既定値の-C2の場合、通常ラベル ":"、外部宣言ラベル "::" +static const char* getColonForLabelDefine(int xdef) { + switch (Dis.symbolColonNum) { + default: + case SYMBOL_COLON_OMIT: + break; + case SYMBOL_COLON_ONE: + return ":"; + case SYMBOL_COLON_AUTO: + return xdef ? "::" : ":"; + case SYMBOL_COLON_TWO: + return "::"; + } + return ""; } -/* - - 初期化データを出力する - - input: - end : block end address - lptr : lblbuf* ( contains block start address ) - -*/ -private lblbuf* -idatagen (address end, lblbuf* lptr) -{ - address pc = lptr->label; - address wkpc = Top - (ULONG) Head.base + (ULONG) HeadOSK.idata + 8; - - newline (pc); - - while (pc < end) { - lblmode mode = lptr->mode; - - do { - lptr = Next (lptr); - } while (lptr->shift); - - label_line_out (pc, mode); - - DEBUG_PRINT (("PC=%08x, NEXT=%08x, MODE=%08x\n", pc, lptr->label, mode)); - - wkpc = idatagen_sub (pc, wkpc, lptr->label, mode); - pc = nlabel; - } - - return lptr; +// ラベル定義行出力 +// 引数 +// adrs: label address +// mode: label mode +// sectType: セクション番号(XDEF_TEXTなど) +// 0の場合はラベルファイルで追加されたシンボルだけを出力する。 +// last: TRUEならソースコード最後尾のラベル +// +// シンボル名が定義されていれば「シンボル名::」、未定義なら「Lxxxxxx:」などの +// 形式で出力する(コロンの数やラベル先頭文字はオプションの状態で変わる)。 +// シンボル属性によっては全く出力されないこともある。 +// +void label_line_out(address adrs, lblmode mode, int sectType, boolean last, + LineType lineType) { + symbol* symbolptr; + SymbolLabelFormula slfml; + const char* colon; + + if (isHIDDEN(mode)) return; + + if ((symbolptr = symbol_search(adrs)) != NULL) { + symlist* sym = &symbolptr->first; + do { + if (sym->type == (UWORD)sectType || (!last && sym->type == 0)) { + colon = getColonForLabelDefine(sym->type); + outputDirective2(lineType, adrs, sym->sym, colon); + } + sym = sym->next; + } while (sym); + return; + } + + // 各セクションの最後尾はシンボルテーブルで定義されたラベル以外は出力しない + if (last && sectType) return; + + // シンボル名が無ければ Lxxxxxx: の形式で出力する + makeBareLabel(&slfml, adrs); + colon = getColonForLabelDefine(0); + outputDirective2(lineType, adrs, slfml.expr, colon); } +const char* ctimez(time_t* clock) { + char* p = ctime(clock); -/* - - vsect ラベル出力 - - input : - adrs : label address - mode : label mode - -*/ -private void -vlabelout (address adrs, lblmode mode) -{ - char buff[128]; - int opt_c_save = option_C; - - if (isHIDDEN (mode)) - return; - - if (opt_c_save == 0) - option_C = 1; /* 非初期化 vsect はラベルだけの記述は出来ない */ - label_line_out (adrs, mode); - option_C = opt_c_save; - outputa (buff); + if (p == NULL) return "(invalid time)"; + removeTailLf(p); + return p; } -/* - - ワードテーブルの出力 - - input: - pc : word table begin address - pcend : word table end address - -*/ -private void -wgen (address pc, address pcend) -{ - char buf[128]; - address store; - - charout ('w'); - - for (store = pc + Ofst; store + 2 <= pcend + Ofst; store += 2) { - address label = (int)*(signed short*)store; - - if ((LONG)label < (LONG)BeginTEXT) { - make_proper_symbol (buf, BeginTEXT); - strcat (buf, "-"); - itox6d (buf + strlen (buf), (ULONG)(BeginTEXT - label)); - } else if ((LONG)label > (LONG)Last) { - make_proper_symbol (work, Last); - strcat (buf, "+"); - itox6d (buf + strlen (buf), (ULONG)(label - Last)); - } else - make_proper_symbol (work, label); - - output_opecode (PSEUDO DC_W); - outputa (buf); - newline (store - Ofst); - } - - if (store != pcend + Ofst) - dataout (store - Ofst, pcend + Ofst - store, UNKNOWN); +static char* mputype_numstr(mputypes m) { + if (m & M000) return "68000"; + if (m & M010) return "68010"; + if (m & M020) return "68020"; + if (m & M030) return "68030"; + if (m & M040) return "68040"; + /* if (m & M060) */ + return "68060"; } -#endif /* OSKDIS */ - - -/* EOF */ +// EOF diff --git a/src/generate.h b/src/generate.h index 1ab9456..2aea5b3 100644 --- a/src/generate.h +++ b/src/generate.h @@ -1,57 +1,44 @@ -/* $Id: generate.h,v 1.1 1996/10/24 04:27:44 ryo freeze $ - * - * ソースコードジェネレータ - * ソースコードジェネレートモジュールヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef GENERATE_H -#define GENERATE_H - - -#include /* typedef time_t */ -#include "estruct.h" /* typedef LONG, ULONG */ - -typedef enum { - SIZE_NORMAL, - SIZE_OMIT, - SIZE_NOT_OMIT -} size_mode; - -extern void generate (char*, char*, time_t, int, char*[]); -extern void disasmlist (char*, char*, time_t); -extern void byteout_for_xoption (address, ULONG, char*); -extern void modify_operand (disasm*); -extern char* make_symbol (char*, address, LONG); -extern void make_proper_symbol (char*, address); - -extern int Data_width; -extern int String_width; -extern int Compress_len; -extern int Adrsline; -extern int Xtab, Atab; -extern int SymbolColonNum; -extern char Label_first_char; -extern short sp_a7_flag; -extern short Old_syntax; -extern size_mode Generate_SizeMode; - -extern char opsize[]; - -#ifdef OSKDIS -extern char* OS9label [0x100]; -extern char* MATHlabel[0x100]; -extern char* CIOlabel [0x100]; -#else -extern char** IOCSlabel; -extern char IOCSCallName[16]; -extern const char* Header_filename; -#endif /* OSKDIS */ - - -#endif /* GENERATE_H */ - -/* EOF */ +// ソースコードジェネレータ +// ソースコードジェネレートモジュール ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#ifndef GENERATE_H +#define GENERATE_H + +#include // time_t + +#include "disasm.h" +#include "estruct.h" +#include "label.h" +#include "output.h" + +typedef struct { + opesize size; + int length; +} SizeLength; + +extern char* make_proper_symbol(char*, address); +extern void com(const char* fmt, ...) GCC_PRINTF(1, 2); +extern void comBlank(void); +extern void outputHeaderCpu(void); +extern void generate(char* xfilename, char* sfilename, time_t filedate, + const char* argv0, char* cmdline); +extern lblbuf* generateSection(char* sfilename, char* section, address end, + lblbuf* lptr, int type, int* currentType); +extern void disasmlist(char*); +extern SizeLength getSizeBytes(opesize size); +extern SizeLength getSizeLength(SizeLength sb, int bytes); +extern void dataoutDc(address pc, codeptr store, opesize size, ULONG bytes, + ULONG bytesPerUnit); +extern void dataoutDcByte(address pc, address pcend); +extern void label_line_out(address adrs, lblmode mode, int sectType, + boolean last, LineType lineType); +extern const char* ctimez(time_t* clock); +extern void otherDirective(const char* s); +extern void otherDirective2(const char* s1, const char* s2); + +#endif + +// EOF diff --git a/src/getopt.c b/src/getopt.c index b80e79e..fbf80c5 100644 --- a/src/getopt.c +++ b/src/getopt.c @@ -1,7 +1,7 @@ /* * PROJECT C Library, X68000 PROGRAMMING INTERFACE DEFINITION * -------------------------------------------------------------------- - * This file is written by the Project C Library Group, and completely + * This file is written by the Project C Library Group, and completely * in public domain. You can freely use, copy, modify, and redistribute * the whole contents, without this notice. * -------------------------------------------------------------------- @@ -9,193 +9,186 @@ */ /* System headers */ +#include "getopt.h" + #include #include -#include "getopt.h" - -char *optarg; /* 引数を指すポインタ */ -int optind = -1; /* ARGV の現在のインデックス */ -static int opterr = 1; /* エラー表示フラグ */ -static int _getopt_no_ordering; /* ORDER フラグ */ +char *optarg; /* 引数を指すポインタ */ +int optind = -1; /* ARGV の現在のインデックス */ +static int opterr = 1; /* エラー表示フラグ */ +static int _getopt_no_ordering; /* ORDER フラグ */ /* File scope functions */ -static void rotate_right (char *vector[], int size) -{ - char *temp; +static void rotate_right(char *vector[], int size) { + char *temp; - /* 最後尾を保存 */ - temp = vector[size - 1]; + /* 最後尾を保存 */ + temp = vector[size - 1]; - /* size 分ローテート */ - while (size--) - vector[size] = vector[size - 1]; + /* size 分ローテート */ + while (size--) vector[size] = vector[size - 1]; - /* 先頭に保存していたものを... */ - vector[0] = temp; + /* 先頭に保存していたものを... */ + vector[0] = temp; } +#if __GNUC__ >= 3 +#define GCC_UNUSED __attribute__((unused)) +#else +#define GCC_UNUSED +#endif + /* Functions */ -int dis_getopt (int argc, char *argv[], const char *options) -{ - int index; /* 現在のインデックス */ - int next; /* 次のインデックス */ - int optchar; /* オプション文字 */ - char *string; /* オプション文字列 */ - const char *ptr; /* options 探査用 */ - - static int init; /* 次回初期化する必要あり */ - static int savepoint; /* 入れ換え用の記憶ポイント */ - static int rotated; /* 交換フラグ */ - static int comidx; /* 複合インデックス */ +int dis_getopt(GCC_UNUSED int argc, char *argv[], const char *options) { + int index; /* 現在のインデックス */ + int next; /* 次のインデックス */ + int optchar; /* オプション文字 */ + char *string; /* オプション文字列 */ + const char *ptr; /* options 探査用 */ + + static int init; /* 次回初期化する必要あり */ + static int savepoint; /* 入れ換え用の記憶ポイント */ + static int rotated; /* 交換フラグ */ + static int comidx; /* 複合インデックス */ #ifdef __LIBC__ -#define ERR(fmt,arg1,arg2) if (opterr) eprintf(fmt,arg1,arg2) +#define ERR(fmt, arg1, arg2) \ + if (opterr) eprintf(fmt, arg1, arg2) #else -#define ERR(fmt,arg1,arg2) if (opterr) fprintf(stderr,fmt,arg1,arg2) +#define ERR(fmt, arg1, arg2) \ + if (opterr) fprintf(stderr, fmt, arg1, arg2) #endif - /* 初期化の必要があれば初期化する */ - if (init || optind < 0) { - optind = 1; - optarg = 0; - rotated = 0; - init = 0; - comidx = 1; - savepoint = 0; + /* 初期化の必要があれば初期化する */ + if (init || optind < 0) { + optind = 1; + optarg = 0; + rotated = 0; + init = 0; + comidx = 1; + savepoint = 0; + } + + /* 捜査開始位置を設定 */ + index = optind; + +again: + + /* 引数を取り出す */ + string = argv[index]; + next = index + 1; + + /* すでに終りか? */ + if (string == 0) { + if (savepoint > 0) optind = savepoint; + init = 1; + return EOF; + } + + /* '-' で始まるか? */ + if (*string == '-') { + /* フラグ分ポインタを進める */ + string += comidx; + + /* 正確に "-" か?ならば普通の引数 */ + if ((optchar = *string++) == '\0') goto normal_arg; + + /* ORDERING の必要があれば引数列を部分的にローテート */ + if (savepoint > 0) { + rotate_right(&argv[savepoint], index - savepoint + 1); + rotated = 1; + index = savepoint; + savepoint++; } - /* 捜査開始位置を設定 */ - index = optind; + /* 正確に "--" ならば強制的に捜査を終りにする */ + if (optchar == '-' && *string == '\0' && comidx == 1) { + init = 1; + optchar = EOF; + goto goback; + } - again: + /* オプション文字群の中から該当するものがあるか調べる */ + for (ptr = options; *ptr; ptr++) + if (*ptr != ':' && *ptr == optchar) break; - /* 引数を取り出す */ - string = argv[index]; - next = index + 1; + /* 引数を伴う場合ならばインデックスは初期化 */ + if (*string == '\0' || ptr[1] == ':') comidx = 1; - /* すでに終りか? */ - if (string == 0) { - if (savepoint > 0) - optind = savepoint; - init = 1; - return EOF; + /* さもなければ複合オプションインデックスを加算 */ + else { + comidx++; + index--; } - /* '-' で始まるか? */ - if (*string == '-') { - - /* フラグ分ポインタを進める */ - string += comidx; - - /* 正確に "-" か?ならば普通の引数 */ - if ((optchar = *string++) == '\0') - goto normal_arg; - - /* ORDERING の必要があれば引数列を部分的にローテート */ - if (savepoint > 0) { - rotate_right (&argv[savepoint], index - savepoint + 1); - rotated = 1; - index = savepoint; - savepoint++; - } - - /* 正確に "--" ならば強制的に捜査を終りにする */ - if (optchar == '-' && *string == '\0' && comidx == 1){ - init = 1; - optchar = EOF; - goto goback; - } - - /* オプション文字群の中から該当するものがあるか調べる */ - for (ptr = options; *ptr; ptr++) - if (*ptr != ':' && *ptr == optchar) - break; - - /* 引数を伴う場合ならばインデックスは初期化 */ - if (*string == '\0' || ptr[1] == ':') - comidx = 1; - - /* さもなければ複合オプションインデックスを加算 */ - else { - comidx++; - index--; - } - - /* 結局見つからなかったなら... */ - if (*ptr == '\0') { - ERR ("%s: unrecognized option '-%c'\n", argv[0], optchar); - optchar = '?'; - } - - /* 見つかったがオプション指定に ':' があるなら... */ - else if (ptr[1] == ':') { - - /* 同じ argv 内に引数があるか */ - if (*string) - optarg = string; - - /* options指定が ?:: ならば、同じ argv 内からしか見ない */ - else if (ptr[2] == ':') - optarg = NULL; - - /* 次の引数にあるか */ - else if (argv[next]) { - - /* ORDERING の必要があれば部分的に入れ換える */ - if (rotated) { - rotate_right (&argv[savepoint], next - savepoint + 1); - index = savepoint; - } - - /* なければ... */ - else - index++; - - /* 次の引数を返す */ - optarg = argv[index]; - - } - - /* なければ... */ - else { - ERR ("%s: option '-%c' requires an argument\n", argv[0], optchar); - optchar = '?'; - } - - } - - goback: - - /* 値を設定して戻る */ - rotated = 0; - savepoint = 0; - optind = index + 1; - return optchar; + /* 結局見つからなかったなら... */ + if (*ptr == '\0') { + ERR("%s: unrecognized option '-%c'\n", argv[0], optchar); + optchar = '?'; + } + /* 見つかったがオプション指定に ':' があるなら... */ + else if (ptr[1] == ':') { + /* 同じ argv 内に引数があるか */ + if (*string) optarg = string; + + /* options指定が ?:: ならば、同じ argv 内からしか見ない */ + else if (ptr[2] == ':') + optarg = NULL; + + /* 次の引数にあるか */ + else if (argv[next]) { + /* ORDERING の必要があれば部分的に入れ換える */ + if (rotated) { + rotate_right(&argv[savepoint], next - savepoint + 1); + index = savepoint; + } + + /* なければ... */ + else + index++; + + /* 次の引数を返す */ + optarg = argv[index]; + + } + + /* なければ... */ + else { + ERR("%s: option '-%c' requires an argument\n", argv[0], optchar); + optchar = '?'; + } } - /* 普通の引数 */ - else { + goback: - normal_arg: + /* 値を設定して戻る */ + rotated = 0; + savepoint = 0; + optind = index + 1; + return optchar; - /* ORDERING する必要があるか? */ - if (_getopt_no_ordering) { - init = 1; - optind = index; - return EOF; - } + } - /* 引数の位置を記憶し、次のオプションを調べる */ - else { - if (savepoint == 0) - savepoint = index; - index++; - goto again; - } + /* 普通の引数 */ + else { + normal_arg: + /* ORDERING する必要があるか? */ + if (_getopt_no_ordering) { + init = 1; + optind = index; + return EOF; + } + + /* 引数の位置を記憶し、次のオプションを調べる */ + else { + if (savepoint == 0) savepoint = index; + index++; + goto again; } + } } /* EOF */ diff --git a/src/getopt.h b/src/getopt.h index 3e6f077..06d3a4f 100644 --- a/src/getopt.h +++ b/src/getopt.h @@ -1,21 +1,17 @@ -/* - * - * ソースコードジェネレータ - * getopt - * Copyright (C) 2010 Tachibana - * - */ +// ソースコードジェネレータ +// getopt +// Copyright (C) 2010-2023 TcbnErik -#ifndef GETOPT_H -#define GETOPT_H +#ifndef GETOPT_H +#define GETOPT_H -#define optarg dis_optarg -#define optind dis_optind +#define optarg dis_optarg +#define optind dis_optind -extern char* optarg; -extern int optind; -extern int dis_getopt (int, char**, const char*); +extern char* optarg; +extern int optind; +extern int dis_getopt(int, char**, const char*); -#endif /* GETOPT_H */ +#endif -/* EOF */ +// EOF diff --git a/src/global.h b/src/global.h index 57e578f..c9caeb4 100644 --- a/src/global.h +++ b/src/global.h @@ -1,77 +1,274 @@ -/* $Id: global.h,v 1.1 1996/10/24 04:27:46 ryo freeze $ - * - * ソースコードジェネレータ - * 大域変数ヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef GLOBAL_H -#define GLOBAL_H +// ソースコードジェネレータ +// 大域変数ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik +#ifndef GLOBAL_H +#define GLOBAL_H + +#include +#include +#include + +#include "disasm.h" #include "estruct.h" +#include "opstr.h" +// 環境変数 +#define ENV_DIS_OPT "DIS_OPT" +#define ENV_dis_opt "dis_opt" +#define ENV_dis_header "dis_header" +#define ENV_dis_sxmac "dis_sxmac" +#define ENV_dis_include "dis_include" +#define ENV_include "include" -#ifndef NULL -#define NULL ((void *)0) -#endif +// branchSize +enum { + BRANCH_SIZE_AUTO, + BRANCH_SIZE_OMIT, + BRANCH_SIZE_NOT_OMIT, +}; -#ifdef __GNUC__ - #define INLINE inline - #undef alloca - #define alloca __builtin_alloca -#else - #define INLINE -#endif +// outputSymbol +enum { + OUTPUT_SYMBOL_OFF, + OUTPUT_SYMBOL_NORMAL, + OUTPUT_SYMBOL_ALL, +}; +// symbolColonNum +enum { + SYMBOL_COLON_OMIT, + SYMBOL_COLON_ONE, + SYMBOL_COLON_AUTO, + SYMBOL_COLON_TWO, +}; -#ifdef PROFILE -#define private extern -#else -#define private static -#endif +// backtrackReason +enum { + BACKTRACK_REASON_OFF, + BACKTRACK_REASON_PROGRAM, + BACKTRACK_REASON_ALL, +}; -extern xheader Head; -#ifdef OSKDIS -extern os9header HeadOSK; -#endif +// fileType +enum { + FILETYPE_AUTO, + FILETYPE_DUMP, + FILETYPE_X, + FILETYPE_R, + FILETYPE_Z, + FILETYPE_OSK, +}; -extern ULONG Top; /* ポインター同士の加算は出来ないので unsigned int */ -extern ULONG Ofst; -extern address BeginTEXT, /* = Head.base */ - BeginDATA, /* = Head.base + Head.text */ - BeginBSS, /* = Head.base + Head.text + Head.data */ -#ifndef OSKDIS - BeginSTACK, -#endif - Last; /* = Head.base + Head.text + Head.data + Head.bss */ -extern address Available_text_end; +// reltblZero +enum { + RELTBL_ZERO_REJECT, + RELTBL_ZERO_HEAD, + RELTBL_ZERO_ALL, +}; -extern int Absolute; -#define NOT_ABSOLUTE 0 -#define ABSOLUTE_ZFILE 1 -#define ABSOLUTE_ZOPT 2 +// dataWidth +#define DATA_WIDTH_MIN 1 +#define DATA_WIDTH_MAX 32 +#define DATA_WIDTH_DEFAULT 8 -extern boolean Exist_symbol; +// stringWidth +#define STRING_WIDTH_MIN 1 +#define STRING_WIDTH_MAX 200 +#define STRING_WIDTH_DEFAULT 60 -extern const char Version[]; -extern const char Date[]; -#ifdef OSKDIS -extern const char OSKEdition[]; -#endif +typedef struct { + void (*registerOperandLabel)(disasm* code); + void (*decodeTrap)(codeptr ptr, disasm* code); + char* (*d16AnToLabel)(char* p, operand* op); + void (*datagenWTable)(address pc, address pcend); + void (*makeRelocateTable)(void); + void (*parseSymbolTable)(ArrayBuffer*); + void (*analyzeProgram)(void); + void (*readIncludeFiles)(void); + void (*modifyMnemonic)(OpStringTable* ops); + void (*outputHeader)(char* filename, time_t filedate, const char* argv0, + char* comline, FILE* fpHeader); + void (*generate)(char* sfilename); +} Actions; + +typedef struct { + // メモリ上に読み込んだ実行ファイルの内容 + codeptr Top; // 実際にファイルのあるアドレス + codeptr Ofst; // 実際のアドレス - 仮想アドレス + + // セクションの情報 + address beginTEXT; // = Dis.base + address beginDATA; // = Dis.base + Dis.text + address beginBSS; // = Dis.base + Dis.text + Dis.data + address beginSTACK; + address LAST; // = Dis.base + Dis.text + Dis.data + Dis.bss + address availableTextEnd; // beginDATA or beginBSS + + // 実行ファイルの情報 + const Actions* actions; + address base; + address exec; + ULONG text; + ULONG data; + ULONG bss; + ULONG offset; + ULONG symbol; + time_t fileDate; + + // ファンクションコール(マクロ)のラベル + char** dosLabel GCC_ALIGN(4); + char** iocsLabel; + char** fefuncLabel; + char** sxLabel; + + // 環境変数の値 + char* dis_opt; + + // オプション設定 + char* execFile; + char* outputFile; + char* inputLabelFile; + char* outputLabelFile; + char* tableFile; + char* headerFile; + + // インクルードファイル + const char* doscallMac; // --include-doscall-mac= + const char* doscallMacPath; // 読み込んだファイルのフルパス名 + const char* iocscallMac; // --include-doscall-mac= + const char* iocscallMacPath; + const char* fefuncMac; // --include-fefunc-mac= + const char* fefuncMacPath; + const char* sxcallMacPath; -#define USEOPTION extern boolean /* useful expression */ -#define DIS_ENVNAME "dis_opt" /* 環境変数名 */ + int addressCommentLine; // -a + int stringLengthMin; // -n + int stringWidth; // -o + int dataWidth; // -w + int outputSplitByte; // -S + int compressLen; // -W -extern int Debug; /* Debug mode */ -#define BDEBUG 1 -#define BTRACE 2 -#define BREASON 4 -#define BLABEL 8 + uint8_t fpuidTable[8] GCC_ALIGN(4); + mputypes mpu; + fputypes fpu; + mmutypes mmu; + char commentStr[2]; // -K + char labelChar; // -L -#endif /* GLOBAL_H */ + uint8_t branchSize; // -b + uint8_t c; // ラベルチェックを行わない + uint8_t d; // デバイスドライバの時に指定 + uint8_t e; // ラベルファイルの出力 + uint8_t f; // バイト操作命令の不定バイトのチェックをしない + uint8_t g; // ラベルファイルを読み込む + uint8_t h; // データ領域中の$4e75(rts)の次のアドレスに注目する + uint8_t i; // 分岐先で未定義命令があってもデータ領域と見なさない + uint8_t acceptAddressError; // -j + uint8_t k; // 命令の中を指すラベルはないものと見なす + uint8_t l; // プログラム領域が見つからなくなるまで何度も捜すことをしない + uint8_t p; // データ領域中のプログラム領域を判別しない + uint8_t q; // メッセージを出力しない + uint8_t r; // 文字列に16進数のコメントを付ける + uint8_t outputSymbol; // -s + uint8_t acceptUnusedTrap; // -u + uint8_t v; // 単なる逆アセンブルリストの出力 + uint8_t x; // 実際のオペコードを16進数のコメントで付ける + uint8_t y; // 全てのデータ領域をプログラム領域でないか確かめることをしない + + uint8_t mnemonicAbbreviation; // -A + uint8_t B; // bra の後でも改行する + uint8_t symbolColonNum; // -C + uint8_t D; // データセクション中にもプログラムを認める + uint8_t E; // バイト操作命令の不定バイトの書き換えチェックをしない + uint8_t dbraToDbf; // -F + uint8_t argAfterCall; // -G + uint8_t I; // 命令の中を差すラベルのアドレスを表示する + uint8_t M; // 即値命令にコメントをつける + uint8_t N; // サイズがデフォルトなら付けない + uint8_t Q; // 環境変数 DIS_OPT, dis_opt を参照しない + uint8_t T; // テーブル記述ファイルを読み込む + uint8_t U; // ニーモニックを大文字で出力する + uint8_t backtrackReason; // -V + uint8_t Y; // 16進数を大文字で出力する + uint8_t Z; // 16進数をゼロサプレスする + + uint8_t undefReg; // -R1 + uint8_t undefExReg; // -R2 + uint8_t undefExScale; // -R4 + uint8_t undefExSize; // -R8 + + uint8_t a7ToSp; + uint8_t cpu32; + uint8_t deterministic; + uint8_t fileType; + uint8_t fpsp; + uint8_t inreal; + uint8_t isp; + uint8_t oldSyntax; + uint8_t overwrite; + uint8_t quietTable; // -q1 + uint8_t reltblZero; + uint8_t stripIncludePath; + uint8_t suppressDollar; // -Z1 + uint8_t sxWindow; // -u1 + + // 動作モード等 + ArrayBuffer reltblArray GCC_ALIGN(4); + ArrayBuffer symtblArray; + + // オプション以外の出力ソースコードの形式 + int UndefTab; // ";undefined inst." のタブ位置(3) + int Mtab; // -Mのタブ位置(5) + int Xtab; // -xのタブ位置(7) + int Atab; // -aのタブ位置(8、-x指定時は10) + opesize dbccSize; + char quoteChar; // 文字列を囲う記号(' or ") + + uint8_t hasSymbol; // シンボルテーブル + uint8_t needString; + uint8_t reasonVerbose; + uint8_t findLinkW; + +#ifdef OSKDIS + // ファンクションコール(マクロ)のラベル + char** OS9label; // OS9 F$???(I$???) + char** MATHlabel; // TCALL T$Math,T$??? + char** CIOlabel; // TCALL CIO$Trap,C$??? + + // 実行ファイルの情報 + UWORD oskModType; // (oskType >> 8) & 0x0f + UWORD oskSysRev; + ULONG oskSize; + ULONG oskOwner; + address oskName; + UWORD oskAccs; + UWORD oskType; + UWORD oskAttr; + UWORD oskEdition; + address oskUsage; + address oskSymbol; + address oskExcpt; + ULONG oskMem; + ULONG oskStack; + address oskIdata; + address oskIrefs; + address oskInit; + address oskTerm; + + // 読み込んだインクルードファイルのフルパス名 + const char* os9MacPath; + const char* mathMacPath; + const char* cioMacPath; +#endif + +} DisVars; + +extern DisVars Dis; + +#endif -/* EOF */ +// EOF diff --git a/src/hex.c b/src/hex.c index b44b9e0..0640715 100644 --- a/src/hex.c +++ b/src/hex.c @@ -1,161 +1,97 @@ -/* $Id: hex.c,v 1.1 1996/11/07 08:03:40 ryo freeze $ - * - * ソースコードジェネレータ - * 16進変換 , String 関数 - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#include /* strcpy */ +// ソースコードジェネレータ +// 16進変換 , String 関数 +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#include "estruct.h" #include "hex.h" +#include -char Hex[16] = "0123456789abcdef"; -int Zerosupress_mode = 0; +#include "estruct.h" +#include "global.h" -USEOPTION option_Z; +char Hex[16] = "0123456789abcdef"; +static char* ulongToDecimal(char* buf, ULONG n); -/* 手抜き ^^; */ -extern char* -itod2 (char* buf, ULONG n) -{ - int i = n % 100; +char* itod2(char* buf, ULONG n) { + char x = n; - if (i / 10) - *buf++ = (i / 10) + '0'; - *buf++ = (n % 10) + '0'; - *buf = '\0'; - return buf; + // 19以下の数を高速に変換する細工(trap #15用) + if (n >= 10) { + if (n >= 20) return ulongToDecimal(buf, n); + *buf++ = '1'; + x -= 10; + } + *buf++ = x + '0'; + *buf = '\0'; + return buf; } +static char* ulongToDecimal(char* buf, ULONG n) { + return buf + sprintf(buf, PRI_ULONG, n); +} -extern char* -itox (char* buf, ULONG n, int width) -{ - if (option_Z) { - if (n == 0) - *buf++ = '0'; - else { - char tmp[8]; - char* p = tmp + sizeof tmp; - int i; - - do { - /* 下位桁からテンポラリに変換 */ - *--p = Hex[n & 0xf]; - n >>= 4; - } while (n); - i = (tmp + sizeof tmp) - p; - do { - /* 上位桁からバッファに転送 */ - *buf++ = *p++; - } while (--i > 0); - } - } - +extern char* itox(char* buf, ULONG n, int width) { + if (Dis.Z) { + if (n == 0) + *buf++ = '0'; else { - char* p = buf += width; - int i; - - for (i = width; --i >= 0;) { - /* 下位桁から変換 */ - *--p = Hex[n & 0xf]; - n >>= 4; - } + char tmp[8]; + char* p = tmp + sizeof tmp; + int i = 0; + + do { + // 下位桁からテンポラリに変換 + i += 1; + *--p = Hex[n & 0xf]; + n >>= 4; + } while (n); + do { + // 上位桁からバッファに転送 + *buf++ = *p++; + } while (--i > 0); } + } - *buf = '\0'; - return buf; -} - - -#define DEFINE_ITOX(func, width) \ -extern char* \ -func (char *buf, ULONG n) \ -{ \ - char* p = buf += width; \ - int i; \ - \ - for (i = width; --i >= 0;) { \ - *--p = Hex[n & 0xf]; \ - n >>= 4; \ - } \ - *buf = '\0'; \ - return buf; \ -} - -DEFINE_ITOX (itox8_without_0supress, 8); -DEFINE_ITOX (itox6_without_0supress, 6); -DEFINE_ITOX (itox4_without_0supress, 4); + else { + char* p = buf += width; + int i; - -/**** 以下の関数は GNU C Compiler 使用時には inline 展開されます. ****/ - -#ifndef __GNUC__ - -extern char* -strend (char *p) -{ - while (*p++) - ; - return --p; -} - - -extern char* -itox2 (char* buf, ULONG n) -{ - if (!option_Z || n >= 0x10) { - /* 10 の位 */ - *buf++ = Hex[(n >> 4) & 0xf]; + for (i = width; --i >= 0;) { + /* 下位桁から変換 */ + *--p = Hex[n & 0xf]; + n >>= 4; } - /* 1 の位 */ - *buf++ = Hex[n & 0xf]; - *buf = '\0'; - return buf; -} - + } -extern char* -itox2_without_0supress (char* buf, ULONG n) -{ - *buf++ = Hex[(n >> 4) & 0xf]; - *buf++ = Hex[n & 0xf]; - *buf = '\0'; - return buf; + *buf = '\0'; + return buf; } +static char* itox_without_0supress(char* buf, ULONG n, int width) { + char* p = buf += width; + int i; -extern char* -itoxd (char* buf, ULONG n, int width) -{ - if (Zerosupress_mode != 1 || n >= 10) - *buf++ = '$'; - return (width == 2) ? itox2 (buf, n) - : itox (buf, n, width); + for (i = width; --i >= 0;) { + *--p = Hex[n & 0xf]; + n >>= 4; + } + *buf = '\0'; + return buf; } - -extern char* -itox6 (char* buf, ULONG n) -{ - return itox (buf, n, (n >= 0x1000000) ? 8 : 6); +char* itox8_without_0supress(char* buf, ULONG n) { + return itox_without_0supress(buf, n, 8); } - -extern char* -itox6d (char* buf, ULONG n) -{ - if (Zerosupress_mode != 1 || n >= 10) - *buf++ = '$'; - return itox6 (buf, n); +char* itox6_without_0supress(char* buf, ULONG n) { + return itox_without_0supress(buf, n, 6); } -#endif /* __GNUC__ */ +char* itox4_without_0supress(char* buf, ULONG n) { + return itox_without_0supress(buf, n, 4); +} -/* EOF */ +// EOF diff --git a/src/hex.h b/src/hex.h index 85a8b25..a3da301 100644 --- a/src/hex.h +++ b/src/hex.h @@ -1,104 +1,59 @@ -/* $Id: hex.h,v 1.1 1996/10/24 04:27:46 ryo freeze $ - * - * ソースコードジェネレータ - * 16進変換 , String 関数 ヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 16進変換, String 関数 ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef HEX_H -#define HEX_H +#ifndef HEX_H +#define HEX_H #include "global.h" - -#define itox8(p, n) itox (p, n, 8) -#define itox4(p, n) itox (p, n, 4) - -#define itox8d(p, n) itoxd (p, n, 8) -#define itox4d(p, n) itoxd (p, n, 4) -#define itox2d(p, n) itoxd (p, n, 2) - - -extern char* itod2 (char*, ULONG); /* 手抜き */ -extern char* itox (char*, ULONG, int); -extern char* itox8_without_0supress (char*, ULONG); -extern char* itox6_without_0supress (char*, ULONG); -extern char* itox4_without_0supress (char*, ULONG); +extern char* itod2(char*, ULONG); +extern char* itox(char*, ULONG, int); +extern char* itox8_without_0supress(char*, ULONG); +extern char* itox6_without_0supress(char*, ULONG); +extern char* itox4_without_0supress(char*, ULONG); extern char Hex[16]; -extern int Zerosupress_mode; - -#ifdef __GNUC__ - -INLINE static char* -strend (char *p) -{ - while (*p++) - ; - return --p; -} - -INLINE static char* -itox2 (char* buf, ULONG n) -{ - USEOPTION option_Z; /* extern boolean option_Z; */ - - if (!option_Z || n >= 0x10) { - /* 10 の位 */ - *buf++ = Hex[(n >> 4) & 0xf]; - } - /* 1 の位 */ - *buf++ = Hex[n & 0xf]; - *buf = '\0'; - return buf; -} - -INLINE static char* -itox2_without_0supress (char *buf, ULONG n) -{ +static inline char* itox2(char* buf, ULONG n) { + if (!Dis.Z || n >= 0x10) { + // 10 の位 *buf++ = Hex[(n >> 4) & 0xf]; - *buf++ = Hex[n & 0xf]; - *buf = '\0'; - return buf; + } + // 1 の位 + *buf++ = Hex[n & 0xf]; + *buf = '\0'; + return buf; } -INLINE static char* -itoxd (char* buf, ULONG n, int width) -{ - if (Zerosupress_mode != 1 || n >= 10) - *buf++ = '$'; - return (width == 2) ? itox2 (buf, n) - : itox (buf, n, width); +static inline char* itox2_without_0supress(char* buf, ULONG n) { + *buf++ = Hex[(n >> 4) & 0xf]; + *buf++ = Hex[n & 0xf]; + *buf = '\0'; + return buf; } -INLINE static char* -itox6 (char* buf, ULONG n) -{ - return itox (buf, n, (n >= 0x1000000) ? 8 : 6); +static inline char* itoxd(char* buf, ULONG n, int width) { + if (!Dis.suppressDollar || n >= 10) *buf++ = '$'; + return (width == 2) ? itox2(buf, n) : itox(buf, n, width); } -INLINE static char* -itox6d (char* buf, ULONG n) -{ - if (Zerosupress_mode != 1 || n >= 10) - *buf++ = '$'; - return itox6 (buf, n); +static inline char* itox6(char* buf, ULONG n) { + return itox(buf, n, (n >= 0x1000000) ? 8 : 6); } -#else - -extern char* strend (char*); -extern char* itox2 (char*, ULONG); -extern char* itox2_without_0supress (char*, ULONG); -extern char* itoxd (char*, ULONG, int); -extern char* itox6 (char*, ULONG); -extern char* itox6d (char*, ULONG); +static inline char* itox6d(char* buf, ULONG n) { + if (!Dis.suppressDollar || n >= 10) *buf++ = '$'; + return itox6(buf, n); +} -#endif /* !__GNUC__ */ +static inline char* itox8(char* buf, ULONG n) { return itox(buf, n, 8); } +static inline char* itox4(char* buf, ULONG n) { return itox(buf, n, 4); } +static inline char* itox8d(char* buf, ULONG n) { return itoxd(buf, n, 8); } +static inline char* itox4d(char* buf, ULONG n) { return itoxd(buf, n, 4); } +static inline char* itox2d(char* buf, ULONG n) { return itoxd(buf, n, 2); } -#endif /* HEX_H */ +#endif diff --git a/src/human.c b/src/human.c new file mode 100644 index 0000000..862fb5b --- /dev/null +++ b/src/human.c @@ -0,0 +1,405 @@ +// ソースコードジェネレータ +// Human68k +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "human.h" + +#include +#include // getenv() +#include + +#include "analyze.h" +#include "estruct.h" +#include "etc.h" +#include "generate.h" +#include "global.h" +#include "include.h" +#include "label.h" +#include "offset.h" +#include "opstr.h" +#include "output.h" +#include "symbol.h" +#include "version.h" + +// X形式実行ファイルのヘッダ +enum { + XHEAD_ID = 0x00, // UBYTE[2] "HU" + XHEAD_BASE = 0x04, // address + XHEAD_EXEC = 0x08, // address + XHEAD_TEXT = 0x0c, // ULONG + XHEAD_DATA = 0x10, // ULONG + XHEAD_BSS = 0x14, // ULONG + XHEAD_OFFSET = 0x18, // ULONG + XHEAD_SYMBOL = 0x1c, // ULONG + XHEAD_BIND = 0x3c, // ULONG + + XHEAD_SIZE = 0x40 +}; + +// Z形式実行ファイルのヘッダ +enum { + ZHEAD_ID = 0x00, // UBYTE[2] "\x60\x1a" + ZHEAD_TEXT = 0x02, // ULONG + ZHEAD_DATA = 0x06, // ULONG + ZHEAD_BSS = 0x0a, // ULONG + ZHEAD_BASE = 0x16, // address + + ZHEAD_SIZE = 0x1c +}; + +// デバイスヘッダの構造 +enum { + DH_NEXT = 0x00, // ULONG + DH_TYPE = 0x04, // UWORD + DH_STRATEGY = 0x06, // address + DH_INTERRUPT = 0x0a, // address + DH_NAME = 0x0e, // UBYTE[8] + DH_SIZE = 0x16, +}; + +// ファイル情報を書き出す +static void outputFileInfoHuman(char* filename, time_t filedate, + const char* argv0, char* comline) { + com("============================================="); + com(" Filename %s", filename); + if (!Dis.deterministic) { + com(" Time Stamp %s", ctimez(&filedate)); + } + comBlank(); + com(" Base address " PRI_ADRS, Dis.base); + com(" Exec address " PRI_ADRS, Dis.exec); + com(" Text size " PRI_ULHEX " byte(s)", Dis.text); + com(" Data size " PRI_ULHEX " byte(s)", Dis.data); + com(" Bss size " PRI_ULHEX " byte(s)", Dis.bss); + + com(" %d Labels", get_Labelnum()); + + if (!Dis.deterministic) { + time_t t = time(NULL); + com(" Code Generate date %s", ctimez(&t)); + } + if (Dis.dis_opt != NULL) { + com(" Environment %s", Dis.dis_opt); + } + com(" Commandline %s %s", argv0, comline); + if (!Dis.deterministic) { + com(" %s", ProgramAndVersion); + } + com("============================================="); + outputBlank(); +} + +// dis_headerで指定されたファイルの中身を書き出す +static void outputHeaderFromFile(FILE* fp) { + char buffer[256]; + + while (fgets(buffer, sizeof buffer, fp)) { + removeTailLf(buffer); + outputDirective(LINETYPE_OTHER, (address)0, buffer); + } +} + +// 外部定義シンボルを書き出す +static void outputHeaderXdef(void) { + uint8_t c = Dis.symbolColonNum; + char* colon = (c == SYMBOL_COLON_OMIT) ? "" + : (c == SYMBOL_COLON_ONE) ? ":" + : "::"; + + if (outputSymbolSection(&Dis.symtblArray, colon)) outputBlank(); +} + +static void outputInclude(const char* path); + +// .include疑似命令(またはdis_headerの中身)を書き出す +static void outputIncludeHuman(FILE* fpHeader) { + if (fpHeader) { + outputHeaderFromFile(fpHeader); + } else { + outputInclude(Dis.doscallMacPath); + outputInclude(Dis.iocscallMacPath); + outputInclude(Dis.fefuncMacPath); + outputInclude(Dis.sxcallMacPath); + } + outputBlank(); +} + +// 有効なパス名からファイル名部分を取り出す +static const char* getBasename(const char* path) { + const char* s = strrchr(path, '/'); + if (s == NULL) s = strrchr(path, ':'); + return (s == NULL) ? path : s + 1; +} + +static void outputInclude(const char* path) { + if (path == NULL) return; + + if (Dis.stripIncludePath) path = getBasename(path); + + otherDirective2(OpString.include_, path); +} + +// ヘッダを書き出す +static void outputHeaderHuman(char* filename, time_t filedate, + const char* argv0, char* comline, + FILE* fpHeader) { + outputFileInfoHuman(filename, filedate, argv0, comline); + outputIncludeHuman(fpHeader); + outputHeaderXdef(); + outputHeaderCpu(); +} + +// .end疑似命令を書き出す +static void outputEnd(void) { + SymbolLabelFormula slfml; + makeSymLabFormula(&slfml, Dis.exec); + + outputBlank(); + { + const char* array[] = {OpString.end, "\t", slfml.symbol, slfml.expr}; + outputDirectiveArray(LINETYPE_OTHER, 0, _countof(array), array); + } +} + +// .text/.data/.bss/.stackセクションを出力する +static void generateHuman(char* sfilename) { + int type = XDEF_TEXT; + lblbuf* lptr = next(Dis.beginTEXT); + + lptr = generateSection(sfilename, OpString.text, Dis.beginDATA, lptr, + XDEF_TEXT, &type); + lptr = generateSection(sfilename, OpString.data, Dis.beginBSS, lptr, + XDEF_DATA, &type); + lptr = generateSection(sfilename, OpString.bss, Dis.beginSTACK, lptr, + XDEF_BSS, &type); + lptr = generateSection(sfilename, OpString.stack, Dis.LAST, lptr, XDEF_STACK, + &type); + + // 末尾にある属性0のシンボルを出力する + label_line_out(lptr->label, lptr->mode, 0, TRUE, LINETYPE_OTHER); + + outputEnd(); +} + +//////////////////////////// + +static const IncludeSpec doscallSpec = { + (1 << 8) - 1, 0xff00, // + &Dis.dosLabel, &Dis.doscallMacPath, + &Dis.doscallMac, OpString.doscall // +}; +static const IncludeSpec fefuncSpec = { + (1 << 8) - 1, 0xfe00, // + &Dis.fefuncLabel, &Dis.fefuncMacPath, + &Dis.fefuncMac, OpString.fefunc // +}; +static const IncludeSpec iocscallSpec = { + (1 << 8) - 1, 0x0000, // + &Dis.iocsLabel, &Dis.iocscallMacPath, + &Dis.iocscallMac, OpString.iocscall // +}; +static const IncludeSpec sxcallSpec = { + (1 << 12) - 1, 0xa000, // + &Dis.sxLabel, &Dis.sxcallMacPath, + NULL, OpString.sxcall // +}; + +// 各種インクルードファイルを読み込む +static void readIncludeFilesHuman(void) { + IncludeEnvs env = {getenv(ENV_dis_include), getenv(ENV_include)}; + + readInludeFileFromEnv(&doscallSpec, &env); + readInludeFileFromEnv(&iocscallSpec, &env); + readInludeFileFromEnv(&fefuncSpec, &env); + + if (Dis.sxWindow) { + const char* sxmac = getenv(ENV_dis_sxmac); + if (sxmac && sxmac[0]) { + if (!readIncludeFile(&sxcallSpec, sxmac)) + err("%s をオープンできません。\n", sxmac); + } + } +} + +// デバイスドライバの解析 +static void analyzeDeviceDriver(void) { + address prev = (address)-1; + address dev = Dis.base; // テキストセクション先頭が最初のデバイスヘッダ + + setReasonVerbose(BACKTRACK_REASON_PROGRAM); + + do { + codeptr ptr = Dis.Ofst + dev; + + lblbuf* lblptr = search_label(dev); + if (lblptr && isDEVLABEL(lblptr->mode)) { + eprintf("\n警告: デバイスヘッダが循環しています(" PRI_ADRS " -> " PRI_ADRS + ")。", + prev, dev); + break; + } + + regist_label(dev + DH_NEXT, DATLABEL | LONGSIZE | FORCE | DEVLABEL); + regist_label(dev + DH_TYPE, DATLABEL | WORDSIZE | FORCE | HIDDEN); + + // ストラテジルーチンと割り込みルーチンはリロケート情報があるので登録不要 + // regist_label(dev + DH_STRATEGY, DATLABEL | LONGSIZE | FORCE); + // regist_label(dev + DH_INTERRUPT, DATLABEL | LONGSIZE | FORCE); + + regist_label(dev + DH_NAME, DATLABEL | STRING | FORCE | HIDDEN); + regist_label(dev + DH_SIZE, DATLABEL | UNKNOWN); + + analyze((address)peekl(ptr + DH_STRATEGY), ANALYZE_IGNOREFAULT); + analyze((address)peekl(ptr + DH_INTERRUPT), ANALYZE_IGNOREFAULT); + + prev = dev; + dev = peekl(ptr + DH_NEXT); + } while (isEven(dev) && (Dis.base < dev) && + (dev < Dis.beginBSS)); // SCSIDRV.SYS 対策 +} + +// プログラム領域を解析する +static void analyzeProgramHuman(void) { + eprintf("プログラム領域解析中です。"); + setReasonVerbose(BACKTRACK_REASON_PROGRAM); + + if (Dis.d) { + analyzeDeviceDriver(); + if (Dis.exec != Dis.base) + analyze(Dis.exec, Dis.i ? ANALYZE_IGNOREFAULT : ANALYZE_NORMAL); + } else + analyze(Dis.exec, ANALYZE_IGNOREFAULT); +} + +static void datagenWTableHuman(GCC_UNUSED address pc, + GCC_UNUSED address pcend) { + // 処理不要 +} + +static void modifyMnemonicHuman(GCC_UNUSED OpStringTable* ops) { + // 処理不要 +} + +// X/R/Z形式実行ファイルの処理関数 +static const Actions actionsHuman = { + NULL, // registerOperandLabel + NULL, // decodeTrap + NULL, // d16AnToLabel + datagenWTableHuman, // + makeRelocateTableHuman, // + parseSymbolTableHuman, // + analyzeProgramHuman, // + readIncludeFilesHuman, // + modifyMnemonicHuman, // + outputHeaderHuman, // + generateHuman // +}; + +// X形式実行ファイルのヘッダの正当性を調べる +static void validateXHeader(UBYTE* head) { + const ULONG MAIN_MEMORY_MAX_BYTES = 12 * 1024 * 1024; + const ULONG HIGH_MEMORY_MAX_BYTES = 256 * 1024 * 1024; + ULONG total = Dis.text + Dis.data + Dis.bss; + + // ハイメモリの最大量でもロードできない値なら実行ファイルとは考えられない + // オーバーフロー対策で個別の値でも比較 + if ((total > HIGH_MEMORY_MAX_BYTES) || (Dis.text > HIGH_MEMORY_MAX_BYTES) || + (Dis.data > HIGH_MEMORY_MAX_BYTES) || (Dis.bss > HIGH_MEMORY_MAX_BYTES)) { + err("X形式実行ファイルではありません。\n"); + } + + // ハイメモリ専用実行ファイルかもしれないので警告のみ + if (total > MAIN_MEMORY_MAX_BYTES) { + eprintf( + "実行時メモリ必要量が12MiBを超えるため、" + "X形式実行ファイルではない可能性があります。\n"); + } + + if (peekl(head + XHEAD_BIND) != 0) { + err("このファイルはバインドされています。\n" + "unbindコマンド等で展開してからソースジェネレートして下さい。\n"); + } +} + +// X形式実行ファイルのヘッダを読み込む +static void loadXHeader(FILE* fp) { + UBYTE head[XHEAD_SIZE]; + + if (fread(head, 1, sizeof(head), fp) != sizeof(head) || + peekw(head + XHEAD_ID) != XHEAD_ID_VALUE) { + err("X形式実行ファイルではありません。\n"); + } + + Dis.base = (address)peekl(head + XHEAD_BASE); + Dis.exec = (address)peekl(head + XHEAD_EXEC); + Dis.text = peekl(head + XHEAD_TEXT); + Dis.data = peekl(head + XHEAD_DATA); + Dis.bss = peekl(head + XHEAD_BSS); + Dis.offset = peekl(head + XHEAD_OFFSET); + Dis.symbol = peekl(head + XHEAD_SYMBOL); + + validateXHeader(head); +} + +// Z形式実行ファイルのヘッダを読み込む +static void loadZHeader(FILE* fp) { + UBYTE head[ZHEAD_SIZE]; + + if (fread(head, 1, sizeof(head), fp) != sizeof(head) || + peekw(head + ZHEAD_ID) != ZHEAD_ID_VALUE) { + err("Z形式実行ファイルではありません。\n"); + } + + Dis.exec = Dis.base = (address)peekl(head + ZHEAD_BASE); + Dis.text = peekl(head + ZHEAD_TEXT); + Dis.data = peekl(head + ZHEAD_DATA); + Dis.bss = peekl(head + ZHEAD_BSS); +} + +// (Human68k) 実行ファイルのヘッダを読み込む +void loadHeaderHuman(FILE* fp, ULONG fileSize) { + switch (Dis.fileType) { + default: + internalError(__FILE__, __LINE__, "Dis.fileType"); + + case FILETYPE_DUMP: + case FILETYPE_R: + Dis.text = fileSize; + break; + case FILETYPE_X: + loadXHeader(fp); + break; + case FILETYPE_Z: + loadZHeader(fp); + break; + + case FILETYPE_OSK: + err("OS-9/X680x0のモジュールには対応していません。\n"); + break; + } + + Dis.beginTEXT = Dis.base; + Dis.beginDATA = Dis.beginTEXT + Dis.text; + Dis.beginBSS = Dis.beginDATA + Dis.data; + Dis.LAST = Dis.beginSTACK = Dis.beginBSS + Dis.bss; + Dis.availableTextEnd = (Dis.D ? Dis.beginBSS : Dis.beginDATA); + + Dis.actions = &actionsHuman; +} + +// EOF diff --git a/src/human.h b/src/human.h new file mode 100644 index 0000000..e2a19d7 --- /dev/null +++ b/src/human.h @@ -0,0 +1,37 @@ +// ソースコードジェネレータ +// Human68k ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef HUMAN_H +#define HUMAN_H + +#include + +#include "estruct.h" + +// 実行ファイルのヘッダID +enum { + XHEAD_ID_VALUE = (('H' << 8) + 'U'), + ZHEAD_ID_VALUE = 0x601a, +}; + +extern void loadHeaderHuman(FILE* fp, ULONG fileSize); + +#endif + +// EOF diff --git a/src/include.c b/src/include.c index 52e269f..0ca0c1c 100644 --- a/src/include.c +++ b/src/include.c @@ -1,372 +1,215 @@ -/* $Id: include.c,v 1.1 1996/11/07 08:03:42 ryo freeze $ - * - * ソースコードジェネレータ - * インクルードファイル読み込みモジュール - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// インクルードファイル読み込みモジュール +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "include.h" #include -#include /* getenv() */ #include -#include "disasm.h" /* OSlabel , FElabel , SXlabel */ -#include "estruct.h" #include "etc.h" -#include "generate.h" /* IOCSlabel */ #include "global.h" -#include "include.h" +#include "opstr.h" + +// static 関数プロトタイプ +static boolean tryReadfile(const IncludeSpec* spec, const char* filename, + const char* path); + +// 各パスからインクルードファイルを探し、見つけたファイルを読み込む +// 1) ./ (-Y オプション指定時のみ) +// 2) $dis_include/ +// 3) $include/ +// の順に readfile() を試す。 +void readInludeFileFromEnv(const IncludeSpec* spec, IncludeEnvs* env) { + const char* filename = *spec->filenamePtr; + int path_flag; + + // --exclude-***call 指定時は読み込まない + if (filename == NULL || filename[0] == '\0') return; + + path_flag = strchr(filename, ':') || strchr(filename, '/'); + + // -Y オプション指定時はカレントディレクトリから検索する + // ファイル名にパスデリミタが含まれる場合もそのまま検索 + if (path_flag || Dis.Y) { + if (readIncludeFile(spec, filename)) return; + } + + // パスデリミタが含まれなければ環境変数 dis_include、include + // のパスから検索する + if (!path_flag) { + if (tryReadfile(spec, filename, env->dis_include)) return; + if (tryReadfile(spec, filename, env->include)) return; + } + + if (path_flag || env->dis_include || env->include) + err("%s をオープンできません。\n", filename); + else + err("環境変数 " ENV_dis_include ", " ENV_include + " が設定されていません。\n"); +} +// パスとファイル名を指定して読み込む +static boolean tryReadfile(const IncludeSpec* spec, const char* filename, + const char* path) { + char* fullpath; -USEOPTION option_Y; + if (path == NULL) return FALSE; + fullpath = Malloc(strlen(path) + 1 + strlen(filename) + 1); + strcat(strcat(strcpy(fullpath, path), "/"), filename); -/* External variables */ -#ifdef OSKDIS -const char* OS9_mac_path; -const char* MATH_mac_path; -const char* CIO_mac_path; -#else -const char* Doscall_mac_path; -const char* Iocscall_mac_path; -const char* Fefunc_mac_path; -const char* Sxcall_mac_path; + if (readIncludeFile(spec, fullpath)) { + // フルパス名はソースコード出力時に使うのでバッファは解放しない + return TRUE; + } -const char* doscall_mac = "doscall.mac"; -const char* iocscall_mac = "iocscall.mac"; -const char* fefunc_mac = "fefunc.mac"; -#endif /* OSKDIS */ + Mfree(fullpath); + return FALSE; +} +#define IS_EOL(p) \ + ((*(p) < 0x20) || (*(p) == '*') || (*(p) == ';') || (*(p) == '#')) -/* static 関数プロトタイプ */ -#ifndef OSKDIS -private void search_and_readfile (const char** bufptr, const char* filename, - char*** label, int hbyte, char* callname, int max); -#endif /* !OSKDIS */ -private int readfile (const char* filename, char*** label, - int hbyte, char* callname, int max); +/* + includeファイルから読み込んだ文字列をシンボル名、疑似命令名、 + 数字(または仮引数名)に分割し、各文字列へのポインタを設定して返す + 文字列の内容が正しくなかった場合は0、正しければ1を返す +*/ +static int separate_line(char* ptr, char** symptr, char** psdptr, + char** parptr) { + char* p = ptr; + char c; -#ifdef OSKDIS -/* + /* 行頭の空白を飛ばす */ + while ((*p == ' ') || (*p == '\t')) p++; - os9defs.d mathdefs.d ciodefs.d を - 環境変数 DISDEFS にしたがって読み込む. + /* 空行または注釈行ならエラー */ + if (IS_EOL(p)) return 0; -*/ + /* シンボル名の収得 */ + *symptr = p; -extern void -load_OS_sym (void) -{ - static const char os9defs_d[] = "os9defs.d"; - static const char mathdefs_d[] = "mathdefs.d"; - static const char ciodefs_d[] = "ciodefs.d"; - char* dis_inc; - int plen; - - eprintf ("%s %s %s を読み込みます.\n", os9defs_d, mathdefs_d, ciodefs_d); - - if ((dis_inc = getenv ("DISDEFS")) == NULL) { - /* err ("環境変数 DISDEFS が設定されていません.\n"); */ - eprintf ("環境変数 DISDEFS が設定されていません.\n"); - return; - } - plen = strlen (dis_inc); + /* シンボル名の末尾をNULにする */ + p = strpbrk(p, ":. \t"); + if (p == NULL) return 0; + c = *p; + *p++ = '\0'; - OS9_mac_path = Malloc (plen + sizeof os9defs_d + 2); - strcat (strcat (strcpy (OS9_mac_path, dis_inc), "/"), os9defs_d); - if (!readfile (OS9_mac_path, OS9label, 0, "OS9")) { - eprintf ("%s をオープン出来ません.\n", os9defs_d); - OS9_mac_path = NULL; - } + /* シンボル定義の':'、空白、疑似命令の'.'を飛ばす */ + while (c == ':') c = *p++; + while ((c == ' ') || (c == '\t')) c = *p++; + if (c == '.') c = *p++; + p--; - MATH_mac_path = Malloc (plen + sizeof mathdefs_d + 2); - strcat (strcat (strcpy (MATH_mac_path, dis_inc), "/"), mathdefs_d); - if (!readfile (MATH_mac_path, MATHlabel, 0, "T$Math")) { - eprintf ("%s をオープン出来ません.\n", mathdefs_d); - MATH_mac_path = NULL; - } + /* 疑似命令が記述されていなければエラー */ + if (IS_EOL(p)) return 0; - CIO_mac_path = Malloc (plen + sizeof ciodefs_d + 2); - strcat (strcat (strcpy (CIO_mac_path, dis_inc), "/"), ciodefs_d); - if (!readfile (CIO_mac_path, CIOlabel, 0, "CIO$Trap")) { - eprintf ("%s をオープン出来ません.\n", ciodefs_d); - CIO_mac_path = NULL; - } -} + /* 疑似命令へのポインタを設定 */ + *psdptr = p; -#else /* !OSKDIS */ -/* + /* 疑似命令名の末尾をNULにする */ + p = strpbrk(p, " \t"); + if (p == NULL) return 0; + *p++ = '\0'; - doscall.mac iocscall.mac fefunc.mac をカレントディレクトリ若しくは - 環境変数 (dis_)include にしたがって読み込む. + /* パラメータまでの空白を飛ばす */ + while ((*p == ' ') || (*p == '\t')) p++; -*/ + /* パラメータが記述されていなければエラー */ + if (IS_EOL(p)) return 0; -extern void -load_OS_sym (void) -{ + /* パラメータへのポインタを設定 */ + *parptr = p; - search_and_readfile (&Doscall_mac_path, doscall_mac, &OSlabel, 0xff, OSCallName, 256); - search_and_readfile (&Iocscall_mac_path,iocscall_mac,&IOCSlabel,0x00,IOCSCallName, 256); - search_and_readfile (&Fefunc_mac_path, fefunc_mac, &FElabel, 0xfe, FECallName, 256); + /* パラメータの末尾をNULにする */ + while (*p++ > 0x20) + ; + *--p = '\0'; - if (Disasm_SX_Window - && (Sxcall_mac_path = getenv ("dis_sxmac")) != NULL - && *Sxcall_mac_path) { - if (!readfile (Sxcall_mac_path, &SXlabel, 0x0a, SXCallName, SXCALL_MAX)) - err ("%s をオープン出来ません.\n" , Sxcall_mac_path); - } + return 1; } -#endif /* OSKDIS */ - -#ifndef OSKDIS /* - 1) ./ (-Y オプション指定時のみ) - 2) $dis_include/ - 3) $include/ - の順に readfile() を試す. + アセンブラのequ/macro疑似命令の行を読み取る + シンボル定義を読み取ったら1を返し、それ以外は0を返す + (二度目の定義を無視した時や、macro定義なども0) */ -private void -search_and_readfile (const char** bufptr, const char* filename, - char*** label, int hbyte, char* callname, int max) -{ - char* dis_inc = NULL; - char* include = NULL; - int path_flag; - - /* --exclude-***call 指定時は読み込まない */ - if (filename == NULL) - return; - - path_flag = strchr (filename, ':') || strchr (filename, '/'); - - /* -Y オプション指定時はカレントディレクトリから検索する. */ - /* ファイル名にパスデリミタが含まれる場合もそのまま検索. */ - if (path_flag || option_Y) { - if (readfile (filename, label, hbyte, callname, max)) { - *bufptr = filename; - return; - } - } - - /* パスデリミタが含まれなければ環境変数を参照する. */ - if (!path_flag) { - int flen = strlen (filename) + 2; - char* buf; - - /* 環境変数 dis_include のパスから検索する. */ - if ((dis_inc = getenv ("dis_include")) != NULL) { - buf = (char*) Malloc (strlen (dis_inc) + flen); - strcat (strcat (strcpy (buf, dis_inc), "/"), filename); - if (readfile (buf, label, hbyte, callname, max)) { - *bufptr = buf; - return; - } - Mfree (buf); - } - - /* 環境変数 include のパスから検索する. */ - if ((include = getenv ("include")) != NULL) { - buf = (char*) Malloc (strlen (include) + flen); - strcat (strcat (strcpy (buf, include), "/"), filename); - if (readfile (buf, label, hbyte, callname, max)) { - *bufptr = buf; - return; - } - Mfree (buf); - } - } - - if (path_flag || dis_inc || include) - err ("%s をオープン出来ません.\n", filename); +static int getlabel(const IncludeSpec* spec, char* linebuf) { + char* symptr; + char* psdptr; + char* parptr; + + if (!separate_line(linebuf, &symptr, &psdptr, &parptr)) return 0; + + // コール名: .equ コール番号 + if (strcasecmp(psdptr, "equ") == 0) { + ULONG val; + char** p; + + if (*parptr == '$') + parptr++; + else if (strncasecmp(parptr, "0x", 2) == 0) + parptr += 2; else - err ("環境変数 (dis_)include が設定されていません.\n"); -} -#endif /* !OSKDIS */ - - -/* - includeファイルから読み込んだ文字列を - シンボル名、疑似命令名、数字(または仮引数名) - に分割し、各文字列へのポインタを設定して返す. + return 0; - 文字列の内容が正しくなかった場合は0、正しければ1を返す. -*/ + val = atox(parptr); + if ((val & ~spec->callnoMask) != spec->high) return 0; -#define IS_EOL(p) ((*(p) < 0x20) || \ - (*(p) == (char)'*') || (*(p) == (char)';') || (*(p) == (char)'#')) - -private int -separate_line (char* ptr, char** symptr, char** psdptr, char** parptr) -{ - char* p = ptr; - unsigned char c; - - /* 行頭の空白を飛ばす */ - while ((*p == (char)' ') || (*p == (char)'\t')) - p++; - - /* 空行または注釈行ならエラー */ - if (IS_EOL (p)) - return 0; - - /* シンボル名の収得 */ - *symptr = p; - - /* シンボル名の末尾をNULにする */ - p = strpbrk (p, ":. \t"); - if (p == NULL) - return 0; - c = *p; - *p++ = '\0'; - - /* シンボル定義の':'、空白、疑似命令の'.'を飛ばす */ - while (c == (char)':') - c = *p++; - while ((c == (char)' ') || (c == (char)'\t')) - c = *p++; - if (c == (char)'.') - c = *p++; - p--; - - /* 疑似命令が記述されていなければエラー */ - if (IS_EOL (p)) - return 0; - - /* 疑似命令へのポインタを設定 */ - *psdptr = p; - - /* 疑似命令名の末尾をNULにする */ - p = strpbrk (p, " \t"); - if (p == NULL) - return 0; - *p++ = '\0'; - - /* パラメータまでの空白を飛ばす */ - while ((*p == (char)' ') || (*p == (char)'\t')) - p++; - - /* パラメータが記述されていなければエラー */ - if (IS_EOL (p)) - return 0; - - /* パラメータへのポインタを設定 */ - *parptr = p; - - /* パラメータの末尾をNULにする */ - while (*(unsigned char*)p++ > 0x20) - ; - *--p = '\0'; + p = *spec->labelListPtr + (val & spec->callnoMask); + if (*p) return 0; // 同じファンクションコールが定義済み + *p = strcpy(Malloc(strlen(symptr) + 1), symptr); return 1; + } + + // マクロ名: .macro 実引数名 + if (strcasecmp(psdptr, "macro") == 0) { + if ((strlen(symptr) < MAX_MACRO_LEN) && spec->macroPtr) { + strcpy(spec->macroPtr, symptr); + } + } + return 0; } +// ファンクション名への配列を確保・初期化 +static void allocateLabelBuffer(const IncludeSpec* spec) { + size_t size = spec->callnoMask + 1; // 256 (SXCALLのみ4096) + char** p = *spec->labelListPtr = Malloc(sizeof(char*) * size); + size_t i; -/* + for (i = 0; i < size; i++) *p++ = NULL; +} - アセンブラのequ/macro疑似命令の行を読み取る. - シンボル定義を読み取ったら1を返し、それ以外は0を返す. - (二度目の定義を無視した時や、macro定義なども0) +// ファイルからシンボル定義を読み込む +// ファイルのオープンに失敗した場合は0を返し、それ以外は1を返す。 +// シンボルが一個も定義されていなくても警告を表示するだけでアボートはしない +int readIncludeFile(const IncludeSpec* spec, const char* filename) { + FILE* fp; + int label_num = 0; + char linebuf[256]; -*/ + if ((fp = fopen(filename, "rt")) == NULL) return 0; -private int -getlabel (char* linebuf, char** label, int hbyte, char* callname) -{ - char* symptr; - char* psdptr; - char* parptr; - - if (separate_line (linebuf, &symptr, &psdptr, &parptr)) { - - /* コール名 equ コール番号 */ - if (strcasecmp (psdptr, "equ") == 0) { - int val; - if (*parptr == (char)'$') - parptr++; - else if (strncasecmp (parptr, "0x", 2) == 0) - parptr += 2; - else - return 0; - val = atox (parptr); - - if (hbyte == 0xa) { /* SXCALL */ - if (((val >> 12) == hbyte) && !label[val & 0xfff]) { - label[val & 0xfff] = strcpy (Malloc (strlen (symptr) + 1), symptr); - return 1; - } - } - else { /* DOS, IOCS, FPACK */ - if (((val >> 8) == hbyte) && !label[val & 0xff]) { - label[val & 0xff] = strcpy (Malloc (strlen (symptr) + 1), symptr); - return 1; - } - } - } - - /* マクロ名: .macro 実引数名 */ - else if (strcasecmp (psdptr, "macro") == 0) { - if (strlen (symptr) < MAX_MACRO_LEN) - strcpy (callname, symptr); -#if 0 - else - eprintf ("Warning : マクロ名が長すぎます(%s)\n", symptr); -#endif - } - } - return 0; -} + allocateLabelBuffer(spec); + eprintf("%s を読み込みます。\n", filename); + while (fgets(linebuf, sizeof linebuf, fp)) + label_num += getlabel(spec, linebuf); -/* - ファイルからシンボル定義を読み込む. - ファイルのオープンに失敗した場合は0を返し、それ以外は1を返す. - シンボルが一個も定義されていなくても警告を表示するだけで - アボートはしない. -*/ -private int -readfile (const char* filename, char*** label, int hbyte, char* callname, int max) -{ - int label_num; - FILE* fp; - - if ((fp = fopen (filename, "rt")) == NULL) - return 0; - - /* ファンクション名への配列を確保 */ - { - char** p; - int i; - - p = *label = Malloc (sizeof (char*) * max); - for (i = 0; i < max; i++) - *p++ = NULL; - } + fclose(fp); - eprintf ("Reading %s...\n", filename); - { - char linebuf[256]; + if (label_num == 0) + eprintf("警告: %s にはシンボルが1つも定義されていません。\n", filename); - label_num = 0; - while (fgets (linebuf, sizeof linebuf, fp)) - label_num += getlabel (linebuf, *label, hbyte, callname); - } - fclose (fp); - - if (label_num == 0) -#if 0 - err ("Error : %s にはシンボルが1つも定義されていません.\n", filename); -#else - eprintf ("Warning : %s にはシンボルが1つも定義されていません.\n", filename); -#endif - return 1; + *spec->fullpathPtr = filename; + return 1; } - -/* EOF */ +// EOF diff --git a/src/include.h b/src/include.h index 40d6631..b370d1b 100644 --- a/src/include.h +++ b/src/include.h @@ -1,30 +1,31 @@ -/* $Id: include.h,v 1.1 1996/10/24 04:27:46 ryo freeze $ - * - * ソースコードジェネレータ - * file include header - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// インクルードファイル ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef INCLUDE_H -#define INCLUDE_H +#ifndef INCLUDE_H +#define INCLUDE_H -extern void load_OS_sym (void); +#include "estruct.h" -#ifndef OSKDIS -extern const char* Doscall_mac_path; -extern const char* Iocscall_mac_path; -extern const char* Fefunc_mac_path; -extern const char* Sxcall_mac_path; +typedef struct { + unsigned int callnoMask; // (1 << n) - 1 であること + ULONG high; // コール番号以外の値(例えばDOSコールなら0xff00) + char*** labelListPtr; // 確保した配列を記録する変数へのポインタ + const char** fullpathPtr; // 読み込んだファイル名を記録する変数へのポインタ + const char** filenamePtr; // ファイル名が記録されている変数へのポインタ + char* macroPtr; // マクロ名を書き込むバッファ +} IncludeSpec; -extern const char* doscall_mac; -extern const char* iocscall_mac; -extern const char* fefunc_mac; +typedef struct { + char* dis_include; + char* include; +} IncludeEnvs; -#endif +extern void readInludeFileFromEnv(const IncludeSpec* spec, IncludeEnvs* env); +extern int readIncludeFile(const IncludeSpec* spec, const char* filename); -#endif /* INCLUDE_H */ +#endif -/* EOF */ +// EOF diff --git a/src/label.c b/src/label.c index d35f207..5a35cd8 100644 --- a/src/label.c +++ b/src/label.c @@ -1,221 +1,182 @@ -/* $Id: label.c,v 1.1 1996/11/07 08:03:44 ryo freeze $ - * - * ソースコードジェネレータ - * ラベル管理モジュール - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// ラベル管理モジュール +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "label.h" #include #include -#include "estruct.h" #include "etc.h" #include "global.h" -#include "label.h" - -#define AVL_USERDATA lblbuf +#define AVL_USERDATA lblbuf #define AVL_INCLUDE +#define AVL_NO_DESTROY_TREE +#define AVL_NO_SEARCH_PREVIOUS +#define AVL_NO_CHECK_TREE #include "./avl/avl.h" -#define AVL_COMPARE(label1, label2) \ - (signed)((unsigned)(label1)->label - (unsigned)(label2)->label) +#define AVL_COMPARE(label1, label2) \ + (LONG)((ULONG)(label1)->label - (ULONG)(label2)->label) #include "./avl/avl.c" - static avl_root_node* LabelRoot; -static lblbuf Nomore = { - (address)-1, NULL, DATLABEL | UNKNOWN, 0, 1 -}; - +static lblbuf Nomore = {(address)-1, NULL, DATLABEL | UNKNOWN, 0, 1}; -private int -compare (lblbuf* label1, lblbuf* label2) -{ - return (unsigned long)label1->label - (unsigned long)label2->label; -} - - -private void -print (lblbuf* label) -{ - printf ("%x", (unsigned int)label->label); +static int compare(lblbuf* label1, lblbuf* label2) { + return (ULONG)label1->label - (ULONG)label2->label; } +static void print(lblbuf* label) { printf(PRI_ADRS, label->label); } /* ラベルバッファを初期化する */ -extern void -init_labelbuf (void) -{ - LabelRoot = AVL_create_tree (compare, (void (*)(AVL_USERDATA*))free, print); +extern void init_labelbuf(void) { + LabelRoot = AVL_create_tree(compare, (void (*)(AVL_USERDATA*))free, print); } +// アドレス登録(デバッグ表示つき) +boolean registerLabelDebug(address adrs, lblmode mode, address target, + const char* file, int line) { + boolean result = registerLabel(adrs, mode); -/* - - 後始末 + if (adrs == target) { + const char* b = result ? "TRUE" : "FALSE"; + lblbuf* lptr = search_label(adrs); + eprintf("\n%s:%d: registerLabel(adrs=" PRI_ADRS + ", mode=$%06x) -> %s (mode=$%06x). ", + file, line, adrs, (unsigned int)mode, b, (unsigned int)lptr->mode); + } -*/ -extern void -free_labelbuf (void) -{ - return; + return result; } +// 新規ラベル登録 +static boolean registerNewLabel(address adrs, lblmode mode) { + lblbuf* lptr = Malloc(sizeof(lblbuf)); + + lptr->label = adrs; + lptr->avl = AVL_insert(LabelRoot, lptr); + lptr->mode = mode; + lptr->shift = 0; + lptr->count = 1; + + return TRUE; +} /* adrs を mode 型のエントリアドレスとして登録する 既に登録されていたら(登録されていたアドレスの型を oldmode とする) - modeがプログラム && oldmodeがプログラム FALSE - modeがプログラム && oldmodeがデータ 登録し直し TRUE - modeがデータ && oldmodeがプログラム FALSE - modeがデータ && oldmodeがデータ - mode == KNOWN && oldmode == UNKNOWN 登録し直し - oldmode != mode 登録し直し - mode == UNKNOWN && oldmode == KNOWN なにもしないFALSE を返す - 返り値は adrs から解析する必要があるかを表す( プログラムの場合 ) + modeがプログラム && oldmodeがプログラム FALSE + modeがプログラム && oldmodeがデータ 登録し直し TRUE + modeがデータ && oldmodeがプログラム FALSE + modeがデータ && oldmodeがデータ + mode == KNOWN && oldmode == UNKNOWN 登録し直し + oldmode != mode 登録し直し + mode == UNKNOWN && oldmode == KNOWN なにもしない FALSE を返す + 返り値は adrs から解析する必要があるかを表す(プログラムの場合) */ +boolean registerLabel(address adrs, lblmode mode) { + lblbuf* lptr; + const lblmode protect = ENDTABLE | SYMLABEL | DEVLABEL; + + if (adrs < Dis.beginTEXT || adrs > Dis.LAST) return FALSE; + + // プログラム領域として受理できないアドレスを処理 + if (isPROLABEL(mode)) { + if (isOdd(adrs)) return FALSE; + if (adrs > Dis.availableTextEnd) { + regist_label(adrs, DATLABEL | UNKNOWN); + return FALSE; + } + } -extern boolean -regist_label (address adrs, lblmode mode) -{ - lblbuf* lptr; - lblbuf* ins_buf; - - if (adrs < BeginTEXT || adrs > Last) - return FALSE; - - if (isPROLABEL (mode)) { - if ((long)adrs & 1) - return FALSE; - else if (adrs > Available_text_end) { - regist_label (adrs, DATLABEL | UNKNOWN); - return FALSE; - } + // 未登録なら新規作成 + lptr = search_label(adrs); + if (lptr == NULL) return registerNewLabel(adrs, mode); + + // 登録済み + lptr->count++; + + if (mode & (TABLE | ENDTABLE | DEVLABEL)) { + if (isTABLE(mode)) { + lptr->mode = (lptr->mode & protect) | mode; + return FALSE; + } + if (isENDTABLE(mode)) { + // テーブルの終端を登録するために呼び出された場合はこのアドレスの + // 属性やこの領域の中身については関与していないので、ENDTABLE + // をセットするだけにする。 + lptr->mode |= ENDTABLE; + return FALSE; } - if (Debug & BLABEL) - printf ("Regist 0x%.6x as %#x\n", (unsigned int) adrs, mode); - - if ((lptr = search_label (adrs)) != NULL) { - lptr->count++; - - if (mode & TABLE) { - lptr->mode = (lptr->mode & (TABLE | ENDTABLE | SYMLABEL)) | mode; - if (Debug & BLABEL) - printf ("registed(table) %x\n", lptr->mode); - return FALSE; - } - else if (mode & ENDTABLE) { - lptr->mode |= ENDTABLE; - if (Debug & BLABEL) - printf ("registed(endtable) %x\n", lptr->mode); - return FALSE; - } - - if ((lptr->mode & FORCE) && !(isDATLABEL (lptr->mode) && isDATLABEL (mode))) { - if (Debug & BLABEL) - printf ("but denied\n"); - return FALSE; - } - if (mode & FORCE) { - lptr->mode = (lptr->mode & (TABLE | ENDTABLE | SYMLABEL)) | mode; - if (Debug & BLABEL) - printf ("regist : %x(%d) was forced to %x\n", - (unsigned int) adrs, lptr->count, lptr->mode); - return TRUE; - } - - lptr->mode &= ~HIDDEN; - - if (isPROLABEL (mode)) { - if (isDATLABEL (lptr->mode)) { - lptr->mode = (lptr->mode & (ENDTABLE | SYMLABEL)) | PROLABEL; - if (Debug & BLABEL) - printf ("regist : %x(%d) was prog. %x\n", - (unsigned int) adrs, lptr->count, lptr->mode); - } - return TRUE; - } - else { /* if (isDATLABEL (mode)) */ - if (isPROLABEL (lptr->mode)) { - if (Debug & BLABEL) - printf ("but denied\n"); - return FALSE; - } - else { /* if (isDATLABEL (lptr->mode)) */ - if (!((mode & 0xff) == UNKNOWN && (lptr->mode & 0xff) != UNKNOWN)) - lptr->mode = (lptr->mode & (FORCE | TABLE | ENDTABLE | SYMLABEL)) - | mode; - if (Debug & BLABEL) - printf ("changed surely(%x)\n", lptr->mode); - return TRUE; - } - } - /* NOT REACHED */ + else { // isDEVLABEL(mode) + lptr->mode = (lptr->mode & protect) | mode; + return FALSE; } + } - ins_buf = Malloc (sizeof (lblbuf)); - ins_buf->label = adrs; - ins_buf->mode = mode; - ins_buf->shift = 0; - ins_buf->count = 1; - - ins_buf->avl = AVL_insert (LabelRoot, ins_buf); -#ifdef AVL_DEBUG - AVL_print_tree (LabelRoot); - printf ("\n"); -#endif + if (lptr->mode & FORCE) { + if (isPROLABEL(lptr->mode) || isPROLABEL(mode)) return FALSE; + } + if (mode & FORCE) { + lptr->mode = (lptr->mode & (TABLE | protect)) | mode; return TRUE; -} - + } -private avl_node* -search_label2 (address adrs) -{ - lblbuf search_data; + if (isPROLABEL(lptr->mode)) { + // プログラム -> プログラム(TRUE)またはデータ(FALSE) + lptr->mode &= ~HIDDEN; + return isPROLABEL(mode) ? TRUE : FALSE; + } - search_data.label = adrs; - return AVL_search (LabelRoot, &search_data); + if (isPROLABEL(mode)) { + // データ -> プログラム(TRUE) + lptr->mode = (lptr->mode & protect) | PROLABEL; + return TRUE; + } + + // データ -> データ(TRUE) + if (lblbufOpesize(lptr) == UNKNOWN || lblmodeOpesize(mode) != UNKNOWN) { + // データサイズが指定されたら更新する + lptr->mode = (lptr->mode & (FORCE | TABLE | protect)) | mode; + } + return TRUE; } +static avl_node* search_label2(address adrs) { + lblbuf search_data; + + search_data.label = adrs; + return AVL_search(LabelRoot, &search_data); +} /* ラベルの登録を取り消す */ -extern void -unregist_label (address adrs) -{ - avl_node* del; +extern void unregist_label(address adrs) { + avl_node* del = search_label2(adrs); - if (Debug & BLABEL) - printf ("* unregist_label %x\n", (unsigned int) adrs); - - if ((del = search_label2 (adrs)) == NULL) { - if (Debug & BLABEL) - printf ("unregist_label : %x was not registed\n", (unsigned int) adrs); - } - else { - lblbuf* ptr = (lblbuf*) AVL_get_data (del); + if (del != NULL) { + lblbuf* ptr = (lblbuf*)AVL_get_data(del); - if (--(ptr->count) == 0 && !(ptr->mode & SYMLABEL)) - AVL_delete (LabelRoot, del); - } + if (--(ptr->count) == 0 && !(ptr->mode & SYMLABEL)) + AVL_delete(LabelRoot, del); + } } - /* ラベルバッファからadrsを捜す @@ -223,16 +184,13 @@ unregist_label (address adrs) なければ NULL を返す */ -extern lblbuf* -search_label (address adrs) -{ - lblbuf search_data; +extern lblbuf* search_label(address adrs) { + lblbuf search_data; - search_data.label = adrs; - return AVL_get_data_safely (AVL_search (LabelRoot, &search_data)); + search_data.label = adrs; + return AVL_get_data_safely(AVL_search(LabelRoot, &search_data)); } - /* adrs の次のラベルバッファへのポインタを返す @@ -240,73 +198,53 @@ search_label (address adrs) adrs と等しいラベルがあればそれが返ってくるので注意! */ -extern lblbuf* -next (address adrs) -{ - lblbuf search_data; - avl_node* node; +extern lblbuf* next(address adrs) { + lblbuf search_data; + avl_node* node; - if (adrs == (address)-1) - return &Nomore; + if (adrs == (address)-1) return &Nomore; - search_data.label = adrs; + search_data.label = adrs; - if ((node = AVL_search_next (LabelRoot, &search_data)) == NULL) - return &Nomore; - else - return AVL_get_data (node); + if ((node = AVL_search_next(LabelRoot, &search_data)) == NULL) + return &Nomore; + else + return AVL_get_data(node); } - /* lptr の次のラベルバッファへのポインタを返す 返り値->label が -1 ならバッファエンプティ - adrs と等しいラベルがあればそれが返ってくるので注意! */ -extern lblbuf* -Next (lblbuf* lptr) -{ - lblbuf* rc = AVL_get_data_safely (AVL_next (lptr->avl)); +extern lblbuf* Next(lblbuf* lptr) { + lblbuf* rc = AVL_get_data_safely(AVL_next(lptr->avl)); - return rc ? rc : &Nomore; + return rc ? rc : &Nomore; } - /* adrs から PROLABEL を探す adrs が PROLABEL ならそれが返ってくる */ -extern lblbuf* -next_prolabel (address adrs) -{ - avl_node* node_ptr; - lblbuf search_data; - -#ifdef DEBUG - printf ("next_prolabel(%x)=", adrs); -#endif - - if (adrs == (address)-1) - return &Nomore; - - search_data.label = adrs; - node_ptr = AVL_search_next (LabelRoot, &search_data); - while (node_ptr && !isPROLABEL (((lblbuf*) AVL_get_data (node_ptr))->mode)) - node_ptr = AVL_next (node_ptr); - - if (node_ptr == NULL) - return &Nomore; - -#ifdef DEBUG - printf ("%x\n", AVL_get_data (node_ptr)); -#endif - return (lblbuf*) AVL_get_data (node_ptr); -} +extern lblbuf* next_prolabel(address adrs) { + avl_node* node_ptr; + lblbuf search_data; + + if (adrs == (address)-1) return &Nomore; + + search_data.label = adrs; + node_ptr = AVL_search_next(LabelRoot, &search_data); + while (node_ptr && !isPROLABEL(((lblbuf*)AVL_get_data(node_ptr))->mode)) + node_ptr = AVL_next(node_ptr); + + if (node_ptr == NULL) return &Nomore; + return (lblbuf*)AVL_get_data(node_ptr); +} /* @@ -314,40 +252,24 @@ next_prolabel (address adrs) adrs が DATLABEL ならそれが返ってくる */ -extern lblbuf* -next_datlabel (address adrs) -{ - avl_node* node_ptr; - lblbuf search_data; - lblbuf* lblptr = &Nomore; - -#ifdef DEBUG - printf ("next_datlabel(%x)=", adrs); -#endif - - if (adrs == (address)-1) - return &Nomore; - - search_data.label = adrs; - node_ptr = AVL_search_next (LabelRoot, &search_data); - while (node_ptr && (!isDATLABEL ((lblptr = AVL_get_data (node_ptr))->mode) - || lblptr->shift)) - node_ptr = AVL_next (node_ptr); - - if (node_ptr == NULL) - return &Nomore; - -#ifdef DEBUG - printf ("%x(%x), %d\n", lblptr->label, lblptr->mode, lblptr->count); -#endif - return lblptr; -} +extern lblbuf* next_datlabel(address adrs) { + avl_node* node_ptr; + lblbuf search_data; + lblbuf* lblptr = &Nomore; + + if (adrs == (address)-1) return &Nomore; + search_data.label = adrs; + node_ptr = AVL_search_next(LabelRoot, &search_data); + while (node_ptr && (!isDATLABEL((lblptr = AVL_get_data(node_ptr))->mode) || + lblptr->shift)) + node_ptr = AVL_next(node_ptr); -extern int -get_Labelnum (void) -{ - return AVL_data_number (LabelRoot); + if (node_ptr == NULL) return &Nomore; + + return lblptr; } -/* EOF */ +extern int get_Labelnum(void) { return AVL_data_number(LabelRoot); } + +// EOF diff --git a/src/label.h b/src/label.h index 7174a3e..0a27ded 100644 --- a/src/label.h +++ b/src/label.h @@ -1,71 +1,69 @@ -/* $Id: label.h,v 1.1 1996/10/24 04:27:48 ryo freeze $ - * - * ソースコードジェネレータ - * ラベル管理モジュールヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// ラベル管理モジュールヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef LABEL_H -#define LABEL_H +#ifndef LABEL_H +#define LABEL_H +#include "estruct.h" +// アドレスの属性 +// 下位8ビットはopesize(データラベルの時のみ意味を持つ) typedef enum { - PROLABEL = 0, /* プログラム */ - DATLABEL = 0x010000, /* データ */ - FORCE = 0x020000, /* 強制フラグ */ - HIDDEN = 0x040000, /* 1 ならそのラベルはソース中に現れない */ - TABLE = 0x080000, /* 1 でテーブル開始 */ - ENDTABLE = 0x100000, /* 1 でテーブル終了 */ - SYMLABEL = 0x200000 /* 1 でシンボル情報あり */ -#ifdef OSKDIS - CODEPTR = 0x400000, /* 1 でコードポインタ */ - DATAPTR = 0x800000, /* 1 でデータポインタ */ -#endif /* OSKDIS */ -} lblmode; + PROLABEL = 0x0000 << 16, // 第16ビット=0: プログラム + DATLABEL = 0x0001 << 16, // 第16ビット=1: データ + FORCE = 0x0002 << 16, // 1なら現在の登録内容を強制する + HIDDEN = 0x0004 << 16, // 1ならそのラベルはソース中に現れない + TABLE = 0x0008 << 16, // 1でテーブル開始 + ENDTABLE = 0x0010 << 16, // 1でテーブル終了 + SYMLABEL = 0x0020 << 16, // 1でシンボル情報あり + DEVLABEL = 0x0040 << 16, // 1でデバイスヘッダ + // OSK専用 + CODEPTR = 0x0400 << 16, // 1でコードポインタ + DATAPTR = 0x0800 << 16, // 1でデータポインタ +} lblmode; struct _avl_node; typedef struct { - address label; /* アドレス */ - struct _avl_node *avl; /* AVL-tree-library side node */ - lblmode mode; /* 属性 */ - short shift; /* ずれ */ - unsigned short count; /* 登録回数 */ + address label; // アドレス + struct _avl_node* avl; // AVL-tree-library side node + lblmode mode; // 属性 + int16_t shift; // ラベルアドレスとのずれ。通常0 + uint16_t count; // 登録回数 } lblbuf; +extern void init_labelbuf(void); +extern boolean registerLabelDebug(address adrs, lblmode mode, address target, + const char* file, int line); +extern boolean registerLabel(address adrs, lblmode mode); +extern void unregist_label(address adrs); +extern lblbuf* search_label(address adrs); +extern lblbuf* next(address adrs); +extern lblbuf* Next(lblbuf*); +extern lblbuf* next_prolabel(address adrs); +extern lblbuf* next_datlabel(address adrs); +extern int get_Labelnum(void); -/* - - lblmode 下位8ビット オペレーションサイズ(データラベルの時のみ意味を持つ) - 第16ビット 0...PROLABEL 1...DATLABEL - 第17ビット 0...普通 1...強制 - shift ラベルアドレスとのずれ.通常0. - 命令のオペランドにラベルがあったりすると... - -*/ - - -extern void init_labelbuf (void); -extern void free_labelbuf (void); -extern boolean regist_label (address adrs, lblmode mode); -extern void unregist_label (address adrs); -extern lblbuf* search_label (address adrs); -extern lblbuf* next(address adrs); -extern lblbuf* Next (lblbuf*); -extern lblbuf* next_prolabel (address adrs); -extern lblbuf* next_datlabel (address adrs); -extern int get_Labelnum (void); +#ifdef DEBUG_REGIST_LABEL +#define regist_label(adrs, mode) \ + registerLabelDebug(adrs, mode, DEBUG_REGIST_LABEL, __FILE__, __LINE__) +#else +#define regist_label(adrs, mode) registerLabel(adrs, mode) +#endif -#define isPROLABEL(a) (!isDATLABEL(a)) -#define isDATLABEL(a) ((a) & DATLABEL) -#define isHIDDEN(a) ((a) & HIDDEN) -#define isTABLE(a) ((a) & TABLE) -#define isENDTABLE(a) ((a) & ENDTABLE) +#define isPROLABEL(a) (!isDATLABEL(a)) +#define isDATLABEL(a) ((a)&DATLABEL) +#define isHIDDEN(a) ((a)&HIDDEN) +#define isTABLE(a) ((a)&TABLE) +#define isENDTABLE(a) ((a)&ENDTABLE) +#define isDEVLABEL(a) ((a)&DEVLABEL) +static inline opesize lblbufOpesize(lblbuf* lptr) { return lptr->mode & 0xff; } +static inline opesize lblmodeOpesize(lblmode mode) { return mode & 0xff; } -#endif /* LABEL_H */ +#endif -/* EOF */ +// EOF diff --git a/src/labelcheck.c b/src/labelcheck.c index cb499a9..cf4c05c 100644 --- a/src/labelcheck.c +++ b/src/labelcheck.c @@ -1,293 +1,209 @@ -/* $Id: labelcheck.c,v 1.1 1996/11/07 08:03:46 ryo freeze $ - * - * ソースコードジェネレータ - * ラベルチェック - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// ラベルチェック +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik #include #include "analyze.h" #include "disasm.h" #include "estruct.h" -#include "etc.h" /* charout */ +#include "etc.h" /* charout */ #include "global.h" -#include "label.h" /* regist_label etc. */ -#include "offset.h" /* depend_address , nearadrs */ - - -/* #define DEBUG */ - - -USEOPTION option_k, option_E, option_I; - +#include "label.h" /* regist_label etc. */ +#include "offset.h" /* depend_address , nearadrs */ static int Label_on_instruction_count = 0; static int Fixed_count = 0; static int Undefined_instruction_count = 0; +static void oops_undefined(address pc0, address previous_pc, address nlabel) { + charout('+'); + eprintf("\n警告: 未定義命令です(" PRI_ADRS "-" PRI_ADRS ", " PRI_ADRS ")。", + pc0, nlabel, previous_pc); -private void -oops_undefined (address pc0, address previous_pc, address nlabel) -{ + not_program(pc0, nlabel); - charout ('+'); - eprintf ("\n* WARNING! UNDEFINED INSTRUCTION FOUND.\n" - "%x - %x (%x)\n", pc0, nlabel, previous_pc); - not_program (pc0, nlabel); - Undefined_instruction_count++; + Undefined_instruction_count++; } +static void printLabelInOpToData(address pc, address nlabel) { + if (!Dis.I) return; -private address -labelshift (address previous_pc, address pc, address end, lblbuf* nadrs) -{ - address nlabel = nadrs->label; - - while (nlabel < pc) { - charout ('!'); - nadrs->shift = nlabel - previous_pc; - regist_label (previous_pc, PROLABEL); -#ifdef DEBUG - printf ("* FOUND at %x - %x - %x(diff %d) in opecode\n", - previous_pc, nlabel, pc, nlabel - previous_pc); -#endif - nadrs = Next (nadrs); /* nadrs = next (nlabel + 1); */ - nlabel = nadrs->label; - } + eprintf("\n" PRI_ADRS + ": ラベルが命令の中を指すためデータ領域に変更します(" PRI_ADRS + "-" PRI_ADRS ")。", + nlabel, pc, nlabel); +} - if (nlabel >= end) /* 泥縄 (^_^;) */ - return next_datlabel (previous_pc)->label; +static void printLabelInOpShift(address pc, address nlabel) { + if (!Dis.I) return; - return end; + eprintf("\n" PRI_ADRS ": 命令の中を指すラベルです(" PRI_ADRS "+$%" PRIx32 + ")。", + nlabel, pc, (ULONG)(nlabel - pc)); } +static address labelshift(address previous_pc, address pc, address end, + lblbuf* nadrs) { + address nlabel = nadrs->label; + + while (nlabel < pc) { + charout('!'); + nadrs->shift = nlabel - previous_pc; + regist_label(previous_pc, PROLABEL); + nadrs = Next(nadrs); /* nadrs = next (nlabel + 1); */ + nlabel = nadrs->label; + } + + if (nlabel >= end) /* 泥縄 (^_^;) */ + return next_datlabel(previous_pc)->label; + + return end; +} /* 既に DATLABEL として登録済みかどうか調べる */ -private boolean -datlabel (address adrs) -{ - lblbuf* ptr = search_label (adrs); +static boolean datlabel(address adrs) { + lblbuf* ptr = search_label(adrs); - return (ptr && isDATLABEL (ptr->mode)) ? TRUE : FALSE; + return (ptr && isDATLABEL(ptr->mode)) ? TRUE : FALSE; } - /* from から end まで逆アセンブルして命令の途中にアクセスしているところを捜す */ -private address -search_change_operand (address from, address end) -{ - address nlabel, pc, previous_pc, pc0; - disasm code; - boolean was_prog = FALSE; /* 直前の領域がプログラムであったかどうか */ - - pc = previous_pc = pc0 = from; - -#ifdef DEBUG - printf ("search_ch_op(%x - %x)\n", from, end); -#endif - - while (end != (address)-1 && pc < end) { - lblbuf* nadrs = next (pc + 1); - address store = pc + Ofst; - - nlabel = nadrs->label; - pc0 = pc; - was_prog = TRUE; - - /* 2つのプログラムラベル間を逆アセンブル */ - while (pc < nlabel && pc < end) { -#ifdef DEBUG - printf ("%x,%x\n", pc, nlabel); -#endif - previous_pc = pc; - store += dis (store, &code, &pc); - if (code.flag == UNDEF) { /* 未定義命令なら警告 */ - oops_undefined (pc0, previous_pc, nlabel); -#ifdef OSKDIS - /* 未定義命令をデータにする */ - regist_label (previous_pc, DATLABEL | FORCE); -#endif /* OSKDIS */ - pc = nlabel; - } - } - - /* 命令の途中にアクセスしているなら */ - if (pc != nlabel) { -#ifdef DEBUG - printf ("* label in instruction (%x, %x)\n", pc, nlabel); -#endif - Label_on_instruction_count++; - if (option_k - || (!option_E && code.size == BYTESIZE - && code.op1.eaadrs + 1 != nlabel - && code.op2.eaadrs + 1 != nlabel - && code.op3.eaadrs + 1 != nlabel - && code.op4.eaadrs + 1 != nlabel)) - { - charout ('*'); - Fixed_count++; - not_program (pc0, nlabel); - if (option_I) - eprintf ("\n命令の中を差すラベル(%x) -> " - "データ領域に変更しました(%x-%x)\n", - nlabel, pc0, nlabel); - pc = nlabel; - was_prog = FALSE; - } - else { - end = labelshift (previous_pc, pc, end, nadrs); - if (option_I) - eprintf ("\n命令の中を差すラベル(%x -> %x+%x)\n", - nlabel, previous_pc, nlabel - previous_pc); - } - } - } - if (code.flag != RTSOP && code.flag != JMPOP && datlabel (pc) && was_prog) { - charout ('-'); -#ifdef DEBUG - printf ("datlabel in prolabel %x\n", pc); -#endif - regist_label (pc, PROLABEL); +static address search_change_operand(address from, address end) { + address previous_pc = from; + DisParam disp; + disasm* code = &disp.code; + boolean was_prog = FALSE; // 直前の領域がプログラムであったかどうか + + setDisParamPcPtr(&disp, from, Dis.Ofst); + disp.pcEnd = Dis.availableTextEnd; + + while (end != (address)-1 && disp.pc < end) { + lblbuf* nadrs = next(disp.pc + 1); + address nlabel = nadrs->label; + address pc0 = disp.pc; + + was_prog = TRUE; + + /* 2つのプログラムラベル間を逆アセンブル */ + while (disp.pc < nlabel && disp.pc < end) { + previous_pc = disp.pc; + dis(&disp); + + if (code->opeType == UNDEF) { /* 未定義命令なら警告 */ + oops_undefined(pc0, previous_pc, nlabel); + setDisParamPcPtr(&disp, nlabel, Dis.Ofst); + } } - return end; + /* 命令の途中にアクセスしているなら */ + if (disp.pc != nlabel) { + Label_on_instruction_count++; + if (Dis.k || + (!Dis.E && code->size == BYTESIZE && code->op1.eaadrs + 1 != nlabel && + code->op2.eaadrs + 1 != nlabel && code->op3.eaadrs + 1 != nlabel && + code->op4.eaadrs + 1 != nlabel)) { + charout('*'); + Fixed_count++; + not_program(pc0, nlabel); + printLabelInOpToData(pc0, nlabel); + setDisParamPcPtr(&disp, nlabel, Dis.Ofst); + was_prog = FALSE; + } else { + end = labelshift(previous_pc, disp.pc, end, nadrs); + printLabelInOpShift(previous_pc, nlabel); + } + } + } + if (code->opeType != RTSOP && code->opeType != JMPOP && datlabel(disp.pc) && + was_prog) { + charout('-'); + regist_label(disp.pc, PROLABEL); + } + + return end; } - /* from から end までのデータ領域をチェック */ -private void -search_change_data (address from, address end) -{ - address pc, pc0; - lblbuf* nadrs; - - pc = pc0 = from; - nadrs = next (pc); -#ifdef DEBUG - printf ("search_ch_dat(%x - %x)\n", from, end); -#endif - - while (end != (address)-1 && pc < end) { - address dependadrs = nearadrs (pc); - address nlabel; - - nadrs = Next (nadrs); /* nadrs = next (pc + 1); */ - nlabel = nadrs->label; - - while (dependadrs != (address)-1 && dependadrs + 4 <= nlabel) - dependadrs = nearadrs (dependadrs + 1); - - while (dependadrs < nlabel && nlabel < dependadrs + 4) { - charout ('!'); - nadrs->shift = nlabel - dependadrs; - regist_label (dependadrs, DATLABEL | UNKNOWN); -#ifdef DEBUG - printf ("* FOUND at %x (diff %d) in data\n", dependadrs, nlabel - dependadrs); -#endif - nadrs = Next (nadrs); /* nadrs = next (nlabel + 1); */ - nlabel = nadrs->label; - } - pc = nlabel; - } -} +static void search_change_data(address from, address end) { + address pc, pc0; + lblbuf* nadrs; + pc = pc0 = from; + nadrs = next(pc); -extern void -search_operand_label (void) -{ -#if 0 - address tmp; -#endif - lblbuf* nadrs = next (BeginTEXT); - address pc, pcend = nadrs->label; - - PCEND = Available_text_end; - - while (nadrs->label < Available_text_end) { - charout ('.'); - nadrs = next_prolabel (pcend); - - pc = nadrs->label; - nadrs = next_datlabel (pc); - pcend = nadrs->label; -#if 0 - if (tmp == pcend) { - nadrs = next_prolabel (pcend + 1); - pc = nadrs->label; - nadrs = next_datlabel (pc); - pcend = nadrs->label; - printf ("ドロナワ処理をしました.\n"); - } - tmp = pcend; -#endif - -#ifdef OSKDIS - if (nadrs->label >= Available_text_end) - break; /* 泥縄 */ -#endif /* OSKDIS */ - - if (pcend != (address)-1) - pcend = search_change_operand (pc, pcend); - } + while (end != (address)-1 && pc < end) { + address dependadrs = nearadrs(pc); + address nlabel; - charout ('\n'); - if (Label_on_instruction_count) { - if (option_q) - eputc ('\n'); - eprintf ("命令の中を指すラベル %d 個.\n", Label_on_instruction_count); - if (Fixed_count) - eprintf ("%d 個の領域をデータ領域に変更しました.\n", Fixed_count); - } + nadrs = Next(nadrs); /* nadrs = next (pc + 1); */ + nlabel = nadrs->label; - nadrs = next (BeginTEXT); - pcend = nadrs->label; + while (dependadrs != (address)-1 && dependadrs + 4 <= nlabel) + dependadrs = nearadrs(dependadrs + 1); - while (nadrs->label < BeginBSS) { - charout (':'); - nadrs = next_datlabel (pcend); - pc = nadrs->label; - nadrs = next_prolabel (pc); - pcend = min (nadrs->label, BeginBSS); -#if 0 - if (tmp == pcend) { - nadrs = next_datlabel (pcend); - pc = nadrs->label; - nadrs = next_prolabel (pc + 1); - pcend = min (nadrs->label, BeginBSS); - printf ("ドロナワ処理2をしました.\n"); - } - tmp = pcend; -#endif - - -#ifdef DEBUG - printf ("chk %x - %x\n", pc, pcend); -#endif - if (pc < BeginBSS) - search_change_data (pc, pcend); + while (dependadrs < nlabel && nlabel < dependadrs + 4) { + charout('!'); + nadrs->shift = nlabel - dependadrs; + regist_label(dependadrs, DATLABEL | UNKNOWN); + nadrs = Next(nadrs); /* nadrs = next (nlabel + 1); */ + nlabel = nadrs->label; } - if (Undefined_instruction_count) /* ラベルチェックに引っ掛かるとデータ消失 ? */ - analyze_data (); - - if (!option_q || !Label_on_instruction_count) - eputc ('\n'); + pc = nlabel; + } } +extern void search_operand_label(void) { + lblbuf* nadrs = next(Dis.beginTEXT); + address pc, pcend = nadrs->label; + + while (nadrs->label < Dis.availableTextEnd) { + charout('.'); + nadrs = next_prolabel(pcend); + + pc = nadrs->label; + nadrs = next_datlabel(pc); + pcend = nadrs->label; + + if (pcend != (address)-1) pcend = search_change_operand(pc, pcend); + } + + if (Label_on_instruction_count) { + eprintf("\n命令の中を指すラベル: %d個。", Label_on_instruction_count); + if (Fixed_count) + eprintf("\n%d個の領域をデータ領域に変更しました。", Fixed_count); + } + + nadrs = next(Dis.beginTEXT); + pcend = nadrs->label; + + while (nadrs->label < Dis.beginBSS) { + charout(':'); + nadrs = next_datlabel(pcend); + pc = nadrs->label; + nadrs = next_prolabel(pc); + pcend = MIN(nadrs->label, Dis.beginBSS); + + if (pc < Dis.beginBSS) search_change_data(pc, pcend); + } + if (Undefined_instruction_count) { + // ラベルチェックに引っ掛かるとデータ消失 ? + analyze_data(); + } +} -/* EOF */ +// EOF diff --git a/src/labelfile.c b/src/labelfile.c index f5c3d5c..db292b3 100644 --- a/src/labelfile.c +++ b/src/labelfile.c @@ -1,14 +1,10 @@ -/* $Id: labelfile.c,v 1.1 1996/11/07 08:03:48 ryo freeze $ - * - * ソースコードジェネレータ - * ラベルファイルモジュール - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#include /* toupper */ +// ソースコードジェネレータ +// ラベルファイルモジュール +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include /* toupper */ #include #include @@ -18,299 +14,330 @@ #include "global.h" #include "label.h" #include "symbol.h" - +#include "version.h" /************************ ラベルファイルへの出力 ************************/ - /* ラベルファイルのヘッダを書く */ -static INLINE void -make_header (FILE* fp, char* filename) -{ - fprintf (fp, "*********************************************\n" - "*\n" - "* Label file for %s\n" - "*\n" - "*\tDIS version %s\n" - "*\n" - "*********************************************\n", - filename, Version); +static void make_header(FILE* fp, char* filename) { + fprintf(fp, + "*********************************************\n" + "*\n" + "* Label file for %s\n" + "*\n", + filename); + if (!Dis.deterministic) { + fprintf(fp, + "*\t%s\n" + "*\n", + ProgramAndVersion); + } + fprintf(fp, "*********************************************\n"); } - /* ラベルファイルを出力 */ -extern void -make_labelfile (char* xfilename, char* labelfilename) -{ - FILE* fp; - lblbuf* nadrs; - - if ((fp = fopen (labelfilename, "w")) == NULL) { - eprintf ("%s をオープンできませんでした.\n", labelfilename); - return; +extern void make_labelfile(char* xfilename, char* labelfilename) { + FILE* fp; + lblbuf* nadrs; + + if ((fp = fopen(labelfilename, "w")) == NULL) { + err("\n%s をオープンできません。\n", labelfilename); + } + + make_header(fp, xfilename); + nadrs = next(Dis.beginTEXT); + + while (nadrs->label != (address)-1) { + opesize mode = lblbufOpesize(nadrs); + + fprintf(fp, "%06" PRIx32 "\t", (ULONG)nadrs->label); + + if (isPROLABEL(nadrs->mode)) + fputc('P', fp); + else if (mode == RELTABLE || mode == RELLONGTABLE) { + fputc('R', fp); + fputc(mode == RELTABLE ? 'W' : 'L', fp); + } else { + static const char labelchar[ZTABLE + 1] = { + 'B', 'W', 'L', 'Q', 'U', /* 整数 */ + 'F', 'D', 'X', 'P', 'U', /* 小数 */ + 'S', 'U', 'U', 'Z' /* その他 */ + }; + + fputc('D', fp); + fputc(mode > ZTABLE ? 'U' : labelchar[mode], fp); } - - make_header (fp, xfilename); - nadrs = next (BeginTEXT); - - while (nadrs->label != (address)-1) { - int mode = (nadrs->mode & 0xff); - - fprintf (fp, "%06x\t", (unsigned int)nadrs->label); - - if (isPROLABEL (nadrs->mode)) - fputc ('P', fp); - else if (mode == RELTABLE || mode == RELLONGTABLE) { - fputc ('R', fp); - fputc (mode == RELTABLE ? 'W' : 'L', fp); - } else { - static const unsigned char labelchar[ZTABLE + 1] = { - 'B', 'W', 'L', 'Q', 'U', /* 整数 */ - 'F', 'D', 'X', 'P', 'U', /* 小数 */ - 'S', 'U', 'U', 'Z' /* その他 */ - }; - - fputc ('D', fp); - fputc (mode > ZTABLE ? 'U' : labelchar[mode], fp); - } - if (nadrs->mode & FORCE) - fputc ('F', fp); - - { - symbol* symbolptr = symbol_search (nadrs->label); - - if (symbolptr) { - symlist* sym = &symbolptr->first; - char space = '\t'; - - do { - fprintf (fp, "%c%s", space, sym->sym); - space = ' '; - sym = sym->next; - } while (sym); - } - } - - fputc ('\n', fp); - nadrs = Next (nadrs); /* nadrs = next (nadrs->label + 1); */ + if (nadrs->mode & FORCE) fputc('F', fp); + if (isHIDDEN(nadrs->mode)) fputc('H', fp); + + { + symbol* symbolptr = symbol_search(nadrs->label); + + if (symbolptr) { + symlist* sym = &symbolptr->first; + char space = '\t'; + + do { + fprintf(fp, "%c%s", space, sym->sym); + space = ' '; + sym = sym->next; + } while (sym); + } } - fclose (fp); + fputc('\n', fp); + nadrs = Next(nadrs); /* nadrs = next (nadrs->label + 1); */ + } + + fclose(fp); } +/*********************** ラベルファイルからの入力 ***********************/ +typedef enum { + PASS_UPPER_FIRST, // 大文字のみ判定(disが出力した属性) + PASS_LOWER_SECOND, // 小文字のみ判定(ユーザが編集した属性) +} LabelFilePass; -/*********************** ラベルファイルからの入力 ***********************/ +static char* skipspace(char* ptr) { + while (*ptr == ' ' || *ptr == '\t') ptr++; + return ptr; +} +static char* untilspace(char* ptr) { + while (*ptr && *ptr != ' ' && *ptr != '\t') ptr++; + return ptr; +} -/* +// 属性文字列をopesizeに変換する +// 成功時はattrptrに書き込んでTRUEを返す +static boolean parseLabelAttribute(char* p, opesize* attrptr) { + opesize attr = DATLABEL; + char c = *p++; + + switch (toupper(c)) { + default: + return FALSE; + + case 'P': + attr = PROLABEL; + break; + + case 'R': + c = *p++; + switch (toupper(c)) { + default: + return FALSE; + case 'W': + attr |= RELTABLE; + break; + case 'L': + attr |= RELLONGTABLE; + break; + } + break; + + case 'D': + c = *p++; + switch (toupper(c)) { + default: + return FALSE; + + case 'B': + attr |= BYTESIZE; + break; + case 'W': + attr |= WORDSIZE; + break; + case 'L': + attr |= LONGSIZE; + break; + case 'Q': + attr |= QUADSIZE; + break; + case 'F': + attr |= SINGLESIZE; + break; + case 'D': + attr |= DOUBLESIZE; + break; + case 'X': + attr |= EXTENDSIZE; + break; + case 'P': + attr |= PACKEDSIZE; + break; + case 'S': + attr |= STRING; + break; + case 'Z': + attr |= ZTABLE; + break; + case 'U': + attr |= UNKNOWN; + break; + + case 'R': + attr |= RELTABLE; + if (toupper(*p) == 'L') { + p += 1; + attr ^= (RELTABLE ^ RELLONGTABLE); + } + break; + } + break; + } + + while (1) { + c = toupper(*p); + if (c == 'F') { + p += 1; + attr |= FORCE; + } else if (c == 'H') { + p += 1; + attr |= HIDDEN; + } else { + break; + } + } - ラベルファイルの1行を解析する + *attrptr = attr; + return TRUE; +} - pass = 0, 大文字のみ判定 - 1, 小文字のみ判定 +// ラベルファイルの1行を解析する +static int get_line(char* linebuf, int line, address* adrs, char** symptrptr, + boolean* isLower, const char* filename) { + address ad = (address)atox(linebuf); + char* ptr = skipspace(untilspace(linebuf)); + opesize attr = 0; -*/ + *isLower = islower(*ptr) ? TRUE : FALSE; + + if (!parseLabelAttribute(ptr, &attr)) { + err("\n%s:%d: " PRI_ADRS ": 不正な文字です。", filename, line, ad); + } -static INLINE unsigned char* -skipspace (unsigned char* ptr) -{ - while (*ptr == ' ' || *ptr == '\t') - ptr++; - return ptr; + *symptrptr = skipspace(untilspace(ptr)); + *adrs = ad; + return attr; } -static INLINE unsigned char* -untilspace (unsigned char* ptr) -{ - while (*ptr && *ptr != ' ' && *ptr != '\t') - ptr++; - return ptr; +static void regLabel(address adrs, lblmode attr, int line, + const char* filename) { + if (!regist_label(adrs, attr)) + eprintf("\n%s:%d: " PRI_ADRS " ???. ", filename, line, adrs); } -static INLINE int -get_line (char* linebuf, int line, int pass, address* adrs, char** symptrptr) -{ - address ad = (address) atox (linebuf); - unsigned char* ptr = skipspace (untilspace ((unsigned char*) linebuf)); - opesize attr; - - if (Debug & BDEBUG) - printf ("%x, %c\n", (unsigned int) ad, *ptr); - - if ((pass == 0 && islower (*ptr)) || - (pass == 1 && isupper (*ptr))) - attr = -1; - else { - unsigned char c = *ptr++; - - attr = DATLABEL; - switch (toupper (c)) { - case 'P': - attr = PROLABEL; - break; - case 'R': - c = *ptr++; - switch (toupper (c)) { - case 'W': - attr |= RELTABLE; - break; - case 'L': - attr |= RELLONGTABLE; - break; - default: - goto er; - } - break; - case 'D': - c = *ptr++; - switch (toupper (c)) { - case 'B': attr |= BYTESIZE; break; - case 'W': attr |= WORDSIZE; break; - case 'L': attr |= LONGSIZE; break; - case 'Q': attr |= QUADSIZE; break; - case 'F': attr |= SINGLESIZE; break; - case 'D': attr |= DOUBLESIZE; break; - case 'X': attr |= EXTENDSIZE; break; - case 'P': attr |= PACKEDSIZE; break; - case 'S': attr |= STRING; break; - case 'Z': attr |= ZTABLE; break; - case 'U': attr |= UNKNOWN; break; - - case 'R': - attr |= RELTABLE; - if (toupper (*ptr) == 'L') { - ptr++; - attr ^= (RELTABLE ^ RELLONGTABLE); - } - break; - - default: - goto er; - } - break; - default: - er: - err ("\nlabelfile %d行 address %x : 不正な文字です.\n", line, ad); - } - if (toupper (*ptr) == 'F') - attr |= FORCE; - } +// 相対オフセットテーブルの解析を呼び出す +static void analyzeReltbl(address table, opesize size) { + // 現在のラベルファイルの仕様上、テーブルの宛先がプログラムとデータの + // どちらかであるかは指定できない + boolean isProgram = FALSE; - *symptrptr = (char*) skipspace (untilspace (ptr)); - *adrs = ad; - return attr; + registerReltblOrder(&Dis.reltblArray, table, size, isProgram, 0); } - -static INLINE void -work (address adrs, int attr, int pass, int line) -{ - if (pass == 0) { - if (!regist_label (adrs, attr)) - eprintf ("??? %d行 address %x\n", line, adrs); - } - else { - if (isPROLABEL (attr)) { - if (Debug & BDEBUG) - printf ("work:prog %x\n", (unsigned int) adrs); - if (!analyze (adrs, ANALYZE_IGNOREFAULT)) - eprintf ("\nAddress %x(labelfile Line %d)からはプログラムと見なせません.", - adrs, line); - } - else { - switch (attr & 0xff) { - case RELTABLE : - relative_table (adrs); - break; - case RELLONGTABLE : - relative_longtable (adrs); - break; - case ZTABLE : - z_table (adrs); - break; - default: - if (!regist_label (adrs, attr)) - eprintf ("\n??? labelfile %d行 address %x", line, adrs); - break; - } - } +// 小文字属性の処理 +// ユーザが指定した情報に従って解析を行う +static void workLower(address adrs, lblmode attr, int line, + const char* filename) { + lblbuf* lptr; + opesize size; + + if (isPROLABEL(attr)) { + if (!analyze(adrs, ANALYZE_IGNOREFAULT)) { + eprintf("\n%s:%d: " PRI_ADRS "からはプログラムと見なせません。", filename, + line, adrs); } + return; + } + + size = lblmodeOpesize(attr); + lptr = search_label(adrs); + if (lptr && lblbufOpesize(lptr) != size) { + // ラベルファイルの現在の行より上にある小文字属性による解析で + // 最初のパスで登録したラベルの属性が変更される可能性あり。 + // 違う属性のままテーブル解析を呼び出すのはまずいかもしれないので + // 念のため属性を再登録する。 + ch_lblmod(adrs, attr); + } + + switch (size) { + default: + break; + + case RELTABLE: + case RELLONGTABLE: + analyzeReltbl(adrs, size); + break; + case ZTABLE: + z_table(adrs); + break; + } } +// ラベルファイルに記述されたシンボル(複数可)を登録する +static void addSymbols(char* s, address adrs) { + const int section = 0; -/* + while (*s && *s != '*') { + char* symend = untilspace(s); + size_t len = symend - s; + char* buf = Malloc(len + 1); - ラベルファイルを読み込む + memcpy(buf, s, len); + buf[len] = '\0'; + add_symbol(adrs, section, buf); -*/ -extern void -read_labelfile (char* filename) -{ - FILE* fp; - int pass; - - if ((fp = fopen (filename, "rt")) == NULL) { - err ("\n%s をオープンできませんでした.\n", filename); - return; - } + s = skipspace(symend); + } +} - for (pass = 0; pass < 2; pass++) { - int line; - - if (Debug & BDEBUG) - eprintf ("pass %d\n", pass); - for (line = 1;; line++) { - char linebuf[1024]; - char* p; - - if (fgets (linebuf, sizeof (linebuf), fp) == NULL) - break; - - /* 末尾の CR、LF を削除する */ - for (p = linebuf + strlen (linebuf); linebuf < p; p--) - if (p[-1] != (char)'\n' && p[-1] != (char)'\r') - break; - *p = '\0'; - - if (isxdigit ((unsigned char)linebuf[0])) { - address adrs; - char* symptr; - int attr = get_line (linebuf, line, pass, &adrs, &symptr); - - if (attr != -1) - work (adrs, attr, pass, line); - if (pass == 0) { -#if 0 - del_symbol (adrs); -#endif - while (*symptr && *symptr != '*') { - char* symend = (char*) untilspace ((unsigned char*) symptr); - char* nextsym = (char*) skipspace ((unsigned char*) symend); - char* label; - - *symend = '\0'; - label = Malloc (strlen (symptr) + 1); - strcpy (label, symptr); - add_symbol (adrs, 0, label); - symptr = nextsym; - } - } - } - } - if (pass == 0) - rewind (fp); +static void parseLabelFile(FILE* fp, const char* filename, LabelFilePass pass) { + int line; + + for (line = 1;; line++) { + char linebuf[1024]; + char* symptr; + address adrs; + lblmode attr; + boolean isLower; + + if (fgets(linebuf, sizeof(linebuf), fp) == NULL) break; + removeTailLf(linebuf); + if (!isxdigit(linebuf[0])) continue; + + attr = get_line(linebuf, line, &adrs, &symptr, &isLower, filename); + + if (pass == PASS_UPPER_FIRST) { + // 最初のパスで大文字小文字に関わらずラベルとシンボルを登録する + regLabel(adrs, attr, line, filename); + addSymbols(symptr, adrs); + } else { + if (isLower) workLower(adrs, attr, line, filename); } - fclose (fp); + } } +// ラベルファイルを読み込む +void read_labelfile(char* filename) { + FILE* fp = fopen(filename, "rt"); + + if (fp == NULL) err("\n%s をオープンできません。\n", filename); + + parseLabelFile(fp, filename, PASS_UPPER_FIRST); + rewind(fp); + parseLabelFile(fp, filename, PASS_LOWER_SECOND); + fclose(fp); +} -/* EOF */ +// EOF diff --git a/src/labelfile.h b/src/labelfile.h index 5502a73..36eaa24 100644 --- a/src/labelfile.h +++ b/src/labelfile.h @@ -1,21 +1,15 @@ -/* $Id: labelfile.h,v 1.1 1996/10/24 04:27:48 ryo freeze $ - * - * ソースコードジェネレータ - * ラベルファイルリードモジュールヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// ラベルファイルリードモジュールヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef LABELFILE_H -#define LABELFILE_H +#ifndef LABELFILE_H +#define LABELFILE_H +extern void make_labelfile(char*, char*); +extern void read_labelfile(char*); -extern void make_labelfile (char*, char*); -extern void read_labelfile (char*); +#endif - -#endif /* LABELFILE_H */ - -/* EOF */ +// EOF diff --git a/src/main.c b/src/main.c index ec14a11..6be27c8 100644 --- a/src/main.c +++ b/src/main.c @@ -1,758 +1,500 @@ -/* $Id: main.c,v 2.76 1995/01/07 11:32:22 ryo Exp $ - * - * ソースコードジェネレータ - * メインルーチン - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - - -#include /* tolower */ -#include /* PATH_MAX */ +// ソースコードジェネレータ +// メインルーチン +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include // PATH_MAX #include -#include /* exit */ -#include /* memcmp */ -#include /* time difftime */ -#include /* access */ +#include +#include #include -#include /* open */ -#include +#include // time difftime + +#ifdef _MSC_VER +#include // isatty() +#else +#include +#endif + +#ifdef __LIBC__ +#include // char* _comline +#define COMMAND_LINE _comline +#else +static char* make_cmdline(char** argv); +#define COMMAND_LINE make_cmdline(argv + 1) +#define NEED_MAKE_CMDLINE +#endif #ifdef QUICK_YES_NO #ifdef __HUMAN68K__ -#include /* getch */ +#include // getch() #else #include #endif -#endif /* QUICK_YES_NO */ +#endif /* QUICK_YES_NO */ -#ifndef O_BINARY -#define O_BINARY 0 +#ifndef PATH_MAX +#define PATH_MAX _MAX_PATH #endif - #include "analyze.h" #include "disasm.h" +#include "eastr.h" // initEAString() #include "estruct.h" #include "etc.h" #include "generate.h" #include "global.h" -#include "include.h" /* load_OS_sym() */ -#include "label.h" +#include "human.h" #include "labelfile.h" -#include "offset.h" +#include "opstr.h" // initOpString() #include "option.h" -#include "symbol.h" +#include "osk.h" #include "table.h" +#include "version.h" +static void decideOutputFilename(const char* fileType, char** nameptr); -USEOPTION option_g, option_e, option_v, option_d, option_i, - option_p, option_l, option_p, option_c, option_z, - option_D, option_T; -USEOPTION option_overwrite; - +DisVars Dis; -/* static 関数プロトタイプ */ -private void analyze_and_generate (int, char*[]); -private void check_open_output_file (char*); -private int check_exist_output_file (char*); -private void change_filename (char** nameptr, const char* file); - - -xheader Head; -#ifdef OSKDIS -os9header HeadOSK; -#else -char FileType; /* ファイル形式(0,'x','r','z') */ -#endif +// オプション初期化 +static void initDisVars(void) { + DisVars* d = &Dis; -ULONG Top; /* 実際にファイルのあるアドレス */ -ULONG Ofst; /* 実際のアドレス - 仮想アドレス */ - -/******************************************** - Human68K 用(-DOSKDIS 無)の場合は、 - BeginTEXT = text section の先頭 - BeginDATA = data section の先頭 - BeginBSS = bss section の先頭 - OS-9/680x0 用(-DOSKDIS 有)の場合は、 - BeginTEXT = psect 先頭 - BeginDATA = 初期化 vsect 先頭 - BeginBSS = vsect 先頭 -*********************************************/ - -address BeginTEXT, - BeginDATA, - BeginBSS, -#ifndef OSKDIS - BeginSTACK, -#endif - Last; -address Available_text_end; /* = BeginDATA or BeginBSS */ + d->mpu = M000; + // d->fpu = 0; + // d->mmu = 0; -int Absolute = NOT_ABSOLUTE; /* 絶対番地形式モード */ - /* NOT_ABSOLUTE, ABSOLUTE_ZFILE, ABSOLUTE_ZOPT */ + d->execFile = NULL; + d->outputFile = NULL; + d->inputLabelFile = NULL; + d->outputLabelFile = NULL; + d->tableFile = NULL; -int String_length_min = 3; /* 文字列の最小長さ */ + d->doscallMac = "doscall.mac"; + d->iocscallMac = "iocscall.mac"; + d->fefuncMac = "fefunc.mac"; -int Debug = 0; -int Verbose = 1; -int Quiet_mode = 0; -short Emulate_mode = 3; /* bit0=1:fpsp bit1=1:isp emulation 命令を認識する */ -char CommentChar = ';'; + d->stringLengthMin = 3; + d->stringWidth = STRING_WIDTH_DEFAULT; + d->dataWidth = DATA_WIDTH_DEFAULT; + d->compressLen = 64; -address Base; /* ロードアドレス */ -address Exec; /* 実行開始アドレス */ -boolean Exist_symbol; /* シンボルテーブルの存在フラグ */ + d->commentStr[0] = ';'; + d->labelChar = 'L'; -char* Filename_in; -char* Filename_out; -char* Labelfilename_in; -char* Labelfilename_out; -char* Tablefilename; + d->outputSymbol = OUTPUT_SYMBOL_NORMAL; + d->symbolColonNum = SYMBOL_COLON_AUTO; + d->backtrackReason = BACKTRACK_REASON_PROGRAM; + d->undefReg = TRUE; + d->undefExReg = TRUE; + d->undefExScale = TRUE; + d->undefExSize = TRUE; -extern void -print_title (void) -{ - static char flag = 1; + d->fpsp = TRUE; + d->isp = TRUE; - if (flag) { - flag = 0; + d->reltblZero = RELTBL_ZERO_HEAD; - eprintf ("ソースコードジェネレータ for X680x0" -#ifdef __linux__ - " (Linux cross)" -#endif -#ifdef __FreeBSD__ - " (BSD cross)" -#endif -#ifdef __CYGWIN__ - " (Cygwin cross)" -#endif -#ifdef __MINGW32__ - " (MinGW cross)" -#endif - " version %s\n" - "Copyright (C)1989-1992 K.Abe, 1994-1997 R.ShimiZu, " - "%s Tachibana.\n", Version, Date); + d->UndefTab = 3; + d->Mtab = 5; + d->Xtab = 7; + d->Atab = 8; + d->dbccSize = WORDSIZE; + d->quoteChar = '\''; -#ifdef OSKDIS - eprintf ("OS-9/68000 version %s by TEMPLE, 1994\n", OSKEdition); -#endif - } + initReltblArray(&d->reltblArray); } +// 実行ファイルの形式を判別する +static uint8_t getFileType(FILE* fp, const char* filename) { + UBYTE head[2]; + char* ext = strrchr(filename, '.'); -typedef struct { - short bit; - char* name; -} target_table; - -private void -print_target (char* str, int bits, const target_table* tbl, int size) -{ - if (bits) { - int f = '\0'; - eprintf (str); - do { - if (bits & tbl->bit) { - if (f) - eputc (f); - eprintf (tbl->name); - f = ','; - } - tbl++; - } while (--size); - eputc ('\n'); - } -} + // 拡張子が".r"ならR形式 + if (ext && strcasecmp(ext, ".r") == 0) return FILETYPE_R; + if (fread(head, 1, sizeof(head), fp) == sizeof(head)) { + UWORD h = peekw(head); -/* + fseek(fp, 0, SEEK_SET); - ファイルを読み込み、ヘッダ情報を大域変数 Head にセット - ファイルの日付を Filedate にセット - 読み込んだ先頭アドレスを返す + if (h == XHEAD_ID_VALUE) return FILETYPE_X; + if (h == ZHEAD_ID_VALUE) return FILETYPE_Z; + if (h == OSKHEAD_ID_VALUE) return FILETYPE_OSK; + } -*/ -static time_t Filedate; - -static INLINE address -loadfile (char* filename) -{ - int handle; - address top; - ULONG bytes; - struct stat statbuf; - - if ((handle = open (filename, O_BINARY | O_RDONLY)) == -1) - err ("%s をオープン出来ません.\n", filename); - - if (fstat( handle , &statbuf) < 0) - err ("fstat failed.\n"); - Filedate = statbuf.st_mtime; - -#ifdef OSKDIS - if (option_z) { - Head.base = Base; - Head.exec = Exec; - Head.text = statbuf.st_size; - Head.data = 0; - Head.bss = 0; - Head.symbol = 0; - Head.bindinfo = 0; - } - else { - if (read (handle, (char *)&HeadOSK, sizeof (HeadOSK)) != sizeof (HeadOSK)) - goto os9head_error; - if (HeadOSK.head != 0x4afc) { - eprintf ("ID=%04X\n", HeadOSK.head); -os9head_error: - close(handle); - err ("OS-9/680x0 のモジュールではありません.\n"); - } - switch (HeadOSK.type & 0x0f00) { - case 0x0100: /* Program */ - Head.base = 0x0048; - Head.bss = HeadOSK.mem; - break; - case 0x0b00: /* Trap */ - Head.base = 0x0048; - Head.bss = HeadOSK.mem; - break; - case 0x0200: /* Subroutine */ - case 0x0c00: /* System */ - case 0x0d00: /* FileMan */ - case 0x0e00: /* Driver */ - Head.base = 0x003c; - Head.bss = HeadOSK.mem; - break; - default: - close(handle); - err ("このモジュールタイプはサポートしていません.\n"); - } - lseek(handle, Head.base, 0); - Head.exec = HeadOSK.exec; - Head.text = statbuf.st_size - (ULONG)(Head.base); - Head.data = 0; - Head.symbol = 0; - Head.bindinfo = 0; - } -#else - if (FileType == 0) { - char* ext = strrchr (filename, '.'); - - /* R 形式は拡張子で判別する */ - if (ext && strcasecmp (ext, ".r") == 0) - FileType = 'r'; - else { - char buf[2]; - - /* 先頭 2 バイトを読み込む */ - if (read (handle, buf, 2) < 2) - goto filetype_error; /* 2 バイト未満なら実行ファイルではない */ - lseek (handle, 0, SEEK_SET); - - /* ファイル形式を判別する */ - if (buf[0] == (char)'H' && buf[1] == (char)'U') - FileType = 'x'; - else if (buf[0] == (char)0x60 && buf[1] == (char)0x1a) - FileType = 'z'; - else - goto filetype_error; - } - } + err("対応していないファイル形式です。\n"); +} - if (option_z || FileType == (char)'r') { - Head.base = Base; - Head.exec = Exec; - Head.text = statbuf.st_size; - Head.data = 0; - Head.bss = 0; - Head.symbol = 0; - Head.bindinfo = 0; - } else if (FileType == (char)'z') { - zheader zhead; - - if (read (handle, (char*) &zhead, sizeof (zhead)) != sizeof (zhead)) - goto filetype_error; - Head.exec = Head.base = (address) peekl (&zhead.base); - Head.text = peekl (&zhead.text); - Head.data = peekl (&zhead.data); - Head.bss = peekl (&zhead.bss); - Head.symbol = 0; - Head.bindinfo = 0; - Absolute = ABSOLUTE_ZFILE; - } else { /* if (FileType == (char)'x') */ - if (read (handle, (char *)&Head, sizeof (Head)) != sizeof (Head)) { -filetype_error: - close (handle); - err ("このようなファイルは取り扱っておりません.\n"); - } - -#ifndef __BIG_ENDIAN__ - /* big-endian で格納されているヘッダを little-endian に変更する */ - Head.base = (address) peekl (&Head.base); - Head.exec = (address) peekl (&Head.exec); - Head.text = peekl (&Head.text); - Head.data = peekl (&Head.data); - Head.bss = peekl (&Head.bss); - Head.offset = peekl (&Head.offset); - Head.symbol = peekl (&Head.symbol); -#endif +// 実行ファイルのコード部を読み込む +static void readExeFile(FILE* fp) { + // 命令デコード中にデータセクション末尾を超えてもいいように余分を確保する + // move ([bd.l,an,ix],od.l),([bd.l,an,ix],od.l) で22バイトなのでそれ以上必要 + const size_t margin = 32; - } -#endif /* OSKDIS */ + size_t bytes = Dis.text + Dis.data + Dis.offset + Dis.symbol; + UBYTE* buffer = Malloc(bytes + margin); - bytes = Head.text + Head.data + Head.offset + Head.symbol; - top = (address) Malloc (bytes + 16); + if (fread(buffer, 1, bytes, fp) != bytes) err("ファイルサイズが異常です。\n"); - if (read (handle, (char*)top, bytes) != bytes) { - close (handle); - err ("ファイルサイズが異常です.\n"); - } + memset(buffer + bytes, 0, margin); - close (handle); - return top; + Dis.Top = buffer; + Dis.Ofst = buffer - (ULONG)Dis.base; } -/* - - 後始末 +// 実行ファイルを読み込む +static void loadExeFile(const char* filename) { + struct stat st; + FILE* fp = fopen(filename, "rb"); -*/ -extern void -free_load_buffer (void) -{ - Mfree ((void *) Top); -} + if (fp == NULL) err("%s をオープンできません。\n", filename); + if (fstat(fileno(fp), &st) != 0) + err("%s のファイル情報が取得できません。\n", filename); + Dis.fileDate = st.st_mtime; + eprintf("%s を読み込みます。\n", filename); -int -main (int argc, char* argv[]) -{ - time_t start_time = time (NULL); + if (Dis.fileType == FILETYPE_AUTO) Dis.fileType = getFileType(fp, filename); -#ifdef OSK - setbuf (stdout, NULL); +#ifdef OSKDIS + loadHeaderOsk(fp, st.st_size); +#else + loadHeaderHuman(fp, st.st_size); #endif - setbuf (stderr, NULL); - - analyze_args (argc, argv); - print_title (); - eprintf ("%s を読み込みます.\n", Filename_in); + readExeFile(fp); + fclose(fp); +} - /* アドレス関係の大域変数を初期化 */ - Top = (ULONG)loadfile (Filename_in); - Ofst = Top - (ULONG)Head.base; - BeginTEXT = Head.base; +typedef struct { + int bit; + char* name; +} TargetTable; + +static void printTarget(char* str, int bits, int size, const TargetTable* tbl); + +// 対象 MPU/MMU/FPU の表示 +static void printTargetISA(void) { + static const TargetTable mpu[] = { + {M000, "68000"}, {M010, "68010"}, {M020, "68020"}, {M030, "68030"}, + {M040, "68040"}, {M060, "68060"}, {MISP, "060ISP"} // + }; + static const TargetTable mmu[] = { + {MMU851, "68851"}, + {MMU030, "68030"}, + {MMU040, "68040"}, + {MMU060, "68060"} // + }; + static const TargetTable fpu[] = { + {F881, "68881"}, {F882, "68882"}, {F040, "68040"}, + {F4SP, "040FPSP"}, {F060, "68060"}, {F6SP, "060FPSP"} // + }; + + printTarget("MPU", Dis.mpu, _countof(mpu), mpu); + printTarget("MMU", Dis.mmu, _countof(mmu), mmu); + printTarget("FPU", Dis.fpu, _countof(fpu), fpu); +} -#ifdef OSKDIS - BeginBSS = BeginTEXT + Head.text; - BeginDATA = BeginBSS + Head.bss; - Last = BeginDATA + Head.data; - Available_text_end = BeginBSS; +static void printTarget(char* str, int bits, int size, const TargetTable* tbl) { + if (bits) { + const char* comma = ""; + eprintf("対象%s: ", str); + do { + if (bits & tbl->bit) { + eprintf("%s%s", comma, tbl->name); + comma = ","; + } + tbl++; + } while (--size); + eputc('\n'); + } +} -#else - BeginDATA = BeginTEXT + Head.text; - BeginBSS = BeginDATA + Head.data; - Last = BeginSTACK = BeginBSS + Head.bss; - Available_text_end = (option_D ? BeginBSS : BeginDATA); - - if (Head.bindinfo) { - eprintf ("このファイルは bind されています.\n" - "unbind コマンド等で展開してからソースジェネレートして下さい.\n"); - return 1; - } -#endif /* OSKDIS */ - - - load_OS_sym(); - init_labelbuf(); - init_symtable(); - - - /* 対象 MPU/MMU/FPU の表示 */ - { - static const target_table mpu_table[] = { - { M000, "68000" }, - { M010, "68010" }, - { M020, "68020" }, - { M030, "68030" }, - { M040, "68040" }, - { M060, "68060" }, - { MISP, "060ISP" } - }; - - static const target_table mmu_table[] = { - { MMU851, "68851" }, - { MMU030, "68030" }, - { MMU040, "68040" }, - { MMU060, "68060" } - }; - - static const target_table fpu_table[] = { - { F881, "68881" }, - { F882, "68882" }, - { F040, "68040" }, - { F4SP, "040FPSP" }, - { F060, "68060" }, - { F6SP, "060FPSP" } - }; - - print_target ("Target MPU: ", MPU_types, - mpu_table, (sizeof mpu_table / sizeof mpu_table[0])); - - print_target ("Target MMU: ", MMU_type, - mmu_table, (sizeof mmu_table / sizeof mmu_table[0])); - - print_target ("Target FPU: ", FPCP_type, - fpu_table, (sizeof fpu_table / sizeof fpu_table[0])); - } +/* + 絶対に必要なラベル(セクション先頭とプログラム末尾)を登録する -#ifndef OSKDIS - eprintf ("リロケート情報を展開します.\n"); - make_relocate_table (); -#endif /* !OSKDIS */ +*/ +static void register_default_labels(void) { + regist_label(Dis.beginTEXT, DATLABEL | UNKNOWN); + regist_label(Dis.beginDATA, DATLABEL | UNKNOWN); + regist_label(Dis.beginBSS, DATLABEL | UNKNOWN); + /* unregist されないように SYMLABEL を指定 */ + regist_label(Dis.LAST, DATLABEL | UNKNOWN | SYMLABEL); +} - while (check_exist_output_file (Filename_out)) - change_filename (&Filename_out, "source"); +// データ領域の中からプログラム領域を探す +static boolean researchDataLoop(boolean tweak) { + int change = FALSE; - if (option_e) - while (check_exist_output_file (Labelfilename_out)) - change_filename (&Labelfilename_out, "label"); + do { + int found = research_data(tweak); + if (found == 0) break; + change = TRUE; + eprintf("{%d}", found); + } while (!Dis.l); - check_open_output_file (Filename_out); + return change; +} - if (option_g) { - eprintf ("ラベルファイルを読み込み中です.\n"); - read_labelfile (Labelfilename_in); - } - if (option_e) - check_open_output_file (Labelfilename_out); - if (option_T) { - eprintf ("テーブル記述ファイルを読み込み中です.\n"); - read_tablefile (Tablefilename); +// 相対オフセットテーブルの宛先からプログラム領域を探す +static boolean analyzeReltblLoop(int countChar) { + int change = FALSE; + + while (1) { + if (analyzeRegisteredReltbl(&Dis.reltblArray) == 0) break; + if (countChar) { + eprintf( + "\n相対オフセットテーブルの宛先からプログラム領域を探しています(%c)" + "。", + countChar); + countChar = 0; } + if (!researchDataLoop(FALSE)) break; + change = TRUE; + } -#ifndef OSKDIS - if (Head.symbol) { - eprintf ("シンボルテーブルを展開します.\n"); - make_symtable (); - } else - eprintf ("シンボルテーブルは残念ながら存在しません.\n"); -#endif + return change; +} - Exist_symbol = is_exist_symbol (); +// データ領域の中から各種の領域を繰り返し探す +static void analyzeLoop(void) { + const uint8_t progInData = !Dis.p; - analyze_and_generate (argc, argv); + if (progInData) { + eprintf("\nデータ領域の中からプログラム領域を探しています(1)。"); + researchDataLoop(FALSE); + } - eprintf ("\n終了しました.\n"); - free_labelbuf (); - free_relocate_buffer (); - free_symbuf (); - free_load_buffer (); + analyzeReltblLoop('1'); - { - time_t finish_time = time (NULL); - eprintf ("所要時間: %d秒\n", (int) difftime (finish_time, start_time)); - } + if (Dis.stringLengthMin == 0) return; + do { + int found; + boolean tweak = FALSE; - return 0; -} + eprintf("\n文字列を探しています。"); + found = search_string(Dis.stringLengthMin); + if (found == 0) + tweak = TRUE; + else + eprintf("{%d}", found); + // 文字列が見つかってもデータ領域からプログラムは探さない + if (!progInData) break; + eprintf("\nデータ領域の中からプログラム領域を探しています(2)。"); + if (!researchDataLoop(tweak)) break; -/* + if (!analyzeReltblLoop('2') && tweak) break; + } while (!Dis.l); +} - デバイスドライバの処理 +// 解析して生成 +static void analyze_and_generate(const char* argv0, char* argv[]) { + if (!Dis.g) { + Dis.actions->analyzeProgram(); + eputc('\n'); + } + + eprintf("データ領域解析中です。"); + setReasonVerbose(BACKTRACK_REASON_ALL); + analyze_data(); + analyzeLoop(); + + if (!Dis.c) { + eprintf("\nラベルチェック中。"); + search_operand_label(); + } + + if (Dis.e) { + eprintf("\nラベルファイルを作成中です。"); + make_labelfile(Dis.execFile, Dis.outputLabelFile); + } + + eprintf("\nソースを作成中です。"); + generate(Dis.execFile, Dis.outputFile, Dis.fileDate, argv0, COMMAND_LINE); +} -*/ -#ifndef OSKDIS -private void -analyze_device (void) -{ - ULONG ad = 0; +int main(int argc, char* argv[]) { + time_t start_time = time(NULL); - Reason_verbose = (Verbose >= 1) ? TRUE : FALSE; + setbuf(stderr, NULL); - do { - regist_label (Head.base + ad , DATLABEL | LONGSIZE | FORCE); - regist_label (Head.base + ad + 4 , DATLABEL | WORDSIZE | FORCE | HIDDEN); -#if 0 - regist_label (Head.base + ad + 6 , DATLABEL | LONGSIZE | FORCE); - regist_label (Head.base + ad + 0xa , DATLABEL | LONGSIZE | FORCE); -#endif - regist_label (Head.base + ad + 0xe , DATLABEL | STRING | FORCE | HIDDEN); - regist_label (Head.base + ad + 0x16, DATLABEL | UNKNOWN); - - analyze (*(address*) (Ofst + ad + 6 ), ANALYZE_IGNOREFAULT); - analyze (*(address*) (Ofst + ad + 0xa), ANALYZE_IGNOREFAULT); - ad = *(ULONG*) (ad + Ofst); - } while (((long)ad & 1) == 0 -#if 0 - && (ad != (address)-1) /* 不要 */ -#endif - && (ad < (ULONG)BeginBSS)); /* SCSIDRV.SYS 対策 */ -} -#endif /* OSKDIS */ + initDisVars(); + analyze_args(argc, argv); + fputs(Title, stderr); + decideOutputFilename("ソースコード", &Dis.outputFile); + if (Dis.e) decideOutputFilename("ラベル", &Dis.outputLabelFile); -/* + printTargetISA(); - 解析して生成 + loadExeFile(Dis.execFile); + Dis.actions->readIncludeFiles(); + init_labelbuf(); + Dis.actions->makeRelocateTable(); -*/ -private void -analyze_and_generate (int argc, char* argv[]) -{ - - if (option_v) { - eprintf ("逆アセンブルリストを出力します.\n"); - disasmlist (Filename_in, Filename_out, Filedate); - return; - } + register_default_labels(); + if (Dis.g) { + eprintf("ラベルファイルを読み込み中です。\n"); + read_labelfile(Dis.inputLabelFile); + } - Disasm_String = FALSE; /* 解析中はニーモニックは不要 */ - - if (!option_g) { - -#ifdef OSKDIS - switch (HeadOSK.type & 0x0f00) { - case 0x0100: /* Program */ - case 0x0b00: /* Trap */ - eprintf ("\n初期化データ領域解析中です."); - analyze_idata (); /* 初期データオフセットを解析 */ - analyze_irefs (); /* 初期データ参照テーブルを解析 */ - eputc ('\n'); - default: - break; - } - regist_label (Head.base + Head.text + Head.data + Head.bss, DATLABEL | UNKNOWN); -#endif /* OSKDIS */ - - eprintf ("プログラム領域解析中です."); - - /* セクションのエントリアドレスをテーブルに登録 */ - regist_label (BeginTEXT, DATLABEL | UNKNOWN); - regist_label (BeginDATA, DATLABEL | UNKNOWN); - regist_label (BeginBSS , DATLABEL | UNKNOWN); -#if 0 - regist_label (Last, DATLABEL | UNKNOWN); -#else /* 最後のラベルが unregist される不具合の対処 */ - regist_label (Last, DATLABEL | UNKNOWN | SYMLABEL); -#endif - Reason_verbose = (Verbose >= 1) ? TRUE : FALSE; - -#ifdef OSKDIS - switch (HeadOSK.type & 0x0f00) { - case 0x0b00: /* Trap */ - regist_label (HeadOSK.init, PROLABEL | WORDSIZE | FORCE); - regist_label (HeadOSK.term, PROLABEL | WORDSIZE | FORCE); - z_table(0x000048); - case 0x0100: /* Program */ -#if 1 /* デバッグの為のコード */ - regist_label (HeadOSK.idata, DATLABEL | LONGSIZE | FORCE); - regist_label (HeadOSK.irefs, DATLABEL | WORDSIZE | FORCE); -#endif - break; - case 0x0200: /* Subroutine */ - case 0x0c00: /* System */ - break; - case 0x0d00: /* FileMan */ - regist_label (HeadOSK.exec + 0, DATLABEL | WORDSIZE | FORCE); - relative_table (HeadOSK.exec); - break; - case 0x0e00: - regist_label (HeadOSK.exec + 0, DATLABEL | WORDSIZE | FORCE); - w_table (HeadOSK.exec); - break; - } - regist_label (HeadOSK.excpt, PROLABEL | WORDSIZE | FORCE); - regist_label (HeadOSK.name, DATLABEL | STRING | FORCE); -#if 1 - regist_label (HeadOSK.size - 4, DATLABEL | BYTESIZE | FORCE); /* CRC */ -#endif - analyze (Head.exec, ANALYZE_IGNOREFAULT); - -#else /* !OSKDIS */ - if (option_d) { - analyze_device (); - if (Head.exec != Head.base) - analyze (Head.exec, option_i ? ANALYZE_IGNOREFAULT : ANALYZE_NORMAL); - } else - analyze (Head.exec, ANALYZE_IGNOREFAULT); -#endif /* OSKDIS */ - } + if (Dis.T) { + eprintf("テーブル記述ファイルを読み込み中です。\n"); + read_tablefile(Dis.tableFile); + } - Reason_verbose = (Verbose == 2) ? TRUE : FALSE; - eprintf ("\nデータ領域解析中です."); - analyze_data (); + Dis.actions->parseSymbolTable(&Dis.symtblArray); -#if 0 - if (!option_g) { - eprintf ("\nアドレステーブルから捜しています."); - search_adrs_table (); - } -#endif + initEAString(); + initOpString(); - if (!option_p) - do - eprintf ("\nデータ領域の中からプログラム領域を捜しています(1)."); - while (research_data () && !option_l); - - if (String_length_min) - do { - eprintf ("\n文字列を捜しています."); - if (!search_string (String_length_min) || option_p) - break; - eprintf ("\nデータ領域の中からプログラム領域を捜しています(2)."); - if (!research_data ()) - break; - do - eprintf ("\nデータ領域の中からプログラム領域を捜しています."); - while (research_data () && !option_l); - } while (!option_l); - - if (!option_c) { - eprintf ("\nラベルチェック中."); - search_operand_label (); - } + if (Dis.v) { + eprintf("逆アセンブルリストを出力します。"); + disasmlist(Dis.outputFile); + } else { + const char* argv0 = Dis.deterministic ? "dis" : argv[0]; + analyze_and_generate(argv0, argv); + } - if (option_e) { - eprintf ("ラベルファイルを作成中です.\n"); - make_labelfile (Filename_in, Labelfilename_out); - } + eprintf("\n終了しました。\n"); + { + time_t finish_time = time(NULL); + eprintf("所要時間: %d秒\n", (int)difftime(finish_time, start_time)); + } - eprintf ("ソースを作成中です."); - generate (Filename_in, Filename_out, Filedate, argc, argv); + return 0; } - /* 出力ファイルの存在チェック 返値: 0 = 出力可能 - 1 = ファイル名を変更する + 1 = ファイル名を変更する */ -private int -check_exist_output_file (char* filename) -{ - FILE* fp; - - /* --overwrite 指定時は無条件に上書き. */ - if (option_overwrite) - return 0; - - /* 標準出力に出力するなら検査不要. */ - if (strcmp ("-", filename) == 0) - return 0; - - /* ファイルが存在しなければOK. */ - if ((fp = fopen (filename, "r")) == NULL) - return 0; - - /* 端末デバイスへの出力ならOK. */ - if (isatty (fileno (fp))) { - fclose (fp); - return 0; - } - - /* いずれでもなければキー入力. */ - fclose (fp); - -#ifdef QUICK_YES_NO /* version 2.79 互換 */ - { - int key; - eprintf ("%s が既に存在します.\n" - "Over Write ( Y or N )? ", filename); - do - key = toupper (getch ()); - while (key != 'Y' && key != 'N'); - eprintf ("%c\n", key); - if (key == 'Y') - return 0; - } -#else /* 安全の為 "yes" を入力させる. */ - { - char buf[256]; - eprintf ("%s が既に存在します.\n" - "上書きしますか?(Yes/No/Rename): ", filename); - - if (fgets (buf, sizeof buf, stdin)) { - /* y, yes なら上書き */ - if (strcasecmp (buf, "y\n") == 0 || strcasecmp (buf, "yes\n") == 0) - return 0; - /* r, rename ならファイル名変更 */ - if (strcasecmp (buf, "r\n") == 0 || strcasecmp (buf, "rename\n") == 0) - return 1; - } - } -#endif /* QUICK_YES_NO */ - - /* 上書きしないならプログラム終了. */ - exit (1); -} +static int check_exist_output_file(char* filename) { + FILE* fp; + /* --overwrite 指定時は無条件に上書き. */ + if (Dis.overwrite) return 0; -/* + /* 標準出力に出力するなら検査不要. */ + if (strcmp("-", filename) == 0) return 0; - 出力ファイル名を変更する. + /* ファイルが存在しなければOK. */ + if ((fp = fopen(filename, "r")) == NULL) return 0; -*/ -private void -change_filename (char** nameptr, const char* file) -{ - char buf[PATH_MAX + 1]; - int len; - - eprintf ("Input %s filename:", file); -#if 0 - fflush (stderr); -#endif - if (fgets (buf, sizeof buf, stdin) && (len = strlen (buf)) > 1) { - buf[len - 1] = '\0'; - *nameptr = strcpy (Malloc (len), buf); - return; + /* 端末デバイスへの出力ならOK. */ + if (isatty(fileno(fp))) { + fclose(fp); + return 0; + } + + /* いずれでもなければキー入力. */ + fclose(fp); + +#ifdef QUICK_YES_NO /* version 2.79 互換 */ + { + int key; + eprintf( + "%s が既に存在します。\n" + "Over Write ( Y or N )? ", + filename); + do key = toupper(getch()); + while (key != 'Y' && key != 'N'); + eprintf("%c\n", key); + if (key == 'Y') return 0; + } +#else /* 安全の為 "yes" を入力させる. */ + { + char buf[256]; + eprintf( + "%s が既に存在します。\n" + "上書きしますか?(Yes/No/Rename): ", + filename); + + if (fgets(buf, sizeof buf, stdin)) { + /* y, yes なら上書き */ + if (strcasecmp(buf, "y\n") == 0 || strcasecmp(buf, "yes\n") == 0) + return 0; + /* r, rename ならファイル名変更 */ + if (strcasecmp(buf, "r\n") == 0 || strcasecmp(buf, "rename\n") == 0) + return 1; } - exit (1); + } +#endif /* QUICK_YES_NO */ + + // 上書きしないならプログラム終了 + errorExit(); } +// 出力ファイル名を変更する +static void change_filename(char** nameptr, const char* file) { + char buf[PATH_MAX + 1]; + size_t len; + + eprintf("%sファイル名:", file); + if (fgets(buf, sizeof buf, stdin) && (len = strlen(buf)) > 1) { + buf[len - 1] = '\0'; + *nameptr = strcpy(Malloc(len + 1), buf); + return; + } + errorExit(); +} -/* +// 出力ファイルに書き込めるどうかのチェック +// 書き込めない場合はエラー終了する +static void check_open_output_file(char* filename) { + struct stat st; - 出力ファイルに書き込めるどうかのチェック + if (!strcmp("-", filename)) return; -*/ -private void -check_open_output_file (char* filename) -{ - int fd; + // ファイルがなければ、(恐らく)書き込みオープンできる + if (stat(filename, &st) < 0) return; - if (!strcmp ("-", filename)) - return; + if ((st.st_mode & S_IWRITE) == 0) err("%s に書き込めません。\n", filename); +} -#ifdef OSK - if ((fd = open (filename, S_IREAD)) < 0) -#else - if ((fd = open (filename, O_RDONLY)) < 0) -#endif /* OSK */ - return; +// 出力ファイル名を決定する +// 同名ファイルがあれば上書きするか別のファイル名に出力するか選択 +// 上書きしない、書き込めない場合はプログラムをエラー終了する +static void decideOutputFilename(const char* fileType, char** nameptr) { + while (check_exist_output_file(*nameptr)) { + change_filename(nameptr, fileType); + } + check_open_output_file(*nameptr); +} - if (isatty (fd)) { - close (fd); - return; - } - close (fd); - if (access (filename, R_OK | W_OK) < 0) - err ("%s にアクセスできません(!)\n", filename); +// LIBC 以外で使用する関数 +#ifdef NEED_MAKE_CMDLINE +static char* make_cmdline(char** argv) { + char** ap; + char* buf; + size_t size = 0; + int needSpace = FALSE; + + for (ap = argv; *ap;) { + size += strlen(*ap++) + 1; + } + buf = Malloc(size); + buf[0] = '\0'; + + for (ap = argv; *ap;) { + if (needSpace) strcat(buf, " "); + needSpace = TRUE; + strcat(buf, *ap++); + } + + return buf; } +#endif -/* EOF */ +// EOF diff --git a/src/mmu.c b/src/mmu.c new file mode 100644 index 0000000..fcacd3d --- /dev/null +++ b/src/mmu.c @@ -0,0 +1,343 @@ +// ソースコードジェネレータ +// MMU命令逆アセンブル +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "mmu.h" + +#include "disasm.h" +#include "ea.h" +#include "global.h" +#include "hex.h" +#include "opstr.h" + +char* stringifyQuadWord(char* buf, quadword* valp) { + *buf++ = '!'; + buf = itox8_without_0supress(buf, valp->hi); + *buf++ = '_'; + return itox8_without_0supress(buf, valp->lo); +} + +// 68851/68030 PLOAD +static boolean pload(codeptr ptr, disasm* code, UWORD word2) { + code->mputypes = M020 | M030; + + OPECODE(pload[(word2 >> 9) & 1]); + code->bytes = 4; + if (!setMMUfc(code, &code->op1, word2)) return FALSE; + return setEA(code, &code->op2, ptr, CTRLCHG); +} + +// 68851 PVALID +static boolean pvalid(codeptr ptr, disasm* code, UWORD word2) { + if (reject_no_pmmu(code)) return FALSE; + + OPECODE(pvalid); + code->bytes = 4; + code->size = code->size2 = code->default_size = LONGSIZE; + if (word2 & 0x0400) + setMMUregVal(&code->op1); + else + setAn(&code->op1, word2); + return setEA(code, &code->op2, ptr, CTRLCHG); +} + +// 68851/68030 PFLUSHA +static boolean pflusha(disasm* code, UWORD word1) { + if (extract_ea_modreg(word1) != 0 && Dis.undefReg) return FALSE; + + code->mputypes = M020 | M030; + + OPECODE(pflusha); + code->bytes = 4; + + return TRUE; +} + +// 68851/68030 PFLUSH +static boolean pflush(codeptr ptr, disasm* code, UWORD word1, UWORD word2) { + int mode = (word2 >> 10) & 7; + + if ((mode & 2) == 0 && extract_ea_modreg(word1) != 0 && Dis.undefReg) + return FALSE; + + if (mode & 1) { + if (reject_no_pmmu(code)) return FALSE; // fflushsは68851のみ + OPECODE(pflushs); + } else { + code->mputypes = M020 | M030; + OPECODE(pflush[PFOPMODE_PFLUSH]); + } + + code->bytes = 4; + if (!setMMUfc(code, &code->op1, word2) || // fc + !setMMUfc(code, &code->op2, (word2 >> 5) | 0x10)) { // #xx + return FALSE; + } + if (mode & 2) return setEA(code, &code->op3, ptr, CTRLCHG); // + + return TRUE; +} + +static boolean op000cls001(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + + if ((word2 & 0xfde0) == 0x2000) return pload(ptr, code, word2); + if ((word2 & 0xfbf8) == 0x2800) return pvalid(ptr, code, word2); + if (word2 == 0x2400) return pflusha(code, word1); + if ((word2 & 0xf200) == 0x3000) return pflush(ptr, code, word1, word2); + + return FALSE; +} + +// 68851/68030 PMOVE +static boolean pmove(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + int rw_fd = (word2 >> 8) & 3; + int rw = rw_fd >> 1; + int fd = rw_fd & 1; + + // pmovefd ea,mmureg は68030専用 + // pmovefd mmureg,ea は存在しない + if ((word2 & 0x00ff) != 0x0000 || rw_fd == 3 || + (rw_fd == 1 && (Dis.mmu & MMU030) == 0)) { + return FALSE; + } + code->mputypes = fd ? M030 : M020 | M030; + + OPECODE2(fd, pmovefd, pmove); + { + operand* mmureg = rw ? &code->op1 : &code->op2; + operand* eamem = rw ? &code->op2 : &code->op1; + + int mode = setMMUreg(code, mmureg, word2, extract_ea_basic(word1)); + if (mode == 0) return FALSE; + return setEA(code, eamem, ptr, mode); + } +} + +// 68851 PMOVE to/from PSR/PCSR +// 68030 PMOVE to/from MMUSR +static boolean cls011pmove(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + int rw = (word2 >> 9) & 1; + + code->mputypes = M020 | M030; + + OPECODE(pmove); + { + operand* mmureg = rw ? &code->op1 : &code->op2; + operand* eamem = rw ? &code->op2 : &code->op1; + + if (!setPMMUreg(code, mmureg, word2)) return FALSE; + return setEA(code, eamem, ptr, CTRLCHG); + } +} + +// 68851/68030 PTEST +static boolean ptest(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + int level = (word2 >> 10) & 7; + int a = (word2 >> 8) & 1; + int regno = (word2 >> 5) & 7; + + if (level == 0 && (a != 0 || regno != 0)) { + // level==0のとき、A-REGISTERフィールドは0でないとFライン例外になる + return FALSE; + } + if (a == 0 && regno != 0 && Dis.undefReg) return FALSE; + + code->mputypes = M020 | M030; + + OPECODE(ptest[(word2 >> 9) & 1]); + code->bytes = 4; + if (!setMMUfc(code, &code->op1, word2)) return FALSE; + if (!setEA(code, &code->op2, ptr, CTRLCHG)) return FALSE; + setImmEmbed(&code->op3, level); + if (a) setAn(&code->op4, regno); + + return TRUE; +} + +// 68851 PFLUSHR +static boolean pflushr(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + + if (word2 != 0xa000) return FALSE; + if (reject_no_pmmu(code)) return FALSE; + + OPECODE(pflushr); + code->bytes = 4; + return setEA(code, &code->op1, ptr, MEMORY); +} + +static boolean op000(codeptr ptr, disasm* code) { + UWORD word1 = peekw(ptr); + int opclass = peekb(ptr + 2) >> 5; + + switch (opclass) { + default: + break; + + case 0: + case 2: + return pmove(ptr, code, word1); + case 1: + return op000cls001(ptr, code, word1); + case 3: + return cls011pmove(ptr, code); + case 4: + return ptest(ptr, code); + case 5: + return pflushr(ptr, code); + } + + return FALSE; +} + +// 68851 PDBcc +static boolean pdbcc(codeptr ptr, disasm* code, UWORD word1) { + UWORD word2 = peekw(ptr + 2); + + if ((word2 & 0xfff0) != 0) return FALSE; + + OPECODE(pdbcc[word2 & 15]); + setDn(&code->op1, word1); + setrelative4(code, &code->op2, extl(peekw(ptr + 4))); + code->jmp = code->op2.opval; + code->jmpea = code->op2.ea = PCDISP; + code->op2.labelchange1 = LABELCHANGE_LABEL_ONLY; + code->opeType = BCCOP; + code->bytes = 6; + code->size = code->size2 = WORDSIZE; + + return TRUE; +} + +// 68851 PTRAPcc +static boolean ptrapcc(codeptr ptr, disasm* code, int opmode) { + UWORD word2 = peekw(ptr + 2); + + if ((word2 & 0xfff0) != 0) return FALSE; + + OPECODE(ptrapcc[word2 & 15]); + code->bytes = 4; + if (opmode != CPTRAP_UNSIZED) { + code->size = (opmode == CPTRAP_WORD) ? WORDSIZE : LONGSIZE; + return setImm(code, &code->op1, ptr, code->size); + } + return TRUE; +} + +// 68851 PScc +static boolean pscc(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + + if ((word2 & 0xfff0) != 0) return FALSE; + + OPECODE(pscc[word2 & 15]); + code->bytes = 4; + code->size = code->size2 = code->default_size = BYTESIZE; + return setEA(code, &code->op1, ptr, DATA & CHANGE); +} + +static boolean op001(codeptr ptr, disasm* code) { + UWORD word1 = peekw(ptr); + int eamode, opmode; + + if (reject_no_pmmu(code)) return FALSE; + + // PScc で未使用のにPDBccとPTRAPccが割り当てられているので先に調べる + eamode = (word1 >> 3) & 7; + if (eamode == 1) return pdbcc(ptr, code, word1); + + opmode = word1 & 7; + if (eamode == 7 && CPTRAP_WORD <= opmode && opmode <= CPTRAP_UNSIZED) { + return ptrapcc(ptr, code, opmode); + } + + return pscc(ptr, code); +} + +// 68851 PBcc +static boolean pbcc(codeptr ptr, disasm* code, UWORD word1, opesize size) { + if (reject_no_pmmu(code)) return FALSE; + if (word1 & 0x0030) return FALSE; + + OPECODE(pbcc[word1 & 15]); + code->default_size = NOTHING; + code->size = code->size2 = size; + if (size == WORDSIZE) { + code->bytes = 4; + setrelative(code, &code->op1, extl(peekw(ptr + 2))); + } else { + LONG d32 = peekl(ptr + 2); + code->bytes = 6; + setrelative(code, &code->op1, d32); + if (-32768 <= d32 && d32 <= 32767) code->codeflags += CODEFLAG_NEED_OPESIZE; + } + code->jmp = code->op1.opval; + code->jmpea = code->op1.ea = PCDISP; + code->opeType = BCCOP; + code->op1.labelchange1 = LABELCHANGE_LABEL_ONLY; + + return TRUE; +} + +// 68851 PSAVE +static boolean psave(codeptr ptr, disasm* code) { + if (reject_no_pmmu(code)) return FALSE; + + OPECODE(psave); + return setEA(code, &code->op1, ptr, CTRLCHG | PREDEC); +} + +// 68851 PRESTORE +static boolean prestore(codeptr ptr, disasm* code) { + if (reject_no_pmmu(code)) return FALSE; + + OPECODE(prestore); + return setEA(code, &code->op1, ptr, CONTROL | POSTINC); +} + +// 68851/68030の拡張命令(コプロセッサID=0) +boolean cp000(codeptr ptr, disasm* code) { + UWORD word1 = peekw(ptr); + int optype = (word1 >> 6) & 7; + + switch (optype) { + default: + break; + + case 0: + return op000(ptr, code); + case 1: + return op001(ptr, code); + case 2: + return pbcc(ptr, code, word1, WORDSIZE); + case 3: + return pbcc(ptr, code, word1, LONGSIZE); + case 4: + return psave(ptr, code); + case 5: + return prestore(ptr, code); + } + + return FALSE; +} + +// EOF diff --git a/src/mmu.h b/src/mmu.h new file mode 100644 index 0000000..256ff18 --- /dev/null +++ b/src/mmu.h @@ -0,0 +1,36 @@ +// ソースコードジェネレータ +// MMU命令逆アセンブル ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef MMU_H +#define MMU_H + +#include "disasm.h" +#include "estruct.h" + +typedef struct { + ULONG hi; + ULONG lo; +} quadword; + +extern char* stringifyQuadWord(char* buf, quadword* valp); +extern boolean cp000(codeptr ptr, disasm* code); + +#endif + +// EOF diff --git a/src/offset.c b/src/offset.c index 8886afe..b4bd62a 100644 --- a/src/offset.c +++ b/src/offset.c @@ -1,157 +1,110 @@ -/* $Id: offset.c,v 1.1 1996/11/07 08:03:52 ryo freeze $ - * - * ソースコードジェネレータ - * 再配置テーブル管理モジュール - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 再配置テーブル管理モジュール +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "offset.h" #include -#include "estruct.h" #include "etc.h" #include "global.h" -#include "offset.h" - - -/* #define DEBUG */ - - -static address* Reltable = NULL; /* 再配置テーブルの頭 */ -static int Relnum; /* 再配置テーブルの要素数 */ - - -#ifdef DEBUG -private void -disp_reltable (void) -{ - int i; - - for (i = 0; i < Relnum; i++) - printf ("%5x\n", Reltable[i]); -} -#endif +static address* Reltable = NULL; /* 再配置テーブルの頭 */ +static int Relnum; /* 再配置テーブルの要素数 */ /* 再配置テーブルから再配置すべきアドレスのテーブルを作る */ -extern void -make_relocate_table (void) -{ - address destadrs = BeginTEXT; - UBYTE* ptr; /* オフセット表へのポインタ ( not always even !) */ - - if ((Reltable = (address *) Malloc (Head.offset * 2)) == NULL) - err ("リロケート情報の展開バッファを確保出来ませんでした\n"); - - Relnum = 0; - ptr = (UBYTE*) (Top + Head.text + Head.data); - - while (ptr < (UBYTE*) (Top + Head.text + Head.data + Head.offset)) { - if ((*ptr << 8) + *(ptr + 1) == 0x0001) { - /* 0x0001 0x???? 0x???? : ロングワード距離 */ - ptr += 2; - destadrs += (ULONG) ( (*(ptr + 0) << 24) - + (*(ptr + 1) << 16) - + (*(ptr + 2) << 8) - + *(ptr + 3)); - ptr += 4; - } - else { - /* 0x???? ( != 0x0001 ) : ワード距離 */ - destadrs += (ULONG) (((*ptr << 8) + *(ptr + 1)) & 0xfffe); - ptr += 2; - } - Reltable[Relnum++] = destadrs; +void makeRelocateTableHuman(void) { + address destadrs = Dis.beginTEXT; + + /* オフセット表へのポインタ (not always even!) */ + UBYTE* ptr = (UBYTE*)(Dis.Top + Dis.text + Dis.data); + + /* オフセット表のword数 */ + size_t units = Dis.offset / sizeof(UWORD); + size_t remain; + + eprintf("リロケート情報を展開します。\n"); + + Relnum = 0; + Reltable = Malloc(units * sizeof(address)); + + for (remain = units; remain > 0;) { + UWORD w = (ptr[0] << 8) + ptr[1]; + ptr += 2; + remain -= 1; + + if (w == 0x0001) { + /* 0x0001 0x???? 0x???? : ロングワード距離 */ + if (remain < 2) { + break; /* リロケート情報のサイズが不正 */ + } + destadrs += (ptr[0] << 24) + (ptr[1] << 16) + (ptr[2] << 8) + ptr[3]; + ptr += 4; + remain -= 2; + } else { + /* 0x???? ( != 0x0001 ) : ワード距離 */ + destadrs += w & 0xfffe; } - -#ifdef DEBUG - disp_reltable (); -#endif -} - - -/* - - 後始末 - -*/ -extern void -free_relocate_buffer (void) -{ - /* if (Reltable) */ - Mfree (Reltable); + Reltable[Relnum++] = destadrs; + } } - /* adrs がプログラムのロードされたアドレスに依存しているなら TRUE - label1 pea.l label2 - このとき depend_address( label1 + 2 ) == TRUE ( label2が依存している ) + label1: pea.l (label2).l + このとき depend_address(label1 + 2) == TRUE (label2が依存している) */ -extern boolean -depend_address (address adrs) -{ - address* ptr = Reltable; - int step = Relnum >> 1; - - while (step > 4) { - if (*(ptr + step) <= adrs) /* binary search */ - ptr += step; - step >>= 1; - } - for (; ptr < Reltable + Relnum; ptr++) { - if (*ptr == adrs) { -#ifdef DEBUG - printf ("%6x is address-dependent\n", adrs); -#endif - return TRUE; - } else - if (adrs < *ptr) - return FALSE; - } - return FALSE; +extern boolean depend_address(address adrs) { + address* ptr = Reltable; + int step = Relnum >> 1; + + while (step > 4) { + if (*(ptr + step) <= adrs) /* binary search */ + ptr += step; + step >>= 1; + } + for (; ptr < Reltable + Relnum; ptr++) { + if (*ptr == adrs) { + return TRUE; + } else if (adrs < *ptr) + return FALSE; + } + return FALSE; } - /* adrs かそれより後で、最も近いアドレス依存のアドレスを返す そのような領域が無ければ 0xffffffff = -1 を返す */ -extern address -nearadrs (address adrs) -{ - address rc = (address)-1; - int step = Relnum >> 1; - address* ptr = Reltable; - - while (step > 4) { - if (*(ptr + step) < adrs) /* binary search */ - ptr += step; - step >>= 1; +extern address nearadrs(address adrs) { + address rc = (address)-1; + int step = Relnum >> 1; + address* ptr = Reltable; + + while (step > 4) { + if (*(ptr + step) < adrs) /* binary search */ + ptr += step; + step >>= 1; + } + + for (; ptr < Reltable + Relnum; ptr++) { + if (adrs <= *ptr) { + rc = *ptr; + break; } + } - for (; ptr < Reltable + Relnum; ptr++) { - if (adrs <= *ptr) { - rc = *ptr; - break; - } - } - -#ifdef DEBUG - printf ("nearadrs (%x) = %x\n", adrs, rc); -#endif - return rc; + return rc; } - -/* EOF */ +// EOF diff --git a/src/offset.h b/src/offset.h index fa71418..4b45c41 100644 --- a/src/offset.h +++ b/src/offset.h @@ -1,28 +1,24 @@ -/* $Id: offset.h,v 1.1 1996/10/24 04:27:48 ryo freeze $ - * - * ソースコードジェネレータ - * 再配置テーブル管理ヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 再配置テーブル管理 ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef OFFSET_H -#define OFFSET_H +#ifndef OFFSET_H +#define OFFSET_H +#include "estruct.h" +#include "global.h" -extern void make_relocate_table (void); -extern void free_relocate_buffer (void); -extern boolean depend_address (address); -extern address nearadrs (address); +extern void makeRelocateTableHuman(void); +extern boolean depend_address(address); +extern address nearadrs(address); -#define INPROG(opval, eaadrs) \ - (depend_address (eaadrs) || \ - (Absolute == ABSOLUTE_ZFILE && Head.base - 0x100 <= opval) || \ - (Absolute == ABSOLUTE_ZOPT && Head.base <= opval && opval <= Last)) +#define INPROG(opval, eaadrs) \ + (depend_address(eaadrs) || \ + (Dis.fileType == FILETYPE_Z && Dis.base - 0x100 <= opval) || \ + (Dis.fileType == FILETYPE_DUMP && Dis.base <= opval && opval <= Dis.LAST)) +#endif -#endif /* OFFSET_H */ - -/* EOF */ +// EOF diff --git a/src/opstr.c b/src/opstr.c new file mode 100644 index 0000000..f3e6c9c --- /dev/null +++ b/src/opstr.c @@ -0,0 +1,324 @@ +// ソースコードジェネレータ +// オペコード文字列 +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "opstr.h" + +#include "etc.h" +#include "global.h" + +// コンディションコード +enum { + COND_F = 1, +}; + +OpStringTable OpString = { + // 疑似命令 + {"\t.dc.b\t", "\t.dc.w\t", "\t.dc.l\t", "\t.dc.d\t", "", // + "\t.dc.s\t", "\t.dc.d\t", "\t.dc.x\t", "\t.dc.p\t"}, + {"\t.dcb.b\t", "\t.dcb.w\t", "\t.dcb.l\t", "\t.dcb.d\t", "", // + "\t.dcb.s\t", "\t.dcb.d\t", "\t.dcb.x\t", "\t.dcb.p\t"}, + {"\t.ds.b\t", "\t.ds.w\t", "\t.ds.l\t", "\t.ds.d\t", "", // + "\t.ds.s\t", "\t.ds.d\t", "\t.ds.x\t", "\t.ds.p\t"}, + + "\t.include\t", + "\t.cpu\t", + "\t.fpid\t", + "\t.equ\t", + "\t.xdef\t", + + "\t.text", + "\t.data", + "\t.bss", + "\t.stack", + "\t.end", + + "\t.even", + "\talign", + +#ifdef OSKDIS + "\tpsect", + "\tvsect", + "\tvsect\tremote", + "\tends", + + "TCALL", + "OS9", +#endif + + ".dc", + + // MPU命令 + {"bra", "bsr", "bhi", "bls", "bcc", "bcs", "bne", "beq", // + "bvc", "bvs", "bpl", "bmi", "bge", "blt", "bgt", "ble"}, + {"dbt", "dbra", "dbhi", "dbls", "dbcc", "dbcs", "dbne", "dbeq", // + "dbvc", "dbvs", "dbpl", "dbmi", "dbge", "dblt", "dbgt", "dble"}, + {"st", "sf", "shi", "sls", "scc", "scs", "sne", "seq", // + "svc", "svs", "spl", "smi", "sge", "slt", "sgt", "sle"}, + { + "trapt", "trapf", "traphi", "trapls", // + "trapcc", "trapcs", "trapne", "trapeq", // + "trapvc", "trapvs", "trappl", "trapmi", // + "trapge", "traplt", "trapgt", "traple", // + }, + + {"btst", "bchg", "bclr", "bset"}, + {"bftst", "bfextu", "bfchg", "bfexts", "bfclr", "bfffo", "bfset", "bfins"}, + {"", "cinvl", "cinvp", "cinva", "", "cpushl", "cpushp", "cpusha"}, + {"pflushn", "pflush", "pflushan", "pflusha"}, + {"plpaw", "plpar"}, + {"ptestw", "ptestr"}, + {"asr", "asl", "lsr", "lsl", "roxr", "roxl", "ror", "rol"}, + {"tblu", "tblun", "tbls", "tblsn"}, + + "dbf", + + "abcd", + "add", + "adda", + "addi", + "addi", + "addq", + "addx", + "and", + "andi", + "andi", + "bgnd", + "bkpt", + "callm", + "cas", + "cas2", + "chk", + "chk2", + "clr", + "cmp", + "cmp2", + "cmpa", + "cmpi", + "cmpi", + "cmpm", + "divs", + "divsl", + "divu", + "divul", + "eor", + "eori", + "exg", + "ext", + "extb", + "illegal", + "jmp", + "jsr", + "lea", + "link", + "lpstop", + "move", + "move16", + "movea", + "movec", + "movem", + "movep", + "moveq", + "moves", + "muls", + "mulsl", + "mulu", + "mulul", + "nbcd", + "neg", + "negx", + "nop", + "not", + "or", + "ori", + "ori", + "pack", + "pea", + "reset", + "rtd", + "rte", + "rtm", + "rtr", + "rts", + "sbcd", + "stop", + "sub", + "suba", + "subi", + "subi", + "subq", + "subx", + "swap", + "tas", + "trap", + "trapv", + "tst", + "unlk", + "unpk", + + // FPU命令 + {"fdbra", "fdbeq", "fdbogt", "fdboge", "fdbolt", "fdbole", + "fdbogl", "fdbor", "fdbun", "fdbueq", "fdbugt", "fdbuge", + "fdbult", "fdbule", "fdbne", "fdbt", "fdbsf", "fdbseq", + "fdbgt", "fdbge", "fdblt", "fdble", "fdbgl", "fdbgle", // + "fdbngle", "fdbngl", "fdbnle", "fdbnlt", "fdbnge", "fdbngt", + "fdbsne", "fdbst"}, + {"ftrapf", "ftrapeq", "ftrapogt", "ftrapoge", "ftrapolt", "ftrapole", + "ftrapogl", "ftrapor", "ftrapun", "ftrapueq", "ftrapugt", "ftrapuge", + "ftrapult", "ftrapule", "ftrapne", "ftrapt", "ftrapsf", "ftrapseq", + "ftrapgt", "ftrapge", "ftraplt", "ftraple", "ftrapgl", "ftrapgle", + "ftrapngle", "ftrapngl", "ftrapnle", "ftrapnlt", "ftrapnge", "ftrapngt", + "ftrapsne", "ftrapst"}, + {"fsf", "fseq", "fsogt", "fsoge", "fsolt", "fsole", + "fsogl", "fsor", "fsun", "fsueq", "fsugt", "fsuge", + "fsult", "fsule", "fsne", "fst", "fssf", "fsseq", + "fsgt", "fsge", "fslt", "fsle", "fsgl", "fsgle", // + "fsngle", "fsngl", "fsnle", "fsnlt", "fsnge", "fsngt", + "fssne", "fsst"}, + {"fbf", "fbeq", "fbogt", "fboge", "fbolt", "fbole", + "fbogl", "fbor", "fbun", "fbueq", "fbugt", "fbuge", + "fbult", "fbule", "fbne", "fbra", "fbsf", "fbseq", + "fbgt", "fbge", "fblt", "fble", "fbgl", "fbgle", // + "fbngle", "fbngl", "fbnle", "fbnlt", "fbnge", "fbngt", + "fbsne", "fbst"}, + + {"fmove", "fint", "fsinh", "fintrz", "fsqrt", "flognp1", + "fetoxm1", "ftanh", "fatan", "fasin", "fatanh", "fsin", + "ftan", "fetox", "ftwotox", "ftentox", "flogn", "flog10", + "flog2", "fabs", "fcosh", "fneg", "facos", "fcos", + "fgetexp", "fgetman", "fdiv", "fmod", "fadd", "fmul", + "fsgldiv", "frem", "fscale", "fsglmul", "fsub", "fsincos", + "fcmp", "ftst", "fsmove", "fssqrt", "fdmove", "fdsqrt", + "fsabs", "fsneg", "fdabs", "fdneg", "fsdiv", "fsadd", + "fsmul", "fddiv", "fdadd", "fdmul", "fssub", "fdsub"}, + + "fdbf", + + "fmovecr", + "fmovem", + "fnop", + "fsave", + "frestore", // + + // MMU命令 + {"pdbbs", "pdbbc", "pdbls", "pdblc", "pdbss", "pdbsc", "pdbas", "pdbac", + "pdbws", "pdbwc", "pdbis", "pdbic", "pdbgs", "pdbgc", "pdbcs", "pdbcc"}, + {"ptrapbs", "ptrapbc", "ptrapls", "ptraplc", // + "ptrapss", "ptrapsc", "ptrapas", "ptrapac", // + "ptrapws", "ptrapwc", "ptrapis", "ptrapic", // + "ptrapgs", "ptrapgc", "ptrapcs", "ptrapcc"}, + {"psbs", "psbc", "psls", "pslc", "psss", "pssc", "psas", "psac", // + "psws", "pswc", "psis", "psic", "psgs", "psgc", "pscs", "pscc"}, + {"pbbs", "pbbc", "pbls", "pblc", "pbss", "pbsc", "pbas", "pbac", // + "pbws", "pbwc", "pbis", "pbic", "pbgs", "pbgc", "pbcs", "pbcc"}, + + {"ploadw", "ploadr"}, + + "pvalid", + "pmove", + "pmovefd", + "pflusha", + "pflushs", + "pflushr", + "psave", + "prestore", // + + // ファンクションコール(マクロ) + "DOS", + "IOCS", + "FPACK", + "SXCALL" // + +}; + +#define OFFS(member) (uint16_t) GET_OPECODE_OFFSET(member) + +typedef struct { + uint16_t to; + uint16_t from; +} ToFrom; + +static void copyMnemonics(OpStringTable* ops, size_t len, const ToFrom* toFrom); + +static void dbraToDbf(OpStringTable* ops) { + static const ToFrom list[] = { + {OFFS(dbcc[COND_F]), OFFS(dbf)}, + {OFFS(fdbcc[FPCOND_F]), OFFS(fdbf)}, + }; + + copyMnemonics(ops, _countof(list), list); +} + +static void abbreviateMnemonic(OpStringTable* ops) { + static const ToFrom list[] = { + {OFFS(adda), OFFS(add)}, // + {OFFS(addiAsAdd), OFFS(add)}, // + {OFFS(andiAsAnd), OFFS(and)}, // + {OFFS(cmpiAsCmp), OFFS(cmp)}, // + {OFFS(cmpm), OFFS(cmp)}, // + {OFFS(movea), OFFS(move)}, // + {OFFS(oriAsOr), OFFS(or)}, // + {OFFS(suba), OFFS(sub)}, // + {OFFS(subiAsSub), OFFS(sub)}, + }; + + copyMnemonics(ops, _countof(list), list); +} + +static void copyMnemonics(OpStringTable* ops, size_t len, + const ToFrom* toFrom) { + size_t i; + + for (i = 0; i < len; ++i) { + char* to = (char*)ops + toFrom[i].to; + char* from = (char*)ops + toFrom[i].from; + strcpy(to, from); + } +} + +static void removeDefaultSize(OpStringTable* ops) { + const size_t tail = strlen(".w\t"); + static const uint16_t list[] = { + OFFS(dc[WORDSIZE]), // + OFFS(dcb[WORDSIZE]), // + OFFS(ds[WORDSIZE]), // + }; + size_t i; + + for (i = 0; i < _countof(list); ++i) { + char* p = (char*)ops + list[i]; + p += strlen(p) - tail; + *p++ = '\t'; + *p++ = '\0'; + *p++ = '\0'; + } +} + +void initOpString(void) { + OpStringTable* ops = &OpString; + + if (Dis.dbraToDbf) dbraToDbf(ops); + if (Dis.mnemonicAbbreviation) abbreviateMnemonic(ops); + if (Dis.N) removeDefaultSize(ops); + + Dis.actions->modifyMnemonic(ops); + + if (Dis.U) toUpperMemory(sizeof(OpStringTable), ops); +} + +// EOF diff --git a/src/opstr.h b/src/opstr.h new file mode 100644 index 0000000..27b2d44 --- /dev/null +++ b/src/opstr.h @@ -0,0 +1,300 @@ +// ソースコードジェネレータ +// オペコード文字列 ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef OPSTR_H +#define OPSTR_H + +#include +#include + +#include "estruct.h" + +// DOSコール、IOCSコール、FEFUNCコール、SXコールのマクロ名(+NUL)の最大長 +#define MAX_MACRO_LEN 16 + +// FPUコンディションコード +// FP Predicateは6ビットだが、定義済みは0~31だけで32~63は未定義 +enum { + FPCOND_F = 0, + FPCOND_T = 15, + FPCOND_NUM = 32, +}; + +// FPU命令(一般命令) +// OpStringTable::fpuType000[] 参照用の通し番号(オペコードとは異なる) +enum { + FPU_T0_FMOVE, + FPU_T0_FINT, + FPU_T0_FSINH, + FPU_T0_FINTRZ, + FPU_T0_FSQRT, + FPU_T0_FLOGNP1, + FPU_T0_FETOXM1, + FPU_T0_FTANH, + FPU_T0_FATAN, + FPU_T0_FASIN, + FPU_T0_FATANH, + FPU_T0_FSIN, + FPU_T0_FTAN, + FPU_T0_FETOX, + FPU_T0_FTWOTOX, + FPU_T0_FTENTOX, + FPU_T0_FLOGN, + FPU_T0_FLOG10, + FPU_T0_FLOG2, + FPU_T0_FABS, + FPU_T0_FCOSH, + FPU_T0_FNEG, + FPU_T0_FACOS, + FPU_T0_FCOS, + FPU_T0_FGETEXP, + FPU_T0_FGETMAN, + FPU_T0_FDIV, + FPU_T0_FMOD, + FPU_T0_FADD, + FPU_T0_FMUL, + FPU_T0_FSGLDIV, + FPU_T0_FREM, + FPU_T0_FSCALE, + FPU_T0_FSGLMUL, + FPU_T0_FSUB, + FPU_T0_FSINCOS, + FPU_T0_FCMP, + FPU_T0_FTST, + FPU_T0_FSMOVE, + FPU_T0_FSSQRT, + FPU_T0_FDMOVE, + FPU_T0_FDSQRT, + FPU_T0_FSABS, + FPU_T0_FSNEG, + FPU_T0_FDABS, + FPU_T0_FDNEG, + FPU_T0_FSDIV, + FPU_T0_FSADD, + FPU_T0_FSMUL, + FPU_T0_FDDIV, + FPU_T0_FDADD, + FPU_T0_FDMUL, + FPU_T0_FSSUB, + FPU_T0_FDSUB, + FPU_T0_NUM +}; + +typedef struct { + // 疑似命令 + char dc[PACKEDSIZE + 1][8]; + char dcb[PACKEDSIZE + 1][12]; + char ds[PACKEDSIZE + 1][8]; + + char include_[12]; + char cpu[8]; + char fpid[8]; + char equ[8]; + char xdef[8]; + + char text[8]; + char data[8]; + char bss[6]; + char stack[8]; + char end[6]; + + char even[8]; + char r68Align[8]; + +#ifdef OSKDIS + char psect[8]; + char vsect[8]; + char vsect_remote[14]; + char ends[6]; + + char tcall[6]; + char os9[4]; +#endif + + char dcWord[4]; // タブ、サイズなし + + // MPU命令 + char bcc[16][4]; + char dbcc[16][8]; + char scc[16][4]; + char trapcc[16][8]; + + char bit[4][8]; + char bitfield[8][8]; + char cache[8][8]; + char pflush[4][10]; + char plpa[2][8]; + char ptest[2][8]; + char shift[8][8]; + char tbl[4][8]; + + char dbf[4]; + + char abcd[6]; + char add[4]; + char adda[6]; + char addi[6]; + char addiAsAdd[6]; + char addq[6]; + char addx[6]; + char and[4]; + char andi[6]; + char andiAsAnd[6]; + char bgnd[6]; + char bkpt[6]; + char callm[6]; + char cas[4]; + char cas2[6]; + char chk[4]; + char chk2[6]; + char clr[4]; + char cmp[4]; + char cmp2[6]; + char cmpa[6]; + char cmpi[6]; + char cmpiAsCmp[6]; + char cmpm[6]; + char divs[6]; + char divsl[6]; + char divu[6]; + char divul[6]; + char eor[4]; + char eori[6]; + char exg[4]; + char ext[4]; + char extb[6]; + char illegal[8]; + char jmp[4]; + char jsr[4]; + char lea[4]; + char link[6]; + char lpstop[8]; + char move[6]; + char move16[8]; + char movea[6]; + char movec[6]; + char movem[6]; + char movep[6]; + char moveq[6]; + char moves[6]; + char muls[6]; + char mulsl[6]; + char mulu[6]; + char mulul[6]; + char nbcd[6]; + char neg[4]; + char negx[6]; + char nop[4]; + char not [4]; + char or [4]; + char ori[4]; + char oriAsOr[4]; + char pack[6]; + char pea[4]; + char reset[6]; + char rtd[4]; + char rte[4]; + char rtm[4]; + char rtr[4]; + char rts[4]; + char sbcd[6]; + char stop[6]; + char sub[4]; + char suba[6]; + char subi[6]; + char subiAsSub[6]; + char subq[6]; + char subx[6]; + char swap[6]; + char tas[4]; + char trap[6]; + char trapv[6]; + char tst[4]; + char unlk[6]; + char unpk[6]; + + // FPU命令 + char fdbcc[FPCOND_NUM][8]; + char ftrapcc[FPCOND_NUM][10]; + char fscc[FPCOND_NUM][8]; + char fbcc[FPCOND_NUM][8]; + + char fpuType000[FPU_T0_NUM][8]; + + char fdbf[6]; + + char fmovecr[8]; + char fmovem[8]; + char fnop[6]; + char fsave[6]; + char frestore[10]; + + // MMU命令 + char pdbcc[16][8]; + char ptrapcc[16][8]; + char pscc[16][8]; + char pbcc[16][8]; + + char pload[2][8]; + + char pvalid[8]; + char pmove[8]; + char pmovefd[8]; + char pflusha[8]; + char pflushs[8]; + char pflushr[8]; + char psave[8]; + char prestore[12]; + + // ファンクションコール(マクロ) + char doscall[MAX_MACRO_LEN]; + char iocscall[MAX_MACRO_LEN]; + char fefunc[MAX_MACRO_LEN]; + char sxcall[MAX_MACRO_LEN]; + +} OpStringTable; + +extern OpStringTable OpString; + +extern void initOpString(void); + +// オペコード文字列をセットする +// disasm* code が宣言されているスコープで使用すること。 +#define OPECODE(member) \ + do { \ + code->opecodeOffset = (WORD)offsetof(OpStringTable, member); \ + } while (0) + +// オペコード文字列をセットする(cond ? m1 : m2) +// cond が真の場合は m1 を、偽の場合は m2 をセットする。 +#define OPECODE2(cond, m1, m2) \ + do { \ + code->opecodeOffset = (WORD)((cond) ? offsetof(OpStringTable, m1) \ + : offsetof(OpStringTable, m2)); \ + } while (0) + +// オペコード文字列を取得する +#define GET_OPECODE(code) ((char *)&OpString + (code)->opecodeOffset) + +// オペコード文字列のオフセット値を取得する +#define GET_OPECODE_OFFSET(member) offsetof(OpStringTable, member) + +#endif + +// EOF diff --git a/src/option.c b/src/option.c index 0ce17a4..94ff2a8 100644 --- a/src/option.c +++ b/src/option.c @@ -1,727 +1,920 @@ -/* $Id: option.c,v 1.1 1996/11/07 08:03:54 ryo freeze $ - * - * ソースコードジェネレータ - * Option analyze , etc - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// Option analyze , etc +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik +#include #include #include #include -#include #ifdef __LIBC__ #include +static char* toslash(char* s) { return _toslash(s); } #else -#define _toslash(p) (p) +static char* toslash(char* s) { return s; } #endif -#include "analyze.h" /* Arg_after_call */ #include "disasm.h" #include "estruct.h" -#include "etc.h" /* strupr */ -#include "fpconv.h" /* Inreal_flag */ +#include "etc.h" #include "generate.h" #include "getopt.h" #include "global.h" #include "hex.h" -#include "include.h" /* xxx_mac */ #include "option.h" -#include "output.h" /* Output_AddressCommentLine, Output_SplitByte */ -#include "symbol.h" /* Output_Symbol */ +#include "output.h" +#include "version.h" + +#define TO_STRING(n) #n +#define S(n) TO_STRING(n) + +#define DETERMINISTIC "deterministic" + +// -Q、--deterministic の状態 +enum { + HEAD_OPT_UNSPECIFIED = 0, + HEAD_OPT_ENGAGED, + HEAD_OPT_ENABLED, +}; + +// static 関数プロトタイプ +static void option_switch(int opt); +static void initFpuOption(void); +static char* dupAndToslash(const char* s); +static int ck_atoi(const char* s); +static int getOptionInt(const char* s, int min, int max, int optionChar); +static int getOptionInt0(const char* s, int max, int optionChar); +static int getLongOptionInt0(const char* s, int max, const char* optionName); +static NORETURN void usage(void) GCC_NORETURN; +static void printTitle(void); + +static void validateProcessorOption(void) { + mputypes mpu = Dis.mpu; + + if ((Dis.mmu & MMU851) && !(mpu & M020)) + err("-m68851 には -m68020 が必要です。\n"); + + if ((Dis.fpu & F88x) && !(mpu & (M020 | M030))) + err("-m6888x は -m68020/68030 が必要です。\n"); + + if (mpu & (M040 | M060)) { + if (Dis.fpuidTable[CPID_CACHE_MMU]) + err("-m6888x,%d と -m68040/68060 は併用できません。\n", CPID_CACHE_MMU); + + if (Dis.fpuidTable[CPID_MOVE16]) + err("-m6888x,%d と -m68040/68060 は併用できません。\n", CPID_MOVE16); + } + + if ((mpu & M060) || Dis.cpu32) { + if (Dis.fpuidTable[CPID_CPU32]) + err("-m6888x,4 と -m68060/cpu32 は併用できません。\n"); + } +} +// 環境変数に設定されたオプションを解析する +static void analyzeEnvOption(char* argv0, const char* optionList) { + char *envs, *envp; // envs=固定, envp=作業用 + char **args, **argp; // args=固定, argp=作業用 + int count, cnt; + int c; + + char* s = getenv(ENV_DIS_OPT); + if (s == NULL) s = getenv(ENV_dis_opt); + if (s == NULL) return; + + Dis.dis_opt = s; + + // 引数をスペースで分割する + while (*s == ' ') s++; + envp = envs = Malloc(strlen(s) + 1); + for (count = 1; *s; count++) { + while (*s && (*s != ' ')) *envp++ = *s++; + *envp++ = '\0'; + while (*s == ' ') s++; + } + + // 各引数へのポインタ配列を作る + argp = args = Malloc((count + 1) * sizeof(char*)); + envp = envs; + *argp++ = argv0; // 自分自身のプログラム名 + for (cnt = count; --cnt;) { + *argp++ = envp; + while (*envp++) + ; + } + *argp = NULL; + + // オプション解析 + // optind = -1; + while ((c = dis_getopt(count, args, optionList)) != EOF) option_switch(c); + + // 忘れずに解放 + Mfree(args); + Mfree(envs); +} -boolean option_a, option_c, option_d, option_e, option_g, option_h, - option_i, option_k, option_l, option_p, option_q, option_r, - option_v, option_x, option_y, option_z, option_B, - option_D, option_E, option_I, option_M, option_N, /* option_Q, */ - option_S, option_T, option_U, option_Y, option_Z; +// コマンドラインのオプションを解析する +static void analyzeCmdOption(int argc, char* argv[], const char* optionList) { + int fileind; + int c; + + optind = -1; + while ((c = dis_getopt(argc, argv, optionList)) != EOF) option_switch(c); + fileind = optind; + + while (fileind < argc) { + char* f = argv[fileind++]; + + if (Dis.execFile == NULL) + Dis.execFile = f; + else if (Dis.outputFile == NULL) + Dis.outputFile = f; + else + err("ファイル名が多すぎます。\n"); + } +} -boolean option_overwrite; +// コマンドラインの先頭にのみ指定できるオプションを仮解釈する +static void analyzeHeadOption(int argc, char* argv[]) { + char* s = (argc >= 2) ? argv[1] : NULL; + if (s == NULL) return; + if (s[0] == '-') { + if (s[1] == 'Q') Dis.Q = HEAD_OPT_ENGAGED; + if (strcmp(s, "--" DETERMINISTIC) == 0) { + Dis.deterministic = HEAD_OPT_ENGAGED; + Dis.Q = HEAD_OPT_ENABLED; + } + } +} -/* main.c */ -extern void print_title (void); +/* -extern short Emulate_mode; /* bit0=1:fpsp bit1=1:isp emulation命令を認識する */ -extern int String_length_min; -extern char CommentChar; -extern address Base, Exec; -extern int Verbose; -extern int Quiet_mode; -#ifndef OSKDIS -extern char FileType; -#endif + オプションを解析する -extern char* Filename_in; -extern char* Filename_out; -extern char* Labelfilename_in; -extern char* Labelfilename_out; -extern char* Tablefilename; +*/ +void analyze_args(int argc, char* argv[]) { + static const char optionlist[] = + "a::b:cde::fg::hijklm:n:o:pq::rs::u::vw:xyz:" + "ABC::DEFGIK:L:MNP:QR:S::T::UV:W:XYZ::#:-:"; + + analyzeHeadOption(argc, argv); + + if (Dis.Q == HEAD_OPT_UNSPECIFIED) { + analyzeEnvOption(argv[0], optionlist); + } + analyzeCmdOption(argc, argv, optionlist); + + if ((Dis.execFile == NULL) || (*Dis.execFile == '\0')) { + printTitle(); + err("処理対象の実行ファイル名が指定されていません。\n" + "--help オプションで使用法を表示します。\n"); + } + if ((Dis.outputFile == NULL) || (*Dis.outputFile == '\0')) + Dis.outputFile = "-"; + + validateProcessorOption(); + + if (Dis.isp && (Dis.mpu & M060)) Dis.mpu |= MISP; + + if (Dis.fpsp) { + fputypes fpu = Dis.fpu; + if (fpu & F040) fpu |= F4SP; + if (fpu & F060) fpu |= F6SP; + Dis.fpu = fpu; + } + + // -x指定時は-aのタブ位置を右にずらす + if (Dis.x) Dis.Atab += 2; + + // テーブルファイル読み込み時はラベルファイルも自動的に読み込む + if (Dis.T) Dis.g = TRUE; + + /* ラベルファイル/テーブルファイル名を作成する */ + { + char* file = strcmp("-", Dis.outputFile) ? Dis.outputFile : "aout"; + char* buf = dupAndToslash(file); + size_t len; + { + char* p = strrchr(buf, '/'); + p = p ? (p + 1) : buf; + p = strrchr((*p == '.') ? (p + 1) : p, '.'); + if (p) *p = '\0'; /* 拡張子を削除する */ + } + len = strlen(buf) + 4 + 1; -/* static 関数プロトタイプ */ -private void option_switch (int, char**); + if (Dis.g && Dis.inputLabelFile == NULL) { + Dis.inputLabelFile = Malloc(len); + strcat(strcpy(Dis.inputLabelFile, buf), ".lab"); + } + if (Dis.e && Dis.outputLabelFile == NULL) { + Dis.outputLabelFile = Malloc(len); + strcat(strcpy(Dis.outputLabelFile, buf), ".lab"); + } + if (Dis.T && Dis.tableFile == NULL) { + Dis.tableFile = Malloc(len); + strcat(strcpy(Dis.tableFile, buf), ".tab"); + } + Mfree(buf); + } +} +static void analyzeOption_a(const char* s) { + Dis.addressCommentLine = (s ? ck_atoi(s) : 5); +} -/* +static void analyzeOption_b(const char* s, int optionChar) { + Dis.branchSize = getOptionInt0(s, BRANCH_SIZE_NOT_OMIT, optionChar); +} - オプションを解析する +enum { + MPUOPT_MPU, + MPUOPT_CPU32, + MPUOPT_FPU, + MPUOPT_MMU, +}; + +typedef struct { + char s[6]; + uint8_t type; + uint8_t mpu; + uint8_t fpu; + uint8_t mmu; +} MpuOption; + +static const MpuOption mpuOptions[] = { + {"68000", MPUOPT_MPU, M000, 0, 0}, + {"68008", MPUOPT_MPU, M000, 0, 0}, + {"68010", MPUOPT_MPU, M010, 0, 0}, + {"68020", MPUOPT_MPU, M020, 0, 0}, + {"68030", MPUOPT_MPU, M030, 0, MMU030}, + {"68040", MPUOPT_MPU, M040, F040, MMU040}, + {"68060", MPUOPT_MPU, M060, F060, MMU060}, + {"680x0", MPUOPT_MPU, M000 | M010 | M020 | M030 | M040 | M060, F040 | F060, + MMU030 | MMU040 | MMU060}, + {"cpu32", MPUOPT_CPU32, 0, 0, 0}, + {"68881", MPUOPT_FPU, 0, F881, 0}, + {"68882", MPUOPT_FPU, 0, F882, 0}, + {"68851", MPUOPT_MMU, 0, 0, MMU851}, +}; + +static const MpuOption* getMpuOption(const char* s, const char** nextptr) { + size_t count = _countof(mpuOptions); + size_t i; + + *nextptr = NULL; + + for (i = 0; i < count; ++i) { + const MpuOption* mo = &mpuOptions[i]; + size_t len = strlen(mo->s); + char c; + + if (strncmp(s, mo->s, len) != 0) continue; + c = s[len]; + if (c != '\0' && c != ',') continue; + + if (c != '\0') *nextptr = &s[len + 1]; + return mo; + } + + return NULL; +} -*/ -extern void -analyze_args (int argc, char* argv[]) -{ - int fileind; - char* envptr; - - static const char optionlist[] = - "a::b:cde::fg::hijklm:n:o:pq::rs::u::vw:xyz:" - "ABC::DEFGIK:L:MNP:QR:S::T::UV:W:XYZ::#:-:"; - -#ifdef READ_FEFUNC_H - fefunc_mac = "fefunc.h"; -#endif +// -m オプション +// -m68000 等は以前の -m の指定を消去するので、複数指定する場合は +// -m68000,68020 のように ',' で繋げる。 +// -mcpu32 -m6888x -m68851 は消去せず追加の指定として扱う。 +// -m6888x[,id] は他の指定を繋げることができない。 +static void analyzeOption_m(const char* s) { + boolean init = TRUE; + + do { + const char* next = NULL; + const MpuOption* mo = getMpuOption(s, &next); + + if (mo == NULL) { + err("対応していない MPU または FPU です(-m)。\n"); + return; + } + s = next; // ','の次 - /* process environment variable `dis_opt' */ - if (/* option_Q == FALSE && */ (envptr = getenv (DIS_ENVNAME))) { - int c; - int count, cnt; - char *envs, *envp; /* envs=固定, envp=作業用 */ - char **args, **argp; /* args=固定, argp=作業用 */ - - /* 引数をスペースで分割する */ - while (*envptr == ' ') - envptr++; - envp = envs = Malloc (strlen (envptr) + 1); - for (count = 1; *envptr; count++) { - while (*envptr && (*envptr != ' ')) - *envp++ = *envptr++; - *envp++ = '\0'; - while (*envptr == ' ') - envptr++; - } - - /* 各引数へのポインタ配列を作る */ - argp = args = Malloc ((count + 1) * sizeof (char*)); - envp = envs; - *argp++ = argv[0]; /* my name */ - for (cnt = count; --cnt;) { - *argp++ = envp; - while (*envp++) - ; - } - *argp = NULL; - - /* オプション解析 */ - /* optind = -1; */ - while ((c = dis_getopt (count, args, optionlist)) != EOF) - option_switch (c, args); - - /* 忘れずに解放 */ - Mfree (args); - Mfree (envs); + if (mo->type == MPUOPT_CPU32) { + Dis.cpu32 = TRUE; + continue; } - /* process commandline variable */ - { - int c; - optind = -1; - while ((c = dis_getopt (argc, argv, optionlist)) != EOF) - option_switch (c, argv); - fileind = optind; + if (mo->type == MPUOPT_MPU && init) { + init = FALSE; + Dis.mpu = 0; + Dis.mmu = 0; + initFpuOption(); } + Dis.mpu |= mo->mpu; + Dis.fpu |= mo->fpu; + Dis.mmu |= mo->mmu; + if (mo->fpu & (F040 | F060)) Dis.fpuidTable[CPID_FPU] = 1; + // -m6888x の場合だけ、','の次はコプロセッサID + if (mo->type == MPUOPT_FPU) { + int fpuid = s ? ck_atoi(s) : CPID_FPU; - while (fileind < argc) { - if (Filename_in == NULL) - Filename_in = argv[fileind++]; - else if (Filename_out == NULL) - Filename_out = argv[fileind++]; - else - err ("ファイル名が多すぎます.\n"); + // 6888x を外付けできる 68020/68030 では id=0 は MMU なので指定できない + if (fpuid <= CPID_MMU || 7 < fpuid) err("FPU IDが範囲外の値です(-m)。\n"); + + Dis.fpuidTable[fpuid] = 1; + return; } - if ((Filename_in == NULL) || (*Filename_in == (char)'\0')) - usage (1); - if ((Filename_out == NULL) || (*Filename_out == (char)'\0')) - Filename_out = "-"; + } while (s && s[0] != '\0'); +} +static void analyzeOption_o(const char* s, int optionChar) { + Dis.stringWidth = + getOptionInt(s, STRING_WIDTH_MIN, STRING_WIDTH_MAX, optionChar); +} - if ((MMU_type & MMU851) && !(MPU_types & M020)) - err ("-m68851 は -m68020 としか併用できません.\n"); +static void analyzeOption_q(const char* s, int optionChar) { + Dis.q = TRUE; + + if (s) { + Dis.quietTable = getOptionInt0(s, 1, optionChar); + } +} - if ((FPCP_type & F88x) && !(MPU_types & (M020|M030))) - err ("-m6888x は -m68020/68030 としか併用できません.\n"); +static void analyzeOption_s(const char* s, int optionChar) { + Dis.outputSymbol = getOptionInt0(s, OUTPUT_SYMBOL_ALL, optionChar); +} - if ((Emulate_mode & 2) && (MPU_types & M060)) - MPU_types |= MISP; +static void analyzeOption_u(const char* s) { + Dis.acceptUnusedTrap = TRUE; + if (s && (ck_atoi(s) == 1)) Dis.sxWindow = TRUE; +} - if (Emulate_mode & 1) { - short tmp = FPCP_type; - if (tmp & F040) tmp |= F4SP; - if (tmp & F060) tmp |= F6SP; - FPCP_type = tmp; - } +static void analyzeOption_w(const char* s, int optionChar) { + Dis.dataWidth = getOptionInt(s, DATA_WIDTH_MIN, DATA_WIDTH_MAX, optionChar); +} +static void analyzeOption_z(const char* s) { + char* comma = strchr(s, ','); + address base = (address)atox(s); + address exec = comma ? (address)atox(comma + 1) : base; - /* if invoked with -T , labelfile must be read */ - if (option_T) - option_g = TRUE; + if (exec < base) + err("ベースアドレスより小さい実行アドレスは指定できません(-z)。\n"); + if (isOdd(base | exec)) err("奇数アドレスは指定できません(-z)。\n"); + Dis.fileType = FILETYPE_DUMP; + Dis.base = base; + Dis.exec = exec; +} - /* ラベルファイル/テーブルファイル名を作成する */ - { - char* file = strcmp ("-", Filename_out) ? Filename_out : "aout"; - char* buf = Malloc (strlen (file) + 1); - size_t len; - - _toslash (strcpy (buf, file)); - - { - char* p = strrchr (buf, '/'); - p = p ? (p + 1) : buf; - p = strrchr ((*p == (char)'.') ? (p + 1) : p, '.'); - if (p) - *p = '\0'; /* 拡張子を削除する */ - } - len = strlen (buf) + 4 + 1; - - if (option_g && Labelfilename_in == NULL) { - Labelfilename_in = Malloc (len); - strcat (strcpy (Labelfilename_in, buf), ".lab"); - } - if (option_e && Labelfilename_out == NULL) { - Labelfilename_out = Malloc (len); - strcat (strcpy (Labelfilename_out, buf), ".lab"); - } - if (option_T && Tablefilename == NULL) { - Tablefilename = Malloc (len); - strcat (strcpy (Tablefilename, buf), ".tab"); - } - - Mfree (buf); - } +static void analyzeOption_C(const char* s, int optionChar) { + Dis.symbolColonNum = getOptionInt0(s, SYMBOL_COLON_TWO, optionChar); } +static void analyzeOption_K(const char* s) { + uint8_t c = s[0]; + if (!c || s[1]) err("コメントキャラクタは一文字しか指定出来ません(-K)。\n"); -private int -ck_atoi (char* str) -{ - unsigned char c; - unsigned char* ptr = (unsigned char*) str; + Dis.commentStr[0] = c; +} - while ((c = *ptr++) != '\0') { - if ((c < '0') || ('9' < c)) - err ("数値の指定が異常です.\n"); - } +static void analyzeOption_L(const char* s) { + uint8_t c = s[0]; + if (!c || s[1]) err("ラベルの先頭文字は一文字しか指定出来ません(-L)。\n"); + if (!isdigit(c)) err("ラベルの先頭文字に数字は使えません(-L)。\n"); + + Dis.labelChar = c; +} + +static void analyzeOption_P(const char* s, int optionChar) { + int n = getOptionInt0(s, 3, optionChar); - return atoi (str); + Dis.fpsp = (n & 1) ? TRUE : FALSE; + Dis.isp = (n & 2) ? TRUE : FALSE; } +static void analyzeOption_R(const char* s, int optionChar) { + int n = getOptionInt0(s, 0x0f, optionChar); -private void -init_fpuid_table (void) -{ - memset (FPUID_table, 0, sizeof FPUID_table); + Dis.undefReg = (n & 1) ? TRUE : FALSE; + Dis.undefExReg = (n & 2) ? TRUE : FALSE; + Dis.undefExScale = (n & 4) ? TRUE : FALSE; + Dis.undefExSize = (n & 8) ? TRUE : FALSE; } +static void analyzeOption_S(const char* s) { + Dis.outputSplitByte = (s ? ck_atoi(s) : 64) * 1024; +} + +static void analyzeOption_V(const char* s, int optionChar) { + Dis.backtrackReason = getOptionInt0(s, BACKTRACK_REASON_ALL, optionChar); +} -private const char** -include_option (char* p) -{ - char eq; +static void analyzeOption_Z(const char* s, int optionChar) { + Dis.suppressDollar = getOptionInt0(s, 1, optionChar); + Dis.Z = TRUE; +} - if (strncmp (p, "exclude-", 8) != 0 && - strncmp (p, "include-", 8) != 0) - return NULL; +static void analyzeOption_deterministic(const char* optionName) { + DisVars* d = &Dis; - eq = (*p == (char)'e') ? '\0' : '='; - p += 8; + if (Dis.deterministic != HEAD_OPT_ENGAGED) + err("--%s はコマンドラインの先頭に指定する必要があります。\n", optionName); - if (strncmp (p, "doscall-mac", 11) == 0 && p[11] == eq) - return &doscall_mac; - if (strncmp (p,"iocscall-mac", 12) == 0 && p[12] == eq) - return &iocscall_mac; - if (strncmp (p, "fefunc-mac", 10) == 0 && p[10] == eq) - return &fefunc_mac; + d->deterministic = HEAD_OPT_ENABLED; + d->h = TRUE; + d->q = TRUE; + d->N = TRUE; + d->Z = TRUE; + d->suppressDollar = 1; + d->a7ToSp = TRUE; + d->stripIncludePath = TRUE; +} - return NULL; +static void analyzeOption_reltblZero(const char* s, const char* optionName) { + Dis.reltblZero = getLongOptionInt0(s, RELTBL_ZERO_ALL, optionName); } -private const char* -include_filename (char* p) -{ - size_t len; +enum { + LONGOPT_VERSION, + LONGOPT_HELP, + LONGOPT_OVERWRITE, + LONGOPT_FPSP, + LONGOPT_ISP, + LONGOPT_NO_FPU, + LONGOPT_NO_MMU, + LONGOPT_SP, + LONGOPT_OLD_SYNTAX, + LONGOPT_INREAL, + LONGOPT_HEADER, + LONGOPT_DOSCALL_MAC, + LONGOPT_IOCSCALL_MAC, + LONGOPT_FEFUNC_MAC, + LONGOPT_STRIP_PATH, + LONGOPT_DETERMINISTIC, + LONGOPT_RELTBL_ZERO, + LONGOPT_FILETYPE, +}; + +typedef struct { + char s[22]; + uint8_t type; + uint8_t hasParam; // --header= など、引数を持つオプション + int val; // --fpsp(TRUE)、--no-fpsp(FALSE) など、コード共用のための値 +} LongOption; + +static const LongOption longOptions[] = { + {"version", LONGOPT_VERSION, FALSE, 0}, + {"help", LONGOPT_HELP, FALSE, 0}, // + {"overwrite", LONGOPT_OVERWRITE, FALSE, 0}, + {"fpsp", LONGOPT_FPSP, FALSE, TRUE}, + {"no-fpsp", LONGOPT_FPSP, FALSE, FALSE}, + {"isp", LONGOPT_ISP, FALSE, TRUE}, // + {"no-isp", LONGOPT_ISP, FALSE, FALSE}, + {"no-fpu", LONGOPT_NO_FPU, FALSE, 0}, // + {"no-mmu", LONGOPT_NO_MMU, FALSE, 0}, // + {"sp", LONGOPT_SP, FALSE, TRUE}, // + {"a7", LONGOPT_SP, FALSE, FALSE}, + {"old-syntax", LONGOPT_OLD_SYNTAX, FALSE, TRUE}, + {"new-syntax", LONGOPT_OLD_SYNTAX, FALSE, FALSE}, + {"inreal", LONGOPT_INREAL, FALSE, TRUE}, + {"real", LONGOPT_INREAL, FALSE, FALSE}, + {"header", LONGOPT_HEADER, TRUE, 0}, // + {"include-doscall-mac", LONGOPT_DOSCALL_MAC, TRUE, 0}, + {"exclude-doscall-mac", LONGOPT_DOSCALL_MAC, FALSE, 0}, + {"include-iocscall-mac", LONGOPT_IOCSCALL_MAC, TRUE, 0}, + {"exclude-iocscall-mac", LONGOPT_IOCSCALL_MAC, FALSE, 0}, + {"include-fefunc-mac", LONGOPT_FEFUNC_MAC, TRUE, 0}, + {"exclude-fefunc-mac", LONGOPT_FEFUNC_MAC, FALSE, 0}, + {"strip-include-path", LONGOPT_STRIP_PATH, FALSE, 0}, + {DETERMINISTIC, LONGOPT_DETERMINISTIC, FALSE, 0}, + {"reltbl-zero", LONGOPT_RELTBL_ZERO, TRUE, 0}, + {"x", LONGOPT_FILETYPE, FALSE, FILETYPE_X}, + {"r", LONGOPT_FILETYPE, FALSE, FILETYPE_R}, + {"z", LONGOPT_FILETYPE, FALSE, FILETYPE_Z}, +}; + +static const LongOption* getLongOption(const char* s, const char** paramptr) { + size_t count = _countof(longOptions); + size_t i; + + *paramptr = NULL; + + for (i = 0; i < count; ++i) { + const LongOption* lo = &longOptions[i]; + + if (lo->hasParam) { + size_t len = strlen(lo->s); + char c; + + if (strncmp(s, lo->s, len) != 0) continue; + c = s[len]; + if (c != '\0' && c != '=') continue; + + if (c != '\0') *paramptr = &s[len + 1]; + return lo; + } else { + if (strcmp(s, lo->s) == 0) return lo; + } + } + + return NULL; +} - if (*p == (char)'e') - return NULL; +static boolean analyzeLongOption(const char* s) { + const char* param = NULL; + const LongOption* lo = getLongOption(s, ¶m); + + if (lo == NULL) return FALSE; + + switch (lo->type) { + case LONGOPT_VERSION: + puts(ProgramAndVersion); + exit(EXIT_SUCCESS); + break; + case LONGOPT_HELP: + usage(); + break; + case LONGOPT_OVERWRITE: + Dis.overwrite = TRUE; + break; + case LONGOPT_FPSP: + Dis.fpsp = lo->val; + break; + case LONGOPT_ISP: + Dis.isp = lo->val; + break; + case LONGOPT_NO_FPU: + initFpuOption(); + break; + case LONGOPT_NO_MMU: + Dis.mmu = 0; + break; + case LONGOPT_SP: + Dis.a7ToSp = lo->val; + break; + case LONGOPT_OLD_SYNTAX: + Dis.oldSyntax = lo->val; + break; + case LONGOPT_INREAL: + Dis.inreal = lo->val; + break; + case LONGOPT_HEADER: + Dis.headerFile = dupAndToslash(param); + break; + case LONGOPT_DOSCALL_MAC: + Dis.doscallMac = dupAndToslash(param); + break; + case LONGOPT_IOCSCALL_MAC: + Dis.iocscallMac = dupAndToslash(param); + break; + case LONGOPT_FEFUNC_MAC: + Dis.fefuncMac = dupAndToslash(param); + break; + case LONGOPT_STRIP_PATH: + Dis.stripIncludePath = TRUE; + break; + case LONGOPT_DETERMINISTIC: + analyzeOption_deterministic(lo->s); + break; + case LONGOPT_RELTBL_ZERO: + analyzeOption_reltblZero(param, lo->s); + break; + case LONGOPT_FILETYPE: + Dis.fileType = lo->val; + Dis.exec = Dis.base = (address)0; + break; + } + return TRUE; +} - while (*p++ != '=') - ; +static char* dupAndToslash(const char* s) { + if (s == NULL) return NULL; - len = strlen (p); - return len ? _toslash (strcpy (Malloc (len + 1), p)) - : NULL; + return toslash(strcpy(Malloc(strlen(s) + 1), s)); } -private void -option_switch (int opt, char** argv) -{ - switch (opt) { +static void initFpuOption(void) { + Dis.fpu = 0; + memset(Dis.fpuidTable, 0, sizeof(Dis.fpuidTable)); +} + +static void option_switch(int opt) { + switch (opt) { case 'a': - option_a = TRUE; - Output_AddressCommentLine = (optarg ? ck_atoi (optarg) : 5); - break; + analyzeOption_a(optarg); + break; case 'b': - Generate_SizeMode = ck_atoi (optarg); - break; + analyzeOption_b(optarg, opt); + break; case 'c': - option_c = TRUE; - break; + Dis.c = TRUE; + break; case 'd': - option_d = TRUE; - break; + Dis.d = TRUE; + break; case 'e': - option_e = TRUE; - if (optarg) - Labelfilename_out = optarg; - break; + Dis.e = TRUE; + if (optarg) Dis.outputLabelFile = optarg; + break; case 'f': - Disasm_Exact = FALSE; - break; + Dis.f = TRUE; + break; case 'g': - option_g = TRUE; - if (optarg) - Labelfilename_in = optarg; - break; + Dis.g = TRUE; + if (optarg) Dis.inputLabelFile = optarg; + break; case 'h': - option_h = TRUE; - break; + Dis.h = TRUE; + break; case 'i': - option_i = TRUE; - break; + Dis.i = TRUE; + break; case 'j': - Disasm_AddressErrorUndefined = FALSE; - break; + Dis.acceptAddressError = TRUE; + break; case 'k': - option_k = TRUE; - break; + Dis.k = TRUE; + break; case 'l': - option_l = TRUE; - break; + Dis.l = TRUE; + break; case 'm': - { - int init = 0; - char* next; -#ifndef __LIBC__ - char* new_optarg = (char*) Malloc (strlen (optarg) + 1); - optarg = strcpy (new_optarg, optarg); -#endif - do { - int m; - - next = strchr (optarg, ','); - if (next) - *next++ = '\0'; - -#ifdef COLDFIRE - if (strcasecmp (optarg, "cf") == 0 - || strcasecmp (optarg, "coldfire") == 0) { - Disasm_ColdFire = TRUE; - continue; - } -#endif - if (strcasecmp (optarg, "cpu32") == 0) { - Disasm_CPU32 = TRUE; - continue; - } - if (strcasecmp (optarg, "680x0") == 0) - m = -1; - else { - m = ck_atoi (optarg); - if (m == 68851) { - MMU_type |= MMU851; - continue; - } else if (m == 68881 || m == 68882) { - int id = next ? ck_atoi (next) : 1; - - FPCP_type |= (m == 68882) ? F882 : F881; - if (id & ~7) - err ("FPU IDの値が異常です(-m).\n"); - FPUID_table[id*2] = 1; - break; - } - } - - /* 680x0, 68000, 68010, ... */ - if (init == 0) { - init = 1; - MPU_types = 0; - FPCP_type = MMU_type = 0; - init_fpuid_table (); - } - switch (m) { - case 68000: - case 68008: - MPU_types |= M000; - break; - case 68010: - MPU_types |= M010; - break; - case 68020: - MPU_types |= M020; - break; - case 68030: - MPU_types |= M030; - MMU_type |= MMU030; - break; - case 68040: - MPU_types |= M040; - FPCP_type |= F040; - MMU_type |= MMU040; - FPUID_table[1*2] = 1; - break; - case 68060: - MPU_types |= M060; - FPCP_type |= F060; - MMU_type |= MMU060; - FPUID_table[1*2] = 1; - break; - case -1: /* -m680x0 */ - MPU_types |= (M000|M010|M020|M030|M040|M060); - FPCP_type |= (F040|F060); - MMU_type |= (MMU030|MMU040|MMU060); - FPUID_table[1*2] = 1; - break; - default: - err ("指定の MPU, FPU はサポートしていません(-m).\n"); - /* NOT REACHED */ - } - } while ((optarg = next) != NULL); -#ifndef __LIBC__ - Mfree (new_optarg); -#endif - } - break; + analyzeOption_m(optarg); + break; case 'n': - String_length_min = ck_atoi (optarg); - break; + Dis.stringLengthMin = ck_atoi(optarg); + break; case 'o': - String_width = ck_atoi (optarg); - if( String_width < 1 || 80 < String_width ) - err ("値が無効な範囲です(-o).\n"); - break; + analyzeOption_o(optarg, opt); + break; case 'p': - option_p = TRUE; - break; + Dis.p = TRUE; + break; case 'q': - option_q = TRUE; - if( optarg ) Quiet_mode = ck_atoi (optarg); - if( Quiet_mode < 0 || 1 < Quiet_mode ) - err ("値が無効な範囲です(-q).\n"); - break; + analyzeOption_q(optarg, opt); + break; case 'r': - option_r = TRUE; - break; + Dis.r = TRUE; + break; case 's': - Output_Symbol = optarg ? ck_atoi (optarg) : 0; - if ((unsigned short)Output_Symbol > 2) - err ("値が無効な範囲です(-s).\n"); - break; + analyzeOption_s(optarg, opt); + break; case 'u': - Disasm_UnusedTrapUndefined = FALSE; - if (optarg && (ck_atoi (optarg) == 1)) - Disasm_SX_Window = TRUE; - break; + analyzeOption_u(optarg); + break; case 'v': - option_v = TRUE; - break; + Dis.v = TRUE; + break; case 'w': - Data_width = ck_atoi (optarg); - if( Data_width < 1 || 32 < Data_width ) - err ("値が無効な範囲です(-w).\n"); - break; + analyzeOption_w(optarg, opt); + break; case 'x': - option_x = TRUE; - break; + Dis.x = TRUE; + break; case 'y': - option_y = TRUE; - break; + Dis.y = TRUE; + break; case 'z': - option_z = TRUE; - Absolute = ABSOLUTE_ZOPT; - FileType = 'r'; - { - char* p; -#ifndef __LIBC__ - char* new_optarg = (char*) Malloc (strlen (optarg) + 1); - optarg = strcpy (new_optarg, optarg); -#endif - p = strchr (optarg, ','); - if (p) { - *p++ = '\0'; - Base = (address) atox (optarg); - Exec = (address) atox (p); - } else - Exec = Base = (address) atox (optarg); -#ifndef __LIBC__ - Mfree (new_optarg); -#endif - } - if (Base > Exec) { - err ("値が無効な範囲です(-z).\n"); - } - break; + analyzeOption_z(optarg); + break; case 'A': - Disasm_MnemonicAbbreviation = TRUE; - break; + Dis.mnemonicAbbreviation = TRUE; + break; case 'B': - option_B = TRUE; - break; + Dis.B = TRUE; + break; case 'C': - SymbolColonNum = optarg ? ck_atoi (optarg) : 0; - if( SymbolColonNum < 0 || 3 < SymbolColonNum ) - err ("値が無効な範囲です(-C).\n"); - break; + analyzeOption_C(optarg, opt); + break; case 'D': - option_D = TRUE; - break; + Dis.D = TRUE; + break; case 'E': - option_E = TRUE; - break; + Dis.E = TRUE; + break; case 'F': - Disasm_Dbra = FALSE; - break; + Dis.dbraToDbf = TRUE; + break; case 'G': - Arg_after_call = TRUE; - break; + Dis.argAfterCall = TRUE; + break; case 'I': - option_I = TRUE; - break; + Dis.I = TRUE; + break; case 'K': - if (!optarg[0] || optarg[1]) - err ("コメントキャラクタは一文字しか指定出来ません(-K).\n"); - CommentChar = *optarg; - break; + analyzeOption_K(optarg); + break; case 'L': - if (!optarg[0] || optarg[1]) - err ("ラベルの先頭文字は一文字しか指定出来ません(-L).\n"); - if ((char)'0' <= *optarg && *optarg <= (char)'9') - err ("ラベルの先頭文字に数字は使えません(-L).\n"); - Label_first_char = *optarg; - break; + analyzeOption_L(optarg); + break; case 'M': - option_M = TRUE; - break; + Dis.M = TRUE; + break; case 'N': - option_N = TRUE; - break; + Dis.N = TRUE; + break; case 'P': - Emulate_mode = ck_atoi (optarg); - if (Emulate_mode & ~0x03) - err ("値が無効な範囲です(-P).\n"); - break; + analyzeOption_P(optarg, opt); + break; case 'Q': - /* option_Q = TRUE; */ - break; + if (Dis.Q != HEAD_OPT_ENGAGED) + err("-Q はコマンドラインの先頭に指定する必要があります。\n"); + Dis.Q = HEAD_OPT_ENABLED; + break; case 'R': - UndefRegLevel = ck_atoi (optarg); - if (UndefRegLevel & ~0x0f) - err ("値が無効な範囲です(-R).\n"); - break; + analyzeOption_R(optarg, opt); + break; case 'S': - option_S = TRUE; - Output_SplitByte = ( optarg ? ck_atoi (optarg) : 64 ) * 1024; - break; + analyzeOption_S(optarg); + break; case 'T': - option_T = TRUE; - if (optarg) - Tablefilename = optarg; - break; + Dis.T = TRUE; + if (optarg) Dis.tableFile = optarg; + break; case 'U': - option_U = TRUE; - strupr (opsize); - /* fall through */ + Dis.U = TRUE; + /* fall through */ case 'X': - strupr (Hex); - break; + toUpperMemory(sizeof(Hex), Hex); + break; case 'V': - Verbose = ck_atoi (optarg); - if( Verbose < 0 || 2 < Verbose ) - err ("値が無効な範囲です(-V).\n"); - break; + analyzeOption_V(optarg, opt); + break; case 'W': - Compress_len = ck_atoi (optarg); - break; + Dis.compressLen = ck_atoi(optarg); + break; case 'Y': - option_Y = TRUE; - break; + Dis.Y = TRUE; + break; case 'Z': - option_Z = TRUE; - Zerosupress_mode = optarg ? ck_atoi(optarg) : 0; - if( Zerosupress_mode < 0 || 1 < Zerosupress_mode ) - err ("値が無効な範囲です(-Z).\n"); - break; + analyzeOption_Z(optarg, opt); + break; case '#': - Debug = ck_atoi (optarg); - break; + // デバッグ表示用オプション + break; case '-': - { -#ifndef OSKDIS - const char** p; - char c = optarg[0]; - if (!optarg[1] && (c == (char)'x' || c == (char)'r' || c == (char)'z')) { - FileType = c; - break; - } -#endif + if (!analyzeLongOption(optarg)) + err("対応していないオプションです: '--%s'\n", optarg); + break; -#define isLONGOPT(str) (strcmp (optarg, str) == 0) - if (isLONGOPT ( "fpsp")) Emulate_mode |= 1; - else if (isLONGOPT ("no-fpsp")) Emulate_mode &= ~1; - else if (isLONGOPT ( "isp")) Emulate_mode |= 2; - else if (isLONGOPT ("no-isp")) Emulate_mode &= ~2; - else if (isLONGOPT ("no-fpu")) { FPCP_type = 0; init_fpuid_table (); } - else if (isLONGOPT ("no-mmu")) MMU_type = 0; - - else if (isLONGOPT ("sp")) sp_a7_flag = TRUE; - else if (isLONGOPT ("a7")) sp_a7_flag = FALSE; - else if (isLONGOPT ("old-syntax")) Old_syntax = TRUE; - else if (isLONGOPT ("new-syntax")) Old_syntax = FALSE; - else if (isLONGOPT ("inreal")) Inreal_flag = TRUE; - else if (isLONGOPT ("real")) Inreal_flag = FALSE; - - else if (isLONGOPT ("overwrite")) option_overwrite = TRUE; - else if (isLONGOPT ("help")) usage (0); - else if (isLONGOPT ("version")) { printf ("dis version %s\n", Version); - exit (0); } -#ifndef OSKDIS - else if (strncmp (optarg, "header=", 7) == 0) - Header_filename = optarg + 7; - else if ((p = include_option (optarg)) != NULL) - *p = include_filename (optarg); -#endif - else - err ("%s: unrecognized option '--%s'\n", argv[0], optarg); - } - break; -/* case '?': */ default: - exit (EXIT_FAILURE); - break; - } - return; -} - - -extern void -usage (int exitcode) -{ - static const char message[] = - "usage: dis [option] 実行ファイル名 [出力ファイル名]\n" - "option:\n" - - /* 小文字オプション */ - " -a[num] num 行ごとにアドレスをコメントで入れる(num を省略すると 5 行ごと)\n" - " -b num 相対分岐命令のサイズの出力(0:自動 1:常に省略 2:常に付ける)\n" - " -c ラベルチェックを行わない\n" - " -d デバイスドライバの時に指定\n" - " -e[file] ラベルファイルの出力\n" - " -f バイト操作命令の不定バイトのチェック($00 or $ff ?)をしない\n" - " -g[file] ラベルファイルを読み込む\n" - " -h データ領域中の $4e75(rts)の次のアドレスに注目する\n" - " -i 分岐先で未定義命令があってもデータ領域と見なさない\n" - " -j アドレスエラーが起こるであろう命令を未定義命令と見なさない\n" - " -k 命令の中を指すラベルはないものと見なす\n" - " -l プログラム領域が見つからなくなるまで何度も捜すことをしない\n" - " -m 680x0[,...] 逆アセンブル対象の MPU を指定(68000-68060,680x0)\n" - " -m 68851 68851 命令を有効にする(-m68020 指定時のみ有効)\n" - " -m 6888x[,ID] 有効な FPCP とその ID を指定(68881/68882 ID=0-7,省略時1)\n" - " -n num 文字列として判定する最小の長さ. 0 なら判定しない(初期値=3)\n" - " -o num 文字列領域の桁数(1≦num≦80 初期値=60)\n" - " -p データ領域中のプログラム領域を判別しない\n" - " -q[num] メッセージを出力しない([0]:通常 1:テーブルに関する情報も出力しない)\n" - " -r 文字列に 16 進数のコメントを付ける\n" - " -s[num] シンボルテーブルの出力([0]:しない 1:[通常] 2:全て)\n" -/* -t */ - " -u[num] 未使用の A,F line trap を未定義命令と見なさない(num=1 SX-Window対応)\n" - " -v 単なる逆アセンブルリストの出力\n" - " -w num データ領域の横バイト数(1≦num≦32 初期値=8)\n" - " -x 実際のオペコードを 16 進数のコメントで付ける\n" - " -y 全てのデータ領域をプログラム領域でないか確かめることをしない\n" - " -z base,exec 実行ファイルを base からのバイナリファイルとみなし、exec から解析する\n" - - /* 大文字オプション */ - "\n" - " -A cmpi, movea 等を cmp, move 等にする\n" - " -B bra の後でも改行する\n" - " -C[num] ラベルの後のコロン(0:付けない 1:全てに1つ [2]:通常 3:全てに2つ)\n" - " -D データセクション中にもプログラムを認める\n" - " -E バイト操作命令の不定バイトの書き換えチェックをしない\n" - " -F dbra,fdbra を dbf,fdbf として出力する\n" - " -G サブルーチンコールの直後に引数を置くプログラムを解析する\n" -/* -H */ - " -I 命令の中を差すラベルのアドレスを表示する\n" -/* -J */ - " -K char char をコメントキャラクタとして用いる\n" - " -L char char をラベル名の先頭文字として用いる\n" - " -M cmpi, move, addi.b, subi.b #imm および pack, unpk にコメントをつける\n" - " -N サイズがデフォルトなら付けない\n" -/* -O */ - " -P num ソフトウェアエミュレーション命令を有効にする(ビット指定, 初期値=3)\n" - " +1 未実装浮動小数点命令を有効にする\n" - " +2 未実装整数命令を有効にする\n" -/* " -Q 環境変数 dis_opt を参照しない\n" */ - " -R num 未使用フィールドのチェック項目の指定(ビット指定, 初期値=15)\n" - " +1 mulu.l, muls.l, ftst.x における未使用レジスタフィールドのチェック\n" - " +2 拡張アドレッシングでのサプレスされたレジスタフィールドのチェック\n" - " +4 サプレスされたインデックスレジスタに対するスケーリングのチェック\n" - " +8 サプレスされたインデックスレジスタに対するサイズ指定(.l)のチェック\n" - " -S[num] 出力ファイルを num KB ごとに分割する(num を省略すると 64KB)\n" - " -T[file] テーブル記述ファイルを読み込む\n" - " -U ニーモニックを大文字で出力する\n" - " -V num バックトラックの原因の表示(0:しない [1]:プログラム領域 2:全ての領域)\n" - " -W num 同一データを .dcb で出力する最小バイト数. 0なら圧縮しない(初期値=64)\n" - " -X 16 進数を大文字で出力する\n" - " -Y カレントディレクトリからも include ファイルを検索する\n" - " -Z[num] 16 進数をゼロサプレスする([0]:通常 1:省略可能な'$'を省略)\n" - - /* 単語名オプション */ - "\n" - -#ifndef OSKDIS - " --include-XXX-mac=file include ファイルの指定(XXX = doscall,iocscall,fefunc)\n" - " --exclude-XXX-mac include ファイルを読み込まない\n" -#endif - " --header=file ヘッダファイルの指定(環境変数 dis_header より優先)\n" - " --(no-)fpsp 未実装浮動小数点命令を[有効](無効)にする\n" - " --(no-)isp 未実装整数命令を[有効](無効)にする\n" - " --no-fpu 内蔵 FPU 命令を無効にする(-m68040~68060 の後に指定)\n" - " --no-mmu 内蔵 MMU 命令を無効にする(-m68030~68060 の後に指定)\n" - " --sp a7 レジスタを'sp'と表記する(標準では --a7)\n" - " --old-syntax アドレッシングを旧表記で出力する(標準では --new-syntax)\n" - " --(in)real 浮動小数点を[実数表記](内部表現)で出力する\n" - " --overwrite ファイルを無条件で上書きする\n" - " --version バージョンを表示する\n" - " --help 使用法を表示する\n" - -#if 0 /* 隠しオプション */ - "\n" -#ifndef OSKDIS - " --x|r|z 実行ファイルを X|R|Z 形式と見なす\n" -#endif - " -# num デバッグモード\n" + errorExit(); + break; + } + return; +} + +static int getIntFromOptarg(const char* s, int min, int max, int oc, + const char* os) { + int n = s ? ck_atoi(s) : 0; + + if (n < min || max < n) err("指定できない値です(-%c%s)。\n", oc, os); + return n; +} + +// オプションの引数を int に変換して返す +// min~max の範囲でなければエラー終了する。 +static int getOptionInt(const char* s, int min, int max, int optionChar) { + return getIntFromOptarg(s, min, max, optionChar, ""); +} + +// オプションの引数を int に変換して返す +// 0~max の範囲でなければエラー終了する。 +static int getOptionInt0(const char* s, int max, int optionChar) { + return getIntFromOptarg(s, 0, max, optionChar, ""); +} + +// ロングオプションの引数を int に変換して返す +// 0~max の範囲でなければエラー終了する。 +static int getLongOptionInt0(const char* s, int max, const char* optionName) { + return getIntFromOptarg(s, 0, max, '-', optionName); +} + +static int ck_atoi(const char* s) { + const char* p = s; + char c; + + while ((c = *p++) != '\0') { + if (!isdigit(c)) err("数値の指定が正しくありません。\n"); + } + + return atoi(s); +} + +static const char usageText[] = + "usage: dis [option] 実行ファイル名 [出力ファイル名]\n" + "\n" + "ファイル入力オプション:\n" + "-d デバイスドライバの時に指定\n" + "-g[file] ラベルファイルを読み込む\n" + "-z base,exec 実行ファイルを base からのバイナリファイルとみなし、exec から解析する\n" + "-T[file] テーブル記述ファイルを読み込む\n" + "-Y インクルードファイルをカレントディレクトリからも検索する\n" + "--include-XXX-mac=file インクルードファイルの指定 (XXX = doscall, iocscall, fefunc)\n" + "--exclude-XXX-mac インクルードファイルを読み込まない\n" + "--header=file ヘッダをファイルから読み込む(環境変数 " ENV_dis_header " より優先)\n" +#ifdef PRINT_HIDDEN_OPTIONS + "--x 実行ファイルを X 形式と見なす\n" + "--r 実行ファイルを R 形式と見なす\n" + "--z 実行ファイルを Z 形式と見なす\n" #endif - ; /* end of message */ - print_title (); - printf (message); - exit (exitcode); + "\n" + "ファイル出力オプション:\n" + "-e[file] ラベルファイルの出力\n" + "-v 単なる逆アセンブルリストの出力\n" + "-S[num] 出力ファイルを num KB ごとに分割する(num を省略すると 64KB)\n" + "--overwrite ファイルを無条件で上書きする\n" + + "\n" + "命令セットオプション:\n" + "-m 680x0[,...] 逆アセンブル対象の MPU を指定(68000-68060, 680x0)\n" + "-m 68851 68851 命令を有効にする(-m68020 指定時のみ有効)\n" + "-m 6888x[,id] 有効な FPCP とその ID を指定(68881/68882, id=[1]-7)\n" + "--no-fpsp 未実装浮動小数点命令を無効にする(--fpsp で取り消し)\n" + "--no-isp 未実装整数命令を無効にする(--isp で取り消し)\n" + "--no-fpu 内蔵 FPU 命令を無効にする(-m68040~68060 の後に指定)\n" + "--no-mmu 内蔵 MMU 命令を無効にする(-m68030~68060 の後に指定)\n" + + "\n" + "解析オプション:\n" + "-c ラベルチェックを行わない\n" + "-f バイト操作命令の不定バイトのチェック($00 or $ff " + "?)をしない\n" + "-h データ領域中の $4e75(rts) の次のアドレスに注目する\n" + "-i 分岐先で未定義命令があってもデータ領域と見なさない\n" + "-j " + "アドレスエラーが起こるであろう命令を未定義命令と見なさない\n" + "-k 命令の中を指すラベルはないものと見なす\n" + "-l " + "プログラム領域が見つからなくなるまで何度も探すことをしない\n" + "-n num " + "文字列として判定する最小の長さ。0なら判定しない(初期値=3)\n" + "-p データ領域中のプログラム領域を判別しない\n" + "-u[num] 未使用の A,F line trap を未定義命令と見なさない(1:SX-Window 対応)\n" + "-y 全てのデータ領域をプログラム領域でないか確かめることをしない\n" + "-D データセクション中にもプログラムを認める\n" + "-E バイト操作命令の不定バイトの書き換えチェックをしない\n" + "-G サブルーチンコールの直後に引数を置くプログラムを解析する\n" + "-R num 未使用フィールドのチェック項目の指定(ビット指定、初期値=15)\n" + " +1 未使用レジスタフィールド(mul[us].l, ftst.x, c{inv,push}a)のチェック\n" + " +2 拡張アドレッシングでのサプレスされたレジスタフィールドのチェック\n" + " +4 サプレスされたインデックスレジスタに対するスケーリングのチェック\n" + " +8 サプレスされたインデックスレジスタに対するサイズ指定(.l)のチェック\n" + "--reltbl-zero=num リラティブオフセットテーブルに0を認める(0:しない 1:[先頭のみ] 2:全域)\n" + + "\n" + "アセンブリ表記オプション:\n" + "-a[num] num 行ごとにアドレスをコメントで入れる(num を省略すると5行ごと)\n" + "-b num 相対分岐命令のサイズの出力(0:自動 1:常に省略 2:常に付ける)\n" + "-o num 文字列領域の桁数(" S(STRING_WIDTH_MIN) "≦num≦" S(STRING_WIDTH_MAX) + " 初期値=" S(STRING_WIDTH_DEFAULT) ")\n" + "-r 文字列に16進数のコメントを付ける\n" + "-s[num] シンボルテーブルの出力([0]:しない 1:[通常] 2:全て)\n" + "-w num データ領域の横バイト数(" S(DATA_WIDTH_MIN) "≦num≦" S(DATA_WIDTH_MAX) + " 初期値=" S(DATA_WIDTH_DEFAULT) ")\n" + "-x 実際のオペコードを16進数のコメントで付ける\n" + "-A cmpi, movea 等を cmp, move 等にする\n" + "-B bra の後でも改行する\n" + "-C[num] ラベルの後のコロン(0:付けない 1:全てに1つ [2]:通常 3:全てに2つ)\n" + "-F dbra, fdbra を dbf, fdbf として出力する\n" + "-K char コメントの先頭文字を char にする(初期値=;)\n" + "-L char ラベル名の先頭文字を char にする(初期値=L)\n" + "-M cmpi, move, addi.b, subi.b #imm および pack, unpk にコメントを付ける\n" + "-N サイズがデフォルトなら付けない\n" + "-U ニーモニックと16進数を大文字で出力する\n" + "-W num 同一データを .dcb で出力する最小バイト数。0なら圧縮しない(初期値=64)\n" + "-X 16進数を大文字で出力する\n" + "-Z[num] 16進数をゼロサプレスする([0]:通常 1:省略可能な'$'を省略)\n" + "--inreal 浮動小数点を実数表記ではなく内部表現で出力する(--real で取り消し)\n" + "--old-syntax アドレッシングを旧表記で出力する(--new-syntax で取り消し)\n" + "--sp a7 レジスタを sp と表記する(--a7 で取り消し)\n" + "--strip-include-path .include にパス名を付けない\n" + + "\n" + "その他:\n" + "-q[num] メッセージを出力しない([0]:通常 1:テーブルに関する情報も出力しない)\n" + "-I 命令の中を差すラベルのアドレスを表示する\n" + "-Q 環境変数 " ENV_DIS_OPT ", " ENV_dis_opt " を参照しない\n" + "-V num バックトラックの原因の表示(0:しない [1]:プログラム領域 2:全ての領域)\n" + "--deterministic 決定論的逆アセンブルを行う\n" + "--help 使用法を表示する\n" + "--version バージョンを表示する\n" + ""; + +static void usage(void) { + printTitle(); + fputs(usageText, stdout); + + exit(EXIT_SUCCESS); } -/* EOF */ +static void printTitle(void) { fputs(Title, stdout); } + +// EOF diff --git a/src/option.h b/src/option.h index 8dae02e..bfc58b0 100644 --- a/src/option.h +++ b/src/option.h @@ -1,21 +1,14 @@ -/* $Id: option.h,v 1.1 1996/10/24 04:27:48 ryo freeze $ - * - * ソースコードジェネレータ - * オプションヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// オプション ヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef OPTION_H -#define OPTION_H +#ifndef OPTION_H +#define OPTION_H +extern void analyze_args(int, char*[]); -extern void analyze_args (int, char*[]); -extern void usage (int); +#endif - -#endif /* OPTION_H */ - -/* EOF */ +// EOF diff --git a/src/osk.c b/src/osk.c new file mode 100644 index 0000000..654c0eb --- /dev/null +++ b/src/osk.c @@ -0,0 +1,754 @@ +// ソースコードジェネレータ +// OS-9/X680x0(OSK) +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#include "osk.h" + +#include // getenv() + +#include "analyze.h" +#include "disasm.h" +#include "estruct.h" +#include "etc.h" +#include "generate.h" +#include "global.h" +#include "hex.h" +#include "include.h" +#include "label.h" +#include "opstr.h" +#include "output.h" +#include "symbol.h" +#include "version.h" + +#ifdef OSKDIS + +// OS-9/X680x0モジュールのヘッダ +enum { + OSKHEAD_ID = 0x00, // UWORD 0x4afc + OSKHEAD_SYSREV = 0x02, // UWORD リビジョンID + OSKHEAD_MODSIZE = 0x04, // ULONG モジュールサイズ + OSKHEAD_OWNER = 0x08, // ULONG オーナID + OSKHEAD_NAME = 0x0c, // address モジュール名オフセット + OSKHEAD_ACCS = 0x10, // UWORD アクセス許可 + OSKHEAD_TYPE = 0x12, // UWORD モジュールタイプ/言語 + OSKHEAD_ATTR = 0x14, // UWORD 属性/リビジョン + OSKHEAD_EDITION = 0x16, // UWORD エディション + OSKHEAD_USAGE = 0x18, // address 使い方コメントのオフセット + OSKHEAD_SYMBOL = 0x1c, // address シンボルテーブル + OSKHEAD_RESV = 0x20, // BYTE[14] 予約済み + OSKHEAD_PARITY = 0x2e, // UWORD ヘッダパリティ + OSKHEAD_EXEC = 0x30, // address 実行オフセット + OSKHEAD_EXCPT = 0x34, // address ユーザトラップエントリ + OSKHEAD_MEM = 0x38, // ULONG メモリサイズ + OSKHEAD_STACK = 0x3c, // ULONG スタックサイズ + OSKHEAD_IDATA = 0x40, // address 初期化データオフセット + OSKHEAD_IREFS = 0x44, // address 初期化参照オフセット + OSKHEAD_INIT = 0x48, // address 初期化実行エントリ(TRAPLIB) + OSKHEAD_TERM = 0x4c, // address 終了実行エントリ(TRAPLIB) + + OSKHEAD_SIZE = 0x50 +}; + +// OS9 ファンクションコールでプログラムを終了させるもの +enum { + F_Exit = 0x0006, // F$Exit + F_RTE = 0x001e, // F$RTE + F_NProc = 0x002d, // F$NProc +}; + +enum { + OSK_BASEREG = 6, +}; + +static lblbuf* idatagen(address end, lblbuf* lptr); +static void vsectbssgen(address pc, address nlabel, lblmode mode); + +static void registerVsectLabelOp(disasm* code, operand* op) { + if (op->ea == AregDISP && op->baseReg == OSK_BASEREG) { + const ULONG offset = 0x8000; + address adrs = Dis.beginBSS + op->opval + offset; + lblbuf* lptr = search_label(adrs); + lblmode wkmode = lptr ? (lptr->mode & (CODEPTR | DATAPTR)) : DATLABEL; + + regist_label(adrs, wkmode | code->size2 | FORCE); + } +} + +// オペランドが(d16,A6)ならvsectとして登録する +static void registerVsectLabel(disasm* code) { + if (Dis.oskModType != OSKTYPE_PROGRAM && Dis.oskModType != OSKTYPE_TRAP) + return; + + registerVsectLabelOp(code, &code->op1); + registerVsectLabelOp(code, &code->op2); + registerVsectLabelOp(code, &code->op3); + registerVsectLabelOp(code, &code->op4); +} + +// ワードテーブルとして登録する +static void w_table(address table) { + address ptr = table; + address tableend = next(table + 1)->label; + + regist_label(table, DATLABEL | WTABLE); + + while (ptr < tableend) { + address label = (WORD)peekw(ptr + Dis.Ofst); + + regist_label(label, DATLABEL | UNKNOWN); + ptr += 2; + tableend = next(ptr)->label; + } +} + +// IDataから初期化データを登録する +static void analyze_idata(void) { + codeptr ptr = Dis.Ofst + (ULONG)Dis.oskIdata; + + regist_label(Dis.oskIdata, DATLABEL | LONGSIZE | FORCE); + Dis.beginDATA = Dis.beginBSS + peekl(ptr + 0); + regist_label(Dis.beginDATA, DATLABEL | UNKNOWN); + regist_label(Dis.beginDATA + peekl(ptr + 4), DATLABEL | UNKNOWN); +} + +static void analyze_irefs_sub(int codelbl, codeptr ptr, ULONG offset, + int mode) { + ULONG value0 = peekl(ptr); + + if (value0 <= offset && offset < (value0 + peekl(ptr + 4))) { + codeptr w = ptr + 8 + offset - value0; + regist_label(peekl(w) + codelbl ? 0 : Dis.beginBSS, mode); + } +} + +typedef struct { + UWORD base; + UWORD cnt; +} RefsTbl; + +// IRefsを解析する +static void analyze_irefs(void) { + const codeptr idatp = Dis.Ofst + (ULONG)Dis.oskIdata; + RefsTbl* offset = (RefsTbl*)(Dis.Ofst + (ULONG)Dis.oskIrefs); + + regist_label(Dis.oskIrefs, DATLABEL | WORDSIZE | FORCE); + + while (offset->cnt) { // コードポインタ + ULONG wk = Dis.beginBSS + ((ULONG)offset->base << 16); + UWORD* p = (UWORD*)&offset[1]; + int i; + + for (i = 0; i < offset->cnt; i++) { + ULONG o = peekw((codeptr)p); + charout('#'); + regist_label(wk + o, DATLABEL | LONGSIZE | CODEPTR | FORCE); + regist_label(wk + o + 4, DATLABEL | UNKNOWN); + analyze_irefs_sub(TRUE, idatp, o, DATLABEL | UNKNOWN); + p++; + } + offset = (RefsTbl*)p; + } + offset++; + while (offset->cnt) { // データポインタ + ULONG wk = Dis.beginBSS + ((ULONG)offset->base << 16); + UWORD* p = (UWORD*)&offset[1]; + int i; + + for (i = 0; i < offset->cnt; i++) { + ULONG o = peekw((codeptr)p); + charout('#'); + regist_label(wk + o, DATLABEL | LONGSIZE | DATAPTR | FORCE); + regist_label(wk + o + 4, DATLABEL | UNKNOWN); + analyze_irefs_sub(FALSE, idatp, o, DATLABEL | UNKNOWN); + p++; + } + offset = (RefsTbl*)p; + } +} + +static void setOskCallLabel(codeptr ptr, disasm* code, operand* op, UWORD word2, + char** labels) { + op->ea = IMMED; + + if (Dis.needString) { + char* label = (labels && (word2 <= 0xff)) ? labels[word2] : NULL; + + if (label) + strcpy(op->operand, label); + else + itox4d(op->operand, word2); + } +} + +// trap命令(ファンクションコール) +static void oskTrap(codeptr ptr, disasm* code) { + UWORD word2 = peekw(ptr + 2); + ULONG n = peekb(ptr + 1) & 15; + + if (n == 0) { + OPECODE(os9); + setOskCallLabel(ptr, code, &code->op1, word2, Dis.OS9label); + + if (word2 == F_Exit || word2 == F_RTE || word2 == F_NProc) + code->opeType = RTSOP; + } else { + char* call = NULL; + char** labels = NULL; + + OPECODE(tcall); + + if (n == 13) { + call = "CIO$Trap"; + labels = Dis.CIOlabel; + } else if (n == 15) { + call = "T$Math"; + labels = Dis.MATHlabel; + } + + code->op1.ea = IMMED; + if (Dis.needString) { + if (call) + strcpy(code->op1.operand, call); + else + itod2(code->op1.operand, n); + } + setOskCallLabel(ptr, code, &code->op2, word2, labels); + } + code->bytes = 4; +} + +// ファイル情報を書き出す +static void outputOskFileInfo(char* filename, time_t filedate, + const char* argv0, char* comline) { + com("============================================="); + com(" Filename %s", filename); + if (!Dis.deterministic) { + com(" Time Stamp %s", ctimez(&filedate)); + } + comBlank(); + com(" %d Labels", get_Labelnum()); + if (!Dis.deterministic) { + time_t t = time(NULL); + com(" Code Generate date %s", ctimez(&t)); + } + if (Dis.dis_opt != NULL) { + com(" Environment %s", Dis.dis_opt); + } + com(" Commandline %s %s", argv0, comline); + if (!Dis.deterministic) { + com(" %s", ProgramAndVersion); + } + + com("********************************************"); + com(" Revision %04x", (int)Dis.oskSysRev); + com(" Module Size %d bytes", (int)Dis.oskSize); + com(" Owner %d.%d", (int)Dis.oskOwner >> 16, + (int)Dis.oskOwner & 0xffff); + com(" Name Offset %08x", (int)Dis.oskName); + com(" Permit %04x", (int)Dis.oskAccs); + com(" Type/Lang %04x", (int)Dis.oskType); + com(" Attribute %04x", (int)Dis.oskAttr); + com(" Edition %d", (int)Dis.oskEdition); + com(" Entry %08x", (int)Dis.exec); + com(" Excpt %08x", (int)Dis.oskExcpt); + + if (Dis.oskModType == OSKTYPE_DRIVER || Dis.oskModType == OSKTYPE_TRAP || + Dis.oskModType == OSKTYPE_PROGRAM) { + com(" Memory Size %d", (int)Dis.oskMem); + } + if (Dis.oskModType == OSKTYPE_PROGRAM || Dis.oskModType == OSKTYPE_TRAP) { + com(" Stack Size %d", (int)Dis.oskStack); + com(" M$IData %08x", (int)Dis.oskIdata); + com(" M$IRefs %08x", (int)Dis.oskIrefs); + } + if (Dis.oskModType == OSKTYPE_TRAP) { + com(" M$Init %08x", (int)Dis.oskInit); + com(" M$Term %08x", (int)Dis.oskTerm); + } + com("********************************************"); + outputBlank(); +} + +static void outputOskPsect(void) { + char buf[128], buf2[32]; + char* name = (char*)(Dis.Ofst + Dis.oskName); // モジュール名 + UWORD type = Dis.oskModType; + int hasStack = (type == OSKTYPE_PROGRAM || type == OSKTYPE_TRAP); + int stack = hasStack ? Dis.oskStack : 0; + + snprintf(buf, sizeof(buf), "%s\t%s,$%04x,$%04x,%d,%d,L%06x", OpString.psect, + name, (int)Dis.oskType, (int)Dis.oskAttr, (int)Dis.oskEdition, stack, + (int)Dis.exec); + + buf2[0] = '\0'; + if (Dis.oskExcpt) { + snprintf(buf2, sizeof(buf2), ",L%06x", (int)Dis.oskExcpt); + } + otherDirective2(buf, buf2); +} + +// ヘッダを書き出す +static void outputHeaderOsk(char* filename, time_t filedate, const char* argv0, + char* comline, FILE* fpHeader) { + outputOskFileInfo(filename, filedate, argv0, comline); + outputOskPsect(); + outputHeaderCpu(); +} + +// 各セクションを出力する +static void generateOsk(char* sfilename) { + int type = XDEF_TEXT; + lblbuf* lptr = generateSection(sfilename, NULL, Dis.beginBSS, + next(Dis.beginTEXT), XDEF_TEXT, &type); + lblmode nmode = lptr->mode; + address pc = lptr->label; + + outputBlank(); + otherDirective(OpString.vsect); + outputBlank(); + + while (pc <= Dis.beginDATA) { + lblmode mode = nmode; + address nlabel; + + lptr = Next(lptr); + nlabel = lptr->label; + nmode = lptr->mode; + + if (pc == Dis.beginDATA) break; // 泥縄 + + vsectbssgen(pc, nlabel, mode); + pc = nlabel; + } + + lptr = next(Dis.beginDATA); // vsect の初期化データ領域をポイント + switch (Dis.oskModType) { + codeptr idatsiz; + case OSKTYPE_PROGRAM: + case OSKTYPE_TRAP: + idatsiz = Dis.Ofst + (ULONG)Dis.oskIdata + 4; + lptr = idatagen(Dis.beginDATA + peekl(idatsiz), lptr); + // vsect の初期化データを出力 + break; + + default: + lptr = idatagen(Dis.LAST, lptr); + break; + } + pc = lptr->label; + + outputBlank(); + otherDirective(OpString.ends); // end vsect + + if (pc < Dis.LAST) { + outputBlank(); + otherDirective(OpString.vsect_remote); + outputBlank(); + + while (pc <= Dis.LAST) { + lblmode mode = nmode; + address nlabel; + + lptr = Next(lptr); + nlabel = lptr->label; + nmode = lptr->mode; + + if (pc == Dis.LAST) break; // 泥縄 + + vsectbssgen(pc, nlabel, mode); + pc = nlabel; + } + outputBlank(); + otherDirective(OpString.ends); // end vsect remote + } + + outputBlank(); + otherDirective(OpString.ends); // end psect + outputBlank(); + otherDirective(OpString.end); +} + +// 初期化データを出力する(下請け2) +static void idatagen_subInner(address pc, codeptr wkpc, lblmode mode, + ULONG byte) { + char buf[64]; + + switch (lblmodeOpesize(mode)) { + default: + case BYTESIZE: + break; + + case WORDSIZE: + if (byte != 2) break; + + snprintf(buf, sizeof(buf), "$%04x", (int)peekw(wkpc)); + outputData2(pc, OpString.dc[WORDSIZE], buf); + return; + + case LONGSIZE: + if (byte != 4) break; + + if (mode & CODEPTR) { + ULONG x = peekl(wkpc); + const char* fmt = (x == 0) ? "_btext\t* $%08x" + : (x == Dis.oskName) ? "_bname\t* $%08x" + : "L%06x"; + snprintf(buf, sizeof(buf), fmt, (int)x); + } else if (mode & DATAPTR) { + snprintf(buf, sizeof(buf), "L%06x", (int)(peekl(wkpc) + Dis.beginBSS)); + } else { + snprintf(buf, sizeof(buf), "$%08x", (int)peekl(wkpc)); + } + outputData2(pc, OpString.dc[LONGSIZE], buf); + return; + } + + dataoutDc(pc, wkpc, BYTESIZE, byte, 1); +} + +// 初期化データを出力する(下請け) +static codeptr idatagen_sub(address pc, codeptr wkpc, address pcend, + lblmode mode) { + while (pc < pcend) { + ULONG byte = pcend - pc; + + idatagen_subInner(pc, wkpc, mode, byte); + pc += byte; + wkpc += byte; + } + return wkpc; +} + +// 初期化データを出力する +// input: +// end : block end address +// lptr : lblbuf* ( contains block start address ) +static lblbuf* idatagen(address end, lblbuf* lptr) { + address pc = lptr->label; + codeptr wkpc = Dis.Ofst + (ULONG)Dis.oskIdata + 8; + + while (pc < end) { + lblmode mode = lptr->mode; + + do { + lptr = Next(lptr); + } while (lptr->shift); + + label_line_out(pc, mode, 0, FALSE, LINETYPE_DATA); + + wkpc = idatagen_sub(pc, wkpc, lptr->label, mode); + pc = lptr->label; + } + + return lptr; +} + +// vsectラベル + BSS出力 +static void vsectbssgen(address pc, address nlabel, lblmode mode) { + char buf[64]; + int bytes = MIN(nlabel, Dis.LAST) - pc; + SizeLength sl; + SymbolLabelFormula slfml; + const char* colon = ""; + + charout('$'); + + slfml.symbol = ""; + slfml.expr[0] = '\0'; + if (!isHIDDEN(mode)) { + makeSymLabFormula(&slfml, pc); + colon = ":"; + } + sl = getSizeLength(getSizeBytes(lblmodeOpesize(mode)), bytes); + snprintf(buf, sizeof(buf), "%s%s%d", colon, OpString.ds[sl.size], sl.length); + + outputData3(pc, slfml.symbol, slfml.expr, buf); +} + +// ワードテーブルの出力 +// input: +// pc : word table begin address +// pcend : word table end address +static void wgen(address pc, address pcend) { + const address limit = pcend - sizeof(UWORD); + + charout('w'); + + while (pc <= limit) { + address adrs = peekw(pc + Dis.Ofst); + + if (adrs == (address)0) { + outputData2(pc, OpString.dc[WORDSIZE], "0"); + } else { + SymbolLabelFormula slfml; + makeSymLabFormula(&slfml, adrs); + outputData3(pc, OpString.dc[WORDSIZE], slfml.symbol, slfml.expr); + } + pc += sizeof(UWORD); + } + + dataoutDcByte(pc, pcend); // 半端に残ったデータを出力 +} + +// (d16,An)のディスプレースメントをラベルに置き換える +static char* operandToVsectLabel(char* p, operand* op) { + if ((Dis.oskModType == OSKTYPE_PROGRAM || Dis.oskModType == OSKTYPE_TRAP) && + op->baseReg == OSK_BASEREG) { + const ULONG offset = 0x8000; + address adrs = Dis.beginBSS + op->opval + offset; + SymbolLabelFormula slfml; + + makeBareLabel(&slfml, adrs); + *p++ = '('; + p = strcpy2(p, slfml.expr); + return strcpy2(p, strchr(op->operand, ',')); + } + + return strcpy2(p, op->operand); +} + +static const IncludeSpec os9defsSpec = { // + (1 << 8) - 1, 0, &Dis.OS9label, &Dis.os9MacPath, NULL, NULL}; +static const IncludeSpec mathdefsSpec = { // + (1 << 8) - 1, 0, &Dis.MATHlabel, &Dis.mathMacPath, NULL, NULL}; +static const IncludeSpec ciodefsSpec = { // + (1 << 8) - 1, 0, &Dis.CIOlabel, &Dis.cioMacPath, NULL, NULL}; + +static void readIncludeFileOsk(const IncludeSpec* spec, const char* path, + const char* filename) { + char* fullpath = Malloc(strlen(path) + 1 + strlen(filename) + 1); + strcat(strcat(strcpy(fullpath, path), "/"), filename); + if (!readIncludeFile(spec, fullpath)) { + eprintf("%s をオープンできません。\n", filename); + return; + } + *spec->fullpathPtr = fullpath; +} + +// 各種インクルードファイルを読み込む +// 環境変数 DISDEFS で指定されたディレクトリから +// os9defs.d mathdefs.d ciodefs.d を読み込む +static void readIncludeFilesOsk(void) { + char* dis_inc = getenv("DISDEFS"); + + if (dis_inc == NULL) { + eprintf("環境変数 DISDEFS が設定されていません。\n"); + return; + } + readIncludeFileOsk(&os9defsSpec, dis_inc, "os9defs.d"); + readIncludeFileOsk(&mathdefsSpec, dis_inc, "mathdefs.d"); + readIncludeFileOsk(&ciodefsSpec, dis_inc, "ciodefs.d"); +} + +static void analyzeOptional(address adrs) { + if (adrs != (address)0) analyze(adrs, ANALYZE_IGNOREFAULT); +} + +// プログラム領域を解析する +static void analyzeProgramOsk(void) { + regist_label(Dis.base + Dis.text + Dis.data + Dis.bss, DATLABEL | UNKNOWN); + regist_label(Dis.oskName, DATLABEL | STRING | FORCE); + regist_label(Dis.oskSize - 4, DATLABEL | BYTESIZE | FORCE); // CRC + + switch (Dis.oskModType) { + case OSKTYPE_PROGRAM: + case OSKTYPE_TRAP: + eprintf("初期化データ領域解析中です。"); + analyze_idata(); // 初期データオフセットを解析 + analyze_irefs(); // 初期データ参照テーブルを解析 + eputc('\n'); + default: + break; + } + + eprintf("プログラム領域解析中です。"); + setReasonVerbose(BACKTRACK_REASON_PROGRAM); + + analyzeOptional(Dis.oskExcpt); + + switch (Dis.oskModType) { + case OSKTYPE_TRAP: + analyzeOptional(Dis.oskInit); + analyzeOptional(Dis.oskTerm); + regist_label((address)0x000048, DATLABEL | ZTABLE); + z_table((address)0x000048); + // FALLTHRU + case OSKTYPE_PROGRAM: + case OSKTYPE_SUBROUTINE: + case OSKTYPE_SYSTEM: + analyze(Dis.exec, ANALYZE_IGNOREFAULT); + break; + + case OSKTYPE_FILEMAN: + registerReltblOrder(&Dis.reltblArray, Dis.exec, RELTABLE, TRUE, + DATLABEL | FORCE); + break; + + case OSKTYPE_DRIVER: + w_table(Dis.exec); // 実行エントリテーブル + break; + } +} + +#define OFFS(member) GET_OPECODE_OFFSET(member) + +// オペコード文字列をr68(OS-9/X680x0用アセンブラ)形式に書き換える +static void modifyMnemonicOsk(OpStringTable* ops) { + static const uint16_t list[] = { + OFFS(dcWord), // + OFFS(include_), // + OFFS(cpu), // + OFFS(fpid), // + OFFS(equ), // + OFFS(xdef), // + OFFS(text), // + OFFS(data), // + OFFS(bss), // + OFFS(stack), // + OFFS(end), // + }; + size_t i; + + // "." を取り除く + for (i = 0; i < _countof(list); ++i) { + char* p = (char*)ops + list[i]; + strcpy(p + 1, p + 2); + } + for (i = 0; i < _countof(ops->dc); ++i) { + char* p = ops->dc[i]; + strcpy(p + 1, p + 2); + } + for (i = 0; i < _countof(ops->ds); ++i) { + char* p = ops->ds[i]; + strcpy(p + 1, p + 2); + } + strcpy(ops->dcWord, ops->dcWord + 1); + + // .even を align に差し替える + strcpy(ops->even, ops->r68Align); +} + +static void makeRelocateTableOsk(void) { + // 処理不要 +} + +static void parseSymbolTableOsk(ArrayBuffer* stbuf) { + // 処理不要 +} + +// OS-9/X680x0モジュールの処理関数 +static const Actions actionsOsk = { + registerVsectLabel, // + oskTrap, // + operandToVsectLabel, // + wgen, // + makeRelocateTableOsk, // + parseSymbolTableOsk, // + analyzeProgramOsk, // + readIncludeFilesOsk, // + modifyMnemonicOsk, // + outputHeaderOsk, // + generateOsk // +}; + +// OS-9/X680x0モジュールのヘッダを読み込む +static void loadHeaderOskModule(FILE* fp, ULONG fileSize) { + UBYTE head[OSKHEAD_SIZE]; + + if (fread(head, 1, sizeof(head), fp) != sizeof(head) || + peekw(head + OSKHEAD_ID) != OSKHEAD_ID_VALUE) { + err("OS-9/680x0のモジュールではありません。\n"); + } + + Dis.oskSysRev = peekw(head + OSKHEAD_SYSREV); + Dis.oskSize = peekl(head + OSKHEAD_MODSIZE); + Dis.oskOwner = peekl(head + OSKHEAD_OWNER); + Dis.oskName = peekl(head + OSKHEAD_NAME); + Dis.oskAccs = peekw(head + OSKHEAD_ACCS); + Dis.oskType = peekw(head + OSKHEAD_TYPE); + Dis.oskAttr = peekw(head + OSKHEAD_ATTR); + Dis.oskEdition = peekw(head + OSKHEAD_EDITION); + Dis.oskUsage = peekl(head + OSKHEAD_USAGE); + Dis.oskSymbol = peekl(head + OSKHEAD_SYMBOL); + Dis.oskExcpt = peekl(head + OSKHEAD_EXCPT); + Dis.oskMem = peekl(head + OSKHEAD_MEM); + Dis.oskStack = peekl(head + OSKHEAD_STACK); + Dis.oskIdata = peekl(head + OSKHEAD_IDATA); + Dis.oskIrefs = peekl(head + OSKHEAD_IREFS); + Dis.oskInit = peekl(head + OSKHEAD_INIT); + Dis.oskTerm = peekl(head + OSKHEAD_TERM); + + Dis.oskModType = (Dis.oskType >> 8) & 0x0f; + switch (Dis.oskModType) { + default: + err("このモジュールタイプはサポートしていません。\n"); + + case OSKTYPE_PROGRAM: + case OSKTYPE_TRAP: + Dis.base = 0x0048; + break; + case OSKTYPE_SUBROUTINE: + case OSKTYPE_SYSTEM: + case OSKTYPE_FILEMAN: + case OSKTYPE_DRIVER: + Dis.base = 0x003c; + break; + } + + Dis.exec = peekl(head + OSKHEAD_EXEC); + Dis.text = fileSize - (ULONG)Dis.base; + Dis.bss = peekl(head + OSKHEAD_MEM); + + fseek(fp, Dis.base, SEEK_SET); +} + +// 実行ファイルのヘッダを読み込む +void loadHeaderOsk(FILE* fp, ULONG fileSize) { + switch (Dis.fileType) { + default: + err("Human68kの実行ファイルには対応していません。\n"); + + case FILETYPE_DUMP: + Dis.text = fileSize; + break; + + case FILETYPE_OSK: + loadHeaderOskModule(fp, fileSize); + break; + } + + // OS-9/680x0のアセンブラ(r68)用の設定 + Dis.compressLen = 0; // dcb疑似命令を使えない + Dis.oldSyntax = TRUE; + Dis.dbccSize = NOTHING; // DBccにサイズを付けるとエラーになる + Dis.quoteChar = '"'; + + Dis.findLinkW = TRUE; + + Dis.beginTEXT = Dis.base; // psect 先頭 + Dis.beginBSS = Dis.beginTEXT + Dis.text; // vsect 先頭 + Dis.beginDATA = Dis.beginBSS + Dis.bss; // 初期化 vsect 先頭 + Dis.LAST = Dis.beginDATA + Dis.data; + Dis.availableTextEnd = Dis.beginBSS; + + Dis.actions = &actionsOsk; +} + +#endif + +// EOF diff --git a/src/osk.h b/src/osk.h new file mode 100644 index 0000000..9027ffc --- /dev/null +++ b/src/osk.h @@ -0,0 +1,51 @@ +// ソースコードジェネレータ +// OS-9/X680x0(OSK) ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef OSK_H +#define OSK_H + +#include + +#include "disasm.h" +#include "estruct.h" + +// 実行ファイルのヘッダID +enum { + OSKHEAD_ID_VALUE = 0x4afc, +}; + +#ifdef OSKDIS + +// Dis.oskModType +enum { + OSKTYPE_PROGRAM = 0x01, + OSKTYPE_SUBROUTINE = 0x02, + OSKTYPE_TRAP = 0x0b, + OSKTYPE_SYSTEM = 0x0c, + OSKTYPE_FILEMAN = 0x0d, + OSKTYPE_DRIVER = 0x0e, + // OSKTYPE_DEVDESC = 0x0f, +}; + +extern void loadHeaderOsk(FILE* fp, ULONG fileSize); + +#endif +#endif + +// EOF diff --git a/src/output.c b/src/output.c index 2940f3f..0e1f2df 100644 --- a/src/output.c +++ b/src/output.c @@ -1,433 +1,420 @@ -/* $Id: output.c,v 1.1 1996/11/07 08:03:56 ryo freeze $ - * - * ソースコードジェネレータ - * 出力ルーチン下請け - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// 出力ルーチン下請け +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . -#include #include +#include #include -#include -#include -#include -#include - -#ifdef __LIBC__ - #define __DOS_INLINE__ - #include /* _dos_getfcb */ -#endif -#ifndef O_BINARY -#define O_BINARY 0 +#ifdef _MSC_VER +#include // write() +#else +#include #endif - #include "disasm.h" #include "estruct.h" -#include "etc.h" /* err */ -#include "generate.h" /* Atab */ +#include "etc.h" #include "global.h" -#include "hex.h" /* strend */ +#include "hex.h" #include "output.h" +#define BLOCK_SIZE_MAX (1024 * 1024) +#define BLOCK_SIZE_MIN (16 * 1024) +#define MAX_LINE_BYTES 1024 -USEOPTION option_a, option_S; +typedef struct { + FILE* fp; + char* basename; + char* filename; -extern char CommentChar; + char* buffer; + char* write; + size_t blockSize; + size_t bufferSize; // blockSize + MAX_LINE_BYTES -int Output_AddressCommentLine; -int Output_SplitByte; + size_t splitByte; + boolean isSplitMode; // 指定サイズごとにファイルを .000 .001 と切り換える + int fileBlockNum; // 切り換え中のファイルの .000~ の番号 + size_t limit; // 次に切り換えるサイズ(アドレス) -#ifdef STREAM -static FILE* Output_fp; -#else -static int Output_handle; -static char* OutputLargeBuffer; -static char* OutputLargeBufferPtr; -#endif -static char OutputBuffer[256]; -static char* OutputBufferEnd = OutputBuffer; -static boolean SplitMode; - -#define OUTPUT_BUFFER_SIZE (64*1024) + int lineCount; // -a + LineType prevLineType; +} OutputFile; -/* private 関数プロトタイプ */ -#ifndef STREAM -private void flush_buffer (void); -#endif - +static OutputFile outputFile; -/* Inline Functions */ +// static 関数プロトタイプ +static char* appendAdrsCommentInner(address pc, char* buffer, char* end); +static void switchOutputFileInner(address pc); +static void openOutputFile2(void); +static char* createNumberedFilename(const char* basename, int n); +static void writeFileFromBuffer(size_t length); -static INLINE char* -strcpy2 (char* dst, char* src) -{ - while ((*dst++ = *src++) != 0) - ; - return --dst; +// 必要なら出力ファイルを切り換える(インライン展開用) +static void switchOutputFile(address pc) { + if (outputFile.isSplitMode) switchOutputFileInner(pc); } +// 必要ならアドレスのコメントを追加する(インライン展開用) +static char* appendAdrsComment(address pc, char* buffer, char* end) { + if (Dis.addressCommentLine == 0) return end; -/* - - 初期化 - -*/ -extern void -init_output (void) -{ -#ifndef STREAM - if ((OutputLargeBuffer = Malloc (OUTPUT_BUFFER_SIZE)) == NULL) - err ("出力バッファ用メモリを確保出来ません\n"); - OutputLargeBufferPtr = OutputLargeBuffer; -#endif + return appendAdrsCommentInner(pc, buffer, end); } +// 必要ならファイル出力して、書き込みバッファの空きを確保する +static void ensureBufferCapacity(void) { + size_t len = outputFile.write - outputFile.buffer; -/* - - 出力ファイルをオープン - - char* filename == NULLなら前回指定されたファイル名を引き続き使用する. - 通常は - output_file_open ("foo", 0); // foo.000 - output_file_open (NULL, 1); // foo.001 - ... - output_file_open (NULL, -1); // foo.dat - output_file_open (NULL, -2); // foo.bss - として呼び出す. - -*/ - -extern void -output_file_open (char* filename, int file_block_num) -{ - static char* basename; - - if (filename) - basename = filename; + if (len >= outputFile.blockSize) { + writeFileFromBuffer(outputFile.blockSize); + } +} - if (basename == NULL) - err ("dis: internal error!\n"); +// 前の行が空行でなければ、空行を出力する +void outputBlank(void) { + if (outputFile.prevLineType == LINETYPE_BLANK) return; - if (strcmp ("-", basename) == 0) { -#ifdef STREAM - Output_fp = stdout; -#else - Output_handle = STDOUT_FILENO; -#endif - } else { - char* buf = Malloc (strlen (basename) + 4 + 1); - strcpy (buf, basename); - - if (option_S) { - switch (file_block_num) { - case 0: - SplitMode = TRUE; - /* fall through */ - default: - sprintf (strend (buf), ".%03x", file_block_num); - break; - case -1: - strcat (buf, ".dat"); - SplitMode = FALSE; - break; - case -2: - strcat (buf, ".bss"); - SplitMode = FALSE; - break; - } - } - -#ifdef STREAM - if ((Output_fp = fopen (buf, "w")) == NULL) -#else -#ifdef OSK - if ((Output_handle = creat (buf, S_IREAD|S_IWRITE)) < 0) -#else - if ((Output_handle = open (buf, - O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, S_IRUSR | S_IWUSR)) < 0) -#endif /* OSK */ - err ("%s をオープン出来ません.\n", buf); -#endif - - Mfree (buf); - } + outputFile.prevLineType = LINETYPE_BLANK; + *outputFile.write++ = '\n'; } +// 必要なら空行を出力する(次の行の種類を指定) +static void outputBlankBefore(LineType type, address pc) { + if (type == LINETYPE_TEXT || type == LINETYPE_DATA) { + // その他orデータ -> テキスト、その他orテキスト -> データに + // 切り替われば空行を出力する + if (outputFile.prevLineType != type) outputBlank(); -extern void -output_file_close (void) -{ -#ifdef STREAM - fclose (Output_fp); -#else - flush_buffer (); - close (Output_handle); -#endif + if (outputFile.prevLineType == LINETYPE_BLANK) { + // 直前に空行を出力していれば、ファイル切り換えを試みる + switchOutputFile(pc); + } + } + outputFile.prevLineType = type; } +// PCを進めない行(疑似命令等)を出力する +// type==LINETYPE_BLANK or LINETYPE_OTHERの場合はpcは0でもよい。 +void outputDirective(LineType type, address pc, const char* s) { + char* p; -/* - - 書き込みエラー + outputBlankBefore(type, pc); -*/ -private void -diskfull (void) -{ -#ifdef STREAM - fclose (Output_fp); -#else - close (Output_handle); -#endif - err ("\nディスクが一杯です\n"); + ensureBufferCapacity(); + p = strcpy2(outputFile.write, s); + *p++ = '\n'; + *p = '\0'; + outputFile.write = p; } +// PCを進めない行を出力する(文字列×2) +void outputDirective2(LineType type, address pc, const char* s1, + const char* s2) { + char* p; -#ifndef STREAM -private void -output_through_buffer (char* str) -{ - - OutputLargeBufferPtr = strcpy2 (OutputLargeBufferPtr, str); + outputBlankBefore(type, pc); - if (OutputLargeBufferPtr - OutputLargeBuffer > OUTPUT_BUFFER_SIZE - 1024) - flush_buffer (); + ensureBufferCapacity(); + p = strcpy2(outputFile.write, s1); + p = strcpy2(p, s2); + *p++ = '\n'; + *p = '\0'; + outputFile.write = p; } +// PCを進めない行を出力する(配列指定) +void outputDirectiveArray(LineType type, address pc, size_t length, + const char* array[]) { + char* p; + size_t i; -/* - - ファイルへ出力 + outputBlankBefore(type, pc); -*/ -extern void -outputf (char* fmt, ...) -{ -#ifndef STREAM - char tmp[256]; -#endif - va_list ap; - va_start (ap, fmt); - -#ifdef STREAM - vfprintf (Output_fp, fmt, ap); - va_end (ap); - if (ferror (Output_fp)) - diskfull (); -#else - vsprintf (tmp, fmt, ap); - va_end (ap); - output_through_buffer (tmp); -#endif + ensureBufferCapacity(); + p = outputFile.write; + for (i = 0; i < length; ++i) p = strcpy2(p, array[i]); + *p++ = '\n'; + *p = '\0'; + outputFile.write = p; } - -extern void -outputa (char* str) -{ - OutputBufferEnd = strcpy2 (OutputBufferEnd, str); +// 文字列を出力 +static void outputString(LineType type, address pc, const char* s) { + char* head; + char* p; + + outputBlankBefore(type, pc); + ensureBufferCapacity(); + head = outputFile.write; + p = strcpy2(head, s); + p = appendAdrsComment(pc, head, p); + *p++ = '\n'; + *p = '\0'; + outputFile.write = p; } - -extern void -outputca (int ch) -{ - *OutputBufferEnd++ = ch; - *OutputBufferEnd = '\0'; +// 文字列(×2)を出力 +static void outputString2(LineType type, address pc, const char* s1, + const char* s2) { + char* head; + char* p; + + outputBlankBefore(type, pc); + ensureBufferCapacity(); + head = outputFile.write; + p = strcpy2(head, s1); + p = strcpy2(p, s2); + p = appendAdrsComment(pc, head, p); + *p++ = '\n'; + *p = '\0'; + outputFile.write = p; } - -extern void -outputfa (char* fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - vsprintf (OutputBufferEnd, fmt, ap); - OutputBufferEnd = strend (OutputBufferEnd); - va_end (ap); +// 文字列(×3)を出力 +static void outputString3(LineType type, address pc, const char* s1, + const char* s2, const char* s3) { + char* head; + char* p; + + outputBlankBefore(type, pc); + ensureBufferCapacity(); + head = outputFile.write; + p = strcpy2(head, s1); + p = strcpy2(p, s2); + p = strcpy2(p, s3); + p = appendAdrsComment(pc, head, p); + *p++ = '\n'; + *p = '\0'; + outputFile.write = p; } - -#if 0 -extern void -outputax (ULONG n, int width) -{ - OutputBufferEnd = itox (OutputBufferEnd, n, width); +// プログラム行を出力する +void outputText(address pc, const char* s) { + outputString(LINETYPE_TEXT, pc, s); } -#endif -extern void -outputaxd (ULONG n, int width) -{ - OutputBufferEnd = itoxd (OutputBufferEnd, n, width); +// プログラム行を出力する(文字列×2) +void outputText2(address pc, const char* s1, const char* s2) { + outputString2(LINETYPE_TEXT, pc, s1, s2); } -extern void -outputax2_without_0supress (ULONG n) -{ - *OutputBufferEnd++ = '$'; - OutputBufferEnd = itox2_without_0supress (OutputBufferEnd, n); +// データ行を出力する +void outputData(address pc, const char* s) { + outputString(LINETYPE_DATA, pc, s); } -extern void -outputax4_without_0supress (ULONG n) -{ - *OutputBufferEnd++ = '$'; - OutputBufferEnd = itox4_without_0supress (OutputBufferEnd, n); +// データ行を出力する(文字列×2) +void outputData2(address pc, const char* s1, const char* s2) { + outputString2(LINETYPE_DATA, pc, s1, s2); } -extern void -outputax8_without_0supress (ULONG n) -{ - *OutputBufferEnd++ = '$'; - OutputBufferEnd = itox8_without_0supress (OutputBufferEnd, n); +// データ行を出力する(文字列×3) +void outputData3(address pc, const char* s1, const char* s2, const char* s3) { + outputString3(LINETYPE_DATA, pc, s1, s2, s3); } +// 文字列の末尾にTABとコメント文字を書き込む +// TABの個数は指定のタブ位置になるまで(最低1個) +// 文字列末尾のアドレスを返す +char* writeTabAndCommentChar(char* buffer, int tabs) { + char* p = buffer; + char c; + int width = 0; + + // 文字列の桁数を数える + while ((c = *p++) != '\0') { + if (c == '\t') + width = (width | (TAB_WIDTH - 1)) + 1; + else if (c == '\n') + width = 0; + else + width += 1; + } + p -= 1; + + tabs -= (width / TAB_WIDTH); // 必要なTABの個数 + tabs -= 1; // 最低1個は書き込む分の補正 + + for (; tabs > 0; tabs--) *p++ = '\t'; + *p++ = '\t'; + *p++ = Dis.commentStr[0]; + + return p; +} -extern void -newline (address lineadrs) -{ - - if (option_S && SplitMode) { - static int file_block_num = 0; - - if (Output_SplitByte <= - ((long)lineadrs - (long)BeginTEXT - Output_SplitByte * file_block_num) - && OutputBuffer[0] == '\n') { - output_file_close (); - output_file_open (NULL, ++file_block_num); - } - } +// アドレスのコメントを追加する +static char* appendAdrsCommentInner(address pc, char* buffer, char* end) { + char* p; - if (option_a) { - static int linecount = 1; - - if (linecount >= Output_AddressCommentLine) { - char* ptr; - int i, len = 0; - - /* 桁数を数える */ - for (ptr = OutputBuffer; *ptr; ptr++) { - if (*ptr == '\t') { - len |= 7; - len++; - } - else if (*ptr == '\n') - len = 0; - else - len++; - } - - /* 規定位置までタブを出力する */ - for (i = Atab - len / 8 - 1; i > 0; i--) - *OutputBufferEnd++ = '\t'; - - *OutputBufferEnd++ = '\t'; - *OutputBufferEnd++ = CommentChar; - - OutputBufferEnd = itox6 (OutputBufferEnd, (ULONG)lineadrs); - linecount = 1; - } - else - linecount++; - } + outputFile.lineCount += 1; + if (outputFile.lineCount < Dis.addressCommentLine) return end; - *OutputBufferEnd++ = '\n'; - *OutputBufferEnd = '\0'; + // 指定行数に達した + outputFile.lineCount = 0; -#ifdef STREAM - fputs (OutputBuffer, Output_fp); - if (ferror (Output_fp)) - diskfull (); -#else - output_through_buffer (OutputBuffer); -#endif - OutputBufferEnd = OutputBuffer; + p = writeTabAndCommentChar(buffer, Dis.Atab); + return itox6(p, (ULONG)pc); } +// 必要なら出力ファイルを切り換える +static void switchOutputFileInner(address pc) { + if ((size_t)(pc - Dis.beginTEXT) < outputFile.limit) return; -private void -flush_buffer (void) -{ - long length = OutputLargeBufferPtr - OutputLargeBuffer; - - if (write (Output_handle, OutputLargeBuffer, length) < length) - diskfull (); + closeOutputFile(FALSE); - OutputLargeBufferPtr = OutputLargeBuffer; + outputFile.limit += outputFile.splitByte; + outputFile.filename = + createNumberedFilename(outputFile.basename, ++outputFile.fileBlockNum); + openOutputFile2(); } -#endif /* STREAM */ +// 可変容量メモリ確保 +static void* allocMemory(size_t max, size_t min, size_t add, size_t* base, + size_t* total) { + size_t size; + for (size = max; size >= min; size >>= 1) { + size_t bufSize = size + add; + void* buf = Malloc(bufSize); + + if (buf) { + *base = size; + *total = bufSize; + return buf; + } + } -/* - ソースファイルの出力先と、標準エラー出力が同じなら真を返す. + return NULL; +} - dis foo.x - どちらも端末なので、真. +// 書き込みバッファを確保する +static void allocBuffer(void) { + void* buf; + size_t blockSize, bufSize; - dis foo.x >& list - どちらも list なので、真 + if (outputFile.buffer != NULL) return; - dis foo.x foo.s - foo.s と端末なので、偽. -*/ + buf = allocMemory(BLOCK_SIZE_MAX, BLOCK_SIZE_MIN, MAX_LINE_BYTES, &blockSize, + &bufSize); + if (buf == NULL) notEnoughMemory(); -extern boolean -is_confuse_output (void) -{ -#ifdef STREAM - int src_no = fileno (Output_fp); -#else - int src_no = Output_handle; -#endif + outputFile.blockSize = blockSize; + outputFile.bufferSize = bufSize; + outputFile.write = outputFile.buffer = buf; +} - if (isatty (src_no) && isatty (STDERR_FILENO)) - return TRUE; +// 書き込みバッファを解放する +static void freeBuffer(void) { + if (outputFile.buffer != NULL) free(outputFile.buffer); + outputFile.write = outputFile.buffer = NULL; +} -#ifdef __LIBC__ - if (_dos_getfcb (src_no) == _dos_getfcb (STDERR_FILENO)) - return TRUE; -#else - { - struct stat src_st, err_st; - - if (fstat (src_no, &src_st) == 0 - && fstat (STDERR_FILENO, &err_st) == 0 - && src_st.st_dev == err_st.st_dev - && src_st.st_ino == err_st.st_ino) - return TRUE; +// 出力ファイルを開く +// splitByte>0のときは分割モードで、extが拡張子として追加される +// (ext==NULLのときは ".001", ".002", ...) +void openOutputFile(char* basename, size_t splitByte, const char* ext) { + allocBuffer(); + + outputFile.basename = basename; + outputFile.filename = NULL; + outputFile.isSplitMode = FALSE; + outputFile.lineCount = 0; + outputFile.prevLineType = LINETYPE_BLANK; + + if (strcmp(basename, "-") == 0) { + // ファイル名が - なら標準出力に書き出す + outputFile.fp = stdout; + return; + } + + if (splitByte == 0) { + char* buf = Malloc(strlen(basename) + 1); + outputFile.filename = strcpy(buf, basename); + } else { + if (ext == NULL) { + // .001 .002 ... + outputFile.isSplitMode = TRUE; + outputFile.splitByte = splitByte; + outputFile.limit = splitByte; + outputFile.fileBlockNum = 0; + outputFile.filename = createNumberedFilename(outputFile.basename, 0); + } else { + // .dat .bss + char* buf = Malloc(strlen(basename) + strlen(ext) + 1); + strcpy(strcpy2(buf, basename), ext); + outputFile.filename = buf; } -#endif + } - return FALSE; + openOutputFile2(); } +static void openOutputFile2(void) { + outputFile.fp = fopen(outputFile.filename, "wb"); + if (outputFile.fp == NULL) + err("\n%s をオープンできません。\n", outputFile.filename); +} -#if 0 -/* following functions is no longer used. */ +static char* createNumberedFilename(const char* basename, int n) { + size_t bufSize = strlen(basename) + 16; + char* buf = Malloc(bufSize); -extern void -output (char* str) -{ - fputs (str, Output_fp); - if (ferror (Output_fp)) - diskfull (); + snprintf(buf, bufSize, "%s.%03x", basename, n); + return buf; } -extern void -outputc (int ch) -{ - fputc (ch, Output_fp); +// 出力ファイルを閉じる +void closeOutputFile(boolean freeBuf) { + writeFileFromBuffer(outputFile.write - outputFile.buffer); + if (freeBuf) freeBuffer(); + + fclose(outputFile.fp); + outputFile.fp = NULL; + + Mfree(outputFile.filename); + outputFile.filename = NULL; } -#endif +// 書き込みバッファ内のデータをファイルに書き出す +static void writeFileFromBuffer(size_t length) { + char* buffer = outputFile.buffer; + size_t wrote; + size_t dataLen, restLen; + + if (length == 0) return; + + dataLen = outputFile.write - buffer; + if (dataLen < length) internalError(__FILE__, __LINE__, "dataLen < length"); + + wrote = (size_t)write(fileno(outputFile.fp), buffer, (unsigned int)length); + if (wrote != length) { + fclose(outputFile.fp); + err("\nディスクが一杯です。\n"); + } + + restLen = dataLen - length; + if (restLen != 0) { + // 残りのデータをバッファ先頭に移動する + memcpy(buffer, buffer + length, restLen); + } + outputFile.write = buffer + restLen; +} -/* EOF */ +// EOF diff --git a/src/output.h b/src/output.h index 09b4a97..da47eed 100644 --- a/src/output.h +++ b/src/output.h @@ -1,46 +1,54 @@ -/* $Id: output.h,v 1.1 1996/10/24 04:27:50 ryo freeze $ - * - * ソースコードジェネレータ - * 出力ルーチン下請けヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef OUTPUT_H -#define OUTPUT_H - - -extern void init_output (void); -extern void output_file_open (char* , int); -extern void output_file_close (void); -extern void outputf (char*, ...); -extern void outputa (char*); -extern void outputca (int); -extern void outputfa (char*, ...); -extern void newline (address); -#if 0 -extern void outputax (ULONG, int); -#endif -extern void outputaxd (ULONG, int); -extern void outputax2_without_0supress (ULONG); -extern void outputax4_without_0supress (ULONG); -extern void outputax8_without_0supress (ULONG); - -extern boolean is_confuse_output (void); +// ソースコードジェネレータ +// 出力ルーチン下請け ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef OUTPUT_H +#define OUTPUT_H + +#include "estruct.h" + +#define TAB_WIDTH 8 + +typedef enum { + LINETYPE_BLANK, + LINETYPE_OTHER, + LINETYPE_TEXT, + LINETYPE_DATA, +} LineType; + +extern void outputBlank(void); +extern void outputDirective(LineType type, address pc, const char* s); +extern void outputDirective2(LineType type, address pc, const char* s1, + const char* s2); +extern void outputDirectiveArray(LineType type, address pc, size_t length, + const char* array[]); +extern void outputText(address pc, const char* s); +extern void outputText2(address pc, const char* s1, const char* s2); +extern void outputData(address pc, const char* s); +extern void outputData2(address pc, const char* s1, const char* s2); +extern void outputData3(address pc, const char* s1, const char* s2, + const char* s3); + +extern char* writeTabAndCommentChar(char* buffer, int tabs); + +extern void openOutputFile(char* basename, size_t splitByte, const char* ext); +extern void closeOutputFile(boolean freeBuf); -#if 0 -extern void output (char*); -extern void outputc (int); #endif -#define CR "\n" - -extern int Output_AddressCommentLine; -extern int Output_SplitByte; - - -#endif /* OUTPUT_H */ - -/* EOF */ +// EOF diff --git a/src/ports/Makefile_Cyg_MinGW b/src/ports/Makefile_Cyg_MinGW index 2bc09ad..996193f 100644 --- a/src/ports/Makefile_Cyg_MinGW +++ b/src/ports/Makefile_Cyg_MinGW @@ -5,19 +5,17 @@ PROGRAM = dis YACC = bison -CC = gcc-3 -mno-cygwin -finput-charset=cp932 -fexec-charset=cp932 +CC = gcc -finput-charset=cp932 -fexec-charset=cp932 -fpermissive LD = $(CC) LDFLAGS = -FUNCCFLAGS = -DHAVE_STRUPR +FUNCCFLAGS = # -DHAVE_STRTOX -# -DHAVE_STRUPR # -DHAVE_JCTYPE_H # -DNO_PRINTF_LDBL DEFAULTCFLAGS = -Wall -pipe # -DQUICK_YES_NO -# -DREAD_FEFUNC_H OPTCFLAGS = -O3 diff --git a/src/ports/Makefile_Cygwin b/src/ports/Makefile_Cygwin index 5a9930e..0890cde 100644 --- a/src/ports/Makefile_Cygwin +++ b/src/ports/Makefile_Cygwin @@ -9,15 +9,13 @@ CC = gcc -finput-charset=cp932 LD = $(CC) LDFLAGS = -FUNCCFLAGS = -DHAVE_STRUPR +FUNCCFLAGS = # -DHAVE_STRTOX -# -DHAVE_STRUPR # -DHAVE_JCTYPE_H # -DNO_PRINTF_LDBL DEFAULTCFLAGS = -Wall -pipe # -DQUICK_YES_NO -# -DREAD_FEFUNC_H OPTCFLAGS = -O3 diff --git a/src/ports/Makefile_FreeBSD b/src/ports/Makefile_FreeBSD index 7c5cb19..7d63b96 100644 --- a/src/ports/Makefile_FreeBSD +++ b/src/ports/Makefile_FreeBSD @@ -11,13 +11,11 @@ LDFLAGS = FUNCCFLAGS = # -DHAVE_STRTOX -# -DHAVE_STRUPR # -DHAVE_JCTYPE_H # -DNO_PRINTF_LDBL DEFAULTCFLAGS = -Wall -pipe # -DQUICK_YES_NO -# -DREAD_FEFUNC_H OPTCFLAGS = -O3 diff --git a/src/ports/Makefile_Linux b/src/ports/Makefile_Linux index 18c7734..3384036 100644 --- a/src/ports/Makefile_Linux +++ b/src/ports/Makefile_Linux @@ -11,13 +11,11 @@ LDFLAGS = FUNCCFLAGS = # -DHAVE_STRTOX -# -DHAVE_STRUPR # -DHAVE_JCTYPE_H # -DNO_PRINTF_LDBL DEFAULTCFLAGS = -Wall -pipe # -DQUICK_YES_NO -# -DREAD_FEFUNC_H OPTCFLAGS = -O3 diff --git a/src/ports/ports.txt b/src/ports/ports.txt index 86c1135..40970f6 100644 --- a/src/ports/ports.txt +++ b/src/ports/ports.txt @@ -1,35 +1,46 @@ -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - X680x0/Human68k *以外* での再コンパイル方法 + X680x0/Human68k *以外* での再コンパイル方法 -──────────────────────────────────── +─────────────────────────────────────── + +※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※ + + dis 3.16 より後のバージョンアップ作業において、ports/ ディレクトリ内の +Makefile の書き換えが行われていません。クロスコンパイル時は適宜修正をお願いし +ます。 + + また、各環境での再コンパイルも行っていないため、それ以外にも不具合が生じてい +るかもしれません。 + +※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※※ - Cygwin、Linux、FreeBSD 用の Makefile を用意してあります。src/ ディレク -トリに Makefile というファイル名でコピーして make するか、 - make -f ports/Makefile_Cyg_MinGW -のように指定して下さい。 + Cygwin、Linux、FreeBSD 用の Makefile を用意してあります。src/ ディレクトリに +Makefile というファイル名でコピーして make するか、 + make -f ports/Makefile_Cyg_MinGW +のように指定して下さい。 - 環境 Makefile - ---- -------- - Cygwin Makefile_Cygwin - Cygwin (MinGW) Makefile_Cyg_MinGW - Linux Makefile_Linux - FreeBSD Makefile_FreeBSD + 環境 Makefile + ---- -------- + Cygwin Makefile_Cygwin + Cygwin (MinGW) Makefile_Cyg_MinGW + Linux Makefile_Linux + FreeBSD Makefile_FreeBSD ● Windows: Cygwin - 文字コードを gcc で変換するように指定しているので、何もせず make する -だけで通る筈です。 + 文字コードを gcc で変換するように指定しているので、何もせず make するだけで +通るはずです。  実行時は cygwin1.dll などの Cygwin の実行環境が必要です。 ● Windows: Cygwin -mno-cygwin (WinGW) - 文字コードを gcc で変換するように指定しているので、何もせず make する -だけで通る筈です。 + 文字コードを gcc で変換するように指定しているので、何もせず make するだけで +通るはずです。  DLL は不要なので、実行ファイルの配布に向いていると思います。 @@ -40,127 +51,95 @@ ※ Ubuntu 10.04 で確認しています。 - 文字コードを gcc で変換するように指定しているので、何もせず make する -だけで通る筈です。 + 文字コードを gcc で変換するように指定しているので、何もせず make するだけで +通るはずです。 ● FreeBSD -※ サポート担当者の手元に開発環境がないため、make してません。そのため何 - か不具合があるかも知れません。 - - version 3.00 発表後に、M.Suzuki 氏から dis を FreeBSD 上でコンパイルす -る為の差分を contribute していただき、それを参考にして正式に FreeBSD に -対応しました。これにより、FreeBSD 上で Human68k 用のバイナリファイルを逆 -アセンブルする、クロス開発環境が実現しています。 + version 3.00 発表後に、M.Suzuki 氏から dis を FreeBSD 上でコンパイルするため +の差分を contribute していただき、それを参考にして正式に FreeBSD に対応しまし +た。これにより、FreeBSD 上で Human68k 用のバイナリファイルを逆アセンブルする、 +クロス開発環境が実現しています。 - FreeBSD で make するには、予め nkf などを使用してソースファイルの文字 + FreeBSD で make するには、あらかじめ nkf などを使用してソースファイルの文字 コードを日本語 EUC に変換して下さい。 -ソースコードでは __HUMAN68K__、__LIBC__、__BIG_ENDIAN__ などの定義を参照 -しています。多分 NetBSD でもコンパイル出来ると思います。 + ソースコードでは __HUMAN68K__、__LIBC__、__BIG_ENDIAN__ などの定義を参照して +います。多分 NetBSD でもコンパイルできると思います。 - FreeBSD クロス版の発案は M.Suzuki 氏によるものですが、正式バージョンへ -の取り込みは全て私自身によるコーディングなので、何か不具合があれば私の方 -に連絡願います。 + FreeBSD クロス版の発案は M.Suzuki 氏によるものですが、正式バージョンへの取り +込みは全て TcbnErik によるコーディングなので、何か不具合があれば私の方に連絡願 +います。 -● それ以外の OS への移植 +● OS-9/X680x0 + + 対応していません。ただし、コンパイルできる環境でマクロ OSKDIS を定義すれば +OS-9/X680x0 用の実行ファイルを逆アセンブルする dis が作成されます。 - 以下の調整をして下さい。 -・M68000 のようなビッグエンディアン環境で、マクロ __BIG_ENDIAN__ が定義 - されない場合は Makefile で自前で定義します。 +● それ以外の OS への移植 -・ソースファイルの文字コードが SHIFT-JIS なので、違う文字コードを使う環 -境では nkf などで変換するか、コンパイラのオプションで指定します。 + 以下の調整をして下さい。 -・src/estruct.h で定義している構造体で GCC 拡張機能の - __attribute__ ((packed)) - を使っているので、GCC 以外では同等の機能への置き換えが必要です。 +・リポジトリにあるソースファイルの文字コードが UTF-8 なので、適宜文字コードを + 変換するか、コンパイラのオプションで指定します。 -・strupr() や strtox() など、標準的でない関数の有無で Makefile を書き換 - えます。 +・M68000 のようなビッグエンディアン環境で、マクロ __BIG_ENDIAN__ が定義されな + い場合は Makefile で自前で定義します。 +・strtox() など、標準的でない関数の有無で Makefile を書き換えます。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ - X680x0/Human68k での再コンパイル方法 +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -──────────────────────────────────── + X680x0/Human68k での再コンパイル方法 - 完全な再コンパイルには、long double(12バイト)に対応している sprintf() -と、文字列を long double に変換する strtox() が必要です。 +─────────────────────────────────────── - strtox() は HAS の fexpr.s からコードを抜き出すと楽に作れますが、 -sprintf() が long double に対応していないと意味がありません。 + 完全な再コンパイルには、long double(12バイト)に対応している sprintf() と、文 +字列を long double に変換する strtox() が必要です。 + strtox() は HAS の fexpr.s からコードを抜き出すと楽に作れますが、sprintf() +が long double に対応していないと意味がありません。 -1) ライブラリの設定 -Makefile の LIBFLAGS を、持っていないライブラリをリンクしないように修正 -します。 - libld.a がない場合 -lld を削除します - libhdi.a 〃 -lhdi 〃 - libhmem.a 〃 -lhmem 〃 +(1) ライブラリの設定 -なお、libioctl.a を持っている人は -lioctl を追加するのも良いでしょう。 + Makefile の LIBFLAGS を、持っていないライブラリをリンクしないように修正しま +す。 + libld.a がない場合 -lld を削除します + libhdi.a 〃 -lhdi 〃 + libhmem.a 〃 -lhmem 〃 -2) sprintf() の long double 対応有無 + なお、libioctl.a を持っている人は -lioctl を追加するのも良いでしょう。 -sprintf() が long double に対応していない場合は、Makefile の FUNCCFLAGS -に -DNO_PRINTF_LDBL を追加します。 +(2) sprintf() の long double 対応有無 -LIBC や libhdi は対応していません。 + sprintf() が long double に対応していない場合(LIBC や libhdi は対応していま +せん)は、Makefile の FUNCCFLAGS に -DNO_PRINTF_LDBL を追加します。 -3) strtox() の有無 +(3) strtox() の有無 strtox() がない場合は FUNCCFLAGS から -DHAVE_STRTOX を削除します。 更に、fpconv.c:fpconv_x() の以下の部分を調整します。 - #ifndef HAVE_STRTOX - || e <= 64 /* ライブラリに依存 */ - #endif - -ただし、-DNO_PRINTF_LDBL を追加した場合は使わないので、そのままで構いま -せん。 - -4) (好みで) ファイル上書き確認時の問い合せ - -標準では Yes/No/Rename 入力後にリターンキーを押さないと続行されません。 -'y' キーなどを押しただけで続行したい場合は、Makefile の DEFAULTCFLAGS -に -DQUICK_YES_NO を追加します。 - -5) (好みで) fefunc.h の読み込み - -dis 実行時に fefunc.mac ではなく fefunc.h を読み込むようにする場合は、同 -じく -DREAD_FEFUNC_H を追加します。 - -6) make - -make を実行します。 - + #ifndef HAVE_STRTOX + || e <= 64 // ライブラリに依存 + #endif -● コンパイル時の警告表示について + ただし、-DNO_PRINTF_LDBL を追加した場合は使わないので、そのままで構いません。 -1. analyze.c の - register void* sp __asm ("sp"); -この部分で変数未初期化警告が出ます。gcc の asm 文の取り扱いに由来するよ -うですが、出ないようにすると僅かですが効率が悪くなるので放置しています。 +(4) (好みで) ファイル上書き確認時の問い合せ -2. eval.y を bison-1.28 で処理すると、eval.c のコンパイルで10進定数が大 -きすぎるという警告が大量に出ます。bison が short を int に符合拡張してい -るのが原因のようです。bison のバージョンが違えば警告は出なくなるかも知れ -ません。dis のソース側で対処できないと思うので、そのままにしています。 + 標準では Yes/No/Rename 入力後にリターンキーを押さないと続行されません。'y' +キーなどを押しただけで続行したい場合は、Makefile の DEFAULTCFLAGS に +-DQUICK_YES_NO を追加します。 -3. X680x0/Human68k 以外では、label.c のコンパイル時に avl.c で - AVL_destroy_tree() - AVL_search_previous() - AVL_check_tree() -が使われていないという警告が出る場合がありますが、その通りの意味です。 +(5) make -実行ファイルに多少無駄が生じますが、avl.c はあまりいじりたくなかったので -そのままにしてあります。 + make を実行します。 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ diff --git a/src/search.c b/src/search.c index b4405c4..035e8b2 100644 --- a/src/search.c +++ b/src/search.c @@ -1,177 +1,138 @@ -/* $Id: search.c,v 1.1 1996/11/07 08:03:58 ryo freeze $ - * - * ソースコードジェネレータ - * 文字列判定 - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#include +// ソースコードジェネレータ +// 文字列判定 +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + #include #include #include "estruct.h" -#include "etc.h" /* charout, */ +#include "etc.h" /* charout, */ #include "global.h" -#include "label.h" /* regist_label etc. */ -#include "offset.h" /* depend_address, nearadrs */ - - -/* #define DEBUG */ - +#include "label.h" /* regist_label etc. */ +#include "offset.h" /* depend_address, nearadrs */ -static INLINE void -foundstr (address pc, address ltemp) -{ - charout ('s'); -#ifdef DEBUG - printf (" * FOUND STRING AT %x - %x \n", pc, ltemp); -#endif - regist_label (pc, DATLABEL | STRING); +static void foundstr(address pc) { + charout('s'); + regist_label(pc, DATLABEL | STRING); } - /* 文字列かどうかを調べる *newend = last string address */ -private boolean -is_string (address from, address end, address* newend, int str_min) -{ - unsigned char* store; - -#ifdef DEBUG - printf (" * is_string %x - %x\n", from, end); -#endif - *newend = end; - store = from + Ofst; - - while (store - Ofst < end) { - unsigned char c = *store++; - - if (isprkana (c)) /* ANK 文字 */ - ; - else if (iskanji (c)) { /* 全角文字 */ - if (!iskanji2 (*store++)) - return FALSE; - } - else if (c == 0x80) { /* 半角ひらがな */ - c = *store++; - if (c < 0x86 || 0xfc < c) - return FALSE; - } - else { - switch (c) { - case 0x07: /* BEL */ - case 0x09: /* TAB */ - case 0x0d: /* CR */ - case 0x0a: /* LF */ - case 0x1a: /* EOF */ - case 0x1b: /* ESC */ - break; - - case 0x00: /* NUL */ - /* 10 億が .dc.b ';毀',0 にならないようにする */ - if (((int) store & 1) == 0 - && peekl (store - sizeof (ULONG)) == 1000000000L - && (store - sizeof (ULONG) - Ofst) == from) - return FALSE; - - if (from + str_min < store - Ofst) { - while (store - Ofst < end && !*store) - store++; - *newend = (address) min ((ULONG) (store - Ofst), (ULONG) end); - return TRUE; - } - return FALSE; - default: - return FALSE; - } - } +static boolean is_string(address from, address end, address* newend, + int str_min) { + UBYTE* store = (UBYTE*)(from + Dis.Ofst); + UBYTE* stend = (UBYTE*)(end + Dis.Ofst); + + *newend = end; + + // .dc.l 1000000000 が .dc.b ';毀',0 にならないようにする + if (isEven(from) && (end - from) >= sizeof(ULONG)) { + if (peekl(store) == 1000000000) return FALSE; + } + + while (store < stend) { + char c = *store++; + + if (isprkana(c)) /* ANK 文字 */ + ; + else if (iskanji(c)) { /* 全角文字 */ + if (!iskanji2(*store++)) return FALSE; + } else if (c == 0x80) { /* 半角ひらがな */ + c = *store++; + if (c < 0x86 || 0xfc < c) return FALSE; + } else { + switch (c) { + case 0x07: /* BEL */ + case 0x09: /* TAB */ + case 0x0d: /* CR */ + case 0x0a: /* LF */ + case 0x1a: /* EOF */ + case 0x1b: /* ESC */ + break; + + case 0x00: /* NUL */ + if (from + str_min < store - Dis.Ofst) { + while (store < stend && !*store) store++; + *newend = MIN((address)(store - Dis.Ofst), end); + return TRUE; + } + return FALSE; + default: + return FALSE; + } } + } - if (from + str_min <= store - Ofst) { - *newend = (address) min ((ULONG) (store - Ofst), (ULONG) end); - return TRUE; - } - return FALSE; + if (from + str_min <= store - Dis.Ofst) { + *newend = MIN((address)(store - Dis.Ofst), end); + return TRUE; + } + return FALSE; } - /* pc から nlabel までのデータ領域中の文字列をチェック */ -private int -check_data_area (address pc, address nlabel, int str_min) -{ - int num_of_str = 0; - -#ifdef DEBUG - printf ("* check_data_area %x - %x \n", pc, nlabel); -#endif - - while (pc < nlabel) { - address ltemp, nlabel2; - - nlabel2 = ltemp = (address) min ((ULONG) nearadrs (pc), (ULONG) nlabel); - while (pc < nlabel2) { - if (is_string (pc, ltemp, <emp, str_min)) { - foundstr (pc, ltemp); - num_of_str++; - while (depend_address (ltemp) && ltemp + 4 <= nlabel2) - ltemp += 4; - regist_label (ltemp, DATLABEL | UNKNOWN); - pc = ltemp; - ltemp = (address) min ((ULONG) nearadrs (pc), (ULONG) nlabel); - } - else - pc = nlabel2; - } - while (depend_address (pc)) - pc += 4; +static int check_data_area(address pc, address nlabel, int str_min) { + int num_of_str = 0; + + while (pc < nlabel) { + address ltemp, nlabel2; + + nlabel2 = ltemp = MIN(nearadrs(pc), nlabel); + while (pc < nlabel2) { + if (is_string(pc, ltemp, <emp, str_min)) { + foundstr(pc); + num_of_str++; + while (depend_address(ltemp) && ltemp + 4 <= nlabel2) ltemp += 4; + regist_label(ltemp, DATLABEL | UNKNOWN); + pc = ltemp; + ltemp = MIN(nearadrs(pc), nlabel); + } else + pc = nlabel2; } + while (depend_address(pc)) pc += 4; + } - return num_of_str; + return num_of_str; } - /* 文字列サーチ 文字列として認識した数を返す */ -extern int -search_string (int str_min) -{ - lblbuf* nadrs = next (BeginTEXT); - lblmode nmode = nadrs->mode; - address pc = nadrs->label; /* 最初 */ - int num_of_str = 0; - - while (pc < BeginBSS) { - lblmode mode = nmode; - address nlabel; - - charout ('.'); - nadrs = Next (nadrs); /* nadrs = next (pc + 1); */ - nlabel = nadrs->label; - nmode = nadrs->mode; - - if (isDATLABEL (mode) && (mode & 0xff) == UNKNOWN) - num_of_str += check_data_area (pc, nlabel, str_min); - - pc = nlabel; - } +extern int search_string(int str_min) { + lblbuf* nadrs = next(Dis.beginTEXT); + lblmode nmode = nadrs->mode; + address pc = nadrs->label; /* 最初 */ + int num_of_str = 0; - return num_of_str; -} + while (pc < Dis.beginBSS) { + lblmode mode = nmode; + address nlabel; + + charout('.'); + nadrs = Next(nadrs); /* nadrs = next (pc + 1); */ + nlabel = nadrs->label; + nmode = nadrs->mode; + if (isDATLABEL(mode) && lblmodeOpesize(mode) == UNKNOWN) + num_of_str += check_data_area(pc, nlabel, str_min); + + pc = nlabel; + } + + return num_of_str; +} /* EOF */ diff --git a/src/symbol.c b/src/symbol.c index baa2282..0c65b47 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -1,304 +1,400 @@ -/* $Id: symbol.c,v 1.1 1996/11/07 08:04:02 ryo freeze $ - * - * ソースコードジェネレータ - * シンボルネーム管理モジュール - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// シンボルネーム管理モジュール +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "symbol.h" #include #include -#include "estruct.h" #include "etc.h" #include "global.h" -#include "hex.h" /* itoxd() */ +#include "hex.h" // itoxd() #include "label.h" -#include "output.h" /* outputf() */ -#include "symbol.h" - - -USEOPTION option_g; -short Output_Symbol = 1; /* 0:しない 1:定数のみ 2:.xdef も */ - +#include "opstr.h" +#include "output.h" + +// X形式実行ファイルのシンボルテーブルの構造 +enum { + XSYM_TYPE = 0, + XSYM_ADRS = 2, + XSYM_NAME = 6, // 文字列+even +}; + +typedef struct { + codeptr name; + size_t nameLen; + address adrs; + ULONG type; +} SymbolTable; + +#define SYM_BUF_UNIT 16 // バッファ拡大時の増加要素数 +static int Symbolbufsize; // シンボルバッファの数 +static symbol* Symtable; // シンボルテーブルの頭 +static int Symnum; // シンボルテーブルの要素数 + +// "Lxxxxxx" 形式のラベル文字列を作成し、文字列末尾を返す +char* makeBareLabel(SymbolLabelFormula* slfml, address adrs) { + char* p = slfml->expr; + *p++ = Dis.labelChar; + return itox6_without_0supress(p, (ULONG)adrs); +} -#define SYM_BUF_UNIT 16 /* バッファ拡大時の増加要素数 */ -static int Symbolbufsize; /* シンボルバッファの数 */ -static symbol* Symtable; /* シンボルテーブルの頭 */ -static int Symnum; /* シンボルテーブルの要素数 */ +// ラベルorシンボル名(±オフセット)形式のラベル文字列を作成する +static void makeSymLabShift(SymbolLabelFormula* slfml, address adrs, + LONG shift) { + char* p = slfml->expr; + symbol* symptr = symbol_search(adrs); + + if (symptr) { + slfml->symbol = symptr->first.sym; + *p = '\0'; + } else { + slfml->symbol = ""; + p = makeBareLabel(slfml, adrs); + } + + if (shift) { + *p++ = '+'; + if (shift < 0) { + p[-1] = '-'; + shift = -shift; + } + itox6d(p, shift); + } +} +// ラベルorシンボル名のラベル式を作成する +// プログラム範囲外のアドレスはプログラム先頭または末尾からの +// ±オフセット形式になる。 +void makeInProgSymLabFormula(SymbolLabelFormula* slfml, address adrs) { + LONG shift = 0; + + if ((LONG)adrs < (LONG)Dis.beginTEXT) { + shift = (LONG)adrs - (LONG)Dis.beginTEXT; + adrs = Dis.beginTEXT; + } else if (Dis.LAST < adrs) { + shift = (LONG)adrs - (LONG)Dis.LAST; + adrs = Dis.LAST; + } + makeSymLabShift(slfml, adrs, shift); +} -extern void -init_symtable (void) -{ +// ラベルorシンボル名(±オフセット)形式のラベル式を作成する +// ラベルが登録されていなかった場合はFALSEを返す +void makeSymLabFormula(SymbolLabelFormula* slfml, address adrs) { + lblbuf* lptr; + + if (((LONG)adrs < (LONG)Dis.beginTEXT) || (Dis.LAST < adrs)) { + if (Dis.outputSymbol == OUTPUT_SYMBOL_ALL) { + symbol* symptr = symbol_search(adrs); + if (symptr) { + // プログラム範囲外でも、-s2かつ該当アドレスのシンボルが存在するなら + // シンボル定義が出力されるので参照してよい + slfml->symbol = symptr->first.sym; + slfml->expr[0] = '\0'; + return; + } + } + // シンボル定義が出力されないなら、beginTEXT/LASTからのオフセット形式にする + makeInProgSymLabFormula(slfml, adrs); return; + } + + // プログラム範囲内 + lptr = search_label(adrs); + if (lptr == NULL) { + slfml->symbol = ""; + makeBareLabel(slfml, adrs); + } else { + makeSymLabShift(slfml, adrs - lptr->shift, lptr->shift); + } } -/* - - 後始末 - - シンボル名リストとシンボル名バッファも解放する必要があるけど手抜き. +// シンボル名の文字列長により必要なタブを返す +static const char* getPaddingTab(SymbolTable* st, const char* colon) { + size_t n = TAB_WIDTH - strlen(colon); + return (st->nameLen < n) ? "\t" : ""; +} -*/ -extern void -free_symbuf (void) -{ - Mfree (Symtable); +// 定数シンボルの外部宣言を出力する +// 「xxx:: .equ $nn」の形式で出力する +static int outputSymbolEqu(SymbolTable* st, const char* colon) { + char buf[16]; + const char* array[] = { + (char*)st->name, colon, getPaddingTab(st, colon), OpString.equ, buf // + }; + + itox8d(buf, (ULONG)st->adrs); + outputDirectiveArray(LINETYPE_OTHER, (address)0, _countof(array), array); + return 1; } -extern boolean -is_exist_symbol (void) -{ - return Symnum ? TRUE : FALSE; +// シンボルの外部宣言を出力する +static int outputSymbolXdef(SymbolTable* st, const char* colon) { + address adrs = st->adrs; + + if (adrs < Dis.beginTEXT || Dis.LAST < adrs) { + // プログラム範囲外ならラベル定義行が出力されないので + // foo:: .equ L000000-$10 のような形式で定義する + SymbolLabelFormula slfml; + makeInProgSymLabFormula(&slfml, adrs); + + { + const char* array[] = { + (char*)st->name, colon, getPaddingTab(st, colon), + OpString.equ, slfml.symbol, slfml.expr // + }; + outputDirectiveArray(LINETYPE_OTHER, (address)0, _countof(array), array); + } + return 1; + } else { + // .xdef foo + const char* array[] = {"\t", OpString.xdef, (char*)st->name}; + outputDirectiveArray(LINETYPE_OTHER, (address)0, _countof(array), array); + } + + return 1; } +static int outputSymbolDefine(SymbolTable* st, int xdef, const char* colon) { + switch ((UWORD)st->type) { + default: + break; -#ifndef OSKDIS + case XDEF_ABS: + return outputSymbolEqu(st, colon); -/* - ソースコードにシンボル定義を出力する + case XDEF_COMMON: + case XDEF_TEXT: + case XDEF_DATA: + case XDEF_BSS: + case XDEF_STACK: + if (xdef) return outputSymbolXdef(st, colon); + break; + } - 引数: - op_equ .equ 疑似命令("\t.equ\t") - colon コロン("::" -C オプションによって変更) - 返値 - 出力したシンボル数(行数) + return 0; +} - Human68k の .x 型実行ファイル形式に依存. -*/ -extern int -output_symbol_table (const char* op_equ, const char* op_xdef, const char* colon) -{ - char* ptr = (char*)(Top + Head.text + Head.data + Head.offset); - ULONG end = (ULONG)ptr + Head.symbol - - (sizeof (UWORD) + sizeof (address) + 2); - int out_xdef = (Output_Symbol == 2); - int count = 0; - - if ((int)ptr & 1 || !Output_Symbol) - return count; - - while ((ULONG)ptr <= end) { - UWORD type; - address adrs; - - type = peekw (ptr); - ptr += sizeof (UWORD); - adrs = (address) peekl (ptr); - ptr += sizeof (address); - - if (*ptr && *ptr != (char)'*') { - char buf[16]; - char* tab; - - switch (type) { - case XDEF_ABS: - /* 「xxx:: .equ $nn」の形式で出力する */ - /* TAB-2 */ - tab = (strlen (ptr) < (8-2)) ? "\t" : ""; - itoxd (buf, (ULONG) adrs, 8); - outputf ("%s%s%s%s%s" CR, ptr, colon, tab, op_equ, buf); - count++; - break; - - case XDEF_COMMON: - case XDEF_TEXT: - case XDEF_DATA: - case XDEF_BSS: - case XDEF_STACK: - if (out_xdef) { - outputf ("%s%s" CR, op_xdef, ptr); - count++; - } - break; - - default: - break; - } - } - - /* 今処理したシンボルを飛ばす */ - while (*ptr++) - ; - ptr += (int)ptr & 1; +// ソースコードにシンボル定義を出力する +// 引数: +// stbuf シンボルテーブルの情報 +// opXdef .xdef疑似命令("\t.xdef\t") +// colon コロン("::" -Cオプションによって変更) +// 返値: +// 出力したシンボル数(行数) +int outputSymbolSection(ArrayBuffer* stbuf, const char* colon) { + int lines = 0; + int xdef = (Dis.outputSymbol == OUTPUT_SYMBOL_ALL); + size_t count; + SymbolTable* symbols = getArrayBufferRawPointer(stbuf, &count); + + if (symbols != NULL) { + const size_t len = count; + size_t i; + for (i = 0; i < len; ++symbols, ++i) { + lines += outputSymbolDefine(symbols, xdef, colon); } + } - return count; + freeArrayBuffer(stbuf); + return lines; } +// ラベルファイルで定義されたシンボルの属性をシンボル情報の属性に変更する +// Human68kのX形式実行ファイル形式に依存。 +static void change_sym_type(symbol* symbolptr, UWORD type, char* ptr) { + symlist* sym = &symbolptr->first; -/* - ラベルファイルで定義されたシンボルの属性を - シンボル情報の属性に変更する - - Human68k の .x 型実行ファイル形式に依存. -*/ -static void -change_sym_type (symbol* symbolptr, int type, char* ptr) -{ - symlist* sym = &symbolptr->first; + do { + if (strcmp(sym->sym, ptr) == 0) { + sym->type = type; + return; + } + sym = sym->next; + } while (sym); +} - do { - if (strcmp (sym->sym, ptr) == 0) { - sym->type = type; - return; - } - sym = sym->next; - } while (sym); +// シンボルテーブル上のシンボルの情報を表示する +static void printSymbol(const char* s, UWORD type, address adrs, + codeptr symName) { + eprintf("\n%s($%04" PRIx16 " " PRI_ADRS " \"%s\")。", s, type, adrs, symName); } -/* - 実行ファイルに付属するシンボルテーブルを登録する - ラベルファイルの読み込みより後に呼び出される +// 1個のアドレス型のシンボル情報を記録する +static void registerAddressSymbol(UWORD type, address adrs, codeptr name) { + symbol* sym = symbol_search(adrs); + + if (sym == NULL) { + // 特定アドレスの初回時はラベルを登録する + // ラベルファイル読み込み時はすでに登録されているかもしれないし、 + // 登録されていない(ラベルファイルから記述が削除されていた)可能性もある。 + regist_label(adrs, DATLABEL | UNKNOWN | SYMLABEL); + } + + if (Dis.g) { + // -g指定時はラベルファイルに記載されたシンボル名を使うので + // シンボル情報のシンボル名は無視する。属性は利用する + if (sym != NULL) change_sym_type(sym, type, (char*)name); + return; + } - Human68k の .x 型実行ファイル形式に依存. -*/ -extern void -make_symtable (void) -{ - char* ptr = (char*)(Top + Head.text + Head.data + Head.offset); - ULONG end = (ULONG)ptr + Head.symbol - - (sizeof (UWORD) + sizeof (address) + 2); - - if ((int)ptr & 1) - return; - - while ((ULONG)ptr <= end) { - UWORD type; - address adrs; - - type = peekw (ptr); - ptr += sizeof (UWORD); - adrs = (address) peekl (ptr); - ptr += sizeof (address); - - if (!*ptr) { -#if 0 - eprintf ("シンボル名が空文字列です(%#.6x %#.6x)", type, adrs); -#endif - } else if (*ptr == (char)'*') { - eprintf ("アドレス境界情報のシンボルです(%#.6x %#.6x %s)\n", - type, adrs, ptr); - } - - else { - symbol* sym; - - /* スタックサイズの収得 */ - if (type == XDEF_STACK && BeginBSS <= adrs && adrs < BeginSTACK) - BeginSTACK = adrs; - - switch (type) { - case XDEF_ABS: - break; - - case XDEF_COMMON: - type = XDEF_BSS; - /* fall through */ - case XDEF_STACK: - case XDEF_TEXT: - case XDEF_DATA: - case XDEF_BSS: - sym = symbol_search (adrs); - - if (!sym) - regist_label (adrs, DATLABEL | UNKNOWN | SYMLABEL); - - /* -g 指定時はシンボルテーブルから登録しない */ - /* ただし、属性だけは利用する */ - if (!option_g) - add_symbol (adrs, type, ptr); - else if (sym) - change_sym_type (sym, type, ptr); - break; - - default: - eprintf ("未対応のシンボル情報です(%#.6x %#.6x %s)\n", - type, adrs, ptr); - break; - - } - } - - /* 今処理したシンボルを飛ばす */ - while (*ptr++) - ; - ptr += (int)ptr & 1; - } + add_symbol(adrs, type, (char*)name); } +// 1個のシンボル情報を記録する +static void registerSymbol(ArrayBuffer* stbuf, UWORD type, address adrs, + codeptr name, size_t nameLen) { + SymbolTable* p = getArrayBufferNewPlace(stbuf); + *p = (SymbolTable){name, nameLen, adrs, type}; + + // スタックサイズの指定 + if (type == XDEF_STACK && Dis.beginBSS <= adrs && adrs < Dis.beginSTACK) + Dis.beginSTACK = adrs; + + switch (type) { + default: + printSymbol("未対応のシンボル情報です", type, adrs, name); + break; + + case XDEF_ABS: + break; + + case XDEF_COMMON: + type = XDEF_BSS; + // FALLTHRU + case XDEF_STACK: + case XDEF_TEXT: + case XDEF_DATA: + case XDEF_BSS: + registerAddressSymbol(type, adrs, name); + break; + } +} -/* - 指定した属性のシンボルを探す -*/ -extern symlist* -symbol_search2 (address adrs, int type) -{ - symbol* symbolptr = symbol_search (adrs); +// シンボル名の文字列長を調べる +// 0: 空文字列 -1:NULがない +static int getSymbolNameLength(codeptr name, ULONG rest) { + UBYTE* p = (UBYTE*)name; - if (symbolptr) { - symlist* sym = &symbolptr->first; + do { + if (rest == 0) return -1; + rest -= 1; + } while (*p++); - while (sym->type != (UWORD)type && (sym = sym->next)) - ; - return sym; - } - return (symlist*)NULL; + return (int)(p - 1 - (UBYTE*)name); } -#endif /* !OSKDIS */ +static void parseSymbolTableLoop(ArrayBuffer* stbuf, ULONG start) { + codeptr ptr = Dis.Top + start; + ULONG rest = Dis.symbol; + + while (rest > XSYM_NAME) { + ULONG size; + UWORD type = peekw(ptr + XSYM_TYPE); + address adrs = peekl(ptr + XSYM_ADRS); + codeptr name = ptr + XSYM_NAME; + int nameLen = getSymbolNameLength(name, rest - XSYM_NAME); + + if (nameLen <= 0) { + eprintf(nameLen ? "シンボル名がNULで終わっていません。\n" + : "シンボル名が空文字列です。\n"); + } else { + registerSymbol(stbuf, type, adrs, name, nameLen); + } + + size = XSYM_NAME + nameLen + 1; + if (size & 1) size += 1; + rest -= size; + ptr += size; + } + if (rest > 0) + eprintf("シンボル情報の末尾に" PRI_ULONG + "バイトの未対応のデータがあります。\n", + rest); +} +// Human68kのX形式実行ファイルに付属するシンボルテーブルを解析する +// Symtable に登録(ラベル名の置換用)。 +// Dis.symtblArray に登録(シンボル定義セクション出力用)。 +// +// ラベルファイルの読み込みより後に呼び出される +void parseSymbolTableHuman(ArrayBuffer* stbuf) { + initArrayBuffer(stbuf, sizeof(SymbolTable)); + + if (Dis.symbol == 0) { + eprintf("シンボルテーブルは残念ながら存在しません。\n"); + } else { + ULONG start = Dis.text + Dis.data + Dis.offset; + + if (start & 1) { + eprintf("シンボルテーブルが奇数アドレスからはじまっています。\n"); + } else { + eprintf("シンボルテーブルを展開します。\n"); + parseSymbolTableLoop(stbuf, start); + } + } -extern void -add_symbol (address adrs, int type, char *symstr) -{ /* type == 0 : labelfileでの定義 */ - int i; - symbol* sym = symbol_search (adrs); + freezeArrayBuffer(stbuf); +} - /* 既に登録済みならシンボル名を追加する */ - if (sym) { - symlist* ptr = &sym->first; +// type == 0 : labelfileでの定義 +extern void add_symbol(address adrs, int type, char* symstr) { + int i; + symbol* sym = symbol_search(adrs); - while (ptr->next) - ptr = ptr->next; + /* 既に登録済みならシンボル名を追加する */ + if (sym) { + symlist* ptr = &sym->first; - /* symlist を確保して、末尾に繋げる */ - ptr = ptr->next = Malloc (sizeof (symlist)); + while (ptr->next) ptr = ptr->next; - /* 確保した symlist を初期化 */ - ptr->next = NULL; - ptr->type = (UWORD)type; - ptr->sym = symstr; + /* symlist を確保して、末尾に繋げる */ + ptr = ptr->next = Malloc(sizeof(symlist)); - return; - } + /* 確保した symlist を初期化 */ + ptr->next = NULL; + ptr->type = (UWORD)type; + ptr->sym = symstr; - if (Symnum == Symbolbufsize) { - /* バッファを拡大する */ - Symbolbufsize += SYM_BUF_UNIT; - Symtable = Realloc (Symtable, Symbolbufsize * sizeof (symbol)); - } + return; + } - for (i = Symnum - 1; (i >= 0) && (Symtable[ i ].adrs > adrs); i--) - Symtable[ i + 1 ] = Symtable[ i ]; + if (Symnum == Symbolbufsize) { + /* バッファを拡大する */ + Symbolbufsize += SYM_BUF_UNIT; + Symtable = Realloc(Symtable, Symbolbufsize * sizeof(symbol)); + } - Symnum++; - sym = &Symtable[ ++i ]; - sym->adrs = adrs; + for (i = Symnum - 1; (i >= 0) && (Symtable[i].adrs > adrs); i--) + Symtable[i + 1] = Symtable[i]; - /* 最初のシンボルを記録 */ - sym->first.next = NULL; - sym->first.type = (UWORD)type; - sym->first.sym = symstr; + Symnum++; + sym = &Symtable[++i]; + sym->adrs = adrs; -#ifdef DEBUG - printf ("type %.4x adrs %.6x sym:%s\n", sym->first.type, sym->.adrs, sym->first.sym); -#endif + /* 最初のシンボルを記録 */ + sym->first.next = NULL; + sym->first.type = (UWORD)type; + sym->first.sym = symstr; } +// 指定した属性のシンボルを探す +symlist* symbol_search2(address adrs, int type) { + symbol* symbolptr = symbol_search(adrs); + + if (symbolptr) { + symlist* sym = &symbolptr->first; + + while (sym->type != (UWORD)type && (sym = sym->next)) + ; + return sym; + } + return NULL; +} /* @@ -307,54 +403,25 @@ add_symbol (address adrs, int type, char *symstr) 見つかったらポインタ、でなければ NULL を返す */ -extern symbol* -symbol_search (address adrs) -{ - int step; - symbol* ptr; - - /* 多少は速くなる? */ - if (Symnum == 0) - return NULL; - - ptr = Symtable; - for (step = Symnum >> 1; step > 4; step >>= 1) - if ((ptr + step)->adrs <= adrs) /* binary search */ - ptr += step; - - for (; ptr < Symtable + Symnum; ptr++) { - if (ptr->adrs == adrs) - return ptr; - else - if (adrs < ptr->adrs) - return NULL; - } - return NULL; -} - - -/* 以下は未使用関数 */ - -#if 0 -extern void -del_symbol (address adrs) -{ - symbol* sym = symbol_search (adrs); - - if (sym) { - symlist* ptr = sym->first.next; - - while (ptr) { - symlist* next = ptr->next; - Mfree (ptr); - ptr = next; - } - - Symnum--; - for (; sym < &Symtable[ Symnum ]; sym++) - *sym = *(sym + 1); - } +extern symbol* symbol_search(address adrs) { + int step; + symbol* ptr; + + /* 多少は速くなる? */ + if (Symnum == 0) return NULL; + + ptr = Symtable; + for (step = Symnum >> 1; step > 4; step >>= 1) + if ((ptr + step)->adrs <= adrs) /* binary search */ + ptr += step; + + for (; ptr < Symtable + Symnum; ptr++) { + if (ptr->adrs == adrs) + return ptr; + else if (adrs < ptr->adrs) + return NULL; + } + return NULL; } -#endif -/* EOF */ +// EOF diff --git a/src/symbol.h b/src/symbol.h index 92b0cdd..7e04f92 100644 --- a/src/symbol.h +++ b/src/symbol.h @@ -1,58 +1,54 @@ -/* $Id: symbol.h,v 1.1 1996/10/24 04:27:50 ryo freeze $ - * - * ソースコードジェネレータ - * シンボルネーム管理モジュールヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// シンボルネーム管理モジュールヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -#ifndef SYMBOL_H -#define SYMBOL_H +#ifndef SYMBOL_H +#define SYMBOL_H +#include "estruct.h" +#include "etc.h" // strcpy2() + +typedef struct { + char* symbol; // シンボル名 or "" + char expr[24]; // "L123456+$12345678" +} SymbolLabelFormula; typedef struct _symlist { - struct _symlist* next; - UWORD type; - char* sym; + struct _symlist* next; + UWORD type; + char* sym; } symlist; typedef struct { - address adrs; - symlist first; + address adrs; + symlist first; } symbol; +enum { + XDEF_COMMON = 0x0003, + XDEF_ABS = 0x0200, + XDEF_TEXT = 0x0201, + XDEF_DATA = 0x0202, + XDEF_BSS = 0x0203, + XDEF_STACK = 0x0204, +}; + +extern char* makeBareLabel(SymbolLabelFormula* slfml, address adrs); +extern void makeInProgSymLabFormula(SymbolLabelFormula* slfml, address adrs); +extern void makeSymLabFormula(SymbolLabelFormula* slfml, address adrs); +extern int outputSymbolSection(ArrayBuffer* stbuf, const char* colon); +extern void parseSymbolTableHuman(ArrayBuffer* stbuf); +extern void add_symbol(address, int, char*); +extern symbol* symbol_search(address); +extern symlist* symbol_search2(address adrs, int type); + +// ラベル式をバッファに転送して文字列末尾のアドレスを返す +static inline char* catSlfml(char* p, SymbolLabelFormula* slfml) { + return strcpy2(strcpy2(p, slfml->symbol), slfml->expr); +} -#ifndef OSKDIS -#define XDEF_COMMON 0x0003 -#define XDEF_ABS 0x0200 -#define XDEF_TEXT 0x0201 -#define XDEF_DATA 0x0202 -#define XDEF_BSS 0x0203 -#define XDEF_STACK 0x0204 -#endif - - -extern void init_symtable (void); -extern void free_symbuf (void); -extern boolean is_exist_symbol (void); -#ifndef OSKDIS -extern int output_symbol_table (const char*, const char*, const char*); -extern void make_symtable (void); -extern symlist* symbol_search2 (address adrs, int type); #endif -extern void add_symbol (address, int, char*); -extern symbol* symbol_search (address); - -#if 0 -extern void del_symbol (address); -#endif - - -extern short Output_Symbol; - - -#endif /* SYMBOL_H */ -/* EOF */ +// EOF diff --git a/src/table.c b/src/table.c index 788ba4a..7620ec5 100644 --- a/src/table.c +++ b/src/table.c @@ -1,362 +1,353 @@ -/* $Id: table.c,v 1.1 1996/10/24 04:27:40 ryo freeze $ - * - * ソースコードジェネレータ - * テーブル処理モジュール - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#include /* isdigit, isxdigit */ +// ソースコードジェネレータ +// テーブル処理モジュール +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#include "table.h" + +#include /* isdigit, isxdigit */ #include -#include /* atoi */ +#include /* atoi */ #include -#include #include "estruct.h" #include "etc.h" +#include "eval.h" #include "global.h" -#include "hex.h" /* strend */ #include "label.h" #include "labelfile.h" -#include "offset.h" /* depend_address */ -#include "table.h" +#include "offset.h" /* depend_address */ +static table* Table; +static int TableCounter; +static int Line_num; -USEOPTION option_q; - -extern int Quiet_mode; - - -static table* Table; -static int TableCounter; -static int Line_num; - - -/* table.loop mode */ -#define TIMES_AUTOMATIC 0 -#define TIMES_DECIDE_BY_BREAK -1 -#define eprintfq if( option_q && Quiet_mode < 1 ) eprintf - - -#ifdef DEBUG -#define debug(str) printf (str) -#else -#define debug(str) -#endif - - -private void -interpret (table* table_ptr) -{ - extern int yyparse (void); - - formula* cur_expr = table_ptr->formulaptr; - address pc0 = 0; - int i, loop = 0; - lblbuf* lblptr = NULL; - boolean in_bss; - address limit; - - Eval_TableTop = Eval_PC = table_ptr->tabletop; - ParseMode = PARSE_ANALYZING; - - in_bss = (BeginBSS <= Eval_PC) ? TRUE : FALSE; - limit = in_bss ? Last : BeginBSS; - -#if 0 - if (BeginBSS <= Eval_PC) -#else - if (Last <= Eval_PC) /* BSS にもテーブルを認める */ -#endif - return; - - do { - for (i = 0; i < table_ptr->lines; i++) { - Eval_Count = 0; /* First, Eval_Count is set in yyparse() */ - do { - Lexptr = cur_expr[i].expr; - eprintfq ("[%d:%06x]:%s\n", loop + 1, Eval_PC, Lexptr); - if (yyparse() == 1) - err ("Syntax error (%d 行)\n", cur_expr[i].line); - - cur_expr[i].id = Eval_ID; - pc0 = Eval_PC; - - if (depend_address (Eval_PC) - && Eval_ID != LONGSIZE && Eval_ID != EVENID -#if 0 - && Eval_ID != LONGID -#endif - && Eval_ID != BREAKID && Eval_ID != CRID) { - if (table_ptr->loop == TIMES_AUTOMATIC) { - debug ("depend chk"); - goto tableend; - } - err ("アドレス依存部でロングワード指定されていません(%x)\n", Eval_PC); - } - -#define BSS_CHECK(idstr) ({ if (in_bss) goto bss_error; }) -#define ODD_CHECK(size) ({ \ - if ((int)Eval_PC & 1) \ - eprintf ("Warning: 奇数アドレス(%x)で%s指定されています.\n", Eval_PC, size); \ - }) - - switch (Eval_ID) { - case LONGSIZE: - ODD_CHECK ("ロングワード"); - Eval_PC += 4; - break; - case WORDSIZE: - ODD_CHECK ("ワード"); - Eval_PC += 2; - break; - case BYTESIZE: - Eval_PC++; - break; - - case SINGLESIZE: - ODD_CHECK ("単精度実数"); - Eval_PC += 4; - break; - case DOUBLESIZE: - ODD_CHECK ("倍精度実数"); - Eval_PC += 8; - break; - case EXTENDSIZE: - ODD_CHECK ("拡張精度実数"); - Eval_PC += 12; - break; - case PACKEDSIZE: - ODD_CHECK ("パックドデシマル"); - Eval_PC += 12; - break; -#if 0 - case LONGID: - BSS_CHECK ("long"); - ODD_CHECK ("ロングワード"); - Eval_PC += Eval_Bytes*4; - break; - case WORDID: - BSS_CHECK ("word"); - ODD_CHECK ("ワード"); - Eval_PC += Eval_Bytes*2; - break; -#endif - case BYTEID: - BSS_CHECK ("byte"); - Eval_PC += Eval_Bytes; - break; - case ASCIIID: - BSS_CHECK ("ascii"); - Eval_PC += Eval_Bytes; - break; - case ASCIIZID: - BSS_CHECK ("asciiz"); - while (PEEK_BYTE (Eval_PC)) - Eval_PC++; - break; - case LASCIIID: - BSS_CHECK ("lascii"); - Eval_PC += PEEK_BYTE (Eval_PC) + 1; - break; - case EVENID: - if ((long)Eval_PC & 1) - Eval_PC++; - break; - case CRID: - break; - case BREAKID: - if (Eval_Break) { - debug ("break"); - loop++; - goto tableend; - } - break; - default: /* reduce warning message */ - break; - } -#undef ODD_CHECK -#undef BSS_CHECK - - if (limit <= Eval_PC - || (table_ptr->loop == TIMES_AUTOMATIC - && ((lblptr = next (pc0 + 1)) == NULL - || Eval_PC >= lblptr->label))) { - loop++; - /* _________ これでいい? */ - if (lblptr && Eval_PC > lblptr->label) - Eval_PC = pc0; - debug ("exceeded next label"); - goto tableend; - } -#if 0 - if (Eval_ID != BREAKID && Eval_ID != CRID) - if (!regist_label (pc0, DATLABEL | Eval_ID)) - eprintf ("??? address %x", pc0); -#endif - Eval_Count--; - } while (Eval_Count > 0); - } - loop++; - } while ((Eval_PC < limit - && (table_ptr->loop == TIMES_AUTOMATIC - && (lblptr = next (pc0 + 1)) != NULL && Eval_PC < lblptr->label) - ) - || table_ptr->loop == TIMES_DECIDE_BY_BREAK - || (table_ptr->loop != TIMES_AUTOMATIC && loop < table_ptr->loop)); +// table.loop mode +enum { + TIMES_AUTOMATIC = 0, + TIMES_DECIDE_BY_BREAK = -1, +}; -tableend: - eprintfq ("Table は %x - %x (%d個)と判断しました\n", - Eval_TableTop, Eval_PC, loop); +#define eprintfq \ + if (!Dis.quietTable) eprintf - if (!regist_label (Eval_PC, DATLABEL|ENDTABLE|UNKNOWN)) { -#if 0 - printf ("??? address %x\n", Eval_PC); -#endif - } +static void bssCheck(int in_bss, const char* idstr, const char* filename, + int lineNo) { + if (!in_bss) return; - if (table_ptr->loop == TIMES_AUTOMATIC || table_ptr->loop == TIMES_DECIDE_BY_BREAK) - table_ptr->loop = loop; /* set implicit loop times */ - return; + err("%s:%d: ブロックストレージセクションでは識別子%sは使えません。\n", + filename, lineNo, idstr); +} -bss_error: - err ("BSS 内では使用できない識別子です(%d 行)\n", cur_expr[i].line); +static void oddCheck(address pc, opesize size) { + static const char* const t[] = { + NULL, // BYTESIZE + "ワード", // WORDSIZE + "ロングワード", // LONGSIZE + NULL, // QUADSIZE + NULL, // SHORTSIZE + "単精度実数", // SINGLESIZE + "倍精度実数", // DOUBLESIZE + "拡張精度実数", // EXTENDSIZE + "パックドデシマル", // PACKEDSIZE + }; + + if (isOdd(pc)) { + eprintf("警告: " PRI_ADRS ": 奇数アドレスで%s指定されています。\n", pc, + t[size]); + } } +// アドレス依存部がロングワード指定か +// +// 例えば元のソースコードで .dc.l label となっている部分は +// テーブルで dc.b と記述されていると元通りのソースコードを +// 出力できないので、そのチェックを行う。 +static boolean isNotLongOnDependAddress(address pc, opesize size) { + if (size == LONGSIZE || size == EVENID || size == BREAKID || size == CRID) { + // dc.l、even、break、crならアドレス依存していてもよい + return FALSE; + } + + // それ以外の識別子は、アドレス依存しているとNG + return depend_address(pc); +} -private void -interpret_all (void) -{ +static void interpret(table* table_ptr, const char* filename) { + formula* cur_expr = table_ptr->formulaptr; + lblbuf* lblptr = NULL; + int loop = 0; + + const address tabletop = table_ptr->tabletop; + address pc = tabletop; + address pc0 = 0; + + const boolean in_bss = (Dis.beginBSS <= tabletop) ? TRUE : FALSE; + const address limit = in_bss ? Dis.LAST : Dis.beginBSS; + + ParseTblParam param = { + .text = NULL, + .buffer = NULL, + .bufLen = 0, + .constValues = {0, tabletop} // + }; + + if (Dis.LAST <= tabletop) { + err(PRI_ADRS + ": " + "テーブル開始アドレスとしてスタックセクション以降が指定されています。" + "\n", + tabletop); + } + + // テーブル数のループ + do { + address blockTop = pc; int i; + // 行のループ + for (i = 0; i < table_ptr->lines; i++) { + int count = 1; + boolean firstCall = TRUE; + + // 繰り返し(dc.b[2]など)のループ + // 初回のパース結果から繰り返し回数を得る + do { + ParseTblResult result; + formula* const fml = &cur_expr[i]; + + param.text = fml->expr; + param.constValues[PARSE_CONST_PC] = pc; + eprintfq("[%d:" PRI_ADRS "]:%s\n", loop + 1, pc, param.text); + + parseTableLine(¶m, &result); + if (result.pr != PARSE_SUCCESS) { + err("%s:%d: %s\n", filename, fml->line, result.error); + } + + if (firstCall) { + count = result.count; + firstCall = FALSE; + } + fml->id = result.id; + pc0 = pc; + + if (isNotLongOnDependAddress(pc, result.id)) { + if (table_ptr->loop == TIMES_AUTOMATIC) { + pc = blockTop; + goto tableend; + } + err(PRI_ADRS ": アドレス依存部でロングワード指定されていません。\n", + pc); + } + + switch (result.id) { + default: + break; + + case BYTESIZE: + break; + case WORDSIZE: + case LONGSIZE: + case SINGLESIZE: + case DOUBLESIZE: + case EXTENDSIZE: + case PACKEDSIZE: + oddCheck(pc, result.id); + break; + + case BYTEID: + case ASCIIID: + case ASCIIZID: + case LASCIIID: + bssCheck(in_bss, result.idstr, filename, fml->line); + break; + + case EVENID: + if (result.bytes && result.value != 0) { + // evenで飛ばすバイトの値は$00でなければならない + if (table_ptr->loop == TIMES_AUTOMATIC) { + pc = blockTop; + goto tableend; + } + err(PRI_ADRS + ": %sに対応する奇数アドレスの値が$00ではありません。\n", + pc, result.idstr); + } + break; + + case CRID: + break; + + case BREAKID: + if (result.value) { // 式の値が真(非0)ならテーブル終了 + loop++; + goto tableend; + } + break; + } + pc += result.bytes; + + // テーブル解析の途中で有効なセクションの末尾に到達したか、 + // ラベルが登録されているアドレスに到達した場合はテーブル終了と判定する。 + // 現在の周回は有効となり、ソースコード生成時は途中までテーブルとして処理される。 + // (現在の周回は無効とすべきかもしれない) + // なお、{式} を使って自ら登録したラベルも到達判定に使われる。 + if (limit <= pc || + (table_ptr->loop == TIMES_AUTOMATIC && + ((lblptr = next(pc0 + 1)) == NULL || lblptr->label <= pc))) { + loop++; + + if (lblptr && lblptr->label < pc) pc = pc0; + goto tableend; + } + + } while (--count > 0); + } + + if (blockTop == pc) { + // 全ての行を処理してもPCが変わらなければ無限ループになるので中断する。 + err(PRI_ADRS + "からPCが進みませんでした。テーブルファイルの修正が必要です。\n", + pc); + } - for (i = 0; i < TableCounter; i++) - interpret (&Table[i]); + loop++; + } while ((pc < limit && + (table_ptr->loop == TIMES_AUTOMATIC && + (lblptr = next(pc0 + 1)) != NULL && pc < lblptr->label)) || + table_ptr->loop == TIMES_DECIDE_BY_BREAK || + (table_ptr->loop != TIMES_AUTOMATIC && loop < table_ptr->loop)); + +tableend: + if (loop == 0) { + err(PRI_ADRS "はテーブルとして判断できませんでした。\n", tabletop); + } + eprintfq("テーブルは" PRI_ADRS "-" PRI_ADRS "(%d個)と判断しました。\n", + tabletop, pc, loop); + + regist_label(pc, DATLABEL | ENDTABLE | UNKNOWN); + + if (table_ptr->loop == TIMES_AUTOMATIC || + table_ptr->loop == TIMES_DECIDE_BY_BREAK) { + table_ptr->loop = loop; // テーブルの数が決定した + } } +static void interpret_all(const char* filename) { + int i; + for (i = 0; i < TableCounter; i++) interpret(&Table[i], filename); +} /* テーブルの処理 */ -private void -tablejob (address tabletop, FILE* fp) -{ - formula* cur_expr; - int formula_line; - - regist_label (tabletop, DATLABEL | TABLE | FORCE); - - /* テーブルバッファを一つ分確保 */ - Table = Realloc (Table, sizeof (table) * (TableCounter + 1)); - Table[TableCounter].tabletop = tabletop; - - cur_expr = 0; /* for Realloc() */ - formula_line = 0; - - while (1) { - char linebuf[1024]; - - if (fgets (linebuf, sizeof linebuf, fp) == NULL) - err ("Table 中に EOF に達しました.\n"); - - if (*(strend (linebuf) - 1) == '\n') - *(strend (linebuf) - 1) = '\0'; - Line_num++; - if (linebuf[0] == '#' || linebuf[0] == '*') /* comment */ - continue; - - if (strncasecmp (linebuf, "end", 3) == 0) { - char* ptr; - - for (ptr = linebuf + 3; *ptr == ' ' || *ptr == '\t'; ptr++) - ; - if (*ptr == '[') { - for (ptr++; *ptr == ' ' || *ptr == '\t'; ptr++) - ; - if (isdigit (*(unsigned char*)ptr)) { - Table[TableCounter].loop = atoi (ptr); - break; - } else if (strncasecmp (ptr, "breakonly", 9) == 0) { - /* テーブル数を break のみで判断 */ - Table[TableCounter].loop = TIMES_DECIDE_BY_BREAK; - break; - } else if (*ptr == ']') { - Table[TableCounter].loop = TIMES_AUTOMATIC; - /* 指定されない -> 自動 */ - break; - } - err ("Syntax error at end(%d 行)\n", Line_num); - } else - Table[TableCounter].loop = 1; - break; - } else { /* if (strncasecmp (linebuf, "end", 3) != 0) */ - - /* 行バッファを一つ分確保して格納する */ - cur_expr = Realloc (cur_expr, sizeof (formula) * (formula_line + 1)); - cur_expr[formula_line].line = Line_num; - cur_expr[formula_line].expr = - strcpy (Malloc (strlen (linebuf) + 1), linebuf); - formula_line++; - } +static void tablejob(address tabletop, FILE* fp, const char* filename) { + formula* cur_expr; + int formula_line; + + eprintfq("テーブル(" PRI_ADRS ")\n", tabletop); + + regist_label(tabletop, DATLABEL | TABLE | FORCE); + + /* テーブルバッファを一つ分確保 */ + Table = Realloc(Table, sizeof(table) * (TableCounter + 1)); + Table[TableCounter].tabletop = tabletop; + + cur_expr = 0; /* for Realloc() */ + formula_line = 0; + + while (1) { + char linebuf[1024]; + + if (fgets(linebuf, sizeof linebuf, fp) == NULL) + err("\nテーブル中にファイル末尾に達しました。\n"); + removeTailLf(linebuf); + + Line_num++; + if (linebuf[0] == '#' || linebuf[0] == '*') // コメント行 + continue; + + if (strncasecmp(linebuf, "end", 3) == 0) { + char* ptr; + + for (ptr = linebuf + 3; *ptr == ' ' || *ptr == '\t'; ptr++) + ; + if (*ptr == '[') { + for (ptr++; *ptr == ' ' || *ptr == '\t'; ptr++) + ; + if (isdigit(*ptr)) { + Table[TableCounter].loop = atoi(ptr); + break; + } else if (strncasecmp(ptr, "breakonly", 9) == 0) { + /* テーブル数を break のみで判断 */ + Table[TableCounter].loop = TIMES_DECIDE_BY_BREAK; + break; + } else if (*ptr == ']') { + Table[TableCounter].loop = TIMES_AUTOMATIC; + /* 指定されない -> 自動 */ + break; + } + err("\n%s:%d: end[]の指定が正しくありません。\n", filename, Line_num); + } else + Table[TableCounter].loop = 1; + break; + } else { /* if (strncasecmp (linebuf, "end", 3) != 0) */ + + /* 行バッファを一つ分確保して格納する */ + cur_expr = Realloc(cur_expr, sizeof(formula) * (formula_line + 1)); + cur_expr[formula_line].line = Line_num; + cur_expr[formula_line].expr = + strcpy(Malloc(strlen(linebuf) + 1), linebuf); + formula_line++; } + } - Table[ TableCounter ].formulaptr = cur_expr; - Table[ TableCounter ].lines = formula_line; - TableCounter++; + Table[TableCounter].formulaptr = cur_expr; + Table[TableCounter].lines = formula_line; + TableCounter++; } - /* テーブル記述ファイルを読み込む */ -extern void -read_tablefile (char* filename) -{ - char linebuf[256]; - FILE* fp = fopen (filename, "rt"); - - if (!fp) - err ("\n%s をオープンできませんでした.\n", filename); - - while (fgets (linebuf, sizeof linebuf, fp)) { - unsigned char c = linebuf[0]; - - Line_num++; - if (c == '#' || c == '*' || c == ';') /* comment */ - continue; - if (isxdigit (c)) { - address tabletop = (address) atox (linebuf); - - eprintfq ("Table(%x)\n", tabletop); - tablejob (tabletop, fp); - } +extern void read_tablefile(char* filename) { + char linebuf[256]; + FILE* fp = fopen(filename, "rt"); + + if (!fp) err("\n%s をオープンできません。\n", filename); + + while (fgets(linebuf, sizeof linebuf, fp)) { + char c = linebuf[0]; + + Line_num++; + if (c == '#' || c == '*' || c == ';') /* comment */ + continue; + if (isxdigit(c)) { + address tabletop = (address)atox(linebuf); + tablejob(tabletop, fp, filename); } - interpret_all (); - fclose (fp); + } + interpret_all(filename); + fclose(fp); } - /* テーブルのサーチ */ -extern table* -search_table (address pc) -{ - int i; +extern table* search_table(address pc) { + int i; - for (i = 0; i < TableCounter; i++) { - if (Table[i].tabletop == pc) - return &Table[i]; - } - return NULL; + for (i = 0; i < TableCounter; i++) { + if (Table[i].tabletop == pc) return &Table[i]; + } + return NULL; } - -/* EOF */ +// EOF diff --git a/src/table.h b/src/table.h index 73fdafa..ab05a11 100644 --- a/src/table.h +++ b/src/table.h @@ -1,31 +1,30 @@ -/* $Id: table.h,v 1.1 1996/10/24 04:27:50 ryo freeze $ - * - * ソースコードジェネレータ - * テーブル処理モジュールヘッダ - * Copyright (C) 1989,1990 K.Abe - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ - -#ifndef TABLE_H -#define TABLE_H - -#include "etc.h" /* peekl */ - - -/* p には Ofst を足していない値を渡す */ -#define PEEK_BYTE(p) ((UBYTE)(BeginBSS <= (p) ? 0 : *((p) + Ofst))) -#define PEEK_WORD(p) ((UWORD)(BeginBSS <= (p) ? 0 : (((p) + Ofst)[0] << 8) \ - + ((p) + Ofst)[1])) -#if defined (__mc68020__) || defined (__i386__) -#define PEEK_LONG(p) ((ULONG)(BeginBSS <= (p) ? 0 : peekl ((p) + Ofst))) +// ソースコードジェネレータ +// テーブル処理モジュールヘッダ +// Copyright (C) 1989,1990 K.Abe +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik + +#ifndef TABLE_H +#define TABLE_H + +#include "etc.h" // peekl + +// p には Ofst を足していない値を渡す +#define PEEK_BYTE(p) ((UBYTE)(Dis.beginBSS <= (p) ? 0 : *((p) + Dis.Ofst))) +#define PEEK_WORD(p) \ + ((UWORD)(Dis.beginBSS <= (p) \ + ? 0 \ + : (((p) + Dis.Ofst)[0] << 8) + ((p) + Dis.Ofst)[1])) +#if defined(__mc68020__) || defined(__i386__) +#define PEEK_LONG(p) ((ULONG)(Dis.beginBSS <= (p) ? 0 : peekl((p) + Ofst))) #else -#define PEEK_LONG(p) ((ULONG)(BeginBSS <= (p) ? 0 : ((int)(p) & 1) ? \ - (peekl ((p) + Ofst - 1) << 8) + ((p) + Ofst)[3] : peekl ((p) + Ofst))) +#define PEEK_LONG(p) \ + ((ULONG)(Dis.beginBSS <= (p) ? 0 \ + : ((int)(p)&1) \ + ? (peekl((p) + Dis.Ofst - 1) << 8) + ((p) + Dis.Ofst)[3] \ + : peekl((p) + Dis.Ofst))) #endif - /* テーブルの構造 1アドレスに1つの table がある @@ -33,44 +32,21 @@ */ typedef struct { -#if 0 - int count; /* now, count is evaluated each time */ -#endif - opesize id; - boolean hidden; - int line; - char* expr; + opesize id; + int line; + char* expr; } formula; typedef struct { - address tabletop; - int loop; - int lines; - formula *formulaptr; /* formula の配列へのポインタ */ + address tabletop; + int loop; + int lines; + formula* formulaptr; // formula の配列へのポインタ } table; -extern void read_tablefile (char*); -extern table* search_table (address); +extern void read_tablefile(char*); +extern table* search_table(address); -typedef enum { - PARSE_ANALYZING , - PARSE_GENERATING , -} parse_mode; - - -extern parse_mode ParseMode; -extern char* Lexptr; -extern int Eval_Value; -extern address Eval_TableTop; -extern address Eval_PC; -extern int Eval_Bytes; -extern opesize Eval_ID; -extern int Eval_Count; -extern int Eval_Break; -extern opesize Eval_SizeID; -extern char Eval_ResultString[256]; - - -#endif /* TABLE_H */ +#endif -/* EOF */ +// EOF diff --git a/src/version.c b/src/version.c index 75089d1..5bdb9f6 100644 --- a/src/version.c +++ b/src/version.c @@ -1,18 +1,53 @@ -/* $Id: version.c,v 2.76 1995/01/07 11:21:00 ryo Exp $ - * - * ソースコードジェネレータ - * Version# - * Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu - * All rights reserved. - * Copyright (C) 1997-2010 Tachibana - * - */ +// ソースコードジェネレータ +// バージョン番号 +// Copyright (C) 1989,1990 K.Abe, 1994 R.ShimiZu +// All rights reserved. +// Copyright (C) 1997-2023 TcbnErik -const char Version[] = "3.16"; -const char Date[] = "2010-05-25"; +// This file is part of dis (source code generator). +// +// 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 3 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, see . -#ifdef OSKDIS -const char OSKEdition = " edition ?"; +#include "version.h" + +#define VERSION "4.00" +#define DATE "2023-04-23" + +const char ProgramAndVersion[] = "dis version " VERSION; + +const char Title[] = + "ソースコードジェネレータ for X680x0" +#ifdef __linux__ + " (Linux cross)" +#endif +#ifdef __FreeBSD__ + " (BSD cross)" +#endif +#ifdef __CYGWIN__ + " (Cygwin cross)" +#endif +#ifdef __MINGW32__ + " (MinGW cross)" +#endif + " version " VERSION + "\n" + "Copyright (C)1989-1992 K.Abe, 1994-1997 R.ShimiZu, " DATE + " TcbnErik.\n" + +#ifdef OSKDIS + "OS-9/68000 version by TEMPLE, 1994\n" #endif + ""; -/* EOF */ +// EOF diff --git a/src/version.h b/src/version.h new file mode 100644 index 0000000..98ea3b9 --- /dev/null +++ b/src/version.h @@ -0,0 +1,28 @@ +// ソースコードジェネレータ +// バージョン番号 ヘッダ +// Copyright (C) 2023 TcbnErik + +// This file is part of dis (source code generator). +// +// 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 3 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, see . + +#ifndef VERSION_H +#define VERSION_H + +extern const char ProgramAndVersion[]; +extern const char Title[]; + +#endif + +// EOF diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..222eca1 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,124 @@ +# Makefile for dis-test +# Do not use non-ASCII characters in this file. + +AS = has +ASFLAGS = +LD = hlk +LDFLAGS = +DIFF = diff +DIFFFLAGS = -Naur +MKDIR_P = mkdir -p + +DIS = ../build/dis.x +DISFLAGS = --deterministic --overwrite -m680x0,68851 + +SRC_DIR = src +EXP_DIR = expected +OBJ_DIR = obj +DIS_DIR = dised +DIFF_DIR = diff + +TEST1 = $(subst $(SRC_DIR)/,,$(basename $(wildcard $(SRC_DIR)/*.s))) +TEST2 = $(TEST1) blankline_B cinvpush_R0 cpu32_mcpu32 pflush040_R0 + +SRCS = $(addprefix $(SRC_DIR)/,$(addsuffix .s,$(TEST1))) +OBJS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(TEST1))) +BINS = $(addprefix $(OBJ_DIR)/,$(addsuffix .x,$(TEST1))) +DISS = $(addprefix $(DIS_DIR)/,$(addsuffix .s,$(TEST2))) +DIFFS = $(addprefix $(DIFF_DIR)/,$(addsuffix .dif,$(TEST2))) +DIFFS_OK = $(addprefix $(DIFF_DIR)/,$(addsuffix .ok,$(TEST2))) + + +.PHONY: all clean makeexe makedis makedif + +.PRECIOUS: $(OBJ_DIR)/%.x $(DIS_DIR)/%.s + + +all: dif + +exe: $(BINS) + +dis: $(DISS) + +dif: $(DIFFS_OK) + + +$(OBJ_DIR) $(DIS_DIR) $(DIFF_DIR): + $(MKDIR_P) $@ + + +$(OBJ_DIR)/%.x: $(SRC_DIR)/%.s $(OBJ_DIR) + $(AS) $(ASFLAGS) -o $(OBJ_DIR)/$*.o $< + $(LD) $(LDFLAGS) -o $@ $(OBJ_DIR)/$*.o + + +$(DIS_DIR)/avoid_q.s: $(OBJ_DIR)/avoid_q.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -A + +$(DIS_DIR)/blankline_B.s: $(OBJ_DIR)/blankline.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -B + +$(DIS_DIR)/cinvpush_R0.s: $(OBJ_DIR)/cinvpush.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -R0 + +$(DIS_DIR)/compress.s: $(OBJ_DIR)/compress.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -W2 + +$(DIS_DIR)/cpu32_mcpu32.s: $(OBJ_DIR)/cpu32.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -mcpu32 + +$(DIS_DIR)/devhead_loop.s: $(OBJ_DIR)/devhead_loop.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -d + +$(DIS_DIR)/imm_comment.s: $(OBJ_DIR)/imm_comment.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -M + +$(DIS_DIR)/lab_rw.s: $(OBJ_DIR)/lab_rw.x $(DIS) $(DIS_DIR) $(SRC_DIR)/lab_rw.lab + $(DIS) $(DISFLAGS) $< $@ -g$(SRC_DIR)/lab_rw.lab + +$(DIS_DIR)/pflush040_R0.s: $(OBJ_DIR)/pflush040.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -R0 + +$(DIS_DIR)/split_end.s: $(OBJ_DIR)/split_end.x $(DIS) $(DIS_DIR) + rm -vf $@ $@.000 + $(DIS) $(DISFLAGS) $< $@ -S1 + mv $@.000 $@ + +$(DIS_DIR)/sym_oorange.s: $(OBJ_DIR)/sym_oorange.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ -s2 + +$(DIS_DIR)/tab_depadrs.s: $(OBJ_DIR)/tab_depadrs.x $(DIS) $(DIS_DIR) \ + $(SRC_DIR)/tab_depadrs.lab $(SRC_DIR)/tab_depadrs.tab + $(DIS) $(DISFLAGS) $< $@ -g$(SRC_DIR)/tab_depadrs.lab -T$(SRC_DIR)/tab_depadrs.tab + +$(DIS_DIR)/tab_even.s: $(OBJ_DIR)/tab_even.x $(DIS) $(DIS_DIR) \ + $(SRC_DIR)/tab_even.lab $(SRC_DIR)/tab_even.tab + $(DIS) $(DISFLAGS) $< $@ -g$(SRC_DIR)/tab_even.lab -T$(SRC_DIR)/tab_even.tab + +$(DIS_DIR)/tab_stuck1.s: $(OBJ_DIR)/tab_stuck1.x $(DIS) $(DIS_DIR) \ + $(SRC_DIR)/tab_stuck1.lab $(SRC_DIR)/tab_stuck1.tab + rm -vf $@ + -$(DIS) $(DISFLAGS) $< $@ -g$(SRC_DIR)/tab_stuck1.lab -T$(SRC_DIR)/tab_stuck1.tab + touch $@ + +$(DIS_DIR)/tab_stuck2.s: $(OBJ_DIR)/tab_stuck2.x $(DIS) $(DIS_DIR) \ + $(SRC_DIR)/tab_stuck2.lab $(SRC_DIR)/tab_stuck2.tab + rm -vf $@ + -$(DIS) $(DISFLAGS) $< $@ -g$(SRC_DIR)/tab_stuck2.lab -T$(SRC_DIR)/tab_stuck2.tab + touch $@ + +$(DIS_DIR)/%.s: $(OBJ_DIR)/%.x $(DIS) $(DIS_DIR) + $(DIS) $(DISFLAGS) $< $@ + +$(DIFF_DIR)/%.ok: $(EXP_DIR)/%.s $(DIS_DIR)/%.s $(DIFF_DIR) + rm -vf $@ + $(DIFF) $(DIFFFLAGS) $(EXP_DIR)/$*.s $(DIS_DIR)/$*.s >! $(DIFF_DIR)/$(*F).dif + mv $(DIFF_DIR)/$(*F).dif $@ + + +clean: + -rm $(OBJS) $(BINS) $(DISS) $(DIFFS) $(DIFFS_OK) + -rmdir $(OBJ_DIR) $(DIS_DIR) $(DIFF_DIR) + + +# EOF diff --git a/tests/expected/after_str.s b/tests/expected/after_str.s new file mode 100644 index 0000000..17c2d32 --- /dev/null +++ b/tests/expected/after_str.s @@ -0,0 +1,37 @@ +;============================================= +; Filename obj/after_str.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000018 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 4 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/after_str.x dised/after_str.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + lea (L000008,pc),a0 + nop + DOS _EXIT + +L000008: + .dc.b $61,$00,$00,$00 + +L00000c: + movem.l d0-d7/a0-a6,-(sp) + nop + movem.l (sp)+,d0-d7/a0-a6 + rts + +L000018: + + .end L000000 diff --git a/tests/expected/avoid_q.s b/tests/expected/avoid_q.s new file mode 100644 index 0000000..cb76991 --- /dev/null +++ b/tests/expected/avoid_q.s @@ -0,0 +1,62 @@ +;============================================= +; Filename obj/avoid_q.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000008e byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/avoid_q.x dised/avoid_q.s -A +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + move.l #0.l,d0 + move.l #$7f.l,d0 + move.l #$80,d0 + move.l #$ffffff80.l,d0 + move.l #$ffffff7f,d0 + nop + add #0,(a0) + add #1.w,(a0) + add #8.w,(a0) + add #9,(a0) + nop + sub #0,(a0) + sub #1.w,(a0) + sub #8.w,(a0) + sub #9,(a0) + nop + add #0,d0 + add #1.w,d0 + add #8.w,d0 + add #9,d0 + nop + sub #0,d0 + sub #1.w,d0 + sub #8.w,d0 + sub #9,d0 + nop + add #0,a0 + add #1.w,a0 + add #8.w,a0 + add #9,a0 + nop + sub #0,a0 + sub #1.w,a0 + sub #8.w,a0 + sub #9,a0 + nop + DOS _EXIT + +L00008e: + + .end L000000 diff --git a/tests/expected/bd_size.s b/tests/expected/bd_size.s new file mode 100644 index 0000000..481435f --- /dev/null +++ b/tests/expected/bd_size.s @@ -0,0 +1,137 @@ +;============================================= +; Filename obj/bd_size.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $000080de byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 32 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/bd_size.x dised/bd_size.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + tst (L0000f8,pc) + nop +L000006: + tst ([L000006+2.w,pc]) +L00000c: + tst ([L00000c+2.l,pc]) + nop + tst (L000096,pc,d0.l) + tst (L00009a.w,pc,d0.l) + tst (L0000a0.l,pc,d0.l) + tst (L0000aa.w,pc,d0.l) + tst (L0000b0.l,pc,d0.l) + tst (L008036,pc,d0.l) + tst (L00803e.l,pc,d0.l) + tst (L008048,pc,d0.l) + nop + tst ([L0000ce,pc]) + tst ([L0000d4.l,pc]) + tst ([L00805c.l,pc]) + tst ([L008066.l,pc]) + tst ([L008070,pc]) + nop + bra L00807c + +L00007c: + .dc.b $00,$00,$00,$00,$00,$00,$00,$00 + .dc.b $00,$00,$00,$00,$00,$00,$00,$00 + .dc.b $00,$00,$00,$00,$00,$00,$00,$00 + .dc.b $00,$00 +L000096: + .dc $0000,$0000 +L00009a: + .dc $0000,$0000,$0000 +L0000a0: + .dc $0000,$0000 +L0000a4: + .dc $0000,$0000,$0000 +L0000aa: + .dc $0000,$0000,$0000 +L0000b0: + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000,$0000 +L0000c6: + .dc.b $00,$00,$00,$00,$00,$00 +L0000cc: + .dc.b $00,$00 +L0000ce: + .dc.l 0 +L0000d2: + .dc.b $00,$00 +L0000d4: + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000 +L0000f8: + .ds 16259 +L007ffe: + .dc $0000,$0000 +L008002: + .dc $0000,$0000,$0000 +L008008: + .dc $0000,$0000,$0000 +L00800e: + .dc $0000,$0000,$0000 +L008014: + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000,$0000,$0000 + .dc $0000 +L008036: + .dc.b $00,$00,$00,$00,$00,$00 +L00803c: + .dc.b $00,$00 +L00803e: + .dc $0000,$0000,$0000,$0000 + .dc $0000 +L008048: + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000,$0000,$0000 + .dc $0000,$0000 +L00805c: + .dc.b $00,$00,$00,$00,$00,$00,$00,$00 + .dc.b $00,$00 +L008066: + .dc.b $00,$00,$00,$00,$00,$00,$00,$00 + .dc.b $00,$00 +L008070: + .dc.l $00000000,$00000000 + .dc.l $00000000 + +L00807c: + tst (L007ffe,pc,d0.l) + tst (L008002.w,pc,d0.l) + tst (L008008.l,pc,d0.l) + tst (L00800e,pc,d0.l) + tst (L008014.l,pc,d0.l) + tst (L0000a0,pc,d0.l) + tst (L0000a4.l,pc,d0.l) + tst (L0000aa,pc,d0.l) + nop + tst ([L008036,pc]) + tst ([L00803c.l,pc]) + tst ([L0000c6.l,pc]) + tst ([L0000cc.l,pc]) + tst ([L0000d2,pc]) + nop + DOS _EXIT + +L0080de: + + .end L000000 diff --git a/tests/expected/bitfield.s b/tests/expected/bitfield.s new file mode 100644 index 0000000..9d263df --- /dev/null +++ b/tests/expected/bitfield.s @@ -0,0 +1,51 @@ +;============================================= +; Filename obj/bitfield.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000005c byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/bitfield.x dised/bitfield.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + bftst d7{d0:d0} + bftst d0{d7:d7} + bftst d7{d1:1} + bftst d0{d1:32} + bftst d7{0:d1} + bftst d7{31:d1} + bftst d7{0:32} + nop + bfextu d7{d0:d0},d0 + bfextu d0{d7:d7},d0 + bfextu d7{d1:1},d0 + bfextu d0{d1:32},d0 + bfextu d7{0:d1},d0 + bfextu d7{31:d1},d0 + bfextu d7{0:32},d0 + nop + bfins d0,d7{d0:d0} + bfins d0,d0{d7:d7} + bfins d0,d7{d1:1} + bfins d0,d0{d1:32} + bfins d0,d7{0:d1} + bfins d0,d7{31:d1} + bfins d0,d7{0:32} + nop + DOS _EXIT + +L00005c: + + .end L000000 diff --git a/tests/expected/bitop.s b/tests/expected/bitop.s new file mode 100644 index 0000000..665d3cd --- /dev/null +++ b/tests/expected/bitop.s @@ -0,0 +1,54 @@ +;============================================= +; Filename obj/bitop.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000004a byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 6 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/bitop.x dised/bitop.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + btst #0,d0 + btst d0,(a0) + btst #$ff,d0 + btst #-1,d0 + rts + +L000010: + bclr #0,d0 + bclr d0,(a0) + bclr #$ff,d0 + bclr #-1,d0 + rts + +L000020: + bset #0,d0 + bset d0,(a0) + bset #$ff,d0 + bset #-1,d0 + rts + +L000030: + bchg #0,d0 + bchg d0,(a0) + bchg #$ff,d0 + bchg #-1,d0 + rts + +L000040: + .dc.b $08,$00,$01,$00,$08,$00,$80,$ff + .dc.b $4e,$75 +L00004a: + + .end L000000 diff --git a/tests/expected/blankline.s b/tests/expected/blankline.s new file mode 100644 index 0000000..cb346d4 --- /dev/null +++ b/tests/expected/blankline.s @@ -0,0 +1,55 @@ +;============================================= +; Filename obj/blankline.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000024 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 9 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/blankline.x dised/blankline.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + nop + rte + +L000004: + nop + .cpu 68010 + rtd #4 + +L00000a: + nop + rts + +L00000e: + nop + rtr + +L000012: + nop + jmp (a0) + +L000016: + nop + bra L000016 +L00001a: + nop + .cpu 68020 + fbra L00001a +L000020: + nop + DOS _EXIT + +L000024: + + .end L000000 diff --git a/tests/expected/blankline_B.s b/tests/expected/blankline_B.s new file mode 100644 index 0000000..302a9f3 --- /dev/null +++ b/tests/expected/blankline_B.s @@ -0,0 +1,57 @@ +;============================================= +; Filename obj/blankline.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000024 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 9 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/blankline.x dised/blankline_B.s -B +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + nop + rte + +L000004: + nop + .cpu 68010 + rtd #4 + +L00000a: + nop + rts + +L00000e: + nop + rtr + +L000012: + nop + jmp (a0) + +L000016: + nop + bra L000016 + +L00001a: + nop + .cpu 68020 + fbra L00001a + +L000020: + nop + DOS _EXIT + +L000024: + + .end L000000 diff --git a/tests/expected/bra_size.s b/tests/expected/bra_size.s new file mode 100644 index 0000000..e304a09 --- /dev/null +++ b/tests/expected/bra_size.s @@ -0,0 +1,150 @@ +;============================================= +; Filename obj/bra_size.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00010004 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 25 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/bra_size.x dised/bra_size.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + move.l (L00002a,pc,d0.w*4),d0 + move.l (L007f9c,pc,d0.w*4),d0 + move.l (L008030,pc,d0.w*4),d0 + move.l (L008076,pc,d0.w*4),d0 + nop + bra L007fd4 +L000020: + nop + rts + +L000024: + nop + rts + +L000028: + rts + +L00002a: + .ds.l 8152 + +L007f8a: + rts + +L007f8c: + nop + rts + +L007f90: + nop + rts + +L007f94: + nop + rts + +L007f98: + nop + rts + +L007f9c: + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + +L007fd4: + bsr L008054 + bsr.w L008056 + bsr.l L00805a + bsr.w L008062 + bsr.l L008066 + bsr L00806e + bsr.l L008072 + nop + bsr L00fff6 + bsr.l L00fffa + bsr.l L010002 + nop + bsr L007f8a + bsr.w L007f8c + bsr.l L007f90 + bsr L007f94 + bsr.l L007f98 + bsr L000020 + bsr.l L000024 + bsr L000028 + DOS _EXIT + +L008030: + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000,$00000000 + .dc.l $00000000 + +L008054: + rts + +L008056: + nop + rts + +L00805a: + nop + nop + nop + rts + +L008062: + nop + rts + +L008066: + nop + nop + nop + rts + +L00806e: + nop + rts + +L008072: + nop + rts + +L008076: + .ds.l 8160 + +L00fff6: + nop + rts + +L00fffa: + nop + nop + nop + rts + +L010002: + rts + +L010004: + + .end L000000 diff --git a/tests/expected/cas.s b/tests/expected/cas.s new file mode 100644 index 0000000..abdd2ee --- /dev/null +++ b/tests/expected/cas.s @@ -0,0 +1,34 @@ +;============================================= +; Filename obj/cas.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000028 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/cas.x dised/cas.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + cas d0,d7,(a0) + cas d7,d0,($12345678) + nop + cas2 d0:d7,d6:d1,(d0):(d7) + cas2 d0:d7,d6:d1,(a0):(sp) + cas2 d0:d7,d6:d1,(d0):(sp) + cas2 d0:d7,d6:d1,(sp):(d0) + DOS _EXIT + +L000028: + + .end L000000 diff --git a/tests/expected/cinvpush.s b/tests/expected/cinvpush.s new file mode 100644 index 0000000..0e094ae --- /dev/null +++ b/tests/expected/cinvpush.s @@ -0,0 +1,78 @@ +;============================================= +; Filename obj/cinvpush.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000070 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 9 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/cinvpush.x dised/cinvpush.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + cinvl ic,(a0) + cinvl dc,(a1) + cinvl bc,(a6) + cinvl nc,(sp) + nop + rts + +L00000c: + cinvp ic,(a0) + cinvp dc,(a1) + cinvp bc,(a6) + cinvp nc,(sp) + nop + rts + +L000018: + cinva ic + cinva dc + cinva bc + cinva nc + nop + rts + +L000024: + cpushl ic,(a0) + cpushl dc,(a1) + cpushl bc,(a6) + cpushl nc,(sp) + nop + rts + +L000030: + cpushp ic,(a0) + cpushp dc,(a1) + cpushp bc,(a6) + cpushp nc,(sp) + nop + rts + +L00003c: + cpusha ic + cpusha dc + cpusha bc + cpusha nc + nop + rts + +L000048: + .dc.b 'NqNu' +L00005c: + .dc.b $f4,$f8,$f4,$f9,$f4,$fa,$f4,$fb + .dc.b $f4,$fc,$f4,$fd,$f4,$fe,$f4,$ff + .dc.b $4e,$71,$4e,$75 +L000070: + + .end L000000 diff --git a/tests/expected/cinvpush_R0.s b/tests/expected/cinvpush_R0.s new file mode 100644 index 0000000..db9e411 --- /dev/null +++ b/tests/expected/cinvpush_R0.s @@ -0,0 +1,96 @@ +;============================================= +; Filename obj/cinvpush.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000070 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 9 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/cinvpush.x dised/cinvpush_R0.s -R0 +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + cinvl ic,(a0) + cinvl dc,(a1) + cinvl bc,(a6) + cinvl nc,(sp) + nop + rts + +L00000c: + cinvp ic,(a0) + cinvp dc,(a1) + cinvp bc,(a6) + cinvp nc,(sp) + nop + rts + +L000018: + cinva ic + cinva dc + cinva bc + cinva nc + nop + rts + +L000024: + cpushl ic,(a0) + cpushl dc,(a1) + cpushl bc,(a6) + cpushl nc,(sp) + nop + rts + +L000030: + cpushp ic,(a0) + cpushp dc,(a1) + cpushp bc,(a6) + cpushp nc,(sp) + nop + rts + +L00003c: + cpusha ic + cpusha dc + cpusha bc + cpusha nc + nop + rts + +L000048: + cinva bc + cinva bc + cinva bc + cinva bc + cinva bc + cinva bc + cinva bc + cinva bc + nop + rts + +L00005c: + cpusha bc + cpusha bc + cpusha bc + cpusha bc + cpusha bc + cpusha bc + cpusha bc + cpusha bc + nop + rts + +L000070: + + .end L000000 diff --git a/tests/expected/compress.s b/tests/expected/compress.s new file mode 100644 index 0000000..53b9d95 --- /dev/null +++ b/tests/expected/compress.s @@ -0,0 +1,70 @@ +;============================================= +; Filename obj/compress.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $000001a4 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 16 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/compress.x dised/compress.s -W2 +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + move.b (L00004c,pc),d0 + move.b (L000050,pc),d0 + move (L000054,pc),d0 + move (L00005c,pc),d0 + move.l (L000064,pc),d0 + move.l (L000074,pc),d0 + nop + .cpu 68040 + fmove.s (L000084,pc),fp0 + fmove.s (L000094,pc),fp0 + fmove.d (L0000a4,pc),fp0 + fmove.d (L0000c4,pc),fp0 + fmove (L0000e4,pc),fp0 + fmove (L000114,pc),fp0 + fmove.p (L000144,pc),fp0 + fmove.p (L000174,pc),fp0 + DOS _EXIT + +L00004c: + .dcb.b 4,$a5 +L000050: + .ds.b 4 +L000054: + .dcb 4,$cafe +L00005c: + .ds 4 +L000064: + .dcb.l 4,$deadbeef +L000074: + .ds.l 4 +L000084: + .dcb.s 4,0f1.5 +L000094: + .ds.s 4 +L0000a4: + .dcb.d 4,0f2.3456 +L0000c4: + .ds.d 4 +L0000e4: + .dcb.x 4,0f3.4567 +L000114: + .ds.x 4 +L000144: + .dcb.p 4,0f4.5678 +L000174: + .ds.p 4 +L0001a4: + + .end L000000 diff --git a/tests/expected/cpu32.s b/tests/expected/cpu32.s new file mode 100644 index 0000000..99d7bdc --- /dev/null +++ b/tests/expected/cpu32.s @@ -0,0 +1,46 @@ +;============================================= +; Filename obj/cpu32.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000003c byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 11 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/cpu32.x dised/cpu32.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68060 + lpstop #$2000 + rts + +L000008: + .dc.b 'JNu' +L00000c: + .dc.b $f8,$10,$79,$00,$4e,$75 +L000012: + .dc.b $f8,$10,$7d,$00,$4e,$75 +L000018: + .dc.b $f8,$00,$78,$01,$4e,$75 +L00001e: + .dc.b $f8,$00,$7c,$01,$4e,$75 +L000024: + .dc.b $f8,$10,$71,$00,$4e,$75 +L00002a: + .dc.b $f8,$10,$75,$00,$4e,$75 +L000030: + .dc.b $f8,$00,$70,$01,$4e,$75 +L000036: + .dc.b $f8,$00,$74,$01,$4e,$75 +L00003c: + + .end L000000 diff --git a/tests/expected/cpu32_mcpu32.s b/tests/expected/cpu32_mcpu32.s new file mode 100644 index 0000000..1a6b693 --- /dev/null +++ b/tests/expected/cpu32_mcpu32.s @@ -0,0 +1,64 @@ +;============================================= +; Filename obj/cpu32.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000003c byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 11 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/cpu32.x dised/cpu32_mcpu32.s -mcpu32 +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68060 + lpstop #$2000 + rts + +L000008: + bgnd + rts + +L00000c: + tbls.b (a0),d7 + rts + +L000012: + tblsn.b (a0),d7 + rts + +L000018: + tbls.b d0:d1,d7 + rts + +L00001e: + tblsn.b d0:d1,d7 + rts + +L000024: + tblu.b (a0),d7 + rts + +L00002a: + tblun.b (a0),d7 + rts + +L000030: + tblu.b d0:d1,d7 + rts + +L000036: + tblun.b d0:d1,d7 + rts + +L00003c: + + .end L000000 diff --git a/tests/expected/devhead_loop.s b/tests/expected/devhead_loop.s new file mode 100644 index 0000000..40c0159 --- /dev/null +++ b/tests/expected/devhead_loop.s @@ -0,0 +1,62 @@ +;============================================= +; Filename obj/devhead_loop.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000004e byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 16 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/devhead_loop.x dised/devhead_loop.s -d +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .dc.l L00001a + .dc $8000 + .dc.l L000016 + .dc.l L000018 + .dc.b '/*?--?*/' + +L000016: + rts + +L000018: + rts + +L00001a: + .dc.l L000034 + .dc $8000 + .dc.l L000030 + .dc.l L000032 + .dc.b '/*?--?*/' + +L000030: + rts + +L000032: + rts + +L000034: + .dc.l L00001a + .dc $8000 + .dc.l L00004a + .dc.l L00004c + .dc.b '/*?--?*/' + +L00004a: + rts + +L00004c: + rts + +L00004e: + + .end L000000 diff --git a/tests/expected/ds.s b/tests/expected/ds.s new file mode 100644 index 0000000..9bf9d49 --- /dev/null +++ b/tests/expected/ds.s @@ -0,0 +1,57 @@ +;============================================= +; Filename obj/ds.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000040 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000066 byte(s) +; 10 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/ds.x dised/ds.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + move.b (L000040,pc),d0 + move (L000042,pc),d0 + move.l (L000046,pc),d0 + .cpu 68020 + pmove (L00004e),srp + pmove (L00004e),srp + pmove (L00004e),srp + nop + .cpu 68040 + fmove.s (L00005e,pc),fp0 + fmove.d (L000066,pc),fp0 + fmove (L000076,pc),fp0 + fmove.p (L00008e,pc),fp0 + DOS _EXIT + + .bss + +L000040: + .ds.b 2 +L000042: + .ds 2 +L000046: + .ds.l 2 +L00004e: + .ds.d 2 +L00005e: + .ds.s 2 +L000066: + .ds.d 2 +L000076: + .ds.x 2 +L00008e: + .ds.p 2 +L0000a6: + + .end L000000 diff --git a/tests/expected/ea_abs.s b/tests/expected/ea_abs.s new file mode 100644 index 0000000..97cf754 --- /dev/null +++ b/tests/expected/ea_abs.s @@ -0,0 +1,38 @@ +;============================================= +; Filename obj/ea_abs.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000003e byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/ea_abs.x dised/ea_abs.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + pea (0) + pea (1) + pea ($7fff) + pea (-$8000) + pea (-1) + pea (-$8000) + pea (0).l + pea (1).l + pea ($7fff).l + pea ($8000) + pea ($ffffffff).l + pea ($ffff8000).l + DOS _EXIT + +L00003e: + + .end L000000 diff --git a/tests/expected/ea_label.s b/tests/expected/ea_label.s new file mode 100644 index 0000000..796f5d4 --- /dev/null +++ b/tests/expected/ea_label.s @@ -0,0 +1,392 @@ +;============================================= +; Filename obj/ea_label.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000970 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 30 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/ea_label.x dised/ea_label.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + nop + DOS _EXIT + +L000004: + .dc.l L000064 + .dc.l L00006a + .dc.l L000078 + .dc.l L00007e + .dc.l L000084 + .dc.l L0000b8 + .dc.l L0000ca + .dc.l L0000e6 + .dc.l L000150 + .dc.l L0001da + .dc.l L000284 + .dc.l L00032e + .dc.l L000398 + .dc.l L000422 + .dc.l L0004cc + .dc.l L000576 + .dc.l L0005e0 + .dc.l L000626 + .dc.l L00066c + .dc.l L0006c2 + .dc.l L00076c + .dc.l L0007d6 + .dc.l L00081c + .dc.l L0008c6 + +L000064: + move ($6800),d0 + rts + +L00006a: + move ($beefcafe),d0 + move (L0000b4),d0 + rts + +L000078: + move (L0000b2,pc),d0 + rts + +L00007e: + move (L0000b2,pc,d0.l),d0 + rts + +L000084: + move (L0000b2,pc),d0 + .cpu 68020 + move (L0000b2.w,pc,d0.l),d0 + move (L0000b2.l,pc),d0 + move (L0000b2.l,pc,d0.l),d0 + move (L0000b2,zpc),d0 + move (L0000b2,zpc,d0.l),d0 + rts + +L0000b0: + bra L0000b8 + +L0000b2: + .dc $cafe +L0000b4: + .dc $1234,$5678 + +L0000b8: + move #$6800,d0 + move.l #$beefcafe,d0 + move.l #L0000b4,d0 + rts + +L0000ca: + move (a0,d0.l),d0 + move ($6800,a0,d0.l),d0 + move ($beefcafe,a0,d0.l),d0 + move (L0000b4,a0,d0.l),d0 + rts + +L0000e6: + move ([za0],d0.l),d0 + move ([za0],d0.l,$6800),d0 + move ([za0],d0.l,$beefcafe),d0 + move ([za0],d0.l,L0000b4),d0 + move ([za0]),d0 + move ([za0],$6800),d0 + move ([za0],$beefcafe),d0 + move ([za0],L0000b4),d0 + move ([a0],d0.l),d0 + move ([a0],d0.l,$6800),d0 + move ([a0],d0.l,$beefcafe),d0 + move ([a0],d0.l,L0000b4),d0 + move ([a0]),d0 + move ([a0],$6800),d0 + move ([a0],$beefcafe),d0 + move ([a0],L0000b4),d0 + rts + +L000150: + move ([$6800],d0.l),d0 + move ([$6800],d0.l,$6800),d0 + move ([$6800],d0.l,$beefcafe),d0 + move ([$6800],d0.l,L0000b4),d0 + move ([$6800]),d0 + move ([$6800],$6800),d0 + move ([$6800],$beefcafe),d0 + move ([$6800],L0000b4),d0 + move ([$6800,a0],d0.l),d0 + move ([$6800,a0],d0.l,$6800),d0 + move ([$6800,a0],d0.l,$beefcafe),d0 + move ([$6800,a0],d0.l,L0000b4),d0 + move ([$6800,a0]),d0 + move ([$6800,a0],$6800),d0 + move ([$6800,a0],$beefcafe),d0 + move ([$6800,a0],L0000b4),d0 + rts + +L0001da: + move ([$beefcafe],d0.l),d0 + move ([$beefcafe],d0.l,$6800),d0 + move ([$beefcafe],d0.l,$beefcafe),d0 + move ([$beefcafe],d0.l,L0000b4),d0 + move ([$beefcafe]),d0 + move ([$beefcafe],$6800),d0 + move ([$beefcafe],$beefcafe),d0 + move ([$beefcafe],L0000b4),d0 + move ([$beefcafe,a0],d0.l),d0 + move ([$beefcafe,a0],d0.l,$6800),d0 + move ([$beefcafe,a0],d0.l,$beefcafe),d0 + move ([$beefcafe,a0],d0.l,L0000b4),d0 + move ([$beefcafe,a0]),d0 + move ([$beefcafe,a0],$6800),d0 + move ([$beefcafe,a0],$beefcafe),d0 + move ([$beefcafe,a0],L0000b4),d0 + rts + +L000284: + move ([L0000b4],d0.l),d0 + move ([L0000b4],d0.l,$6800),d0 + move ([L0000b4],d0.l,$beefcafe),d0 + move ([L0000b4],d0.l,L0000b4),d0 + move ([L0000b4]),d0 + move ([L0000b4],$6800),d0 + move ([L0000b4],$beefcafe),d0 + move ([L0000b4],L0000b4),d0 + move ([L0000b4,a0],d0.l),d0 + move ([L0000b4,a0],d0.l,$6800),d0 + move ([L0000b4,a0],d0.l,$beefcafe),d0 + move ([L0000b4,a0],d0.l,L0000b4),d0 + move ([L0000b4,a0]),d0 + move ([L0000b4,a0],$6800),d0 + move ([L0000b4,a0],$beefcafe),d0 + move ([L0000b4,a0],L0000b4),d0 + rts + +L00032e: + move ([d0.l]),d0 + move ([d0.l],$6800),d0 + move ([d0.l],$beefcafe),d0 + move ([d0.l],L0000b4),d0 + move ([za0]),d0 + move ([za0],$6800),d0 + move ([za0],$beefcafe),d0 + move ([za0],L0000b4),d0 + move ([a0,d0.l]),d0 + move ([a0,d0.l],$6800),d0 + move ([a0,d0.l],$beefcafe),d0 + move ([a0,d0.l],L0000b4),d0 + move ([a0]),d0 + move ([a0],$6800),d0 + move ([a0],$beefcafe),d0 + move ([a0],L0000b4),d0 + rts + +L000398: + move ([$6800,d0.l]),d0 + move ([$6800,d0.l],$6800),d0 + move ([$6800,d0.l],$beefcafe),d0 + move ([$6800,d0.l],L0000b4),d0 + move ([$6800]),d0 + move ([$6800],$6800),d0 + move ([$6800],$beefcafe),d0 + move ([$6800],L0000b4),d0 + move ([$6800,a0,d0.l]),d0 + move ([$6800,a0,d0.l],$6800),d0 + move ([$6800,a0,d0.l],$beefcafe),d0 + move ([$6800,a0,d0.l],L0000b4),d0 + move ([$6800,a0]),d0 + move ([$6800,a0],$6800),d0 + move ([$6800,a0],$beefcafe),d0 + move ([$6800,a0],L0000b4),d0 + rts + +L000422: + move ([$beefcafe,d0.l]),d0 + move ([$beefcafe,d0.l],$6800),d0 + move ([$beefcafe,d0.l],$beefcafe),d0 + move ([$beefcafe,d0.l],L0000b4),d0 + move ([$beefcafe]),d0 + move ([$beefcafe],$6800),d0 + move ([$beefcafe],$beefcafe),d0 + move ([$beefcafe],L0000b4),d0 + move ([$beefcafe,a0,d0.l]),d0 + move ([$beefcafe,a0,d0.l],$6800),d0 + move ([$beefcafe,a0,d0.l],$beefcafe),d0 + move ([$beefcafe,a0,d0.l],L0000b4),d0 + move ([$beefcafe,a0]),d0 + move ([$beefcafe,a0],$6800),d0 + move ([$beefcafe,a0],$beefcafe),d0 + move ([$beefcafe,a0],L0000b4),d0 + rts + +L0004cc: + move ([L0000b4,d0.l]),d0 + move ([L0000b4,d0.l],$6800),d0 + move ([L0000b4,d0.l],$beefcafe),d0 + move ([L0000b4,d0.l],L0000b4),d0 + move ([L0000b4]),d0 + move ([L0000b4],$6800),d0 + move ([L0000b4],$beefcafe),d0 + move ([L0000b4],L0000b4),d0 + move ([L0000b4,a0,d0.l]),d0 + move ([L0000b4,a0,d0.l],$6800),d0 + move ([L0000b4,a0,d0.l],$beefcafe),d0 + move ([L0000b4,a0,d0.l],L0000b4),d0 + move ([L0000b4,a0]),d0 + move ([L0000b4,a0],$6800),d0 + move ([L0000b4,a0],$beefcafe),d0 + move ([L0000b4,a0],L0000b4),d0 + rts + +L000576: + move ([zpc],d0.l),d0 + move ([zpc],d0.l,$6800),d0 + move ([zpc],d0.l,$beefcafe),d0 + move ([zpc],d0.l,L0000b4),d0 + move ([zpc]),d0 + move ([zpc],$6800),d0 + move ([zpc],$beefcafe),d0 + move ([zpc],L0000b4),d0 + move ([pc],d0.l),d0 + move ([pc],d0.l,$6800),d0 + move ([pc],d0.l,$beefcafe),d0 + move ([pc],d0.l,L0000b4),d0 + move ([pc]),d0 + move ([pc],$6800),d0 + move ([pc],$beefcafe),d0 + move ([pc],L0000b4),d0 + rts + +L0005e0: + move ([$6800,zpc],d0.l),d0 + move ([$6800,zpc],d0.l,$6800),d0 + move ([$6800,zpc],d0.l,$beefcafe),d0 + move ([$6800,zpc],d0.l,L0000b4),d0 + move ([$6800,zpc]),d0 + move ([$6800,zpc],$6800),d0 + move ([$6800,zpc],$beefcafe),d0 + move ([$6800,zpc],L0000b4),d0 + rts + +L000626: + move ([L0000b4,pc],d0.l),d0 + move ([L0000b4,pc],d0.l,$6800),d0 + move ([L0000b4,pc],d0.l,$beefcafe),d0 + move ([L0000b4,pc],d0.l,L0000b4),d0 + move ([L0000b4,pc]),d0 + move ([L0000b4,pc],$6800),d0 + move ([L0000b4,pc],$beefcafe),d0 + move ([L0000b4,pc],L0000b4),d0 + rts + +L00066c: + move ([$beefcafe,zpc],d0.l),d0 + move ([$beefcafe,zpc],d0.l,$6800),d0 + move ([$beefcafe,zpc],d0.l,$beefcafe),d0 + move ([$beefcafe,zpc],d0.l,L0000b4),d0 + move ([$beefcafe,zpc]),d0 + move ([$beefcafe,zpc],$6800),d0 + move ([$beefcafe,zpc],$beefcafe),d0 + move ([$beefcafe,zpc],L0000b4),d0 + rts + +L0006c2: + move ([L0000b4,zpc],d0.l),d0 + move ([L0000b4,zpc],d0.l,$6800),d0 + move ([L0000b4,zpc],d0.l,$beefcafe),d0 + move ([L0000b4,zpc],d0.l,L0000b4),d0 + move ([L0000b4,zpc]),d0 + move ([L0000b4,zpc],$6800),d0 + move ([L0000b4,zpc],$beefcafe),d0 + move ([L0000b4,zpc],L0000b4),d0 + move ([L0000b4.l,pc],d0.l),d0 + move ([L0000b4.l,pc],d0.l,$6800),d0 + move ([L0000b4.l,pc],d0.l,$beefcafe),d0 + move ([L0000b4.l,pc],d0.l,L0000b4),d0 + move ([L0000b4.l,pc]),d0 + move ([L0000b4.l,pc],$6800),d0 + move ([L0000b4.l,pc],$beefcafe),d0 + move ([L0000b4.l,pc],L0000b4),d0 + rts + +L00076c: + move ([zpc,d0.l]),d0 + move ([zpc,d0.l],$6800),d0 + move ([zpc,d0.l],$beefcafe),d0 + move ([zpc,d0.l],L0000b4),d0 + move ([zpc]),d0 + move ([zpc],$6800),d0 + move ([zpc],$beefcafe),d0 + move ([zpc],L0000b4),d0 + move ([pc,d0.l]),d0 + move ([pc,d0.l],$6800),d0 + move ([pc,d0.l],$beefcafe),d0 + move ([pc,d0.l],L0000b4),d0 + move ([pc]),d0 + move ([pc],$6800),d0 + move ([pc],$beefcafe),d0 + move ([pc],L0000b4),d0 + rts + +L0007d6: + move ([L0000b4,pc,d0.l]),d0 + move ([L0000b4,pc,d0.l],$6800),d0 + move ([L0000b4,pc,d0.l],$beefcafe),d0 + move ([L0000b4,pc,d0.l],L0000b4),d0 + move ([L0000b4,pc]),d0 + move ([L0000b4,pc],$6800),d0 + move ([L0000b4,pc],$beefcafe),d0 + move ([L0000b4,pc],L0000b4),d0 + rts + +L00081c: + move ([$beefcafe,zpc,d0.l]),d0 + move ([$beefcafe,zpc,d0.l],$6800),d0 + move ([$beefcafe,zpc,d0.l],$beefcafe),d0 + move ([$beefcafe,zpc,d0.l],L0000b4),d0 + move ([$beefcafe,zpc]),d0 + move ([$beefcafe,zpc],$6800),d0 + move ([$beefcafe,zpc],$beefcafe),d0 + move ([$beefcafe,zpc],L0000b4),d0 + move ([L000000-$41102c90,pc,d0.l]),d0 + move ([L000000-$41102c88,pc,d0.l],$6800),d0 + move ([L000000-$41102c7e,pc,d0.l],$beefcafe),d0 + move ([L000000-$41102c72,pc,d0.l],L0000b4),d0 + move ([L000000-$41102c66,pc]),d0 + move ([L000000-$41102c5e,pc],$6800),d0 + move ([L000000-$41102c54,pc],$beefcafe),d0 + move ([L000000-$41102c48,pc],L0000b4),d0 + rts + +L0008c6: + move ([L0000b4,zpc,d0.l]),d0 + move ([L0000b4,zpc,d0.l],$6800),d0 + move ([L0000b4,zpc,d0.l],$beefcafe),d0 + move ([L0000b4,zpc,d0.l],L0000b4),d0 + move ([L0000b4,zpc]),d0 + move ([L0000b4,zpc],$6800),d0 + move ([L0000b4,zpc],$beefcafe),d0 + move ([L0000b4,zpc],L0000b4),d0 + move ([L0000b4.l,pc,d0.l]),d0 + move ([L0000b4.l,pc,d0.l],$6800),d0 + move ([L0000b4.l,pc,d0.l],$beefcafe),d0 + move ([L0000b4.l,pc,d0.l],L0000b4),d0 + move ([L0000b4.l,pc]),d0 + move ([L0000b4.l,pc],$6800),d0 + move ([L0000b4.l,pc],$beefcafe),d0 + move ([L0000b4.l,pc],L0000b4),d0 + rts + +L000970: + + .end L000000 diff --git a/tests/expected/ea_misc.s b/tests/expected/ea_misc.s new file mode 100644 index 0000000..0dba5d9 --- /dev/null +++ b/tests/expected/ea_misc.s @@ -0,0 +1,68 @@ +;============================================= +; Filename obj/ea_misc.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000076 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/ea_misc.x dised/ea_misc.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + cmpm (a0)+,(a0)+ + cmpm (a0)+,(sp)+ + cmpm (sp)+,(sp)+ + cmpm (a6)+,(a6)+ + nop + addx -(a0),-(a0) + addx -(a0),-(sp) + addx -(sp),-(a0) + addx -(sp),-(sp) + addx d0,d0 + addx d0,d7 + addx d7,d0 + addx d7,d7 + nop + abcd -(a0),-(a0) + abcd -(a0),-(sp) + abcd -(sp),-(a0) + abcd -(sp),-(sp) + abcd d0,d0 + abcd d0,d7 + abcd d7,d0 + abcd d7,d7 + nop + .cpu 68020 + pack d0,d0,#$30 + pack d0,d7,#0 + unpk d7,d0,#$ffff + unpk d3,d4,#$80 + nop + pack -(a0),-(a0),#$30 + pack -(a0),-(sp),#0 + unpk -(a6),-(a0),#$ffff + unpk -(a3),-(a4),#$80 + nop + .cpu 68040 + move16 (a0)+,(0) + move16 (0),(a0)+ + move16 (a0),(0) + move16 (0),(a0) + move16 (a0)+,(a0)+ + move16 (sp)+,(sp)+ + nop + DOS _EXIT + +L000076: + + .end L000000 diff --git a/tests/expected/fmovem.s b/tests/expected/fmovem.s new file mode 100644 index 0000000..5e9d74c --- /dev/null +++ b/tests/expected/fmovem.s @@ -0,0 +1,90 @@ +;============================================= +; Filename obj/fmovem.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000098 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 18 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/fmovem.x dised/fmovem.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + fmove.b #0,fp0 + fmove.b #1,fp1 + fmove.b #$14,fp2 + fmove.w #$12c,fp3 + fmove.w #$fa0,fp4 + fmove.l #$c350,fp5 + fmove.l #$927c0,fp6 + fmove.l #$6acfc0,fp7 + rts + +L000038: + fmovem.x fp0-fp3,(a0) + rts + +L00003e: + .dc.b $f2,$10,$e0,$f0,$4e,$75 + +L000044: + fmovem.x d0,(a0) + rts + +L00004a: + .dc.b $f2,$10,$e8,$00,$4e,$75 + +L000050: + fmovem.x fp0-fp3,-(a0) + rts + +L000056: + .dc.b $f2,$20,$f0,$0f,$4e,$75 + +L00005c: + fmovem.x d0,-(a0) + rts + +L000062: + .dc.b $f2,$20,$f8,$00,$4e,$75 + +L000068: + fmovem.x (a0),fp0-fp3 + rts + +L00006e: + .dc.b $f2,$10,$c0,$f0,$4e,$75 + +L000074: + fmovem.x (a0),d0 + rts + +L00007a: + .dc.b $f2,$10,$c8,$00,$4e,$75 + +L000080: + fmovem.x (a0),fp0-fp3 + rts + +L000086: + .dc.b $f2,$10,$c0,$f0,$4e,$75 + +L00008c: + fmovem.x (a0),d0 + rts + +L000092: + .dc.b $f2,$10,$c8,$00,$4e,$75 +L000098: + + .end L000000 diff --git a/tests/expected/fp_imm.s b/tests/expected/fp_imm.s new file mode 100644 index 0000000..cb4dc6c --- /dev/null +++ b/tests/expected/fp_imm.s @@ -0,0 +1,128 @@ +;============================================= +; Filename obj/fp_imm.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $000002c4 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 14 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/fp_imm.x dised/fp_imm.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +SingleZero:: + .cpu 68040 + fmove.s #0f0,fp0 + nop + fmove.s #0f-0,fp0 + rts + +SingleDenorm:: + fmove.s #!00000001,fp0 + fmove.s #!00400000,fp0 + nop + fmove.s #!80000001,fp0 + fmove.s #!80400000,fp0 + rts + +SingleInf:: + fmove.s #!7f800000,fp0 + nop + fmove.s #!ff800000,fp0 + rts + +SingleNaN:: + fmove.s #!7f800001,fp0 + fmove.s #!7fc00000,fp0 + nop + fmove.s #!ff800001,fp0 + fmove.s #!ffc00000,fp0 + rts + +DoubleZero:: + fmove.d #0f0,fp0 + nop + fmove.d #0f-0,fp0 + rts + +DoubleDenorm:: + fmove.d #!00000000_00000001,fp0 + fmove.d #!00000000_80000000,fp0 + fmove.d #!00000001_00000000,fp0 + fmove.d #!00080000_00000000,fp0 + nop + fmove.d #!80000000_00000001,fp0 + fmove.d #!80000000_80000000,fp0 + fmove.d #!80000001_00000000,fp0 + fmove.d #!80080000_00000000,fp0 + rts + +DoubleInf:: + fmove.d #!7ff00000_00000000,fp0 + nop + fmove.d #!fff00000_00000000,fp0 + rts + +DoubleNaN:: + fmove.d #!7ff00000_00000001,fp0 + fmove.d #!7ff00000_80000000,fp0 + fmove.d #!7ff00001_00000000,fp0 + fmove.d #!7ff80000_00000000,fp0 + nop + fmove.d #!fff00000_00000001,fp0 + fmove.d #!fff00000_80000000,fp0 + fmove.d #!fff00001_00000000,fp0 + fmove.d #!fff80000_00000000,fp0 + rts + +ExtendedZero:: + fmove #0f0,fp0 + nop + fmove #0f-0,fp0 + rts + +ExtendedDenorm:: + fmove #!00000000_00000000_00000001,fp0 + fmove #!00000000_00000000_80000000,fp0 + fmove #!00000000_00000001_00000000,fp0 + fmove #!00000000_80000000_00000000,fp0 + nop + fmove #!80000000_00000000_00000001,fp0 + fmove #!80000000_00000000_80000000,fp0 + fmove #!80000000_00000001_00000000,fp0 + fmove #!80000000_80000000_00000000,fp0 + rts + +ExtendedInf:: + fmove #!7fff0000_00000000_00000000,fp0 + nop + fmove #!ffff0000_00000000_00000000,fp0 + rts + +ExtendedNaN:: + fmove #!7fff0000_00000000_00000001,fp0 + fmove #!7fff0000_00000000_80000000,fp0 + fmove #!7fff0000_00000001_00000000,fp0 + fmove #!7fff0000_80000000_00000000,fp0 + nop + rts + +ExtendedReservedNotZero:: + fmove #!00000001_00000000_00000000,fp0 + fmove #!00008000_00000000_00000000,fp0 + nop + fmove #!80000001_00000000_00000000,fp0 + fmove #!80008000_00000000_00000000,fp0 + rts + +L0002c4: + + .end SingleZero diff --git a/tests/expected/fp_undefreg.s b/tests/expected/fp_undefreg.s new file mode 100644 index 0000000..2bd28b0 --- /dev/null +++ b/tests/expected/fp_undefreg.s @@ -0,0 +1,68 @@ +;============================================= +; Filename obj/fp_undefreg.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000005a byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 16 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/fp_undefreg.x dised/fp_undefreg.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + ftst fp0 + rts + +L000006: + .dc.b $f2,$04,$00,$3a,$4e,$75 +L00000c: + .dc.b $f2,$00,$01,$3a,$4e,$75 +L000012: + .dc.b $f2,$00,$0f,$3a,$4e,$75 + +L000018: + fmove fp0,fp0 + rts + +L00001e: + .dc.b $f2,$01,$00,$00,$4e,$75 + +L000024: + fmovecr #0,fp0 + rts + +L00002a: + .dc.b $f2,$01,$5c,$00,$4e,$75 +L000030: + .dc.b $f2,$08,$5c,$00,$4e,$75 +L000036: + .dc.b $f2,$3f,$5c,$00,$4e,$75 + +L00003c: + fmove.p fp0,(a0){d7} + rts + +L000042: + .dc.b $f2,$10,$7c,$7f,$4e,$75 + +L000048: + fmove fp0,(a0) + rts + +L00004e: + .dc.b $f2,$10,$68,$40,$4e,$75 +L000054: + .dc.b $f2,$10,$68,$01,$4e,$75 +L00005a: + + .end L000000 diff --git a/tests/expected/fsincos.s b/tests/expected/fsincos.s new file mode 100644 index 0000000..25321b8 --- /dev/null +++ b/tests/expected/fsincos.s @@ -0,0 +1,31 @@ +;============================================= +; Filename obj/fsincos.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000010 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/fsincos.x dised/fsincos.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + fsincos fp0,fp1:fp0 + fsincos fp7,fp0:fp7 + fsincos (a0),fp0:fp1 + nop + DOS _EXIT + +L000010: + + .end L000000 diff --git a/tests/expected/imm.s b/tests/expected/imm.s new file mode 100644 index 0000000..64f4aef --- /dev/null +++ b/tests/expected/imm.s @@ -0,0 +1,141 @@ +;============================================= +; Filename obj/imm.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000118 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 20 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/imm.x dised/imm.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + btst #0,d0 + btst #$1f,d7 + btst #0,(a0) + btst #7,(a0) + rts + +L000012: + ori #0,d0 + ori #$8000,d1 + ori #$ffff,d7 + rts + +L000020: + stop #0 + stop #$ffff + rts + +L00002a: + .cpu 68010 + rtd #0 + +L00002e: + rtd #$ffff + +L000032: + rts + +L000034: + .cpu 68020 + trapcc #0 + trapcc #$ffff + trapcc.l #0 + trapcc.l #$ffffffff + rts + +L00004a: + pack d0,d7,#0 + pack d7,d0,#$ffff + unpk d0,d7,#0 + unpk d7,d0,#$ffff + rts + +L00005c: + .cpu 68060 + lpstop #0 + lpstop #$ffff + rts + +L00006a: + .cpu 68020 + ptrapcc #0 + ptrapcc #$ffff + ptrapcc.l #0 + ptrapcc.l #$ffffffff + rts + +L000088: + ftrapeq #0 + ftrapeq #$ffff + ftrapeq.l #0 + ftrapeq.l #$ffffffff + rts + +L0000a6: + link a6,#0 + link a6,#$7fff + link a6,#-1 + link a6,#-$8000 + link.l a6,#0 + link.l a6,#$7fffffff + link.l a6,#-1 + link.l a6,#-$80000000 + rts + +L0000d0: + callm #0,(a0) + rtm d0 + callm #$ff,(a0) + rtm d7 + trap #0 + IOCS _B_KEYINP + rts + +L0000e4: + bkpt #0 + bkpt #7 + rts + +L0000ea: + moveq #0,d0 + moveq #$7f,d1 + moveq #$80,d6 + moveq #$ff,d7 + rts + +L0000f4: + fmovecr #0,fp0 + fmovecr #$7f,fp7 + rts + +L0000fe: + ptestr sfc,(a0),#0 + ptestr sfc,(a0),#7 + rts + +L000108: + addq #1,d0 + addq #8,d7 + subq #1,d0 + subq #8,d7 + rts + +L000112: + lsl #1,d0 + lsl #8,d0 + rts + +L000118: + + .end L000000 diff --git a/tests/expected/imm_comment.s b/tests/expected/imm_comment.s new file mode 100644 index 0000000..2f27190 --- /dev/null +++ b/tests/expected/imm_comment.s @@ -0,0 +1,63 @@ +;============================================= +; Filename obj/imm_comment.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $000000b4 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/imm_comment.x dised/imm_comment.s -M +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + moveq #$61,d0 ;'a' + move.b #$61,d0 ;'a' + move #$6162,d0 ;'ab' + move #$78,d0 ;'x' + move.l #$61626364,d0 ;'abcd' + move.l #$78797a,d0 ;'xyz' + move.l #$78797a00,d0 ;'xyz'<<8 + move.l #$787900,d0 ;'xy'<<8 + cmp.b #$61,d0 ;'a' + cmp #$6162,d0 ;'ab' + cmp #$78,d0 ;'x' + cmp.l #$61626364,d0 ;'abcd' + cmp.l #$78797a,d0 ;'xyz' + cmp.l #$78797a00,d0 ;'xyz'<<8 + cmp.l #$787900,d0 ;'xy'<<8 + cmpi.b #$61,d0 ;'a' + cmpi #$6162,d0 ;'ab' + cmpi #$78,d0 ;'x' + cmpi.l #$61626364,d0 ;'abcd' + cmpi.l #$78797a,d0 ;'xyz' + cmpi.l #$78797a00,d0 ;'xyz'<<8 + cmpi.l #$787900,d0 ;'xy'<<8 + cmpa #$6162,a0 ;'ab' + cmpa #$78,a0 ;'x' + cmpa.l #$61626364,a0 ;'abcd' + cmpa.l #$78797a,a0 ;'xyz' + cmpa.l #$78797a00,a0 ;'xyz'<<8 + cmpa.l #$787900,a0 ;'xy'<<8 + add.b #$61,d0 ;'a' + add #$6162,d0 + add.l #$61626364,d0 + sub.b #$61,d0 ;'a' + sub #$6162,d0 + sub.l #$61626364,d0 + .cpu 68020 + pack d0,d0,#$6162 ;'ab' + unpk d0,d0,#$6162 ;'ab' + DOS _EXIT + +L0000b4: + + .end L000000 diff --git a/tests/expected/kfactor.s b/tests/expected/kfactor.s new file mode 100644 index 0000000..46339ab --- /dev/null +++ b/tests/expected/kfactor.s @@ -0,0 +1,35 @@ +;============================================= +; Filename obj/kfactor.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000020 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/kfactor.x dised/kfactor.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + fmove.p fp0,(a0){d0} + fmove.p fp7,(a0){d7} + nop + fmove.p fp0,(a0){#-64} + fmove.p fp0,(a0){#-1} + fmove.p fp0,(a0){#0} + fmove.p fp0,(a0){#-1} + fmove.p fp0,(a0){#-63} + DOS _EXIT + +L000020: + + .end L000000 diff --git a/tests/expected/lab_in_reltbl.s b/tests/expected/lab_in_reltbl.s new file mode 100644 index 0000000..b892781 --- /dev/null +++ b/tests/expected/lab_in_reltbl.s @@ -0,0 +1,49 @@ +;============================================= +; Filename obj/lab_in_reltbl.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000001e byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 8 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/lab_in_reltbl.x dised/lab_in_reltbl.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + move (L00000a,pc,d0.w),d0 + jsr (L00000a,pc,d0.w) + DOS _EXIT + +L00000a: + .dc L000012-L00000a + .dc L000014-L00000a + .dc L000016-L00000a + .dc.b $00 +xxx:: + .dc.b $e + +L000012: + rts + +L000014: + rts + +L000016: + rts + +L000018: + lea (xxx,pc),a0 + rts + +L00001e: + + .end L000000 diff --git a/tests/expected/lab_oorange.s b/tests/expected/lab_oorange.s new file mode 100644 index 0000000..3b60f41 --- /dev/null +++ b/tests/expected/lab_oorange.s @@ -0,0 +1,28 @@ +;============================================= +; Filename obj/lab_oorange.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000000a byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/lab_oorange.x dised/lab_oorange.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + lea (L000000-$100,pc),a0 + lea (L00000a+$100,pc),a1 + DOS _EXIT + +L00000a: + + .end L000000 diff --git a/tests/expected/lab_rw.s b/tests/expected/lab_rw.s new file mode 100644 index 0000000..ff82bcf --- /dev/null +++ b/tests/expected/lab_rw.s @@ -0,0 +1,44 @@ +;============================================= +; Filename obj/lab_rw.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000001c byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 6 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/lab_rw.x dised/lab_rw.s -gsrc/lab_rw.lab +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + moveq #0,d0 + move (L00000e,pc,d0.w),d0 + nop + jsr (L00000e,pc,d0.w) + DOS _EXIT + +L00000e: + .dc L000018-L00000e + .dc L00001a-L00000e + +L000012: + ori.b #$a,(a0) + rts + +L000018: + rts + +L00001a: + rts + +L00001c: + + .end L000000 diff --git a/tests/expected/mmu.s b/tests/expected/mmu.s new file mode 100644 index 0000000..166fc3e --- /dev/null +++ b/tests/expected/mmu.s @@ -0,0 +1,143 @@ +;============================================= +; Filename obj/mmu.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000132 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 10 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/mmu.x dised/mmu.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + pflush (a0) + pflushn (sp) + pflusha + pflushan + nop + ptestr (a0) + ptestw (sp) + nop + .cpu 68060 + plpar (a0) + plpaw (sp) + nop + rts + +L000018: + .cpu 68030 + pmovefd (a0),srp + ploadr sfc,(a0) + ploadr dfc,(a0) + ploadr d0,(a0) + ploadr d7,(a0) + ploadr #0,(a0) + ploadr #7,(a0) + .cpu 68020 + ploadr #8,(a0) + ploadr #15,(a0) + nop + rts + +L000040: + .cpu 68030 + pmovefd (a0),srp + ploadw sfc,(a0) + ploadw dfc,(a0) + ploadw d0,(a0) + ploadw d7,(a0) + ploadw #0,(a0) + ploadw #7,(a0) + .cpu 68020 + ploadw #8,(a0) + ploadw #15,(a0) + nop + rts + +L000068: + .cpu 68030 + pmovefd (a0),srp + pflush sfc,#0 + pflush dfc,#7,(a0) + pflush #1,#0 + pflush #6,#7,(a0) + .cpu 68020 + pflush sfc,#8 + pflush dfc,#15,(a0) + pflush #8,#0 + pflush #15,#7,(a0) + nop + rts + +L000090: + .cpu 68030 + pmovefd (a0),srp + .cpu 68020 + pflushs sfc,#0 + pflushs dfc,#7,(a0) + pflushs #1,#0 + pflushs #6,#7,(a0) + pflushs sfc,#8 + pflushs dfc,#15,(a0) + pflushs #8,#0 + pflushs #15,#7,(a0) + nop + rts + +L0000b8: + .cpu 68030 + pmovefd (a0),srp + ptestr #0,(a0),#7 + ptestr #7,(sp),#0 + ptestr #0,(a0),#7,sp + ptestw #0,(a0),#7 + ptestw #7,(sp),#0 + ptestw #0,(a0),#7,sp + nop + rts + +L0000d8: + pmovefd (a0),srp + pmove mmusr,(a0) + .cpu 68020 + pmove pcsr,(a0) + pmove bad0,(a0) + pmove bad7,(a0) + pmove bac0,(a0) + pmove bac7,(a0) + nop + rts + +L0000f8: + .cpu 68030 + pmove tt0,(a0) + pmove tt1,(a0) + pmove tc,(a0) + .cpu 68020 + pmove drp,(a0) + pmove srp,(a0) + pmove crp,(a0) + pmove cal,(a0) + pmove val,(a0) + pmove scc,(a0) + pmove ac,(a0) + nop + rts + +L000124: + pmove #!12345678_9abcdef0,crp + rts + +L000132: + + .end L000000 diff --git a/tests/expected/mmu_undefreg.s b/tests/expected/mmu_undefreg.s new file mode 100644 index 0000000..5b71bbe --- /dev/null +++ b/tests/expected/mmu_undefreg.s @@ -0,0 +1,51 @@ +;============================================= +; Filename obj/mmu_undefreg.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000030 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 9 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/mmu_undefreg.x dised/mmu_undefreg.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + ptestr sfc,(a0),#1,a1 + rts + +L000006: + .dc.b $f0,$10,$82,$20,$4e,$75 + +L00000c: + ptestr sfc,(a0),#1,a1 + rts + +L000012: + .dc.b $f0,$10,$86,$20,$4e,$75 + +L000018: + pflusha + rts + +L00001e: + .dc.b $f0,$11,$24,$00,$4e,$75 + +L000024: + pflush sfc,#0,(a1) + rts + +L00002a: + .dc.b $f0,$11,$30,$00,$4e,$75 +L000030: + + .end L000000 diff --git a/tests/expected/movec.s b/tests/expected/movec.s new file mode 100644 index 0000000..3acfa9c --- /dev/null +++ b/tests/expected/movec.s @@ -0,0 +1,73 @@ +;============================================= +; Filename obj/movec.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000007a byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 7 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/movec.x dised/movec.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68010 + movec d0,sfc + movec d0,dfc + .cpu 68020 + movec d0,cacr + .cpu 68040 + movec d0,tc + movec d0,itt0 + movec d0,itt1 + movec d0,dtt0 + movec d0,dtt1 + .cpu 68060 + movec d0,buscr + nop + movec d0,usp + movec d0,vbr + .cpu 68020 + movec d0,caar + movec d0,msp + movec d0,isp + .cpu 68040 + movec d0,mmusr + movec d0,urp + movec d0,srp + .cpu 68060 + movec d0,pcr + nop + move d0,ccr + move ccr,d0 + move d0,sr + move sr,d0 + nop + move a0,usp + move usp,a0 + nop + DOS _EXIT + +L00005e: + nop + rts + +L000062: + .dc.b $4e,$7b,$0f,$ff,$4e,$75 +L000068: + .dc.b $4e,$7b,$00,$09,$4e,$75 +L00006e: + .dc.b $4e,$7b,$07,$ff,$4e,$75 +L000074: + .dc.b $4e,$7b,$08,$09,$4e,$75 +L00007a: + + .end L000000 diff --git a/tests/expected/pflush040.s b/tests/expected/pflush040.s new file mode 100644 index 0000000..4c7caa0 --- /dev/null +++ b/tests/expected/pflush040.s @@ -0,0 +1,41 @@ +;============================================= +; Filename obj/pflush040.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000018 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 7 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/pflush040.x dised/pflush040.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + pflusha + rts + +L000004: + .dc.b $f5,$19,$4e,$75 +L000008: + .dc.b $f5,$1c,$4e,$75 + +L00000c: + pflushan + rts + +L000010: + .dc.b $f5,$11,$4e,$75 +L000014: + .dc.b $f5,$14,$4e,$75 +L000018: + + .end L000000 diff --git a/tests/expected/pflush040_R0.s b/tests/expected/pflush040_R0.s new file mode 100644 index 0000000..4248e0a --- /dev/null +++ b/tests/expected/pflush040_R0.s @@ -0,0 +1,48 @@ +;============================================= +; Filename obj/pflush040.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000018 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 7 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/pflush040.x dised/pflush040_R0.s -R0 +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68040 + pflusha + rts + +L000004: + pflusha + rts + +L000008: + pflusha + rts + +L00000c: + pflushan + rts + +L000010: + pflushan + rts + +L000014: + pflushan + rts + +L000018: + + .end L000000 diff --git a/tests/expected/registdata.s b/tests/expected/registdata.s new file mode 100644 index 0000000..b4bd3f8 --- /dev/null +++ b/tests/expected/registdata.s @@ -0,0 +1,37 @@ +;============================================= +; Filename obj/registdata.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000028 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 4 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/registdata.x dised/registdata.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + move (2,zpc),d0 + move ([8,zpc]),d0 + nop + move (L000022,zpc),d0 + move ([L000024,zpc]),d0 + nop + DOS _EXIT + +L000022: + .dc $beef +L000024: + .dc.l $12345678 +L000028: + + .end L000000 diff --git a/tests/expected/reglist.s b/tests/expected/reglist.s new file mode 100644 index 0000000..a13484c --- /dev/null +++ b/tests/expected/reglist.s @@ -0,0 +1,1153 @@ +;============================================= +; Filename obj/reglist.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $000010da byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/reglist.x dised/reglist.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + movem d0,(a0) + movem d1,(a0) + movem d0-d1,(a0) + movem d2,(a0) + movem d0/d2,(a0) + movem d1-d2,(a0) + movem d0-d2,(a0) + movem d3,(a0) + movem d0/d3,(a0) + movem d1/d3,(a0) + movem d0-d1/d3,(a0) + movem d2-d3,(a0) + movem d0/d2-d3,(a0) + movem d1-d3,(a0) + movem d0-d3,(a0) + movem d4,(a0) + movem d0/d4,(a0) + movem d1/d4,(a0) + movem d0-d1/d4,(a0) + movem d2/d4,(a0) + movem d0/d2/d4,(a0) + movem d1-d2/d4,(a0) + movem d0-d2/d4,(a0) + movem d3-d4,(a0) + movem d0/d3-d4,(a0) + movem d1/d3-d4,(a0) + movem d0-d1/d3-d4,(a0) + movem d2-d4,(a0) + movem d0/d2-d4,(a0) + movem d1-d4,(a0) + movem d0-d4,(a0) + movem d5,(a0) + movem d0/d5,(a0) + movem d1/d5,(a0) + movem d0-d1/d5,(a0) + movem d2/d5,(a0) + movem d0/d2/d5,(a0) + movem d1-d2/d5,(a0) + movem d0-d2/d5,(a0) + movem d3/d5,(a0) + movem d0/d3/d5,(a0) + movem d1/d3/d5,(a0) + movem d0-d1/d3/d5,(a0) + movem d2-d3/d5,(a0) + movem d0/d2-d3/d5,(a0) + movem d1-d3/d5,(a0) + movem d0-d3/d5,(a0) + movem d4-d5,(a0) + movem d0/d4-d5,(a0) + movem d1/d4-d5,(a0) + movem d0-d1/d4-d5,(a0) + movem d2/d4-d5,(a0) + movem d0/d2/d4-d5,(a0) + movem d1-d2/d4-d5,(a0) + movem d0-d2/d4-d5,(a0) + movem d3-d5,(a0) + movem d0/d3-d5,(a0) + movem d1/d3-d5,(a0) + movem d0-d1/d3-d5,(a0) + movem d2-d5,(a0) + movem d0/d2-d5,(a0) + movem d1-d5,(a0) + movem d0-d5,(a0) + movem d6,(a0) + movem d0/d6,(a0) + movem d1/d6,(a0) + movem d0-d1/d6,(a0) + movem d2/d6,(a0) + movem d0/d2/d6,(a0) + movem d1-d2/d6,(a0) + movem d0-d2/d6,(a0) + movem d3/d6,(a0) + movem d0/d3/d6,(a0) + movem d1/d3/d6,(a0) + movem d0-d1/d3/d6,(a0) + movem d2-d3/d6,(a0) + movem d0/d2-d3/d6,(a0) + movem d1-d3/d6,(a0) + movem d0-d3/d6,(a0) + movem d4/d6,(a0) + movem d0/d4/d6,(a0) + movem d1/d4/d6,(a0) + movem d0-d1/d4/d6,(a0) + movem d2/d4/d6,(a0) + movem d0/d2/d4/d6,(a0) + movem d1-d2/d4/d6,(a0) + movem d0-d2/d4/d6,(a0) + movem d3-d4/d6,(a0) + movem d0/d3-d4/d6,(a0) + movem d1/d3-d4/d6,(a0) + movem d0-d1/d3-d4/d6,(a0) + movem d2-d4/d6,(a0) + movem d0/d2-d4/d6,(a0) + movem d1-d4/d6,(a0) + movem d0-d4/d6,(a0) + movem d5-d6,(a0) + movem d0/d5-d6,(a0) + movem d1/d5-d6,(a0) + movem d0-d1/d5-d6,(a0) + movem d2/d5-d6,(a0) + movem d0/d2/d5-d6,(a0) + movem d1-d2/d5-d6,(a0) + movem d0-d2/d5-d6,(a0) + movem d3/d5-d6,(a0) + movem d0/d3/d5-d6,(a0) + movem d1/d3/d5-d6,(a0) + movem d0-d1/d3/d5-d6,(a0) + movem d2-d3/d5-d6,(a0) + movem d0/d2-d3/d5-d6,(a0) + movem d1-d3/d5-d6,(a0) + movem d0-d3/d5-d6,(a0) + movem d4-d6,(a0) + movem d0/d4-d6,(a0) + movem d1/d4-d6,(a0) + movem d0-d1/d4-d6,(a0) + movem d2/d4-d6,(a0) + movem d0/d2/d4-d6,(a0) + movem d1-d2/d4-d6,(a0) + movem d0-d2/d4-d6,(a0) + movem d3-d6,(a0) + movem d0/d3-d6,(a0) + movem d1/d3-d6,(a0) + movem d0-d1/d3-d6,(a0) + movem d2-d6,(a0) + movem d0/d2-d6,(a0) + movem d1-d6,(a0) + movem d0-d6,(a0) + movem d7,(a0) + movem d0/d7,(a0) + movem d1/d7,(a0) + movem d0-d1/d7,(a0) + movem d2/d7,(a0) + movem d0/d2/d7,(a0) + movem d1-d2/d7,(a0) + movem d0-d2/d7,(a0) + movem d3/d7,(a0) + movem d0/d3/d7,(a0) + movem d1/d3/d7,(a0) + movem d0-d1/d3/d7,(a0) + movem d2-d3/d7,(a0) + movem d0/d2-d3/d7,(a0) + movem d1-d3/d7,(a0) + movem d0-d3/d7,(a0) + movem d4/d7,(a0) + movem d0/d4/d7,(a0) + movem d1/d4/d7,(a0) + movem d0-d1/d4/d7,(a0) + movem d2/d4/d7,(a0) + movem d0/d2/d4/d7,(a0) + movem d1-d2/d4/d7,(a0) + movem d0-d2/d4/d7,(a0) + movem d3-d4/d7,(a0) + movem d0/d3-d4/d7,(a0) + movem d1/d3-d4/d7,(a0) + movem d0-d1/d3-d4/d7,(a0) + movem d2-d4/d7,(a0) + movem d0/d2-d4/d7,(a0) + movem d1-d4/d7,(a0) + movem d0-d4/d7,(a0) + movem d5/d7,(a0) + movem d0/d5/d7,(a0) + movem d1/d5/d7,(a0) + movem d0-d1/d5/d7,(a0) + movem d2/d5/d7,(a0) + movem d0/d2/d5/d7,(a0) + movem d1-d2/d5/d7,(a0) + movem d0-d2/d5/d7,(a0) + movem d3/d5/d7,(a0) + movem d0/d3/d5/d7,(a0) + movem d1/d3/d5/d7,(a0) + movem d0-d1/d3/d5/d7,(a0) + movem d2-d3/d5/d7,(a0) + movem d0/d2-d3/d5/d7,(a0) + movem d1-d3/d5/d7,(a0) + movem d0-d3/d5/d7,(a0) + movem d4-d5/d7,(a0) + movem d0/d4-d5/d7,(a0) + movem d1/d4-d5/d7,(a0) + movem d0-d1/d4-d5/d7,(a0) + movem d2/d4-d5/d7,(a0) + movem d0/d2/d4-d5/d7,(a0) + movem d1-d2/d4-d5/d7,(a0) + movem d0-d2/d4-d5/d7,(a0) + movem d3-d5/d7,(a0) + movem d0/d3-d5/d7,(a0) + movem d1/d3-d5/d7,(a0) + movem d0-d1/d3-d5/d7,(a0) + movem d2-d5/d7,(a0) + movem d0/d2-d5/d7,(a0) + movem d1-d5/d7,(a0) + movem d0-d5/d7,(a0) + movem d6-d7,(a0) + movem d0/d6-d7,(a0) + movem d1/d6-d7,(a0) + movem d0-d1/d6-d7,(a0) + movem d2/d6-d7,(a0) + movem d0/d2/d6-d7,(a0) + movem d1-d2/d6-d7,(a0) + movem d0-d2/d6-d7,(a0) + movem d3/d6-d7,(a0) + movem d0/d3/d6-d7,(a0) + movem d1/d3/d6-d7,(a0) + movem d0-d1/d3/d6-d7,(a0) + movem d2-d3/d6-d7,(a0) + movem d0/d2-d3/d6-d7,(a0) + movem d1-d3/d6-d7,(a0) + movem d0-d3/d6-d7,(a0) + movem d4/d6-d7,(a0) + movem d0/d4/d6-d7,(a0) + movem d1/d4/d6-d7,(a0) + movem d0-d1/d4/d6-d7,(a0) + movem d2/d4/d6-d7,(a0) + movem d0/d2/d4/d6-d7,(a0) + movem d1-d2/d4/d6-d7,(a0) + movem d0-d2/d4/d6-d7,(a0) + movem d3-d4/d6-d7,(a0) + movem d0/d3-d4/d6-d7,(a0) + movem d1/d3-d4/d6-d7,(a0) + movem d0-d1/d3-d4/d6-d7,(a0) + movem d2-d4/d6-d7,(a0) + movem d0/d2-d4/d6-d7,(a0) + movem d1-d4/d6-d7,(a0) + movem d0-d4/d6-d7,(a0) + movem d5-d7,(a0) + movem d0/d5-d7,(a0) + movem d1/d5-d7,(a0) + movem d0-d1/d5-d7,(a0) + movem d2/d5-d7,(a0) + movem d0/d2/d5-d7,(a0) + movem d1-d2/d5-d7,(a0) + movem d0-d2/d5-d7,(a0) + movem d3/d5-d7,(a0) + movem d0/d3/d5-d7,(a0) + movem d1/d3/d5-d7,(a0) + movem d0-d1/d3/d5-d7,(a0) + movem d2-d3/d5-d7,(a0) + movem d0/d2-d3/d5-d7,(a0) + movem d1-d3/d5-d7,(a0) + movem d0-d3/d5-d7,(a0) + movem d4-d7,(a0) + movem d0/d4-d7,(a0) + movem d1/d4-d7,(a0) + movem d0-d1/d4-d7,(a0) + movem d2/d4-d7,(a0) + movem d0/d2/d4-d7,(a0) + movem d1-d2/d4-d7,(a0) + movem d0-d2/d4-d7,(a0) + movem d3-d7,(a0) + movem d0/d3-d7,(a0) + movem d1/d3-d7,(a0) + movem d0-d1/d3-d7,(a0) + movem d2-d7,(a0) + movem d0/d2-d7,(a0) + movem d1-d7,(a0) + movem d0-d7,(a0) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + movem a0,(a0) + movem a1,(a0) + movem a0-a1,(a0) + movem a2,(a0) + movem a0/a2,(a0) + movem a1-a2,(a0) + movem a0-a2,(a0) + movem a3,(a0) + movem a0/a3,(a0) + movem a1/a3,(a0) + movem a0-a1/a3,(a0) + movem a2-a3,(a0) + movem a0/a2-a3,(a0) + movem a1-a3,(a0) + movem a0-a3,(a0) + movem a4,(a0) + movem a0/a4,(a0) + movem a1/a4,(a0) + movem a0-a1/a4,(a0) + movem a2/a4,(a0) + movem a0/a2/a4,(a0) + movem a1-a2/a4,(a0) + movem a0-a2/a4,(a0) + movem a3-a4,(a0) + movem a0/a3-a4,(a0) + movem a1/a3-a4,(a0) + movem a0-a1/a3-a4,(a0) + movem a2-a4,(a0) + movem a0/a2-a4,(a0) + movem a1-a4,(a0) + movem a0-a4,(a0) + movem a5,(a0) + movem a0/a5,(a0) + movem a1/a5,(a0) + movem a0-a1/a5,(a0) + movem a2/a5,(a0) + movem a0/a2/a5,(a0) + movem a1-a2/a5,(a0) + movem a0-a2/a5,(a0) + movem a3/a5,(a0) + movem a0/a3/a5,(a0) + movem a1/a3/a5,(a0) + movem a0-a1/a3/a5,(a0) + movem a2-a3/a5,(a0) + movem a0/a2-a3/a5,(a0) + movem a1-a3/a5,(a0) + movem a0-a3/a5,(a0) + movem a4-a5,(a0) + movem a0/a4-a5,(a0) + movem a1/a4-a5,(a0) + movem a0-a1/a4-a5,(a0) + movem a2/a4-a5,(a0) + movem a0/a2/a4-a5,(a0) + movem a1-a2/a4-a5,(a0) + movem a0-a2/a4-a5,(a0) + movem a3-a5,(a0) + movem a0/a3-a5,(a0) + movem a1/a3-a5,(a0) + movem a0-a1/a3-a5,(a0) + movem a2-a5,(a0) + movem a0/a2-a5,(a0) + movem a1-a5,(a0) + movem a0-a5,(a0) + movem a6,(a0) + movem a0/a6,(a0) + movem a1/a6,(a0) + movem a0-a1/a6,(a0) + movem a2/a6,(a0) + movem a0/a2/a6,(a0) + movem a1-a2/a6,(a0) + movem a0-a2/a6,(a0) + movem a3/a6,(a0) + movem a0/a3/a6,(a0) + movem a1/a3/a6,(a0) + movem a0-a1/a3/a6,(a0) + movem a2-a3/a6,(a0) + movem a0/a2-a3/a6,(a0) + movem a1-a3/a6,(a0) + movem a0-a3/a6,(a0) + movem a4/a6,(a0) + movem a0/a4/a6,(a0) + movem a1/a4/a6,(a0) + movem a0-a1/a4/a6,(a0) + movem a2/a4/a6,(a0) + movem a0/a2/a4/a6,(a0) + movem a1-a2/a4/a6,(a0) + movem a0-a2/a4/a6,(a0) + movem a3-a4/a6,(a0) + movem a0/a3-a4/a6,(a0) + movem a1/a3-a4/a6,(a0) + movem a0-a1/a3-a4/a6,(a0) + movem a2-a4/a6,(a0) + movem a0/a2-a4/a6,(a0) + movem a1-a4/a6,(a0) + movem a0-a4/a6,(a0) + movem a5-a6,(a0) + movem a0/a5-a6,(a0) + movem a1/a5-a6,(a0) + movem a0-a1/a5-a6,(a0) + movem a2/a5-a6,(a0) + movem a0/a2/a5-a6,(a0) + movem a1-a2/a5-a6,(a0) + movem a0-a2/a5-a6,(a0) + movem a3/a5-a6,(a0) + movem a0/a3/a5-a6,(a0) + movem a1/a3/a5-a6,(a0) + movem a0-a1/a3/a5-a6,(a0) + movem a2-a3/a5-a6,(a0) + movem a0/a2-a3/a5-a6,(a0) + movem a1-a3/a5-a6,(a0) + movem a0-a3/a5-a6,(a0) + movem a4-a6,(a0) + movem a0/a4-a6,(a0) + movem a1/a4-a6,(a0) + movem a0-a1/a4-a6,(a0) + movem a2/a4-a6,(a0) + movem a0/a2/a4-a6,(a0) + movem a1-a2/a4-a6,(a0) + movem a0-a2/a4-a6,(a0) + movem a3-a6,(a0) + movem a0/a3-a6,(a0) + movem a1/a3-a6,(a0) + movem a0-a1/a3-a6,(a0) + movem a2-a6,(a0) + movem a0/a2-a6,(a0) + movem a1-a6,(a0) + movem a0-a6,(a0) + movem sp,(a0) + movem a0/sp,(a0) + movem a1/sp,(a0) + movem a0-a1/sp,(a0) + movem a2/sp,(a0) + movem a0/a2/sp,(a0) + movem a1-a2/sp,(a0) + movem a0-a2/sp,(a0) + movem a3/sp,(a0) + movem a0/a3/sp,(a0) + movem a1/a3/sp,(a0) + movem a0-a1/a3/sp,(a0) + movem a2-a3/sp,(a0) + movem a0/a2-a3/sp,(a0) + movem a1-a3/sp,(a0) + movem a0-a3/sp,(a0) + movem a4/sp,(a0) + movem a0/a4/sp,(a0) + movem a1/a4/sp,(a0) + movem a0-a1/a4/sp,(a0) + movem a2/a4/sp,(a0) + movem a0/a2/a4/sp,(a0) + movem a1-a2/a4/sp,(a0) + movem a0-a2/a4/sp,(a0) + movem a3-a4/sp,(a0) + movem a0/a3-a4/sp,(a0) + movem a1/a3-a4/sp,(a0) + movem a0-a1/a3-a4/sp,(a0) + movem a2-a4/sp,(a0) + movem a0/a2-a4/sp,(a0) + movem a1-a4/sp,(a0) + movem a0-a4/sp,(a0) + movem a5/sp,(a0) + movem a0/a5/sp,(a0) + movem a1/a5/sp,(a0) + movem a0-a1/a5/sp,(a0) + movem a2/a5/sp,(a0) + movem a0/a2/a5/sp,(a0) + movem a1-a2/a5/sp,(a0) + movem a0-a2/a5/sp,(a0) + movem a3/a5/sp,(a0) + movem a0/a3/a5/sp,(a0) + movem a1/a3/a5/sp,(a0) + movem a0-a1/a3/a5/sp,(a0) + movem a2-a3/a5/sp,(a0) + movem a0/a2-a3/a5/sp,(a0) + movem a1-a3/a5/sp,(a0) + movem a0-a3/a5/sp,(a0) + movem a4-a5/sp,(a0) + movem a0/a4-a5/sp,(a0) + movem a1/a4-a5/sp,(a0) + movem a0-a1/a4-a5/sp,(a0) + movem a2/a4-a5/sp,(a0) + movem a0/a2/a4-a5/sp,(a0) + movem a1-a2/a4-a5/sp,(a0) + movem a0-a2/a4-a5/sp,(a0) + movem a3-a5/sp,(a0) + movem a0/a3-a5/sp,(a0) + movem a1/a3-a5/sp,(a0) + movem a0-a1/a3-a5/sp,(a0) + movem a2-a5/sp,(a0) + movem a0/a2-a5/sp,(a0) + movem a1-a5/sp,(a0) + movem a0-a5/sp,(a0) + movem a6-sp,(a0) + movem a0/a6-sp,(a0) + movem a1/a6-sp,(a0) + movem a0-a1/a6-sp,(a0) + movem a2/a6-sp,(a0) + movem a0/a2/a6-sp,(a0) + movem a1-a2/a6-sp,(a0) + movem a0-a2/a6-sp,(a0) + movem a3/a6-sp,(a0) + movem a0/a3/a6-sp,(a0) + movem a1/a3/a6-sp,(a0) + movem a0-a1/a3/a6-sp,(a0) + movem a2-a3/a6-sp,(a0) + movem a0/a2-a3/a6-sp,(a0) + movem a1-a3/a6-sp,(a0) + movem a0-a3/a6-sp,(a0) + movem a4/a6-sp,(a0) + movem a0/a4/a6-sp,(a0) + movem a1/a4/a6-sp,(a0) + movem a0-a1/a4/a6-sp,(a0) + movem a2/a4/a6-sp,(a0) + movem a0/a2/a4/a6-sp,(a0) + movem a1-a2/a4/a6-sp,(a0) + movem a0-a2/a4/a6-sp,(a0) + movem a3-a4/a6-sp,(a0) + movem a0/a3-a4/a6-sp,(a0) + movem a1/a3-a4/a6-sp,(a0) + movem a0-a1/a3-a4/a6-sp,(a0) + movem a2-a4/a6-sp,(a0) + movem a0/a2-a4/a6-sp,(a0) + movem a1-a4/a6-sp,(a0) + movem a0-a4/a6-sp,(a0) + movem a5-sp,(a0) + movem a0/a5-sp,(a0) + movem a1/a5-sp,(a0) + movem a0-a1/a5-sp,(a0) + movem a2/a5-sp,(a0) + movem a0/a2/a5-sp,(a0) + movem a1-a2/a5-sp,(a0) + movem a0-a2/a5-sp,(a0) + movem a3/a5-sp,(a0) + movem a0/a3/a5-sp,(a0) + movem a1/a3/a5-sp,(a0) + movem a0-a1/a3/a5-sp,(a0) + movem a2-a3/a5-sp,(a0) + movem a0/a2-a3/a5-sp,(a0) + movem a1-a3/a5-sp,(a0) + movem a0-a3/a5-sp,(a0) + movem a4-sp,(a0) + movem a0/a4-sp,(a0) + movem a1/a4-sp,(a0) + movem a0-a1/a4-sp,(a0) + movem a2/a4-sp,(a0) + movem a0/a2/a4-sp,(a0) + movem a1-a2/a4-sp,(a0) + movem a0-a2/a4-sp,(a0) + movem a3-sp,(a0) + movem a0/a3-sp,(a0) + movem a1/a3-sp,(a0) + movem a0-a1/a3-sp,(a0) + movem a2-sp,(a0) + movem a0/a2-sp,(a0) + movem a1-sp,(a0) + movem a0-sp,(a0) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + movem.l d7/a0,-(a0) + movem.l d7/a0,(a0) + movem.l d0-d7/a0-sp,-(sp) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + .cpu 68020 + fmovem.x fp7,(a0) + fmovem.x fp6,(a0) + fmovem.x fp6-fp7,(a0) + fmovem.x fp5,(a0) + fmovem.x fp5/fp7,(a0) + fmovem.x fp5-fp6,(a0) + fmovem.x fp5-fp7,(a0) + fmovem.x fp4,(a0) + fmovem.x fp4/fp7,(a0) + fmovem.x fp4/fp6,(a0) + fmovem.x fp4/fp6-fp7,(a0) + fmovem.x fp4-fp5,(a0) + fmovem.x fp4-fp5/fp7,(a0) + fmovem.x fp4-fp6,(a0) + fmovem.x fp4-fp7,(a0) + fmovem.x fp3,(a0) + fmovem.x fp3/fp7,(a0) + fmovem.x fp3/fp6,(a0) + fmovem.x fp3/fp6-fp7,(a0) + fmovem.x fp3/fp5,(a0) + fmovem.x fp3/fp5/fp7,(a0) + fmovem.x fp3/fp5-fp6,(a0) + fmovem.x fp3/fp5-fp7,(a0) + fmovem.x fp3-fp4,(a0) + fmovem.x fp3-fp4/fp7,(a0) + fmovem.x fp3-fp4/fp6,(a0) + fmovem.x fp3-fp4/fp6-fp7,(a0) + fmovem.x fp3-fp5,(a0) + fmovem.x fp3-fp5/fp7,(a0) + fmovem.x fp3-fp6,(a0) + fmovem.x fp3-fp7,(a0) + fmovem.x fp2,(a0) + fmovem.x fp2/fp7,(a0) + fmovem.x fp2/fp6,(a0) + fmovem.x fp2/fp6-fp7,(a0) + fmovem.x fp2/fp5,(a0) + fmovem.x fp2/fp5/fp7,(a0) + fmovem.x fp2/fp5-fp6,(a0) + fmovem.x fp2/fp5-fp7,(a0) + fmovem.x fp2/fp4,(a0) + fmovem.x fp2/fp4/fp7,(a0) + fmovem.x fp2/fp4/fp6,(a0) + fmovem.x fp2/fp4/fp6-fp7,(a0) + fmovem.x fp2/fp4-fp5,(a0) + fmovem.x fp2/fp4-fp5/fp7,(a0) + fmovem.x fp2/fp4-fp6,(a0) + fmovem.x fp2/fp4-fp7,(a0) + fmovem.x fp2-fp3,(a0) + fmovem.x fp2-fp3/fp7,(a0) + fmovem.x fp2-fp3/fp6,(a0) + fmovem.x fp2-fp3/fp6-fp7,(a0) + fmovem.x fp2-fp3/fp5,(a0) + fmovem.x fp2-fp3/fp5/fp7,(a0) + fmovem.x fp2-fp3/fp5-fp6,(a0) + fmovem.x fp2-fp3/fp5-fp7,(a0) + fmovem.x fp2-fp4,(a0) + fmovem.x fp2-fp4/fp7,(a0) + fmovem.x fp2-fp4/fp6,(a0) + fmovem.x fp2-fp4/fp6-fp7,(a0) + fmovem.x fp2-fp5,(a0) + fmovem.x fp2-fp5/fp7,(a0) + fmovem.x fp2-fp6,(a0) + fmovem.x fp2-fp7,(a0) + fmovem.x fp1,(a0) + fmovem.x fp1/fp7,(a0) + fmovem.x fp1/fp6,(a0) + fmovem.x fp1/fp6-fp7,(a0) + fmovem.x fp1/fp5,(a0) + fmovem.x fp1/fp5/fp7,(a0) + fmovem.x fp1/fp5-fp6,(a0) + fmovem.x fp1/fp5-fp7,(a0) + fmovem.x fp1/fp4,(a0) + fmovem.x fp1/fp4/fp7,(a0) + fmovem.x fp1/fp4/fp6,(a0) + fmovem.x fp1/fp4/fp6-fp7,(a0) + fmovem.x fp1/fp4-fp5,(a0) + fmovem.x fp1/fp4-fp5/fp7,(a0) + fmovem.x fp1/fp4-fp6,(a0) + fmovem.x fp1/fp4-fp7,(a0) + fmovem.x fp1/fp3,(a0) + fmovem.x fp1/fp3/fp7,(a0) + fmovem.x fp1/fp3/fp6,(a0) + fmovem.x fp1/fp3/fp6-fp7,(a0) + fmovem.x fp1/fp3/fp5,(a0) + fmovem.x fp1/fp3/fp5/fp7,(a0) + fmovem.x fp1/fp3/fp5-fp6,(a0) + fmovem.x fp1/fp3/fp5-fp7,(a0) + fmovem.x fp1/fp3-fp4,(a0) + fmovem.x fp1/fp3-fp4/fp7,(a0) + fmovem.x fp1/fp3-fp4/fp6,(a0) + fmovem.x fp1/fp3-fp4/fp6-fp7,(a0) + fmovem.x fp1/fp3-fp5,(a0) + fmovem.x fp1/fp3-fp5/fp7,(a0) + fmovem.x fp1/fp3-fp6,(a0) + fmovem.x fp1/fp3-fp7,(a0) + fmovem.x fp1-fp2,(a0) + fmovem.x fp1-fp2/fp7,(a0) + fmovem.x fp1-fp2/fp6,(a0) + fmovem.x fp1-fp2/fp6-fp7,(a0) + fmovem.x fp1-fp2/fp5,(a0) + fmovem.x fp1-fp2/fp5/fp7,(a0) + fmovem.x fp1-fp2/fp5-fp6,(a0) + fmovem.x fp1-fp2/fp5-fp7,(a0) + fmovem.x fp1-fp2/fp4,(a0) + fmovem.x fp1-fp2/fp4/fp7,(a0) + fmovem.x fp1-fp2/fp4/fp6,(a0) + fmovem.x fp1-fp2/fp4/fp6-fp7,(a0) + fmovem.x fp1-fp2/fp4-fp5,(a0) + fmovem.x fp1-fp2/fp4-fp5/fp7,(a0) + fmovem.x fp1-fp2/fp4-fp6,(a0) + fmovem.x fp1-fp2/fp4-fp7,(a0) + fmovem.x fp1-fp3,(a0) + fmovem.x fp1-fp3/fp7,(a0) + fmovem.x fp1-fp3/fp6,(a0) + fmovem.x fp1-fp3/fp6-fp7,(a0) + fmovem.x fp1-fp3/fp5,(a0) + fmovem.x fp1-fp3/fp5/fp7,(a0) + fmovem.x fp1-fp3/fp5-fp6,(a0) + fmovem.x fp1-fp3/fp5-fp7,(a0) + fmovem.x fp1-fp4,(a0) + fmovem.x fp1-fp4/fp7,(a0) + fmovem.x fp1-fp4/fp6,(a0) + fmovem.x fp1-fp4/fp6-fp7,(a0) + fmovem.x fp1-fp5,(a0) + fmovem.x fp1-fp5/fp7,(a0) + fmovem.x fp1-fp6,(a0) + fmovem.x fp1-fp7,(a0) + fmovem.x fp0,(a0) + fmovem.x fp0/fp7,(a0) + fmovem.x fp0/fp6,(a0) + fmovem.x fp0/fp6-fp7,(a0) + fmovem.x fp0/fp5,(a0) + fmovem.x fp0/fp5/fp7,(a0) + fmovem.x fp0/fp5-fp6,(a0) + fmovem.x fp0/fp5-fp7,(a0) + fmovem.x fp0/fp4,(a0) + fmovem.x fp0/fp4/fp7,(a0) + fmovem.x fp0/fp4/fp6,(a0) + fmovem.x fp0/fp4/fp6-fp7,(a0) + fmovem.x fp0/fp4-fp5,(a0) + fmovem.x fp0/fp4-fp5/fp7,(a0) + fmovem.x fp0/fp4-fp6,(a0) + fmovem.x fp0/fp4-fp7,(a0) + fmovem.x fp0/fp3,(a0) + fmovem.x fp0/fp3/fp7,(a0) + fmovem.x fp0/fp3/fp6,(a0) + fmovem.x fp0/fp3/fp6-fp7,(a0) + fmovem.x fp0/fp3/fp5,(a0) + fmovem.x fp0/fp3/fp5/fp7,(a0) + fmovem.x fp0/fp3/fp5-fp6,(a0) + fmovem.x fp0/fp3/fp5-fp7,(a0) + fmovem.x fp0/fp3-fp4,(a0) + fmovem.x fp0/fp3-fp4/fp7,(a0) + fmovem.x fp0/fp3-fp4/fp6,(a0) + fmovem.x fp0/fp3-fp4/fp6-fp7,(a0) + fmovem.x fp0/fp3-fp5,(a0) + fmovem.x fp0/fp3-fp5/fp7,(a0) + fmovem.x fp0/fp3-fp6,(a0) + fmovem.x fp0/fp3-fp7,(a0) + fmovem.x fp0/fp2,(a0) + fmovem.x fp0/fp2/fp7,(a0) + fmovem.x fp0/fp2/fp6,(a0) + fmovem.x fp0/fp2/fp6-fp7,(a0) + fmovem.x fp0/fp2/fp5,(a0) + fmovem.x fp0/fp2/fp5/fp7,(a0) + fmovem.x fp0/fp2/fp5-fp6,(a0) + fmovem.x fp0/fp2/fp5-fp7,(a0) + fmovem.x fp0/fp2/fp4,(a0) + fmovem.x fp0/fp2/fp4/fp7,(a0) + fmovem.x fp0/fp2/fp4/fp6,(a0) + fmovem.x fp0/fp2/fp4/fp6-fp7,(a0) + fmovem.x fp0/fp2/fp4-fp5,(a0) + fmovem.x fp0/fp2/fp4-fp5/fp7,(a0) + fmovem.x fp0/fp2/fp4-fp6,(a0) + fmovem.x fp0/fp2/fp4-fp7,(a0) + fmovem.x fp0/fp2-fp3,(a0) + fmovem.x fp0/fp2-fp3/fp7,(a0) + fmovem.x fp0/fp2-fp3/fp6,(a0) + fmovem.x fp0/fp2-fp3/fp6-fp7,(a0) + fmovem.x fp0/fp2-fp3/fp5,(a0) + fmovem.x fp0/fp2-fp3/fp5/fp7,(a0) + fmovem.x fp0/fp2-fp3/fp5-fp6,(a0) + fmovem.x fp0/fp2-fp3/fp5-fp7,(a0) + fmovem.x fp0/fp2-fp4,(a0) + fmovem.x fp0/fp2-fp4/fp7,(a0) + fmovem.x fp0/fp2-fp4/fp6,(a0) + fmovem.x fp0/fp2-fp4/fp6-fp7,(a0) + fmovem.x fp0/fp2-fp5,(a0) + fmovem.x fp0/fp2-fp5/fp7,(a0) + fmovem.x fp0/fp2-fp6,(a0) + fmovem.x fp0/fp2-fp7,(a0) + fmovem.x fp0-fp1,(a0) + fmovem.x fp0-fp1/fp7,(a0) + fmovem.x fp0-fp1/fp6,(a0) + fmovem.x fp0-fp1/fp6-fp7,(a0) + fmovem.x fp0-fp1/fp5,(a0) + fmovem.x fp0-fp1/fp5/fp7,(a0) + fmovem.x fp0-fp1/fp5-fp6,(a0) + fmovem.x fp0-fp1/fp5-fp7,(a0) + fmovem.x fp0-fp1/fp4,(a0) + fmovem.x fp0-fp1/fp4/fp7,(a0) + fmovem.x fp0-fp1/fp4/fp6,(a0) + fmovem.x fp0-fp1/fp4/fp6-fp7,(a0) + fmovem.x fp0-fp1/fp4-fp5,(a0) + fmovem.x fp0-fp1/fp4-fp5/fp7,(a0) + fmovem.x fp0-fp1/fp4-fp6,(a0) + fmovem.x fp0-fp1/fp4-fp7,(a0) + fmovem.x fp0-fp1/fp3,(a0) + fmovem.x fp0-fp1/fp3/fp7,(a0) + fmovem.x fp0-fp1/fp3/fp6,(a0) + fmovem.x fp0-fp1/fp3/fp6-fp7,(a0) + fmovem.x fp0-fp1/fp3/fp5,(a0) + fmovem.x fp0-fp1/fp3/fp5/fp7,(a0) + fmovem.x fp0-fp1/fp3/fp5-fp6,(a0) + fmovem.x fp0-fp1/fp3/fp5-fp7,(a0) + fmovem.x fp0-fp1/fp3-fp4,(a0) + fmovem.x fp0-fp1/fp3-fp4/fp7,(a0) + fmovem.x fp0-fp1/fp3-fp4/fp6,(a0) + fmovem.x fp0-fp1/fp3-fp4/fp6-fp7,(a0) + fmovem.x fp0-fp1/fp3-fp5,(a0) + fmovem.x fp0-fp1/fp3-fp5/fp7,(a0) + fmovem.x fp0-fp1/fp3-fp6,(a0) + fmovem.x fp0-fp1/fp3-fp7,(a0) + fmovem.x fp0-fp2,(a0) + fmovem.x fp0-fp2/fp7,(a0) + fmovem.x fp0-fp2/fp6,(a0) + fmovem.x fp0-fp2/fp6-fp7,(a0) + fmovem.x fp0-fp2/fp5,(a0) + fmovem.x fp0-fp2/fp5/fp7,(a0) + fmovem.x fp0-fp2/fp5-fp6,(a0) + fmovem.x fp0-fp2/fp5-fp7,(a0) + fmovem.x fp0-fp2/fp4,(a0) + fmovem.x fp0-fp2/fp4/fp7,(a0) + fmovem.x fp0-fp2/fp4/fp6,(a0) + fmovem.x fp0-fp2/fp4/fp6-fp7,(a0) + fmovem.x fp0-fp2/fp4-fp5,(a0) + fmovem.x fp0-fp2/fp4-fp5/fp7,(a0) + fmovem.x fp0-fp2/fp4-fp6,(a0) + fmovem.x fp0-fp2/fp4-fp7,(a0) + fmovem.x fp0-fp3,(a0) + fmovem.x fp0-fp3/fp7,(a0) + fmovem.x fp0-fp3/fp6,(a0) + fmovem.x fp0-fp3/fp6-fp7,(a0) + fmovem.x fp0-fp3/fp5,(a0) + fmovem.x fp0-fp3/fp5/fp7,(a0) + fmovem.x fp0-fp3/fp5-fp6,(a0) + fmovem.x fp0-fp3/fp5-fp7,(a0) + fmovem.x fp0-fp4,(a0) + fmovem.x fp0-fp4/fp7,(a0) + fmovem.x fp0-fp4/fp6,(a0) + fmovem.x fp0-fp4/fp6-fp7,(a0) + fmovem.x fp0-fp5,(a0) + fmovem.x fp0-fp5/fp7,(a0) + fmovem.x fp0-fp6,(a0) + fmovem.x fp0-fp7,(a0) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + fmovem.x fp0,-(a0) + fmovem.x fp1,-(a0) + fmovem.x fp0-fp1,-(a0) + fmovem.x fp2,-(a0) + fmovem.x fp0/fp2,-(a0) + fmovem.x fp1-fp2,-(a0) + fmovem.x fp0-fp2,-(a0) + fmovem.x fp3,-(a0) + fmovem.x fp0/fp3,-(a0) + fmovem.x fp1/fp3,-(a0) + fmovem.x fp0-fp1/fp3,-(a0) + fmovem.x fp2-fp3,-(a0) + fmovem.x fp0/fp2-fp3,-(a0) + fmovem.x fp1-fp3,-(a0) + fmovem.x fp0-fp3,-(a0) + fmovem.x fp4,-(a0) + fmovem.x fp0/fp4,-(a0) + fmovem.x fp1/fp4,-(a0) + fmovem.x fp0-fp1/fp4,-(a0) + fmovem.x fp2/fp4,-(a0) + fmovem.x fp0/fp2/fp4,-(a0) + fmovem.x fp1-fp2/fp4,-(a0) + fmovem.x fp0-fp2/fp4,-(a0) + fmovem.x fp3-fp4,-(a0) + fmovem.x fp0/fp3-fp4,-(a0) + fmovem.x fp1/fp3-fp4,-(a0) + fmovem.x fp0-fp1/fp3-fp4,-(a0) + fmovem.x fp2-fp4,-(a0) + fmovem.x fp0/fp2-fp4,-(a0) + fmovem.x fp1-fp4,-(a0) + fmovem.x fp0-fp4,-(a0) + fmovem.x fp5,-(a0) + fmovem.x fp0/fp5,-(a0) + fmovem.x fp1/fp5,-(a0) + fmovem.x fp0-fp1/fp5,-(a0) + fmovem.x fp2/fp5,-(a0) + fmovem.x fp0/fp2/fp5,-(a0) + fmovem.x fp1-fp2/fp5,-(a0) + fmovem.x fp0-fp2/fp5,-(a0) + fmovem.x fp3/fp5,-(a0) + fmovem.x fp0/fp3/fp5,-(a0) + fmovem.x fp1/fp3/fp5,-(a0) + fmovem.x fp0-fp1/fp3/fp5,-(a0) + fmovem.x fp2-fp3/fp5,-(a0) + fmovem.x fp0/fp2-fp3/fp5,-(a0) + fmovem.x fp1-fp3/fp5,-(a0) + fmovem.x fp0-fp3/fp5,-(a0) + fmovem.x fp4-fp5,-(a0) + fmovem.x fp0/fp4-fp5,-(a0) + fmovem.x fp1/fp4-fp5,-(a0) + fmovem.x fp0-fp1/fp4-fp5,-(a0) + fmovem.x fp2/fp4-fp5,-(a0) + fmovem.x fp0/fp2/fp4-fp5,-(a0) + fmovem.x fp1-fp2/fp4-fp5,-(a0) + fmovem.x fp0-fp2/fp4-fp5,-(a0) + fmovem.x fp3-fp5,-(a0) + fmovem.x fp0/fp3-fp5,-(a0) + fmovem.x fp1/fp3-fp5,-(a0) + fmovem.x fp0-fp1/fp3-fp5,-(a0) + fmovem.x fp2-fp5,-(a0) + fmovem.x fp0/fp2-fp5,-(a0) + fmovem.x fp1-fp5,-(a0) + fmovem.x fp0-fp5,-(a0) + fmovem.x fp6,-(a0) + fmovem.x fp0/fp6,-(a0) + fmovem.x fp1/fp6,-(a0) + fmovem.x fp0-fp1/fp6,-(a0) + fmovem.x fp2/fp6,-(a0) + fmovem.x fp0/fp2/fp6,-(a0) + fmovem.x fp1-fp2/fp6,-(a0) + fmovem.x fp0-fp2/fp6,-(a0) + fmovem.x fp3/fp6,-(a0) + fmovem.x fp0/fp3/fp6,-(a0) + fmovem.x fp1/fp3/fp6,-(a0) + fmovem.x fp0-fp1/fp3/fp6,-(a0) + fmovem.x fp2-fp3/fp6,-(a0) + fmovem.x fp0/fp2-fp3/fp6,-(a0) + fmovem.x fp1-fp3/fp6,-(a0) + fmovem.x fp0-fp3/fp6,-(a0) + fmovem.x fp4/fp6,-(a0) + fmovem.x fp0/fp4/fp6,-(a0) + fmovem.x fp1/fp4/fp6,-(a0) + fmovem.x fp0-fp1/fp4/fp6,-(a0) + fmovem.x fp2/fp4/fp6,-(a0) + fmovem.x fp0/fp2/fp4/fp6,-(a0) + fmovem.x fp1-fp2/fp4/fp6,-(a0) + fmovem.x fp0-fp2/fp4/fp6,-(a0) + fmovem.x fp3-fp4/fp6,-(a0) + fmovem.x fp0/fp3-fp4/fp6,-(a0) + fmovem.x fp1/fp3-fp4/fp6,-(a0) + fmovem.x fp0-fp1/fp3-fp4/fp6,-(a0) + fmovem.x fp2-fp4/fp6,-(a0) + fmovem.x fp0/fp2-fp4/fp6,-(a0) + fmovem.x fp1-fp4/fp6,-(a0) + fmovem.x fp0-fp4/fp6,-(a0) + fmovem.x fp5-fp6,-(a0) + fmovem.x fp0/fp5-fp6,-(a0) + fmovem.x fp1/fp5-fp6,-(a0) + fmovem.x fp0-fp1/fp5-fp6,-(a0) + fmovem.x fp2/fp5-fp6,-(a0) + fmovem.x fp0/fp2/fp5-fp6,-(a0) + fmovem.x fp1-fp2/fp5-fp6,-(a0) + fmovem.x fp0-fp2/fp5-fp6,-(a0) + fmovem.x fp3/fp5-fp6,-(a0) + fmovem.x fp0/fp3/fp5-fp6,-(a0) + fmovem.x fp1/fp3/fp5-fp6,-(a0) + fmovem.x fp0-fp1/fp3/fp5-fp6,-(a0) + fmovem.x fp2-fp3/fp5-fp6,-(a0) + fmovem.x fp0/fp2-fp3/fp5-fp6,-(a0) + fmovem.x fp1-fp3/fp5-fp6,-(a0) + fmovem.x fp0-fp3/fp5-fp6,-(a0) + fmovem.x fp4-fp6,-(a0) + fmovem.x fp0/fp4-fp6,-(a0) + fmovem.x fp1/fp4-fp6,-(a0) + fmovem.x fp0-fp1/fp4-fp6,-(a0) + fmovem.x fp2/fp4-fp6,-(a0) + fmovem.x fp0/fp2/fp4-fp6,-(a0) + fmovem.x fp1-fp2/fp4-fp6,-(a0) + fmovem.x fp0-fp2/fp4-fp6,-(a0) + fmovem.x fp3-fp6,-(a0) + fmovem.x fp0/fp3-fp6,-(a0) + fmovem.x fp1/fp3-fp6,-(a0) + fmovem.x fp0-fp1/fp3-fp6,-(a0) + fmovem.x fp2-fp6,-(a0) + fmovem.x fp0/fp2-fp6,-(a0) + fmovem.x fp1-fp6,-(a0) + fmovem.x fp0-fp6,-(a0) + fmovem.x fp7,-(a0) + fmovem.x fp0/fp7,-(a0) + fmovem.x fp1/fp7,-(a0) + fmovem.x fp0-fp1/fp7,-(a0) + fmovem.x fp2/fp7,-(a0) + fmovem.x fp0/fp2/fp7,-(a0) + fmovem.x fp1-fp2/fp7,-(a0) + fmovem.x fp0-fp2/fp7,-(a0) + fmovem.x fp3/fp7,-(a0) + fmovem.x fp0/fp3/fp7,-(a0) + fmovem.x fp1/fp3/fp7,-(a0) + fmovem.x fp0-fp1/fp3/fp7,-(a0) + fmovem.x fp2-fp3/fp7,-(a0) + fmovem.x fp0/fp2-fp3/fp7,-(a0) + fmovem.x fp1-fp3/fp7,-(a0) + fmovem.x fp0-fp3/fp7,-(a0) + fmovem.x fp4/fp7,-(a0) + fmovem.x fp0/fp4/fp7,-(a0) + fmovem.x fp1/fp4/fp7,-(a0) + fmovem.x fp0-fp1/fp4/fp7,-(a0) + fmovem.x fp2/fp4/fp7,-(a0) + fmovem.x fp0/fp2/fp4/fp7,-(a0) + fmovem.x fp1-fp2/fp4/fp7,-(a0) + fmovem.x fp0-fp2/fp4/fp7,-(a0) + fmovem.x fp3-fp4/fp7,-(a0) + fmovem.x fp0/fp3-fp4/fp7,-(a0) + fmovem.x fp1/fp3-fp4/fp7,-(a0) + fmovem.x fp0-fp1/fp3-fp4/fp7,-(a0) + fmovem.x fp2-fp4/fp7,-(a0) + fmovem.x fp0/fp2-fp4/fp7,-(a0) + fmovem.x fp1-fp4/fp7,-(a0) + fmovem.x fp0-fp4/fp7,-(a0) + fmovem.x fp5/fp7,-(a0) + fmovem.x fp0/fp5/fp7,-(a0) + fmovem.x fp1/fp5/fp7,-(a0) + fmovem.x fp0-fp1/fp5/fp7,-(a0) + fmovem.x fp2/fp5/fp7,-(a0) + fmovem.x fp0/fp2/fp5/fp7,-(a0) + fmovem.x fp1-fp2/fp5/fp7,-(a0) + fmovem.x fp0-fp2/fp5/fp7,-(a0) + fmovem.x fp3/fp5/fp7,-(a0) + fmovem.x fp0/fp3/fp5/fp7,-(a0) + fmovem.x fp1/fp3/fp5/fp7,-(a0) + fmovem.x fp0-fp1/fp3/fp5/fp7,-(a0) + fmovem.x fp2-fp3/fp5/fp7,-(a0) + fmovem.x fp0/fp2-fp3/fp5/fp7,-(a0) + fmovem.x fp1-fp3/fp5/fp7,-(a0) + fmovem.x fp0-fp3/fp5/fp7,-(a0) + fmovem.x fp4-fp5/fp7,-(a0) + fmovem.x fp0/fp4-fp5/fp7,-(a0) + fmovem.x fp1/fp4-fp5/fp7,-(a0) + fmovem.x fp0-fp1/fp4-fp5/fp7,-(a0) + fmovem.x fp2/fp4-fp5/fp7,-(a0) + fmovem.x fp0/fp2/fp4-fp5/fp7,-(a0) + fmovem.x fp1-fp2/fp4-fp5/fp7,-(a0) + fmovem.x fp0-fp2/fp4-fp5/fp7,-(a0) + fmovem.x fp3-fp5/fp7,-(a0) + fmovem.x fp0/fp3-fp5/fp7,-(a0) + fmovem.x fp1/fp3-fp5/fp7,-(a0) + fmovem.x fp0-fp1/fp3-fp5/fp7,-(a0) + fmovem.x fp2-fp5/fp7,-(a0) + fmovem.x fp0/fp2-fp5/fp7,-(a0) + fmovem.x fp1-fp5/fp7,-(a0) + fmovem.x fp0-fp5/fp7,-(a0) + fmovem.x fp6-fp7,-(a0) + fmovem.x fp0/fp6-fp7,-(a0) + fmovem.x fp1/fp6-fp7,-(a0) + fmovem.x fp0-fp1/fp6-fp7,-(a0) + fmovem.x fp2/fp6-fp7,-(a0) + fmovem.x fp0/fp2/fp6-fp7,-(a0) + fmovem.x fp1-fp2/fp6-fp7,-(a0) + fmovem.x fp0-fp2/fp6-fp7,-(a0) + fmovem.x fp3/fp6-fp7,-(a0) + fmovem.x fp0/fp3/fp6-fp7,-(a0) + fmovem.x fp1/fp3/fp6-fp7,-(a0) + fmovem.x fp0-fp1/fp3/fp6-fp7,-(a0) + fmovem.x fp2-fp3/fp6-fp7,-(a0) + fmovem.x fp0/fp2-fp3/fp6-fp7,-(a0) + fmovem.x fp1-fp3/fp6-fp7,-(a0) + fmovem.x fp0-fp3/fp6-fp7,-(a0) + fmovem.x fp4/fp6-fp7,-(a0) + fmovem.x fp0/fp4/fp6-fp7,-(a0) + fmovem.x fp1/fp4/fp6-fp7,-(a0) + fmovem.x fp0-fp1/fp4/fp6-fp7,-(a0) + fmovem.x fp2/fp4/fp6-fp7,-(a0) + fmovem.x fp0/fp2/fp4/fp6-fp7,-(a0) + fmovem.x fp1-fp2/fp4/fp6-fp7,-(a0) + fmovem.x fp0-fp2/fp4/fp6-fp7,-(a0) + fmovem.x fp3-fp4/fp6-fp7,-(a0) + fmovem.x fp0/fp3-fp4/fp6-fp7,-(a0) + fmovem.x fp1/fp3-fp4/fp6-fp7,-(a0) + fmovem.x fp0-fp1/fp3-fp4/fp6-fp7,-(a0) + fmovem.x fp2-fp4/fp6-fp7,-(a0) + fmovem.x fp0/fp2-fp4/fp6-fp7,-(a0) + fmovem.x fp1-fp4/fp6-fp7,-(a0) + fmovem.x fp0-fp4/fp6-fp7,-(a0) + fmovem.x fp5-fp7,-(a0) + fmovem.x fp0/fp5-fp7,-(a0) + fmovem.x fp1/fp5-fp7,-(a0) + fmovem.x fp0-fp1/fp5-fp7,-(a0) + fmovem.x fp2/fp5-fp7,-(a0) + fmovem.x fp0/fp2/fp5-fp7,-(a0) + fmovem.x fp1-fp2/fp5-fp7,-(a0) + fmovem.x fp0-fp2/fp5-fp7,-(a0) + fmovem.x fp3/fp5-fp7,-(a0) + fmovem.x fp0/fp3/fp5-fp7,-(a0) + fmovem.x fp1/fp3/fp5-fp7,-(a0) + fmovem.x fp0-fp1/fp3/fp5-fp7,-(a0) + fmovem.x fp2-fp3/fp5-fp7,-(a0) + fmovem.x fp0/fp2-fp3/fp5-fp7,-(a0) + fmovem.x fp1-fp3/fp5-fp7,-(a0) + fmovem.x fp0-fp3/fp5-fp7,-(a0) + fmovem.x fp4-fp7,-(a0) + fmovem.x fp0/fp4-fp7,-(a0) + fmovem.x fp1/fp4-fp7,-(a0) + fmovem.x fp0-fp1/fp4-fp7,-(a0) + fmovem.x fp2/fp4-fp7,-(a0) + fmovem.x fp0/fp2/fp4-fp7,-(a0) + fmovem.x fp1-fp2/fp4-fp7,-(a0) + fmovem.x fp0-fp2/fp4-fp7,-(a0) + fmovem.x fp3-fp7,-(a0) + fmovem.x fp0/fp3-fp7,-(a0) + fmovem.x fp1/fp3-fp7,-(a0) + fmovem.x fp0-fp1/fp3-fp7,-(a0) + fmovem.x fp2-fp7,-(a0) + fmovem.x fp0/fp2-fp7,-(a0) + fmovem.x fp1-fp7,-(a0) + fmovem.x fp0-fp7,-(a0) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + fmove fpiar,(a0) + fmove fpsr,(a0) + fmovem fpsr/fpiar,(a0) + fmove fpcr,(a0) + fmovem fpcr/fpiar,(a0) + fmovem fpcr/fpsr,(a0) + fmovem fpcr/fpsr/fpiar,(a0) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + DOS _EXIT + +L0010da: + + .end L000000 diff --git a/tests/expected/relbdpc.s b/tests/expected/relbdpc.s new file mode 100644 index 0000000..982f550 --- /dev/null +++ b/tests/expected/relbdpc.s @@ -0,0 +1,54 @@ +;============================================= +; Filename obj/relbdpc.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000003e byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 8 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/relbdpc.x dised/relbdpc.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + .cpu 68020 + move (L000000,zpc),d0 + rts + +L00000a: + .dc.b $41,$fb,$01,$70 + .dc.l L000000 + .dc.b $4e,$75 + +L000014: + lea ([L000000,zpc,d0.l]),a0 + rts + +L00001e: + .dc.b $41,$fb,$09,$31 + .dc.l L000000 + .dc.b $4e,$75 + +L000028: + lea ([L000000,zpc],d0.l),a0 + rts + +L000032: + .dc.b $41,$fb,$09,$35 + .dc.l L000000 + .dc.b $4e,$75 + +L00003c: + DOS _EXIT + +L00003e: + + .end L000000 diff --git a/tests/expected/reltbl.s b/tests/expected/reltbl.s new file mode 100644 index 0000000..f257452 --- /dev/null +++ b/tests/expected/reltbl.s @@ -0,0 +1,281 @@ +;============================================= +; Filename obj/reltbl.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $0000018e byte(s) +; Data size $00000000 byte(s) +; Bss size $00000002 byte(s) +; 69 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/reltbl.x dised/reltbl.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + DOS _EXIT + +MOVEw_JMPJSR:: + move (L00000a,pc,d0.w),d0 + jmp (L00000a,pc,d0.w) + +L00000a: + .dc L00000c-L00000a + +L00000c: + rts + +MOVEl_JMPJSR:: + move (L000016,pc,d0.l),d0 + jmp (L000016,pc,d0.w) + +L000016: + .dc L000018-L000016 + +L000018: + rts + +L00001a: + move (L000022,pc,d0.w),d0 + jmp (L000022,pc,d1.w) + +L000022: + .dc $0002,$4e75 + +L000026: + move (L000022,pc,d0.w),d0 + jmp (L00002e,pc,d0.w) + +L00002e: + .dc.b $00,$02,$4e,$75 + +LEA_MOVEw_JMPJSR:: + lea (L00003e,pc),a0 + move (a0,d0.w),d0 + jmp (a0,d0.w) + +L00003e: + .dc L000040-L00003e + +L000040: + rts + +LEA_MOVEl_JMPJSR:: + lea (L00004e,pc),a0 + move (a0,d0.l),d0 + jmp (a0,d0.w) + +L00004e: + .dc L000050-L00004e + +L000050: + rts + +L000052: + lea (L00005e,pc),a0 + move (a0,d0.w),d0 + jmp (a0,d1.w) + +L00005e: + .dc.b $00,$02,$4e,$75 + +L000062: + lea (L00006e,pc),a0 + move (a1,d0.w),d0 + jmp (a0,d0.w) + +L00006e: + .dc.b $00,$02,$4e,$75 + +L000072: + lea (L00007e,pc),a0 + move (a0,d0.w),d0 + jmp (a1,d0.w) + +L00007e: + .dc.b $00,$02,$4e,$75 + +LEA_MOVEw_PEA:: + lea (L000090,pc),a0 + move (a0,d0.w),d0 + pea (a0,d0.w) + rts + +L000090: + .dc L000092-L000090 + +L000092: + rts + +LEA_MOVEl_PEA:: + lea (L0000a2,pc),a0 + move (a0,d0.l),d0 + pea (a0,d0.w) + rts + +L0000a2: + .dc L0000a4-L0000a2 + +L0000a4: + rts + +L0000a6: + lea (L0000b4,pc),a0 + move (a0,d0.w),d0 + pea (a0,d1.w) + rts + +L0000b4: + .dc.b $00,$02,$4e,$75 + +L0000b8: + lea (L0000c6,pc),a0 + move (a1,d0.w),d0 + pea (a0,d0.w) + rts + +L0000c6: + .dc.b $00,$02,$4e,$75 + +L0000ca: + lea (L0000d8,pc),a0 + move (a0,d0.w),d0 + pea (a1,d0.w) + rts + +L0000d8: + .dc.b $00,$02,$4e,$75 + +LEA_ADDA:: + lea (L0000e6,pc),a0 + adda (L0000e6,pc,d0.w),a0 + rts + +L0000e6: + .dc L0000e8-L0000e6 + +L0000e8: + rts + +L0000ea: + lea (L0000f4,pc),a0 + adda (L0000f4,pc,d0.w),a1 + rts + +L0000f4: + .dc $0002,$4e75 + +L0000f8: + lea (L0000f4,pc),a0 + adda (L000102,pc,d0.w),a0 + rts + +L000102: + .dc $0002,$4e75 + +MOVEw_LEA:: + move (L000110,pc,d0.w),d0 + lea (L000110,pc,d0.w),a0 + rts + +L000110: + .dc L000112-L000110 + +L000112: + rts + +MOVEl_LEA:: + move (L00011e,pc,d0.l),d0 + lea (L00011e,pc,d0.w),a0 + rts + +L00011e: + .dc L000120-L00011e + +L000120: + rts + +L000122: + move (L00012c,pc,d0.w),d0 + lea (L00012c,pc,d1.w),a0 + rts + +L00012c: + .dc $0002,$4e75 + +L000130: + move (L00012c,pc,d0.w),d0 + lea (L00013a,pc,d0.w),a0 + rts + +L00013a: + .dc.b $00,$02,$4e,$75 + +MOVEw_PEA:: + move (L000148,pc,d0.w),d0 + pea (L000148,pc,d0.w) + rts + +L000148: + .dc L00014a-L000148 + +L00014a: + rts + +MOVEl_PEA:: + move (L000156,pc,d0.l),d0 + pea (L000156,pc,d0.w) + rts + +L000156: + .dc L000158-L000156 + +L000158: + rts + +L00015a: + move (L000164,pc,d0.w),d0 + pea (L000164,pc,d1.w) + rts + +L000164: + .dc $0002,$4e75 + +L000168: + move (L000164,pc,d0.w),d0 + pea (L000172,pc,d0.w) + rts + +L000172: + .dc.b $00,$02,$4e,$75 + +OFFSET_0:: + move (L00017e,pc,d0.w),d0 + jmp (L00017e,pc,d0.w) + +L00017e: + .dc 0 + .dc L000184-L00017e +L000182: + .dc.b $00,$00 + +L000184: + rts + +IN_BSS:: + move (L00018e,pc,d0.w),d0 + jmp (L00018e,pc,d0.w) + + .bss + +L00018e: + .ds 1 +L000190: + + .end L000000 diff --git a/tests/expected/scalefactor.s b/tests/expected/scalefactor.s new file mode 100644 index 0000000..c861552 --- /dev/null +++ b/tests/expected/scalefactor.s @@ -0,0 +1,37 @@ +;============================================= +; Filename obj/scalefactor.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000026 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 2 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/scalefactor.x dised/scalefactor.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + move (a0,d0.w),d0 + .cpu 68020 + move (a0,d0.w*2),d0 + move (a0,d0.w*4),d0 + move (a0,d0.w*8),d0 + nop + move (a0,d0.l),d0 + move (a0,d0.l*2),d0 + move (a0,d0.l*4),d0 + move (a0,d0.l*8),d0 + nop + DOS _EXIT + +L000026: + + .end L000000 diff --git a/tests/expected/split_end.s b/tests/expected/split_end.s new file mode 100644 index 0000000..61e4384 --- /dev/null +++ b/tests/expected/split_end.s @@ -0,0 +1,30 @@ +;============================================= +; Filename obj/split_end.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000400 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 3 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/split_end.x dised/split_end.s -S1 +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + move.l (L000008,pc),d0 + nop + DOS _EXIT + +L000008: + .ds.l 254 +L000400: + + .end L000000 diff --git a/tests/expected/sym_oorange.s b/tests/expected/sym_oorange.s new file mode 100644 index 0000000..179f29a --- /dev/null +++ b/tests/expected/sym_oorange.s @@ -0,0 +1,45 @@ +;============================================= +; Filename obj/sym_oorange.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000014 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 4 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/sym_oorange.x dised/sym_oorange.s -s2 +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + +XXX:: .equ 0 + .xdef aaa +AAA:: .equ aaa-$100 + .xdef bbb +BBB:: .equ aaa-$fe +YYY:: .equ $12345678 + .xdef ccc +CCC:: .equ ddd+$fe + .xdef ddd +DDD:: .equ ddd+$100 +ZZZ:: .equ $ffffffff + + .cpu 68000 + + .text + +aaa:: + nop +bbb:: + lea (AAA,pc),a0 + lea (BBB,pc),a0 + lea (CCC,pc),a0 + lea (DDD,pc),a0 +ccc:: + DOS _EXIT + +ddd:: + + .end aaa diff --git a/tests/expected/symbol.s b/tests/expected/symbol.s new file mode 100644 index 0000000..5de7641 --- /dev/null +++ b/tests/expected/symbol.s @@ -0,0 +1,45 @@ +;============================================= +; Filename obj/symbol.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000004 byte(s) +; Data size $00000004 byte(s) +; Bss size $00000404 byte(s) +; 5 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/symbol.x dised/symbol.s +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +textStart:: + nop + rts + +textEnd:: + + .data + +dataStart:: + .dc.b $12,$34,$56,$78 +dataEnd:: + + .bss + +bssStart:: + .ds.b 4 +bssEnd:: + + .stack + +stackStart:: + .ds.b 1024 +stackEnd:: + + .end textStart diff --git a/tests/expected/tab_depadrs.s b/tests/expected/tab_depadrs.s new file mode 100644 index 0000000..fe646f1 --- /dev/null +++ b/tests/expected/tab_depadrs.s @@ -0,0 +1,43 @@ +;============================================= +; Filename obj/tab_depadrs.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000022 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 5 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/tab_depadrs.x dised/tab_depadrs.s -gsrc/tab_depadrs.lab -Tsrc/tab_depadrs.tab +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + lea (L000006,pc),a0 + DOS _EXIT + +L000006: + .dc 1 + .dc 0 + .dc.l L000006 + .dc 2 + .dc 0 + .dc.l L000006 + +L000016: + clr (L000006) + rts + +L00001e: + moveq #0,d0 + rts + +L000022: + + .end L000000 diff --git a/tests/expected/tab_even.s b/tests/expected/tab_even.s new file mode 100644 index 0000000..a206912 --- /dev/null +++ b/tests/expected/tab_even.s @@ -0,0 +1,37 @@ +;============================================= +; Filename obj/tab_even.x +; +; Base address $00000000 +; Exec address $00000000 +; Text size $00000010 byte(s) +; Data size $00000000 byte(s) +; Bss size $00000000 byte(s) +; 4 Labels +; Commandline dis --deterministic --overwrite -m680x0,68851 obj/tab_even.x dised/tab_even.s -gsrc/tab_even.lab -Tsrc/tab_even.tab +;============================================= + + .include doscall.mac + .include iocscall.mac + .include fefunc.mac + + .cpu 68000 + + .text + +L000000: + lea (L000006,pc),a0 + DOS _EXIT + +L000006: + .dc.b 1 + .dc.b 'a' + .even + + .dc.b 2 + .dc.b 'ab' + .even +L00000c: + .dc.b $02,$78,$79,$ff +L000010: + + .end L000000 diff --git a/tests/expected/tab_stuck1.s b/tests/expected/tab_stuck1.s new file mode 100644 index 0000000..e69de29 diff --git a/tests/expected/tab_stuck2.s b/tests/expected/tab_stuck2.s new file mode 100644 index 0000000..e69de29 diff --git a/tests/src/after_str.s b/tests/src/after_str.s new file mode 100644 index 0000000..f89fd9a --- /dev/null +++ b/tests/src/after_str.s @@ -0,0 +1,13 @@ + lea (a,pc),a0 + nop + .dc $ff00 + +a: + .dc.b 'a',0 + .align 4,$0000 + +p: + movem.l d0-d7/a0-a6,-(sp) + nop + movem.l (sp)+,d0-d7/a0-a6 + rts diff --git a/tests/src/avoid_q.s b/tests/src/avoid_q.s new file mode 100644 index 0000000..8e43d7d --- /dev/null +++ b/tests/src/avoid_q.s @@ -0,0 +1,46 @@ +;dis -A + + move.l #0.l,d0 + move.l #127.l,d0 + move.l #128.l,d0 + move.l #-128.l,d0 + move.l #-129.l,d0 + nop + + addi #0.w,(a0) + addi #1.w,(a0) + addi #8.w,(a0) + addi #9.w,(a0) + nop + + subi #0.w,(a0) + subi #1.w,(a0) + subi #8.w,(a0) + subi #9.w,(a0) + nop + + add #0.w,d0 + add #1.w,d0 + add #8.w,d0 + add #9.w,d0 + nop + + sub #0.w,d0 + sub #1.w,d0 + sub #8.w,d0 + sub #9.w,d0 + nop + + adda #0.w,a0 + adda #1.w,a0 + adda #8.w,a0 + adda #9.w,a0 + nop + + suba #0.w,a0 + suba #1.w,a0 + suba #8.w,a0 + suba #9.w,a0 + nop + + .dc $ff00 diff --git a/tests/src/bd_size.s b/tests/src/bd_size.s new file mode 100644 index 0000000..1cf92b7 --- /dev/null +++ b/tests/src/bd_size.s @@ -0,0 +1,57 @@ +.cpu 68020 + tst (dummy1,pc) + nop + + tst ([0.w,pc]) ;Lxxxxxx.w + tst ([0.l,pc]) ;Lxxxxxx.l + nop + + tst (126.b,pc,d0.l) ;Lxxxxxx + tst (126.w,pc,d0.l) ;Lxxxxxx.w + tst (126.l,pc,d0.l) ;Lxxxxxx.l + + tst (128.w,pc,d0.l) ;Lxxxxxx.w + tst (128.l,pc,d0.l) ;Lxxxxxx.l + + tst (32766.w,pc,d0.l) ;Lxxxxxx + tst (32768.l,pc,d0.l) ;Lxxxxxx.l + tst (32770.l,pc,d0.l) ;Ideally Lxxxxxx, but an assembly error occurs + nop + + tst ([126.w,pc]) ;Lxxxxxx + tst ([126.l,pc]) ;Lxxxxxx.l + + tst ([32766.l,pc]) ;Lxxxxxx.l + tst ([32768.l,pc]) ;Lxxxxxx.l + tst ([32770.l,pc]) ;Lxxxxxx.l + nop + bra negative + + + .ds.b 124 +dummy1: + .ds.b 32768-124 + + +negative: + tst (-128.b,pc,d0.l) ;Lxxxxxx + tst (-128.w,pc,d0.l) ;Lxxxxxx.w + tst (-128.l,pc,d0.l) ;Lxxxxxx.l + + tst (-130.w,pc,d0.l) ;Lxxxxxx + tst (-130.l,pc,d0.l) ;Lxxxxxx.l + + tst (-32766.w,pc,d0.l) ;Lxxxxxx + tst (-32768.l,pc,d0.l) ;Lxxxxxx.l + tst (-32770.l,pc,d0.l) ;Lxxxxxx + nop + + tst ([-128.w,pc]) ;Lxxxxxx.w + tst ([-128.l,pc]) ;Lxxxxxx.l + + tst ([-32766.l,pc]) ;Lxxxxxx.l + tst ([-32768.l,pc]) ;Lxxxxxx.l + tst ([-32770.l,pc]) ;Lxxxxxx + nop + + .dc $ff00 diff --git a/tests/src/bitfield.s b/tests/src/bitfield.s new file mode 100644 index 0000000..19544f9 --- /dev/null +++ b/tests/src/bitfield.s @@ -0,0 +1,29 @@ +.cpu 68020 + bftst d7{d0:d0} + bftst d0{d7:d7} + bftst d7{d1:1} + bftst d0{d1:32} + bftst d7{0:d1} + bftst d7{31:d1} + bftst d7{0:32} + nop + + bfextu d7{d0:d0},d0 + bfextu d0{d7:d7},d0 + bfextu d7{d1:1},d0 + bfextu d0{d1:32},d0 + bfextu d7{0:d1},d0 + bfextu d7{31:d1},d0 + bfextu d7{0:32},d0 + nop + + bfins d0,d7{d0:d0} + bfins d0,d0{d7:d7} + bfins d0,d7{d1:1} + bfins d0,d0{d1:32} + bfins d0,d7{0:d1} + bfins d0,d7{31:d1} + bfins d0,d7{0:32} + nop + + .dc $ff00 diff --git a/tests/src/bitop.s b/tests/src/bitop.s new file mode 100644 index 0000000..94467af --- /dev/null +++ b/tests/src/bitop.s @@ -0,0 +1,29 @@ + btst #0,d0 + btst d0,(a0) + btst #$ff,d0 + btst #-1,d0 + rts + + bclr #0,d0 + bclr d0,(a0) + bclr #$ff,d0 + bclr #-1,d0 + rts + + bset #0,d0 + bset d0,(a0) + bset #$ff,d0 + bset #-1,d0 + rts + + bchg #0,d0 + bchg d0,(a0) + bchg #$ff,d0 + bchg #-1,d0 + rts + +;btst #0,d0 with illegal undef byte +;dis -f -> forced disassembly (binary mismatch when reassembled) + .dc $0800,$0100 + .dc $0800,$80ff + rts diff --git a/tests/src/blankline.s b/tests/src/blankline.s new file mode 100644 index 0000000..317820c --- /dev/null +++ b/tests/src/blankline.s @@ -0,0 +1,26 @@ +;dis -B + +.cpu 68020 + nop + rte + + nop + rtd #4 + + nop + rts + + nop + rtr + + nop + jmp (a0) +@@: + nop + bra @b +@@ + nop + fbra @b + + nop + .dc $ff00 diff --git a/tests/src/bra_size.s b/tests/src/bra_size.s new file mode 100644 index 0000000..88038fa --- /dev/null +++ b/tests/src/bra_size.s @@ -0,0 +1,125 @@ +.cpu 68020 + move.l (dummy1,pc,d0.w*4),d0 + move.l (dummy2,pc,d0.w*4),d0 + move.l (dummy3,pc,d0.w*4),d0 + move.l (dummy4,pc,d0.w*4),d0 + nop + bra mid + +bsr_w_$2m32768: + nop + rts + +bsr_l_$2m32768: + nop + rts + +bsr_l_$2m32770: + rts + +dummy1: + .ds.b 32608 + +bsr_s_$2m128: + rts + +bsr_w_$2m128: + nop + rts + +bsr_l_$2m128: + nop + rts + +bsr_w_$2m130: + nop + rts + +bsr_l_$2m130: + nop + rts + +dummy2: + .ds.b 56 + +mid: + bsr.s ($+2)+126 ;bsr + bsr.w ($+2)+126 ;bsr.w + bsr.l ($+2)+126 ;bsr.l + + bsr.w ($+2)+128 ;bsr.w + bsr.l ($+2)+128 ;bsr.l + + bsr.w ($+2)+130 ;bsr + bsr.l ($+2)+130 ;bsr.l + nop + + bsr.w ($+2)+32766 ;bsr + bsr.l ($+2)+32766 ;bsr.l + + bsr.l ($+2)+32768 ;bsr.l + nop + + bsr.s ($+2)-128 ;bsr + bsr.w ($+2)-128 ;bsr.w + bsr.l ($+2)-128 ;bsr.l + + bsr.w ($+2)-130 ;bsr + bsr.l ($+2)-130 ;bsr.l + + bsr.w ($+2)-32768 ;bsr + bsr.l ($+2)-32768 ;bsr.l + + bsr.l ($+2)-32770 ;bsr + + .dc $ff00 + +dummy3: + .ds.b 36 + +bsr_s_$2p126: + rts + +bsr_w_$2p126: + nop + rts + +bsr_l_$2p126: + nop + nop + nop + rts + +bsr_w_$2p128: + nop + rts + +bsr_l_$2p128: + nop + nop + nop + rts + +bsr_w_$2p130: + nop + rts + +bsr_l_$2p130: + nop + rts + +dummy4: + .ds.b 32640 + +bsr_w_$2p32766: + nop + rts + +bsr_l_$2p32766: + nop + nop + nop + rts + +bsr_l_$2p32768: + rts diff --git a/tests/src/cas.s b/tests/src/cas.s new file mode 100644 index 0000000..0069976 --- /dev/null +++ b/tests/src/cas.s @@ -0,0 +1,10 @@ +.cpu 68020 + cas d0,d7,(a0) + cas d7,d0,($12345678) + nop + + cas2 d0:d7,d6:d1,(d0):(d7) + cas2 d0:d7,d6:d1,(a0):(a7) + cas2 d0:d7,d6:d1,(d0):(a7) + cas2 d0:d7,d6:d1,(a7):(d0) + .dc $ff00 diff --git a/tests/src/cinvpush.s b/tests/src/cinvpush.s new file mode 100644 index 0000000..449f410 --- /dev/null +++ b/tests/src/cinvpush.s @@ -0,0 +1,67 @@ +.cpu 68040 + cinvl ic,(a0) + cinvl dc,(a1) + cinvl bc,(a6) + cinvl nc,(a7) + nop + rts + + cinvp ic,(a0) + cinvp dc,(a1) + cinvp bc,(a6) + cinvp nc,(a7) + nop + rts + + cinva ic + cinva dc + cinva bc + cinva nc + nop + rts + + cpushl ic,(a0) + cpushl dc,(a1) + cpushl bc,(a6) + cpushl nc,(a7) + nop + rts + + cpushp ic,(a0) + cpushp dc,(a1) + cpushp bc,(a6) + cpushp nc,(a7) + nop + rts + + cpusha ic + cpusha dc + cpusha bc + cpusha nc + nop + rts + +;dis -R0 --> forced disassembly (binary mismatch when reassembled) +;dis -R1 --> undefined instruction + + cinva bc ;(a0) $f4d8 + .dc $f4d9 ;(a1) + .dc $f4da ;(a2) + .dc $f4db ;(a3) + .dc $f4dc ;(a4) + .dc $f4dd ;(a5) + .dc $f4de ;(a6) + .dc $f4df ;(a7) + nop + rts + + cpusha bc ;(a0) $f4f8 + .dc $f4f9 ;(a1) + .dc $f4fa ;(a2) + .dc $f4fb ;(a3) + .dc $f4fc ;(a4) + .dc $f4fd ;(a5) + .dc $f4fe ;(a6) + .dc $f4ff ;(a7) + nop + rts diff --git a/tests/src/compress.s b/tests/src/compress.s new file mode 100644 index 0000000..ccc55c5 --- /dev/null +++ b/tests/src/compress.s @@ -0,0 +1,43 @@ +;dis -m680x0 -W2 + +.cpu 68020 + move.b (byte1,pc),d0 + move.b (byte2,pc),d0 + move.w (word1,pc),d0 + move.w (word2,pc),d0 + move.l (long1,pc),d0 + move.l (long2,pc),d0 + nop + fmove.s (single1,pc),fp0 + fmove.s (single2,pc),fp0 + fmove.d (double1,pc),fp0 + fmove.d (double2,pc),fp0 + fmove.x (extend1,pc),fp0 + fmove.x (extend2,pc),fp0 + fmove.p (packed1,pc),fp0 + fmove.p (packed2,pc),fp0 + .dc $ff00 + + +byte1: .dcb.b 4,$a5 +byte2: .ds.b 4 + +word1: .dcb.w 4,$cafe +word2: .ds.w 4 + +long1: .dcb.l 4,$deadbeef +long2: .ds.l 4 + +single1: .dcb.s 4,1.5 +single2: .ds.s 4 + +double1: .dcb.d 4,2.3456 +double2: .ds.d 4 + +extend1: .dcb.x 4,3.4567 +extend2: .ds.x 4 + +packed1: .dcb.p 4,4.5678 +packed2: .ds.p 4 + +.end diff --git a/tests/src/cpu32.s b/tests/src/cpu32.s new file mode 100644 index 0000000..001b996 --- /dev/null +++ b/tests/src/cpu32.s @@ -0,0 +1,47 @@ +;dis -m68060 +;dis -mcpu32 + +.cpu 68060 + + lpstop #$2000 + rts + +.cpu 68000 + +;bgnd + .dc $4afa + rts + +;tbls.b (a0),d7 + .dc $f810,$7900 + rts + +;tblsn.b (a0),d7 + .dc $f810,$7d00 + rts + +;tbls.b d0:d1,d7 + .dc $f800,$7801 + rts + +;tblsn.b d0:d1,d7 + .dc $f800,$7c01 + rts + +;tblu.b (a0),d7 + .dc $f810,$7100 + rts + +;tblun.b (a0),d7 + .dc $f810,$7500 + rts + +;tblu.b d0:d1,d7 + .dc $f800,$7001 + rts + +;tblun.b d0:d1,d7 + .dc $f800,$7401 + rts + +.end diff --git a/tests/src/devhead_loop.s b/tests/src/devhead_loop.s new file mode 100644 index 0000000..c50fe13 --- /dev/null +++ b/tests/src/devhead_loop.s @@ -0,0 +1,35 @@ +devhead1: + .dc.l devhead2 + .dc $8000 + .dc.l strategy1 + .dc.l interrupt1 + .dc.b '/*?--?*/' + +strategy1: + rts +interrupt1: + rts + +devhead2: + .dc.l devhead3 + .dc $8000 + .dc.l strategy2 + .dc.l interrupt2 + .dc.b '/*?--?*/' + +strategy2: + rts +interrupt2: + rts + +devhead3: + .dc.l devhead2 + .dc $8000 + .dc.l strategy3 + .dc.l interrupt3 + .dc.b '/*?--?*/' + +strategy3: + rts +interrupt3: + rts diff --git a/tests/src/ds.s b/tests/src/ds.s new file mode 100644 index 0000000..341886e --- /dev/null +++ b/tests/src/ds.s @@ -0,0 +1,28 @@ + move.b (byte,pc),d0 + move (word,pc),d0 + move.l (long,pc),d0 + +.cpu 68020 + pmove (quad_),srp + pmove.q (quad_),srp + pmove.d (quad_),srp + + nop + fmove.s (single,pc),fp0 + fmove.d (double,pc),fp0 + fmove.x (extend,pc),fp0 + fmove.p (packed,pc),fp0 + + .dc $ff00 + +.bss +byte: .ds.b 2 +.even +word: .ds 2 +long: .ds.l 2 +quad_: .ds.b 8*2 + +single: .ds.s 2 +double: .ds.d 2 +extend: .ds.x 2 +packed: .ds.p 2 diff --git a/tests/src/ea_abs.s b/tests/src/ea_abs.s new file mode 100644 index 0000000..849f94b --- /dev/null +++ b/tests/src/ea_abs.s @@ -0,0 +1,14 @@ + pea (0).w + pea (1).w + pea ($7fff).w + pea ($8000).w + pea (-1).w + pea (-$8000).w + + pea (0).l + pea (1).l + pea ($7fff).l + pea ($8000).l + pea (-1).l + pea (-$8000).l + .dc $ff00 diff --git a/tests/src/ea_label.s b/tests/src/ea_label.s new file mode 100644 index 0000000..710c323 --- /dev/null +++ b/tests/src/ea_label.s @@ -0,0 +1,369 @@ +.cpu 68020 + nop + .dc $ff00 + +table: + .irp x,10f,11f,12f,13f,14f,15f,16f,17f,18f,19f,20f,21f,22f,23f,24f,25f,26f,27f,28f,29f,30f,31f,32f,33f + .dc.l x + .endm + + +;abs.w +10: + move ($6800).w,d0 + rts + +;abs.l +11: + move ($beefcafe),d0 + move (a).l,d0 + rts + +;(d16,pc) +12: + move (pclabel,pc),d0 + rts + +;(d8,pc,ix) +13: + move (pclabel,pc,d0.l),d0 + rts + +;(bd,pc,ix) +14: + move (pclabel.w,pc),d0 + move (pclabel.w,pc,d0.l),d0 + move (pclabel.l,pc),d0 + move (pclabel.l,pc,d0.l),d0 + move (pclabel.l,zpc),d0 + move (pclabel.l,zpc,d0.l),d0 + rts + + bra @f +pclabel: .dc $cafe +a: .dc.l $12345678 +@@: + + +;#imm +15: + move #$6800,d0 + move.l #$beefcafe,d0 + move.l #a,d0 + rts + +;(bd,an,ix) +16: + move (a0,d0.l),d0 + move ($6800,a0,d0.l),d0 + move ($beefcafe,a0,d0.l),d0 + move (a,a0,d0.l),d0 + rts + +;([an],ix,od) +17: + move ([za0],d0.l),d0 + move ([za0],d0.l,$6800),d0 + move ([za0],d0.l,$beefcafe),d0 + move ([za0],d0.l,a),d0 + move ([za0]),d0 + move ([za0],$6800),d0 + move ([za0],$beefcafe),d0 + move ([za0],a),d0 + move ([a0],d0.l),d0 + move ([a0],d0.l,$6800),d0 + move ([a0],d0.l,$beefcafe),d0 + move ([a0],d0.l,a),d0 + move ([a0]),d0 + move ([a0],$6800),d0 + move ([a0],$beefcafe),d0 + move ([a0],a),d0 + rts + +;([bd.w,an],ix,od) +18: + move ([$6800,za0],d0.l),d0 + move ([$6800,za0],d0.l,$6800),d0 + move ([$6800,za0],d0.l,$beefcafe),d0 + move ([$6800,za0],d0.l,a),d0 + move ([$6800,za0]),d0 + move ([$6800,za0],$6800),d0 + move ([$6800,za0],$beefcafe),d0 + move ([$6800,za0],a),d0 + move ([$6800,a0],d0.l),d0 + move ([$6800,a0],d0.l,$6800),d0 + move ([$6800,a0],d0.l,$beefcafe),d0 + move ([$6800,a0],d0.l,a),d0 + move ([$6800,a0]),d0 + move ([$6800,a0],$6800),d0 + move ([$6800,a0],$beefcafe),d0 + move ([$6800,a0],a),d0 + rts + +;([bd.l,an],ix,od) +19: + move ([$beefcafe,za0],d0.l),d0 + move ([$beefcafe,za0],d0.l,$6800),d0 + move ([$beefcafe,za0],d0.l,$beefcafe),d0 + move ([$beefcafe,za0],d0.l,a),d0 + move ([$beefcafe,za0]),d0 + move ([$beefcafe,za0],$6800),d0 + move ([$beefcafe,za0],$beefcafe),d0 + move ([$beefcafe,za0],a),d0 + move ([$beefcafe,a0],d0.l),d0 + move ([$beefcafe,a0],d0.l,$6800),d0 + move ([$beefcafe,a0],d0.l,$beefcafe),d0 + move ([$beefcafe,a0],d0.l,a),d0 + move ([$beefcafe,a0]),d0 + move ([$beefcafe,a0],$6800),d0 + move ([$beefcafe,a0],$beefcafe),d0 + move ([$beefcafe,a0],a),d0 + rts + +;([bd.l,an],ix,od) label +20: + move ([a,za0],d0.l),d0 + move ([a,za0],d0.l,$6800),d0 + move ([a,za0],d0.l,$beefcafe),d0 + move ([a,za0],d0.l,a),d0 + move ([a,za0]),d0 + move ([a,za0],$6800),d0 + move ([a,za0],$beefcafe),d0 + move ([a,za0],a),d0 + move ([a,a0],d0.l),d0 + move ([a,a0],d0.l,$6800),d0 + move ([a,a0],d0.l,$beefcafe),d0 + move ([a,a0],d0.l,a),d0 + move ([a,a0]),d0 + move ([a,a0],$6800),d0 + move ([a,a0],$beefcafe),d0 + move ([a,a0],a),d0 + rts + +;([an,ix],od) +21: + move ([za0,d0.l]),d0 + move ([za0,d0.l],$6800),d0 + move ([za0,d0.l],$beefcafe),d0 + move ([za0,d0.l],a),d0 + move ([za0]),d0 + move ([za0],$6800),d0 + move ([za0],$beefcafe),d0 + move ([za0],a),d0 + move ([a0,d0.l]),d0 + move ([a0,d0.l],$6800),d0 + move ([a0,d0.l],$beefcafe),d0 + move ([a0,d0.l],a),d0 + move ([a0]),d0 + move ([a0],$6800),d0 + move ([a0],$beefcafe),d0 + move ([a0],a),d0 + rts + +;([bd.w,an],ix,od) +22: + move ([$6800,za0,d0.l]),d0 + move ([$6800,za0,d0.l],$6800),d0 + move ([$6800,za0,d0.l],$beefcafe),d0 + move ([$6800,za0,d0.l],a),d0 + move ([$6800,za0]),d0 + move ([$6800,za0],$6800),d0 + move ([$6800,za0],$beefcafe),d0 + move ([$6800,za0],a),d0 + move ([$6800,a0,d0.l]),d0 + move ([$6800,a0,d0.l],$6800),d0 + move ([$6800,a0,d0.l],$beefcafe),d0 + move ([$6800,a0,d0.l],a),d0 + move ([$6800,a0]),d0 + move ([$6800,a0],$6800),d0 + move ([$6800,a0],$beefcafe),d0 + move ([$6800,a0],a),d0 + rts + +;([bd.l,an],ix,od) +23: + move ([$beefcafe,za0,d0.l]),d0 + move ([$beefcafe,za0,d0.l],$6800),d0 + move ([$beefcafe,za0,d0.l],$beefcafe),d0 + move ([$beefcafe,za0,d0.l],a),d0 + move ([$beefcafe,za0]),d0 + move ([$beefcafe,za0],$6800),d0 + move ([$beefcafe,za0],$beefcafe),d0 + move ([$beefcafe,za0],a),d0 + move ([$beefcafe,a0,d0.l]),d0 + move ([$beefcafe,a0,d0.l],$6800),d0 + move ([$beefcafe,a0,d0.l],$beefcafe),d0 + move ([$beefcafe,a0,d0.l],a),d0 + move ([$beefcafe,a0]),d0 + move ([$beefcafe,a0],$6800),d0 + move ([$beefcafe,a0],$beefcafe),d0 + move ([$beefcafe,a0],a),d0 + rts + +;([bd.l,an],ix,od) label +24: + move ([a,za0,d0.l]),d0 + move ([a,za0,d0.l],$6800),d0 + move ([a,za0,d0.l],$beefcafe),d0 + move ([a,za0,d0.l],a),d0 + move ([a,za0]),d0 + move ([a,za0],$6800),d0 + move ([a,za0],$beefcafe),d0 + move ([a,za0],a),d0 + move ([a,a0,d0.l]),d0 + move ([a,a0,d0.l],$6800),d0 + move ([a,a0,d0.l],$beefcafe),d0 + move ([a,a0,d0.l],a),d0 + move ([a,a0]),d0 + move ([a,a0],$6800),d0 + move ([a,a0],$beefcafe),d0 + move ([a,a0],a),d0 + rts + +;([pc],ix,od) +25: + move ([zpc],d0.l),d0 + move ([zpc],d0.l,$6800),d0 + move ([zpc],d0.l,$beefcafe),d0 + move ([zpc],d0.l,a),d0 + move ([zpc]),d0 + move ([zpc],$6800),d0 + move ([zpc],$beefcafe),d0 + move ([zpc],a),d0 + move ([pc],d0.l),d0 + move ([pc],d0.l,$6800),d0 + move ([pc],d0.l,$beefcafe),d0 + move ([pc],d0.l,a),d0 + move ([pc]),d0 + move ([pc],$6800),d0 + move ([pc],$beefcafe),d0 + move ([pc],a),d0 + rts + +;([bd.w,pc],ix,od) +26: + move ([$6800,zpc],d0.l),d0 + move ([$6800,zpc],d0.l,$6800),d0 + move ([$6800,zpc],d0.l,$beefcafe),d0 + move ([$6800,zpc],d0.l,a),d0 + move ([$6800,zpc]),d0 + move ([$6800,zpc],$6800),d0 + move ([$6800,zpc],$beefcafe),d0 + move ([$6800,zpc],a),d0 + rts + +;([bd.w,pc],ix,od) label +27: + move ([a.w,pc],d0.l),d0 + move ([a.w,pc],d0.l,$6800),d0 + move ([a.w,pc],d0.l,$beefcafe),d0 + move ([a.w,pc],d0.l,a),d0 + move ([a.w,pc]),d0 + move ([a.w,pc],$6800),d0 + move ([a.w,pc],$beefcafe),d0 + move ([a.w,pc],a),d0 + rts + +;([bd.l,pc],ix,od) +28: + move ([$beefcafe,zpc],d0.l),d0 + move ([$beefcafe,zpc],d0.l,$6800),d0 + move ([$beefcafe,zpc],d0.l,$beefcafe),d0 + move ([$beefcafe,zpc],d0.l,a),d0 + move ([$beefcafe,zpc]),d0 + move ([$beefcafe,zpc],$6800),d0 + move ([$beefcafe,zpc],$beefcafe),d0 + move ([$beefcafe,zpc],a),d0 + rts + +;([bd.l,pc],ix,od) label +29: + move ([a.l,zpc],d0.l),d0 + move ([a.l,zpc],d0.l,$6800),d0 + move ([a.l,zpc],d0.l,$beefcafe),d0 + move ([a.l,zpc],d0.l,a),d0 + move ([a.l,zpc]),d0 + move ([a.l,zpc],$6800),d0 + move ([a.l,zpc],$beefcafe),d0 + move ([a.l,zpc],a),d0 + move ([a.l,pc],d0.l),d0 + move ([a.l,pc],d0.l,$6800),d0 + move ([a.l,pc],d0.l,$beefcafe),d0 + move ([a.l,pc],d0.l,a),d0 + move ([a.l,pc]),d0 + move ([a.l,pc],$6800),d0 + move ([a.l,pc],$beefcafe),d0 + move ([a.l,pc],a),d0 + rts + +;([pc,ix],od) +30: + move ([zpc,d0.l]),d0 + move ([zpc,d0.l],$6800),d0 + move ([zpc,d0.l],$beefcafe),d0 + move ([zpc,d0.l],a),d0 + move ([zpc]),d0 + move ([zpc],$6800),d0 + move ([zpc],$beefcafe),d0 + move ([zpc],a),d0 + move ([pc,d0.l]),d0 + move ([pc,d0.l],$6800),d0 + move ([pc,d0.l],$beefcafe),d0 + move ([pc,d0.l],a),d0 + move ([pc]),d0 + move ([pc],$6800),d0 + move ([pc],$beefcafe),d0 + move ([pc],a),d0 + rts + +;([bd.w,pc],ix,od) +31: + move ([a.w,pc,d0.l]),d0 + move ([a.w,pc,d0.l],$6800),d0 + move ([a.w,pc,d0.l],$beefcafe),d0 + move ([a.w,pc,d0.l],a),d0 + move ([a.w,pc]),d0 + move ([a.w,pc],$6800),d0 + move ([a.w,pc],$beefcafe),d0 + move ([a.w,pc],a),d0 + rts + +;([bd.l,pc],ix,od) +32: + move ([$beefcafe,zpc,d0.l]),d0 + move ([$beefcafe,zpc,d0.l],$6800),d0 + move ([$beefcafe,zpc,d0.l],$beefcafe),d0 + move ([$beefcafe,zpc,d0.l],a),d0 + move ([$beefcafe,zpc]),d0 + move ([$beefcafe,zpc],$6800),d0 + move ([$beefcafe,zpc],$beefcafe),d0 + move ([$beefcafe,zpc],a),d0 + move ([$beefcafe,pc,d0.l]),d0 + move ([$beefcafe,pc,d0.l],$6800),d0 + move ([$beefcafe,pc,d0.l],$beefcafe),d0 + move ([$beefcafe,pc,d0.l],a),d0 + move ([$beefcafe,pc]),d0 + move ([$beefcafe,pc],$6800),d0 + move ([$beefcafe,pc],$beefcafe),d0 + move ([$beefcafe,pc],a),d0 + rts + +;([bd.l,pc],ix,od) label +33: + move ([a.l,zpc,d0.l]),d0 + move ([a.l,zpc,d0.l],$6800),d0 + move ([a.l,zpc,d0.l],$beefcafe),d0 + move ([a.l,zpc,d0.l],a),d0 + move ([a.l,zpc]),d0 + move ([a.l,zpc],$6800),d0 + move ([a.l,zpc],$beefcafe),d0 + move ([a.l,zpc],a),d0 + move ([a.l,pc,d0.l]),d0 + move ([a.l,pc,d0.l],$6800),d0 + move ([a.l,pc,d0.l],$beefcafe),d0 + move ([a.l,pc,d0.l],a),d0 + move ([a.l,pc]),d0 + move ([a.l,pc],$6800),d0 + move ([a.l,pc],$beefcafe),d0 + move ([a.l,pc],a),d0 + rts diff --git a/tests/src/ea_misc.s b/tests/src/ea_misc.s new file mode 100644 index 0000000..d2d81e6 --- /dev/null +++ b/tests/src/ea_misc.s @@ -0,0 +1,50 @@ +.cpu 68000 + cmpm (a0)+,(a0)+ + cmpm (a0)+,(a7)+ + cmpm (a7)+,(a7)+ + cmpm (a6)+,(a6)+ + nop + + addx -(a0),-(a0) + addx -(a0),-(a7) + addx -(a7),-(a0) + addx -(a7),-(a7) + addx d0,d0 + addx d0,d7 + addx d7,d0 + addx d7,d7 + nop + + abcd -(a0),-(a0) + abcd -(a0),-(a7) + abcd -(a7),-(a0) + abcd -(a7),-(a7) + abcd d0,d0 + abcd d0,d7 + abcd d7,d0 + abcd d7,d7 + nop + +.cpu 68020 + pack d0,d0,#'0' + pack d0,d7,#0 + unpk d7,d0,#-1 + unpk d3,d4,#$80 + nop + + pack -(a0),-(a0),#'0' + pack -(a0),-(a7),#0 + unpk -(a6),-(a0),#-1 + unpk -(a3),-(a4),#$80 + nop + +.cpu 68040 + move16 (a0)+,(0) + move16 (0),(a0)+ + move16 (a0),(0) + move16 (0),(a0) + move16 (a0)+,(a0)+ + move16 (a7)+,(a7)+ + nop + + .dc $ff00 diff --git a/tests/src/fmovem.s b/tests/src/fmovem.s new file mode 100644 index 0000000..0b983f6 --- /dev/null +++ b/tests/src/fmovem.s @@ -0,0 +1,58 @@ +.cpu 68020 + fmove.b #0,fp0 + fmove.b #1,fp1 + fmove.b #20,fp2 + fmove.w #300,fp3 + fmove.w #4000,fp4 + fmove.l #50000,fp5 + fmove.l #600000,fp6 + fmove.l #7000000,fp7 + rts + + fmovem fp0-fp3,(a0) ;mode=%10 static, postinc or ctrl + rts + + .dc $f210,$e0f0 ;NG mode=%00 + rts + + fmovem d0,(a0) ;%mode=%11 dynamic, postinc or ctrl + rts + + .dc $f210,$e800 ;NG %mode=%01 + rts + + fmovem fp0-fp3,-(a0) ;mode=%00 static, predec + rts + + .dc $f220,$f00f ;NG %mode=%10 + rts + + fmovem d0,-(a0) ;mode=%01 dynamic, predec + rts + + .dc $f220,$f800 ;NG mode=%11 + rts + + fmovem (a0),fp0-fp3 ;mode=%10 static, postinc or ctrl + rts + + .dc $f210,$c0f0 ;NG %mode=00 + rts + + fmovem (a0),d0 ;mode=%11 dynamic, postinc or ctrl + rts + + .dc $f210,$c800 ;NG mode=%01 + rts + + fmovem (a0),fp0-fp3 ;mode=%10 static, postinc or ctrl + rts + + .dc $f210,$c0f0 ;NG mode=%00 + rts + + fmovem (a0),d0 ;mode=%11 dynamic, postinc or ctrl + rts + + .dc $f210,$c800 ;NG mode=%01 + rts diff --git a/tests/src/fp_imm.s b/tests/src/fp_imm.s new file mode 100644 index 0000000..b8fd3a6 --- /dev/null +++ b/tests/src/fp_imm.s @@ -0,0 +1,109 @@ +.cpu 68020 + +SingleZero:: ;e == 0 && m == 0 + fmove.s #!00000000,fp0 + nop + fmove.s #!80000000,fp0 + rts + +SingleDenorm:: ;e == 0 && m != 0 + fmove.s #!00000001,fp0 + fmove.s #!00400000,fp0 + nop + fmove.s #!80000001,fp0 + fmove.s #!80400000,fp0 + rts + +SingleInf:: ;e == max && m == 0 + fmove.s #!7f800000,fp0 + nop + fmove.s #!ff800000,fp0 + rts + +SingleNaN:: ;e == max && m != 0 + fmove.s #!7f800001,fp0 + fmove.s #!7fc00000,fp0 + nop + fmove.s #!ff800001,fp0 + fmove.s #!ffc00000,fp0 + rts + + +DoubleZero:: ;e == 0 && m == 0 + fmove.d #!00000000_00000000,fp0 + nop + fmove.d #!80000000_00000000,fp0 + rts + +DoubleDenorm:: ;e == 0 && m != 0 + fmove.d #!00000000_00000001,fp0 + fmove.d #!00000000_80000000,fp0 + fmove.d #!00000001_00000000,fp0 + fmove.d #!00080000_00000000,fp0 + nop + fmove.d #!80000000_00000001,fp0 + fmove.d #!80000000_80000000,fp0 + fmove.d #!80000001_00000000,fp0 + fmove.d #!80080000_00000000,fp0 + rts + +DoubleInf:: ;e == max && m == 0 + fmove.d #!7ff00000_00000000,fp0 + nop + fmove.d #!fff00000_00000000,fp0 + rts + +DoubleNaN:: ;e == max && m != 0 + fmove.d #!7ff00000_00000001,fp0 + fmove.d #!7ff00000_80000000,fp0 + fmove.d #!7ff00001_00000000,fp0 + fmove.d #!7ff80000_00000000,fp0 + nop + fmove.d #!fff00000_00000001,fp0 + fmove.d #!fff00000_80000000,fp0 + fmove.d #!fff00001_00000000,fp0 + fmove.d #!fff80000_00000000,fp0 + rts + + +ExtendedZero:: ;e == 0 && m == 0 + fmove.x #!00000000_00000000_00000000,fp0 + nop + fmove.x #!80000000_00000000_00000000,fp0 + rts + +ExtendedDenorm:: ;e == 0 && m != 0 + fmove.x #!00000000_00000000_00000001,fp0 + fmove.x #!00000000_00000000_80000000,fp0 + fmove.x #!00000000_00000001_00000000,fp0 + fmove.x #!00000000_80000000_00000000,fp0 + nop + fmove.x #!80000000_00000000_00000001,fp0 + fmove.x #!80000000_00000000_80000000,fp0 + fmove.x #!80000000_00000001_00000000,fp0 + fmove.x #!80000000_80000000_00000000,fp0 + rts + +ExtendedInf:: ;e == max && m == 0 + fmove.x #!7fff0000_00000000_00000000,fp0 + nop + fmove.x #!ffff0000_00000000_00000000,fp0 + rts + +ExtendedNaN:: ;e == max && m != 0 + fmove.x #!7fff0000_00000000_00000001,fp0 + fmove.x #!7fff0000_00000000_80000000,fp0 + fmove.x #!7fff0000_00000001_00000000,fp0 + fmove.x #!7fff0000_80000000_00000000,fp0 + nop + rts + +ExtendedReservedNotZero:: + fmove.x #!00000001_00000000_00000000,fp0 + fmove.x #!00008000_00000000_00000000,fp0 + nop + fmove.x #!80000001_00000000_00000000,fp0 + fmove.x #!80008000_00000000_00000000,fp0 + rts + +.end diff --git a/tests/src/fp_undefreg.s b/tests/src/fp_undefreg.s new file mode 100644 index 0000000..600b5a8 --- /dev/null +++ b/tests/src/fp_undefreg.s @@ -0,0 +1,53 @@ +;dis -m68020,68851 -R0 --> forced disassembly (binary mismatch when reassembled) +; (exclude NG instruction) +;dis -m68020,68851 -R1 --> undefined instruction + +.cpu 68020 + ftst fp0 + rts + + .dc $f204,$003a ;NG != 0 + rts + + .dc $f200,$013a ;ng != 0 + rts + + .dc $f200,$0f3a ;ng != + rts + + + fmove fp0,fp0 + rts + + .dc $f201,$0000 ;NG != 0 + rts + + + fmovecr #0,fp0 + rts + + .dc $f201,$5c00 ;NG != 0 + rts + + .dc $f208,$5c00 ;NG != 0 + rts + + .dc $f23f,$5c00 ;NG != 0 + rts + + + fmove.p fp0,(a0){d7} + rts + + .dc $f210,$7c7f ;NG != 0 + rts + + + fmove.x fp0,(a0) + rts + + .dc $f210,$6840 ;NG != 0 + rts + + .dc $f210,$6801 ;NG != 0 + rts diff --git a/tests/src/fsincos.s b/tests/src/fsincos.s new file mode 100644 index 0000000..249b82a --- /dev/null +++ b/tests/src/fsincos.s @@ -0,0 +1,6 @@ +.cpu 68020 + fsincos fp0,fp1:fp0 + fsincos fp7,fp0:fp7 + fsincos (a0),fp0:fp1 + nop + .dc $ff00 diff --git a/tests/src/imm.s b/tests/src/imm.s new file mode 100644 index 0000000..53527db --- /dev/null +++ b/tests/src/imm.s @@ -0,0 +1,98 @@ + btst #0,d0 + btst #31,d7 + btst #0,(a0) + btst #7,(a0) + rts + + ori #0,d0 + ori #$8000,d1 + ori #$ffff,d7 + rts + + stop #0 + stop #$ffff + rts + +.cpu 68020 + rtd #0 + rtd #$ffff + rts + + trapcc #0 + trapcc #$ffff + trapcc.l #0 + trapcc.l #$ffffffff + rts + + pack d0,d7,#0 + pack d7,d0,#$ffff + unpk d0,d7,#0 + unpk d7,d0,#$ffff + rts + +.cpu 68060 + lpstop #0 + lpstop #$ffff + rts + +.cpu 68020 + ptrapcc #0 + ptrapcc #$ffff + ptrapcc.l #0 + ptrapcc.l #$ffffffff + rts + + ftrapeq #0 + ftrapeq #$ffff + ftrapeq.l #0 + ftrapeq.l #$ffffffff + rts + + link a6,#0 + link a6,#$7fff + link a6,#-1 + link a6,#-$8000 + link.l a6,#0 + link.l a6,#$7fffffff + link.l a6,#-1 + link.l a6,#-$80000000 + rts + +.cpu 68020 + callm #0,(a0) + rtm d0 + callm #$ff,(a0) + rtm d7 + + trap #0 + moveq #0,d0 + trap #15 + rts + + bkpt #0 + bkpt #7 + rts + + moveq #0,d0 + moveq #$7f,d1 + moveq #$80,d6 + moveq #$ff,d7 + rts + + fmovecr #0,fp0 + fmovecr #$7f,fp7 + rts + + ptestr sfc,(a0),#0 + ptestr sfc,(a0),#7 + rts + + addq #1,d0 + addq #8,d7 + subq #1,d0 + subq #8,d7 + rts + + lsl #1,d0 + lsl #8,d0 + rts diff --git a/tests/src/imm_comment.s b/tests/src/imm_comment.s new file mode 100644 index 0000000..7389651 --- /dev/null +++ b/tests/src/imm_comment.s @@ -0,0 +1,48 @@ +;dis -M + + moveq.l #'a',d0 + + move.b #'a',d0 + move.w #'ab',d0 + move.w #'x',d0 + move.l #'abcd',d0 + move.l #'xyz',d0 + move.l #'xyz'<<8,d0 + move.l #'xy'<<8,d0 + + cmp.b #'a',d0 + cmp.w #'ab',d0 + cmp.w #'x',d0 + cmp.l #'abcd',d0 + cmp.l #'xyz',d0 + cmp.l #'xyz'<<8,d0 + cmp.l #'xy'<<8,d0 + + cmpi.b #'a',d0 + cmpi.w #'ab',d0 + cmpi.w #'x',d0 + cmpi.l #'abcd',d0 + cmpi.l #'xyz',d0 + cmpi.l #'xyz'<<8,d0 + cmpi.l #'xy'<<8,d0 + + cmpa.w #'ab',a0 + cmpa.w #'x',a0 + cmpa.l #'abcd',a0 + cmpa.l #'xyz',a0 + cmpa.l #'xyz'<<8,a0 + cmpa.l #'xy'<<8,a0 + + add.b #'a',d0 + add.w #'ab',d0 ;no comment + add.l #'abcd',d0 ;no comment + + sub.b #'a',d0 + sub.w #'ab',d0 ;no comment + sub.l #'abcd',d0 ;no comment + +.cpu 68020 + pack d0,d0,#'ab' + unpk d0,d0,#'ab' + + .dc $ff00 diff --git a/tests/src/kfactor.s b/tests/src/kfactor.s new file mode 100644 index 0000000..00a44cf --- /dev/null +++ b/tests/src/kfactor.s @@ -0,0 +1,12 @@ +.cpu 68020 + fmove.p fp0,(a0){d0} + fmove.p fp7,(a0){d7} + nop + + fmove.p fp0,(a0){#-64} + fmove.p fp0,(a0){#-1} + fmove.p fp0,(a0){#-0} + fmove.p fp0,(a0){#-1} + fmove.p fp0,(a0){#-63} + + .dc $ff00 diff --git a/tests/src/lab_in_reltbl.s b/tests/src/lab_in_reltbl.s new file mode 100644 index 0000000..c7ca341 --- /dev/null +++ b/tests/src/lab_in_reltbl.s @@ -0,0 +1,18 @@ + move (@f,pc,d0.w),d0 + jsr (@f,pc,d0.w) + .dc $ff00 + +@@: + .dc 1f-@b + .dc 2f-@b + .dc 3f-@b + .dc.b 0 +xxx:: + .dc.b 4f-@b + + .even +1: rts +2: rts +3: rts +4: lea (xxx,pc),a0 + rts diff --git a/tests/src/lab_oorange.s b/tests/src/lab_oorange.s new file mode 100644 index 0000000..73bb21f --- /dev/null +++ b/tests/src/lab_oorange.s @@ -0,0 +1,5 @@ +start: + lea (start-$100,pc),a0 + lea (last+$100,pc),a1 + .dc $ff00 +last: diff --git a/tests/src/lab_rw.lab b/tests/src/lab_rw.lab new file mode 100644 index 0000000..37c5f4e --- /dev/null +++ b/tests/src/lab_rw.lab @@ -0,0 +1,10 @@ +********************************************* +* +* Label file for bin/lab_rw.x +* +********************************************* +000000 P +00000e rw +000018 P +00001a P +00001c DU diff --git a/tests/src/lab_rw.s b/tests/src/lab_rw.s new file mode 100644 index 0000000..8de5be5 --- /dev/null +++ b/tests/src/lab_rw.s @@ -0,0 +1,21 @@ +;dis -e +;edit labelfile +;dis -g + + moveq #0,d0 + move (table,pc,d0.w),d0 + nop ;avoid auto reltbl detection + jsr (table,pc,d0.w) + .dc $ff00 + +table: + .dc 1f-table + .dc 2f-table + +test: + ori.b #10,(a0) + rts +1: + rts +2: + rts diff --git a/tests/src/mmu.s b/tests/src/mmu.s new file mode 100644 index 0000000..7773023 --- /dev/null +++ b/tests/src/mmu.s @@ -0,0 +1,118 @@ +MPU_68030: .macro +.cpu 68030 + pmovefd (a0),srp +.endm + +.cpu 68040 + pflush (a0) + pflushn (a7) + pflusha + pflushan + nop + ptestr (a0) + ptestw (a7) + nop + +.cpu 68060 + plpar (a0) + plpaw (a7) + nop + rts + + MPU_68030 +.cpu 68020 + ploadr sfc,(a0) + ploadr dfc,(a0) + ploadr d0,(a0) + ploadr d7,(a0) + ploadr #0,(a0) + ploadr #7,(a0) + ploadr #8,(a0) + ploadr #15,(a0) + nop + rts + + MPU_68030 +.cpu 68020 + ploadw sfc,(a0) + ploadw dfc,(a0) + ploadw d0,(a0) + ploadw d7,(a0) + ploadw #0,(a0) + ploadw #7,(a0) + ploadw #8,(a0) + ploadw #15,(a0) + nop + rts + + MPU_68030 +.cpu 68020 + pflush sfc,#0 + pflush dfc,#7,(a0) + pflush #1,#0 + pflush #6,#7,(a0) + pflush sfc,#8 + pflush dfc,#15,(a0) + pflush #8,#0 + pflush #15,#7,(a0) + nop + rts + + MPU_68030 +.cpu 68020 + pflushs sfc,#0 + pflushs dfc,#7,(a0) + pflushs #1,#0 + pflushs #6,#7,(a0) + pflushs sfc,#8 + pflushs dfc,#15,(a0) + pflushs #8,#0 + pflushs #15,#7,(a0) + nop + rts + + MPU_68030 +.cpu 68020 + ptestr #0,(a0),#7 + ptestr #7,(a7),#0 + ptestr #0,(a0),#7,sp +; ptestr #7,(a7),#0,a0 ;F-line exception + ptestw #0,(a0),#7 + ptestw #7,(a7),#0 + ptestw #0,(a0),#7,sp +; ptestw #7,(a7),#0,a0 ;F-line exception + nop + rts + + MPU_68030 +.cpu 68020 + pmove psr,(a0) + pmove pcsr,(a0) + pmove bad0,(a0) + pmove bad7,(a0) + pmove bac0,(a0) + pmove bac7,(a0) + nop + rts + +.cpu 68030 + pmove tt0,(a0) + pmove tt1,(a0) + pmove tc,(a0) +.cpu 68020 + pmove drp,(a0) +.cpu 68030 + pmove srp,(a0) + pmove crp,(a0) +.cpu 68020 + pmove cal,(a0) + pmove val,(a0) + pmove scc,(a0) + pmove ac,(a0) + nop + rts + +.cpu 68020 + pmove #$12345678,#$9abcdef0,crp + rts + diff --git a/tests/src/mmu_undefreg.s b/tests/src/mmu_undefreg.s new file mode 100644 index 0000000..0ceb94d --- /dev/null +++ b/tests/src/mmu_undefreg.s @@ -0,0 +1,24 @@ +;dis -m68020,68851 -R0 --> forced disassembly (binary mismatch when reassembled) +; (exclude NG instruction) +;dis -m68020,68851 -R1 --> undefined instruction + +.cpu 68020 + .dc $f010,$8720 ;ok - ptestr sfc,(a0),#1,a1 + rts + .dc $f010,$8220 ;NG - ptestr sfc,(a0),#0 [,a1] ... always undefined inst. + rts + + .dc $f010,$8720 ;ok - ptestr sfc,(a0),#1,a1 + rts + .dc $f010,$8620 ;ng - ptestr sfc,(a0),#1 [,a1] + rts + + .dc $f000,$2400 ;ok - pflusha + rts + .dc $f011,$2400 ;ng - pflusha [(a1)] + rts + + .dc $f011,$3800 ;ok - pflush sfc,#0,(a1) + rts + .dc $f011,$3000 ;ng - pflush sfc,#0 [,(a1)] + rts diff --git a/tests/src/movec.s b/tests/src/movec.s new file mode 100644 index 0000000..bb84a9e --- /dev/null +++ b/tests/src/movec.s @@ -0,0 +1,51 @@ +.cpu 68040 + movec d0,sfc + movec d0,dfc + movec d0,cacr + movec d0,tc + movec d0,itt0 + movec d0,itt1 + movec d0,dtt0 + movec d0,dtt1 +.cpu 68060 + movec d0,buscr + nop + movec d0,usp + movec d0,vbr +.cpu 68030 + movec d0,caar + movec d0,msp + movec d0,isp +.cpu 68040 + movec d0,mmusr + movec d0,urp + movec d0,srp +.cpu 68060 + movec d0,pcr + nop + + move d0,ccr + move ccr,d0 + move d0,sr + move sr,d0 + nop + + move a0,usp + move usp,a0 + nop + + + .dc $ff00 + +;illegal code + nop + rts + .dc $4e7b,$0fff + rts + .dc $4e7b,$0009 + rts + .dc $4e7b,$07ff + rts + .dc $4e7b,$0809 + rts + diff --git a/tests/src/pflush040.s b/tests/src/pflush040.s new file mode 100644 index 0000000..31b4f6f --- /dev/null +++ b/tests/src/pflush040.s @@ -0,0 +1,24 @@ +;dis -m68040 -R0 --> forced disassembly (binary mismatch when reassembled) +;dis -m68040 -R1 --> undefined instruction + +.cpu 68040 + + pflusha + rts + + .dc $f519 ;ng != 0 + rts + + .dc $f51c ;ng != 0 + rts + + pflushan + rts + + .dc $f511 ;ng != 0 + rts + + .dc $f514 ;ng != 0 + rts + +.end diff --git a/tests/src/registdata.s b/tests/src/registdata.s new file mode 100644 index 0000000..26e8432 --- /dev/null +++ b/tests/src/registdata.s @@ -0,0 +1,15 @@ +.cpu 68020 + move (2,zpc),d0 + move ([8,zpc]),d0 + nop + + move (foo,zpc),d0 + move ([bar,zpc]),d0 + nop + + .dc $ff00 + +foo: .dc $beef +bar: .dc.l $12345678 + +.end diff --git a/tests/src/reglist.s b/tests/src/reglist.s new file mode 100644 index 0000000..ca5b173 --- /dev/null +++ b/tests/src/reglist.s @@ -0,0 +1,60 @@ +;movem dreg,(a0) +i:=1 +.rept 255 + .dc $4890,i + i:=i+1 +.endm +.rept 16 + nop +.endm + +;movem areg,(a0) +i:=1 +.rept 255 + .dc $4890,i<<8 + i:=i+1 +.endm +.rept 16 + nop +.endm + + movem.l d7/a0,-(a0) + movem.l d7/a0,(a0) + movem.l d0-d7/a0-a7,-(sp) +.rept 16 + nop +.endm + +;fmovem fpreg,(a0) +i:=1 +.rept 255 + .dc $f210,$f000+i + i:=i+1 +.endm +.rept 16 + nop +.endm + +;fmovem fpreg,-(a0) +i:=1 +.rept 255 + .dc $f220,$e000+i + i:=i+1 +.endm +.rept 16 + nop +.endm + +;fmovem fpcr,(a0) +i:=1 +.rept 7 + .dc $f210,$a000+(i<<10) + i:=i+1 +.endm +.rept 16 + nop +.endm + + .dc $ff00 + + diff --git a/tests/src/relbdpc.s b/tests/src/relbdpc.s new file mode 100644 index 0000000..4b211c7 --- /dev/null +++ b/tests/src/relbdpc.s @@ -0,0 +1,37 @@ +;dis -m68020 +; +; {start} in comment is an address-dependent label with relocate data. + +.cpu 68020 + +start: + +;ok + move (start,zpc),d0 + rts + +;ng ... move ({start}.l,pc),d0 + .dc $41fb,$0170 + .dc.l start + rts + +;ok + lea ([start,zpc,d0.l]),a0 + rts + +;ng ... lea ([{start}.l,pc,d0.l]),a0 + .dc $41fb,$0931 + .dc.l start + rts + +;ok + lea ([start,zpc],d0.l),a0 + rts + +;ng ... lea ([{start}.l,pc],d0.l),a0 + .dc $41fb,$0935 + .dc.l start + rts + + .dc $ff00 + diff --git a/tests/src/reltbl.s b/tests/src/reltbl.s new file mode 100644 index 0000000..b131247 --- /dev/null +++ b/tests/src/reltbl.s @@ -0,0 +1,178 @@ + .dc $ff00 + +RELTBL: .macro +@@: + .dc 1f-@b +1: + rts +.endm + +MOVEw_JMPJSR:: + move (@f,pc,d0.w),d0 + jmp (@f,pc,d0.w) + RELTBL + +MOVEl_JMPJSR:: + move (@f,pc,d0.l),d0 + jmp (@f,pc,d0.w) + RELTBL + +;ng + move (@f,pc,d0.w),d0 + jmp (@f,pc,d1.w) ;d0 != d1 + RELTBL + +;ng + move (@b,pc,d0.w),d0 + jmp (@f,pc,d0.w) ;@b != @f + RELTBL + +LEA_MOVEw_JMPJSR:: + lea (@f,pc),a0 + move (a0,d0.w),d0 + jmp (a0,d0.w) + RELTBL + +LEA_MOVEl_JMPJSR:: + lea (@f,pc),a0 + move (a0,d0.l),d0 + jmp (a0,d0.w) + RELTBL + +;ng + lea (@f,pc),a0 + move (a0,d0.w),d0 + jmp (a0,d1.w) ;d0 != d1 + RELTBL + +;ng + lea (@f,pc),a0 + move (a1,d0.w),d0 ;a0 != a1 + jmp (a0,d0.w) + RELTBL + +;ng + lea (@f,pc),a0 + move (a0,d0.w),d0 + jmp (a1,d0.w) ;a0 != a1 + RELTBL + +LEA_MOVEw_PEA:: + lea (@f,pc),a0 + move (a0,d0.w),d0 + pea (a0,d0.w) + rts + RELTBL + +LEA_MOVEl_PEA:: + lea (@f,pc),a0 + move (a0,d0.l),d0 + pea (a0,d0.w) + rts + RELTBL + +;ng + lea (@f,pc),a0 + move (a0,d0.w),d0 + pea (a0,d1.w) ;d0 != d1 + rts + RELTBL + +;ng + lea (@f,pc),a0 + move (a1,d0.w),d0 ;a0 != a1 + pea (a0,d0.w) + rts + RELTBL + +;ng + lea (@f,pc),a0 + move (a0,d0.w),d0 + pea (a1,d0.w) ;a0 != a1 + rts + RELTBL + +LEA_ADDA:: + lea (@f,pc),a0 + adda (@f,pc,d0.w),a0 + rts + RELTBL + +;ng + lea (@f,pc),a0 + adda (@f,pc,d0.w),a1 ;a0 != a1 + rts + RELTBL + +;ng + lea (@b,pc),a0 + adda (@f,pc,d0.w),a0 ;@b != @f + rts + RELTBL + +MOVEw_LEA:: + move (@f,pc,d0.w),d0 + lea (@f,pc,d0.w),a0 + rts + RELTBL + +MOVEl_LEA:: + move (@f,pc,d0.l),d0 + lea (@f,pc,d0.w),a0 + rts + RELTBL + +;ng + move (@f,pc,d0.w),d0 + lea (@f,pc,d1.w),a0 ;d0 != d1 + rts + RELTBL + +;ng + move (@b,pc,d0.w),d0 + lea (@f,pc,d0.w),a0 ;@b != @f + rts + RELTBL + +MOVEw_PEA:: + move (@f,pc,d0.w),d0 + pea (@f,pc,d0.w) + rts + RELTBL + +MOVEl_PEA:: + move (@f,pc,d0.l),d0 + pea (@f,pc,d0.w) + rts + RELTBL + +;ng + move (@f,pc,d0.w),d0 + pea (@f,pc,d1.w) ;d0 != d1 + rts + RELTBL + +;ng + move (@b,pc,d0.w),d0 + pea (@f,pc,d0.w) ;@b != @f + rts + RELTBL + +OFFSET_0:: + move (@f,pc,d0.w),d0 + jmp (@f,pc,d0.w) +@@: + .dc 0 + .dc 1f-@b + .dc 0 +1: + rts + +IN_BSS:: +;ng + move (@f,pc,d0.w),d0 + jmp (@f,pc,d0.w) +.bss +@@: + .ds 1 + diff --git a/tests/src/scalefactor.s b/tests/src/scalefactor.s new file mode 100644 index 0000000..78861f7 --- /dev/null +++ b/tests/src/scalefactor.s @@ -0,0 +1,12 @@ +.cpu 68020 + move (a0,d0.w*1),d0 + move (a0,d0.w*2),d0 + move (a0,d0.w*4),d0 + move (a0,d0.w*8),d0 + nop + move (a0,d0.l*1),d0 + move (a0,d0.l*2),d0 + move (a0,d0.l*4),d0 + move (a0,d0.l*8),d0 + nop + .dc $ff00 diff --git a/tests/src/split_end.s b/tests/src/split_end.s new file mode 100644 index 0000000..5652549 --- /dev/null +++ b/tests/src/split_end.s @@ -0,0 +1,8 @@ +;dis -S1 + + move.l (@f,pc),d0 + nop + .dc $ff00 + +@@: .ds.b 1024-8 + diff --git a/tests/src/sym_oorange.s b/tests/src/sym_oorange.s new file mode 100644 index 0000000..cbe5c96 --- /dev/null +++ b/tests/src/sym_oorange.s @@ -0,0 +1,21 @@ +;dis -s2 + +XXX:: .equ 0 +AAA:: .equ aaa-$100 +BBB:: .equ bbb-$100 +YYY:: .equ $12345678 +CCC:: .equ ccc+$100 +DDD:: .equ ddd+$100 +ZZZ:: .equ $ffffffff + +aaa:: + nop +bbb:: + lea (AAA,pc),a0 + lea (BBB,pc),a0 + lea (CCC,pc),a0 + lea (DDD,pc),a0 +ccc:: + .dc $ff00 +ddd:: + diff --git a/tests/src/symbol.s b/tests/src/symbol.s new file mode 100644 index 0000000..c58a240 --- /dev/null +++ b/tests/src/symbol.s @@ -0,0 +1,21 @@ +.text +textStart:: + nop + rts +textEnd:: + +.data +dataStart:: + .dc.l $12345678 +dataEnd:: + +.bss +bssStart:: + .ds.b 4 +bssEnd:: + +.stack +stackStart:: + .ds.b 1024 +stackEnd:: + diff --git a/tests/src/tab_depadrs.lab b/tests/src/tab_depadrs.lab new file mode 100644 index 0000000..a57c5ef --- /dev/null +++ b/tests/src/tab_depadrs.lab @@ -0,0 +1,9 @@ +********************************************* +* +* Label file for bin/tab_depadrs.x +* +********************************************* +000000 P +000006 DWF +00001e P +000022 DU diff --git a/tests/src/tab_depadrs.s b/tests/src/tab_depadrs.s new file mode 100644 index 0000000..b278417 --- /dev/null +++ b/tests/src/tab_depadrs.s @@ -0,0 +1,17 @@ + lea (table,pc),a0 + .dc $ff00 + +table: + .dc 1 + .dc 0 + .dc.l table + + .dc 2 + .dc 0 + .dc.l table + + clr (table) + rts + + moveq #0,d0 + rts diff --git a/tests/src/tab_depadrs.tab b/tests/src/tab_depadrs.tab new file mode 100644 index 0000000..2e5919d --- /dev/null +++ b/tests/src/tab_depadrs.tab @@ -0,0 +1,5 @@ +6 + dc.w + dc.w + dc.l +end[] diff --git a/tests/src/tab_even.lab b/tests/src/tab_even.lab new file mode 100644 index 0000000..873d0e2 --- /dev/null +++ b/tests/src/tab_even.lab @@ -0,0 +1,8 @@ +********************************************* +* +* Label file for bin/tab_even.x +* +********************************************* +000000 P +000006 DBF +000010 DU diff --git a/tests/src/tab_even.s b/tests/src/tab_even.s new file mode 100644 index 0000000..cfa8786 --- /dev/null +++ b/tests/src/tab_even.s @@ -0,0 +1,15 @@ + lea (table,pc),a0 + .dc $ff00 + +table: + .dc.b 1,'a' + .even ;no align + + .dc.b 2,'ab' + .even + +dummy: + .dc.b 2,'xy' + .dc.b $ff + +.end diff --git a/tests/src/tab_even.tab b/tests/src/tab_even.tab new file mode 100644 index 0000000..8bcdf55 --- /dev/null +++ b/tests/src/tab_even.tab @@ -0,0 +1,5 @@ +6 + .lascii + .even + .cr +end[] diff --git a/tests/src/tab_stuck1.lab b/tests/src/tab_stuck1.lab new file mode 100644 index 0000000..fc20cb2 --- /dev/null +++ b/tests/src/tab_stuck1.lab @@ -0,0 +1,8 @@ +********************************************* +* +* Label file for bin/tab_stuck1.x +* +********************************************* +000000 P +000006 DU +00000a DU diff --git a/tests/src/tab_stuck1.s b/tests/src/tab_stuck1.s new file mode 100644 index 0000000..3ceff0a --- /dev/null +++ b/tests/src/tab_stuck1.s @@ -0,0 +1,5 @@ + lea (table,pc),a0 + .dc $ff00 + +table: + .dc.l table diff --git a/tests/src/tab_stuck1.tab b/tests/src/tab_stuck1.tab new file mode 100644 index 0000000..abf353c --- /dev/null +++ b/tests/src/tab_stuck1.tab @@ -0,0 +1,3 @@ +6 + .dc.b[4] +end[] diff --git a/tests/src/tab_stuck2.lab b/tests/src/tab_stuck2.lab new file mode 100644 index 0000000..b0ab0ce --- /dev/null +++ b/tests/src/tab_stuck2.lab @@ -0,0 +1,8 @@ +********************************************* +* +* Label file for bin/tab_stuck2.x +* +********************************************* +000000 P +000006 DUF +000008 DU diff --git a/tests/src/tab_stuck2.s b/tests/src/tab_stuck2.s new file mode 100644 index 0000000..9a42f21 --- /dev/null +++ b/tests/src/tab_stuck2.s @@ -0,0 +1,5 @@ + lea (table,pc),a0 + .dc $ff00 + +table: + .dc 0 diff --git a/tests/src/tab_stuck2.tab b/tests/src/tab_stuck2.tab new file mode 100644 index 0000000..52c7dec --- /dev/null +++ b/tests/src/tab_stuck2.tab @@ -0,0 +1,3 @@ +6 + even +end[]