Massive code modernization spree.

Full PEP8 compliance. Also, booleans have been inserted where
they make sense (introduced in 2.3!) and I haven't knowingly
added anything that will break 2.3 compatibility.

At this point the code really doesn't look like it was written
ten years ago. Hooray!
This commit is contained in:
Michael C. Martin 2012-06-01 10:25:48 -07:00
parent f83379287f
commit 14a37ca879
38 changed files with 1459 additions and 925 deletions

2
README
View File

@ -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.
THE SOFTWARE.

View File

@ -9,4 +9,4 @@ _next: .word 0 ; End of program
.advance 2064
.require "kernal.oph"
.require "kernal.oph"

View File

@ -37,4 +37,4 @@ _next: .word 0 ; End of program
_main:
; Program follows...
.scend
.scend

View File

@ -249,7 +249,7 @@
.checkpc $100
</programlisting>
</section>
</section>
</section>
<section>
<title>Macros</title>
<para>
@ -400,7 +400,7 @@
code in and of itself, nor does it overwrite anything that
previously existed.</emphasis> If you wish to jump ahead in memory,
use <literal>.advance</literal>.</para></listitem>
<listitem><para><literal>.require</literal> <emphasis>filename</emphasis>: Includes the entirety
<listitem><para><literal>.require</literal> <emphasis>filename</emphasis>: Includes the entirety
of the file specified at that point in the program. Unlike <literal>.include</literal>,
however, code included with <literal>.require</literal> will only be inserted once.
The <literal>.require</literal> directive is useful for ensuring that certain code libraries
@ -447,5 +447,5 @@
macro definition intends to read. A shorthand for <literal>.invoke</literal>
is the name of the macro to invoke, backquoted.</para></listitem>
</itemizedlist>
</section>
</section>
</appendix>

View File

@ -333,7 +333,7 @@ delay: tax
iny
bne -
dex
bne -
bne -
rts
</programlisting>
</section>

View File

@ -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 <literal>next</literal>.
</para></listitem>
<listitem><para>
<listitem><para>
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.
</para></listitem>
<listitem><para>
<listitem><para>
Instead of adding the buffer ourselves, we
used <literal>.advance</literal>, which outputs zeros until
the specified address is reached. Attempting
to <literal>.advance</literal> backwards produces an
assemble-time error.
</para></listitem>
<listitem><para>
<listitem><para>
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
<row>
<entry align="center">Option</entry>
<entry align="center">Effect</entry>
</row>
</row>
</thead>
<tbody>
<tbody>
<row><entry><option>-6510</option></entry><entry>Allows the 6510 undocumented opcodes as listed in the VICE documentation.</entry></row>
<row><entry><option>-65c02</option></entry><entry>Allows opcodes and addressing modes added by the 65C02.</entry></row>
<row><entry><option>-v 0</option></entry><entry>Quiet operation. Only reports errors.</entry></row>

View File

@ -64,4 +64,4 @@
; ...and character set
.alias upper'case 142
.alias lower'case 14
.alias lower'case 14

View File

@ -15,4 +15,4 @@ loop: lda hello, x
bne loop
done: rts
hello: .byte "HELLO, WORLD!", 0
hello: .byte "HELLO, WORLD!", 0

View File

@ -19,4 +19,4 @@ _next: .word 0 ; End of program
bne -
* rts
hello: .byte "HELLO, WORLD!", 0
hello: .byte "HELLO, WORLD!", 0

View File

@ -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
target10: .byte "UNIVERSE", 0

View File

@ -63,7 +63,7 @@ delay: tax
bne -
dex
bne -
rts

View File

@ -65,7 +65,7 @@ delay: tax
bne -
dex
bne -
rts

View File

@ -68,6 +68,6 @@ delay: tax
bne -
dex
bne -
rts
rts

View File

@ -72,4 +72,4 @@ delay: sta _tmp ; save argument (rdtim destroys it)
.checkpc $A000
.data
.checkpc $D000
.checkpc $D000

View File

@ -99,4 +99,4 @@ _done: rts
.checkpc $A000
.data
.checkpc $D000
.checkpc $D000

View File

@ -93,4 +93,4 @@ _done: rts
.checkpc $D000
.data zp
.checkpc $80
.checkpc $80

View File

@ -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

View File

@ -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":

View File

@ -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)

View File

@ -12,15 +12,20 @@ import sys
count = 0
currentpoint = "<Top Level>"
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"

View File

@ -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("<Top Level>", filename)

View File

@ -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>", "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 "<UNKNOWN: "+`self.data`+">"
def valid(self, env=None, PCvalid=0):
return "<UNKNOWN: " + repr(self.data) + ">"
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

View File

@ -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, ""

View File

@ -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:])

View File

@ -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],
}

View File

@ -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)

View File

@ -155,4 +155,4 @@ Section Uninstall
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
SetAutoClose true
SectionEnd
SectionEnd

View File

@ -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'])

View File

@ -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"}])

View File

@ -51,4 +51,4 @@ late:
jmp early
* bne +
jmp early
*
*

View File

@ -76,4 +76,4 @@
ISB $F7, X
ISB $FBFB, Y
ISB $FFFF, X

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 ""

View File

@ -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:

View File

@ -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

View File

@ -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