diff --git a/README b/README index ae7d12e..d6c19e5 100644 --- a/README +++ b/README @@ -28,4 +28,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/doc/c64-1.oph b/doc/c64-1.oph index 04166dd..0a30520 100644 --- a/doc/c64-1.oph +++ b/doc/c64-1.oph @@ -9,4 +9,4 @@ _next: .word 0 ; End of program .advance 2064 -.require "kernal.oph" \ No newline at end of file +.require "kernal.oph" diff --git a/doc/c64-2.oph b/doc/c64-2.oph index 720ef21..e694c12 100644 --- a/doc/c64-2.oph +++ b/doc/c64-2.oph @@ -37,4 +37,4 @@ _next: .word 0 ; End of program _main: ; Program follows... -.scend \ No newline at end of file +.scend diff --git a/doc/docbook/cmdref.sgm b/doc/docbook/cmdref.sgm index 6dbfb30..e7b4a5a 100644 --- a/doc/docbook/cmdref.sgm +++ b/doc/docbook/cmdref.sgm @@ -249,7 +249,7 @@ .checkpc $100 - +
Macros @@ -400,7 +400,7 @@ code in and of itself, nor does it overwrite anything that previously existed. If you wish to jump ahead in memory, use .advance. - .require filename: Includes the entirety + .require filename: Includes the entirety of the file specified at that point in the program. Unlike .include, however, code included with .require will only be inserted once. The .require directive is useful for ensuring that certain code libraries @@ -447,5 +447,5 @@ macro definition intends to read. A shorthand for .invoke is the name of the macro to invoke, backquoted. -
+ diff --git a/doc/docbook/samplecode.sgm b/doc/docbook/samplecode.sgm index 6d65b07..24d2344 100644 --- a/doc/docbook/samplecode.sgm +++ b/doc/docbook/samplecode.sgm @@ -333,7 +333,7 @@ delay: tax iny bne - dex - bne - + bne - rts diff --git a/doc/docbook/tutor1.sgm b/doc/docbook/tutor1.sgm index 6a754b9..861d1a3 100644 --- a/doc/docbook/tutor1.sgm +++ b/doc/docbook/tutor1.sgm @@ -153,19 +153,19 @@ next: .word 0 ; End of program Labels are defined by putting their name, then a colon, as seen in the definition of next. - + Instead of putting in the hex codes for the string part of the BASIC code, we included the string directly. Each character in the string becomes one byte. - + Instead of adding the buffer ourselves, we used .advance, which outputs zeros until the specified address is reached. Attempting to .advance backwards produces an assemble-time error. - + It has comments that explain what the data are for. The semicolon is the comment marker; everything from a semicolon to the end of the line is ignored. @@ -263,9 +263,9 @@ hello: .byte "HELLO, WORLD!", 0 Option Effect - + - + Allows the 6510 undocumented opcodes as listed in the VICE documentation. Allows opcodes and addressing modes added by the 65C02. Quiet operation. Only reports errors. diff --git a/doc/kernal.oph b/doc/kernal.oph index ea13fad..ec777a8 100644 --- a/doc/kernal.oph +++ b/doc/kernal.oph @@ -64,4 +64,4 @@ ; ...and character set .alias upper'case 142 -.alias lower'case 14 \ No newline at end of file +.alias lower'case 14 diff --git a/doc/tutor1.oph b/doc/tutor1.oph index 6789ce7..e5b6a9d 100644 --- a/doc/tutor1.oph +++ b/doc/tutor1.oph @@ -15,4 +15,4 @@ loop: lda hello, x bne loop done: rts -hello: .byte "HELLO, WORLD!", 0 \ No newline at end of file +hello: .byte "HELLO, WORLD!", 0 diff --git a/doc/tutor2.oph b/doc/tutor2.oph index 27c6682..7a4f436 100644 --- a/doc/tutor2.oph +++ b/doc/tutor2.oph @@ -19,4 +19,4 @@ _next: .word 0 ; End of program bne - * rts -hello: .byte "HELLO, WORLD!", 0 \ No newline at end of file +hello: .byte "HELLO, WORLD!", 0 diff --git a/doc/tutor3.oph b/doc/tutor3.oph index 112e2bf..ead6014 100644 --- a/doc/tutor3.oph +++ b/doc/tutor3.oph @@ -42,4 +42,4 @@ target6: .byte "NATION", 0 target7: .byte "WORLD", 0 target8: .byte "SOLAR SYSTEM", 0 target9: .byte "GALAXY", 0 -target10: .byte "UNIVERSE", 0 \ No newline at end of file +target10: .byte "UNIVERSE", 0 diff --git a/doc/tutor4a.oph b/doc/tutor4a.oph index d218a5f..906cfe6 100644 --- a/doc/tutor4a.oph +++ b/doc/tutor4a.oph @@ -63,7 +63,7 @@ delay: tax bne - dex bne - - - + + rts diff --git a/doc/tutor4b.oph b/doc/tutor4b.oph index 3926965..ab93ead 100644 --- a/doc/tutor4b.oph +++ b/doc/tutor4b.oph @@ -65,7 +65,7 @@ delay: tax bne - dex bne - - - + + rts diff --git a/doc/tutor4c.oph b/doc/tutor4c.oph index f05d023..a84d04a 100644 --- a/doc/tutor4c.oph +++ b/doc/tutor4c.oph @@ -68,6 +68,6 @@ delay: tax bne - dex bne - - - - rts \ No newline at end of file + + + rts diff --git a/doc/tutor5.oph b/doc/tutor5.oph index 8caf839..6e21c57 100644 --- a/doc/tutor5.oph +++ b/doc/tutor5.oph @@ -72,4 +72,4 @@ delay: sta _tmp ; save argument (rdtim destroys it) .checkpc $A000 .data -.checkpc $D000 \ No newline at end of file +.checkpc $D000 diff --git a/doc/tutor6.oph b/doc/tutor6.oph index 60ad8e9..eea3a3c 100644 --- a/doc/tutor6.oph +++ b/doc/tutor6.oph @@ -99,4 +99,4 @@ _done: rts .checkpc $A000 .data -.checkpc $D000 \ No newline at end of file +.checkpc $D000 diff --git a/doc/tutor7.oph b/doc/tutor7.oph index 88ba5bf..f01506a 100644 --- a/doc/tutor7.oph +++ b/doc/tutor7.oph @@ -93,4 +93,4 @@ _done: rts .checkpc $D000 .data zp -.checkpc $80 \ No newline at end of file +.checkpc $80 diff --git a/src/Ophis/CmdLine.py b/src/Ophis/CmdLine.py index aa73170..6beb174 100644 --- a/src/Ophis/CmdLine.py +++ b/src/Ophis/CmdLine.py @@ -6,44 +6,59 @@ import optparse # You may use, modify, and distribute this file under the MIT # license: See README for details. -enable_collapse = True -enable_branch_extend = True -enable_undoc_ops = False -enable_65c02_exts = False +enable_collapse = True +enable_branch_extend = True +enable_undoc_ops = False +enable_65c02_exts = False warn_on_branch_extend = True -print_summary = True -print_loaded_files = False -print_pass = False -print_ir = False -print_labels = False +print_summary = True +print_loaded_files = False +print_pass = False +print_ir = False +print_labels = False + +infile = None +outfile = None -infile = None -outfile = None def parse_args(raw_args): "Populate the module's globals based on the command-line options given." - global enable_collapse, enable_branch_extend, enable_undoc_ops, enable_65c02_exts + global enable_collapse, enable_branch_extend + global enable_undoc_ops, enable_65c02_exts global warn_on_branch_extend - global print_summary, print_loaded_files, print_pass, print_ir, print_labels + global print_summary, print_loaded_files + global print_pass, print_ir, print_labels global infile, outfile - parser = optparse.OptionParser(usage= "Usage: %prog [options] srcfile outfile", version="Ophis 6502 cross-assembler, version 2.0") + parser = optparse.OptionParser( + usage="Usage: %prog [options] srcfile outfile", + version="Ophis 6502 cross-assembler, version 2.0") ingrp = optparse.OptionGroup(parser, "Input options") - ingrp.add_option("-u", "--undoc", action="store_true", default=False, help="Enable 6502 undocumented opcodes") - ingrp.add_option("-c", "--65c02", action="store_true", default=False, dest="c02", help="Enable 65c02 extended instruction set") + ingrp.add_option("-u", "--undoc", action="store_true", default=False, + help="Enable 6502 undocumented opcodes") + ingrp.add_option("-c", "--65c02", action="store_true", default=False, + dest="c02", help="Enable 65c02 extended instruction set") outgrp = optparse.OptionGroup(parser, "Console output options") - outgrp.add_option("-v", "--verbose", action="store_const", const=2, help="Verbose mode", default=1) - outgrp.add_option("-q", "--quiet", action="store_const", help="Quiet mode", dest="verbose", const=0) - outgrp.add_option("-d", "--debug", action="count", dest="verbose", help=optparse.SUPPRESS_HELP) - outgrp.add_option("--no-warn", action="store_false", dest="warn", default=True, help="Do not print warnings") + outgrp.add_option("-v", "--verbose", action="store_const", const=2, + help="Verbose mode", default=1) + outgrp.add_option("-q", "--quiet", action="store_const", help="Quiet mode", + dest="verbose", const=0) + outgrp.add_option("-d", "--debug", action="count", dest="verbose", + help=optparse.SUPPRESS_HELP) + outgrp.add_option("--no-warn", action="store_false", dest="warn", + default=True, help="Do not print warnings") - bingrp = optparse.OptionGroup(parser, "Binary output options") - bingrp.add_option("--no-collapse", action="store_false", dest="enable_collapse", default="True", help="Disable zero-page collapse pass") - bingrp.add_option("--no-branch-extend", action="store_false", dest="enable_branch_extend", default="True", help="Disable branch-extension pass") + bingrp = optparse.OptionGroup(parser, "Compilation options") + bingrp.add_option("--no-collapse", action="store_false", + dest="enable_collapse", default="True", + help="Disable zero-page collapse pass") + bingrp.add_option("--no-branch-extend", action="store_false", + dest="enable_branch_extend", default="True", + help="Disable branch-extension pass") parser.add_option_group(ingrp) parser.add_option_group(outgrp) @@ -60,15 +75,15 @@ def parse_args(raw_args): if options.c02 and options.undoc: parser.error("--undoc and --65c02 are mutually exclusive") - infile = args[0] - outfile = args[1] - enable_collapse = options.enable_collapse - enable_branch_extend = options.enable_branch_extend - enable_undoc_ops = options.undoc - enable_65c02_exts = options.c02 + infile = args[0] + outfile = args[1] + enable_collapse = options.enable_collapse + enable_branch_extend = options.enable_branch_extend + enable_undoc_ops = options.undoc + enable_65c02_exts = options.c02 warn_on_branch_extend = options.warn - print_summary = options.verbose > 0 # no options set - print_loaded_files = options.verbose > 1 # v - print_pass = options.verbose > 2 # dd - print_ir = options.verbose > 3 # ddd - print_labels = options.verbose > 4 # dddd + print_summary = options.verbose > 0 # no options set + print_loaded_files = options.verbose > 1 # v + print_pass = options.verbose > 2 # dd + print_ir = options.verbose > 3 # ddd + print_labels = options.verbose > 4 # dddd diff --git a/src/Ophis/CorePragmas.py b/src/Ophis/CorePragmas.py index 176222c..7087785 100644 --- a/src/Ophis/CorePragmas.py +++ b/src/Ophis/CorePragmas.py @@ -10,46 +10,52 @@ import Ophis.IR as IR import Ophis.Frontend as FE import Ophis.Errors as Err -loadedfiles={} +loadedfiles = {} basecharmap = "".join([chr(x) for x in range(256)]) currentcharmap = basecharmap + def reset(): global loadedfiles, currentcharmap, basecharmap - loadedfiles={} + loadedfiles = {} currentcharmap = basecharmap + def pragmaInclude(ppt, line, result): "Includes a source file" filename = line.expect("STRING").value line.expect("EOL") - if type(filename)==str: result.append(FE.parse_file(ppt, filename)) + if type(filename) == str: + result.append(FE.parse_file(ppt, filename)) + def pragmaRequire(ppt, line, result): "Includes a source file at most one time" filename = line.expect("STRING").value line.expect("EOL") - if type(filename)==str: + if type(filename) == str: global loadedfiles if filename not in loadedfiles: - loadedfiles[filename]=1 + loadedfiles[filename] = True result.append(FE.parse_file(ppt, filename)) + def pragmaIncbin(ppt, line, result): "Includes a binary file" filename = line.expect("STRING").value line.expect("EOL") - if type(filename)==str: + if type(filename) == str: try: f = file(filename, "rb") bytes = f.read() f.close() except IOError: - Err.log ("Could not read "+filename) + Err.log("Could not read " + filename) return bytes = [IR.ConstantExpr(ord(x)) for x in bytes] result.append(IR.Node(ppt, "Byte", *bytes)) + def pragmaCharmap(ppt, line, result): "Modify the character map." global currentcharmap, basecharmap @@ -60,30 +66,33 @@ def pragmaCharmap(ppt, line, result): try: base = bytes[0].data newsubstr = "".join([chr(x.data) for x in bytes[1:]]) - currentcharmap = currentcharmap[:base] + newsubstr + currentcharmap[base+len(newsubstr):] + currentcharmap = currentcharmap[:base] + newsubstr + \ + currentcharmap[base + len(newsubstr):] if len(currentcharmap) != 256 or base < 0 or base > 255: Err.log("Charmap replacement out of range") currentcharmap = currentcharmap[:256] except ValueError: Err.log("Illegal character in .charmap directive") + def pragmaCharmapbin(ppt, line, result): "Load a new character map from a file" global currentcharmap filename = line.expect("STRING").value line.expect("EOL") - if type(filename)==str: + if type(filename) == str: try: f = file(filename, "rb") bytes = f.read() f.close() except IOError: - Err.log ("Could not read "+filename) + Err.log("Could not read " + filename) return - if len(bytes)==256: + if len(bytes) == 256: currentcharmap = bytes else: - Err.log("Character map "+filename+" not 256 bytes long") + Err.log("Character map " + filename + " not 256 bytes long") + def pragmaOrg(ppt, line, result): "Relocates the PC with no output" @@ -91,6 +100,7 @@ def pragmaOrg(ppt, line, result): line.expect("EOL") result.append(IR.Node(ppt, "SetPC", newPC)) + def pragmaAdvance(ppt, line, result): "Outputs filler until reaching the target PC" newPC = FE.parse_expr(line) @@ -102,25 +112,31 @@ def pragmaAdvance(ppt, line, result): line.expect("EOL") result.append(IR.Node(ppt, "Advance", newPC, fillexpr)) + def pragmaCheckpc(ppt, line, result): "Enforces that the PC has not exceeded a certain point" target = FE.parse_expr(line) line.expect("EOL") result.append(IR.Node(ppt, "CheckPC", target)) + def pragmaAlias(ppt, line, result): "Assigns an arbitrary label" lbl = line.expect("LABEL").value target = FE.parse_expr(line) result.append(IR.Node(ppt, "Label", lbl, target)) + def pragmaSpace(ppt, line, result): "Reserves space in a data segment for a variable" lbl = line.expect("LABEL").value size = line.expect("NUM").value line.expect("EOL") result.append(IR.Node(ppt, "Label", lbl, IR.PCExpr())) - result.append(IR.Node(ppt, "SetPC", IR.SequenceExpr([IR.PCExpr(), "+", IR.ConstantExpr(size)]))) + result.append(IR.Node(ppt, "SetPC", + IR.SequenceExpr([IR.PCExpr(), "+", + IR.ConstantExpr(size)]))) + def pragmaText(ppt, line, result): "Switches to a text segment" @@ -132,6 +148,7 @@ def pragmaText(ppt, line, result): segment = "*text-default*" result.append(IR.Node(ppt, "TextSegment", segment)) + def pragmaData(ppt, line, result): "Switches to a data segment (no output allowed)" next = line.expect("LABEL", "EOL") @@ -142,67 +159,80 @@ def pragmaData(ppt, line, result): segment = "*data-default*" result.append(IR.Node(ppt, "DataSegment", segment)) + def readData(line): "Read raw data from a comma-separated list" if line.lookahead(0).type == "STRING": - data = [IR.ConstantExpr(ord(x)) for x in line.expect("STRING").value.translate(currentcharmap)] + data = [IR.ConstantExpr(ord(x)) + for x in line.expect("STRING").value.translate(currentcharmap)] else: data = [FE.parse_expr(line)] next = line.expect(',', 'EOL').type while next == ',': if line.lookahead(0).type == "STRING": - data.extend([IR.ConstantExpr(ord(x)) for x in line.expect("STRING").value]) + data.extend([IR.ConstantExpr(ord(x)) + for x in line.expect("STRING").value]) else: data.append(FE.parse_expr(line)) next = line.expect(',', 'EOL').type return data + def pragmaByte(ppt, line, result): "Raw data, a byte at a time" bytes = readData(line) result.append(IR.Node(ppt, "Byte", *bytes)) + def pragmaWord(ppt, line, result): "Raw data, a word at a time, little-endian" words = readData(line) result.append(IR.Node(ppt, "Word", *words)) + def pragmaDword(ppt, line, result): "Raw data, a double-word at a time, little-endian" dwords = readData(line) result.append(IR.Node(ppt, "Dword", *dwords)) + def pragmaWordbe(ppt, line, result): "Raw data, a word at a time, big-endian" words = readData(line) result.append(IR.Node(ppt, "WordBE", *words)) + def pragmaDwordbe(ppt, line, result): "Raw data, a dword at a time, big-endian" dwords = readData(line) result.append(IR.Node(ppt, "DwordBE", *dwords)) + def pragmaScope(ppt, line, result): "Create a new lexical scoping block" line.expect("EOL") result.append(IR.Node(ppt, "ScopeBegin")) + def pragmaScend(ppt, line, result): "End the innermost lexical scoping block" line.expect("EOL") result.append(IR.Node(ppt, "ScopeEnd")) + def pragmaMacro(ppt, line, result): "Begin a macro definition" lbl = line.expect("LABEL").value line.expect("EOL") result.append(IR.Node(ppt, "MacroBegin", lbl)) + def pragmaMacend(ppt, line, result): "End a macro definition" line.expect("EOL") result.append(IR.Node(ppt, "MacroEnd")) + def pragmaInvoke(ppt, line, result): macro = line.expect("LABEL").value if line.lookahead(0).type == "EOL": diff --git a/src/Ophis/Environment.py b/src/Ophis/Environment.py index 0450262..ec4e201 100644 --- a/src/Ophis/Environment.py +++ b/src/Ophis/Environment.py @@ -9,6 +9,7 @@ import Ophis.Errors as Err + class Environment(object): """Environment class. Controls the various scopes and global abstract execution variables.""" @@ -19,39 +20,52 @@ class Environment(object): self.segmentdict = {} self.segment = "*text-default*" self.scopecount = 0 + def __contains__(self, item): if item[0] == '_': for dict in [self.dicts[i] for i in self.stack]: - if item in dict: return 1 - return 0 + if item in dict: + return True + return False return item in self.dicts[0] + def __getitem__(self, item): if item[0] == '_': for dict in [self.dicts[i] for i in self.stack]: - if item in dict: return dict[item] + if item in dict: + return dict[item] else: - if item in self.dicts[0]: return self.dicts[0][item] + if item in self.dicts[0]: + return self.dicts[0][item] Err.log("Unknown label '%s'" % item) return 0 + def __setitem__(self, item, value): if item[0] == '_': self.dicts[self.stack[0]][item] = value else: self.dicts[0][item] = value + def __str__(self): return str(self.dicts) + def getPC(self): return self.pc + def setPC(self, value): self.pc = value + def incPC(self, amount): self.pc += amount + def getsegment(self): return self.segment + def setsegment(self, segment): self.segmentdict[self.segment] = self.pc self.segment = segment self.pc = self.segmentdict.get(segment, 0) + def reset(self): "Clears out program counter, segment, and scoping information" self.pc = 0 @@ -61,14 +75,16 @@ class Environment(object): if len(self.stack) > 1: Err.log("Unmatched .scope") self.stack = [0] + def newscope(self): "Enters a new scope for temporary labels." self.scopecount += 1 self.stack.insert(0, self.scopecount) - if len(self.dicts) <= self.scopecount: self.dicts.append({}) + if len(self.dicts) <= self.scopecount: + self.dicts.append({}) + def endscope(self): "Leaves a scope." if len(self.stack) == 1: Err.log("Unmatched .scend") self.stack.pop(0) - diff --git a/src/Ophis/Errors.py b/src/Ophis/Errors.py index bdc9d65..88f37e0 100644 --- a/src/Ophis/Errors.py +++ b/src/Ophis/Errors.py @@ -12,15 +12,20 @@ import sys count = 0 currentpoint = "" + def log(err): """Reports an error at the current program point, and increases the global error count.""" global count - count = count+1 - print>>sys.stderr, currentpoint+": "+err + count = count + 1 + print>>sys.stderr, currentpoint + ": " + err + def report(): "Print out the number of errors." - if count == 0: print>>sys.stderr, "No errors" - elif count == 1: print>>sys.stderr, "1 error" - else: print>>sys.stderr, str(count)+" errors" + if count == 0: + print>>sys.stderr, "No errors" + elif count == 1: + print>>sys.stderr, "1 error" + else: + print>>sys.stderr, str(count) + " errors" diff --git a/src/Ophis/Frontend.py b/src/Ophis/Frontend.py index 38c03a9..f8176ce 100644 --- a/src/Ophis/Frontend.py +++ b/src/Ophis/Frontend.py @@ -13,35 +13,44 @@ import os # You may use, modify, and distribute this file under the MIT # license: See README for details. + class Lexeme(object): "Class for lexer tokens. Used by lexer and parser." def __init__(self, type="UNKNOWN", value=None): self.type = type.upper() self.value = value + def __str__(self): - if self.value == None: + if self.value is None: return self.type else: - return self.type+":"+str(self.value) + return self.type + ":" + str(self.value) + def __repr__(self): - return "Lexeme("+`self.type`+", "+`self.value`+")" + return "Lexeme(" + repr(self.type) + ", " + repr(self.value) + ")" + def matches(self, other): "1 if Lexemes a and b have the same type." return self.type == other.type -bases = {"$":("hexadecimal", 16), - "%":("binary", 2), - "0":("octal", 8)} + +bases = {"$": ("hexadecimal", 16), + "%": ("binary", 2), + "0": ("octal", 8)} + punctuation = "#,`<>():.+-*/&|^[]" + def lex(point, line): """Turns a line of source into a sequence of lexemes.""" Err.currentpoint = point result = [] + def is_opcode(op): "Tests whether a string is an opcode or an identifier" return op in Ops.opcodes + def add_token(token): "Converts a substring into a single lexeme" if token == "": @@ -59,7 +68,8 @@ def lex(point, line): result.append(Lexeme("NUM", long(rest, bases[firstchar][1]))) return except ValueError: - Err.log('Invalid '+bases[firstchar][0]+' constant: '+rest) + Err.log('Invalid ' + bases[firstchar][0] + ' constant: ' + + rest) result.append(Lexeme("NUM", 0)) return elif firstchar.isdigit(): @@ -73,12 +83,12 @@ def lex(point, line): if len(rest) == 1: result.append(Lexeme("NUM", ord(rest))) else: - Err.log("Invalid character constant '"+rest+"'") + Err.log("Invalid character constant '" + rest + "'") result.append(Lexeme("NUM", 0)) return elif firstchar in punctuation: if rest != "": - Err.log("Internal lexer error! '"+token+"' can't happen!") + Err.log("Internal lexer error! '" + token + "' can't happen!") result.append(Lexeme(firstchar)) return else: # Label, opcode, or index register @@ -94,22 +104,24 @@ def lex(point, line): return # should never reach here Err.log("Internal lexer error: add_token fall-through") + def add_EOL(): "Adds an end-of-line lexeme" result.append(Lexeme("EOL")) + # Actual routine begins here value = "" - quotemode = 0 - backslashmode = 0 + quotemode = False + backslashmode = False for c in line.strip(): if backslashmode: - backslashmode = 0 + backslashmode = False value = value + c elif c == "\\": - backslashmode = 1 + backslashmode = True elif quotemode: if c == '"': - quotemode = 0 + quotemode = False else: value = value + c elif c == ';': @@ -126,7 +138,7 @@ def lex(point, line): elif c == '"': add_token(value) value = '"' - quotemode = 1 + quotemode = True else: value = value + c if backslashmode: @@ -137,35 +149,45 @@ def lex(point, line): add_EOL() return result + class ParseLine(object): - "Maintains the parse state of a line of code. Enables arbitrary lookahead." + "Maintains the parse state of a line of code. Enables arbitrary lookahead." + def __init__(self, lexemes): self.lexemes = lexemes self.location = 0 + def lookahead(self, i): - """Returns the token i units ahead in the parse. - lookahead(0) returns the next token; trying to read off the end of + """Returns the token i units ahead in the parse. + lookahead(0) returns the next token; trying to read off the end of the sequence returns the last token in the sequence (usually EOL).""" - target = self.location+i - if target >= len(self.lexemes): target = -1 + target = self.location + i + if target >= len(self.lexemes): + target = -1 return self.lexemes[target] + def pop(self): "Returns and removes the next element in the line." old = self.location - if self.location < len(self.lexemes)-1: self.location += 1 + if self.location < len(self.lexemes) - 1: + self.location += 1 return self.lexemes[old] + def expect(self, *tokens): - """Reads a token from the ParseLine line and returns it if it's of a type - in the sequence tokens. Otherwise, it logs an error.""" + """Reads a token from the ParseLine line and returns it if it's of a + type in the sequence tokens. Otherwise, it logs an error.""" token = self.pop() - if token.type not in tokens: - Err.log('Expected: "'+'", "'.join(tokens)+'"') + if token.type not in tokens: + Err.log('Expected: "' + '", "'.join(tokens) + '"') return token + pragma_modules = [] + def parse_expr(line): "Parses an Ophis arithmetic expression." + def atom(): "Parses lowest-priority expression components." next = line.lookahead(0).type @@ -187,14 +209,14 @@ def parse_expr(line): offset += 1 line.expect("+") next = line.lookahead(0).type - return IR.LabelExpr("*"+str(templabelcount+offset)) + return IR.LabelExpr("*" + str(templabelcount + offset)) elif next == "-": offset = 1 while next == "-": offset -= 1 line.expect("-") next = line.lookahead(0).type - return IR.LabelExpr("*"+str(templabelcount+offset)) + return IR.LabelExpr("*" + str(templabelcount + offset)) elif next == ">": line.expect(">") return IR.HighByteExpr(atom()) @@ -203,6 +225,7 @@ def parse_expr(line): return IR.LowByteExpr(atom()) else: Err.log('Expected: expression') + def precedence_read(constructor, reader, separators): """Handles precedence. The reader argument is a function that returns expressions that bind more tightly than these; separators is a list @@ -218,51 +241,60 @@ def parse_expr(line): result.append(nextop) result.append(reader()) nextop = line.lookahead(0).type - if len(result) == 1: return result[0] + if len(result) == 1: + return result[0] return constructor(result) + def term(): "Parses * and /" return precedence_read(IR.SequenceExpr, atom, ["*", "/"]) + def arith(): "Parses + and -" return precedence_read(IR.SequenceExpr, term, ["+", "-"]) + def bits(): "Parses &, |, and ^" return precedence_read(IR.SequenceExpr, arith, ["&", "|", "^"]) + return bits() + def parse_line(ppt, lexemelist): "Turn a line of source into an IR Node." Err.currentpoint = ppt result = [] line = ParseLine(lexemelist) + def aux(): "Accumulates all IR nodes defined by this line." if line.lookahead(0).type == "EOL": pass elif line.lookahead(1).type == ":": - newlabel=line.expect("LABEL").value + newlabel = line.expect("LABEL").value line.expect(":") result.append(IR.Node(ppt, "Label", newlabel, IR.PCExpr())) aux() elif line.lookahead(0).type == "*": global templabelcount templabelcount = templabelcount + 1 - result.append(IR.Node(ppt, "Label", "*"+str(templabelcount), IR.PCExpr())) + result.append(IR.Node(ppt, "Label", "*" + str(templabelcount), + IR.PCExpr())) line.expect("*") aux() elif line.lookahead(0).type == "." or line.lookahead(0).type == "`": which = line.expect(".", "`").type - if (which == "."): pragma = line.expect("LABEL").value - else: pragma = "invoke" - pragmaFunction = "pragma"+pragma.title() + if (which == "."): + pragma = line.expect("LABEL").value + else: + pragma = "invoke" + pragmaFunction = "pragma" + pragma.title() for mod in pragma_modules: if hasattr(mod, pragmaFunction): getattr(mod, pragmaFunction)(ppt, line, result) break else: - Err.log("Unknown pragma "+pragma) - + Err.log("Unknown pragma " + pragma) else: # Instruction opcode = line.expect("OPCODE").value if line.lookahead(0).type == "#": @@ -296,23 +328,30 @@ def parse_line(ppt, lexemelist): tok = line.expect("EOL", ",").type if tok == ",": tok = line.expect("X", "Y").type - if tok == "X": mode = "MemoryX" - else: mode = "MemoryY" + if tok == "X": + mode = "MemoryX" + else: + mode = "MemoryY" line.expect("EOL") - else: mode = "Memory" + else: + mode = "Memory" result.append(IR.Node(ppt, mode, opcode, arg)) + aux() result = [node for node in result if node is not IR.NullNode] - if len(result) == 0: return IR.NullNode - if len(result) == 1: return result[0] + if len(result) == 0: + return IR.NullNode + if len(result) == 1: + return result[0] return IR.SequenceNode(ppt, result) + def parse_file(ppt, filename): "Loads an Ophis source file, and returns an IR list." Err.currentpoint = ppt if Cmd.print_loaded_files: if filename != '-': - print>>sys.stderr, "Loading "+filename + print>>sys.stderr, "Loading " + filename else: print>>sys.stderr, "Loading from standard input" try: @@ -322,18 +361,19 @@ def parse_file(ppt, filename): f.close() else: linelist = sys.stdin.readlines() - pptlist = ["%s:%d" % (filename, i+1) for i in range(len(linelist))] + pptlist = ["%s:%d" % (filename, i + 1) for i in range(len(linelist))] lexlist = map(lex, pptlist, linelist) IRlist = map(parse_line, pptlist, lexlist) IRlist = [node for node in IRlist if node is not IR.NullNode] return IR.SequenceNode(ppt, IRlist) except IOError: - Err.log ("Could not read "+filename) + Err.log("Could not read " + filename) return IR.NullNode + def parse(filename): - "Top level parsing routine, taking a source file name and returning an IR list." + """Top level parsing routine, taking a source file name + and returning an IR list.""" global templabelcount templabelcount = 0 return parse_file("", filename) - diff --git a/src/Ophis/IR.py b/src/Ophis/IR.py index 40fe818..2250541 100644 --- a/src/Ophis/IR.py +++ b/src/Ophis/IR.py @@ -9,6 +9,7 @@ import Ophis.Errors as Err + class Node(object): """The default IR Node Instances of Node always have the three fields ppt(Program Point), @@ -17,27 +18,35 @@ class Node(object): self.ppt = ppt self.nodetype = nodetype self.data = list(data) + def accept(self, asmpass, env=None): """Implements the Visitor pattern for an assembler pass. - Calls the routine 'asmpass.visitTYPE(self, env)' where + Calls the routine 'asmpass.visitTYPE(self, env)' where TYPE is the value of self.nodetype.""" Err.currentpoint = self.ppt - routine = getattr(asmpass, "visit"+self.nodetype, asmpass.visitUnknown) + routine = getattr(asmpass, "visit" + self.nodetype, + asmpass.visitUnknown) routine(self, env) + def __str__(self): if self.nodetype != "SEQUENCE": - return str(self.ppt)+": "+self.nodetype+" - "+" ".join(map(str, self.data)) + return str(self.ppt) + ": " + self.nodetype + " - " + \ + " ".join(map(str, self.data)) else: return "\n".join(map(str, self.data)) + def __repr__(self): args = [self.ppt, self.nodetype] + self.data return "Node(" + ", ".join(map(repr, args)) + ")" + NullNode = Node("", "None") + def SequenceNode(ppt, nodelist): return Node(ppt, "SEQUENCE", *nodelist) + class Expr(object): """Base class for Ophis expressions All expressions have a field called "data" and a boolean field @@ -45,78 +54,102 @@ class Expr(object): symbolic values in it.""" def __init__(self, data): self.data = data - self.hardcoded = 0 + self.hardcoded = False + def __str__(self): - return "" - def valid(self, env=None, PCvalid=0): + return "" + + def valid(self, env=None, PCvalid=False): """Returns true if the the expression can be successfully evaluated in the specified environment.""" - return 0 + return False + def value(self, env=None): "Evaluates this expression in the given environment." return None + class ConstantExpr(Expr): "Represents a numeric constant" def __init__(self, data): self.data = data - self.hardcoded = 1 + self.hardcoded = True + def __str__(self): return str(self.data) - def valid(self, env=None, PCvalid=0): - return 1 + + def valid(self, env=None, PCvalid=False): + return True + def value(self, env=None): return self.data + class LabelExpr(Expr): "Represents a symbolic constant" def __init__(self, data): self.data = data - self.hardcoded = 0 + self.hardcoded = False + def __str__(self): return self.data - def valid(self, env=None, PCvalid=0): + + def valid(self, env=None, PCvalid=False): return (env is not None) and self.data in env + def value(self, env=None): return env[self.data] + class PCExpr(Expr): "Represents the current program counter: ^" def __init__(self): - self.hardcoded = 0 + self.hardcoded = False + def __str__(self): return "^" - def valid(self, env=None, PCvalid=0): + + def valid(self, env=None, PCvalid=False): return env is not None and PCvalid + def value(self, env=None): return env.getPC() + class HighByteExpr(Expr): "Represents the expression >{data}" def __init__(self, data): self.data = data self.hardcoded = data.hardcoded + def __str__(self): - return ">"+str(self.data) - def valid(self, env=None, PCvalid=0): + return ">" + str(self.data) + + def valid(self, env=None, PCvalid=False): return self.data.valid(env, PCvalid) + def value(self, env=None): val = self.data.value(env) return (val >> 8) & 0xff - + + class LowByteExpr(Expr): "Represents the expression <{data}" def __init__(self, data): self.data = data self.hardcoded = data.hardcoded + def __str__(self): - return "<"+str(self.data) - def valid(self, env=None, PCvalid=0): + return "<" + str(self.data) + + def valid(self, env=None, PCvalid=False): return self.data.valid(env, PCvalid) + def value(self, env=None): val = self.data.value(env) return val & 0xff + class SequenceExpr(Expr): """Represents an interleaving of operands (of type Expr) and operators (of type String). Subclasses must provide a routine @@ -128,20 +161,23 @@ class SequenceExpr(Expr): [Expr, str, Expr, str, Expr, str, ... Expr, str, Expr].""" self.data = data self.operands = [x for x in data if isinstance(x, Expr)] - self.operators = [x for x in data if type(x)==str] + self.operators = [x for x in data if type(x) == str] for i in self.operands: if not i.hardcoded: - self.hardcoded = 0 + self.hardcoded = False break else: - self.hardcoded = 1 + self.hardcoded = True + def __str__(self): - return "["+" ".join(map(str, self.data))+"]" - def valid(self, env=None, PCvalid=0): + return "[" + " ".join(map(str, self.data)) + "]" + + def valid(self, env=None, PCvalid=False): for i in self.operands: if not i.valid(env, PCvalid): - return 0 - return 1 + return False + return True + def value(self, env=None): subs = map((lambda x: x.value(env)), self.operands) result = subs[0] @@ -150,11 +186,19 @@ class SequenceExpr(Expr): result = self.operate(result, op, subs[index]) index += 1 return result + def operate(self, start, op, other): - if op=="*": return start * other - if op=="/": return start // other - if op=="+": return start + other - if op=="-": return start - other - if op=="&": return start & other - if op=="|": return start | other - if op=="^": return start ^ other + if op == "*": + return start * other + if op == "/": + return start // other + if op == "+": + return start + other + if op == "-": + return start - other + if op == "&": + return start & other + if op == "|": + return start | other + if op == "^": + return start ^ other diff --git a/src/Ophis/Macro.py b/src/Ophis/Macro.py index ee3a68f..65b0017 100644 --- a/src/Ophis/Macro.py +++ b/src/Ophis/Macro.py @@ -18,6 +18,7 @@ macros = {} currentname = None currentbody = None + def newMacro(name): "Start creating a new macro with the specified name." global currentname @@ -31,10 +32,12 @@ def newMacro(name): currentname = name currentbody = [] + def registerNode(node): global currentbody currentbody.append(IR.Node(node.ppt, node.nodetype, *node.data)) + def endMacro(): global currentname global currentbody @@ -46,21 +49,29 @@ def endMacro(): currentname = None currentbody = None + def expandMacro(ppt, name, arglist): global macros if name not in macros: Err.log("Undefined macro '%s'" % name) return IR.NullNode - argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg) for (i, arg) in zip(xrange(1, sys.maxint), arglist)] - bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i)) for i in range(1, len(arglist)+1)] - body = [IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data) for node in macros[name]] - invocation = [IR.Node(ppt, "ScopeBegin")] + argexprs + [IR.Node(ppt, "ScopeBegin")] + bindexprs + body + [IR.Node(ppt, "ScopeEnd"), IR.Node(ppt, "ScopeEnd")] + argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg) + for (i, arg) in zip(xrange(1, sys.maxint), arglist)] + bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i)) + for i in range(1, len(arglist) + 1)] + body = [IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data) + for node in macros[name]] + invocation = [IR.Node(ppt, "ScopeBegin")] + argexprs + \ + [IR.Node(ppt, "ScopeBegin")] + bindexprs + body + \ + [IR.Node(ppt, "ScopeEnd"), IR.Node(ppt, "ScopeEnd")] return IR.SequenceNode(ppt, invocation) + def dump(): global macros for mac in macros: body = macros[mac] - print>>sys.stderr, "Macro: "+mac - for node in body: print>>sys.stderr, node + print>>sys.stderr, "Macro: " + mac + for node in body: + print>>sys.stderr, node print>>sys.stderr, "" diff --git a/src/Ophis/Main.py b/src/Ophis/Main.py index c439f32..f66bf08 100644 --- a/src/Ophis/Main.py +++ b/src/Ophis/Main.py @@ -17,6 +17,7 @@ import Ophis.Environment import Ophis.CmdLine import Ophis.Opcodes + def run_all(infile, outfile): "Transforms the source infile to a binary outfile." Err.count = 0 @@ -26,21 +27,31 @@ def run_all(infile, outfile): m = Ophis.Passes.ExpandMacros() i = Ophis.Passes.InitLabels() l_basic = Ophis.Passes.UpdateLabels() - l = Ophis.Passes.FixPoint("label update", [l_basic], lambda: l_basic.changed == 0) + l = Ophis.Passes.FixPoint("label update", [l_basic], + lambda: not l_basic.changed) c_basic = Ophis.Passes.Collapse() - c = Ophis.Passes.FixPoint("instruction selection 1", [l, c_basic], lambda: c_basic.collapsed == 0) + c = Ophis.Passes.FixPoint("instruction selection 1", [l, c_basic], + lambda: not c_basic.changed) b = Ophis.Passes.ExtendBranches() a = Ophis.Passes.Assembler() passes = [] passes.append(Ophis.Passes.DefineMacros()) - passes.append(Ophis.Passes.FixPoint("macro expansion", [m], lambda: m.changed == 0)) - passes.append(Ophis.Passes.FixPoint("label initialization", [i], lambda: i.changed == 0)) - passes.extend([Ophis.Passes.CircularityCheck(), Ophis.Passes.CheckExprs(), Ophis.Passes.EasyModes()]) - passes.append(Ophis.Passes.FixPoint("instruction selection 2", [c, b], lambda: b.expanded == 0)) - passes.extend([Ophis.Passes.NormalizeModes(), Ophis.Passes.UpdateLabels(), a]) + passes.append(Ophis.Passes.FixPoint("macro expansion", [m], + lambda: not m.changed)) + passes.append(Ophis.Passes.FixPoint("label initialization", [i], + lambda: not i.changed)) + passes.extend([Ophis.Passes.CircularityCheck(), + Ophis.Passes.CheckExprs(), + Ophis.Passes.EasyModes()]) + passes.append(Ophis.Passes.FixPoint("instruction selection 2", [c, b], + lambda: not b.changed)) + passes.extend([Ophis.Passes.NormalizeModes(), + Ophis.Passes.UpdateLabels(), + a]) - for p in passes: p.go(z, env) + for p in passes: + p.go(z, env) if Err.count == 0: try: @@ -53,10 +64,11 @@ def run_all(infile, outfile): if outfile != '-': output.close() except IOError: - print>>sys.stderr, "Could not write to "+outfile + print>>sys.stderr, "Could not write to " + outfile else: Err.report() + def run_ophis(args): Ophis.CmdLine.parse_args(args) Ophis.Frontend.pragma_modules.append(Ophis.CorePragmas) @@ -69,5 +81,6 @@ def run_ophis(args): Ophis.CorePragmas.reset() run_all(Ophis.CmdLine.infile, Ophis.CmdLine.outfile) + if __name__ == '__main__': run_ophis(sys.argv[1:]) diff --git a/src/Ophis/Opcodes.py b/src/Ophis/Opcodes.py index 4ff55af..0be2676 100644 --- a/src/Ophis/Opcodes.py +++ b/src/Ophis/Opcodes.py @@ -12,162 +12,291 @@ # the tables in tools/opcodes. Edit those tables, not these. # Names of addressing modes -modes = ["Implied", # 0 - "Immediate", # 1 - "Zero Page", # 2 - "Zero Page, X", # 3 - "Zero Page, Y", # 4 - "Absolute", # 5 - "Absolute, X", # 6 - "Absolute, Y", # 7 - "(Absolute)", # 8 - "(Absolute, X)", # 9 +modes = ["Implied", # 0 + "Immediate", # 1 + "Zero Page", # 2 + "Zero Page, X", # 3 + "Zero Page, Y", # 4 + "Absolute", # 5 + "Absolute, X", # 6 + "Absolute, Y", # 7 + "(Absolute)", # 8 + "(Absolute, X)", # 9 "(Absolute), Y", # 10 "(Zero Page)", # 11 "(Zero Page, X)", # 12 "(Zero Page), Y", # 13 "Relative"] # 14 + # Lengths of the argument lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1] opcodes = { - 'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, None, None, None, None, 0x61, 0x71, None], - 'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, None, None, None, None, 0x21, 0x31, None], - 'asl': [0x0A, None, 0x06, 0x16, None, 0x0E, 0x1E, None, None, None, None, None, None, None, None], - 'bcc': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x90], - 'bcs': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xB0], - 'beq': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xF0], - 'bit': [None, None, 0x24, None, None, 0x2C, None, None, None, None, None, None, None, None, None], - 'bmi': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x30], - 'bne': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xD0], - 'bpl': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x10], - 'brk': [0x00, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'bvc': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x50], - 'bvs': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x70], - 'clc': [0x18, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'cld': [0xD8, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'cli': [0x58, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'clv': [0xB8, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, None, None, None, None, 0xC1, 0xD1, None], - 'cpx': [None, 0xE0, 0xE4, None, None, 0xEC, None, None, None, None, None, None, None, None, None], - 'cpy': [None, 0xC0, 0xC4, None, None, 0xCC, None, None, None, None, None, None, None, None, None], - 'dec': [None, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, None, None, None, None, None, None, None], - 'dex': [0xCA, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'dey': [0x88, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, None, None, None, None, 0x41, 0x51, None], - 'inc': [None, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, None, None, None, None, None, None, None], - 'inx': [0xE8, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'iny': [0xC8, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'jmp': [None, None, None, None, None, 0x4C, None, None, 0x6C, None, None, None, None, None, None], - 'jsr': [None, None, None, None, None, 0x20, None, None, None, None, None, None, None, None, None], - 'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, None, None, None, None, 0xA1, 0xB1, None], - 'ldx': [None, 0xA2, 0xA6, None, 0xB6, 0xAE, None, 0xBE, None, None, None, None, None, None, None], - 'ldy': [None, 0xA0, 0xA4, 0xB4, None, 0xAC, 0xBC, None, None, None, None, None, None, None, None], - 'lsr': [0x4A, None, 0x46, 0x56, None, 0x4E, 0x5E, None, None, None, None, None, None, None, None], - 'nop': [0xEA, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, None, None, None, None, 0x01, 0x11, None], - 'pha': [0x48, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'php': [0x08, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'pla': [0x68, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'plp': [0x28, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'rol': [0x2A, None, 0x26, 0x36, None, 0x2E, 0x3E, None, None, None, None, None, None, None, None], - 'ror': [0x6A, None, 0x66, 0x76, None, 0x6E, 0x7E, None, None, None, None, None, None, None, None], - 'rti': [0x40, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'rts': [0x60, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, None, None, None, None, 0xE1, 0xF1, None], - 'sec': [0x38, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'sed': [0xF8, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'sei': [0x78, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, None, None, None, None, 0x81, 0x91, None], - 'stx': [None, None, 0x86, None, 0x96, 0x8E, None, None, None, None, None, None, None, None, None], - 'sty': [None, None, 0x84, 0x94, None, 0x8C, None, None, None, None, None, None, None, None, None], - 'tax': [0xAA, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'tay': [0xA8, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'tsx': [0xBA, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'txa': [0x8A, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'txs': [0x9A, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'tya': [0x98, None, None, None, None, None, None, None, None, None, None, None, None, None, None], + 'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, + None, None, None, None, 0x61, 0x71, None], + 'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, + None, None, None, None, 0x21, 0x31, None], + 'asl': [0x0A, None, 0x06, 0x16, None, 0x0E, 0x1E, None, + None, None, None, None, None, None, None], + 'bcc': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x90], + 'bcs': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xB0], + 'beq': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xF0], + 'bit': [None, None, 0x24, None, None, 0x2C, None, None, + None, None, None, None, None, None, None], + 'bmi': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x30], + 'bne': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xD0], + 'bpl': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x10], + 'brk': [0x00, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'bvc': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x50], + 'bvs': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x70], + 'clc': [0x18, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'cld': [0xD8, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'cli': [0x58, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'clv': [0xB8, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, + None, None, None, None, 0xC1, 0xD1, None], + 'cpx': [None, 0xE0, 0xE4, None, None, 0xEC, None, None, + None, None, None, None, None, None, None], + 'cpy': [None, 0xC0, 0xC4, None, None, 0xCC, None, None, + None, None, None, None, None, None, None], + 'dec': [None, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, + None, None, None, None, None, None, None], + 'dex': [0xCA, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'dey': [0x88, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, + None, None, None, None, 0x41, 0x51, None], + 'inc': [None, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, + None, None, None, None, None, None, None], + 'inx': [0xE8, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'iny': [0xC8, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'jmp': [None, None, None, None, None, 0x4C, None, None, + 0x6C, None, None, None, None, None, None], + 'jsr': [None, None, None, None, None, 0x20, None, None, + None, None, None, None, None, None, None], + 'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, + None, None, None, None, 0xA1, 0xB1, None], + 'ldx': [None, 0xA2, 0xA6, None, 0xB6, 0xAE, None, 0xBE, + None, None, None, None, None, None, None], + 'ldy': [None, 0xA0, 0xA4, 0xB4, None, 0xAC, 0xBC, None, + None, None, None, None, None, None, None], + 'lsr': [0x4A, None, 0x46, 0x56, None, 0x4E, 0x5E, None, + None, None, None, None, None, None, None], + 'nop': [0xEA, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, + None, None, None, None, 0x01, 0x11, None], + 'pha': [0x48, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'php': [0x08, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'pla': [0x68, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'plp': [0x28, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rol': [0x2A, None, 0x26, 0x36, None, 0x2E, 0x3E, None, + None, None, None, None, None, None, None], + 'ror': [0x6A, None, 0x66, 0x76, None, 0x6E, 0x7E, None, + None, None, None, None, None, None, None], + 'rti': [0x40, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rts': [0x60, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, + None, None, None, None, 0xE1, 0xF1, None], + 'sec': [0x38, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sed': [0xF8, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sei': [0x78, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, + None, None, None, None, 0x81, 0x91, None], + 'stx': [None, None, 0x86, None, 0x96, 0x8E, None, None, + None, None, None, None, None, None, None], + 'sty': [None, None, 0x84, 0x94, None, 0x8C, None, None, + None, None, None, None, None, None, None], + 'tax': [0xAA, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'tay': [0xA8, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'tsx': [0xBA, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'txa': [0x8A, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'txs': [0x9A, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'tya': [0x98, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], } - undocops = { - 'anc': [None, 0x0B, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'ane': [None, 0x8B, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'arr': [None, 0x6B, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'asr': [None, 0x4B, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'dcp': [None, None, 0xC7, 0xD7, None, 0xCF, 0xDF, 0xDB, None, None, None, None, 0xC3, 0xD3, None], - 'isb': [None, None, 0xE7, 0xF7, None, 0xEF, 0xFF, 0xFB, None, None, None, None, 0xE3, 0xF3, None], - 'las': [None, None, None, None, None, None, None, 0xBB, None, None, None, None, None, None, None], - 'lax': [None, None, 0xA7, None, 0xB7, 0xAF, None, 0xBF, None, None, None, None, 0xA3, 0xB3, None], - 'lxa': [None, 0xAB, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'nop': [0xEA, None, 0x04, None, None, None, None, None, None, None, None, None, None, None, None], - 'rla': [None, None, 0x27, 0x37, None, 0x2F, 0x3F, 0x3B, None, None, None, None, 0x23, 0x33, None], - 'rra': [None, None, 0x67, 0x77, None, 0x6F, 0x7F, 0x7B, None, None, None, None, 0x63, 0x73, None], - 'sax': [None, None, 0x87, None, 0x97, 0x8F, None, None, None, None, None, None, 0x83, None, None], - 'sbx': [None, 0xCB, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'sha': [None, None, None, None, None, None, None, 0x9F, None, None, None, None, None, 0x93, None], - 'shs': [None, None, None, None, None, None, None, 0x9B, None, None, None, None, None, None, None], - 'shx': [None, None, None, None, None, None, None, 0x9E, None, None, None, None, None, None, None], - 'slo': [None, None, 0x07, 0x17, None, 0x0F, 0x1F, 0x1B, None, None, None, None, 0x03, 0x13, None], - 'sre': [None, None, 0x47, 0x57, None, 0x4F, 0x5F, 0x5B, None, None, None, None, 0x43, 0x53, None], + 'anc': [None, 0x0B, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'ane': [None, 0x8B, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'arr': [None, 0x6B, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'asr': [None, 0x4B, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'dcp': [None, None, 0xC7, 0xD7, None, 0xCF, 0xDF, 0xDB, + None, None, None, None, 0xC3, 0xD3, None], + 'isb': [None, None, 0xE7, 0xF7, None, 0xEF, 0xFF, 0xFB, + None, None, None, None, 0xE3, 0xF3, None], + 'las': [None, None, None, None, None, None, None, 0xBB, + None, None, None, None, None, None, None], + 'lax': [None, None, 0xA7, None, 0xB7, 0xAF, None, 0xBF, + None, None, None, None, 0xA3, 0xB3, None], + 'lxa': [None, 0xAB, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'nop': [0xEA, None, 0x04, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rla': [None, None, 0x27, 0x37, None, 0x2F, 0x3F, 0x3B, + None, None, None, None, 0x23, 0x33, None], + 'rra': [None, None, 0x67, 0x77, None, 0x6F, 0x7F, 0x7B, + None, None, None, None, 0x63, 0x73, None], + 'sax': [None, None, 0x87, None, 0x97, 0x8F, None, None, + None, None, None, None, 0x83, None, None], + 'sbx': [None, 0xCB, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sha': [None, None, None, None, None, None, None, 0x9F, + None, None, None, None, None, 0x93, None], + 'shs': [None, None, None, None, None, None, None, 0x9B, + None, None, None, None, None, None, None], + 'shx': [None, None, None, None, None, None, None, 0x9E, + None, None, None, None, None, None, None], + 'slo': [None, None, 0x07, 0x17, None, 0x0F, 0x1F, 0x1B, + None, None, None, None, 0x03, 0x13, None], + 'sre': [None, None, 0x47, 0x57, None, 0x4F, 0x5F, 0x5B, + None, None, None, None, 0x43, 0x53, None], } - c02extensions = { - 'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, None, None, None, 0x72, 0x61, 0x71, None], - 'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, None, None, None, 0x32, 0x21, 0x31, None], - 'bbr0': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x0F], - 'bbr1': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x1F], - 'bbr2': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x2F], - 'bbr3': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x3F], - 'bbr4': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x4F], - 'bbr5': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x5F], - 'bbr6': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x6F], - 'bbr7': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x7F], - 'bbs0': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x8F], - 'bbs1': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x9F], - 'bbs2': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xAF], - 'bbs3': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xBF], - 'bbs4': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xCF], - 'bbs5': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xDF], - 'bbs6': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xEF], - 'bbs7': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xFF], - 'bit': [None, 0x89, 0x24, 0x34, None, 0x2C, 0x3C, None, None, None, None, None, None, None, None], - 'bra': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x80], - 'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, None, None, None, 0xD2, 0xC1, 0xD1, None], - 'dea': [0x3A, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'dec': [0x3A, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, None, None, None, None, None, None, None], - 'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, None, None, None, 0x52, 0x41, 0x51, None], - 'ina': [0x1A, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'inc': [0x1A, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, None, None, None, None, None, None, None], - 'jmp': [None, None, None, None, None, 0x4C, None, None, 0x6C, 0x7C, None, None, None, None, None], - 'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, None, None, None, 0xB2, 0xA1, 0xB1, None], - 'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, None, None, None, 0x12, 0x01, 0x11, None], - 'phx': [0xDA, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'phy': [0x5A, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'plx': [0xFA, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'ply': [0x7A, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb0': [None, None, 0x07, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb1': [None, None, 0x17, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb2': [None, None, 0x27, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb3': [None, None, 0x37, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb4': [None, None, 0x47, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb5': [None, None, 0x57, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb6': [None, None, 0x67, None, None, None, None, None, None, None, None, None, None, None, None], - 'rmb7': [None, None, 0x77, None, None, None, None, None, None, None, None, None, None, None, None], - 'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, None, None, None, 0xF2, 0xE1, 0xF1, None], - 'smb0': [None, None, 0x87, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb1': [None, None, 0x97, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb2': [None, None, 0xA7, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb3': [None, None, 0xB7, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb4': [None, None, 0xC7, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb5': [None, None, 0xD7, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb6': [None, None, 0xE7, None, None, None, None, None, None, None, None, None, None, None, None], - 'smb7': [None, None, 0xF7, None, None, None, None, None, None, None, None, None, None, None, None], - 'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, None, None, None, 0x92, 0x81, 0x91, None], - 'stp': [0xDB, None, None, None, None, None, None, None, None, None, None, None, None, None, None], - 'stz': [None, None, 0x64, 0x74, None, 0x9C, 0x9E, None, None, None, None, None, None, None, None], - 'trb': [None, None, 0x14, None, None, 0x1C, None, None, None, None, None, None, None, None, None], - 'tsb': [None, None, 0x04, None, None, 0x0C, None, None, None, None, None, None, None, None, None], - 'wai': [0xCB, None, None, None, None, None, None, None, None, None, None, None, None, None, None], + 'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, + None, None, None, 0x72, 0x61, 0x71, None], + 'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, + None, None, None, 0x32, 0x21, 0x31, None], + 'bbr0': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x0F], + 'bbr1': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x1F], + 'bbr2': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x2F], + 'bbr3': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x3F], + 'bbr4': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x4F], + 'bbr5': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x5F], + 'bbr6': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x6F], + 'bbr7': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x7F], + 'bbs0': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x8F], + 'bbs1': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x9F], + 'bbs2': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xAF], + 'bbs3': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xBF], + 'bbs4': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xCF], + 'bbs5': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xDF], + 'bbs6': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xEF], + 'bbs7': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0xFF], + 'bit': [None, 0x89, 0x24, 0x34, None, 0x2C, 0x3C, None, + None, None, None, None, None, None, None], + 'bra': [None, None, None, None, None, None, None, None, + None, None, None, None, None, None, 0x80], + 'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, + None, None, None, 0xD2, 0xC1, 0xD1, None], + 'dea': [0x3A, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'dec': [0x3A, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, + None, None, None, None, None, None, None], + 'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, + None, None, None, 0x52, 0x41, 0x51, None], + 'ina': [0x1A, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'inc': [0x1A, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, + None, None, None, None, None, None, None], + 'jmp': [None, None, None, None, None, 0x4C, None, None, + 0x6C, 0x7C, None, None, None, None, None], + 'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, + None, None, None, 0xB2, 0xA1, 0xB1, None], + 'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, + None, None, None, 0x12, 0x01, 0x11, None], + 'phx': [0xDA, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'phy': [0x5A, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'plx': [0xFA, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'ply': [0x7A, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb0': [None, None, 0x07, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb1': [None, None, 0x17, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb2': [None, None, 0x27, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb3': [None, None, 0x37, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb4': [None, None, 0x47, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb5': [None, None, 0x57, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb6': [None, None, 0x67, None, None, None, None, None, + None, None, None, None, None, None, None], + 'rmb7': [None, None, 0x77, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, + None, None, None, 0xF2, 0xE1, 0xF1, None], + 'smb0': [None, None, 0x87, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb1': [None, None, 0x97, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb2': [None, None, 0xA7, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb3': [None, None, 0xB7, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb4': [None, None, 0xC7, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb5': [None, None, 0xD7, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb6': [None, None, 0xE7, None, None, None, None, None, + None, None, None, None, None, None, None], + 'smb7': [None, None, 0xF7, None, None, None, None, None, + None, None, None, None, None, None, None], + 'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, + None, None, None, 0x92, 0x81, 0x91, None], + 'stp': [0xDB, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], + 'stz': [None, None, 0x64, 0x74, None, 0x9C, 0x9E, None, + None, None, None, None, None, None, None], + 'trb': [None, None, 0x14, None, None, 0x1C, None, None, + None, None, None, None, None, None, None], + 'tsb': [None, None, 0x04, None, None, 0x0C, None, None, + None, None, None, None, None, None, None], + 'wai': [0xCB, None, None, None, None, None, None, None, + None, None, None, None, None, None, None], } - diff --git a/src/Ophis/Passes.py b/src/Ophis/Passes.py index 497f37e..ae8139e 100644 --- a/src/Ophis/Passes.py +++ b/src/Ophis/Passes.py @@ -6,7 +6,7 @@ translation occurs. This structure also makes the assembler very extensible; additional analyses or optimizations may be added as new subclasses of Pass.""" - + # Copyright 2002-2012 Michael C. Martin and additional contributors. # You may use, modify, and distribute this file under the MIT # license: See README for details. @@ -20,41 +20,55 @@ import Ophis.Macro as Macro # The passes themselves + class Pass(object): """Superclass for all assembler passes. Automatically handles IR types that modify the environent's structure, and by default raises an error on anything else. Override visitUnknown in your extension pass to produce a pass that accepts everything.""" name = "Default Pass" + def __init__(self): - self.writeOK = 1 + self.writeOK = True + def visitNone(self, node, env): pass + def visitSEQUENCE(self, node, env): Err.currentpoint = node.ppt for n in node.data: n.accept(self, env) + def visitDataSegment(self, node, env): - self.writeOK = 0 + self.writeOK = False env.setsegment(node.data[0]) + def visitTextSegment(self, node, env): - self.writeOK = 1 + self.writeOK = True env.setsegment(node.data[0]) + def visitScopeBegin(self, node, env): env.newscope() + def visitScopeEnd(self, node, env): env.endscope() + def visitUnknown(self, node, env): - Err.log("Internal error! "+self.name+" cannot understand node type "+node.nodetype) + Err.log("Internal error! " + self.name + + " cannot understand node type " + node.nodetype) + def prePass(self): pass + def postPass(self): pass + def go(self, node, env): - """Prepares the environment and runs this pass, possibly + """Prepares the environment and runs this pass, possibly printing debugging information.""" if Err.count == 0: - if Cmd.print_pass: print>>sys.stderr, "Running: "+self.name + if Cmd.print_pass: + print>>sys.stderr, "Running: " + self.name env.reset() self.prePass() node.accept(self, env) @@ -67,6 +81,7 @@ class Pass(object): print>>sys.stderr, "Current IR:" print>>sys.stderr, node + class FixPoint(object): """A specialized class that is not a pass but can be run like one. This class takes a list of passes and a "fixpoint" function.""" @@ -74,48 +89,60 @@ class FixPoint(object): self.name = name self.passes = passes self.fixpoint = fixpoint + def go(self, node, env): """Runs this FixPoint's passes, in order, until the fixpoint is true. Always runs the passes at least once.""" for i in xrange(100): - if Err.count != 0: break + if Err.count != 0: + break for p in self.passes: p.go(node, env) - if Err.count != 0: break - if self.fixpoint(): break - if Cmd.print_pass: print>>sys.stderr, "Fixpoint failed, looping back" + if Err.count != 0: + break + if self.fixpoint(): + break + if Cmd.print_pass: + print>>sys.stderr, "Fixpoint failed, looping back" else: - Err.log("Can't make %s converge! Maybe there's a recursive dependency somewhere?" % self.name) + Err.log("Can't make %s converge! Maybe there's a recursive " + "dependency somewhere?" % self.name) + class DefineMacros(Pass): "Extract macro definitions and remove them from the IR" name = "Macro definition pass" + def prePass(self): - self.inDef = 0 - self.nestedError = 0 + self.inDef = False + self.nestedError = False + def postPass(self): if self.inDef: Err.log("Unmatched .macro") elif Cmd.print_ir: print>>sys.stderr, "Macro definitions:" Macro.dump() + def visitMacroBegin(self, node, env): if self.inDef: Err.log("Nested macro definition") - self.nestedError = 1 + self.nestedError = True else: Macro.newMacro(node.data[0]) node.nodetype = "None" node.data = [] - self.inDef = 1 + self.inDef = True + def visitMacroEnd(self, node, env): if self.inDef: Macro.endMacro() node.nodetype = "None" node.data = [] - self.inDef = 0 + self.inDef = False elif not self.nestedError: Err.log("Unmatched .macend") + def visitUnknown(self, node, env): if self.inDef: Macro.registerNode(node) @@ -126,305 +153,438 @@ class DefineMacros(Pass): class ExpandMacros(Pass): "Replace macro invocations with the appropriate text" name = "Macro expansion pass" + def prePass(self): - self.changed = 0 + self.changed = False + def visitMacroInvoke(self, node, env): replacement = Macro.expandMacro(node.ppt, node.data[0], node.data[1:]) node.nodetype = replacement.nodetype node.data = replacement.data - self.changed = 1 + self.changed = True + def visitUnknown(self, node, env): pass + class InitLabels(Pass): "Finds all reachable labels" name = "Label initialization pass" + def __init__(self): Pass.__init__(self) self.labelmap = {} + def prePass(self): - self.changed = 0 - self.PCvalid = 1 + self.changed = False + self.PCvalid = True + def visitAdvance(self, node, env): - self.PCvalid=node.data[0].valid(env, self.PCvalid) + self.PCvalid = node.data[0].valid(env, self.PCvalid) + def visitSetPC(self, node, env): - self.PCvalid=node.data[0].valid(env, self.PCvalid) + self.PCvalid = node.data[0].valid(env, self.PCvalid) + def visitLabel(self, node, env): (label, val) = node.data fulllabel = "%d:%s" % (env.stack[0], label) - if fulllabel in self.labelmap and self.labelmap[fulllabel] is not node: + if fulllabel in self.labelmap and self.labelmap[fulllabel] is not node: Err.log("Duplicate label definition '%s'" % label) if fulllabel not in self.labelmap: self.labelmap[fulllabel] = node if val.valid(env, self.PCvalid) and label not in env: - env[label]=0 - self.changed=1 + env[label] = 0 + self.changed = True + def visitUnknown(self, node, env): pass + class CircularityCheck(Pass): "Checks for circular label dependencies" name = "Circularity check pass" + def prePass(self): - self.changed=0 - self.PCvalid=1 + self.changed = False + self.PCvalid = True + def visitAdvance(self, node, env): PCvalid = self.PCvalid - self.PCvalid=node.data[0].valid(env, self.PCvalid) + self.PCvalid = node.data[0].valid(env, self.PCvalid) if not node.data[0].valid(env, PCvalid): Err.log("Undefined or circular reference on .advance") + def visitSetPC(self, node, env): PCvalid = self.PCvalid - self.PCvalid=node.data[0].valid(env, self.PCvalid) + self.PCvalid = node.data[0].valid(env, self.PCvalid) if not node.data[0].valid(env, PCvalid): Err.log("Undefined or circular reference on program counter set") + def visitCheckPC(self, node, env): if not node.data[0].valid(env, self.PCvalid): Err.log("Undefined or circular reference on program counter check") + def visitLabel(self, node, env): (label, val) = node.data - if not val.valid(env, self.PCvalid): + if not val.valid(env, self.PCvalid): Err.log("Undefined or circular dependency for label '%s'" % label) + def visitUnknown(self, node, env): pass + class CheckExprs(Pass): "Ensures all expressions can resolve" name = "Expression checking pass" + def visitUnknown(self, node, env): + # Throw away result, just confirm validity of all expressions for i in [x for x in node.data if isinstance(x, IR.Expr)]: - i.value(env) # Throw away result, just confirm validity of all expressions + i.value(env) + class EasyModes(Pass): "Assigns address modes to hardcoded and branch instructions" name = "Easy addressing modes pass" + def visitMemory(self, node, env): if Ops.opcodes[node.data[0]][14] is not None: node.nodetype = "Relative" return - if node.data[1].hardcoded: + if node.data[1].hardcoded: if not collapse_no_index(node, env): node.nodetype = "Absolute" - def visitMemoryX(self, node, env): - if node.data[1].hardcoded: + + def visitMemoryX(self, node, env): + if node.data[1].hardcoded: if not collapse_x(node, env): node.nodetype = "AbsoluteX" - def visitMemoryY(self, node, env): - if node.data[1].hardcoded: + + def visitMemoryY(self, node, env): + if node.data[1].hardcoded: if not collapse_y(node, env): node.nodetype = "AbsoluteY" + def visitPointer(self, node, env): if node.data[1].hardcoded: if not collapse_no_index_ind(node, env): node.nodetype = "Indirect" + def visitPointerX(self, node, env): if node.data[1].hardcoded: if not collapse_x_ind(node, env): node.nodetype = "AbsIndX" + def visitPointerY(self, node, env): if node.data[1].hardcoded: if not collapse_y_ind(node, env): node.nodetype = "AbsIndY" + def visitUnknown(self, node, env): pass + class PCTracker(Pass): "Superclass for passes that need an accurate program counter." name = "**BUG** PC Tracker Superpass used directly" - def visitSetPC(self, node, env): env.setPC(node.data[0].value(env)) - def visitAdvance(self, node, env): env.setPC(node.data[0].value(env)) - def visitImplied(self, node, env): env.incPC(1) - def visitImmediate(self, node, env): env.incPC(2) - def visitIndirectX(self, node, env): env.incPC(2) - def visitIndirectY(self, node, env): env.incPC(2) - def visitZPIndirect(self, node, env): env.incPC(2) - def visitZeroPage(self, node, env): env.incPC(2) - def visitZeroPageX(self, node, env): env.incPC(2) - def visitZeroPageY(self, node, env): env.incPC(2) - def visitRelative(self, node, env): env.incPC(2) - def visitIndirect(self, node, env): env.incPC(3) - def visitAbsolute(self, node, env): env.incPC(3) - def visitAbsoluteX(self, node, env): env.incPC(3) - def visitAbsoluteY(self, node, env): env.incPC(3) - def visitAbsIndX(self, node, env): env.incPC(3) - def visitAbsIndY(self, node, env): env.incPC(3) - def visitMemory(self, node, env): env.incPC(3) - def visitMemoryX(self, node, env): env.incPC(3) - def visitMemoryY(self, node, env): env.incPC(3) - def visitPointer(self, node, env): env.incPC(3) - def visitPointerX(self, node, env): env.incPC(3) - def visitPointerY(self, node, env): env.incPC(3) - def visitCheckPC(self, node, env): pass - def visitLabel(self, node, env): pass - def visitByte(self, node, env): env.incPC(len(node.data)) - def visitWord(self, node, env): env.incPC(len(node.data)*2) - def visitDword(self, node, env): env.incPC(len(node.data)*4) - def visitWordBE(self, node, env): env.incPC(len(node.data)*2) - def visitDwordBE(self, node, env): env.incPC(len(node.data)*4) + + def visitSetPC(self, node, env): + env.setPC(node.data[0].value(env)) + + def visitAdvance(self, node, env): + env.setPC(node.data[0].value(env)) + + def visitImplied(self, node, env): + env.incPC(1) + + def visitImmediate(self, node, env): + env.incPC(2) + + def visitIndirectX(self, node, env): + env.incPC(2) + + def visitIndirectY(self, node, env): + env.incPC(2) + + def visitZPIndirect(self, node, env): + env.incPC(2) + + def visitZeroPage(self, node, env): + env.incPC(2) + + def visitZeroPageX(self, node, env): + env.incPC(2) + + def visitZeroPageY(self, node, env): + env.incPC(2) + + def visitRelative(self, node, env): + env.incPC(2) + + def visitIndirect(self, node, env): + env.incPC(3) + + def visitAbsolute(self, node, env): + env.incPC(3) + + def visitAbsoluteX(self, node, env): + env.incPC(3) + + def visitAbsoluteY(self, node, env): + env.incPC(3) + + def visitAbsIndX(self, node, env): + env.incPC(3) + + def visitAbsIndY(self, node, env): + env.incPC(3) + + def visitMemory(self, node, env): + env.incPC(3) + + def visitMemoryX(self, node, env): + env.incPC(3) + + def visitMemoryY(self, node, env): + env.incPC(3) + + def visitPointer(self, node, env): + env.incPC(3) + + def visitPointerX(self, node, env): + env.incPC(3) + + def visitPointerY(self, node, env): + env.incPC(3) + + def visitCheckPC(self, node, env): + pass + + def visitLabel(self, node, env): + pass + + def visitByte(self, node, env): + env.incPC(len(node.data)) + + def visitWord(self, node, env): + env.incPC(len(node.data) * 2) + + def visitDword(self, node, env): + env.incPC(len(node.data) * 4) + + def visitWordBE(self, node, env): + env.incPC(len(node.data) * 2) + + def visitDwordBE(self, node, env): + env.incPC(len(node.data) * 4) + class UpdateLabels(PCTracker): "Computes the new values for all entries in the symbol table" name = "Label Update Pass" + def prePass(self): - self.changed = 0 + self.changed = False + def visitLabel(self, node, env): (label, val) = node.data old = env[label] env[label] = val.value(env) if old != env[label]: - self.changed = 1 + self.changed = True + class Collapse(Pass): - """Selects as many zero-page instructions to convert as - possible, and tracks how many instructions have been - converted this pass.""" + "Selects as many zero-page instructions to convert as possible." name = "Instruction Collapse Pass" + def prePass(self): - self.collapsed = 0 + self.changed = False + def visitMemory(self, node, env): - if collapse_no_index(node, env): self.collapsed += 1 + self.changed |= collapse_no_index(node, env) + def visitMemoryX(self, node, env): - if collapse_x(node, env): self.collapsed += 1 + self.changed |= collapse_x(node, env) + def visitMemoryY(self, node, env): - if collapse_y(node, env): self.collapsed += 1 + self.changed |= collapse_y(node, env) + def visitPointer(self, node, env): - if collapse_no_index_ind(node, env): self.collapsed += 1 + self.changed |= collapse_no_index_ind(node, env) + def visitPointerX(self, node, env): - if collapse_x_ind(node, env): self.collapsed += 1 + self.changed |= collapse_x_ind(node, env) + def visitPointerY(self, node, env): - if collapse_y_ind(node, env): self.collapsed += 1 + self.changed |= collapse_y_ind(node, env) + def visitUnknown(self, node, env): pass + def collapse_no_index(node, env): """Transforms a Memory node into a ZeroPage one if possible. - Returns 1 if it made the collapse, false otherwise.""" - if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][2] is not None: - node.nodetype = "ZeroPage" - return 1 - else: - return 0 + Returns boolean indicating whether or not it made the collapse.""" + if node.data[1].value(env) < 0x100: + if Ops.opcodes[node.data[0]][2] is not None: + node.nodetype = "ZeroPage" + return True + return False + def collapse_x(node, env): """Transforms a MemoryX node into a ZeroPageX one if possible. - Returns 1 if it made the collapse, false otherwise.""" - if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][3] is not None: - node.nodetype = "ZeroPageX" - return 1 - else: - return 0 + Returns boolean indicating whether or not it made the collapse.""" + if node.data[1].value(env) < 0x100: + if Ops.opcodes[node.data[0]][3] is not None: + node.nodetype = "ZeroPageX" + return True + return False + def collapse_y(node, env): """Transforms a MemoryY node into a ZeroPageY one if possible. - Returns 1 if it made the collapse, false otherwise.""" - if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][4] is not None: - node.nodetype = "ZeroPageY" - return 1 - else: - return 0 + Returns boolean indicating whether or not it made the collapse.""" + if node.data[1].value(env) < 0x100: + if Ops.opcodes[node.data[0]][4] is not None: + node.nodetype = "ZeroPageY" + return True + return False + def collapse_no_index_ind(node, env): """Transforms a Pointer node into a ZPIndirect one if possible. - Returns 1 if it made the collapse, false otherwise.""" - if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][11] is not None: - node.nodetype = "ZPIndirect" - return 1 - else: - return 0 + Returns boolean indicating whether or not it made the collapse.""" + if node.data[1].value(env) < 0x100: + if Ops.opcodes[node.data[0]][11] is not None: + node.nodetype = "ZPIndirect" + return True + return False + def collapse_x_ind(node, env): """Transforms a PointerX node into an IndirectX one if possible. - Returns 1 if it made the collapse, false otherwise.""" - if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][12] is not None: - node.nodetype = "IndirectX" - return 1 - else: - return 0 + Returns boolean indicating whether or not it made the collapse.""" + if node.data[1].value(env) < 0x100: + if Ops.opcodes[node.data[0]][12] is not None: + node.nodetype = "IndirectX" + return True + return False + def collapse_y_ind(node, env): """Transforms a PointerY node into an IndirectY one if possible. - Returns 1 if it made the collapse, false otherwise.""" - if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][13] is not None: - node.nodetype = "IndirectY" - return 1 - else: - return 0 + Returns boolean indicating whether or not it made the collapse.""" + if node.data[1].value(env) < 0x100: + if Ops.opcodes[node.data[0]][13] is not None: + node.nodetype = "IndirectY" + return True + return False + class ExtendBranches(PCTracker): """Eliminates any branch instructions that would end up going past - the 128-byte range, and replaces them with a branch-jump - pair. Also tracks how many elements where changed this pass.""" + the 128-byte range, and replaces them with a branch-jump pair.""" name = "Branch Expansion Pass" - reversed = { 'bcc': 'bcs', - 'bcs': 'bcc', - 'beq': 'bne', - 'bmi': 'bpl', - 'bne': 'beq', - 'bpl': 'bmi', - 'bvc': 'bvs', - 'bvs': 'bvc', - # 65c02 ones. 'bra' is special, though, having no inverse - 'bbr0': 'bbs0', - 'bbs0': 'bbr0', - 'bbr1': 'bbs1', - 'bbs1': 'bbr1', - 'bbr2': 'bbs2', - 'bbs2': 'bbr2', - 'bbr3': 'bbs3', - 'bbs3': 'bbr3', - 'bbr4': 'bbs4', - 'bbs4': 'bbr4', - 'bbr5': 'bbs5', - 'bbs5': 'bbr5', - 'bbr6': 'bbs6', - 'bbs6': 'bbr6', - 'bbr7': 'bbs7', - 'bbs7': 'bbr7' - } + reversed = {'bcc': 'bcs', + 'bcs': 'bcc', + 'beq': 'bne', + 'bmi': 'bpl', + 'bne': 'beq', + 'bpl': 'bmi', + 'bvc': 'bvs', + 'bvs': 'bvc', + # 65c02 ones. 'bra' is special, though, having no inverse + 'bbr0': 'bbs0', + 'bbs0': 'bbr0', + 'bbr1': 'bbs1', + 'bbs1': 'bbr1', + 'bbr2': 'bbs2', + 'bbs2': 'bbr2', + 'bbr3': 'bbs3', + 'bbs3': 'bbr3', + 'bbr4': 'bbs4', + 'bbs4': 'bbr4', + 'bbr5': 'bbs5', + 'bbs5': 'bbr5', + 'bbr6': 'bbs6', + 'bbs6': 'bbr6', + 'bbr7': 'bbs7', + 'bbs7': 'bbr7' + } + def prePass(self): - self.expanded = 0 + self.changed = False + def visitRelative(self, node, env): (opcode, expr) = node.data arg = expr.value(env) - arg = arg-(env.getPC()+2) + arg = arg - (env.getPC() + 2) if arg < -128 or arg > 127: if opcode == 'bra': # If BRA - BRanch Always - is out of range, it's a JMP. node.data = ('jmp', expr) node.nodetype = "Absolute" if Cmd.warn_on_branch_extend: - print>>sys.stderr, str(node.ppt) + ": WARNING: bra out of range, replacing with jmp" + print>>sys.stderr, str(node.ppt) + ": WARNING: " \ + "bra out of range, replacing with jmp" else: # Otherwise, we replace it with a 'macro' of sorts by hand: # $branch LOC -> $reversed_branch ^+5; JMP LOC - # We don't use temp labels here because labels need to have been fixed - # in place by this point, and JMP is always 3 bytes long. - expansion = [IR.Node(node.ppt, "Relative", ExtendBranches.reversed[opcode], IR.SequenceExpr([IR.PCExpr(), "+", IR.ConstantExpr(5)])), + # We don't use temp labels here because labels need to have + # been fixed in place by this point, and JMP is always 3 + # bytes long. + expansion = [IR.Node(node.ppt, "Relative", + ExtendBranches.reversed[opcode], + IR.SequenceExpr([IR.PCExpr(), "+", + IR.ConstantExpr(5)])), IR.Node(node.ppt, "Absolute", 'jmp', expr)] - node.nodetype='SEQUENCE' + node.nodetype = 'SEQUENCE' node.data = expansion if Cmd.warn_on_branch_extend: - print>>sys.stderr, str(node.ppt) + ": WARNING: "+opcode+" out of range, replacing with "+ExtendBranches.reversed[opcode] +"/jmp combo" - self.expanded += 1 + print>>sys.stderr, str(node.ppt) + ": WARNING: " + \ + opcode + " out of range, " \ + "replacing with " + \ + ExtendBranches.reversed[opcode] + \ + "/jmp combo" + self.changed = True node.accept(self, env) else: env.incPC(2) + class NormalizeModes(Pass): """Eliminates the intermediate "Memory" and "Pointer" nodes, converting them to "Absolute".""" name = "Mode Normalization pass" - def visitMemory(self, node, env): node.nodetype = "Absolute" - def visitMemoryX(self, node, env): node.nodetype = "AbsoluteX" - def visitMemoryY(self, node, env): node.nodetype = "AbsoluteY" - def visitPointer(self, node, env): node.nodetype = "Indirect" - def visitPointerX(self, node, env): node.nodetype = "AbsIndX" + + def visitMemory(self, node, env): + node.nodetype = "Absolute" + + def visitMemoryX(self, node, env): + node.nodetype = "AbsoluteX" + + def visitMemoryY(self, node, env): + node.nodetype = "AbsoluteY" + + def visitPointer(self, node, env): + node.nodetype = "Indirect" + + def visitPointerX(self, node, env): + node.nodetype = "AbsIndX" + # If we ever hit a PointerY by this point, we have a bug. - def visitPointerY(self, node, env): node.nodetype = "AbsIndY" - def visitUnknown(self, node, env): pass + + def visitPointerY(self, node, env): + node.nodetype = "AbsIndY" + + def visitUnknown(self, node, env): + pass + class Assembler(Pass): - """Converts the IR into a list of bytes, suitable for writing to + """Converts the IR into a list of bytes, suitable for writing to a file.""" name = "Assembler" @@ -436,36 +596,40 @@ class Assembler(Pass): def postPass(self): if Cmd.print_summary and Err.count == 0: - print>>sys.stderr, "Assembly complete: %s bytes output (%s code, %s data, %s filler)" \ - % (len(self.output), self.code, self.data, self.filler) + print>>sys.stderr, "Assembly complete: %s bytes output " \ + "(%s code, %s data, %s filler)" \ + % (len(self.output), + self.code, self.data, self.filler) def outputbyte(self, expr, env): 'Outputs a byte, with range checking' if self.writeOK: val = expr.value(env) if val < 0x00 or val > 0xff: - Err.log("Byte constant "+str(expr)+" out of range") + Err.log("Byte constant " + str(expr) + " out of range") val = 0 self.output.append(int(val)) else: Err.log("Attempt to write to data segment") + def outputword(self, expr, env): 'Outputs a little-endian word, with range checking' if self.writeOK: val = expr.value(env) if val < 0x0000 or val > 0xFFFF: - Err.log("Word constant "+str(expr)+" out of range") + Err.log("Word constant " + str(expr) + " out of range") val = 0 self.output.append(int(val & 0xFF)) self.output.append(int((val >> 8) & 0xFF)) else: Err.log("Attempt to write to data segment") + def outputdword(self, expr, env): 'Outputs a little-endian dword, with range checking' if self.writeOK: val = expr.value(env) if val < 0x00000000 or val > 0xFFFFFFFFL: - Err.log("DWord constant "+str(expr)+" out of range") + Err.log("DWord constant " + str(expr) + " out of range") val = 0 self.output.append(int(val & 0xFF)) self.output.append(int((val >> 8) & 0xFF)) @@ -479,18 +643,19 @@ class Assembler(Pass): if self.writeOK: val = expr.value(env) if val < 0x0000 or val > 0xFFFF: - Err.log("Word constant "+str(expr)+" out of range") + Err.log("Word constant " + str(expr) + " out of range") val = 0 self.output.append(int((val >> 8) & 0xFF)) self.output.append(int(val & 0xFF)) else: Err.log("Attempt to write to data segment") + def outputdword_be(self, expr, env): 'Outputs a big-endian dword, with range checking' if self.writeOK: val = expr.value(env) if val < 0x00000000 or val > 0xFFFFFFFFL: - Err.log("DWord constant "+str(expr)+" out of range") + Err.log("DWord constant " + str(expr) + " out of range") val = 0 self.output.append(int((val >> 24) & 0xFF)) self.output.append(int((val >> 16) & 0xFF)) @@ -504,77 +669,122 @@ class Assembler(Pass): (opcode, expr) = node.data bin_op = Ops.opcodes[opcode][mode] if bin_op is None: - Err.log('%s does not have mode "%s"' % (opcode.upper(), Ops.modes[mode])) + Err.log('%s does not have mode "%s"' % (opcode.upper(), + Ops.modes[mode])) return self.outputbyte(IR.ConstantExpr(bin_op), env) arglen = Ops.lengths[mode] if mode == 14: # Special handling for relative mode arg = expr.value(env) - arg = arg-(env.getPC()+2) + arg = arg - (env.getPC() + 2) if arg < -128 or arg > 127: Err.log("Branch target out of bounds") arg = 0 - if arg < 0: arg += 256 + if arg < 0: + arg += 256 expr = IR.ConstantExpr(arg) - if arglen == 1: self.outputbyte(expr, env) - if arglen == 2: self.outputword(expr, env) - env.incPC(1+arglen) - self.code += 1+arglen + if arglen == 1: + self.outputbyte(expr, env) + if arglen == 2: + self.outputword(expr, env) + env.incPC(1 + arglen) + self.code += 1 + arglen + + def visitImplied(self, node, env): + self.assemble(node, 0, env) + + def visitImmediate(self, node, env): + self.assemble(node, 1, env) + + def visitZeroPage(self, node, env): + self.assemble(node, 2, env) + + def visitZeroPageX(self, node, env): + self.assemble(node, 3, env) + + def visitZeroPageY(self, node, env): + self.assemble(node, 4, env) + + def visitAbsolute(self, node, env): + self.assemble(node, 5, env) + + def visitAbsoluteX(self, node, env): + self.assemble(node, 6, env) + + def visitAbsoluteY(self, node, env): + self.assemble(node, 7, env) + + def visitIndirect(self, node, env): + self.assemble(node, 8, env) + + def visitAbsIndX(self, node, env): + self.assemble(node, 9, env) + + def visitAbsIndY(self, node, env): + self.assemble(node, 10, env) + + def visitZPIndirect(self, node, env): + self.assemble(node, 11, env) + + def visitIndirectX(self, node, env): + self.assemble(node, 12, env) + + def visitIndirectY(self, node, env): + self.assemble(node, 13, env) + + def visitRelative(self, node, env): + self.assemble(node, 14, env) + + def visitLabel(self, node, env): + pass - def visitImplied(self, node, env): self.assemble(node, 0, env) - def visitImmediate(self, node, env): self.assemble(node, 1, env) - def visitZeroPage(self, node, env): self.assemble(node, 2, env) - def visitZeroPageX(self, node, env): self.assemble(node, 3, env) - def visitZeroPageY(self, node, env): self.assemble(node, 4, env) - def visitAbsolute(self, node, env): self.assemble(node, 5, env) - def visitAbsoluteX(self, node, env): self.assemble(node, 6, env) - def visitAbsoluteY(self, node, env): self.assemble(node, 7, env) - def visitIndirect(self, node, env): self.assemble(node, 8, env) - def visitAbsIndX(self, node, env): self.assemble(node, 9, env) - def visitAbsIndY(self, node, env): self.assemble(node, 10, env) - def visitZPIndirect(self, node, env): self.assemble(node, 11, env) - def visitIndirectX(self, node, env): self.assemble(node, 12, env) - def visitIndirectY(self, node, env): self.assemble(node, 13, env) - def visitRelative(self, node, env): self.assemble(node, 14, env) - def visitLabel(self, node, env): pass def visitByte(self, node, env): for expr in node.data: self.outputbyte(expr, env) env.incPC(len(node.data)) self.data += len(node.data) + def visitWord(self, node, env): for expr in node.data: self.outputword(expr, env) - env.incPC(len(node.data)*2) - self.data += len(node.data)*2 + env.incPC(len(node.data) * 2) + self.data += len(node.data) * 2 + def visitDword(self, node, env): for expr in node.data: self.outputdword(expr, env) - env.incPC(len(node.data)*4) - self.data += len(node.data)*4 + env.incPC(len(node.data) * 4) + self.data += len(node.data) * 4 + def visitWordBE(self, node, env): for expr in node.data: self.outputword_be(expr, env) - env.incPC(len(node.data)*2) - self.data += len(node.data)*2 + env.incPC(len(node.data) * 2) + self.data += len(node.data) * 2 + def visitDwordBE(self, node, env): for expr in node.data: self.outputdword_be(expr, env) - env.incPC(len(node.data)*4) - self.data += len(node.data)*4 - def visitSetPC(self, node, env): + env.incPC(len(node.data) * 4) + self.data += len(node.data) * 4 + + def visitSetPC(self, node, env): env.setPC(node.data[0].value(env)) + def visitCheckPC(self, node, env): pc = env.getPC() target = node.data[0].value(env) if (pc > target): Err.log(".checkpc assertion failed: $%x > $%x" % (pc, target)) - def visitAdvance(self, node, env): + + def visitAdvance(self, node, env): pc = env.getPC() target = node.data[0].value(env) if (pc > target): - Err.log("Attempted to .advance backwards: $%x to $%x" % (pc, target)) + Err.log("Attempted to .advance backwards: $%x to $%x" % + (pc, target)) else: - for i in xrange(target-pc): self.outputbyte(node.data[1], env) - self.filler += target-pc + for i in xrange(target - pc): + self.outputbyte(node.data[1], env) + self.filler += target - pc env.setPC(target) diff --git a/src/scripts/ophis.nsi b/src/scripts/ophis.nsi index 5382375..5964ff8 100644 --- a/src/scripts/ophis.nsi +++ b/src/scripts/ophis.nsi @@ -155,4 +155,4 @@ Section Uninstall DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" SetAutoClose true -SectionEnd \ No newline at end of file +SectionEnd diff --git a/src/setup.py b/src/setup.py index b60c09f..c602381 100644 --- a/src/setup.py +++ b/src/setup.py @@ -6,6 +6,11 @@ setup(name='Ophis', author="Michael Martin", author_email="mcmartin@gmail.com", license="MIT", - long_description="Ophis is a cross-assembler for the 65xx series of chips. It supports the stock 6502 opcodes, the 65c02 extensions, and syntax for the \"undocumented opcodes\" in the 6510 chip used on the Commodore 64. (Syntax for these opcodes matches those given in the VICE team's documentation.)", + long_description="Ophis is a cross-assembler for the 65xx series of " + "chips. It supports the stock 6502 opcodes, the 65c02 " + "extensions, and syntax for the \"undocumented " + "opcodes\" in the 6510 chip used on the Commodore 64. " + "(Syntax for these opcodes matches those given in the " + "VICE team's documentation.)", packages=['Ophis'], scripts=['scripts/ophis']) diff --git a/src/win_setup.py b/src/win_setup.py index d5c682c..6e5322b 100644 --- a/src/win_setup.py +++ b/src/win_setup.py @@ -1,9 +1,10 @@ from distutils.core import setup -import py2exe, sys +import py2exe +import sys sys.argv.append('py2exe') -setup(options = {'py2exe': {'bundle_files': 1}}, - packages = ['Ophis'], - zipfile = None, - console = [{'script': "scripts/ophis"}]) +setup(options={'py2exe': {'bundle_files': 1}}, + packages=['Ophis'], + zipfile=None, + console=[{'script': "scripts/ophis"}]) diff --git a/tests/longbranch_ref.oph b/tests/longbranch_ref.oph index 72f585d..1cf5778 100644 --- a/tests/longbranch_ref.oph +++ b/tests/longbranch_ref.oph @@ -51,4 +51,4 @@ late: jmp early * bne + jmp early -* \ No newline at end of file +* diff --git a/tests/test6510.oph b/tests/test6510.oph index 8b0a707..e5cbda3 100644 --- a/tests/test6510.oph +++ b/tests/test6510.oph @@ -76,4 +76,4 @@ ISB $F7, X ISB $FBFB, Y ISB $FFFF, X - + diff --git a/tests/test65c02.oph b/tests/test65c02.oph index ebaba8d..ab027cf 100644 --- a/tests/test65c02.oph +++ b/tests/test65c02.oph @@ -25,7 +25,7 @@ AND ($32) ; 32: AND - (Zero Page) BIT $34, X ; 34: BIT - Zero Page, X RMB3 $37 ; 37: RMB3 - Zero Page - DEA ; 3A: DEA - Implied + DEA ; 3A: DEA - Implied DEC ; 3A: DEC - Implied BIT $3C3C,X ; 3C: BIT - Absolute, X BBR3 ^+$41 ; 3F: BBR3 - Relative diff --git a/tests/testbase.oph b/tests/testbase.oph index 44b636d..96c8f64 100644 --- a/tests/testbase.oph +++ b/tests/testbase.oph @@ -1,157 +1,157 @@ -; Test file for base 6502 opcode compliance -; This odd little source file uses every addressing mode -; of every opcode, and uses the opcode itself as the argument -; to each instruction that takes one. The resulting binary's -; bytes are thus in strictly increasing numerical order. - - BRK - ORA ($01, X) - ORA $05 - ASL $06 - PHP - ORA #$09 - ASL - ORA $0D0D - ASL $0E0E - BPL ^+$12 - ORA ($11), Y - ORA $15, X - ASL $16, X - CLC - ORA $1919, Y - ORA $1D1D, X - ASL $1E1E, X - JSR $2020 - AND ($21, X) - BIT $24 - AND $25 - ROL $26 - PLP - AND #$29 - ROL - BIT $2C2C - AND $2D2D - ROL $2E2E - BMI ^+$32 - AND ($31), Y - AND $35, X - ROL $36, X - SEC - AND $3939, Y - AND $3D3D, X - ROL $3E3E, X - RTI - EOR ($41, X) - EOR $45 - LSR $46 - PHA - EOR #$49 - LSR - JMP $4C4C - EOR $4D4D - LSR $4E4E - BVC ^+$52 - EOR ($51), Y - EOR $55, X - LSR $56, X - CLI - EOR $5959, Y - EOR $5D5D, X - LSR $5E5E, X - RTS - ADC ($61, X) - ADC $65 - ROR $66 - PLA - ADC #$69 - ROR - JMP ($6C6C) - ADC $6D6D - ROR $6E6E - BVS ^+$72 - ADC ($71), Y - ADC $75, X - ROR $76, X - SEI - ADC $7979, Y - ADC $7D7D, X - ROR $7E7E, X - STA ($81, X) - STY $84 - STA $85 - STX $86 - DEY - TXA - STY $8C8C - STA $8D8D - STX $8E8E - BCC ^-$6E - STA ($91), Y - STY $94, X - STA $95, X - STX $96, Y - TYA - STA $9999, Y - TXS - STA $9D9D, X - LDY #$A0 - LDA ($A1, X) - LDX #$A2 - LDY $A4 - LDA $A5 - LDX $A6 - TAY - LDA #$A9 - TAX - LDY $ACAC - LDA $ADAD - LDX $AEAE - BCS ^-$4e - LDA ($B1), Y - LDY $B4, X - LDA $B5, X - LDX $B6, Y - CLV - LDA $B9B9,Y - TSX - LDY $BCBC, X - LDA $BDBD, X - LDX $BEBE, Y - CPY #$C0 - CMP ($C1, X) - CPY $C4 - CMP $C5 - DEC $C6 - INY - CMP #$C9 - DEX - CPY $CCCC - CMP $CDCD - DEC $CECE - BNE ^-$2E - CMP ($D1), Y - CMP $D5, X - DEC $D6, X - CLD - CMP $D9D9, Y - CMP $DDDD, X - DEC $DEDE, X - CPX #$E0 - SBC ($E1, X) - CPX $E4 - SBC $E5 - INC $E6 - INX - SBC #$E9 - NOP - CPX $ECEC - SBC $EDED - INC $EEEE - BEQ ^-$0E - SBC ($F1), Y - SBC $F5, X - INC $F6, X - SED - SBC $F9F9, Y - SBC $FDFD, X - INC $FEFE, X +; Test file for base 6502 opcode compliance +; This odd little source file uses every addressing mode +; of every opcode, and uses the opcode itself as the argument +; to each instruction that takes one. The resulting binary's +; bytes are thus in strictly increasing numerical order. + + BRK + ORA ($01, X) + ORA $05 + ASL $06 + PHP + ORA #$09 + ASL + ORA $0D0D + ASL $0E0E + BPL ^+$12 + ORA ($11), Y + ORA $15, X + ASL $16, X + CLC + ORA $1919, Y + ORA $1D1D, X + ASL $1E1E, X + JSR $2020 + AND ($21, X) + BIT $24 + AND $25 + ROL $26 + PLP + AND #$29 + ROL + BIT $2C2C + AND $2D2D + ROL $2E2E + BMI ^+$32 + AND ($31), Y + AND $35, X + ROL $36, X + SEC + AND $3939, Y + AND $3D3D, X + ROL $3E3E, X + RTI + EOR ($41, X) + EOR $45 + LSR $46 + PHA + EOR #$49 + LSR + JMP $4C4C + EOR $4D4D + LSR $4E4E + BVC ^+$52 + EOR ($51), Y + EOR $55, X + LSR $56, X + CLI + EOR $5959, Y + EOR $5D5D, X + LSR $5E5E, X + RTS + ADC ($61, X) + ADC $65 + ROR $66 + PLA + ADC #$69 + ROR + JMP ($6C6C) + ADC $6D6D + ROR $6E6E + BVS ^+$72 + ADC ($71), Y + ADC $75, X + ROR $76, X + SEI + ADC $7979, Y + ADC $7D7D, X + ROR $7E7E, X + STA ($81, X) + STY $84 + STA $85 + STX $86 + DEY + TXA + STY $8C8C + STA $8D8D + STX $8E8E + BCC ^-$6E + STA ($91), Y + STY $94, X + STA $95, X + STX $96, Y + TYA + STA $9999, Y + TXS + STA $9D9D, X + LDY #$A0 + LDA ($A1, X) + LDX #$A2 + LDY $A4 + LDA $A5 + LDX $A6 + TAY + LDA #$A9 + TAX + LDY $ACAC + LDA $ADAD + LDX $AEAE + BCS ^-$4e + LDA ($B1), Y + LDY $B4, X + LDA $B5, X + LDX $B6, Y + CLV + LDA $B9B9,Y + TSX + LDY $BCBC, X + LDA $BDBD, X + LDX $BEBE, Y + CPY #$C0 + CMP ($C1, X) + CPY $C4 + CMP $C5 + DEC $C6 + INY + CMP #$C9 + DEX + CPY $CCCC + CMP $CDCD + DEC $CECE + BNE ^-$2E + CMP ($D1), Y + CMP $D5, X + DEC $D6, X + CLD + CMP $D9D9, Y + CMP $DDDD, X + DEC $DEDE, X + CPX #$E0 + SBC ($E1, X) + CPX $E4 + SBC $E5 + INC $E6 + INX + SBC #$E9 + NOP + CPX $ECEC + SBC $EDED + INC $EEEE + BEQ ^-$0E + SBC ($F1), Y + SBC $F5, X + INC $F6, X + SED + SBC $F9F9, Y + SBC $FDFD, X + INC $FEFE, X diff --git a/tools/charmaps/makea2maps.py b/tools/charmaps/makea2maps.py index 40dac91..a95f692 100644 --- a/tools/charmaps/makea2maps.py +++ b/tools/charmaps/makea2maps.py @@ -10,11 +10,13 @@ normmap = ''.join([bits[x] for x in norm]) ivrsmap = ''.join([bits[x] for x in ivrs]) blnkmap = ''.join([bits[x] for x in blnk]) + def dumpfile(n, m): f = file(n, 'wb') f.write(m) f.close() + dumpfile('a2normal.map', normmap) dumpfile('a2inverse.map', ivrsmap) dumpfile('a2blink.map', blnkmap) diff --git a/tools/opcodes/gensets.py b/tools/opcodes/gensets.py index 64f791a..84a5991 100644 --- a/tools/opcodes/gensets.py +++ b/tools/opcodes/gensets.py @@ -3,7 +3,7 @@ import sys verbose = 0 -prologue = '"""' +"""Opcodes file. +prologue = '"""' + """Opcodes file. Tables for the assembly of 6502-family instructions, mapping opcodes and addressing modes to binary instructions.""" + '"""' + """ @@ -17,37 +17,38 @@ prologue = '"""' +"""Opcodes file. # the tables in tools/opcodes. Edit those tables, not these. # Names of addressing modes -modes = ["Implied", # 0 - "Immediate", # 1 - "Zero Page", # 2 - "Zero Page, X", # 3 - "Zero Page, Y", # 4 - "Absolute", # 5 - "Absolute, X", # 6 - "Absolute, Y", # 7 - "(Absolute)", # 8 - "(Absolute, X)", # 9 +modes = ["Implied", # 0 + "Immediate", # 1 + "Zero Page", # 2 + "Zero Page, X", # 3 + "Zero Page, Y", # 4 + "Absolute", # 5 + "Absolute, X", # 6 + "Absolute, Y", # 7 + "(Absolute)", # 8 + "(Absolute, X)", # 9 "(Absolute), Y", # 10 "(Zero Page)", # 11 "(Zero Page, X)", # 12 "(Zero Page), Y", # 13 "Relative"] # 14 + # Lengths of the argument lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1] """ # These values should match the ones in the prologue string. -modes = ["Implied", # 0 - "Immediate", # 1 - "Zero Page", # 2 - "Zero Page, X", # 3 - "Zero Page, Y", # 4 - "Absolute", # 5 - "Absolute, X", # 6 - "Absolute, Y", # 7 - "(Absolute)", # 8 - "(Absolute, X)", # 9 +modes = ["Implied", # 0 + "Immediate", # 1 + "Zero Page", # 2 + "Zero Page, X", # 3 + "Zero Page, Y", # 4 + "Absolute", # 5 + "Absolute, X", # 6 + "Absolute, Y", # 7 + "(Absolute)", # 8 + "(Absolute, X)", # 9 "(Absolute), Y", # 10 "(Zero Page)", # 11 "(Zero Page, X)", # 12 @@ -56,24 +57,28 @@ modes = ["Implied", # 0 flatmodes = [x.lower() for x in modes] + # WARNING: This decommenter assumes that # never appears anywhere else # in a line. -def decomment (l): +def decomment(l): if '#' in l: l = l[:l.index('#')] return l.strip() -def decomment_readlines (fname): - result = [decomment(x) for x in file(fname).readlines()] - return [x for x in result if len(x) > 0] -def parse_chipset_file (fname): +def decomment_readlines(fname): + result = [decomment(x) for x in file(fname).readlines()] + return [x for x in result if len(x) > 0] + + +def parse_chipset_file(fname): result = [None] * 256 - ls = [[x.strip() for x in y] for y in [z.split(':', 1) for z in decomment_readlines (fname)]] + ls = [[x.strip() for x in y] + for y in [z.split(':', 1) for z in decomment_readlines(fname)]] for l in ls: if len(l) == 2: try: - op = int (l[0], 16) + op = int(l[0], 16) syns = l[1].split(';') for s in syns: s_p = s.split('-') @@ -81,19 +86,20 @@ def parse_chipset_file (fname): mnem = s_p[0].lower().strip() mode = s_p[1].lower().strip() if mode in flatmodes: - if result[op] == None: + if result[op] is None: result[op] = [] result[op].append((mnem, flatmodes.index(mode))) else: print "Unknown mode '%s'" % s_p[1] except ValueError: print "Illegal opcode '%s'" % l[0] - return result + return result -def collate_chipset_map (cs_list, base): + +def collate_chipset_map(cs_list, base): result = {} - for (opcode, insts) in zip (range(256), cs_list): - if insts != None: + for (opcode, insts) in zip(range(256), cs_list): + if insts is not None: for inst in insts: (mnem, mode) = inst if mnem not in result: @@ -115,19 +121,26 @@ def collate_chipset_map (cs_list, base): del result[x] return result + def mapval(x): if x is None: return "None" else: return "0x%02X" % x -def dump_map (m, prologue = ''): + +def dump_map(m, prologue=''): mnems = m.keys() mnems.sort() for mnem in mnems: - print "%s'%s': [%s]," % (prologue, mnem, ', '.join([mapval(x) for x in m[mnem]])) + codes = [mapval(x) for x in m[mnem]] + print "%s'%s': [%s,\n%s %s]," % (prologue, mnem, + ', '.join(codes[:8]), + prologue + " " * len(mnem), + ', '.join(codes[8:])) -if __name__=='__main__': + +if __name__ == '__main__': if len(sys.argv) > 1: chipsets = argv[1:] else: @@ -135,7 +148,8 @@ if __name__=='__main__': archs = [] for x in chipsets: try: - ls = [[x.strip() for x in y] for y in [z.split(':', 1) for z in decomment_readlines (x)]] + ls = [[x.strip() for x in y] + for y in [z.split(':', 1) for z in decomment_readlines(x)]] for l in ls: if len(l) != 2: print "Could not parse the chipset line '%s'" % ":".join(l) @@ -147,10 +161,9 @@ if __name__=='__main__': baseset = None for (field, fname) in archs: chipset_list = parse_chipset_file(fname) - instruction_map = collate_chipset_map (chipset_list, baseset) - if baseset == None: + instruction_map = collate_chipset_map(chipset_list, baseset) + if baseset is None: baseset = instruction_map print "%s = {" % field - dump_map (instruction_map, ' ' * (len(field) + 4)) + dump_map(instruction_map, ' ' * (len(field) + 4)) print "%s}" % (' ' * (len(field) + 3)) - print "" diff --git a/tools/opcodes/op6502.txt b/tools/opcodes/op6502.txt index 9e3e8c5..524698a 100644 --- a/tools/opcodes/op6502.txt +++ b/tools/opcodes/op6502.txt @@ -1,256 +1,256 @@ 00: BRK - Implied 01: ORA - (Zero Page, X) - 02: - 03: - 04: + 02: + 03: + 04: 05: ORA - Zero Page 06: ASL - Zero Page - 07: + 07: 08: PHP - Implied 09: ORA - Immediate 0A: ASL - Implied - 0B: - 0C: + 0B: + 0C: 0D: ORA - Absolute 0E: ASL - Absolute - 0F: + 0F: 10: BPL - Relative 11: ORA - (Zero Page), Y - 12: - 13: - 14: + 12: + 13: + 14: 15: ORA - Zero Page, X 16: ASL - Zero Page, X - 17: + 17: 18: CLC - Implied 19: ORA - Absolute, Y - 1A: - 1B: - 1C: + 1A: + 1B: + 1C: 1D: ORA - Absolute, X 1E: ASL - Absolute, X - 1F: + 1F: 20: JSR - Absolute 21: AND - (Zero Page, X) - 22: - 23: + 22: + 23: 24: BIT - Zero Page 25: AND - Zero Page 26: ROL - Zero Page - 27: + 27: 28: PLP - Implied 29: AND - Immediate 2A: ROL - Implied - 2B: + 2B: 2C: BIT - Absolute 2D: AND - Absolute 2E: ROL - Absolute - 2F: + 2F: 30: BMI - Relative 31: AND - (Zero Page), Y - 32: - 33: - 34: + 32: + 33: + 34: 35: AND - Zero Page, X 36: ROL - Zero Page, X - 37: + 37: 38: SEC - Implied 39: AND - Absolute, Y - 3A: - 3B: - 3C: + 3A: + 3B: + 3C: 3D: AND - Absolute, X 3E: ROL - Absolute, X - 3F: + 3F: 40: RTI - Implied 41: EOR - (Zero Page, X) - 42: - 43: - 44: + 42: + 43: + 44: 45: EOR - Zero Page 46: LSR - Zero Page - 47: + 47: 48: PHA - Implied 49: EOR - Immediate 4A: LSR - Implied - 4B: + 4B: 4C: JMP - Absolute 4D: EOR - Absolute 4E: LSR - Absolute - 4F: + 4F: 50: BVC - Relative 51: EOR - (Zero Page), Y - 52: - 53: - 54: + 52: + 53: + 54: 55: EOR - Zero Page, X 56: LSR - Zero Page, X - 57: + 57: 58: CLI - Implied 59: EOR - Absolute, Y - 5A: - 5B: - 5C: + 5A: + 5B: + 5C: 5D: EOR - Absolute, X 5E: LSR - Absolute, X - 5F: + 5F: 60: RTS - Implied 61: ADC - (Zero Page, X) - 62: - 63: - 64: + 62: + 63: + 64: 65: ADC - Zero Page 66: ROR - Zero Page - 67: + 67: 68: PLA - Implied 69: ADC - Immediate 6A: ROR - Implied - 6B: + 6B: 6C: JMP - (Absolute) 6D: ADC - Absolute 6E: ROR - Absolute - 6F: + 6F: 70: BVS - Relative 71: ADC - (Zero Page), Y - 72: - 73: - 74: + 72: + 73: + 74: 75: ADC - Zero Page, X 76: ROR - Zero Page, X - 77: + 77: 78: SEI - Implied 79: ADC - Absolute, Y - 7A: - 7B: - 7C: + 7A: + 7B: + 7C: 7D: ADC - Absolute, X 7E: ROR - Absolute, X - 7F: - 80: + 7F: + 80: 81: STA - (Zero Page, X) - 82: - 83: + 82: + 83: 84: STY - Zero Page 85: STA - Zero Page 86: STX - Zero Page - 87: + 87: 88: DEY - Implied - 89: + 89: 8A: TXA - Implied - 8B: + 8B: 8C: STY - Absolute 8D: STA - Absolute 8E: STX - Absolute - 8F: + 8F: 90: BCC - Relative 91: STA - (Zero Page), Y - 92: - 93: + 92: + 93: 94: STY - Zero Page, X 95: STA - Zero Page, X 96: STX - Zero Page, Y - 97: + 97: 98: TYA - Implied 99: STA - Absolute, Y 9A: TXS - Implied - 9B: - 9C: + 9B: + 9C: 9D: STA - Absolute, X - 9E: - 9F: + 9E: + 9F: A0: LDY - Immediate A1: LDA - (Zero Page, X) A2: LDX - Immediate - A3: + A3: A4: LDY - Zero Page A5: LDA - Zero Page A6: LDX - Zero Page - A7: + A7: A8: TAY - Implied A9: LDA - Immediate AA: TAX - Implied - AB: + AB: AC: LDY - Absolute AD: LDA - Absolute AE: LDX - Absolute - AF: + AF: B0: BCS - Relative B1: LDA - (Zero Page), Y - B2: - B3: + B2: + B3: B4: LDY - Zero Page, X B5: LDA - Zero Page, X B6: LDX - Zero Page, Y - B7: + B7: B8: CLV - Implied B9: LDA - Absolute, Y BA: TSX - Implied - BB: + BB: BC: LDY - Absolute, X BD: LDA - Absolute, X BE: LDX - Absolute, Y - BF: + BF: C0: CPY - Immediate C1: CMP - (Zero Page, X) - C2: - C3: + C2: + C3: C4: CPY - Zero Page C5: CMP - Zero Page C6: DEC - Zero Page - C7: + C7: C8: INY - Implied C9: CMP - Immediate CA: DEX - Implied - CB: + CB: CC: CPY - Absolute CD: CMP - Absolute CE: DEC - Absolute - CF: + CF: D0: BNE - Relative D1: CMP - (Zero Page), Y - D2: - D3: - D4: + D2: + D3: + D4: D5: CMP - Zero Page, X D6: DEC - Zero Page, X - D7: + D7: D8: CLD - Implied D9: CMP - Absolute, Y - DA: - DB: - DC: + DA: + DB: + DC: DD: CMP - Absolute, X DE: DEC - Absolute, X - DF: + DF: E0: CPX - Immediate E1: SBC - (Zero Page, X) - E2: - E3: + E2: + E3: E4: CPX - Zero Page E5: SBC - Zero Page E6: INC - Zero Page - E7: + E7: E8: INX - Implied E9: SBC - Immediate EA: NOP - Implied - EB: + EB: EC: CPX - Absolute ED: SBC - Absolute EE: INC - Absolute - EF: + EF: F0: BEQ - Relative F1: SBC - (Zero Page), Y - F2: - F3: - F4: + F2: + F3: + F4: F5: SBC - Zero Page, X F6: INC - Zero Page, X - F7: + F7: F8: SED - Implied F9: SBC - Absolute, Y - FA: - FB: - FC: + FA: + FB: + FC: FD: SBC - Absolute, X FE: INC - Absolute, X - FF: + FF: diff --git a/tools/opcodes/op6510.txt b/tools/opcodes/op6510.txt index 2de216e..43b4f29 100644 --- a/tools/opcodes/op6510.txt +++ b/tools/opcodes/op6510.txt @@ -1,8 +1,8 @@ 00: BRK - Implied 01: ORA - (Zero Page, X) - 02: + 02: 03: SLO - (Zero Page, X) - 04: NOP - Zero Page + 04: NOP - Zero Page 05: ORA - Zero Page 06: ASL - Zero Page 07: SLO - Zero Page @@ -10,29 +10,29 @@ 09: ORA - Immediate 0A: ASL - Implied 0B: ANC - Immediate - 0C: + 0C: 0D: ORA - Absolute 0E: ASL - Absolute 0F: SLO - Absolute 10: BPL - Relative 11: ORA - (Zero Page), Y - 12: + 12: 13: SLO - (Zero Page), Y - 14: + 14: 15: ORA - Zero Page, X 16: ASL - Zero Page, X 17: SLO - Zero Page, X 18: CLC - Implied 19: ORA - Absolute, Y - 1A: + 1A: 1B: SLO - Absolute, Y - 1C: + 1C: 1D: ORA - Absolute, X 1E: ASL - Absolute, X 1F: SLO - Absolute, X 20: JSR - Absolute 21: AND - (Zero Page, X) - 22: + 22: 23: RLA - (Zero Page, X) 24: BIT - Zero Page 25: AND - Zero Page @@ -41,32 +41,32 @@ 28: PLP - Implied 29: AND - Immediate 2A: ROL - Implied - 2B: + 2B: 2C: BIT - Absolute 2D: AND - Absolute 2E: ROL - Absolute 2F: RLA - Absolute 30: BMI - Relative 31: AND - (Zero Page), Y - 32: + 32: 33: RLA - (Zero Page), Y - 34: + 34: 35: AND - Zero Page, X 36: ROL - Zero Page, X 37: RLA - Zero Page, X 38: SEC - Implied 39: AND - Absolute, Y - 3A: + 3A: 3B: RLA - Absolute, Y - 3C: + 3C: 3D: AND - Absolute, X 3E: ROL - Absolute, X 3F: RLA - Absolute, X 40: RTI - Implied 41: EOR - (Zero Page, X) - 42: + 42: 43: SRE - (Zero Page, X) - 44: + 44: 45: EOR - Zero Page 46: LSR - Zero Page 47: SRE - Zero Page @@ -80,25 +80,25 @@ 4F: SRE - Absolute 50: BVC - Relative 51: EOR - (Zero Page), Y - 52: + 52: 53: SRE - (Zero Page), Y - 54: + 54: 55: EOR - Zero Page, X 56: LSR - Zero Page, X 57: SRE - Zero Page, X 58: CLI - Implied 59: EOR - Absolute, Y - 5A: + 5A: 5B: SRE - Absolute, Y - 5C: + 5C: 5D: EOR - Absolute, X 5E: LSR - Absolute, X 5F: SRE - Absolute, X 60: RTS - Implied 61: ADC - (Zero Page, X) - 62: + 62: 63: RRA - (Zero Page, X) - 64: + 64: 65: ADC - Zero Page 66: ROR - Zero Page 67: RRA - Zero Page @@ -112,30 +112,30 @@ 6F: RRA - Absolute 70: BVS - Relative 71: ADC - (Zero Page), Y - 72: + 72: 73: RRA - (Zero Page), Y - 74: + 74: 75: ADC - Zero Page, X 76: ROR - Zero Page, X 77: RRA - Zero Page, X 78: SEI - Implied 79: ADC - Absolute, Y - 7A: + 7A: 7B: RRA - Absolute, Y - 7C: + 7C: 7D: ADC - Absolute, X 7E: ROR - Absolute, X 7F: RRA - Absolute, X - 80: + 80: 81: STA - (Zero Page, X) - 82: + 82: 83: SAX - (Zero Page, X) 84: STY - Zero Page 85: STA - Zero Page 86: STX - Zero Page 87: SAX - Zero Page 88: DEY - Implied - 89: + 89: 8A: TXA - Implied 8B: ANE - Immediate 8C: STY - Absolute @@ -144,7 +144,7 @@ 8F: SAX - Absolute 90: BCC - Relative 91: STA - (Zero Page), Y - 92: + 92: 93: SHA - (Zero Page), Y 94: STY - Zero Page, X 95: STA - Zero Page, X @@ -154,7 +154,7 @@ 99: STA - Absolute, Y 9A: TXS - Implied 9B: SHS - Absolute, Y - 9C: + 9C: 9D: STA - Absolute, X 9E: SHX - Absolute, Y 9F: SHA - Absolute, Y @@ -176,7 +176,7 @@ AF: LAX - Absolute B0: BCS - Relative B1: LDA - (Zero Page), Y - B2: + B2: B3: LAX - (Zero Page), Y B4: LDY - Zero Page, X B5: LDA - Zero Page, X @@ -192,7 +192,7 @@ BF: LAX - Absolute, Y C0: CPY - Immediate C1: CMP - (Zero Page, X) - C2: + C2: C3: DCP - (Zero Page, X) C4: CPY - Zero Page C5: CMP - Zero Page @@ -208,23 +208,23 @@ CF: DCP - Absolute D0: BNE - Relative D1: CMP - (Zero Page), Y - D2: + D2: D3: DCP - (Zero Page), Y - D4: + D4: D5: CMP - Zero Page, X D6: DEC - Zero Page, X D7: DCP - Zero Page, X D8: CLD - Implied D9: CMP - Absolute, Y - DA: + DA: DB: DCP - Absolute, Y - DC: + DC: DD: CMP - Absolute, X DE: DEC - Absolute, X DF: DCP - Absolute, X E0: CPX - Immediate E1: SBC - (Zero Page, X) - E2: + E2: E3: ISB - (Zero Page, X) E4: CPX - Zero Page E5: SBC - Zero Page @@ -233,24 +233,24 @@ E8: INX - Implied E9: SBC - Immediate EA: NOP - Implied - EB: + EB: EC: CPX - Absolute ED: SBC - Absolute EE: INC - Absolute EF: ISB - Absolute F0: BEQ - Relative F1: SBC - (Zero Page), Y - F2: + F2: F3: ISB - (Zero Page), Y - F4: + F4: F5: SBC - Zero Page, X F6: INC - Zero Page, X F7: ISB - Zero Page, X F8: SED - Implied F9: SBC - Absolute, Y - FA: + FA: FB: ISB - Absolute, Y - FC: + FC: FD: SBC - Absolute, X FE: INC - Absolute, X FF: ISB - Absolute, X diff --git a/tools/opcodes/op65c02.txt b/tools/opcodes/op65c02.txt index ebe8c94..9072f27 100644 --- a/tools/opcodes/op65c02.txt +++ b/tools/opcodes/op65c02.txt @@ -1,7 +1,7 @@ 00: BRK - Implied 01: ORA - (Zero Page, X) - 02: - 03: + 02: + 03: 04: TSB - Zero Page 05: ORA - Zero Page 06: ASL - Zero Page @@ -9,7 +9,7 @@ 08: PHP - Implied 09: ORA - Immediate 0A: ASL - Implied - 0B: + 0B: 0C: TSB - Absolute 0D: ORA - Absolute 0E: ASL - Absolute @@ -17,7 +17,7 @@ 10: BPL - Relative 11: ORA - (Zero Page), Y 12: ORA - (Zero Page) - 13: + 13: 14: TRB - Zero Page 15: ORA - Zero Page, X 16: ASL - Zero Page, X @@ -25,15 +25,15 @@ 18: CLC - Implied 19: ORA - Absolute, Y 1A: INA - Implied; INC - Implied - 1B: + 1B: 1C: TRB - Absolute 1D: ORA - Absolute, X 1E: ASL - Absolute, X 1F: BBR1 - Relative 20: JSR - Absolute 21: AND - (Zero Page, X) - 22: - 23: + 22: + 23: 24: BIT - Zero Page 25: AND - Zero Page 26: ROL - Zero Page @@ -41,7 +41,7 @@ 28: PLP - Implied 29: AND - Immediate 2A: ROL - Implied - 2B: + 2B: 2C: BIT - Absolute 2D: AND - Absolute 2E: ROL - Absolute @@ -49,7 +49,7 @@ 30: BMI - Relative 31: AND - (Zero Page), Y 32: AND - (Zero Page) - 33: + 33: 34: BIT - Zero Page, X 35: AND - Zero Page, X 36: ROL - Zero Page, X @@ -57,23 +57,23 @@ 38: SEC - Implied 39: AND - Absolute, Y 3A: DEA - Implied; DEC - Implied - 3B: + 3B: 3C: BIT - Absolute, X 3D: AND - Absolute, X 3E: ROL - Absolute, X 3F: BBR3 - Relative 40: RTI - Implied 41: EOR - (Zero Page, X) - 42: - 43: - 44: + 42: + 43: + 44: 45: EOR - Zero Page 46: LSR - Zero Page 47: RMB4 - Zero Page 48: PHA - Implied 49: EOR - Immediate 4A: LSR - Implied - 4B: + 4B: 4C: JMP - Absolute 4D: EOR - Absolute 4E: LSR - Absolute @@ -81,23 +81,23 @@ 50: BVC - Relative 51: EOR - (Zero Page), Y 52: EOR - (Zero Page) - 53: - 54: + 53: + 54: 55: EOR - Zero Page, X 56: LSR - Zero Page, X 57: RMB5 - Zero Page 58: CLI - Implied 59: EOR - Absolute, Y 5A: PHY - Implied - 5B: - 5C: + 5B: + 5C: 5D: EOR - Absolute, X 5E: LSR - Absolute, X 5F: BBR5 - Relative 60: RTS - Implied 61: ADC - (Zero Page, X) - 62: - 63: + 62: + 63: 64: STZ - Zero Page 65: ADC - Zero Page 66: ROR - Zero Page @@ -105,7 +105,7 @@ 68: PLA - Implied 69: ADC - Immediate 6A: ROR - Implied - 6B: + 6B: 6C: JMP - (Absolute) 6D: ADC - Absolute 6E: ROR - Absolute @@ -113,7 +113,7 @@ 70: BVS - Relative 71: ADC - (Zero Page), Y 72: ADC - (Zero Page) - 73: + 73: 74: STZ - Zero Page, X 75: ADC - Zero Page, X 76: ROR - Zero Page, X @@ -121,15 +121,15 @@ 78: SEI - Implied 79: ADC - Absolute, Y 7A: PLY - Implied - 7B: + 7B: 7C: JMP - (Absolute, X) 7D: ADC - Absolute, X 7E: ROR - Absolute, X 7F: BBR7 - Relative 80: BRA - Relative 81: STA - (Zero Page, X) - 82: - 83: + 82: + 83: 84: STY - Zero Page 85: STA - Zero Page 86: STX - Zero Page @@ -137,7 +137,7 @@ 88: DEY - Implied 89: BIT - Immediate 8A: TXA - Implied - 8B: + 8B: 8C: STY - Absolute 8D: STA - Absolute 8E: STX - Absolute @@ -145,7 +145,7 @@ 90: BCC - Relative 91: STA - (Zero Page), Y 92: STA - (Zero Page) - 93: + 93: 94: STY - Zero Page, X 95: STA - Zero Page, X 96: STX - Zero Page, Y @@ -153,7 +153,7 @@ 98: TYA - Implied 99: STA - Absolute, Y 9A: TXS - Implied - 9B: + 9B: 9C: STZ - Absolute 9D: STA - Absolute, X 9E: STZ - Absolute, X @@ -161,7 +161,7 @@ A0: LDY - Immediate A1: LDA - (Zero Page, X) A2: LDX - Immediate - A3: + A3: A4: LDY - Zero Page A5: LDA - Zero Page A6: LDX - Zero Page @@ -169,7 +169,7 @@ A8: TAY - Implied A9: LDA - Immediate AA: TAX - Implied - AB: + AB: AC: LDY - Absolute AD: LDA - Absolute AE: LDX - Absolute @@ -177,7 +177,7 @@ B0: BCS - Relative B1: LDA - (Zero Page), Y B2: LDA - (Zero Page) - B3: + B3: B4: LDY - Zero Page, X B5: LDA - Zero Page, X B6: LDX - Zero Page, Y @@ -185,15 +185,15 @@ B8: CLV - Implied B9: LDA - Absolute, Y BA: TSX - Implied - BB: + BB: BC: LDY - Absolute, X BD: LDA - Absolute, X BE: LDX - Absolute, Y BF: BBS3 - Relative C0: CPY - Immediate C1: CMP - (Zero Page, X) - C2: - C3: + C2: + C3: C4: CPY - Zero Page C5: CMP - Zero Page C6: DEC - Zero Page @@ -209,8 +209,8 @@ D0: BNE - Relative D1: CMP - (Zero Page), Y D2: CMP - (Zero Page) - D3: - D4: + D3: + D4: D5: CMP - Zero Page, X D6: DEC - Zero Page, X D7: SMB5 - Zero Page @@ -218,14 +218,14 @@ D9: CMP - Absolute, Y DA: PHX - Implied DB: STP - Implied - DC: + DC: DD: CMP - Absolute, X DE: DEC - Absolute, X DF: BBS5 - Relative E0: CPX - Immediate E1: SBC - (Zero Page, X) - E2: - E3: + E2: + E3: E4: CPX - Zero Page E5: SBC - Zero Page E6: INC - Zero Page @@ -233,7 +233,7 @@ E8: INX - Implied E9: SBC - Immediate EA: NOP - Implied - EB: + EB: EC: CPX - Absolute ED: SBC - Absolute EE: INC - Absolute @@ -241,16 +241,16 @@ F0: BEQ - Relative F1: SBC - (Zero Page), Y F2: SBC - (Zero Page) - F3: - F4: + F3: + F4: F5: SBC - Zero Page, X F6: INC - Zero Page, X F7: SMB7 - Zero Page F8: SED - Implied F9: SBC - Absolute, Y FA: PLX - Implied - FB: - FC: + FB: + FC: FD: SBC - Absolute, X FE: INC - Absolute, X FF: BBS7 - Relative