Mercurial > hg > forks > dxa
changeset 0:4410c9c7750d
Initial import.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 24 Feb 2015 18:53:52 +0200 |
parents | |
children | cfcae2ef1c2b |
files | INSTALL Makefile dump.c dxa.1 label.c main.c opcodes.h options.h proto.h scan.c structures.h table.c vector.c |
diffstat | 13 files changed, 3750 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/INSTALL Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,17 @@ +Installation for dxa +-------------------- + +dxa should build out of the box with any even vaguely recent version of gcc. +You might need to do some tweakage for non-Unix systems or cc. I have tested +it on AIX, NetBSD and Mac OS X/Darwin. -- Cameron Kaiser + +1. Uncomment LONG_OPTIONS in options.h if you have getopts_long() and want + long options (--example). This is purely optional. +2. Edit the Makefile and make sure your compiler and CFLAGS make sense. The + default works for most people. +3. "make" +4. Documentation in man format is in dxa.1. + +Please keep in mind this is still considered "alpha" software and there may +be bugs, which is why it is not part of the official xa distribution yet. +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,34 @@ +# dxa makefile +# marko's originally, hacked up by cameron + +TARGET = dxa +OBJECTS = scan.o vector.o dump.o table.o label.o main.o +VERSION = 0.1.3 + +# choose the compiler and flags + +CC = gcc +CFLAGS = -Wall -Wmissing-prototypes -O6 +#CFLAGS = -Wall -Wmissing-prototypes -ggdb + +#CC = cc +#CFLAGS = -O +#CFLAGS = -O2 + +all: $(TARGET) + +$(TARGET) : $(OBJECTS) + $(CC) $(LDFLAGS) -o $@ $(OBJECTS) + +scan.o : structures.h proto.h options.h opcodes.h +vector.o : structures.h proto.h options.h +dump.o : structures.h proto.h options.h opcodes.h +table.o : structures.h proto.h +label.o : structures.h proto.h +main.o : structures.h proto.h options.h opcodes.h + +clean: + rm -f $(OBJECTS) $(TARGET) core + +dist: clean + cd ..;tar cvf dxa-$(VERSION).tar dxa-$(VERSION);gzip dxa-$(VERSION).tar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dump.c Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,324 @@ +/*\ + * dxa v0.1.3 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * Changes for dxa (C) 2004, 2006 Cameron Kaiser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Marko does not maintain dxa, so questions specific to dxa should be + * sent to me at ckaiser@floodgap.com . Otherwise, + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +#define _DUMP_C_ +#include <stdio.h> +#include <stdlib.h> + +#include "proto.h" +#include "options.h" +#include "opcodes.h" + +#ifndef __STDC__ +void +Dump () +#else +void Dump (void) +#endif +{ + ADDR_T address, addr; + unsigned counter, size, maxwidth; + char *lineprefix, *lineinfix; + table *entry; + opcodes *instr; + + if (fVerbose) + fprintf (stderr, "%s: Dumping the source code.\n", prog); + + /* determine the maximum amount of bytes dumped per line */ + + maxwidth = listwidth < 2 ? 2 : listwidth; + + for (counter = 0; counter < 256; counter++) + if (maxwidth < sizes[opset[counter].admode]) + maxwidth = sizes[opset[counter].admode]; + + /* create prefix string for lines without address information */ + switch (Options & M_ADDRESSES) { + case O_ADR_ADRPFIX: + counter = 5; + break; + + case O_ADR_ADR_DMP: + counter = 5 + 3 * maxwidth; + break; + + default: + counter = 0; + } + + lineprefix = malloc (counter + 1); + + if (counter >= 5) { + lineinfix = lineprefix + 5; + + for (lineprefix[counter] = 0; counter--; lineprefix[counter] = ' '); + } + else { + *lineprefix = 0; + lineinfix = lineprefix; + } + + /* print the label definitions */ + + for (address = EndAddress < StartAddress ? EndAddress : 0; + address != StartAddress; address++) + if (IsLabeled (address)) + fprintf (stdout, "%s%s = $%x\n", lineprefix, Label (address, abso), + address); + + if (EndAddress >= StartAddress) + for (address = EndAddress; address; address++) + if (IsLabeled (address)) + fprintf (stdout, "%s%s = $%x\n", lineprefix, Label (address, abso), + address); + + /* dump the program */ + + if(Options & B_SA_WORD) + fprintf(stdout, "%s\t.word $%04x", lineprefix, StartAddress); + fprintf (stdout, "\n%s\t* = $%04x\n\n", lineprefix, StartAddress); + + for (address = StartAddress; (ADDR_T)(address - StartAddress) < + (ADDR_T)(EndAddress - StartAddress); address += size) + if (GetMemType (address) == MEM_INSTRUCTION) { + if (IsLabeled (address)) { + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x %s%s:\n", address, + lineinfix, Label (address, abso)); + else { + fprintf (stdout, "%s", Label (address, abso)); + if (Options & B_LABCOL) + fprintf(stdout, ":\n"); + } + } + + instr = &opset[Memory[address]]; + size = sizes[instr->admode]; + + for (counter = 1; counter < size; counter++) { + if (IsLabeled (address + counter)) { + if (Options & M_ADDRESSES) + fprintf (stdout, "\t%04x %s%s = * + %u\n", + (ADDR_T)(address + counter), + lineinfix, Label (address + counter, abso), counter); + else + fprintf (stdout, "\t%s = * + %u\n", + Label (address + counter, abso), counter); + } + + if (FindNextEntry (NULL, address, ~0, WRN_INSTR_WRITTEN_TO)) + fprintf (stdout, "%s; Instruction opcode accessed.\n", lineprefix); + + entry = NULL; + + while ((entry = FindNextEntry (entry, address + counter, 0, 0))) + switch (entry->type) { + case WRN_PARAM_WRITTEN_TO: + fprintf (stdout, "%s; Instruction parameter accessed.\n", + lineprefix); + break; + + case WRN_PARAM_JUMPED_TO: + fprintf (stdout, "%s; Instruction parameter jumped to.\n", + lineprefix); + break; + } + } + + switch (Options & M_ADDRESSES) { + case O_ADR_ADRPFIX: + fprintf (stdout, "%04x ", address); + break; + + case O_ADR_ADR_DMP: + fprintf (stdout, "%04x ", address); + + for (counter = 0; counter < size; counter++) + fprintf (stdout, "%02x ", Memory[(ADDR_T)(address + counter)]); + + fputs (lineinfix + 3 * counter, stdout); + } + + fputs ("\t", stdout); + + switch (instr->admode) { + case accu: + case impl: + fprintf (stdout, "%s%s\n", mne[instr->mnemonic], + postfix[instr->admode]); + break; + case imm: + addr = Memory[(ADDR_T)(address + 1)]; + fprintf (stdout, "%s #$%02x\n", mne[instr->mnemonic], addr); + break; + case abso: + case absx: + case absy: + case iabs: + case iabsx: + addr = Memory[(ADDR_T)(address + 1)] | + (Memory[(ADDR_T)(address + 2)] << 8); + /* Fix to ensure 16-bit addresses to zero-page are maintained as 16-bit */ + fprintf (stdout, "%s %s%s%s%s\n", mne[instr->mnemonic], + prefix[instr->admode], + ((addr < 256 && instr->mnemonic != S_JMP && + instr->mnemonic != S_JSR) ? "!" : ""), + Label (addr, abso),postfix[instr->admode]); + break; + case zp: + case zpx: + case zpy: + case ind: + case indx: + case indy: + addr = Memory[(ADDR_T)(address + 1)]; + fprintf (stdout, "%s %s%s%s\n", mne[instr->mnemonic], + prefix[instr->admode], Label (addr, zp), + postfix[instr->admode]); + break; + case rel: + addr = (int)(char)Memory[(ADDR_T)(address + 1)]; + /* addr -= (addr > 127) ? 256 : 0; BUGFIX: sign extend already done */ +/*fprintf(stderr, "%d %d %d\n", address, size, addr);*/ + addr += address + size; + fprintf (stdout, "%s %s%s%s\n", mne[instr->mnemonic], + prefix[instr->admode], Label (addr, abso), + postfix[instr->admode]); + break; + case zrel: /* BBR0, etc. 65C02 instructions */ + addr = (int)(char)Memory[(ADDR_T)(address + 2)]; + /* addr -= (addr > 127) ? 256 : 0; BUGFIX: sign extend already done */ + addr += address + size; + fprintf (stdout, "%s %s, %s\n", mne[instr->mnemonic], + Label (Memory[(ADDR_T)(address + 1)], abso), + Label (addr, abso)); + break; + } + } + else if (address != (addr = WordTableEnd (address))) { /* word table */ + for (size = (ADDR_T)(addr - address); size; + address += (counter = size > (maxwidth & ~1) ? + (maxwidth & ~1) : size), size -= counter) { + if (IsLabeled (address)) { + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x %s%s:\n", address, lineinfix, + Label (address, abso)); + else + fprintf (stdout, "%s ", Label (address, abso)); + } + for (counter = size > (maxwidth & ~1) ? (maxwidth & ~1) : size, + addr = address + 1; --counter; addr++) + if (IsLabeled (addr)) { + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x %s%s = * + %u\n", addr, lineinfix, + Label (addr, abso), (ADDR_T)(addr - address)); + else + fprintf (stdout, "\t%s = * + %u\n", Label (addr, abso), + (ADDR_T)(addr - address)); + } + + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x ", address); + + if ((Options & M_ADDRESSES) == O_ADR_ADR_DMP) { + for (counter = size > (maxwidth & ~1) ? (maxwidth & ~1) : size, + addr = address; counter--; addr++) { + fprintf (stdout, "%02x ", Memory[addr]); + } + fputs (lineinfix + 3 * (size > (maxwidth & ~1) ? + (maxwidth & ~1) : size), stdout); + } + + fprintf (stdout, " .word %s", + Label (Memory[address] | + (Memory[(ADDR_T)(address + 1)] << 8), abso)); + + for (counter = size > (maxwidth & ~1) ? (maxwidth & ~1) : size, + addr = address + 2; counter -= 2; addr += 2) + fprintf (stdout, ",%s", + Label (Memory[addr] | (Memory[(ADDR_T)(addr + 1)] << 8), + abso)); + + + fputc ('\n', stdout); + } + } + else { /* data block */ + for (size = 1; size < maxwidth; size++) { /* determine the size */ + addr = address + size; + + if (GetMemType (addr) == MEM_INSTRUCTION || + addr != WordTableEnd (addr)) + break; + } + + if (IsLabeled (address)) { + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x %s%s:\n", address, lineinfix, + Label (address, abso)); + else + fprintf (stdout, "%s ", Label (address, abso)); + } + + for (counter = size, addr = address + 1; --counter; addr++) + if (IsLabeled (addr)) { + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x %s%s = * + %u\n", addr, lineinfix, + Label (addr, abso), (ADDR_T)(addr - address)); + else + fprintf (stdout, "\t%s = * + %u\n", Label (addr, abso), + (ADDR_T)(addr - address)); + } + + if (Options & M_ADDRESSES) + fprintf (stdout, "%04x ", address); + + if ((Options & M_ADDRESSES) == O_ADR_ADR_DMP) { + for (counter = size, addr = address; counter--; addr++) + fprintf (stdout, "%02x ", Memory[addr]); + + fputs (lineinfix + 3 * size, stdout); + } + + fprintf (stdout, "\t.byt $%02x", Memory[address]); + + for (counter = size, addr = address + 1; --counter; addr++) + if (addr < EndAddress) /* problems with this overflowing */ + fprintf (stdout, ",$%02x", Memory[addr]); + + fputc ('\n', stdout); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dxa.1 Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,402 @@ +.TH DXA "1" "31 January 2007" + +.SH NAME +dxa \- 6502/R65C02 disassembler + +.SH SYNOPSIS +.B dxa +[\fIOPTION\fR]... \fIFILE\fR + +.SH DESCRIPTION +.B dxa +is the semi-official disassembler option for the +.BR xa (1) +package, a weakly patched version of Marko Mäkelä's +.B d65 +disassembler that generates output similar to the de facto coding +conventions used for +.BR xa (1). +The package is designed to intelligently(?) scan arbitrary code and (with +hints) can identify the difference between data and valid machine code, +generating a sane looking, "perfect" disassembly with data and code portions. +.LP +Perfect, in this case, means that you can take what +.B dxa +spits out and feed it right back into +.BR xa (1), +and get the exact same object file you started with, even if sometimes +.B dxa +can't identify everything correctly. With a few extra options, you can tease +and twist the output to generate something not quite so parseable, or even +more like true assembler source. +.SH OPTIONS +For historical and compatibility reasons, the long options (--) only exist +if +.B dxa +were compiled with LONG_OPTIONS enabled in options.h. +.TP +.B \--datablock xxxx-yyyy +.TP +.B \-b xxxx-yyyy +Defines the memory range xxxx to yyyy (hexadecimal, inclusive) to be a data +block. The memory range can be further specified: +.RS +.IP * +If the range is preceded by ! (an exclamation point), such as +.BR !c000-cfff , +then it is +further defined to be a data block with no vectors in it either. +.IP * +If the range is preceded by ? (a question mark), then it is further +defined to be a data block that is completely unused and therefore +no valid routine may contain instructions whose parameter lie in this +range. Useful for providing enhanced protection against misinterpreting +data to be program code, but be careful, or some code may be listed as +data. For instance, the Commodore 64 firmware uses the base address $CFFF +when initializing the video chip, and the BASIC interpreter uses the +addresses $9FEA and $9FEB while loading the instruction pointers. +In addition to this, there are a number of BIT instructions used for +skipping the next instruction. Thus, you must allow addresses like $1A9, +$2A9 and so on. +.RE +.TP +.B \--datablocks filename +.TP +.B \-B filename +Reads data blocks from file +.B filename +as if they had been specified on the command +line, one per line (such as xxxx-yyyy, ?xxxx-yyyy, etc.). +.TP +.B \--labels filename +.TP +.B \-l filename +Causes label names to be read from file +.BR filename . +This file format is the same as the labelfile/symbol table file generated +by +.BR xa (1) +with the +.B \-l +option. The +.B \-l +was chosen on purpose for consistency with +.BR xa (1). +.TP +.B \--routine xxxx +.TP +.B \-r xxxx +Specifies an address (in hexadecimal) that is declared to be a valid routine. +.B It is strongly recommended +that you specify the initial execution address as a routine. +For example, for a Commodore 64 binary with a +.B SYS 2064 +header, add +.B \-r0810 +so that disassembly starts at that location. This may have interactions with +datablock detection +.RB ( \-d ). +.TP +.B \--routines filename +.TP +.B \-R filename +Causes a list of routines to be read from file +.BR filename , +one per line as if they had been specified on the command line. +.TP +.B \--addresses option +.TP +.B \-a option +Determines if and what kind of address information should be dumped with the +disassembly, if any. Note that this may make your output no longer intelligible +to +.BR xa (1). +The valid options are: +.RS +.TP +.B disabled +Dump source only with no address information. This is the default. +.TP +.B enabled +Write the current address at the beginning of each line. +.TP +.B dump +Write the current address at the beginning of each line, along with a hexdump +of the bytes for which the statement was generated. +.RE +.TP +.B \--colon-newline +.TP +.B \-N +.TP +.B \--no-colon-newline +.TP +.B \-n +A purely cosmetic option to determine how labels are emitted. Many people, +including myself, prefer a listing where the label is given, then a tab, +then the code +.RB ( \-n ). +Since this is +.I my +preference, it's the default. On the other hand, there are also many who +prefer to have the label demarcated by a colon and a newline, and the code +beginning indented on the next line. This is the way +.B d65 +used to do it, and is still supported with +.BR \-N . +.TP +.B \--processor option +.TP +.B \-p option +Specify the instruction set. Note that specifying an instruction set that +permits and disassembles illegal and/or undocumented +NMOS opcodes may make your output unintelligible to +.BR xa (1). +Only one may be specified. The valid options are: +.RS +.TP +.B standard-nmos6502 +Only official opcodes will be recognized. This is the default. +.TP +.B r65c02 +Opcodes specific to the Rockwell 65C02 (R65C02) will also be allowed. +.TP +.B all-nmos6502 +Allows all 256 NMOS opcodes to be disassembled, whether documented or +undocumented. +Note that instructions generated by this mode are not guaranteed to work on +all NMOS 6502s. +.TP +.B rational-nmos6502 +Only allows "rational" undocumented instructions. This excludes ANE, SHA, +SHS, SHY, SHX, LXA and LAXS. This is a judgment call. +.TP +.B useful-nmos6502 +Only allows "useful" undocumented instructions. This excludes ANE, SHA, +SHS, SHY, SHX, LXA, LAXS, NOOP and STP. This is a judgment call. +.TP +.B traditional-nmos6502 +Only allows the most widely accepted undocumented instructions based on +combinations of ALU and RMW operations. This excludes ANE, SHA, SHS, SHY, +SHX, LXA, LAXS, NOOP, STP, ARR, ASR, ANC, SBX and USBC. +This is a judgment call. +.RE +.TP +.B \--get-sa +.TP +.B \-G +.TP +.B \--no-get-sa xxxx +.TP +.B \-g xxxx +Enables or disables automatic starting address detection. If enabled (the +default), +.B dxa +looks at the first two bytes as a 16-bit word in 6502 little-endian format +and considers that to be the starting address for the object, discarding them +without further interpretation. This is very useful for Commodore computers in +particular. If your binary does not have a starting address, you must +specify one using +.B \-g +or +.B \--no-get-sa +followed by a hexadecimal address. The starting address will then be encoded +into the output using +.BR "* =" . +.TP +.B \--no-word-sa +.TP +.B \-q +.TP +.B \--word-sa +.TP +.B \-Q +Only relevant if automatic starting address detection is enabled. If so, +the default is to also emit the starting address as a +.B \&.word +pseudo-op before the starting address indicated with +.B * = +so that it will be regenerated on re-assembly +.RB ( \-Q ). +Otherwise, if this option is disabled, the starting address word will not be +re-emitted and +will need to be tacked back on if the target requires it. If you specify an +address with +.BR \-g , +then that address will be used here too. +.TP +.B \--verbose +.TP +.B \-v +Enables verbose output, which may or may not be useful in the same way that +Schroedinger's Cat may or may not be dead. +.TP +.B \--help +.TP +.B \-? +.TP +.B \-V +A quick summary of options. +.LP +The following options control how program code is scanned and determined +to be a valid (or invalid) portion of a putative routine. +.TP +.B \--datablock-detection option +.TP +.B \-d option +This controls how the program automatically detects data blocks for addresses +where no previous hints are specified. Only one method may be specified. +The valid options are: +.RS +.TP +.B poor +As much as the object as possible will be listed as program code, even if +there are illegal instructions present. This is the default. +.TP +.B strict +Assumes that all declared routines call and execute only valid instructions. If +any portion of code declared as a routine leads to an address block containing +illegal opcodes, a consistency error will occur and disassembly will stop. +.TP +.B skip-scanning +Program addresses that are not referenced by any routine will not be scanned +for valid routines (thus data a priori). +.RE +.TP +.B \--no-external-labels +.TP +.B \-e +.TP +.B \--external-labels +.TP +.B \-E +Controls whether labels should be generated for addresses outside of the +program itself. The default is not to (i.e., leave the addresses absolute). +.TP +.B \--address-tables option +.TP +.B \-t option +Controls detection of address tables/dispatch tables. The following options +are available: +.RS +.TP +.B ignore +Don't attempt to detect address tables. +.TP +.B detect-all +Address tables referencing any label will be detected. +.TP +.B detect-internal +Address tables with labels whose addresses lie within the program's address +range will be detected. This is the default. +.RE +.TP +.B \--no-suspect-jsr +.TP +.B \-j +.TP +.B \--suspect-jsr +.TP +.B \-J +These options indicate whether JSRs are always expected to return to the +following instruction or not. This will affect how routines are parsed. For +example, the Commodore 128 KERNAL has a routine called PRIMM that prints a +null-terminated string directly following the JSR instruction, returning after +the null byte. In this case, +.B \-J +should be specified to alert the disassembler that this is possible. The +default is to expect "normal" JSRs (i.e., +.BR \-j ). +.TP +.B \--no-one-byte-routines +.TP +.B \-o +.TP +.B \--one-byte-routines +.TP +.B \-O +These options permit or inhibit a single RTS, RTI or BRK instruction (or STP +if enabled by the instruction set), or a conditional branch, from being +automatically identified as a routine. The default is to inhibit this; specific +cases may be selectively overridden with the +.B \-r +option. +.TP +.B \--no-stupid-jumps +.TP +.B \-m +.TP +.B \--stupid-jumps +.TP +.B \-M +These options consider jumps or branches to the current address (such as +JMP *, BCC *) to be invalid or valid code depending on which is specified. +Note that BVC * is always accepted as the V flag can sometimes be toggled +by an external hardware signal. The default is to consider them +invalid otherwise. +.TP +.B \--no-allow-brk +.TP +.B \-w +.TP +.B \--allow-brk +.TP +.B \-W +These options control if BRK (or STP if enabled by the instruction set) should +be treated as a valid exit from a routine, just like RTS or RTI. The default +is not to do so. +.TP +.B \--no-suspect-branches +.TP +.B \-c +.TP +.B \--suspect-branches +.TP +.B \-C +These options are rarely needed, but account for the case where a program may +intentionally obfuscate its code using branches with unusual destination +addresses like LDA #2:BEQ *-1. In the default case, this would be considered +to be invalid and not treated as a routine +.RB ( \-c ); +if +.B \-C +is specified, it would be accepted as valid. +.SH BUGS/TO-DO +There are probably quite a few bugs yet to be found. +.LP +65816 opcodes are not (yet) supported. +.LP +The disassembler can easily be confused by the common idiom of tacking on +BASIC text to call an appended ML routine. There probably should be a special +case option for this. One workaround is to use the +.B \--datablock +option and specify the range as unused (such as in the case of +.B 10 SYS2061 +(Commodore), giving +.B \-b ?0801-080c +to ignore that range as data). +.LP +There are a few options Marko created that aren't hooked up to anything (and +are not documented here on purpose). I might finish these later. + +.SH "SEE ALSO" +.BR xa (1), +.BR file65 (1), +.BR ldo65 (1), +.BR printcbm (1), +.BR reloc65 (1), +.BR uncpk (1) + +.SH AUTHOR +This manual page was written by Cameron Kaiser <ckaiser@floodgap.com>. +.B dxa +is based on +.B d65 +0.2.1 by Marko Mäkelä. +Original package (C)1993, 1994, 2000 Marko Mäkelä. Additional changes +(C)2006 Cameron Kaiser. +.B dxa +is maintained independently. + +.SHWEBSITE +http://www.floodgap.com/retrotech/xa/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/label.c Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,152 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +#define _LABEL_C_ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "proto.h" +#include "options.h" +#include "opcodes.h" + +label *labeltable; +char defaultlabel[5]; +unsigned numLabels = 0; + +#ifndef __STDC__ +void +AddLabel (address, name) + ADDR_T address; + char *name; +#else +void AddLabel (ADDR_T address, char *name) +#endif +{ + label *entry; + char *buffer; + + if (!((buffer = malloc (strlen (name))))) + return; + + entry = numLabels ? + realloc (labeltable, (numLabels + 1) * sizeof *entry) : + malloc (sizeof *entry); + + if (!entry) return; + + labeltable = entry; + entry = &labeltable[numLabels++]; + + entry->address = address; + entry->name = buffer; + while ((*buffer++ = *name++)); +} + +#ifndef __STDC__ +char * +Label (address, admode) + ADDR_T address; + int admode; +#else +char *Label (ADDR_T address, int admode) +#endif +{ + label *entry; + + if (!IsLabeled (address)) { + + /* dirty kludge to allow zero page stuff to still work. this sometimes + guesses wrong */ + if (admode == zp) + sprintf (defaultlabel, "$%02x", address); + else + sprintf (defaultlabel, "$%04x", address); + return defaultlabel; + } + + for (entry = &labeltable[numLabels]; entry-- > labeltable;) + if (entry->address == address) + return entry->name; + + sprintf (defaultlabel, "l%x", address); + + return defaultlabel; +} + +#ifndef __STDC__ +void +Collect () +#else +void Collect (void) +#endif +{ + unsigned counter = 0; + table *entry = NULL, *entry2; + label *labels; + + if (fVerbose) + fprintf (stderr, "%s: collecting garbage.\n", prog); + + while ((entry = entry2 = FindNextEntryType (entry, 0, 0))) { + counter++; + + PutLabel (entry->address); + PutLowByte (entry->address); + PutHighByte (entry->address); + + while ((entry2 = FindNextEntry (entry2, entry->address, + ~0, entry->type))) + DeleteEntry (entry2); /* remove duplicate warnings */ + } + + if ((entry = malloc (counter * sizeof *entry))) { /* compact the table */ + entrycount = counter; + + for (entry2 = scantable; counter; entry2++) { + if (!entry2->type) continue; + + memcpy (&entry[--counter], entry2, sizeof *entry); + } + + free (scantable); + scantable = entry; + } + + for (labels = &labeltable[numLabels]; labels-- > labeltable;) + if ((ADDR_T)(labels->address - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) { + PutLabel (labels->address); + PutLowByte (labels->address); + PutHighByte (labels->address); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.c Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,540 @@ +/*\ + * dxa v0.1.3 -- symbolic 65xx disassembler + * + * Based on d65 Copyright (C) 1993, 1994 Marko M\"akel\"a + * Changes for dxa (C) 2005, 2006 Cameron Kaiser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Marko does not maintain dxa, so questions specific to dxa should be + * sent to me at ckaiser@floodgap.com . Otherwise, + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +#define _MAIN_C_ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef __GNUC__ +#include <unistd.h> +#endif +#ifdef LONG_OPTIONS +#include <getopt.h> +#endif /* __GNUC__ */ +#include "proto.h" +#include "options.h" +#include "opcodes.h" + +#ifndef __STDC__ +int +main (argc, argv) + int argc; + char **argv; +#else +int main (int argc, char **argv) +#endif +{ + FILE *file; + unsigned address1, address2; +#ifdef LONG_OPTIONS + int option_index; +#endif + int fFinished = FALSE, fType; + char labelname[MAXLINE], strig[MAXLINE], *scanner; + + extern char *optarg; + extern int optind; + +#ifdef LONG_OPTIONS + static struct option cmd_options [] = { + { "datablock", 1, 0, 'b' }, /* an address range to be marked + as a data block */ + { "datablocks", 1, 0, 'B' },/* a file containing the address ranges + to be marked as data blocks */ + { "labels", 1, 0, 'l' }, /* a file containing labels to be translated + in the output phase */ + { "routine", 1, 0, 'r' }, /* an address of a routine */ + { "routines", 1, 0, 'R' }, /* a file containing the addresses */ + + { "listing-width", 1, 0, 'L' }, + /* maximum number of dumped bytes per line */ + { "addresses", 1, 0, 'a' }, /* dumping addresses in the output phase */ + { "datablock-detection", 1, 0, 'd' }, + /* data block detection options */ + { "processor", 1, 0, 'p' }, /* instruction set */ + { "no-colon-newline", 0, 0, 'n' }, + { "colon-newline", 0, 0, 'N' }, + { "no-external-labels", 0, 0, 'e' }, + { "external-labels", 0, 0, 'E' }, + { "address-tables", 0, 0, 't' }, + { "no-address-statements", 0, 0, 's' }, + { "address-statements", 0, 0, 'S' }, + { "suspect-jsr", 0, 0, 'J' }, + { "no-suspect-jsr", 0, 0, 'j' }, + { "one-byte-routines", 0, 0, 'O' }, + { "no-one-byte-routines", 0, 0, 'o' }, + { "stupid-jumps", 0, 0, 'M' }, + { "no-stupid-jumps", 0, 0, 'm' }, + { "allow-brk", 0, 0, 'W' }, + { "no-allow-brk", 0, 0, 'w' }, + { "suspect-branches", 0, 0, 'C' }, + { "no-suspect-branches", 0, 0, 'c' }, + { "cross-reference", 0, 0, 'X' }, + { "no-cross-reference", 0, 0, 'x' }, + { "verbose", 0, 0, 'v' }, + { "help", 0, 0, '?' }, + { "word-sa", 0, 0, 'Q' }, + { "no-word-sa", 0, 0, 'q' }, + { "get-sa", 0, 0, 'G' }, + { "no-get-sa", 0, 0, 'g' }, + { NULL, 0, 0, 0 } + }; +#endif /* LONG_OPTIONS */ + + opset = standard_nmos6502; + + StartAddress = 0; + Options = O_ADR_ADR_DMP | B_LBL_ALWAYS | O_TBL_NOEXT | + B_STM_DETECT | B_STK_BALANCE | B_RSC_STRICT | O_DBL_STRICT | + B_JMP_STRICT | B_BRK_REJECT; + + /* dxa defaults */ + Options = (Options & ~M_ADDRESSES) | O_ADR_NOTHING; + Options = (Options & ~M_DATA_BLOCKS) | O_DBL_IGNORE; + Options &= ~B_LBL_ALWAYS; + Options &= ~B_LABCOL; + Options |= B_SA_WORD; + Options |= B_GET_SA; + + for (address1 = sizeof MemType / sizeof *MemType; address1--; + MemType[address1] = 0); + + for (address1 = sizeof MemFlag / sizeof *MemFlag; address1--; + MemFlag[address1] = MemLabel[address1] = 0); + + for (address1 = sizeof LowByte / sizeof *LowByte; address1--; + HighByte[address1] = LowByte[address1] = 0); + + for (prog = *argv; *prog; prog++); + for (;prog > *argv; prog--) + if (*prog == '/') { + prog++; + break; + } + + while (!fFinished) +#ifdef LONG_OPTIONS + switch (getopt_long (argc, argv, + "?b:B:L:r:R:h:l:a:d:p:g:t:eEnNsSjJoOcCmMvVwWxXqQG", + cmd_options, &option_index)) { +#else + switch (getopt (argc, argv, + "?b:B:L:r:R:h:l:a:d:p:g:t:eEnNsSjJoOcCmMvVwWxXqQG")){ +#endif /* LONG_OPTIONS */ + case -1: + case ':': + fFinished = TRUE; + break; + + case '?': + case 'V': + goto Usage; + + case 'b': + if (*optarg == '!') { + fType = MEM_PARAMETER; + optarg++; + } + else if (*optarg == '?') { + fType = MEM_UNPROCESSED; + optarg++; + } + else + fType = MEM_DATA; + + if (!sscanf (optarg, "%X-%X", &address1, &address2) || + address1 > 65535 || address2 > 65535) { + fprintf (stderr, "%s: Error in data block address range `%s'.\n\n", + prog, optarg); + goto Usage; + } + + for (; (ADDR_T)address1 != address2; address1++) { + SetMemType (address1, fType); + SetMemFlag (address1); + } + + SetMemType (address1, fType); + SetMemFlag (address1); + + break; + + case 'B': + if (!((file = fopen (optarg, "rt")))) { + fprintf (stderr, "%s: Could not open %s.\n", prog, optarg); + return 2; + } + + while (!feof (file)) { + if ('!' == (fType = fgetc (file))) + fType = MEM_PARAMETER; + else if ('?' == fType) + fType = MEM_UNPROCESSED; + else { + ungetc (fType, file); + fType = MEM_DATA; + } + + if (!fscanf (file, "%X-%X\n", &address1, &address2) || + address1 > 65535 || address2 > 65535) { + fprintf (stderr, "%s: Error in data block address file %s.\n", + prog, optarg); + + fclose (file); + return 3; + } + + for (; (ADDR_T)address1 != address2; address1++) { + SetMemType (address1, fType); + SetMemFlag (address1); + } + + SetMemType (address1, fType); + SetMemFlag (address1); + } + + fclose (file); + break; + + case 'r': + if (!sscanf (optarg, "%X", &address1) || address1 > 65535) { + fprintf (stderr, "%s: Error in routine address `%s'.\n\n", + prog, optarg); + goto Usage; + } + + AddEntry (address1, address1, RTN_SURE); + break; + + case 'R': + if (!((file = fopen (optarg, "rt")))) { + fprintf (stderr, "%s: Could not open %s.\n", prog, optarg); + return 2; + } + + while (!feof (file)) { + if (!fscanf (file, "%X\n", &address1) || address1 > 65535) { + fprintf (stderr, "%s: Error in data block address file `%s'.\n", + prog, optarg); + + fclose (file); + return 3; + } + + AddEntry (address1, address1, RTN_SURE); + } + + fclose (file); + break; + + case 'L': + if (0 > (listwidth = atoi (optarg))) { + fprintf (stderr, "%s: Illegal listing width specified.\n\n", prog); + goto Usage; + } + + break; + + case 'a': + if (!strcmp (optarg, "disabled")) + Options = (Options & ~M_ADDRESSES) | O_ADR_NOTHING; + else if (!strcmp (optarg, "enabled")) + Options = (Options & ~M_ADDRESSES) | O_ADR_ADRPFIX; + else if (!strcmp (optarg, "dump")) + Options = (Options & ~M_ADDRESSES) | O_ADR_ADR_DMP; + else { + fprintf (stderr, "%s: Unrecognized option for dumping addresses.\n\n", + prog); + goto Usage; + } + break; + + case 'd': + if (!strcmp (optarg, "poor")) + Options = (Options & ~M_DATA_BLOCKS) | O_DBL_IGNORE; + else if (!strcmp (optarg, "extended")) + Options = (Options & ~M_DATA_BLOCKS) | O_DBL_DETECT; + else if (!strcmp (optarg, "skip-scanning")) + Options = (Options & ~M_DATA_BLOCKS) | O_DBL_NOSCAN; + else if (!strcmp (optarg, "strict")) + Options = (Options & ~M_DATA_BLOCKS) | O_DBL_STRICT; + else { + fprintf (stderr, + "%s: Unrecognized option for detecting data blocks.\n\n", + prog); + goto Usage; + } + break; + + case 'p': + if (!strcmp (optarg, "all-nmos6502")) + opset = all_nmos6502; + else if (!strcmp (optarg, "rational-nmos6502")) + opset = rational_nmos6502; + else if (!strcmp (optarg, "useful-nmos6502")) + opset = useful_nmos6502; + else if (!strcmp (optarg, "traditional-nmos6502")) + opset = traditional_nmos6502; + else if (!strcmp (optarg, "r65c02")) + opset = r65c02; + else if (!strcmp (optarg, "standard-nmos6502")) + opset = standard_nmos6502; + else { + fprintf (stderr, "%s: Unsupported instruction set `%s'.\n\n", + prog, optarg); + goto Usage; + } + break; + + case 'e': + Options &= ~B_LBL_ALWAYS; + break; + case 'E': + Options |= B_LBL_ALWAYS; + break; + + case 't': + if (!strcmp (optarg, "ignore")) + Options = (Options & ~M_ADR_TABLES) | O_TBL_IGNORE; + else if (!strcmp (optarg, "detect-all")) + Options = (Options & ~M_ADR_TABLES) | O_TBL_DETECT; + else if (!strcmp (optarg, "detect-internal")) + Options = (Options & ~M_ADR_TABLES) | O_TBL_NOEXT; + else { + fprintf (stderr, + "%s: Unknown address table detection option `%s'.\n\n", + prog, optarg); + goto Usage; + } + break; + + case 's': + Options &= ~B_STM_DETECT; + break; + case 'S': + Options |= B_STM_DETECT; + break; + + case 'J': + Options &= ~B_STK_BALANCE; + break; + case 'j': + Options |= B_STK_BALANCE; + break; + + case 'o': + Options &= ~B_RSC_STRICT; + break; + case 'O': + Options |= B_RSC_STRICT; + break; + + case 'c': + Options &= ~B_SCEPTIC; + break; + case 'C': + Options |= B_SCEPTIC; + break; + + case 'M': + Options &= ~B_JMP_STRICT; + break; + case 'm': + Options |= B_JMP_STRICT; + break; + + case 'v': + fVerbose = TRUE; + break; + + case 'W': + Options &= ~B_BRK_REJECT; + break; + case 'w': + Options |= B_BRK_REJECT; + break; + + case 'x': + Options &= ~B_CROSSREF; + break; + case 'X': + Options |= B_CROSSREF; + break; + +/* new or altered dxa options */ + case 'n': + Options &= ~B_LABCOL; + break; + case 'N': + Options |= B_LABCOL; + break; + case 'q': + Options &= ~B_SA_WORD; + break; + case 'Q': + Options |= B_SA_WORD; + break; + case 'G': + Options |= B_GET_SA; + break; + case 'g': + Options &= ~B_GET_SA; + if (!sscanf (optarg, "%X", &address1) || address1 > 65535) { + fprintf (stderr, "%s: Error specifying starting address `%s'.\n\n", + prog, optarg); + goto Usage; + } + StartAddress = address1; + break; + case 'l': + if (!((file = fopen (optarg, "rt")))) { + fprintf (stderr, + "%s: Label file %s could not be opened for reading.\n\n", + prog, optarg); + + goto Usage; + } + + while (!feof (file)) { + fType = fgetc (file); + + if (feof (file)) + break; + + ungetc (fType, file); + +#if(0) + /* This is the old behaviour. -- Cameron */ + if (!fscanf (file, "%X:", &address1) || address1 > 65535 || + !fgets (labelname, sizeof labelname, file)) { +#else + /* This is the xa-compatible label scanner. */ + if (!fscanf(file, "%s%i", labelname, &address1) || + address1 > 65535 || + !fgets(strig, sizeof strig, file)) { +#endif + LabelError: + fprintf (stderr, "%s: Error in label file %s.\n", prog, optarg); + fprintf (stderr, "Address(?): 0x%x ... Label(?): \"%s\"\n\n", + address1, labelname); + fclose (file); + return 3; + } + + for (scanner = labelname; *scanner; scanner++); + +#if(0) + if (scanner[-1] != '\n') goto LabelError; /* line too long */ +#endif + + while (--scanner > labelname && ( + *(unsigned char *)scanner < 32 || + *(unsigned char *)scanner == 44)) /* and commas */ + *scanner = 0; /* remove trailing control characters */ + + for (scanner = labelname; *(unsigned char *)scanner < 32; scanner++) + if (!*scanner) goto LabelError; /* label name missing */ + + AddLabel (address1, scanner); + } + + fclose (file); + } + + if (argc - optind > 1) { + Usage: + fprintf (stderr, "%s v0.1.3 -- symbolic 65xx disassembler\n", prog); + fprintf (stderr, "Based on d65 copyright (C) 1993-4 Marko M\"akel\"a\n"); + fprintf (stderr, "Changes for dxa copyright (c) 2006-7 Cameron Kaiser\n\n"); + fprintf (stderr, "Usage: %s [options] [filename]\n", prog); + return 1; + } + + /* Fix, Need "rb" (binary mode) on Windows to avoid termintating on $1A */ + if (!(file = (argc - optind) ? fopen (argv[argc - 1], "rb") : stdin)) { + fprintf (stderr, "%s: Couldn't open input file.\n", prog); + return 2; + } + + if (Options & B_GET_SA) { + StartAddress = (unsigned)fgetc (file); + StartAddress |= (unsigned)fgetc (file) << 8; + } + + + if (feof (file)) { + fprintf (stderr, "%s: Error reading the file.\n", prog); + return 3; + } + +/* this doesn't work so well */ +/* AddEntry (StartAddress, StartAddress, RTN_SURE); */ + EndAddress = StartAddress + fread (&Memory[StartAddress], sizeof (char), + 65536 - StartAddress, file); + + if (!feof (file)) { + if ((EndAddress = fread (Memory, sizeof (char), StartAddress, file))) + fprintf (stderr, "%s: Warning: Input file caused an address overflow.\n", + prog); + + if (!feof (file)) { + fprintf (stderr, "%s: Error: Input file is longer than 64 kilobytes.\n", + prog); + fclose (file); + return 3; + } + } + + fclose (file); + + if (fVerbose) + fprintf (stderr, "%s: disassembling %X-%X\n", prog, + StartAddress, EndAddress); + + if (ScanSpecified ()) { + fprintf (stderr, "\n%s: Invalid routine address(es) specified. Stop.\n", + prog); + + return 4; + } + + ScanPotentials (); + ScanTheRest (); + Collect (); + SearchVectors (); + Dump (); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/opcodes.h Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,617 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * Changes for dxa (C) 2006 Cameron Kaiser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Marko does not maintain dxa, so questions specific to dxa should be + * sent to me at ckaiser@floodgap.com . Otherwise, + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +/* opcodes.h - opcodes for different microprocessors */ + +#ifndef _OPCODES_H_ +#define _OPCODES_H_ + +#ifdef _DUMP_C_ + +static char *mne[] = { "???", "lda", "ldx", "ldy", "sta", "stx", "sty", +"stz", "adc", "sbc", "dec", "dex", "dey", "inc", "inx", "iny", "cmp", +"cpx", "cpy", "bit", "and", "ora", "eor", "asl", "lsr", "rol", "ror", +"tax", "tay", "tsx", "txs", "tya", "tad", "tas", "tda", "tsa", "txy", +"tyx", "pha", "phx", "phy", "php", "pea", "pei", "per", "phb", "phd", +"phk", "plb", "pld", "pla", "plx", "ply", "plp", "clc", "cld", "cli", +"clv", "sec", "sed", "sei", "rep", "sep", "xba", "xce", "bcc", "bcs", +"bne", "beq", "bra", "brl", "bpl", "bmi", "bvc", "bvs", "jmp", "jml", +"jsr", "jsl", "rts", "rtl", "rti", "brk", "nop", "trb", "tsb", "wai", +"bbr0", "bbr1", "bbr2", "bbr3", "bbr4", "bbr5", "bbr6", "bbr7", +"bbs0", "bbs1", "bbs2", "bbs3", "bbs4", "bbs5", "bbs6", "bbs7", +"rmb0", "rmb1", "rmb2", "rmb3", "rmb4", "rmb5", "rmb6", "rmb7", +"smb0", "smb1", "smb2", "smb3", "smb4", "smb5", "smb6", "smb7", "cop", +"mvn", "mvp", "laxs", "stax", "sha", "shx", "shy", "ane", "lxa", "lae", +"shs", "sbx", "usbc", "dcmp", "isbc", "rlan", "rrad", "slor", "sreo", +"arr", "asr", "anc", "noop", "stp", "txa", "ldax" }; + +#endif /* _DUMP_C_ */ + +enum +{ + S_ILLEGAL = 0, S_LDA, S_LDX, S_LDY, S_STA, S_STX, S_STY, S_STZ, S_ADC, + S_SBC, S_DEC, S_DEX, S_DEY, S_INC, S_INX, S_INY, S_CMP, S_CPX, S_CPY, + S_BIT, S_AND, S_ORA, S_EOR, S_ASL, S_LSR, S_ROL, S_ROR, S_TAX, S_TAY, + S_TSX, S_TXS, S_TYA, S_TAD, S_TAS, S_TDA, S_TSA, S_TXY, S_TYX, S_PHA, + S_PHX, S_PHY, S_PHP, S_PEA, S_PEI, S_PER, S_PHB, S_PHD, S_PHK, S_PLB, + S_PLD, S_PLA, S_PLX, S_PLY, S_PLP, S_CLC, S_CLD, S_CLI, S_CLV, S_SEC, + S_SED, S_SEI, S_REP, S_SEP, S_XBA, S_XCE, S_BCC, S_BCS, S_BNE, S_BEQ, + S_BRA, S_BRL, S_BPL, S_BMI, S_BVC, S_BVS, S_JMP, S_JML, S_JSR, S_JSL, + S_RTS, S_RTL, S_RTI, S_BRK, S_NOP, S_TRB, S_TSB, S_WAI, + S_BBR0, S_BBR1, S_BBR2, S_BBR3, S_BBR4, S_BBR5, S_BBR6, S_BBR7, + S_BBS0, S_BBS1, S_BBS2, S_BBS3, S_BBS4, S_BBS5, S_BBS6, S_BBS7, + S_RMB0, S_RMB1, S_RMB2, S_RMB3, S_RMB4, S_RMB5, S_RMB6, S_RMB7, + S_SMB0, S_SMB1, S_SMB2, S_SMB3, S_SMB4, S_SMB5, S_SMB6, S_SMB7, + S_COP, S_MVN, S_MVP, S_LAXS, S_STAX, S_SHA, S_SHX, S_SHY, S_ANE, S_LXA, + S_LAE, S_SHS, S_SBX, S_USBC, S_DCMP, S_ISBC, S_RLAN, S_RRAD, S_SLOR, + S_SREO, S_ARR, S_ASR, S_ANC, S_NOOP, S_STP, S_TXA, S_LDAX +}; + +enum +{ + accu=0, imm, abso, zp, zpx, zpy, absx, absy, + iabsx, impl, rel, zrel, indx, indy, iabs, ind +}; + +#ifdef _DUMP_C_ +static char *prefix[] = { "", "#", "", "", "", "", "", "", + "(", "", "", "", "(", "(", "(", "(" }; + +/* static char *postfix[] = { " A", "", "", "", ",X", ",Y", ",X", ",Y", */ +static char *postfix[] = { "", "", "", "", ",x", ",y", ",x", ",y", + ",x)", "", "", "", ",x)", "),y", ")", ")" }; +#endif /* _DUMP_C_ */ + +/* Adressing mode types. */ +enum +{ + absindir, /* absolute parameter (8 or 16 bits) for indirection */ + absolute, /* absolute parameter (8 or 16 bits), not indexed */ + other, /* something else (except impimm) */ + impimm /* implied or immediate parameter */ +}; + +#ifndef _SCAN_C_ +extern unsigned int types[]; +#else +unsigned int types[] = { impimm, impimm, absolute, absolute, other, other, + other, other, other, impimm, other, other, + other, absindir, absindir, absindir }; +#endif + +/* Number of bytes that instructions of different addressing modes occupy */ +#ifndef _SCAN_C_ +extern unsigned int sizes[]; +#else +unsigned int sizes[] = { 1, 2, 3, 2, 2, 2, 3, 3, 3, 1, 2, 3, 2, 2, 3, 2 }; +#endif + +typedef struct opcodes +{ + int mnemonic; /* index to mnemonic instruction name table */ + int admode; /* addressing mode */ +} opcodes; + +#ifndef _MAIN_C_ +extern +#endif +opcodes *opset; + +#ifdef _MAIN_C_ +opcodes all_nmos6502[] = +{ + {S_BRK, impl}, {S_ORA, indx}, {S_STP, impl}, {S_SLOR,indx}, + {S_NOOP, zp}, {S_ORA, zp}, {S_ASL, zp}, {S_SLOR, zp}, + {S_PHP, impl}, {S_ORA, imm}, {S_ASL, accu}, {S_ANC, imm}, + {S_NOOP,abso}, {S_ORA, abso}, {S_ASL, abso}, {S_SLOR, abso}, + {S_BPL, rel}, {S_ORA, indy}, {S_STP, impl}, {S_SLOR,indy}, + {S_NOOP, zpx}, {S_ORA, zpx}, {S_ASL, zpx}, {S_SLOR, zpx}, + {S_CLC, impl}, {S_ORA, absy}, {S_NOOP,impl}, {S_SLOR,absy}, + {S_NOOP,absx}, {S_ORA, absx}, {S_ASL, absx}, {S_SLOR,absx}, + + {S_JSR, abso}, {S_AND, indx}, {S_STP, impl}, {S_RLAN,indx}, + {S_BIT, zp}, {S_AND, zp}, {S_ROL, zp}, {S_RLAN, zp}, + {S_PLP, impl}, {S_AND, imm}, {S_ROL, accu}, {S_ANC, imm}, + {S_BIT, abso}, {S_AND, abso}, {S_ROL, abso}, {S_RLAN,abso}, + {S_BMI, rel}, {S_AND, indy}, {S_STP, impl}, {S_RLAN,indy}, + {S_NOOP, zpx}, {S_AND, zpx}, {S_ROL, zpx}, {S_RLAN, zpx}, + {S_SEC, impl}, {S_AND, absy}, {S_NOOP,impl}, {S_RLAN,absy}, + {S_NOOP,absx}, {S_AND, absx}, {S_ROL, absx}, {S_RLAN,absx}, + + {S_RTI, impl}, {S_EOR, indx}, {S_STP, impl}, {S_SREO,indx}, + {S_NOOP, zp}, {S_EOR, zp}, {S_LSR, zp}, {S_SREO, zp}, + {S_PHA, impl}, {S_EOR, imm}, {S_LSR, accu}, {S_ASR, imm}, + {S_JMP, abso}, {S_EOR, abso}, {S_LSR, abso}, {S_SREO,abso}, + {S_BVC, rel}, {S_EOR, indy}, {S_STP, impl}, {S_SREO,indy}, + {S_NOOP, zpx}, {S_EOR, zpx}, {S_LSR, zpx}, {S_SREO, zpx}, + {S_CLI, impl}, {S_EOR, absy}, {S_NOOP,impl}, {S_SREO,absy}, + {S_NOOP,absx}, {S_EOR, absx}, {S_LSR, absx}, {S_SREO,absx}, + + {S_RTS, impl}, {S_ADC, indx}, {S_STP, impl}, {S_RRAD,indx}, + {S_NOOP, zp}, {S_ADC, zp}, {S_ROR, zp}, {S_RRAD, zp}, + {S_PLA, impl}, {S_ADC, imm}, {S_ROR, accu}, {S_ARR, imm}, + {S_JMP, iabs}, {S_ADC, abso}, {S_ROR, abso}, {S_RRAD,abso}, + {S_BVS, rel}, {S_ADC, indy}, {S_STP, impl}, {S_RRAD,indy}, + {S_NOOP, zpx}, {S_ADC, zpx}, {S_ROR, zpx}, {S_RRAD, zpx}, + {S_SEI, impl}, {S_ADC, absy}, {S_NOOP,impl}, {S_RRAD,absy}, + {S_NOOP,absx}, {S_ADC, absx}, {S_ROR, absx}, {S_RRAD,absx}, + + {S_NOOP, imm}, {S_STA, indx}, {S_NOOP, imm}, {S_STAX,indx}, + {S_STY, zp}, {S_STA, zp}, {S_STX, zp}, {S_STAX, zp}, + {S_DEY, impl}, {S_NOOP, imm}, {S_TXA, impl}, {S_ANE, imm}, + {S_STY, abso}, {S_STA, abso}, {S_STX, abso}, {S_STAX,abso}, + {S_BCC, rel}, {S_STA, indy}, {S_STP, impl}, {S_SHA, indy}, + {S_STY, zpx}, {S_STA, zpx}, {S_STX, zpy}, {S_STAX, zpy}, + {S_TYA, impl}, {S_STA, absy}, {S_TXS, impl}, {S_SHS, absy}, + {S_SHY, absx}, {S_STA, absx}, {S_SHX, absx}, {S_SHA, absx}, + + {S_LDY, imm}, {S_LDA, indx}, {S_LDX, imm}, {S_LDAX,indy}, + {S_LDY, zp}, {S_LDA, zp}, {S_LDX, zp}, {S_LDAX, zp}, + {S_TAY, impl}, {S_LDA, imm}, {S_TAX, impl}, {S_LXA, imm}, + {S_LDY, abso}, {S_LDA, abso}, {S_LDX, abso}, {S_LDAX,abso}, + {S_BCS, rel}, {S_LDA, indy}, {S_STP, impl}, {S_LDAX,indy}, + {S_LDY, zpx}, {S_LDA, zpx}, {S_LDX, zpy}, {S_LDAX, zpy}, + {S_CLV, impl}, {S_LDA, absy}, {S_TSX, impl}, {S_LAXS,absy}, + {S_LDY, absx}, {S_LDA, absx}, {S_LDX, absy}, {S_LDAX,absy}, + + {S_CPY, imm}, {S_CMP, indx}, {S_NOOP, imm}, {S_DCMP,indx}, + {S_CPY, zp}, {S_CMP, zp}, {S_DEC, zp}, {S_DCMP, zp}, + {S_INY, impl}, {S_CMP, imm}, {S_DEX, impl}, {S_SBX, imm}, + {S_CPY, abso}, {S_CMP, abso}, {S_DEC, abso}, {S_DCMP,abso}, + {S_BNE, rel}, {S_CMP, indy}, {S_STP, impl}, {S_DCMP,indy}, + {S_NOOP, zpx}, {S_CMP, zpx}, {S_DEC, zpx}, {S_DCMP, zpx}, + {S_CLD, impl}, {S_CMP, absy}, {S_NOOP,impl}, {S_DCMP,absy}, + {S_NOOP,absx}, {S_CMP, absx}, {S_DEC, absx}, {S_DCMP,absx}, + + {S_CPX, imm}, {S_SBC, indx}, {S_NOOP, imm}, {S_ISBC,indx}, + {S_CPX, zp}, {S_SBC, zp}, {S_INC, zp}, {S_ISBC, zp}, + {S_INX, impl}, {S_SBC, imm}, {S_NOP, impl}, {S_USBC, imm}, + {S_CPX, abso}, {S_SBC, abso}, {S_INC, abso}, {S_ISBC,abso}, + {S_BEQ, rel}, {S_SBC, indy}, {S_STP, impl}, {S_ISBC,indy}, + {S_NOOP, zpx}, {S_SBC, zpx}, {S_INC, zpx}, {S_ISBC, zpx}, + {S_SED, impl}, {S_SBC, absy}, {S_NOOP,impl}, {S_ISBC,absy}, + {S_NOOP,absx}, {S_SBC, absx}, {S_INC, absx}, {S_ISBC,absx}, +}; + +/*\ + * The following NMOS 6502 instructions are missing from the + * rational_nmos6502 map: + * + * ANE SHA SHS SHY SHX LXA LAXS +\*/ + +opcodes rational_nmos6502[] = +{ + {S_BRK, impl}, {S_ORA, indx}, {S_STP, impl}, {S_SLOR,indx}, + {S_NOOP, zp}, {S_ORA, zp}, {S_ASL, zp}, {S_SLOR, zp}, + {S_PHP, impl}, {S_ORA, imm}, {S_ASL, accu}, {S_ANC, imm}, + {S_NOOP,abso}, {S_ORA, abso}, {S_ASL, abso}, {S_SLOR, abso}, + {S_BPL, rel}, {S_ORA, indy}, {S_STP, impl}, {S_SLOR,indy}, + {S_NOOP, zpx}, {S_ORA, zpx}, {S_ASL, zpx}, {S_SLOR, zpx}, + {S_CLC, impl}, {S_ORA, absy}, {S_NOOP,impl}, {S_SLOR,absy}, + {S_NOOP,absx}, {S_ORA, absx}, {S_ASL, absx}, {S_SLOR,absx}, + + {S_JSR, abso}, {S_AND, indx}, {S_STP, impl}, {S_RLAN,indx}, + {S_BIT, zp}, {S_AND, zp}, {S_ROL, zp}, {S_RLAN, zp}, + {S_PLP, impl}, {S_AND, imm}, {S_ROL, accu}, {S_ANC, imm}, + {S_BIT, abso}, {S_AND, abso}, {S_ROL, abso}, {S_RLAN,abso}, + {S_BMI, rel}, {S_AND, indy}, {S_STP, impl}, {S_RLAN,indy}, + {S_NOOP, zpx}, {S_AND, zpx}, {S_ROL, zpx}, {S_RLAN, zpx}, + {S_SEC, impl}, {S_AND, absy}, {S_NOOP,impl}, {S_RLAN,absy}, + {S_NOOP,absx}, {S_AND, absx}, {S_ROL, absx}, {S_RLAN,absx}, + + {S_RTI, impl}, {S_EOR, indx}, {S_STP, impl}, {S_SREO,indx}, + {S_NOOP, zp}, {S_EOR, zp}, {S_LSR, zp}, {S_SREO, zp}, + {S_PHA, impl}, {S_EOR, imm}, {S_LSR, accu}, {S_ASR, imm}, + {S_JMP, abso}, {S_EOR, abso}, {S_LSR, abso}, {S_SREO,abso}, + {S_BVC, rel}, {S_EOR, indy}, {S_STP, impl}, {S_SREO,indy}, + {S_NOOP, zpx}, {S_EOR, zpx}, {S_LSR, zpx}, {S_SREO, zpx}, + {S_CLI, impl}, {S_EOR, absy}, {S_NOOP,impl}, {S_SREO,absy}, + {S_NOOP,absx}, {S_EOR, absx}, {S_LSR, absx}, {S_SREO,absx}, + + {S_RTS, impl}, {S_ADC, indx}, {S_STP, impl}, {S_RRAD,indx}, + {S_NOOP, zp}, {S_ADC, zp}, {S_ROR, zp}, {S_RRAD, zp}, + {S_PLA, impl}, {S_ADC, imm}, {S_ROR, accu}, {S_ARR, imm}, + {S_JMP, iabs}, {S_ADC, abso}, {S_ROR, abso}, {S_RRAD,abso}, + {S_BVS, rel}, {S_ADC, indy}, {S_STP, impl}, {S_RRAD,indy}, + {S_NOOP, zpx}, {S_ADC, zpx}, {S_ROR, zpx}, {S_RRAD, zpx}, + {S_SEI, impl}, {S_ADC, absy}, {S_NOOP,impl}, {S_RRAD,absy}, + {S_NOOP,absx}, {S_ADC, absx}, {S_ROR, absx}, {S_RRAD,absx}, + + {S_NOOP, imm}, {S_STA, indx}, {S_NOOP, imm}, {S_STAX,indx}, + {S_STY, zp}, {S_STA, zp}, {S_STX, zp}, {S_STAX, zp}, + {S_DEY, impl}, {S_NOOP, imm}, {S_TXA, impl}, {S_ILLEGAL,0}, + {S_STY, abso}, {S_STA, abso}, {S_STX, abso}, {S_STAX,abso}, + {S_BCC, rel}, {S_STA, indy}, {S_STP, impl}, {S_ILLEGAL,0}, + {S_STY, zpx}, {S_STA, zpx}, {S_STX, zpy}, {S_STAX, zpy}, + {S_TYA, impl}, {S_STA, absy}, {S_TXS, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_STA, absx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + + {S_LDY, imm}, {S_LDA, indx}, {S_LDX, imm}, {S_LDAX,indy}, + {S_LDY, zp}, {S_LDA, zp}, {S_LDX, zp}, {S_LDAX, zp}, + {S_TAY, impl}, {S_LDA, imm}, {S_TAX, impl}, {S_ILLEGAL,0}, + {S_LDY, abso}, {S_LDA, abso}, {S_LDX, abso}, {S_LDAX,abso}, + {S_BCS, rel}, {S_LDA, indy}, {S_STP, impl}, {S_LDAX,indy}, + {S_LDY, zpx}, {S_LDA, zpx}, {S_LDX, zpy}, {S_LDAX, zpy}, + {S_CLV, impl}, {S_LDA, absy}, {S_TSX, impl}, {S_ILLEGAL,0}, + {S_LDY, absx}, {S_LDA, absx}, {S_LDX, absy}, {S_LDAX,absy}, + + {S_CPY, imm}, {S_CMP, indx}, {S_NOOP, imm}, {S_DCMP,indx}, + {S_CPY, zp}, {S_CMP, zp}, {S_DEC, zp}, {S_DCMP, zp}, + {S_INY, impl}, {S_CMP, imm}, {S_DEX, impl}, {S_SBX, imm}, + {S_CPY, abso}, {S_CMP, abso}, {S_DEC, abso}, {S_DCMP,abso}, + {S_BNE, rel}, {S_CMP, indy}, {S_STP, impl}, {S_DCMP,indy}, + {S_NOOP, zpx}, {S_CMP, zpx}, {S_DEC, zpx}, {S_DCMP, zpx}, + {S_CLD, impl}, {S_CMP, absy}, {S_NOOP,impl}, {S_DCMP,absy}, + {S_NOOP,absx}, {S_CMP, absx}, {S_DEC, absx}, {S_DCMP,absx}, + + {S_CPX, imm}, {S_SBC, indx}, {S_NOOP, imm}, {S_ISBC,indx}, + {S_CPX, zp}, {S_SBC, zp}, {S_INC, zp}, {S_ISBC, zp}, + {S_INX, impl}, {S_SBC, imm}, {S_NOP, impl}, {S_USBC, imm}, + {S_CPX, abso}, {S_SBC, abso}, {S_INC, abso}, {S_ISBC,abso}, + {S_BEQ, rel}, {S_SBC, indy}, {S_STP, impl}, {S_ISBC,indy}, + {S_NOOP, zpx}, {S_SBC, zpx}, {S_INC, zpx}, {S_ISBC, zpx}, + {S_SED, impl}, {S_SBC, absy}, {S_NOOP,impl}, {S_ISBC,absy}, + {S_NOOP,absx}, {S_SBC, absx}, {S_INC, absx}, {S_ISBC,absx}, +}; + +/*\ + * The following NMOS 6502 instructions are missing from the + * useful_nmos6502 map: + * + * ANE SHA SHS SHY SHX LXA LAXS NOOP STP +\*/ + +opcodes useful_nmos6502[] = +{ + {S_BRK, impl}, {S_ORA, indx}, {S_ILLEGAL,0}, {S_SLOR,indx}, + {S_ILLEGAL,0}, {S_ORA, zp}, {S_ASL, zp}, {S_SLOR, zp}, + {S_PHP, impl}, {S_ORA, imm}, {S_ASL, accu}, {S_ANC, imm}, + {S_ILLEGAL,0}, {S_ORA, abso}, {S_ASL, abso}, {S_SLOR,abso}, + {S_BPL, rel}, {S_ORA, indy}, {S_ILLEGAL,0}, {S_SLOR,indy}, + {S_ILLEGAL,0}, {S_ORA, zpx}, {S_ASL, zpx}, {S_SLOR, zpx}, + {S_CLC, impl}, {S_ORA, absy}, {S_ILLEGAL,0}, {S_SLOR,absy}, + {S_ILLEGAL,0}, {S_ORA, absx}, {S_ASL, absx}, {S_SLOR,absx}, + + {S_JSR, abso}, {S_AND, indx}, {S_ILLEGAL,0}, {S_RLAN,indx}, + {S_BIT, zp}, {S_AND, zp}, {S_ROL, zp}, {S_RLAN, zp}, + {S_PLP, impl}, {S_AND, imm}, {S_ROL, accu}, {S_ANC, imm}, + {S_BIT, abso}, {S_AND, abso}, {S_ROL, abso}, {S_RLAN,abso}, + {S_BMI, rel}, {S_AND, indy}, {S_ILLEGAL,0}, {S_RLAN,indy}, + {S_ILLEGAL,0}, {S_AND, zpx}, {S_ROL, zpx}, {S_RLAN, zpx}, + {S_SEC, impl}, {S_AND, absy}, {S_ILLEGAL,0}, {S_RLAN,absy}, + {S_ILLEGAL,0}, {S_AND, absx}, {S_ROL, absx}, {S_RLAN,absx}, + + {S_RTI, impl}, {S_EOR, indx}, {S_ILLEGAL,0}, {S_SREO,indx}, + {S_ILLEGAL,0}, {S_EOR, zp}, {S_LSR, zp}, {S_SREO, zp}, + {S_PHA, impl}, {S_EOR, imm}, {S_LSR, accu}, {S_ASR, imm}, + {S_JMP, abso}, {S_EOR, abso}, {S_LSR, abso}, {S_SREO,abso}, + {S_BVC, rel}, {S_EOR, indy}, {S_ILLEGAL,0}, {S_SREO,indy}, + {S_ILLEGAL,0}, {S_EOR, zpx}, {S_LSR, zpx}, {S_SREO, zpx}, + {S_CLI, impl}, {S_EOR, absy}, {S_ILLEGAL,0}, {S_SREO,absy}, + {S_ILLEGAL,0}, {S_EOR, absx}, {S_LSR, absx}, {S_SREO,absx}, + + {S_RTS, impl}, {S_ADC, indx}, {S_ILLEGAL,0}, {S_RRAD,indx}, + {S_ILLEGAL,0}, {S_ADC, zp}, {S_ROR, zp}, {S_RRAD, zp}, + {S_PLA, impl}, {S_ADC, imm}, {S_ROR, accu}, {S_ARR, imm}, + {S_JMP, iabs}, {S_ADC, abso}, {S_ROR, abso}, {S_RRAD,abso}, + {S_BVS, rel}, {S_ADC, indy}, {S_ILLEGAL,0}, {S_RRAD,indy}, + {S_ILLEGAL,0}, {S_ADC, zpx}, {S_ROR, zpx}, {S_RRAD, zpx}, + {S_SEI, impl}, {S_ADC, absy}, {S_ILLEGAL,0}, {S_RRAD,absy}, + {S_ILLEGAL,0}, {S_ADC, absx}, {S_ROR, absx}, {S_RRAD,absx}, + + {S_ILLEGAL,0}, {S_STA, indx}, {S_ILLEGAL,0}, {S_STAX,indx}, + {S_STY, zp}, {S_STA, zp}, {S_STX, zp}, {S_STAX, zp}, + {S_DEY, impl}, {S_ILLEGAL,0}, {S_TXA, impl}, {S_ILLEGAL,0}, + {S_STY, abso}, {S_STA, abso}, {S_STX, abso}, {S_STAX,abso}, + {S_BCC, rel}, {S_STA, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_STY, zpx}, {S_STA, zpx}, {S_STX, zpy}, {S_STAX, zpy}, + {S_TYA, impl}, {S_STA, absy}, {S_TXS, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_STA, absx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + + {S_LDY, imm}, {S_LDA, indx}, {S_LDX, imm}, {S_LDAX,indy}, + {S_LDY, zp}, {S_LDA, zp}, {S_LDX, zp}, {S_LDAX, zp}, + {S_TAY, impl}, {S_LDA, imm}, {S_TAX, impl}, {S_ILLEGAL,0}, + {S_LDY, abso}, {S_LDA, abso}, {S_LDX, abso}, {S_LDAX,abso}, + {S_BCS, rel}, {S_LDA, indy}, {S_ILLEGAL,0}, {S_LDAX,indy}, + {S_LDY, zpx}, {S_LDA, zpx}, {S_LDX, zpy}, {S_LDAX, zpy}, + {S_CLV, impl}, {S_LDA, absy}, {S_TSX, impl}, {S_ILLEGAL,0}, + {S_LDY, absx}, {S_LDA, absx}, {S_LDX, absy}, {S_LDAX,absy}, + + {S_CPY, imm}, {S_CMP, indx}, {S_ILLEGAL,0}, {S_DCMP,indx}, + {S_CPY, zp}, {S_CMP, zp}, {S_DEC, zp}, {S_DCMP, zp}, + {S_INY, impl}, {S_CMP, imm}, {S_DEX, impl}, {S_SBX, imm}, + {S_CPY, abso}, {S_CMP, abso}, {S_DEC, abso}, {S_DCMP,abso}, + {S_BNE, rel}, {S_CMP, indy}, {S_ILLEGAL,0}, {S_DCMP,indy}, + {S_ILLEGAL,0}, {S_CMP, zpx}, {S_DEC, zpx}, {S_DCMP, zpx}, + {S_CLD, impl}, {S_CMP, absy}, {S_ILLEGAL,0}, {S_DCMP,absy}, + {S_ILLEGAL,0}, {S_CMP, absx}, {S_DEC, absx}, {S_DCMP,absx}, + + {S_CPX, imm}, {S_SBC, indx}, {S_ILLEGAL,0}, {S_ISBC,indx}, + {S_CPX, zp}, {S_SBC, zp}, {S_INC, zp}, {S_ISBC, zp}, + {S_INX, impl}, {S_SBC, imm}, {S_NOP, impl}, {S_USBC, imm}, + {S_CPX, abso}, {S_SBC, abso}, {S_INC, abso}, {S_ISBC,abso}, + {S_BEQ, rel}, {S_SBC, indy}, {S_ILLEGAL,0}, {S_ISBC,indy}, + {S_ILLEGAL,0}, {S_SBC, zpx}, {S_INC, zpx}, {S_ISBC, zpx}, + {S_SED, impl}, {S_SBC, absy}, {S_ILLEGAL,0}, {S_ISBC,absy}, + {S_ILLEGAL,0}, {S_SBC, absx}, {S_INC, absx}, {S_ISBC,absx}, +}; + +/*\ + * The following NMOS 6502 instructions are missing from the + * traditional_nmos6502 map: + * + * ANE SHA SHS SHY SHX LXA LAXS NOOP STP + * ARR ASR ANC SBX USBC +\*/ + +opcodes traditional_nmos6502[] = +{ + {S_BRK, impl}, {S_ORA, indx}, {S_ILLEGAL,0}, {S_SLOR,indx}, + {S_ILLEGAL,0}, {S_ORA, zp}, {S_ASL, zp}, {S_SLOR, zp}, + {S_PHP, impl}, {S_ORA, imm}, {S_ASL, accu}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ORA, abso}, {S_ASL, abso}, {S_SLOR,abso}, + {S_BPL, rel}, {S_ORA, indy}, {S_ILLEGAL,0}, {S_SLOR,indy}, + {S_ILLEGAL,0}, {S_ORA, zpx}, {S_ASL, zpx}, {S_SLOR, zpx}, + {S_CLC, impl}, {S_ORA, absy}, {S_ILLEGAL,0}, {S_SLOR,absy}, + {S_ILLEGAL,0}, {S_ORA, absx}, {S_ASL, absx}, {S_SLOR,absx}, + + {S_JSR, abso}, {S_AND, indx}, {S_ILLEGAL,0}, {S_RLAN,indx}, + {S_BIT, zp}, {S_AND, zp}, {S_ROL, zp}, {S_RLAN, zp}, + {S_PLP, impl}, {S_AND, imm}, {S_ROL, accu}, {S_ILLEGAL,0}, + {S_BIT, abso}, {S_AND, abso}, {S_ROL, abso}, {S_RLAN,abso}, + {S_BMI, rel}, {S_AND, indy}, {S_ILLEGAL,0}, {S_RLAN,indy}, + {S_ILLEGAL,0}, {S_AND, zpx}, {S_ROL, zpx}, {S_RLAN, zpx}, + {S_SEC, impl}, {S_AND, absy}, {S_ILLEGAL,0}, {S_RLAN,absy}, + {S_ILLEGAL,0}, {S_AND, absx}, {S_ROL, absx}, {S_RLAN,absx}, + + {S_RTI, impl}, {S_EOR, indx}, {S_ILLEGAL,0}, {S_SREO,indx}, + {S_ILLEGAL,0}, {S_EOR, zp}, {S_LSR, zp}, {S_SREO, zp}, + {S_PHA, impl}, {S_EOR, imm}, {S_LSR, accu}, {S_ILLEGAL,0}, + {S_JMP, abso}, {S_EOR, abso}, {S_LSR, abso}, {S_SREO,abso}, + {S_BVC, rel}, {S_EOR, indy}, {S_ILLEGAL,0}, {S_SREO,indy}, + {S_ILLEGAL,0}, {S_EOR, zpx}, {S_LSR, zpx}, {S_SREO, zpx}, + {S_CLI, impl}, {S_EOR, absy}, {S_ILLEGAL,0}, {S_SREO,absy}, + {S_ILLEGAL,0}, {S_EOR, absx}, {S_LSR, absx}, {S_SREO,absx}, + + {S_RTS, impl}, {S_ADC, indx}, {S_ILLEGAL,0}, {S_RRAD,indx}, + {S_ILLEGAL,0}, {S_ADC, zp}, {S_ROR, zp}, {S_RRAD, zp}, + {S_PLA, impl}, {S_ADC, imm}, {S_ROR, accu}, {S_ILLEGAL,0}, + {S_JMP, iabs}, {S_ADC, abso}, {S_ROR, abso}, {S_RRAD,abso}, + {S_BVS, rel}, {S_ADC, indy}, {S_ILLEGAL,0}, {S_RRAD,indy}, + {S_ILLEGAL,0}, {S_ADC, zpx}, {S_ROR, zpx}, {S_RRAD, zpx}, + {S_SEI, impl}, {S_ADC, absy}, {S_ILLEGAL,0}, {S_RRAD,absy}, + {S_ILLEGAL,0}, {S_ADC, absx}, {S_ROR, absx}, {S_RRAD,absx}, + + {S_ILLEGAL,0}, {S_STA, indx}, {S_ILLEGAL,0}, {S_STAX,indx}, + {S_STY, zp}, {S_STA, zp}, {S_STX, zp}, {S_STAX, zp}, + {S_DEY, impl}, {S_ILLEGAL,0}, {S_TXA, impl}, {S_ILLEGAL,0}, + {S_STY, abso}, {S_STA, abso}, {S_STX, abso}, {S_STAX,abso}, + {S_BCC, rel}, {S_STA, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_STY, zpx}, {S_STA, zpx}, {S_STX, zpy}, {S_STAX, zpy}, + {S_TYA, impl}, {S_STA, absy}, {S_TXS, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_STA, absx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + + {S_LDY, imm}, {S_LDA, indx}, {S_LDX, imm}, {S_LDAX,indy}, + {S_LDY, zp}, {S_LDA, zp}, {S_LDX, zp}, {S_LDAX, zp}, + {S_TAY, impl}, {S_LDA, imm}, {S_TAX, impl}, {S_ILLEGAL,0}, + {S_LDY, abso}, {S_LDA, abso}, {S_LDX, abso}, {S_LDAX,abso}, + {S_BCS, rel}, {S_LDA, indy}, {S_ILLEGAL,0}, {S_LDAX,indy}, + {S_LDY, zpx}, {S_LDA, zpx}, {S_LDX, zpy}, {S_LDAX, zpy}, + {S_CLV, impl}, {S_LDA, absy}, {S_TSX, impl}, {S_ILLEGAL,0}, + {S_LDY, absx}, {S_LDA, absx}, {S_LDX, absy}, {S_LDAX,absy}, + + {S_CPY, imm}, {S_CMP, indx}, {S_ILLEGAL,0}, {S_DCMP,indx}, + {S_CPY, zp}, {S_CMP, zp}, {S_DEC, zp}, {S_DCMP, zp}, + {S_INY, impl}, {S_CMP, imm}, {S_DEX, impl}, {S_ILLEGAL,0}, + {S_CPY, abso}, {S_CMP, abso}, {S_DEC, abso}, {S_DCMP,abso}, + {S_BNE, rel}, {S_CMP, indy}, {S_ILLEGAL,0}, {S_DCMP,indy}, + {S_ILLEGAL,0}, {S_CMP, zpx}, {S_DEC, zpx}, {S_DCMP, zpx}, + {S_CLD, impl}, {S_CMP, absy}, {S_ILLEGAL,0}, {S_DCMP,absy}, + {S_ILLEGAL,0}, {S_CMP, absx}, {S_DEC, absx}, {S_DCMP,absx}, + + {S_CPX, imm}, {S_SBC, indx}, {S_ILLEGAL,0}, {S_ISBC,indx}, + {S_CPX, zp}, {S_SBC, zp}, {S_INC, zp}, {S_ISBC, zp}, + {S_INX, impl}, {S_SBC, imm}, {S_NOP, impl}, {S_ILLEGAL,0}, + {S_CPX, abso}, {S_SBC, abso}, {S_INC, abso}, {S_ISBC,abso}, + {S_BEQ, rel}, {S_SBC, indy}, {S_ILLEGAL,0}, {S_ISBC,indy}, + {S_ILLEGAL,0}, {S_SBC, zpx}, {S_INC, zpx}, {S_ISBC, zpx}, + {S_SED, impl}, {S_SBC, absy}, {S_ILLEGAL,0}, {S_ISBC,absy}, + {S_ILLEGAL,0}, {S_SBC, absx}, {S_INC, absx}, {S_ISBC,absx}, +}; + +/*\ + * The following is the officially documented + * MOS 6502 instruction set. +\*/ + +opcodes standard_nmos6502[] = +{ + {S_BRK, impl}, {S_ORA, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ORA, zp}, {S_ASL, zp}, {S_ILLEGAL,0}, + {S_PHP, impl}, {S_ORA, imm}, {S_ASL, accu}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ORA, abso}, {S_ASL, abso}, {S_ILLEGAL,0}, + {S_BPL, rel}, {S_ORA, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ORA, zpx}, {S_ASL, zpx}, {S_ILLEGAL,0}, + {S_CLC, impl}, {S_ORA, absy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ORA, absx}, {S_ASL, absx}, {S_ILLEGAL,0}, + + {S_JSR, abso}, {S_AND, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_BIT, zp}, {S_AND, zp}, {S_ROL, zp}, {S_ILLEGAL,0}, + {S_PLP, impl}, {S_AND, imm}, {S_ROL, accu}, {S_ILLEGAL,0}, + {S_BIT, abso}, {S_AND, abso}, {S_ROL, abso}, {S_ILLEGAL,0}, + {S_BMI, rel}, {S_AND, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_AND, zpx}, {S_ROL, zpx}, {S_ILLEGAL,0}, + {S_SEC, impl}, {S_AND, absy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_AND, absx}, {S_ROL, absx}, {S_ILLEGAL,0}, + + {S_RTI, impl}, {S_EOR, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_EOR, zp}, {S_LSR, zp}, {S_ILLEGAL,0}, + {S_PHA, impl}, {S_EOR, imm}, {S_LSR, accu}, {S_ILLEGAL,0}, + {S_JMP, abso}, {S_EOR, abso}, {S_LSR, abso}, {S_ILLEGAL,0}, + {S_BVC, rel}, {S_EOR, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_EOR, zpx}, {S_LSR, zpx}, {S_ILLEGAL,0}, + {S_CLI, impl}, {S_EOR, absy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_EOR, absx}, {S_LSR, absx}, {S_ILLEGAL,0}, + + {S_RTS, impl}, {S_ADC, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ADC, zp}, {S_ROR, zp}, {S_ILLEGAL,0}, + {S_PLA, impl}, {S_ADC, imm}, {S_ROR, accu}, {S_ILLEGAL,0}, + {S_JMP, iabs}, {S_ADC, abso}, {S_ROR, abso}, {S_ILLEGAL,0}, + {S_BVS, rel}, {S_ADC, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ADC, zpx}, {S_ROR, zpx}, {S_ILLEGAL,0}, + {S_SEI, impl}, {S_ADC, absy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_ADC, absx}, {S_ROR, absx}, {S_ILLEGAL,0}, + + {S_ILLEGAL,0}, {S_STA, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_STY, zp}, {S_STA, zp}, {S_STX, zp}, {S_ILLEGAL,0}, + {S_DEY, impl}, {S_ILLEGAL,0}, {S_TXA, impl}, {S_ILLEGAL,0}, + {S_STY, abso}, {S_STA, abso}, {S_STX, abso}, {S_ILLEGAL,0}, + {S_BCC, rel}, {S_STA, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_STY, zpx}, {S_STA, zpx}, {S_STX, zpy}, {S_ILLEGAL,0}, + {S_TYA, impl}, {S_STA, absy}, {S_TXS, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_STA, absx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + + {S_LDY, imm}, {S_LDA, indx}, {S_LDX, imm}, {S_ILLEGAL,0}, + {S_LDY, zp}, {S_LDA, zp}, {S_LDX, zp}, {S_ILLEGAL,0}, + {S_TAY, impl}, {S_LDA, imm}, {S_TAX, impl}, {S_ILLEGAL,0}, + {S_LDY, abso}, {S_LDA, abso}, {S_LDX, abso}, {S_ILLEGAL,0}, + {S_BCS, rel}, {S_LDA, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_LDY, zpx}, {S_LDA, zpx}, {S_LDX, zpy}, {S_ILLEGAL,0}, + {S_CLV, impl}, {S_LDA, absy}, {S_TSX, impl}, {S_ILLEGAL,0}, + {S_LDY, absx}, {S_LDA, absx}, {S_LDX, absy}, {S_ILLEGAL,0}, + + {S_CPY, imm}, {S_CMP, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_CPY, zp}, {S_CMP, zp}, {S_DEC, zp}, {S_ILLEGAL,0}, + {S_INY, impl}, {S_CMP, imm}, {S_DEX, impl}, {S_ILLEGAL,0}, + {S_CPY, abso}, {S_CMP, abso}, {S_DEC, abso}, {S_ILLEGAL,0}, + {S_BNE, rel}, {S_CMP, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_CMP, zpx}, {S_DEC, zpx}, {S_ILLEGAL,0}, + {S_CLD, impl}, {S_CMP, absy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_CMP, absx}, {S_DEC, absx}, {S_ILLEGAL,0}, + + {S_CPX, imm}, {S_SBC, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_CPX, zp}, {S_SBC, zp}, {S_INC, zp}, {S_ILLEGAL,0}, + {S_INX, impl}, {S_SBC, imm}, {S_NOP, impl}, {S_ILLEGAL,0}, + {S_CPX, abso}, {S_SBC, abso}, {S_INC, abso}, {S_ILLEGAL,0}, + {S_BEQ, rel}, {S_SBC, indy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_SBC, zpx}, {S_INC, zpx}, {S_ILLEGAL,0}, + {S_SED, impl}, {S_SBC, absy}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_SBC, absx}, {S_INC, absx}, {S_ILLEGAL,0}, +}; + + +/*\ + * The following is the officially documented + * Rockwell R65C02 instruction set. +\*/ + +opcodes r65c02[] = +{ + {S_BRK, impl}, {S_ORA, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_TSB, zp}, {S_ORA, zp}, {S_ASL, zp}, {S_RMB0, zp}, + {S_PHP, impl}, {S_ORA, imm}, {S_ASL, accu}, {S_ILLEGAL,0}, + {S_TSB, abso}, {S_ORA, abso}, {S_ASL, abso}, {S_BBR0,zrel}, + {S_BPL, rel}, {S_ORA, indy}, {S_ORA, ind}, {S_ILLEGAL,0}, + {S_TRB, zp}, {S_ORA, zpx}, {S_ASL, zpx}, {S_RMB1, zp}, + {S_CLC, impl}, {S_ORA, absy}, {S_INC, accu}, {S_ILLEGAL,0}, + {S_TRB, abso}, {S_ORA, absx}, {S_ASL, absx}, {S_BBR1,zrel}, + + {S_JSR, abso}, {S_AND, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_BIT, zp}, {S_AND, zp}, {S_ROL, zp}, {S_RMB2, zp}, + {S_PLP, impl}, {S_AND, imm}, {S_ROL, accu}, {S_ILLEGAL,0}, + {S_BIT, abso}, {S_AND, abso}, {S_ROL, abso}, {S_BBR2,zrel}, + {S_BMI, rel}, {S_AND, indy}, {S_AND, ind}, {S_ILLEGAL,0}, + {S_BIT, zpx}, {S_AND, zpx}, {S_ROL, zpx}, {S_RMB3, zp}, + {S_SEC, impl}, {S_AND, absy}, {S_DEC, accu}, {S_ILLEGAL,0}, + {S_BIT, absx}, {S_AND, absx}, {S_ROL, absx}, {S_BBR3,zrel}, + + {S_RTI, impl}, {S_EOR, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_EOR, zp}, {S_LSR, zp}, {S_RMB4, zp}, + {S_PHA, impl}, {S_EOR, imm}, {S_LSR, accu}, {S_ILLEGAL,0}, + {S_JMP, abso}, {S_EOR, abso}, {S_LSR, abso}, {S_BBR4,zrel}, + {S_BVC, rel}, {S_EOR, indy}, {S_EOR, ind}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_EOR, zpx}, {S_LSR, zpx}, {S_RMB5, zp}, + {S_CLI, impl}, {S_EOR, absy}, {S_PHY, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_EOR, absx}, {S_LSR, absx}, {S_BBR5,zrel}, + + {S_RTS, impl}, {S_ADC, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_STZ, zp}, {S_ADC, zp}, {S_ROR, zp}, {S_RMB6, zp}, + {S_PLA, impl}, {S_ADC, imm}, {S_ROR, accu}, {S_ILLEGAL,0}, + {S_JMP, iabs}, {S_ADC, abso}, {S_ROR, abso}, {S_BBR6,zrel}, + {S_BVS, rel}, {S_ADC, indy}, {S_ADC, ind}, {S_ILLEGAL,0}, + {S_STZ, zpx}, {S_ADC, zpx}, {S_ROR, zpx}, {S_RMB7, zp}, + {S_SEI, impl}, {S_ADC, absy}, {S_PLY, impl}, {S_ILLEGAL,0}, + {S_JMP,iabsx}, {S_ADC, absx}, {S_ROR, absx}, {S_BBR7,zrel}, + + {S_BRA, rel}, {S_STA, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_STY, zp}, {S_STA, zp}, {S_STX, zp}, {S_SMB0, zp}, + {S_DEY, impl}, {S_BIT, imm}, {S_TXA, impl}, {S_ILLEGAL,0}, + {S_STY, abso}, {S_STA, abso}, {S_STX, abso}, {S_BBS0,zrel}, + {S_BCC, rel}, {S_STA, indy}, {S_STA, ind}, {S_ILLEGAL,0}, + {S_STY, zpx}, {S_STA, zpx}, {S_STX, zpy}, {S_SMB1, zp}, + {S_TYA, impl}, {S_STA, absy}, {S_TXS, impl}, {S_ILLEGAL,0}, + {S_STZ, abso}, {S_STA, absx}, {S_STZ, absx}, {S_BBS1,zrel}, + + {S_LDY, imm}, {S_LDA, indx}, {S_LDX, imm}, {S_ILLEGAL,0}, + {S_LDY, zp}, {S_LDA, zp}, {S_LDX, zp}, {S_SMB2, zp}, + {S_TAY, impl}, {S_LDA, imm}, {S_TAX, impl}, {S_ILLEGAL,0}, + {S_LDY, abso}, {S_LDA, abso}, {S_LDX, abso}, {S_BBS2,zrel}, + {S_BCS, rel}, {S_LDA, indy}, {S_LDA, ind}, {S_ILLEGAL,0}, + {S_LDY, zpx}, {S_LDA, zpx}, {S_LDX, zpy}, {S_SMB3, zp}, + {S_CLV, impl}, {S_LDA, absy}, {S_TSX, impl}, {S_ILLEGAL,0}, + {S_LDY, absx}, {S_LDA, absx}, {S_LDX, absy}, {S_BBS3,zrel}, + + {S_CPY, imm}, {S_CMP, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_CPY, zp}, {S_CMP, zp}, {S_DEC, zp}, {S_SMB4, zp}, + {S_INY, impl}, {S_CMP, imm}, {S_DEX, impl}, {S_ILLEGAL,0}, + {S_CPY, abso}, {S_CMP, abso}, {S_DEC, abso}, {S_BBS4,zrel}, + {S_BNE, rel}, {S_CMP, indy}, {S_CMP, ind}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_CMP, zpx}, {S_DEC, zpx}, {S_SMB5, zp}, + {S_CLD, impl}, {S_CMP, absy}, {S_PHX, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_CMP, absx}, {S_DEC, absx}, {S_BBS5,zrel}, + + {S_CPX, imm}, {S_SBC, indx}, {S_ILLEGAL,0}, {S_ILLEGAL,0}, + {S_CPX, zp}, {S_SBC, zp}, {S_INC, zp}, {S_SMB6, zp}, + {S_INX, impl}, {S_SBC, imm}, {S_NOP, impl}, {S_ILLEGAL,0}, + {S_CPX, abso}, {S_SBC, abso}, {S_INC, abso}, {S_BBS6,zrel}, + {S_BEQ, rel}, {S_SBC, indy}, {S_SBC, ind}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_SBC, zpx}, {S_INC, zpx}, {S_SMB7, zp}, + {S_SED, impl}, {S_SBC, absy}, {S_PLX, impl}, {S_ILLEGAL,0}, + {S_ILLEGAL,0}, {S_SBC, absx}, {S_INC, absx}, {S_BBS7,zrel}, +}; +#endif /* _MAIN_C_ */ + +#endif /* _OPCODES_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/options.h Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,138 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * Changes for dxa (C) 2005, 2006 Cameron Kaiser + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Marko does not maintain dxa, so questions specific to dxa should be + * sent to me at ckaiser@floodgap.com . Otherwise, + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +/* options.h - constant definitions for program options */ +#ifndef _OPTIONS_H_ +#define _OPTIONS_H_ + +/************** USER DEFINED SETTINGS ... you may change these **************/ + +/* #define LONG_OPTIONS *//* turn on if you want them -- needs getopt_long() */ + +/******************* WHITE HATS ONLY BELOW THIS POINT !! ********************/ + +#ifndef _MAIN_C_ +extern +#endif +unsigned int Options; + +/****************\ +* OUTPUT OPTIONS * +\****************/ + +#define M_ADDRESSES 12 /* ADDRESS INFORMATION PRODUCTION */ +#define O_ADR_NOTHING 0 /* do not include addresses in the output */ +#define O_ADR_ADRPFIX 8 /* begin each line with its assembling address */ +#define O_ADR_ADR_DMP 12 /* begin each line with a hexadecimal dump of + its address and the bytes it contains */ + + /* LABEL INFORMATION PRODUCTION */ +#define B_LBL_NO_EXT 0 /* do not produce labels for referred + addresses outside the program's area */ +#define B_LBL_ALWAYS 16 /* substitute all found address references + with label references */ + +#define M_ADR_TABLES 96 /* ADDRESS TABLE DETECTION */ +#define O_TBL_IGNORE 0 /* do not detect any address tables */ +#define O_TBL_DETECT 32 /* detect address tables and provide them + with label statements */ +#define O_TBL_NOEXT 64 /* detect only addresses that belong to + the program file */ + + /* ADDRESS STATEMENT INTERPRETATION */ +#define B_STM_IGNORE 0 /* do not detect or interpret statements + like lda #<label */ +#define B_STM_DETECT 128 /* provide load instructions with label + statements when possible*/ + + /* TAB OR COLON */ +#define B_LABTAB 0 /* use tabs to separate labels from text */ +#define B_LABCOL 262144 /* use colon and newline */ + +/********************\ +* PROCESSING OPTIONS * +\********************/ + + /* STARTING ADDRESS */ +#define B_SA_WORD 65536 /* write the starting address as .word to file */ +#define B_SA_NO_WORD 0 /* ... or don't */ +#define B_GET_SA 131072 /* read the first 2 bytes as starting address */ +#define B_NO_GET_SA 0 /* ... or expect them on the command line */ + + /* CUSTOM STACK HANDLING COMPATIBILITY */ +#define B_STK_SUSPECT 0 /* assume that a JSR might not return to the + following address; mark the routines + following a JSR as "potential". */ +#define B_STK_BALANCE 256 /* expect the rest of the routine following + a JSR to be valid */ + + /* ROUTINE DETECTION */ +#define B_RSC_LOUSE 0 /* all routines that consist of plain single-byte + instruction (e.g. RTI or RTS) are valid */ +#define B_RSC_STRICT 512 /* routines found by scanning remaining + unprocessed bytes must consist of more + than one instruction to be valid */ + +#define M_DATA_BLOCKS 3072 /* DATA BLOCK DETECTION */ +#define O_DBL_IGNORE 0 /* list the whole file as a program; dump hex + only if the area is marked as a data block */ +#define O_DBL_DETECT 1024 /* if a "suspected" routine contains invalid + code or jumps to any routine that leads to + any routine containing invalid code, the + start byte of it is marked to be data */ +#define O_DBL_NOSCAN 2048 /* skip the scanning in the fourth phase (3.4): + list as data all the bytes that have remained + unprocessed in the previous phases */ +#define O_DBL_STRICT 3072 /* if a "sure" routine contains illegal code, + exit the unassembling process immediately */ + + /* IMPROVED DATA BLOCK DETECTION */ +#define B_JMP_LOUSE 0 /* `stupid' jumps cause only warnings to the + output listing */ +#define B_JMP_STRICT 4096 /* valid routines may not contain unreasonable + branches or jumps like `BNE *' (D0 FE), + `JMP *' or `JSR *' */ +#define B_BRK_ACCEPT 0 /* a BRK or STP is considered to mark the end of + a routine */ +#define B_BRK_REJECT 8192 /* any routine that contains a BRK or an STP is + invalid */ + +#define B_SCEPTIC 16384 /* determines if the program should suspect also + the target addresses of relative branches */ + +#define B_CROSSREF 32768 /* determines if a cross-reference should + be created */ + +#endif /* _OPTIONS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/proto.h Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,72 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +#include "structures.h" + +#ifdef __STDC__ +#define PROTO(x) x +#else +#define PROTO(x) () +#endif + +/* scan.c */ + +int ScanSpecified PROTO((void)); /* scan all "sure" routines */ +void ScanPotentials PROTO((void)); /* scan the "potential" routines */ +void ScanTheRest PROTO((void)); /* scan unprocessed memory places + for routines */ + +/* table.c */ + +table *FindNextEntryType PROTO((table *entry, unsigned char andmask, + unsigned char eormask)); +table *FindNextEntryTypeParent PROTO((table *entry, ADDR_T parent, + unsigned char andmask, + unsigned char eormask)); +table *FindNextEntry PROTO((table *entry, ADDR_T address, + unsigned char andmask, unsigned char eormask)); +void AddEntry PROTO((ADDR_T address, ADDR_T parent, unsigned char type)); +void DeleteEntry PROTO((table *entry)); + +/* label.c */ + +void AddLabel PROTO((ADDR_T address, char *name)); +char *Label PROTO((ADDR_T address, int admode)); +void Collect PROTO((void)); /* garbage collection */ + +/* vector.c */ + +void SearchVectors PROTO((void)); +ADDR_T WordTableEnd PROTO((ADDR_T Start)); + +/* dump.c */ + +void Dump PROTO((void)); /* dump the program */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scan.c Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,920 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +#define _SCAN_C_ +#include <stdio.h> +#include "proto.h" +#include "opcodes.h" +#include "options.h" + +int ScanSure PROTO((ADDR_T scanstart)); +int ScanPotential PROTO((ADDR_T scanstart)); +void UnDoScan PROTO((ADDR_T scanstart)); +void DeleteSuspectedParents PROTO((ADDR_T child)); + +#ifndef __STDC__ +int +ScanSure (scanstart) + ADDR_T scanstart; +#else +int ScanSure (ADDR_T scanstart) +#endif +{ + ADDR_T address, addr; + opcodes *instr; + + unsigned int size, counter; + + for (address = scanstart;; address += size) { + if (GetMemFlag (address)) /* rest of routine not valid */ + return ((Options & M_DATA_BLOCKS) == O_DBL_STRICT); + + instr = &opset[Memory[address]]; + + if (!instr->mnemonic) /* invalid opcode */ + return ((Options & M_DATA_BLOCKS) == O_DBL_STRICT); + + size = sizes[instr->admode]; + if ((ADDR_T)(address + size - StartAddress) > + (ADDR_T)(EndAddress - StartAddress)) + break; /* end of program code encountered */ + + switch (GetMemType (address)) { + case MEM_INSTRUCTION: + return 0; /* The rest of the routine has already been processed. */ + + case MEM_DATA: + AddEntry (address, scanstart, WRN_INSTR_WRITTEN_TO); + break; + + case MEM_PARAMETER: + AddEntry (address, scanstart, WRN_PARAM_JUMPED_TO); + } + + SetMemType (address, MEM_INSTRUCTION); + + for (counter = size, addr = address + 1; --counter; addr++) + switch GetMemType(addr) { + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_PARAM_JUMPED_TO); + break; + case MEM_DATA: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO); + /* fall through */ + default: + SetMemType (addr, MEM_PARAMETER); + } + + if (instr->admode == zrel) { + addr = Memory[(ADDR_T)(address + 1)]; + + if (GetMemFlag (addr) && GetMemType (addr) == MEM_UNPROCESSED) + return (Options & M_DATA_BLOCKS) == O_DBL_STRICT; + + if (((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress) || + Options & B_LBL_ALWAYS)) { + PutLabel (addr); + PutLowByte (addr); + PutHighByte (addr); + } + + addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 2)] + + address + size); + goto IsJump; + } + + if (instr->admode == rel) { + addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 1)] + + address + size); + + goto IsJump; + } + if ((instr->mnemonic == S_JSR || instr->mnemonic == S_JMP) && + instr->admode == abso) { + addr = Memory[(ADDR_T)(address + 1)] + + (Memory[(ADDR_T)(address + 2)] << 8); + + IsJump: + if (GetMemFlag (addr)) + return ((Options & M_DATA_BLOCKS) == O_DBL_STRICT); + + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) { + if (GetMemType (addr) == MEM_INSTRUCTION) { + PutLabel (addr); + PutLowByte (addr); + PutHighByte (addr); + } + else + AddEntry (addr, scanstart, Options & B_SCEPTIC && + instr->admode == rel && instr->mnemonic != S_BRA ? + RTN_POTENTIAL : RTN_SURE); + } + else if (Options & B_LBL_ALWAYS) { + PutLabel (addr); + PutLowByte (addr); + PutHighByte (addr); + } + + if ((Options & M_DATA_BLOCKS) == O_DBL_STRICT && + Options & B_JMP_STRICT && + addr == address && instr->mnemonic != S_BVC) + return 1; + } + + switch (instr->mnemonic) { + case S_JMP: + addr = Memory[(ADDR_T)(address + 1)] + + (Memory[(ADDR_T)(address + 2)] << 8); + + if (instr->admode == iabs && (ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) { + PutLabel (addr); + PutLowByte (addr); + PutHighByte (addr); + + /* Mark pointer as data. */ + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + SetMemType (addr, MEM_DATA); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_INSTR_WRITTEN_TO); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO); + break; + } + + addr++; + + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + SetMemType (addr, MEM_DATA); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_INSTR_WRITTEN_TO); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO); + break; + } + } + else if (Options & B_LBL_ALWAYS) { + PutLabel (addr); + PutLowByte (addr); + PutHighByte (addr); + } + case S_BRA: + case S_RTS: + case S_RTI: + return 0; + + case S_BRK: + case S_STP: + return (Options & M_DATA_BLOCKS) == O_DBL_STRICT && + Options & B_BRK_REJECT; + } + + if (instr->admode == rel) { + if ((ADDR_T)(addr - scanstart) >= (ADDR_T)(address - scanstart) + || GetMemType (addr) != MEM_INSTRUCTION) { + if (GetMemType (address + size) != MEM_INSTRUCTION) + AddEntry (address + size, scanstart, RTN_POTENTIAL); + + return 0; + } + + continue; + } + + if (instr->mnemonic == S_JSR) { + if (!(Options & B_STK_BALANCE)) { + if (GetMemType (address + size) != MEM_INSTRUCTION) + AddEntry (address + size, scanstart, RTN_POTENTIAL); + + return 0; + } + + continue; + } + + switch (size) { + case 2: + addr = Memory[(ADDR_T)(address + 1)]; + break; + case 3: + addr = Memory[(ADDR_T)(address + 1)] + + (Memory[(ADDR_T)(address + 2)] << 8); + break; + } + + if (types[instr->admode] != impimm && GetMemFlag (addr) && + GetMemType (addr) == MEM_UNPROCESSED) + return (Options & M_DATA_BLOCKS) == O_DBL_STRICT; + + if (types[instr->admode] != impimm && + ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress) || + Options & B_LBL_ALWAYS)) { + PutLabel (addr); + PutLowByte (addr); + PutHighByte (addr); + } + + if (types[instr->admode] != other && types[instr->admode] != impimm) { + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) { + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + SetMemType (addr, MEM_DATA); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_INSTR_WRITTEN_TO); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO); + break; + } + + if (types[instr->admode] == absindir) { /* indirect mode */ + addr++; /* set flags for upper vector byte */ + + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + SetMemType (addr, MEM_DATA); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_INSTR_WRITTEN_TO); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO); + break; + } + } + } + } + } + + /* end of program (unexpectedly) encountered */ + + if (Options & O_DBL_STRICT) return 1; + + AddEntry (EndAddress, scanstart, WRN_RTN_TRUNCATED); + return 0; +} + +#ifndef __STDC__ +int +ScanPotential (scanstart) + ADDR_T scanstart; +#else +int ScanPotential (ADDR_T scanstart) +#endif +{ + ADDR_T address, addr; + opcodes *instr; + + unsigned int size, counter; + + for (address = scanstart;; address += size) { + if (GetMemFlag (address)) /* rest of routine not valid */ + return 1; + + instr = &opset[Memory[address]]; + + if (!instr->mnemonic) { /* invalid opcode */ + SetMemFlag (address); + + if (GetMemType (address) == MEM_UNPROCESSED) + SetMemType (address, MEM_DATA); + return 1; + } + + size = sizes[instr->admode]; + if ((ADDR_T)(address + size - StartAddress) > + (ADDR_T)(EndAddress - StartAddress)) + break; /* end of program code encountered */ + + if (GetMemType (address) == MEM_INSTRUCTION) + return 0; /* The rest of the routine has already been processed. */ + + if (instr->admode == zrel) { + addr = Memory[(ADDR_T)(address + 1)]; + + if (GetMemFlag (addr) && GetMemType (addr) == MEM_UNPROCESSED) + goto Failure; + + if (((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress) || + Options & B_LBL_ALWAYS)) + AddEntry (addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY); + + addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 1)] + + address + size); + + goto IsJump; + } + + if (instr->admode == rel) { + addr = (ADDR_T)((int)(char)Memory[(ADDR_T)(address + 1)] + + address + size); + + goto IsJump; + } + + switch (size) { + case 2: + addr = Memory[(ADDR_T)(address + 1)]; + break; + case 3: + addr = Memory[(ADDR_T)(address + 1)] + + (Memory[(ADDR_T)(address + 2)] << 8); + break; + default: + addr = address; + } + + if (types[instr->admode] != impimm && GetMemFlag (addr) && + GetMemType (addr) == MEM_UNPROCESSED) { + Failure: + SetMemFlag (address); + + if (GetMemType (address) == MEM_UNPROCESSED) + SetMemType (address, MEM_DATA); + return 1; + } + + if ((instr->mnemonic == S_JSR || instr->mnemonic == S_JMP) && + instr->admode == abso) { + IsJump: + if (GetMemFlag (addr)) { + SetMemFlag (address); + + if (GetMemType (address) == MEM_UNPROCESSED) + SetMemType (address, MEM_DATA); + return 1; + } + + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) + AddEntry (addr, scanstart, Options & B_SCEPTIC && + instr->admode == rel && instr->mnemonic != S_BRA ? + RTN_SUSP_POT : RTN_SUSPECTED); + else if (Options & B_LBL_ALWAYS) + AddEntry (addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY); + + if (Options & B_JMP_STRICT && addr == address && + instr->mnemonic != S_BVC) { + SetMemFlag (address); + + if (GetMemType (address) == MEM_UNPROCESSED) + SetMemType (address, MEM_DATA); + return 1; + } + } + + switch (instr->mnemonic) { + case S_BRK: + case S_STP: + if (Options & B_BRK_REJECT) { + SetMemFlag (address); + + if (GetMemType (address) == MEM_UNPROCESSED) + SetMemType (address, MEM_DATA); + return 1; + } + } + + if (!GetMemFlag (address)) + switch (GetMemType (address)) { + case MEM_DATA: + AddEntry (address, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY); + break; + + case MEM_PARAMETER: + AddEntry (address, scanstart, WRN_PARAM_JUMPED_TO | WRN_B_TEMPORARY); + } + + SetMemType (address, MEM_INSTRUCTION); + + for (counter = size, addr = address + 1; --counter; addr++) + switch (GetMemType (addr)) { + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_PARAM_JUMPED_TO | WRN_B_TEMPORARY); + break; + case MEM_DATA: + if (!GetMemFlag (addr)) + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY); + break; + default: + SetMemType (addr, MEM_PARAMETER); + } + + switch (instr->mnemonic) { + case S_BRK: + case S_STP: + case S_RTS: + case S_BRA: + case S_RTI: + return 0; + + case S_JMP: + addr = Memory[(ADDR_T)(address + 1)] + + (Memory[(ADDR_T)(address + 2)] << 8); + + if (instr->admode == iabs && (ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) { + AddEntry (addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY); + + /* Mark pointer as data. */ + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + AddEntry (addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY); + break; + } + + addr++; + + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + AddEntry (addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, + WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, + WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY); + break; + } + } + else if (Options & B_LBL_ALWAYS) + AddEntry (addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY); + + return 0; + } + + if (instr->admode == rel && + GetMemType (address + size) != MEM_INSTRUCTION) { + AddEntry (address + size, scanstart, RTN_SUSP_POT); + + return 0; + } + + if (instr->mnemonic == S_JSR) { + if (!(Options & B_STK_BALANCE)) { + if (GetMemType (address + size) != MEM_INSTRUCTION) + AddEntry (address + size, scanstart, RTN_SUSP_POT); + + return 0; + } + + continue; + } + + switch (size) { + case 2: + addr = Memory[(ADDR_T)(address + 1)]; + break; + case 3: + addr = Memory[(ADDR_T)(address + 1)] + + (Memory[(ADDR_T)(address + 2)] << 8); + break; + } + + if (types[instr->admode] != impimm && + ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress) || + Options & B_LBL_ALWAYS)) + AddEntry (addr, scanstart, WRN_I_LABEL_NEEDED | WRN_B_TEMPORARY); + + if (types[instr->admode] != other && types[instr->admode] != impimm) { + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) { + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + AddEntry (addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY); + break; + } + + if (types[instr->admode] == absindir) { /* indirect mode */ + addr++; /* set flags for upper vector byte */ + + if ((ADDR_T)(addr - StartAddress) < + (ADDR_T)(EndAddress - StartAddress)) + switch (GetMemType (addr)) { + case MEM_UNPROCESSED: + AddEntry (addr, scanstart, WRN_I_ACCESSED | WRN_B_TEMPORARY); + break; + case MEM_INSTRUCTION: + AddEntry (addr, scanstart, + WRN_INSTR_WRITTEN_TO | WRN_B_TEMPORARY); + break; + case MEM_PARAMETER: + AddEntry (addr, scanstart, + WRN_PARAM_WRITTEN_TO | WRN_B_TEMPORARY); + break; + } + } + } + } + } + + /* end of program (unexpectedly) encountered */ + + return 1; +} + +#ifndef __STDC__ +int +ScanSpecified () +#else +int ScanSpecified (void) +#endif +{ + table *entry; + + if (fVerbose) + fprintf (stderr, "%s: scanning the routines at specified address(es)", + prog); + + while ((entry = FindNextEntryType (NULL, ~0, RTN_SURE))) { + PutLabel (entry->address); + PutLowByte (entry->address); + PutHighByte (entry->address); + + if (ScanSure (entry->address)) { + fprintf(stderr,"For routine specified at %i:", + (unsigned int)entry->address); + return 1; + } + DeleteEntry (entry); + } + + return 0; +} + +#ifndef __STDC__ +void +UnDoScan (scanstart) + ADDR_T scanstart; +#else +void UnDoScan (ADDR_T scanstart) +#endif +{ + opcodes *instr; + unsigned counter; + ADDR_T address; + + for (address = scanstart; address != EndAddress; address++) { + if (GetMemFlag (address)) return; + + switch (GetMemType (address)) { + case MEM_UNPROCESSED: + return; + + case MEM_INSTRUCTION: + SetMemFlag (address); + SetMemType (address, MEM_DATA); /* This could cause WRN_PARAM_WRITTEN_TO + in vain. */ + instr = &opset[Memory[address++]]; + for (counter = sizes[instr->admode]; --counter; address++) + if (GetMemType (address) == MEM_PARAMETER) + SetMemType (address, MEM_UNPROCESSED); + else if (GetMemType (address) == MEM_INSTRUCTION) + break; + + if (instr->mnemonic == S_STP || instr->mnemonic == S_BRK || + instr->mnemonic == S_RTI || instr->mnemonic == S_RTS || + instr->mnemonic == S_JMP || instr->admode == rel) + return; + + address--; + break; + + case MEM_PARAMETER: + SetMemType (address, MEM_UNPROCESSED); + } + } +} + +#ifndef __STDC__ +void +DeleteSuspectedParents (child) + ADDR_T child; +#else +void DeleteSuspectedParents (ADDR_T child) +#endif +{ + table *entry = NULL; + + while ((entry = FindNextEntry (entry, child, ~(RTN_B_PROCESSED | + RTN_B_TEMPORARY), + RTN_SUSPECTED))) { + if (entry->type & RTN_B_PROCESSED && entry->parent != child) + DeleteSuspectedParents (entry->parent); + + DeleteEntry (entry); + } + + entry = NULL; + + while ((entry = FindNextEntryTypeParent (entry, child, ~0, RTN_SUSP_POT))) + DeleteEntry (entry); + + entry = NULL; + + while ((entry = FindNextEntryTypeParent (entry, child, + MASK_ANY | WRN_B_TEMPORARY, + WRN_ANY | WRN_B_TEMPORARY))) { + if (entry->type == (WRN_PARAM_JUMPED_TO | WRN_B_TEMPORARY)) + SetMemType (entry->address, MEM_PARAMETER); + + DeleteEntry (entry); + } + + UnDoScan (child); +} + +#ifndef __STDC__ +void +ScanPotentials () +#else +void ScanPotentials (void) +#endif +{ + table *entry; + ADDR_T address; + + if (fVerbose) + fprintf (stderr, "\n%s: scanning potential routines\n", prog); + + while ((entry = FindNextEntryType (NULL, ~0, RTN_POTENTIAL))) { + address = entry->address; + DeleteEntry (entry); + + if (!ScanPotential (address)) { + while ((entry = FindNextEntryType (NULL, ~RTN_B_TEMPORARY, + RTN_SUSPECTED))) { + entry->type |= RTN_B_PROCESSED; + + if (ScanPotential (entry->address) && + (Options & M_DATA_BLOCKS) != O_DBL_IGNORE) { + DeleteSuspectedParents (entry->address); + SetMemType (address, MEM_DATA); + } + } + + if (GetMemType (address) != MEM_DATA) { + PutLabel (address); + PutLowByte (address); + PutHighByte (address); + } + + entry = NULL; + + while ((entry = FindNextEntryType (entry, ~0, RTN_B_TEMPORARY | + RTN_SUSPECTED | RTN_B_PROCESSED))) + DeleteEntry (entry); + + entry = NULL; + + while ((entry = FindNextEntryType (entry, ~0, + RTN_SUSPECTED | RTN_B_PROCESSED))) { + PutLabel (entry->address); + PutLowByte (entry->address); + PutHighByte (entry->address); + DeleteEntry (entry); + } + + entry = NULL; + + while ((entry = FindNextEntryType (entry, ~0, RTN_SUSP_POT))) + entry->type = RTN_POTENTIAL; + + entry = NULL; + + while ((entry = FindNextEntryType (entry, MASK_ANY | WRN_B_TEMPORARY, + WRN_ANY | WRN_B_TEMPORARY))) { + switch (entry->type & ~WRN_B_TEMPORARY) { + case WRN_PARAM_WRITTEN_TO: + if (GetMemType (entry->address) == MEM_DATA) + SetMemType (entry->address, MEM_PARAMETER); + entry->type &= ~WRN_B_TEMPORARY; + break; + + case WRN_INSTR_WRITTEN_TO: + if (GetMemType (entry->address) == MEM_DATA) + SetMemType (entry->address, MEM_INSTRUCTION); + entry->type &= ~WRN_B_TEMPORARY; + break; + + case WRN_I_ACCESSED: + SetMemType (entry->address, MEM_DATA); + /* fall through */ + case WRN_I_LABEL_NEEDED: + PutLabel (entry->address); + PutLowByte (entry->address); + PutHighByte (entry->address); + DeleteEntry (entry); + break; + + default: + entry->type &= ~WRN_B_TEMPORARY; + } + } + } + else { + DeleteSuspectedParents (address); + SetMemType (address, MEM_DATA); + } + } +} + +#ifndef __STDC__ +void +ScanTheRest () +#else +void ScanTheRest (void) +#endif +{ + ADDR_T address; + table *entry; + unsigned int fPotentials; + + if ((Options & M_DATA_BLOCKS) == O_DBL_NOSCAN) { + for (address = StartAddress; address != EndAddress; address++) + if (GetMemType (address) == MEM_UNPROCESSED) + SetMemType (address, MEM_DATA); + + return; + } + + if (fVerbose) + fprintf (stderr, "%s: scanning the remaining bytes for routines\n", prog); + + for (address = StartAddress; address != EndAddress; address++) { + if (GetMemType (address) || GetMemFlag (address)) + continue; /* scan only unprocessed bytes */ + + if (Options & B_RSC_STRICT) + switch (opset[Memory[address]].mnemonic) { + case S_RTI: + case S_RTS: + case S_BRK: + case S_STP: + continue; + + case S_BRA: + break; + + default: + if (opset[Memory[address]].admode == rel && + GetMemType (address + sizes[rel]) != MEM_INSTRUCTION) + AddEntry (address + sizes[rel], address, + RTN_SUSPECTED | RTN_B_TEMPORARY); + } + + if (fVerbose) + fprintf (stderr, "\r%s: scanning at %X", prog, address); + + if (!ScanPotential (address)) { + while ((entry = FindNextEntryType (NULL, ~RTN_B_TEMPORARY, + RTN_SUSPECTED))) { + entry->type |= RTN_B_PROCESSED; + + if (ScanPotential (entry->address) && + (Options & M_DATA_BLOCKS) != O_DBL_IGNORE) { + DeleteSuspectedParents (entry->address); + SetMemType (address, MEM_DATA); + } + } + + if (GetMemType (address) != MEM_DATA) { + PutLabel (address); + PutLowByte (address); + PutHighByte (address); + } + + fPotentials = FALSE; + entry = NULL; + + while ((entry = FindNextEntryType (entry, ~0, RTN_SUSP_POT))) { + fPotentials = TRUE; + entry->type = RTN_POTENTIAL; + } + + entry = NULL; + + while ((entry = FindNextEntryType (entry, ~0, RTN_B_TEMPORARY | + RTN_SUSPECTED | RTN_B_PROCESSED))) + DeleteEntry (entry); + + entry = NULL; + + while ((entry = FindNextEntryType (entry, ~0, + RTN_SUSPECTED | RTN_B_PROCESSED))) { + PutLabel (entry->address); + PutLowByte (entry->address); + PutHighByte (entry->address); + DeleteEntry (entry); + } + + entry = NULL; + + while ((entry = FindNextEntryType (entry, MASK_ANY | WRN_B_TEMPORARY, + WRN_ANY | WRN_B_TEMPORARY))) { + switch (entry->type & ~WRN_B_TEMPORARY) { + case WRN_PARAM_WRITTEN_TO: + if (GetMemType (entry->address) == MEM_DATA) + SetMemType (entry->address, MEM_PARAMETER); + entry->type &= ~WRN_B_TEMPORARY; + break; + + case WRN_INSTR_WRITTEN_TO: + if (GetMemType (entry->address) == MEM_DATA) + SetMemType (entry->address, MEM_INSTRUCTION); + entry->type &= ~WRN_B_TEMPORARY; + break; + + case WRN_I_ACCESSED: + SetMemType (entry->address, MEM_DATA); + /* fall through */ + case WRN_I_LABEL_NEEDED: + PutLabel (entry->address); + PutLowByte (entry->address); + PutHighByte (entry->address); + DeleteEntry (entry); + break; + + default: + entry->type &= ~WRN_B_TEMPORARY; + } + } + + if (fPotentials) ScanPotentials (); + } + else { + DeleteSuspectedParents (address); + SetMemType (address, MEM_DATA); + } + } + + if (fVerbose) + fprintf (stderr, "\n"); + + for (address = StartAddress; address != EndAddress; address++) + if (GetMemType (address) == MEM_UNPROCESSED) { + fPotentials = GetMemFlag (address) ? MEM_PARAMETER : MEM_DATA; + SetMemType (address, fPotentials); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/structures.h Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,246 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +/* structures.h - memory structures and related constants and macros */ +#ifndef _STRUCTURES_H_ +#define _STRUCTURES_H_ + +#ifndef FALSE +#define FALSE 0 +#define TRUE !FALSE +#endif + +#ifndef NULL +#define NULL (void *)0 +#endif + +#define MAXLINE 50 /* maximum amount of bytes used when reading a label in */ + +typedef unsigned short int ADDR_T; /* 16-bit unsigned integer */ +typedef unsigned char DATA_T; /* 8-bit unsigned integer */ + +/********************\ +* Program code table * +\********************/ + +#ifndef _MAIN_C_ +extern +#endif +DATA_T Memory[1 << 16]; + +/*************************\ +* Memory place type table * +\*************************/ + +#ifndef _MAIN_C_ +extern +#endif +unsigned MemType[(1 << 14) / sizeof(unsigned)]; + +#define GetMemType(address) \ + ((MemType[((ADDR_T)address) / (4 * sizeof *MemType)] >> \ + ((address % (4 * sizeof *MemType)) << 1)) & 3) + +#define SetMemType(address, type) \ + (MemType[((ADDR_T)address) / (4 * sizeof *MemType)] = \ + (MemType[((ADDR_T)address) / (4 * sizeof *MemType)] & \ + ~(3 << ((address % (4 * sizeof *MemType)) << 1))) | \ + (type << ((address % (4 * sizeof *MemType)) << 1))) + +/* The table consists of bit pairs with the following values: */ + +#define MEM_UNPROCESSED 0 /* the memory place has not been processed yet */ +#define MEM_INSTRUCTION 1 /* a machine language instruction starts at + this memory place */ +#define MEM_DATA 2 /* the memory place contains data */ +#define MEM_PARAMETER 3 /* a parameter of a machine language + instruction is at this place */ + +/*************************\ +* Memory place flag table * +\*************************/ + +#ifndef _MAIN_C_ +extern +#endif +unsigned + MemFlag[(1 << 13) / sizeof(unsigned)], + MemLabel[(1 << 13) / sizeof(unsigned)], + LowByte[(1 << 8) / sizeof(unsigned)], + HighByte[(1 << 8) / sizeof(unsigned)]; + +#define GetMemFlag(address) \ + ((MemFlag[((ADDR_T)address) / (8 * sizeof *MemFlag)] >> \ + (address % (8 * sizeof *MemFlag))) & 1) + +#define SetMemFlag(address) \ + (MemFlag[((ADDR_T)address) / (8 * sizeof *MemFlag)] |= \ + (1 << (address % (8 * sizeof *MemFlag)))) + +/* The flag table indicates if there may be a valid routine at the address. + If a flag is set, there cannot be valid routines at the address. */ + +#define IsLabeled(address) \ + ((MemLabel[((ADDR_T)address) / (8 * sizeof *MemLabel)] >> \ + (address % (8 * sizeof *MemLabel))) & 1) + +#define PutLabel(address) \ + (MemLabel[((ADDR_T)address) / (8 * sizeof *MemLabel)] |= \ + (1 << (address % (8 * sizeof *MemLabel)))) + +/* These macros tell if there is a label for a given address, or cause a + label to be produced for an address. */ + +#define IsLowByte(address) \ + ((LowByte[((unsigned char)address) / (8 * sizeof *LowByte)] >> \ + (address % (8 * sizeof *LowByte))) & 1) + +#define PutLowByte(address) \ + (LowByte[((unsigned char)address) / (8 * sizeof *LowByte)] |= \ + (1 << (address % (8 * sizeof *LowByte)))) + +/* Corresponding macros for the low byte address table. */ + +#define IsHighByte(address) \ + ((HighByte[(address >> 8) / (8 * sizeof *HighByte)] >> \ + ((address >> 8) % (8 * sizeof *HighByte))) & 1) + +#define PutHighByte(address) \ + (HighByte[(address >> 8) / (8 * sizeof *HighByte)] |= \ + (1 << ((address >> 8) % (8 * sizeof *HighByte)))) + +/* Corresponding macros for the high byte address table. */ + +/***************************************\ +* Routine/warning address table entries * +\***************************************/ + +typedef struct table +{ + ADDR_T address; + ADDR_T parent; + unsigned char type; +} table; + +/* The table.type byte has the following format: */ + +#define RTN_SURE 0x80 /* address must point to a valid subprogram */ +#define RTN_POTENTIAL 0x81 /* address may point to a valid subprogram (an + address following a conditional branch + instruction) */ +#define RTN_SUSPECTED 0x82 /* address might point to a valid subprogram + (an address encountered during processing + an RTN_POTENTIAL entry) */ +#define RTN_SUSP_POT 0x83 /* address might point to a subprogram (an + address following a conditional branch + instruction that was encountered during + processing an RTN_SUSPECTED or + RTN_POTENTIAL entry) */ +#define RTN_B_TEMPORARY 0x10 /* declares the entry as temporary */ +#define RTN_B_PROCESSED 0x20 /* address seems to point to a valid + subprogram (a successfully processed + RTN_SUSPECTED entry is + RTN_SUSPECTED | RTN_B_PROCESSED) */ + +#define MASK_ANY 0xc0 /* mask for determining the type of the entry */ + +#define RTN_ANY 0x80 /* mask for determining if an entry is a + routine or not */ + +#define WRN_PARAM_WRITTEN_TO 0x40 /* the parameter of the instruction is + written to */ +#define WRN_INSTR_WRITTEN_TO 0x41 /* the instruction is modified by the + program */ + +#define WRN_PARAM_JUMPED_TO 0x42 /* a jump occurs in the middle of the + instruction, e.g. BIT $01A9 */ +#define WRN_RTN_TRUNCATED 0x43 /* the routine is truncated, the rest of + the instructions are retrieved outside + the loaded file (very fatal error) */ +#define WRN_I_ACCESSED 0x44 /* not an actual warning: an unprocessed + memory place is accessed by an + RTN_POTENTIAL or RTN_SUSPECTED routine */ +#define WRN_I_LABEL_NEEDED 0x45 /* not an actual warning: a label will be + needed for this memory place */ + +#define WRN_B_TEMPORARY 0x20 /* mask for determining whether a warning + is temporary and may be deleted later */ + +#define WRN_ANY 0x40 /* mask for determining whether an + entry is a warning or not */ + +#define TBL_DELETED 0 /* the entry may be reused */ + +/*********************\ +* Label table entries * +\*********************/ + +typedef struct label +{ + ADDR_T address; + char *name; +} label; + +/********************\ +* Word table entries * +\********************/ + +typedef struct words +{ + ADDR_T start, end; +} words; + +#ifndef _MAIN_C_ +extern char *prog; +extern ADDR_T StartAddress, EndAddress; +extern int fVerbose; +#else +char *prog; +ADDR_T StartAddress, EndAddress; +int fVerbose = FALSE; +#endif /* _MAIN_C_ */ + +#ifndef _TABLE_C_ +extern unsigned int entrycount; +extern table *scantable; /* table of all warnings generated or routines + encountered */ +#else +unsigned int entrycount = 0; +table *scantable = NULL; +#endif /* _TABLE_C_ */ + +#ifndef _DUMP_C_ +extern int listwidth; /* maximum amount of bytes dumped on a source line */ +#else +int listwidth = 0; +#endif /* _DUMP_C_ */ + +#endif /* _STRUCTURES_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/table.c Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,162 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +/* table.c */ +#define _TABLE_C_ + +#include <stdlib.h> +#include "proto.h" + +static unsigned int firstunused = 0; + +#ifndef __STDC__ +table * +FindNextEntryType (entry, andmask, eormask) + table *entry; + unsigned char andmask; + unsigned char eormask; +#else +table *FindNextEntryType (table *entry, unsigned char andmask, + unsigned char eormask) +#endif +{ + if (!scantable) return NULL; + + if (!entry || entry >= &scantable[entrycount]) + entry = scantable; + else if (++entry >= &scantable[entrycount]) + return NULL; + + for (; entry < &scantable[entrycount]; entry++) + if (entry->type && !((entry->type & andmask) ^ eormask)) + return entry; + + return NULL; +} + +#ifndef __STDC__ +table * +FindNextEntryTypeParent (entry, parent, andmask, eormask) + table *entry; + ADDR_T parent; + unsigned char andmask; + unsigned char eormask; +#else +table *FindNextEntryTypeParent (table *entry, ADDR_T parent, + unsigned char andmask, unsigned char eormask) +#endif +{ + if (!scantable) return NULL; + + + if (!entry || entry >= &scantable[entrycount]) + entry = scantable; + else if (++entry >= &scantable[entrycount]) + return NULL; + + for (; entry < &scantable[entrycount]; entry++) + if (entry->parent == parent && entry->type && + !((entry->type & andmask) ^ eormask)) + return entry; + + return NULL; +} + +#ifndef __STDC__ +table * +FindNextEntry (entry, address, andmask, eormask) + table *entry; + ADDR_T address; + unsigned char andmask; + unsigned char eormask; +#else +table *FindNextEntry (table *entry, ADDR_T address, + unsigned char andmask, unsigned char eormask) +#endif +{ + if (!scantable) return NULL; + + if (!entry || entry >= &scantable[entrycount]) + entry = scantable; + else if (++entry >= &scantable[entrycount]) + return NULL; + + for (; entry < &scantable[entrycount]; entry++) + if (entry->address == address && entry->type && + !((entry->type & andmask) ^ eormask)) + return entry; + + return NULL; +} + +#ifndef __STDC__ +void +AddEntry (address, parent, type) + ADDR_T address; + ADDR_T parent; + unsigned char type; +#else +void AddEntry (ADDR_T address, ADDR_T parent, unsigned char type) +#endif +{ + if (firstunused < entrycount) { + scantable[firstunused].address = address; + scantable[firstunused].parent = parent; + scantable[firstunused].type = type; + + while (++firstunused < entrycount && scantable[firstunused].type); + } + else { + scantable = scantable ? + realloc (scantable, (entrycount + 1) * sizeof *scantable) : + malloc (sizeof *scantable); + + scantable[entrycount].address = address; + scantable[entrycount].parent = parent; + scantable[entrycount].type = type; + + firstunused = ++entrycount; + } +} + +#ifndef __STDC__ +void +DeleteEntry (entry) + table *entry; +#else +void DeleteEntry (table *entry) +#endif +{ + entry -> type = TBL_DELETED; + + if (firstunused > entry - scantable) + firstunused = entry - scantable; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vector.c Tue Feb 24 18:53:52 2015 +0200 @@ -0,0 +1,126 @@ +/*\ + * dxa v0.1.1 -- symbolic 65xx disassembler + * + * Copyright (C) 1993, 1994 Marko M\"akel\"a + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Contacting the author: + * + * Via Internet E-mail: + * <Marko.Makela@FTP.FUNET.FI> + * + * Via Snail Mail: + * Marko M\"akel\"a + * Sillitie 10 A + * FIN-01480 VANTAA + * Finland +\*/ + +#define _VECTOR_C_ + +#include <stdio.h> +#include <stdlib.h> + +#include "proto.h" +#include "options.h" + +unsigned WordCount = 0; +words *WordTable = NULL; + +void AddWordEntry PROTO((ADDR_T start, ADDR_T end)); + +#ifndef __STDC__ +void +AddWordEntry (start, end) + ADDR_T start; + ADDR_T end; +#else +void AddWordEntry (ADDR_T start, ADDR_T end) +#endif +{ + words *entry; + + entry = WordCount ? + realloc (WordTable, (WordCount + 1) * sizeof *entry) : + malloc (sizeof *entry); + + if (!entry) return; + + WordTable = entry; + entry += WordCount++; + entry->start = start; + entry->end = end; +} + +#ifndef __STDC__ +ADDR_T +WordTableEnd (start) + ADDR_T start; +#else +ADDR_T WordTableEnd (ADDR_T start) +#endif +{ + words *entry; + + if (!((entry = &WordTable[WordCount]))) + return start; + + while (entry-- > WordTable) + if (entry->start == start) + return entry->end; + + return start; +} + +#ifndef __STDC__ +void +SearchVectors () +#else +void SearchVectors (void) +#endif +{ + ADDR_T start, end, address; + + if ((Options & M_ADR_TABLES) == O_TBL_IGNORE) return; + + if (fVerbose) + fprintf (stderr, "%s: Searching for address tables.\n", prog); + + for (start = StartAddress; start != EndAddress; start++) { + if (GetMemType (start) != MEM_DATA || !IsLowByte (Memory[start])) + continue; + + for (end = start; (end | 1) != (1 | EndAddress); end += 2) { + if (GetMemType (end) != MEM_DATA || GetMemType (end + 1) != MEM_DATA) + break; + + address = Memory[end] | (Memory[(ADDR_T)(end + 1)] << 8); + + if (!IsLabeled (address)) + break; + + if ((Options & M_ADR_TABLES) == O_TBL_NOEXT && + (ADDR_T)(address - StartAddress) >= + (ADDR_T)(EndAddress - StartAddress)) + break; + } + + if ((ADDR_T)(end - start) > 2) { + AddWordEntry (start, end); + if (EndAddress == (start = end)) break; + } + } +}