mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-06-16 08:29:35 +00:00
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:
parent
f83379287f
commit
14a37ca879
|
@ -22,28 +22,43 @@ print_labels = False
|
||||||
infile = None
|
infile = None
|
||||||
outfile = None
|
outfile = None
|
||||||
|
|
||||||
|
|
||||||
def parse_args(raw_args):
|
def parse_args(raw_args):
|
||||||
"Populate the module's globals based on the command-line options given."
|
"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 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
|
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 = optparse.OptionGroup(parser, "Input options")
|
||||||
ingrp.add_option("-u", "--undoc", action="store_true", default=False, help="Enable 6502 undocumented opcodes")
|
ingrp.add_option("-u", "--undoc", action="store_true", default=False,
|
||||||
ingrp.add_option("-c", "--65c02", action="store_true", default=False, dest="c02", help="Enable 65c02 extended instruction set")
|
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 = optparse.OptionGroup(parser, "Console output options")
|
||||||
outgrp.add_option("-v", "--verbose", action="store_const", const=2, help="Verbose mode", default=1)
|
outgrp.add_option("-v", "--verbose", action="store_const", const=2,
|
||||||
outgrp.add_option("-q", "--quiet", action="store_const", help="Quiet mode", dest="verbose", const=0)
|
help="Verbose mode", default=1)
|
||||||
outgrp.add_option("-d", "--debug", action="count", dest="verbose", help=optparse.SUPPRESS_HELP)
|
outgrp.add_option("-q", "--quiet", action="store_const", help="Quiet mode",
|
||||||
outgrp.add_option("--no-warn", action="store_false", dest="warn", default=True, help="Do not print warnings")
|
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 = 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-collapse", action="store_false",
|
||||||
bingrp.add_option("--no-branch-extend", action="store_false", dest="enable_branch_extend", default="True", help="Disable branch-extension pass")
|
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(ingrp)
|
||||||
parser.add_option_group(outgrp)
|
parser.add_option_group(outgrp)
|
||||||
|
|
|
@ -10,46 +10,52 @@ import Ophis.IR as IR
|
||||||
import Ophis.Frontend as FE
|
import Ophis.Frontend as FE
|
||||||
import Ophis.Errors as Err
|
import Ophis.Errors as Err
|
||||||
|
|
||||||
loadedfiles={}
|
loadedfiles = {}
|
||||||
basecharmap = "".join([chr(x) for x in range(256)])
|
basecharmap = "".join([chr(x) for x in range(256)])
|
||||||
currentcharmap = basecharmap
|
currentcharmap = basecharmap
|
||||||
|
|
||||||
|
|
||||||
def reset():
|
def reset():
|
||||||
global loadedfiles, currentcharmap, basecharmap
|
global loadedfiles, currentcharmap, basecharmap
|
||||||
loadedfiles={}
|
loadedfiles = {}
|
||||||
currentcharmap = basecharmap
|
currentcharmap = basecharmap
|
||||||
|
|
||||||
|
|
||||||
def pragmaInclude(ppt, line, result):
|
def pragmaInclude(ppt, line, result):
|
||||||
"Includes a source file"
|
"Includes a source file"
|
||||||
filename = line.expect("STRING").value
|
filename = line.expect("STRING").value
|
||||||
line.expect("EOL")
|
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):
|
def pragmaRequire(ppt, line, result):
|
||||||
"Includes a source file at most one time"
|
"Includes a source file at most one time"
|
||||||
filename = line.expect("STRING").value
|
filename = line.expect("STRING").value
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
if type(filename)==str:
|
if type(filename) == str:
|
||||||
global loadedfiles
|
global loadedfiles
|
||||||
if filename not in loadedfiles:
|
if filename not in loadedfiles:
|
||||||
loadedfiles[filename]=1
|
loadedfiles[filename] = True
|
||||||
result.append(FE.parse_file(ppt, filename))
|
result.append(FE.parse_file(ppt, filename))
|
||||||
|
|
||||||
|
|
||||||
def pragmaIncbin(ppt, line, result):
|
def pragmaIncbin(ppt, line, result):
|
||||||
"Includes a binary file"
|
"Includes a binary file"
|
||||||
filename = line.expect("STRING").value
|
filename = line.expect("STRING").value
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
if type(filename)==str:
|
if type(filename) == str:
|
||||||
try:
|
try:
|
||||||
f = file(filename, "rb")
|
f = file(filename, "rb")
|
||||||
bytes = f.read()
|
bytes = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
Err.log ("Could not read "+filename)
|
Err.log("Could not read " + filename)
|
||||||
return
|
return
|
||||||
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
||||||
result.append(IR.Node(ppt, "Byte", *bytes))
|
result.append(IR.Node(ppt, "Byte", *bytes))
|
||||||
|
|
||||||
|
|
||||||
def pragmaCharmap(ppt, line, result):
|
def pragmaCharmap(ppt, line, result):
|
||||||
"Modify the character map."
|
"Modify the character map."
|
||||||
global currentcharmap, basecharmap
|
global currentcharmap, basecharmap
|
||||||
|
@ -60,30 +66,33 @@ def pragmaCharmap(ppt, line, result):
|
||||||
try:
|
try:
|
||||||
base = bytes[0].data
|
base = bytes[0].data
|
||||||
newsubstr = "".join([chr(x.data) for x in bytes[1:]])
|
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:
|
if len(currentcharmap) != 256 or base < 0 or base > 255:
|
||||||
Err.log("Charmap replacement out of range")
|
Err.log("Charmap replacement out of range")
|
||||||
currentcharmap = currentcharmap[:256]
|
currentcharmap = currentcharmap[:256]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
Err.log("Illegal character in .charmap directive")
|
Err.log("Illegal character in .charmap directive")
|
||||||
|
|
||||||
|
|
||||||
def pragmaCharmapbin(ppt, line, result):
|
def pragmaCharmapbin(ppt, line, result):
|
||||||
"Load a new character map from a file"
|
"Load a new character map from a file"
|
||||||
global currentcharmap
|
global currentcharmap
|
||||||
filename = line.expect("STRING").value
|
filename = line.expect("STRING").value
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
if type(filename)==str:
|
if type(filename) == str:
|
||||||
try:
|
try:
|
||||||
f = file(filename, "rb")
|
f = file(filename, "rb")
|
||||||
bytes = f.read()
|
bytes = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
Err.log ("Could not read "+filename)
|
Err.log("Could not read " + filename)
|
||||||
return
|
return
|
||||||
if len(bytes)==256:
|
if len(bytes) == 256:
|
||||||
currentcharmap = bytes
|
currentcharmap = bytes
|
||||||
else:
|
else:
|
||||||
Err.log("Character map "+filename+" not 256 bytes long")
|
Err.log("Character map " + filename + " not 256 bytes long")
|
||||||
|
|
||||||
|
|
||||||
def pragmaOrg(ppt, line, result):
|
def pragmaOrg(ppt, line, result):
|
||||||
"Relocates the PC with no output"
|
"Relocates the PC with no output"
|
||||||
|
@ -91,6 +100,7 @@ def pragmaOrg(ppt, line, result):
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "SetPC", newPC))
|
result.append(IR.Node(ppt, "SetPC", newPC))
|
||||||
|
|
||||||
|
|
||||||
def pragmaAdvance(ppt, line, result):
|
def pragmaAdvance(ppt, line, result):
|
||||||
"Outputs filler until reaching the target PC"
|
"Outputs filler until reaching the target PC"
|
||||||
newPC = FE.parse_expr(line)
|
newPC = FE.parse_expr(line)
|
||||||
|
@ -102,25 +112,31 @@ def pragmaAdvance(ppt, line, result):
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "Advance", newPC, fillexpr))
|
result.append(IR.Node(ppt, "Advance", newPC, fillexpr))
|
||||||
|
|
||||||
|
|
||||||
def pragmaCheckpc(ppt, line, result):
|
def pragmaCheckpc(ppt, line, result):
|
||||||
"Enforces that the PC has not exceeded a certain point"
|
"Enforces that the PC has not exceeded a certain point"
|
||||||
target = FE.parse_expr(line)
|
target = FE.parse_expr(line)
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "CheckPC", target))
|
result.append(IR.Node(ppt, "CheckPC", target))
|
||||||
|
|
||||||
|
|
||||||
def pragmaAlias(ppt, line, result):
|
def pragmaAlias(ppt, line, result):
|
||||||
"Assigns an arbitrary label"
|
"Assigns an arbitrary label"
|
||||||
lbl = line.expect("LABEL").value
|
lbl = line.expect("LABEL").value
|
||||||
target = FE.parse_expr(line)
|
target = FE.parse_expr(line)
|
||||||
result.append(IR.Node(ppt, "Label", lbl, target))
|
result.append(IR.Node(ppt, "Label", lbl, target))
|
||||||
|
|
||||||
|
|
||||||
def pragmaSpace(ppt, line, result):
|
def pragmaSpace(ppt, line, result):
|
||||||
"Reserves space in a data segment for a variable"
|
"Reserves space in a data segment for a variable"
|
||||||
lbl = line.expect("LABEL").value
|
lbl = line.expect("LABEL").value
|
||||||
size = line.expect("NUM").value
|
size = line.expect("NUM").value
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "Label", lbl, IR.PCExpr()))
|
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):
|
def pragmaText(ppt, line, result):
|
||||||
"Switches to a text segment"
|
"Switches to a text segment"
|
||||||
|
@ -132,6 +148,7 @@ def pragmaText(ppt, line, result):
|
||||||
segment = "*text-default*"
|
segment = "*text-default*"
|
||||||
result.append(IR.Node(ppt, "TextSegment", segment))
|
result.append(IR.Node(ppt, "TextSegment", segment))
|
||||||
|
|
||||||
|
|
||||||
def pragmaData(ppt, line, result):
|
def pragmaData(ppt, line, result):
|
||||||
"Switches to a data segment (no output allowed)"
|
"Switches to a data segment (no output allowed)"
|
||||||
next = line.expect("LABEL", "EOL")
|
next = line.expect("LABEL", "EOL")
|
||||||
|
@ -142,67 +159,80 @@ def pragmaData(ppt, line, result):
|
||||||
segment = "*data-default*"
|
segment = "*data-default*"
|
||||||
result.append(IR.Node(ppt, "DataSegment", segment))
|
result.append(IR.Node(ppt, "DataSegment", segment))
|
||||||
|
|
||||||
|
|
||||||
def readData(line):
|
def readData(line):
|
||||||
"Read raw data from a comma-separated list"
|
"Read raw data from a comma-separated list"
|
||||||
if line.lookahead(0).type == "STRING":
|
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:
|
else:
|
||||||
data = [FE.parse_expr(line)]
|
data = [FE.parse_expr(line)]
|
||||||
next = line.expect(',', 'EOL').type
|
next = line.expect(',', 'EOL').type
|
||||||
while next == ',':
|
while next == ',':
|
||||||
if line.lookahead(0).type == "STRING":
|
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:
|
else:
|
||||||
data.append(FE.parse_expr(line))
|
data.append(FE.parse_expr(line))
|
||||||
next = line.expect(',', 'EOL').type
|
next = line.expect(',', 'EOL').type
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def pragmaByte(ppt, line, result):
|
def pragmaByte(ppt, line, result):
|
||||||
"Raw data, a byte at a time"
|
"Raw data, a byte at a time"
|
||||||
bytes = readData(line)
|
bytes = readData(line)
|
||||||
result.append(IR.Node(ppt, "Byte", *bytes))
|
result.append(IR.Node(ppt, "Byte", *bytes))
|
||||||
|
|
||||||
|
|
||||||
def pragmaWord(ppt, line, result):
|
def pragmaWord(ppt, line, result):
|
||||||
"Raw data, a word at a time, little-endian"
|
"Raw data, a word at a time, little-endian"
|
||||||
words = readData(line)
|
words = readData(line)
|
||||||
result.append(IR.Node(ppt, "Word", *words))
|
result.append(IR.Node(ppt, "Word", *words))
|
||||||
|
|
||||||
|
|
||||||
def pragmaDword(ppt, line, result):
|
def pragmaDword(ppt, line, result):
|
||||||
"Raw data, a double-word at a time, little-endian"
|
"Raw data, a double-word at a time, little-endian"
|
||||||
dwords = readData(line)
|
dwords = readData(line)
|
||||||
result.append(IR.Node(ppt, "Dword", *dwords))
|
result.append(IR.Node(ppt, "Dword", *dwords))
|
||||||
|
|
||||||
|
|
||||||
def pragmaWordbe(ppt, line, result):
|
def pragmaWordbe(ppt, line, result):
|
||||||
"Raw data, a word at a time, big-endian"
|
"Raw data, a word at a time, big-endian"
|
||||||
words = readData(line)
|
words = readData(line)
|
||||||
result.append(IR.Node(ppt, "WordBE", *words))
|
result.append(IR.Node(ppt, "WordBE", *words))
|
||||||
|
|
||||||
|
|
||||||
def pragmaDwordbe(ppt, line, result):
|
def pragmaDwordbe(ppt, line, result):
|
||||||
"Raw data, a dword at a time, big-endian"
|
"Raw data, a dword at a time, big-endian"
|
||||||
dwords = readData(line)
|
dwords = readData(line)
|
||||||
result.append(IR.Node(ppt, "DwordBE", *dwords))
|
result.append(IR.Node(ppt, "DwordBE", *dwords))
|
||||||
|
|
||||||
|
|
||||||
def pragmaScope(ppt, line, result):
|
def pragmaScope(ppt, line, result):
|
||||||
"Create a new lexical scoping block"
|
"Create a new lexical scoping block"
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "ScopeBegin"))
|
result.append(IR.Node(ppt, "ScopeBegin"))
|
||||||
|
|
||||||
|
|
||||||
def pragmaScend(ppt, line, result):
|
def pragmaScend(ppt, line, result):
|
||||||
"End the innermost lexical scoping block"
|
"End the innermost lexical scoping block"
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "ScopeEnd"))
|
result.append(IR.Node(ppt, "ScopeEnd"))
|
||||||
|
|
||||||
|
|
||||||
def pragmaMacro(ppt, line, result):
|
def pragmaMacro(ppt, line, result):
|
||||||
"Begin a macro definition"
|
"Begin a macro definition"
|
||||||
lbl = line.expect("LABEL").value
|
lbl = line.expect("LABEL").value
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "MacroBegin", lbl))
|
result.append(IR.Node(ppt, "MacroBegin", lbl))
|
||||||
|
|
||||||
|
|
||||||
def pragmaMacend(ppt, line, result):
|
def pragmaMacend(ppt, line, result):
|
||||||
"End a macro definition"
|
"End a macro definition"
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
result.append(IR.Node(ppt, "MacroEnd"))
|
result.append(IR.Node(ppt, "MacroEnd"))
|
||||||
|
|
||||||
|
|
||||||
def pragmaInvoke(ppt, line, result):
|
def pragmaInvoke(ppt, line, result):
|
||||||
macro = line.expect("LABEL").value
|
macro = line.expect("LABEL").value
|
||||||
if line.lookahead(0).type == "EOL":
|
if line.lookahead(0).type == "EOL":
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
import Ophis.Errors as Err
|
import Ophis.Errors as Err
|
||||||
|
|
||||||
|
|
||||||
class Environment(object):
|
class Environment(object):
|
||||||
"""Environment class.
|
"""Environment class.
|
||||||
Controls the various scopes and global abstract execution variables."""
|
Controls the various scopes and global abstract execution variables."""
|
||||||
|
@ -19,39 +20,52 @@ class Environment(object):
|
||||||
self.segmentdict = {}
|
self.segmentdict = {}
|
||||||
self.segment = "*text-default*"
|
self.segment = "*text-default*"
|
||||||
self.scopecount = 0
|
self.scopecount = 0
|
||||||
|
|
||||||
def __contains__(self, item):
|
def __contains__(self, item):
|
||||||
if item[0] == '_':
|
if item[0] == '_':
|
||||||
for dict in [self.dicts[i] for i in self.stack]:
|
for dict in [self.dicts[i] for i in self.stack]:
|
||||||
if item in dict: return 1
|
if item in dict:
|
||||||
return 0
|
return True
|
||||||
|
return False
|
||||||
return item in self.dicts[0]
|
return item in self.dicts[0]
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
if item[0] == '_':
|
if item[0] == '_':
|
||||||
for dict in [self.dicts[i] for i in self.stack]:
|
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:
|
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)
|
Err.log("Unknown label '%s'" % item)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def __setitem__(self, item, value):
|
def __setitem__(self, item, value):
|
||||||
if item[0] == '_':
|
if item[0] == '_':
|
||||||
self.dicts[self.stack[0]][item] = value
|
self.dicts[self.stack[0]][item] = value
|
||||||
else:
|
else:
|
||||||
self.dicts[0][item] = value
|
self.dicts[0][item] = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.dicts)
|
return str(self.dicts)
|
||||||
|
|
||||||
def getPC(self):
|
def getPC(self):
|
||||||
return self.pc
|
return self.pc
|
||||||
|
|
||||||
def setPC(self, value):
|
def setPC(self, value):
|
||||||
self.pc = value
|
self.pc = value
|
||||||
|
|
||||||
def incPC(self, amount):
|
def incPC(self, amount):
|
||||||
self.pc += amount
|
self.pc += amount
|
||||||
|
|
||||||
def getsegment(self):
|
def getsegment(self):
|
||||||
return self.segment
|
return self.segment
|
||||||
|
|
||||||
def setsegment(self, segment):
|
def setsegment(self, segment):
|
||||||
self.segmentdict[self.segment] = self.pc
|
self.segmentdict[self.segment] = self.pc
|
||||||
self.segment = segment
|
self.segment = segment
|
||||||
self.pc = self.segmentdict.get(segment, 0)
|
self.pc = self.segmentdict.get(segment, 0)
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
"Clears out program counter, segment, and scoping information"
|
"Clears out program counter, segment, and scoping information"
|
||||||
self.pc = 0
|
self.pc = 0
|
||||||
|
@ -61,14 +75,16 @@ class Environment(object):
|
||||||
if len(self.stack) > 1:
|
if len(self.stack) > 1:
|
||||||
Err.log("Unmatched .scope")
|
Err.log("Unmatched .scope")
|
||||||
self.stack = [0]
|
self.stack = [0]
|
||||||
|
|
||||||
def newscope(self):
|
def newscope(self):
|
||||||
"Enters a new scope for temporary labels."
|
"Enters a new scope for temporary labels."
|
||||||
self.scopecount += 1
|
self.scopecount += 1
|
||||||
self.stack.insert(0, self.scopecount)
|
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):
|
def endscope(self):
|
||||||
"Leaves a scope."
|
"Leaves a scope."
|
||||||
if len(self.stack) == 1:
|
if len(self.stack) == 1:
|
||||||
Err.log("Unmatched .scend")
|
Err.log("Unmatched .scend")
|
||||||
self.stack.pop(0)
|
self.stack.pop(0)
|
||||||
|
|
||||||
|
|
|
@ -12,15 +12,20 @@ import sys
|
||||||
count = 0
|
count = 0
|
||||||
currentpoint = "<Top Level>"
|
currentpoint = "<Top Level>"
|
||||||
|
|
||||||
|
|
||||||
def log(err):
|
def log(err):
|
||||||
"""Reports an error at the current program point, and increases
|
"""Reports an error at the current program point, and increases
|
||||||
the global error count."""
|
the global error count."""
|
||||||
global count
|
global count
|
||||||
count = count+1
|
count = count + 1
|
||||||
print>>sys.stderr, currentpoint+": "+err
|
print>>sys.stderr, currentpoint + ": " + err
|
||||||
|
|
||||||
|
|
||||||
def report():
|
def report():
|
||||||
"Print out the number of errors."
|
"Print out the number of errors."
|
||||||
if count == 0: print>>sys.stderr, "No errors"
|
if count == 0:
|
||||||
elif count == 1: print>>sys.stderr, "1 error"
|
print>>sys.stderr, "No errors"
|
||||||
else: print>>sys.stderr, str(count)+" errors"
|
elif count == 1:
|
||||||
|
print>>sys.stderr, "1 error"
|
||||||
|
else:
|
||||||
|
print>>sys.stderr, str(count) + " errors"
|
||||||
|
|
|
@ -13,35 +13,44 @@ import os
|
||||||
# You may use, modify, and distribute this file under the MIT
|
# You may use, modify, and distribute this file under the MIT
|
||||||
# license: See README for details.
|
# license: See README for details.
|
||||||
|
|
||||||
|
|
||||||
class Lexeme(object):
|
class Lexeme(object):
|
||||||
"Class for lexer tokens. Used by lexer and parser."
|
"Class for lexer tokens. Used by lexer and parser."
|
||||||
def __init__(self, type="UNKNOWN", value=None):
|
def __init__(self, type="UNKNOWN", value=None):
|
||||||
self.type = type.upper()
|
self.type = type.upper()
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.value == None:
|
if self.value is None:
|
||||||
return self.type
|
return self.type
|
||||||
else:
|
else:
|
||||||
return self.type+":"+str(self.value)
|
return self.type + ":" + str(self.value)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "Lexeme("+`self.type`+", "+`self.value`+")"
|
return "Lexeme(" + repr(self.type) + ", " + repr(self.value) + ")"
|
||||||
|
|
||||||
def matches(self, other):
|
def matches(self, other):
|
||||||
"1 if Lexemes a and b have the same type."
|
"1 if Lexemes a and b have the same type."
|
||||||
return self.type == other.type
|
return self.type == other.type
|
||||||
|
|
||||||
bases = {"$":("hexadecimal", 16),
|
|
||||||
"%":("binary", 2),
|
bases = {"$": ("hexadecimal", 16),
|
||||||
"0":("octal", 8)}
|
"%": ("binary", 2),
|
||||||
|
"0": ("octal", 8)}
|
||||||
|
|
||||||
|
|
||||||
punctuation = "#,`<>():.+-*/&|^[]"
|
punctuation = "#,`<>():.+-*/&|^[]"
|
||||||
|
|
||||||
|
|
||||||
def lex(point, line):
|
def lex(point, line):
|
||||||
"""Turns a line of source into a sequence of lexemes."""
|
"""Turns a line of source into a sequence of lexemes."""
|
||||||
Err.currentpoint = point
|
Err.currentpoint = point
|
||||||
result = []
|
result = []
|
||||||
|
|
||||||
def is_opcode(op):
|
def is_opcode(op):
|
||||||
"Tests whether a string is an opcode or an identifier"
|
"Tests whether a string is an opcode or an identifier"
|
||||||
return op in Ops.opcodes
|
return op in Ops.opcodes
|
||||||
|
|
||||||
def add_token(token):
|
def add_token(token):
|
||||||
"Converts a substring into a single lexeme"
|
"Converts a substring into a single lexeme"
|
||||||
if token == "":
|
if token == "":
|
||||||
|
@ -59,7 +68,8 @@ def lex(point, line):
|
||||||
result.append(Lexeme("NUM", long(rest, bases[firstchar][1])))
|
result.append(Lexeme("NUM", long(rest, bases[firstchar][1])))
|
||||||
return
|
return
|
||||||
except ValueError:
|
except ValueError:
|
||||||
Err.log('Invalid '+bases[firstchar][0]+' constant: '+rest)
|
Err.log('Invalid ' + bases[firstchar][0] + ' constant: ' +
|
||||||
|
rest)
|
||||||
result.append(Lexeme("NUM", 0))
|
result.append(Lexeme("NUM", 0))
|
||||||
return
|
return
|
||||||
elif firstchar.isdigit():
|
elif firstchar.isdigit():
|
||||||
|
@ -73,12 +83,12 @@ def lex(point, line):
|
||||||
if len(rest) == 1:
|
if len(rest) == 1:
|
||||||
result.append(Lexeme("NUM", ord(rest)))
|
result.append(Lexeme("NUM", ord(rest)))
|
||||||
else:
|
else:
|
||||||
Err.log("Invalid character constant '"+rest+"'")
|
Err.log("Invalid character constant '" + rest + "'")
|
||||||
result.append(Lexeme("NUM", 0))
|
result.append(Lexeme("NUM", 0))
|
||||||
return
|
return
|
||||||
elif firstchar in punctuation:
|
elif firstchar in punctuation:
|
||||||
if rest != "":
|
if rest != "":
|
||||||
Err.log("Internal lexer error! '"+token+"' can't happen!")
|
Err.log("Internal lexer error! '" + token + "' can't happen!")
|
||||||
result.append(Lexeme(firstchar))
|
result.append(Lexeme(firstchar))
|
||||||
return
|
return
|
||||||
else: # Label, opcode, or index register
|
else: # Label, opcode, or index register
|
||||||
|
@ -94,22 +104,24 @@ def lex(point, line):
|
||||||
return
|
return
|
||||||
# should never reach here
|
# should never reach here
|
||||||
Err.log("Internal lexer error: add_token fall-through")
|
Err.log("Internal lexer error: add_token fall-through")
|
||||||
|
|
||||||
def add_EOL():
|
def add_EOL():
|
||||||
"Adds an end-of-line lexeme"
|
"Adds an end-of-line lexeme"
|
||||||
result.append(Lexeme("EOL"))
|
result.append(Lexeme("EOL"))
|
||||||
|
|
||||||
# Actual routine begins here
|
# Actual routine begins here
|
||||||
value = ""
|
value = ""
|
||||||
quotemode = 0
|
quotemode = False
|
||||||
backslashmode = 0
|
backslashmode = False
|
||||||
for c in line.strip():
|
for c in line.strip():
|
||||||
if backslashmode:
|
if backslashmode:
|
||||||
backslashmode = 0
|
backslashmode = False
|
||||||
value = value + c
|
value = value + c
|
||||||
elif c == "\\":
|
elif c == "\\":
|
||||||
backslashmode = 1
|
backslashmode = True
|
||||||
elif quotemode:
|
elif quotemode:
|
||||||
if c == '"':
|
if c == '"':
|
||||||
quotemode = 0
|
quotemode = False
|
||||||
else:
|
else:
|
||||||
value = value + c
|
value = value + c
|
||||||
elif c == ';':
|
elif c == ';':
|
||||||
|
@ -126,7 +138,7 @@ def lex(point, line):
|
||||||
elif c == '"':
|
elif c == '"':
|
||||||
add_token(value)
|
add_token(value)
|
||||||
value = '"'
|
value = '"'
|
||||||
quotemode = 1
|
quotemode = True
|
||||||
else:
|
else:
|
||||||
value = value + c
|
value = value + c
|
||||||
if backslashmode:
|
if backslashmode:
|
||||||
|
@ -137,35 +149,45 @@ def lex(point, line):
|
||||||
add_EOL()
|
add_EOL()
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
class ParseLine(object):
|
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):
|
def __init__(self, lexemes):
|
||||||
self.lexemes = lexemes
|
self.lexemes = lexemes
|
||||||
self.location = 0
|
self.location = 0
|
||||||
|
|
||||||
def lookahead(self, i):
|
def lookahead(self, i):
|
||||||
"""Returns the token i units ahead in the parse.
|
"""Returns the token i units ahead in the parse.
|
||||||
lookahead(0) returns the next token; trying to read off the end of
|
lookahead(0) returns the next token; trying to read off the end of
|
||||||
the sequence returns the last token in the sequence (usually EOL)."""
|
the sequence returns the last token in the sequence (usually EOL)."""
|
||||||
target = self.location+i
|
target = self.location + i
|
||||||
if target >= len(self.lexemes): target = -1
|
if target >= len(self.lexemes):
|
||||||
|
target = -1
|
||||||
return self.lexemes[target]
|
return self.lexemes[target]
|
||||||
|
|
||||||
def pop(self):
|
def pop(self):
|
||||||
"Returns and removes the next element in the line."
|
"Returns and removes the next element in the line."
|
||||||
old = self.location
|
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]
|
return self.lexemes[old]
|
||||||
|
|
||||||
def expect(self, *tokens):
|
def expect(self, *tokens):
|
||||||
"""Reads a token from the ParseLine line and returns it if it's of a type
|
"""Reads a token from the ParseLine line and returns it if it's of a
|
||||||
in the sequence tokens. Otherwise, it logs an error."""
|
type in the sequence tokens. Otherwise, it logs an error."""
|
||||||
token = self.pop()
|
token = self.pop()
|
||||||
if token.type not in tokens:
|
if token.type not in tokens:
|
||||||
Err.log('Expected: "'+'", "'.join(tokens)+'"')
|
Err.log('Expected: "' + '", "'.join(tokens) + '"')
|
||||||
return token
|
return token
|
||||||
|
|
||||||
|
|
||||||
pragma_modules = []
|
pragma_modules = []
|
||||||
|
|
||||||
|
|
||||||
def parse_expr(line):
|
def parse_expr(line):
|
||||||
"Parses an Ophis arithmetic expression."
|
"Parses an Ophis arithmetic expression."
|
||||||
|
|
||||||
def atom():
|
def atom():
|
||||||
"Parses lowest-priority expression components."
|
"Parses lowest-priority expression components."
|
||||||
next = line.lookahead(0).type
|
next = line.lookahead(0).type
|
||||||
|
@ -187,14 +209,14 @@ def parse_expr(line):
|
||||||
offset += 1
|
offset += 1
|
||||||
line.expect("+")
|
line.expect("+")
|
||||||
next = line.lookahead(0).type
|
next = line.lookahead(0).type
|
||||||
return IR.LabelExpr("*"+str(templabelcount+offset))
|
return IR.LabelExpr("*" + str(templabelcount + offset))
|
||||||
elif next == "-":
|
elif next == "-":
|
||||||
offset = 1
|
offset = 1
|
||||||
while next == "-":
|
while next == "-":
|
||||||
offset -= 1
|
offset -= 1
|
||||||
line.expect("-")
|
line.expect("-")
|
||||||
next = line.lookahead(0).type
|
next = line.lookahead(0).type
|
||||||
return IR.LabelExpr("*"+str(templabelcount+offset))
|
return IR.LabelExpr("*" + str(templabelcount + offset))
|
||||||
elif next == ">":
|
elif next == ">":
|
||||||
line.expect(">")
|
line.expect(">")
|
||||||
return IR.HighByteExpr(atom())
|
return IR.HighByteExpr(atom())
|
||||||
|
@ -203,6 +225,7 @@ def parse_expr(line):
|
||||||
return IR.LowByteExpr(atom())
|
return IR.LowByteExpr(atom())
|
||||||
else:
|
else:
|
||||||
Err.log('Expected: expression')
|
Err.log('Expected: expression')
|
||||||
|
|
||||||
def precedence_read(constructor, reader, separators):
|
def precedence_read(constructor, reader, separators):
|
||||||
"""Handles precedence. The reader argument is a function that returns
|
"""Handles precedence. The reader argument is a function that returns
|
||||||
expressions that bind more tightly than these; separators is a list
|
expressions that bind more tightly than these; separators is a list
|
||||||
|
@ -218,51 +241,60 @@ def parse_expr(line):
|
||||||
result.append(nextop)
|
result.append(nextop)
|
||||||
result.append(reader())
|
result.append(reader())
|
||||||
nextop = line.lookahead(0).type
|
nextop = line.lookahead(0).type
|
||||||
if len(result) == 1: return result[0]
|
if len(result) == 1:
|
||||||
|
return result[0]
|
||||||
return constructor(result)
|
return constructor(result)
|
||||||
|
|
||||||
def term():
|
def term():
|
||||||
"Parses * and /"
|
"Parses * and /"
|
||||||
return precedence_read(IR.SequenceExpr, atom, ["*", "/"])
|
return precedence_read(IR.SequenceExpr, atom, ["*", "/"])
|
||||||
|
|
||||||
def arith():
|
def arith():
|
||||||
"Parses + and -"
|
"Parses + and -"
|
||||||
return precedence_read(IR.SequenceExpr, term, ["+", "-"])
|
return precedence_read(IR.SequenceExpr, term, ["+", "-"])
|
||||||
|
|
||||||
def bits():
|
def bits():
|
||||||
"Parses &, |, and ^"
|
"Parses &, |, and ^"
|
||||||
return precedence_read(IR.SequenceExpr, arith, ["&", "|", "^"])
|
return precedence_read(IR.SequenceExpr, arith, ["&", "|", "^"])
|
||||||
|
|
||||||
return bits()
|
return bits()
|
||||||
|
|
||||||
|
|
||||||
def parse_line(ppt, lexemelist):
|
def parse_line(ppt, lexemelist):
|
||||||
"Turn a line of source into an IR Node."
|
"Turn a line of source into an IR Node."
|
||||||
Err.currentpoint = ppt
|
Err.currentpoint = ppt
|
||||||
result = []
|
result = []
|
||||||
line = ParseLine(lexemelist)
|
line = ParseLine(lexemelist)
|
||||||
|
|
||||||
def aux():
|
def aux():
|
||||||
"Accumulates all IR nodes defined by this line."
|
"Accumulates all IR nodes defined by this line."
|
||||||
if line.lookahead(0).type == "EOL":
|
if line.lookahead(0).type == "EOL":
|
||||||
pass
|
pass
|
||||||
elif line.lookahead(1).type == ":":
|
elif line.lookahead(1).type == ":":
|
||||||
newlabel=line.expect("LABEL").value
|
newlabel = line.expect("LABEL").value
|
||||||
line.expect(":")
|
line.expect(":")
|
||||||
result.append(IR.Node(ppt, "Label", newlabel, IR.PCExpr()))
|
result.append(IR.Node(ppt, "Label", newlabel, IR.PCExpr()))
|
||||||
aux()
|
aux()
|
||||||
elif line.lookahead(0).type == "*":
|
elif line.lookahead(0).type == "*":
|
||||||
global templabelcount
|
global templabelcount
|
||||||
templabelcount = templabelcount + 1
|
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("*")
|
line.expect("*")
|
||||||
aux()
|
aux()
|
||||||
elif line.lookahead(0).type == "." or line.lookahead(0).type == "`":
|
elif line.lookahead(0).type == "." or line.lookahead(0).type == "`":
|
||||||
which = line.expect(".", "`").type
|
which = line.expect(".", "`").type
|
||||||
if (which == "."): pragma = line.expect("LABEL").value
|
if (which == "."):
|
||||||
else: pragma = "invoke"
|
pragma = line.expect("LABEL").value
|
||||||
pragmaFunction = "pragma"+pragma.title()
|
else:
|
||||||
|
pragma = "invoke"
|
||||||
|
pragmaFunction = "pragma" + pragma.title()
|
||||||
for mod in pragma_modules:
|
for mod in pragma_modules:
|
||||||
if hasattr(mod, pragmaFunction):
|
if hasattr(mod, pragmaFunction):
|
||||||
getattr(mod, pragmaFunction)(ppt, line, result)
|
getattr(mod, pragmaFunction)(ppt, line, result)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
Err.log("Unknown pragma "+pragma)
|
Err.log("Unknown pragma " + pragma)
|
||||||
|
|
||||||
else: # Instruction
|
else: # Instruction
|
||||||
opcode = line.expect("OPCODE").value
|
opcode = line.expect("OPCODE").value
|
||||||
if line.lookahead(0).type == "#":
|
if line.lookahead(0).type == "#":
|
||||||
|
@ -296,23 +328,30 @@ def parse_line(ppt, lexemelist):
|
||||||
tok = line.expect("EOL", ",").type
|
tok = line.expect("EOL", ",").type
|
||||||
if tok == ",":
|
if tok == ",":
|
||||||
tok = line.expect("X", "Y").type
|
tok = line.expect("X", "Y").type
|
||||||
if tok == "X": mode = "MemoryX"
|
if tok == "X":
|
||||||
else: mode = "MemoryY"
|
mode = "MemoryX"
|
||||||
|
else:
|
||||||
|
mode = "MemoryY"
|
||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
else: mode = "Memory"
|
else:
|
||||||
|
mode = "Memory"
|
||||||
result.append(IR.Node(ppt, mode, opcode, arg))
|
result.append(IR.Node(ppt, mode, opcode, arg))
|
||||||
|
|
||||||
aux()
|
aux()
|
||||||
result = [node for node in result if node is not IR.NullNode]
|
result = [node for node in result if node is not IR.NullNode]
|
||||||
if len(result) == 0: return IR.NullNode
|
if len(result) == 0:
|
||||||
if len(result) == 1: return result[0]
|
return IR.NullNode
|
||||||
|
if len(result) == 1:
|
||||||
|
return result[0]
|
||||||
return IR.SequenceNode(ppt, result)
|
return IR.SequenceNode(ppt, result)
|
||||||
|
|
||||||
|
|
||||||
def parse_file(ppt, filename):
|
def parse_file(ppt, filename):
|
||||||
"Loads an Ophis source file, and returns an IR list."
|
"Loads an Ophis source file, and returns an IR list."
|
||||||
Err.currentpoint = ppt
|
Err.currentpoint = ppt
|
||||||
if Cmd.print_loaded_files:
|
if Cmd.print_loaded_files:
|
||||||
if filename != '-':
|
if filename != '-':
|
||||||
print>>sys.stderr, "Loading "+filename
|
print>>sys.stderr, "Loading " + filename
|
||||||
else:
|
else:
|
||||||
print>>sys.stderr, "Loading from standard input"
|
print>>sys.stderr, "Loading from standard input"
|
||||||
try:
|
try:
|
||||||
|
@ -322,18 +361,19 @@ def parse_file(ppt, filename):
|
||||||
f.close()
|
f.close()
|
||||||
else:
|
else:
|
||||||
linelist = sys.stdin.readlines()
|
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)
|
lexlist = map(lex, pptlist, linelist)
|
||||||
IRlist = map(parse_line, pptlist, lexlist)
|
IRlist = map(parse_line, pptlist, lexlist)
|
||||||
IRlist = [node for node in IRlist if node is not IR.NullNode]
|
IRlist = [node for node in IRlist if node is not IR.NullNode]
|
||||||
return IR.SequenceNode(ppt, IRlist)
|
return IR.SequenceNode(ppt, IRlist)
|
||||||
except IOError:
|
except IOError:
|
||||||
Err.log ("Could not read "+filename)
|
Err.log("Could not read " + filename)
|
||||||
return IR.NullNode
|
return IR.NullNode
|
||||||
|
|
||||||
|
|
||||||
def parse(filename):
|
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
|
global templabelcount
|
||||||
templabelcount = 0
|
templabelcount = 0
|
||||||
return parse_file("<Top Level>", filename)
|
return parse_file("<Top Level>", filename)
|
||||||
|
|
||||||
|
|
106
src/Ophis/IR.py
106
src/Ophis/IR.py
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
import Ophis.Errors as Err
|
import Ophis.Errors as Err
|
||||||
|
|
||||||
|
|
||||||
class Node(object):
|
class Node(object):
|
||||||
"""The default IR Node
|
"""The default IR Node
|
||||||
Instances of Node always have the three fields ppt(Program Point),
|
Instances of Node always have the three fields ppt(Program Point),
|
||||||
|
@ -17,27 +18,35 @@ class Node(object):
|
||||||
self.ppt = ppt
|
self.ppt = ppt
|
||||||
self.nodetype = nodetype
|
self.nodetype = nodetype
|
||||||
self.data = list(data)
|
self.data = list(data)
|
||||||
|
|
||||||
def accept(self, asmpass, env=None):
|
def accept(self, asmpass, env=None):
|
||||||
"""Implements the Visitor pattern for an assembler pass.
|
"""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."""
|
TYPE is the value of self.nodetype."""
|
||||||
Err.currentpoint = self.ppt
|
Err.currentpoint = self.ppt
|
||||||
routine = getattr(asmpass, "visit"+self.nodetype, asmpass.visitUnknown)
|
routine = getattr(asmpass, "visit" + self.nodetype,
|
||||||
|
asmpass.visitUnknown)
|
||||||
routine(self, env)
|
routine(self, env)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if self.nodetype != "SEQUENCE":
|
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:
|
else:
|
||||||
return "\n".join(map(str, self.data))
|
return "\n".join(map(str, self.data))
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
args = [self.ppt, self.nodetype] + self.data
|
args = [self.ppt, self.nodetype] + self.data
|
||||||
return "Node(" + ", ".join(map(repr, args)) + ")"
|
return "Node(" + ", ".join(map(repr, args)) + ")"
|
||||||
|
|
||||||
|
|
||||||
NullNode = Node("<none>", "None")
|
NullNode = Node("<none>", "None")
|
||||||
|
|
||||||
|
|
||||||
def SequenceNode(ppt, nodelist):
|
def SequenceNode(ppt, nodelist):
|
||||||
return Node(ppt, "SEQUENCE", *nodelist)
|
return Node(ppt, "SEQUENCE", *nodelist)
|
||||||
|
|
||||||
|
|
||||||
class Expr(object):
|
class Expr(object):
|
||||||
"""Base class for Ophis expressions
|
"""Base class for Ophis expressions
|
||||||
All expressions have a field called "data" and a boolean field
|
All expressions have a field called "data" and a boolean field
|
||||||
|
@ -45,78 +54,102 @@ class Expr(object):
|
||||||
symbolic values in it."""
|
symbolic values in it."""
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.hardcoded = 0
|
self.hardcoded = False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "<UNKNOWN: "+`self.data`+">"
|
return "<UNKNOWN: " + repr(self.data) + ">"
|
||||||
def valid(self, env=None, PCvalid=0):
|
|
||||||
|
def valid(self, env=None, PCvalid=False):
|
||||||
"""Returns true if the the expression can be successfully
|
"""Returns true if the the expression can be successfully
|
||||||
evaluated in the specified environment."""
|
evaluated in the specified environment."""
|
||||||
return 0
|
return False
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
"Evaluates this expression in the given environment."
|
"Evaluates this expression in the given environment."
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ConstantExpr(Expr):
|
class ConstantExpr(Expr):
|
||||||
"Represents a numeric constant"
|
"Represents a numeric constant"
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.hardcoded = 1
|
self.hardcoded = True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.data)
|
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):
|
def value(self, env=None):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
|
|
||||||
class LabelExpr(Expr):
|
class LabelExpr(Expr):
|
||||||
"Represents a symbolic constant"
|
"Represents a symbolic constant"
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.hardcoded = 0
|
self.hardcoded = False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.data
|
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
|
return (env is not None) and self.data in env
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
return env[self.data]
|
return env[self.data]
|
||||||
|
|
||||||
|
|
||||||
class PCExpr(Expr):
|
class PCExpr(Expr):
|
||||||
"Represents the current program counter: ^"
|
"Represents the current program counter: ^"
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.hardcoded = 0
|
self.hardcoded = False
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "^"
|
return "^"
|
||||||
def valid(self, env=None, PCvalid=0):
|
|
||||||
|
def valid(self, env=None, PCvalid=False):
|
||||||
return env is not None and PCvalid
|
return env is not None and PCvalid
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
return env.getPC()
|
return env.getPC()
|
||||||
|
|
||||||
|
|
||||||
class HighByteExpr(Expr):
|
class HighByteExpr(Expr):
|
||||||
"Represents the expression >{data}"
|
"Represents the expression >{data}"
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.hardcoded = data.hardcoded
|
self.hardcoded = data.hardcoded
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ">"+str(self.data)
|
return ">" + str(self.data)
|
||||||
def valid(self, env=None, PCvalid=0):
|
|
||||||
|
def valid(self, env=None, PCvalid=False):
|
||||||
return self.data.valid(env, PCvalid)
|
return self.data.valid(env, PCvalid)
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
val = self.data.value(env)
|
val = self.data.value(env)
|
||||||
return (val >> 8) & 0xff
|
return (val >> 8) & 0xff
|
||||||
|
|
||||||
|
|
||||||
class LowByteExpr(Expr):
|
class LowByteExpr(Expr):
|
||||||
"Represents the expression <{data}"
|
"Represents the expression <{data}"
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.data = data
|
self.data = data
|
||||||
self.hardcoded = data.hardcoded
|
self.hardcoded = data.hardcoded
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "<"+str(self.data)
|
return "<" + str(self.data)
|
||||||
def valid(self, env=None, PCvalid=0):
|
|
||||||
|
def valid(self, env=None, PCvalid=False):
|
||||||
return self.data.valid(env, PCvalid)
|
return self.data.valid(env, PCvalid)
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
val = self.data.value(env)
|
val = self.data.value(env)
|
||||||
return val & 0xff
|
return val & 0xff
|
||||||
|
|
||||||
|
|
||||||
class SequenceExpr(Expr):
|
class SequenceExpr(Expr):
|
||||||
"""Represents an interleaving of operands (of type Expr) and
|
"""Represents an interleaving of operands (of type Expr) and
|
||||||
operators (of type String). Subclasses must provide a routine
|
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]."""
|
[Expr, str, Expr, str, Expr, str, ... Expr, str, Expr]."""
|
||||||
self.data = data
|
self.data = data
|
||||||
self.operands = [x for x in data if isinstance(x, Expr)]
|
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:
|
for i in self.operands:
|
||||||
if not i.hardcoded:
|
if not i.hardcoded:
|
||||||
self.hardcoded = 0
|
self.hardcoded = False
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.hardcoded = 1
|
self.hardcoded = True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "["+" ".join(map(str, self.data))+"]"
|
return "[" + " ".join(map(str, self.data)) + "]"
|
||||||
def valid(self, env=None, PCvalid=0):
|
|
||||||
|
def valid(self, env=None, PCvalid=False):
|
||||||
for i in self.operands:
|
for i in self.operands:
|
||||||
if not i.valid(env, PCvalid):
|
if not i.valid(env, PCvalid):
|
||||||
return 0
|
return False
|
||||||
return 1
|
return True
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
subs = map((lambda x: x.value(env)), self.operands)
|
subs = map((lambda x: x.value(env)), self.operands)
|
||||||
result = subs[0]
|
result = subs[0]
|
||||||
|
@ -150,11 +186,19 @@ class SequenceExpr(Expr):
|
||||||
result = self.operate(result, op, subs[index])
|
result = self.operate(result, op, subs[index])
|
||||||
index += 1
|
index += 1
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def operate(self, start, op, other):
|
def operate(self, start, op, other):
|
||||||
if op=="*": return start * other
|
if op == "*":
|
||||||
if op=="/": return start // other
|
return start * other
|
||||||
if op=="+": return start + other
|
if op == "/":
|
||||||
if op=="-": return start - other
|
return start // other
|
||||||
if op=="&": return start & other
|
if op == "+":
|
||||||
if op=="|": return start | other
|
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
|
||||||
|
|
|
@ -18,6 +18,7 @@ macros = {}
|
||||||
currentname = None
|
currentname = None
|
||||||
currentbody = None
|
currentbody = None
|
||||||
|
|
||||||
|
|
||||||
def newMacro(name):
|
def newMacro(name):
|
||||||
"Start creating a new macro with the specified name."
|
"Start creating a new macro with the specified name."
|
||||||
global currentname
|
global currentname
|
||||||
|
@ -31,10 +32,12 @@ def newMacro(name):
|
||||||
currentname = name
|
currentname = name
|
||||||
currentbody = []
|
currentbody = []
|
||||||
|
|
||||||
|
|
||||||
def registerNode(node):
|
def registerNode(node):
|
||||||
global currentbody
|
global currentbody
|
||||||
currentbody.append(IR.Node(node.ppt, node.nodetype, *node.data))
|
currentbody.append(IR.Node(node.ppt, node.nodetype, *node.data))
|
||||||
|
|
||||||
|
|
||||||
def endMacro():
|
def endMacro():
|
||||||
global currentname
|
global currentname
|
||||||
global currentbody
|
global currentbody
|
||||||
|
@ -46,21 +49,29 @@ def endMacro():
|
||||||
currentname = None
|
currentname = None
|
||||||
currentbody = None
|
currentbody = None
|
||||||
|
|
||||||
|
|
||||||
def expandMacro(ppt, name, arglist):
|
def expandMacro(ppt, name, arglist):
|
||||||
global macros
|
global macros
|
||||||
if name not in macros:
|
if name not in macros:
|
||||||
Err.log("Undefined macro '%s'" % name)
|
Err.log("Undefined macro '%s'" % name)
|
||||||
return IR.NullNode
|
return IR.NullNode
|
||||||
argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg) for (i, arg) in zip(xrange(1, sys.maxint), arglist)]
|
argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg)
|
||||||
bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i)) for i in range(1, len(arglist)+1)]
|
for (i, arg) in zip(xrange(1, sys.maxint), arglist)]
|
||||||
body = [IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data) for node in macros[name]]
|
bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i))
|
||||||
invocation = [IR.Node(ppt, "ScopeBegin")] + argexprs + [IR.Node(ppt, "ScopeBegin")] + bindexprs + body + [IR.Node(ppt, "ScopeEnd"), IR.Node(ppt, "ScopeEnd")]
|
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)
|
return IR.SequenceNode(ppt, invocation)
|
||||||
|
|
||||||
|
|
||||||
def dump():
|
def dump():
|
||||||
global macros
|
global macros
|
||||||
for mac in macros:
|
for mac in macros:
|
||||||
body = macros[mac]
|
body = macros[mac]
|
||||||
print>>sys.stderr, "Macro: "+mac
|
print>>sys.stderr, "Macro: " + mac
|
||||||
for node in body: print>>sys.stderr, node
|
for node in body:
|
||||||
|
print>>sys.stderr, node
|
||||||
print>>sys.stderr, ""
|
print>>sys.stderr, ""
|
||||||
|
|
|
@ -17,6 +17,7 @@ import Ophis.Environment
|
||||||
import Ophis.CmdLine
|
import Ophis.CmdLine
|
||||||
import Ophis.Opcodes
|
import Ophis.Opcodes
|
||||||
|
|
||||||
|
|
||||||
def run_all(infile, outfile):
|
def run_all(infile, outfile):
|
||||||
"Transforms the source infile to a binary outfile."
|
"Transforms the source infile to a binary outfile."
|
||||||
Err.count = 0
|
Err.count = 0
|
||||||
|
@ -26,21 +27,31 @@ def run_all(infile, outfile):
|
||||||
m = Ophis.Passes.ExpandMacros()
|
m = Ophis.Passes.ExpandMacros()
|
||||||
i = Ophis.Passes.InitLabels()
|
i = Ophis.Passes.InitLabels()
|
||||||
l_basic = Ophis.Passes.UpdateLabels()
|
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_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()
|
b = Ophis.Passes.ExtendBranches()
|
||||||
a = Ophis.Passes.Assembler()
|
a = Ophis.Passes.Assembler()
|
||||||
|
|
||||||
passes = []
|
passes = []
|
||||||
passes.append(Ophis.Passes.DefineMacros())
|
passes.append(Ophis.Passes.DefineMacros())
|
||||||
passes.append(Ophis.Passes.FixPoint("macro expansion", [m], lambda: m.changed == 0))
|
passes.append(Ophis.Passes.FixPoint("macro expansion", [m],
|
||||||
passes.append(Ophis.Passes.FixPoint("label initialization", [i], lambda: i.changed == 0))
|
lambda: not m.changed))
|
||||||
passes.extend([Ophis.Passes.CircularityCheck(), Ophis.Passes.CheckExprs(), Ophis.Passes.EasyModes()])
|
passes.append(Ophis.Passes.FixPoint("label initialization", [i],
|
||||||
passes.append(Ophis.Passes.FixPoint("instruction selection 2", [c, b], lambda: b.expanded == 0))
|
lambda: not i.changed))
|
||||||
passes.extend([Ophis.Passes.NormalizeModes(), Ophis.Passes.UpdateLabels(), a])
|
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:
|
if Err.count == 0:
|
||||||
try:
|
try:
|
||||||
|
@ -53,10 +64,11 @@ def run_all(infile, outfile):
|
||||||
if outfile != '-':
|
if outfile != '-':
|
||||||
output.close()
|
output.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
print>>sys.stderr, "Could not write to "+outfile
|
print>>sys.stderr, "Could not write to " + outfile
|
||||||
else:
|
else:
|
||||||
Err.report()
|
Err.report()
|
||||||
|
|
||||||
|
|
||||||
def run_ophis(args):
|
def run_ophis(args):
|
||||||
Ophis.CmdLine.parse_args(args)
|
Ophis.CmdLine.parse_args(args)
|
||||||
Ophis.Frontend.pragma_modules.append(Ophis.CorePragmas)
|
Ophis.Frontend.pragma_modules.append(Ophis.CorePragmas)
|
||||||
|
@ -69,5 +81,6 @@ def run_ophis(args):
|
||||||
Ophis.CorePragmas.reset()
|
Ophis.CorePragmas.reset()
|
||||||
run_all(Ophis.CmdLine.infile, Ophis.CmdLine.outfile)
|
run_all(Ophis.CmdLine.infile, Ophis.CmdLine.outfile)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
run_ophis(sys.argv[1:])
|
run_ophis(sys.argv[1:])
|
||||||
|
|
|
@ -28,146 +28,275 @@ modes = ["Implied", # 0
|
||||||
"(Zero Page), Y", # 13
|
"(Zero Page), Y", # 13
|
||||||
"Relative"] # 14
|
"Relative"] # 14
|
||||||
|
|
||||||
|
|
||||||
# Lengths of the argument
|
# Lengths of the argument
|
||||||
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
|
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
|
||||||
|
|
||||||
opcodes = {
|
opcodes = {
|
||||||
'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, None, None, None, None, 0x61, 0x71, None],
|
'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79,
|
||||||
'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, None, None, None, None, 0x21, 0x31, None],
|
None, None, None, None, 0x61, 0x71, None],
|
||||||
'asl': [0x0A, None, 0x06, 0x16, None, 0x0E, 0x1E, None, None, None, None, None, None, None, None],
|
'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39,
|
||||||
'bcc': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x90],
|
None, None, None, None, 0x21, 0x31, None],
|
||||||
'bcs': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xB0],
|
'asl': [0x0A, None, 0x06, 0x16, None, 0x0E, 0x1E, None,
|
||||||
'beq': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xF0],
|
None, None, None, None, None, None, None],
|
||||||
'bit': [None, None, 0x24, None, None, 0x2C, None, None, None, None, None, None, None, None, None],
|
'bcc': [None, None, None, None, None, None, None, None,
|
||||||
'bmi': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x30],
|
None, None, None, None, None, None, 0x90],
|
||||||
'bne': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xD0],
|
'bcs': [None, None, None, None, None, None, None, None,
|
||||||
'bpl': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x10],
|
None, None, None, None, None, None, 0xB0],
|
||||||
'brk': [0x00, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'beq': [None, None, None, None, None, None, None, None,
|
||||||
'bvc': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x50],
|
None, None, None, None, None, None, 0xF0],
|
||||||
'bvs': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x70],
|
'bit': [None, None, 0x24, None, None, 0x2C, None, None,
|
||||||
'clc': [0x18, None, None, None, None, None, None, None, 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],
|
'bmi': [None, None, None, None, None, None, None, None,
|
||||||
'cli': [0x58, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0x30],
|
||||||
'clv': [0xB8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'bne': [None, None, None, None, None, None, None, None,
|
||||||
'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, None, None, None, None, 0xC1, 0xD1, None],
|
None, None, None, None, None, None, 0xD0],
|
||||||
'cpx': [None, 0xE0, 0xE4, None, None, 0xEC, None, None, None, None, None, None, None, None, None],
|
'bpl': [None, None, None, None, None, None, None, None,
|
||||||
'cpy': [None, 0xC0, 0xC4, None, None, 0xCC, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0x10],
|
||||||
'dec': [None, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, None, None, None, None, None, None, None],
|
'brk': [0x00, None, None, None, None, None, None, None,
|
||||||
'dex': [0xCA, None, None, None, None, None, None, None, 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],
|
'bvc': [None, None, None, None, None, None, None, None,
|
||||||
'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, None, None, None, None, 0x41, 0x51, None],
|
None, None, None, None, None, None, 0x50],
|
||||||
'inc': [None, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, None, None, None, None, None, None, None],
|
'bvs': [None, None, None, None, None, None, None, None,
|
||||||
'inx': [0xE8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0x70],
|
||||||
'iny': [0xC8, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'clc': [0x18, None, None, None, None, None, None, None,
|
||||||
'jmp': [None, None, None, None, None, 0x4C, None, None, 0x6C, None, None, None, None, None, None],
|
None, None, None, None, None, None, None],
|
||||||
'jsr': [None, None, None, None, None, 0x20, None, None, None, None, None, None, None, None, None],
|
'cld': [0xD8, None, None, None, None, None, None, None,
|
||||||
'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, None, None, None, None, 0xA1, 0xB1, None],
|
None, None, None, None, None, None, None],
|
||||||
'ldx': [None, 0xA2, 0xA6, None, 0xB6, 0xAE, None, 0xBE, None, None, None, None, None, None, None],
|
'cli': [0x58, None, None, None, None, None, None, None,
|
||||||
'ldy': [None, 0xA0, 0xA4, 0xB4, None, 0xAC, 0xBC, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, None],
|
||||||
'lsr': [0x4A, None, 0x46, 0x56, None, 0x4E, 0x5E, None, None, None, None, None, None, None, None],
|
'clv': [0xB8, None, None, None, None, None, None, None,
|
||||||
'nop': [0xEA, None, None, None, None, None, None, None, 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],
|
'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9,
|
||||||
'pha': [0x48, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, 0xC1, 0xD1, None],
|
||||||
'php': [0x08, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'cpx': [None, 0xE0, 0xE4, None, None, 0xEC, None, None,
|
||||||
'pla': [0x68, None, None, None, None, None, None, None, 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],
|
'cpy': [None, 0xC0, 0xC4, None, None, 0xCC, None, None,
|
||||||
'rol': [0x2A, None, 0x26, 0x36, None, 0x2E, 0x3E, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, None],
|
||||||
'ror': [0x6A, None, 0x66, 0x76, None, 0x6E, 0x7E, None, None, None, None, None, None, None, None],
|
'dec': [None, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None,
|
||||||
'rti': [0x40, None, None, None, None, None, None, None, 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],
|
'dex': [0xCA, None, None, None, None, None, None, None,
|
||||||
'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, None, None, None, None, 0xE1, 0xF1, None],
|
None, None, None, None, None, None, None],
|
||||||
'sec': [0x38, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'dey': [0x88, None, None, None, None, None, None, None,
|
||||||
'sed': [0xF8, None, None, None, None, None, None, None, 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],
|
'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59,
|
||||||
'sta': [None, None, 0x85, 0x95, None, 0x8D, 0x9D, 0x99, None, None, None, None, 0x81, 0x91, None],
|
None, None, None, None, 0x41, 0x51, None],
|
||||||
'stx': [None, None, 0x86, None, 0x96, 0x8E, None, None, None, None, None, None, None, None, None],
|
'inc': [None, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None,
|
||||||
'sty': [None, None, 0x84, 0x94, None, 0x8C, None, None, None, None, None, None, None, 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],
|
'inx': [0xE8, None, None, None, None, None, None, None,
|
||||||
'tay': [0xA8, None, None, None, None, None, None, None, 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],
|
'iny': [0xC8, None, None, None, None, None, None, None,
|
||||||
'txa': [0x8A, None, None, None, None, None, None, None, 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],
|
'jmp': [None, None, None, None, None, 0x4C, None, None,
|
||||||
'tya': [0x98, None, None, None, None, None, None, None, None, None, None, None, None, 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 = {
|
undocops = {
|
||||||
'anc': [None, 0x0B, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'anc': [None, 0x0B, None, None, None, None, None, None,
|
||||||
'ane': [None, 0x8B, None, None, None, None, None, None, None, 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],
|
'ane': [None, 0x8B, None, None, None, None, None, None,
|
||||||
'asr': [None, 0x4B, None, None, None, None, None, None, None, 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],
|
'arr': [None, 0x6B, None, None, None, None, None, None,
|
||||||
'isb': [None, None, 0xE7, 0xF7, None, 0xEF, 0xFF, 0xFB, None, None, None, None, 0xE3, 0xF3, None],
|
None, None, None, None, None, None, None],
|
||||||
'las': [None, None, None, None, None, None, None, 0xBB, None, None, None, None, None, None, None],
|
'asr': [None, 0x4B, None, None, None, None, None, None,
|
||||||
'lax': [None, None, 0xA7, None, 0xB7, 0xAF, None, 0xBF, None, None, None, None, 0xA3, 0xB3, None],
|
None, None, None, None, None, None, None],
|
||||||
'lxa': [None, 0xAB, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'dcp': [None, None, 0xC7, 0xD7, None, 0xCF, 0xDF, 0xDB,
|
||||||
'nop': [0xEA, None, 0x04, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, 0xC3, 0xD3, None],
|
||||||
'rla': [None, None, 0x27, 0x37, None, 0x2F, 0x3F, 0x3B, None, None, None, None, 0x23, 0x33, None],
|
'isb': [None, None, 0xE7, 0xF7, None, 0xEF, 0xFF, 0xFB,
|
||||||
'rra': [None, None, 0x67, 0x77, None, 0x6F, 0x7F, 0x7B, None, None, None, None, 0x63, 0x73, None],
|
None, None, None, None, 0xE3, 0xF3, None],
|
||||||
'sax': [None, None, 0x87, None, 0x97, 0x8F, None, None, None, None, None, None, 0x83, None, None],
|
'las': [None, None, None, None, None, None, None, 0xBB,
|
||||||
'sbx': [None, 0xCB, None, None, None, None, None, None, None, 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],
|
'lax': [None, None, 0xA7, None, 0xB7, 0xAF, None, 0xBF,
|
||||||
'shs': [None, None, None, None, None, None, None, 0x9B, None, None, None, None, None, None, None],
|
None, None, None, None, 0xA3, 0xB3, None],
|
||||||
'shx': [None, None, None, None, None, None, None, 0x9E, None, None, None, None, None, None, None],
|
'lxa': [None, 0xAB, None, None, None, None, None, None,
|
||||||
'slo': [None, None, 0x07, 0x17, None, 0x0F, 0x1F, 0x1B, None, None, None, None, 0x03, 0x13, None],
|
None, None, None, None, None, None, None],
|
||||||
'sre': [None, None, 0x47, 0x57, None, 0x4F, 0x5F, 0x5B, None, None, None, None, 0x43, 0x53, 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 = {
|
c02extensions = {
|
||||||
'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79, None, None, None, 0x72, 0x61, 0x71, None],
|
'adc': [None, 0x69, 0x65, 0x75, None, 0x6D, 0x7D, 0x79,
|
||||||
'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39, None, None, None, 0x32, 0x21, 0x31, None],
|
None, None, None, 0x72, 0x61, 0x71, None],
|
||||||
'bbr0': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x0F],
|
'and': [None, 0x29, 0x25, 0x35, None, 0x2D, 0x3D, 0x39,
|
||||||
'bbr1': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x1F],
|
None, None, None, 0x32, 0x21, 0x31, None],
|
||||||
'bbr2': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x2F],
|
'bbr0': [None, None, None, None, None, None, None, None,
|
||||||
'bbr3': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x3F],
|
None, None, None, None, None, None, 0x0F],
|
||||||
'bbr4': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x4F],
|
'bbr1': [None, None, None, None, None, None, None, None,
|
||||||
'bbr5': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x5F],
|
None, None, None, None, None, None, 0x1F],
|
||||||
'bbr6': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x6F],
|
'bbr2': [None, None, None, None, None, None, None, None,
|
||||||
'bbr7': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x7F],
|
None, None, None, None, None, None, 0x2F],
|
||||||
'bbs0': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x8F],
|
'bbr3': [None, None, None, None, None, None, None, None,
|
||||||
'bbs1': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x9F],
|
None, None, None, None, None, None, 0x3F],
|
||||||
'bbs2': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xAF],
|
'bbr4': [None, None, None, None, None, None, None, None,
|
||||||
'bbs3': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xBF],
|
None, None, None, None, None, None, 0x4F],
|
||||||
'bbs4': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xCF],
|
'bbr5': [None, None, None, None, None, None, None, None,
|
||||||
'bbs5': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xDF],
|
None, None, None, None, None, None, 0x5F],
|
||||||
'bbs6': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xEF],
|
'bbr6': [None, None, None, None, None, None, None, None,
|
||||||
'bbs7': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0xFF],
|
None, None, None, None, None, None, 0x6F],
|
||||||
'bit': [None, 0x89, 0x24, 0x34, None, 0x2C, 0x3C, None, None, None, None, None, None, None, None],
|
'bbr7': [None, None, None, None, None, None, None, None,
|
||||||
'bra': [None, None, None, None, None, None, None, None, None, None, None, None, None, None, 0x80],
|
None, None, None, None, None, None, 0x7F],
|
||||||
'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9, None, None, None, 0xD2, 0xC1, 0xD1, None],
|
'bbs0': [None, None, None, None, None, None, None, None,
|
||||||
'dea': [0x3A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0x8F],
|
||||||
'dec': [0x3A, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None, None, None, None, None, None, None, None],
|
'bbs1': [None, None, None, None, None, None, None, None,
|
||||||
'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59, None, None, None, 0x52, 0x41, 0x51, None],
|
None, None, None, None, None, None, 0x9F],
|
||||||
'ina': [0x1A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'bbs2': [None, None, None, None, None, None, None, None,
|
||||||
'inc': [0x1A, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0xAF],
|
||||||
'jmp': [None, None, None, None, None, 0x4C, None, None, 0x6C, 0x7C, None, None, None, None, None],
|
'bbs3': [None, None, None, None, None, None, None, None,
|
||||||
'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9, None, None, None, 0xB2, 0xA1, 0xB1, None],
|
None, None, None, None, None, None, 0xBF],
|
||||||
'ora': [None, 0x09, 0x05, 0x15, None, 0x0D, 0x1D, 0x19, None, None, None, 0x12, 0x01, 0x11, None],
|
'bbs4': [None, None, None, None, None, None, None, None,
|
||||||
'phx': [0xDA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0xCF],
|
||||||
'phy': [0x5A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'bbs5': [None, None, None, None, None, None, None, None,
|
||||||
'plx': [0xFA, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0xDF],
|
||||||
'ply': [0x7A, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
'bbs6': [None, None, None, None, None, None, None, None,
|
||||||
'rmb0': [None, None, 0x07, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0xEF],
|
||||||
'rmb1': [None, None, 0x17, None, None, None, None, None, None, None, None, None, None, None, None],
|
'bbs7': [None, None, None, None, None, None, None, None,
|
||||||
'rmb2': [None, None, 0x27, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0xFF],
|
||||||
'rmb3': [None, None, 0x37, None, None, None, None, None, None, None, None, None, None, None, None],
|
'bit': [None, 0x89, 0x24, 0x34, None, 0x2C, 0x3C, None,
|
||||||
'rmb4': [None, None, 0x47, None, None, None, None, None, None, None, 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],
|
'bra': [None, None, None, None, None, None, None, None,
|
||||||
'rmb6': [None, None, 0x67, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, None, None, None, 0x80],
|
||||||
'rmb7': [None, None, 0x77, None, None, None, None, None, None, None, None, None, None, None, None],
|
'cmp': [None, 0xC9, 0xC5, 0xD5, None, 0xCD, 0xDD, 0xD9,
|
||||||
'sbc': [None, 0xE9, 0xE5, 0xF5, None, 0xED, 0xFD, 0xF9, None, None, None, 0xF2, 0xE1, 0xF1, None],
|
None, None, None, 0xD2, 0xC1, 0xD1, None],
|
||||||
'smb0': [None, None, 0x87, None, None, None, None, None, None, None, None, None, None, None, None],
|
'dea': [0x3A, None, None, None, None, None, None, None,
|
||||||
'smb1': [None, None, 0x97, None, None, None, None, None, None, None, 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],
|
'dec': [0x3A, None, 0xC6, 0xD6, None, 0xCE, 0xDE, None,
|
||||||
'smb3': [None, None, 0xB7, None, None, None, None, None, None, None, 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],
|
'eor': [None, 0x49, 0x45, 0x55, None, 0x4D, 0x5D, 0x59,
|
||||||
'smb5': [None, None, 0xD7, None, None, None, None, None, None, None, None, None, None, None, None],
|
None, None, None, 0x52, 0x41, 0x51, None],
|
||||||
'smb6': [None, None, 0xE7, None, None, None, None, None, None, None, None, None, None, None, None],
|
'ina': [0x1A, None, None, None, None, None, None, None,
|
||||||
'smb7': [None, None, 0xF7, None, None, None, None, None, 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, 0x92, 0x81, 0x91, None],
|
'inc': [0x1A, None, 0xE6, 0xF6, None, 0xEE, 0xFE, None,
|
||||||
'stp': [0xDB, None, None, None, None, None, None, None, 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],
|
'jmp': [None, None, None, None, None, 0x4C, None, None,
|
||||||
'trb': [None, None, 0x14, None, None, 0x1C, None, None, None, None, None, None, None, None, None],
|
0x6C, 0x7C, None, None, None, None, None],
|
||||||
'tsb': [None, None, 0x04, None, None, 0x0C, None, None, None, None, None, None, None, None, None],
|
'lda': [None, 0xA9, 0xA5, 0xB5, None, 0xAD, 0xBD, 0xB9,
|
||||||
'wai': [0xCB, None, None, None, None, None, None, None, None, None, None, None, None, None, None],
|
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],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,41 +20,55 @@ import Ophis.Macro as Macro
|
||||||
|
|
||||||
# The passes themselves
|
# The passes themselves
|
||||||
|
|
||||||
|
|
||||||
class Pass(object):
|
class Pass(object):
|
||||||
"""Superclass for all assembler passes. Automatically handles IR
|
"""Superclass for all assembler passes. Automatically handles IR
|
||||||
types that modify the environent's structure, and by default
|
types that modify the environent's structure, and by default
|
||||||
raises an error on anything else. Override visitUnknown in your
|
raises an error on anything else. Override visitUnknown in your
|
||||||
extension pass to produce a pass that accepts everything."""
|
extension pass to produce a pass that accepts everything."""
|
||||||
name = "Default Pass"
|
name = "Default Pass"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.writeOK = 1
|
self.writeOK = True
|
||||||
|
|
||||||
def visitNone(self, node, env):
|
def visitNone(self, node, env):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def visitSEQUENCE(self, node, env):
|
def visitSEQUENCE(self, node, env):
|
||||||
Err.currentpoint = node.ppt
|
Err.currentpoint = node.ppt
|
||||||
for n in node.data:
|
for n in node.data:
|
||||||
n.accept(self, env)
|
n.accept(self, env)
|
||||||
|
|
||||||
def visitDataSegment(self, node, env):
|
def visitDataSegment(self, node, env):
|
||||||
self.writeOK = 0
|
self.writeOK = False
|
||||||
env.setsegment(node.data[0])
|
env.setsegment(node.data[0])
|
||||||
|
|
||||||
def visitTextSegment(self, node, env):
|
def visitTextSegment(self, node, env):
|
||||||
self.writeOK = 1
|
self.writeOK = True
|
||||||
env.setsegment(node.data[0])
|
env.setsegment(node.data[0])
|
||||||
|
|
||||||
def visitScopeBegin(self, node, env):
|
def visitScopeBegin(self, node, env):
|
||||||
env.newscope()
|
env.newscope()
|
||||||
|
|
||||||
def visitScopeEnd(self, node, env):
|
def visitScopeEnd(self, node, env):
|
||||||
env.endscope()
|
env.endscope()
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
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):
|
def prePass(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def postPass(self):
|
def postPass(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def go(self, node, env):
|
def go(self, node, env):
|
||||||
"""Prepares the environment and runs this pass, possibly
|
"""Prepares the environment and runs this pass, possibly
|
||||||
printing debugging information."""
|
printing debugging information."""
|
||||||
if Err.count == 0:
|
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()
|
env.reset()
|
||||||
self.prePass()
|
self.prePass()
|
||||||
node.accept(self, env)
|
node.accept(self, env)
|
||||||
|
@ -67,6 +81,7 @@ class Pass(object):
|
||||||
print>>sys.stderr, "Current IR:"
|
print>>sys.stderr, "Current IR:"
|
||||||
print>>sys.stderr, node
|
print>>sys.stderr, node
|
||||||
|
|
||||||
|
|
||||||
class FixPoint(object):
|
class FixPoint(object):
|
||||||
"""A specialized class that is not a pass but can be run like one.
|
"""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."""
|
This class takes a list of passes and a "fixpoint" function."""
|
||||||
|
@ -74,48 +89,60 @@ class FixPoint(object):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.passes = passes
|
self.passes = passes
|
||||||
self.fixpoint = fixpoint
|
self.fixpoint = fixpoint
|
||||||
|
|
||||||
def go(self, node, env):
|
def go(self, node, env):
|
||||||
"""Runs this FixPoint's passes, in order, until the fixpoint
|
"""Runs this FixPoint's passes, in order, until the fixpoint
|
||||||
is true. Always runs the passes at least once."""
|
is true. Always runs the passes at least once."""
|
||||||
for i in xrange(100):
|
for i in xrange(100):
|
||||||
if Err.count != 0: break
|
if Err.count != 0:
|
||||||
|
break
|
||||||
for p in self.passes:
|
for p in self.passes:
|
||||||
p.go(node, env)
|
p.go(node, env)
|
||||||
if Err.count != 0: break
|
if Err.count != 0:
|
||||||
if self.fixpoint(): break
|
break
|
||||||
if Cmd.print_pass: print>>sys.stderr, "Fixpoint failed, looping back"
|
if self.fixpoint():
|
||||||
|
break
|
||||||
|
if Cmd.print_pass:
|
||||||
|
print>>sys.stderr, "Fixpoint failed, looping back"
|
||||||
else:
|
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):
|
class DefineMacros(Pass):
|
||||||
"Extract macro definitions and remove them from the IR"
|
"Extract macro definitions and remove them from the IR"
|
||||||
name = "Macro definition pass"
|
name = "Macro definition pass"
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.inDef = 0
|
self.inDef = False
|
||||||
self.nestedError = 0
|
self.nestedError = False
|
||||||
|
|
||||||
def postPass(self):
|
def postPass(self):
|
||||||
if self.inDef:
|
if self.inDef:
|
||||||
Err.log("Unmatched .macro")
|
Err.log("Unmatched .macro")
|
||||||
elif Cmd.print_ir:
|
elif Cmd.print_ir:
|
||||||
print>>sys.stderr, "Macro definitions:"
|
print>>sys.stderr, "Macro definitions:"
|
||||||
Macro.dump()
|
Macro.dump()
|
||||||
|
|
||||||
def visitMacroBegin(self, node, env):
|
def visitMacroBegin(self, node, env):
|
||||||
if self.inDef:
|
if self.inDef:
|
||||||
Err.log("Nested macro definition")
|
Err.log("Nested macro definition")
|
||||||
self.nestedError = 1
|
self.nestedError = True
|
||||||
else:
|
else:
|
||||||
Macro.newMacro(node.data[0])
|
Macro.newMacro(node.data[0])
|
||||||
node.nodetype = "None"
|
node.nodetype = "None"
|
||||||
node.data = []
|
node.data = []
|
||||||
self.inDef = 1
|
self.inDef = True
|
||||||
|
|
||||||
def visitMacroEnd(self, node, env):
|
def visitMacroEnd(self, node, env):
|
||||||
if self.inDef:
|
if self.inDef:
|
||||||
Macro.endMacro()
|
Macro.endMacro()
|
||||||
node.nodetype = "None"
|
node.nodetype = "None"
|
||||||
node.data = []
|
node.data = []
|
||||||
self.inDef = 0
|
self.inDef = False
|
||||||
elif not self.nestedError:
|
elif not self.nestedError:
|
||||||
Err.log("Unmatched .macend")
|
Err.log("Unmatched .macend")
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
def visitUnknown(self, node, env):
|
||||||
if self.inDef:
|
if self.inDef:
|
||||||
Macro.registerNode(node)
|
Macro.registerNode(node)
|
||||||
|
@ -126,29 +153,38 @@ class DefineMacros(Pass):
|
||||||
class ExpandMacros(Pass):
|
class ExpandMacros(Pass):
|
||||||
"Replace macro invocations with the appropriate text"
|
"Replace macro invocations with the appropriate text"
|
||||||
name = "Macro expansion pass"
|
name = "Macro expansion pass"
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.changed = 0
|
self.changed = False
|
||||||
|
|
||||||
def visitMacroInvoke(self, node, env):
|
def visitMacroInvoke(self, node, env):
|
||||||
replacement = Macro.expandMacro(node.ppt, node.data[0], node.data[1:])
|
replacement = Macro.expandMacro(node.ppt, node.data[0], node.data[1:])
|
||||||
node.nodetype = replacement.nodetype
|
node.nodetype = replacement.nodetype
|
||||||
node.data = replacement.data
|
node.data = replacement.data
|
||||||
self.changed = 1
|
self.changed = True
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
def visitUnknown(self, node, env):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InitLabels(Pass):
|
class InitLabels(Pass):
|
||||||
"Finds all reachable labels"
|
"Finds all reachable labels"
|
||||||
name = "Label initialization pass"
|
name = "Label initialization pass"
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Pass.__init__(self)
|
Pass.__init__(self)
|
||||||
self.labelmap = {}
|
self.labelmap = {}
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.changed = 0
|
self.changed = False
|
||||||
self.PCvalid = 1
|
self.PCvalid = True
|
||||||
|
|
||||||
def visitAdvance(self, node, env):
|
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):
|
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):
|
def visitLabel(self, node, env):
|
||||||
(label, val) = node.data
|
(label, val) = node.data
|
||||||
fulllabel = "%d:%s" % (env.stack[0], label)
|
fulllabel = "%d:%s" % (env.stack[0], label)
|
||||||
|
@ -157,47 +193,60 @@ class InitLabels(Pass):
|
||||||
if fulllabel not in self.labelmap:
|
if fulllabel not in self.labelmap:
|
||||||
self.labelmap[fulllabel] = node
|
self.labelmap[fulllabel] = node
|
||||||
if val.valid(env, self.PCvalid) and label not in env:
|
if val.valid(env, self.PCvalid) and label not in env:
|
||||||
env[label]=0
|
env[label] = 0
|
||||||
self.changed=1
|
self.changed = True
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
def visitUnknown(self, node, env):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CircularityCheck(Pass):
|
class CircularityCheck(Pass):
|
||||||
"Checks for circular label dependencies"
|
"Checks for circular label dependencies"
|
||||||
name = "Circularity check pass"
|
name = "Circularity check pass"
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.changed=0
|
self.changed = False
|
||||||
self.PCvalid=1
|
self.PCvalid = True
|
||||||
|
|
||||||
def visitAdvance(self, node, env):
|
def visitAdvance(self, node, env):
|
||||||
PCvalid = self.PCvalid
|
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):
|
if not node.data[0].valid(env, PCvalid):
|
||||||
Err.log("Undefined or circular reference on .advance")
|
Err.log("Undefined or circular reference on .advance")
|
||||||
|
|
||||||
def visitSetPC(self, node, env):
|
def visitSetPC(self, node, env):
|
||||||
PCvalid = self.PCvalid
|
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):
|
if not node.data[0].valid(env, PCvalid):
|
||||||
Err.log("Undefined or circular reference on program counter set")
|
Err.log("Undefined or circular reference on program counter set")
|
||||||
|
|
||||||
def visitCheckPC(self, node, env):
|
def visitCheckPC(self, node, env):
|
||||||
if not node.data[0].valid(env, self.PCvalid):
|
if not node.data[0].valid(env, self.PCvalid):
|
||||||
Err.log("Undefined or circular reference on program counter check")
|
Err.log("Undefined or circular reference on program counter check")
|
||||||
|
|
||||||
def visitLabel(self, node, env):
|
def visitLabel(self, node, env):
|
||||||
(label, val) = node.data
|
(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)
|
Err.log("Undefined or circular dependency for label '%s'" % label)
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
def visitUnknown(self, node, env):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class CheckExprs(Pass):
|
class CheckExprs(Pass):
|
||||||
"Ensures all expressions can resolve"
|
"Ensures all expressions can resolve"
|
||||||
name = "Expression checking pass"
|
name = "Expression checking pass"
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
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)]:
|
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):
|
class EasyModes(Pass):
|
||||||
"Assigns address modes to hardcoded and branch instructions"
|
"Assigns address modes to hardcoded and branch instructions"
|
||||||
name = "Easy addressing modes pass"
|
name = "Easy addressing modes pass"
|
||||||
|
|
||||||
def visitMemory(self, node, env):
|
def visitMemory(self, node, env):
|
||||||
if Ops.opcodes[node.data[0]][14] is not None:
|
if Ops.opcodes[node.data[0]][14] is not None:
|
||||||
node.nodetype = "Relative"
|
node.nodetype = "Relative"
|
||||||
|
@ -205,157 +254,240 @@ class EasyModes(Pass):
|
||||||
if node.data[1].hardcoded:
|
if node.data[1].hardcoded:
|
||||||
if not collapse_no_index(node, env):
|
if not collapse_no_index(node, env):
|
||||||
node.nodetype = "Absolute"
|
node.nodetype = "Absolute"
|
||||||
|
|
||||||
def visitMemoryX(self, node, env):
|
def visitMemoryX(self, node, env):
|
||||||
if node.data[1].hardcoded:
|
if node.data[1].hardcoded:
|
||||||
if not collapse_x(node, env):
|
if not collapse_x(node, env):
|
||||||
node.nodetype = "AbsoluteX"
|
node.nodetype = "AbsoluteX"
|
||||||
|
|
||||||
def visitMemoryY(self, node, env):
|
def visitMemoryY(self, node, env):
|
||||||
if node.data[1].hardcoded:
|
if node.data[1].hardcoded:
|
||||||
if not collapse_y(node, env):
|
if not collapse_y(node, env):
|
||||||
node.nodetype = "AbsoluteY"
|
node.nodetype = "AbsoluteY"
|
||||||
|
|
||||||
def visitPointer(self, node, env):
|
def visitPointer(self, node, env):
|
||||||
if node.data[1].hardcoded:
|
if node.data[1].hardcoded:
|
||||||
if not collapse_no_index_ind(node, env):
|
if not collapse_no_index_ind(node, env):
|
||||||
node.nodetype = "Indirect"
|
node.nodetype = "Indirect"
|
||||||
|
|
||||||
def visitPointerX(self, node, env):
|
def visitPointerX(self, node, env):
|
||||||
if node.data[1].hardcoded:
|
if node.data[1].hardcoded:
|
||||||
if not collapse_x_ind(node, env):
|
if not collapse_x_ind(node, env):
|
||||||
node.nodetype = "AbsIndX"
|
node.nodetype = "AbsIndX"
|
||||||
|
|
||||||
def visitPointerY(self, node, env):
|
def visitPointerY(self, node, env):
|
||||||
if node.data[1].hardcoded:
|
if node.data[1].hardcoded:
|
||||||
if not collapse_y_ind(node, env):
|
if not collapse_y_ind(node, env):
|
||||||
node.nodetype = "AbsIndY"
|
node.nodetype = "AbsIndY"
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
def visitUnknown(self, node, env):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class PCTracker(Pass):
|
class PCTracker(Pass):
|
||||||
"Superclass for passes that need an accurate program counter."
|
"Superclass for passes that need an accurate program counter."
|
||||||
name = "**BUG** PC Tracker Superpass used directly"
|
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 visitSetPC(self, node, env):
|
||||||
def visitImplied(self, node, env): env.incPC(1)
|
env.setPC(node.data[0].value(env))
|
||||||
def visitImmediate(self, node, env): env.incPC(2)
|
|
||||||
def visitIndirectX(self, node, env): env.incPC(2)
|
def visitAdvance(self, node, env):
|
||||||
def visitIndirectY(self, node, env): env.incPC(2)
|
env.setPC(node.data[0].value(env))
|
||||||
def visitZPIndirect(self, node, env): env.incPC(2)
|
|
||||||
def visitZeroPage(self, node, env): env.incPC(2)
|
def visitImplied(self, node, env):
|
||||||
def visitZeroPageX(self, node, env): env.incPC(2)
|
env.incPC(1)
|
||||||
def visitZeroPageY(self, node, env): env.incPC(2)
|
|
||||||
def visitRelative(self, node, env): env.incPC(2)
|
def visitImmediate(self, node, env):
|
||||||
def visitIndirect(self, node, env): env.incPC(3)
|
env.incPC(2)
|
||||||
def visitAbsolute(self, node, env): env.incPC(3)
|
|
||||||
def visitAbsoluteX(self, node, env): env.incPC(3)
|
def visitIndirectX(self, node, env):
|
||||||
def visitAbsoluteY(self, node, env): env.incPC(3)
|
env.incPC(2)
|
||||||
def visitAbsIndX(self, node, env): env.incPC(3)
|
|
||||||
def visitAbsIndY(self, node, env): env.incPC(3)
|
def visitIndirectY(self, node, env):
|
||||||
def visitMemory(self, node, env): env.incPC(3)
|
env.incPC(2)
|
||||||
def visitMemoryX(self, node, env): env.incPC(3)
|
|
||||||
def visitMemoryY(self, node, env): env.incPC(3)
|
def visitZPIndirect(self, node, env):
|
||||||
def visitPointer(self, node, env): env.incPC(3)
|
env.incPC(2)
|
||||||
def visitPointerX(self, node, env): env.incPC(3)
|
|
||||||
def visitPointerY(self, node, env): env.incPC(3)
|
def visitZeroPage(self, node, env):
|
||||||
def visitCheckPC(self, node, env): pass
|
env.incPC(2)
|
||||||
def visitLabel(self, node, env): pass
|
|
||||||
def visitByte(self, node, env): env.incPC(len(node.data))
|
def visitZeroPageX(self, node, env):
|
||||||
def visitWord(self, node, env): env.incPC(len(node.data)*2)
|
env.incPC(2)
|
||||||
def visitDword(self, node, env): env.incPC(len(node.data)*4)
|
|
||||||
def visitWordBE(self, node, env): env.incPC(len(node.data)*2)
|
def visitZeroPageY(self, node, env):
|
||||||
def visitDwordBE(self, node, env): env.incPC(len(node.data)*4)
|
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):
|
class UpdateLabels(PCTracker):
|
||||||
"Computes the new values for all entries in the symbol table"
|
"Computes the new values for all entries in the symbol table"
|
||||||
name = "Label Update Pass"
|
name = "Label Update Pass"
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.changed = 0
|
self.changed = False
|
||||||
|
|
||||||
def visitLabel(self, node, env):
|
def visitLabel(self, node, env):
|
||||||
(label, val) = node.data
|
(label, val) = node.data
|
||||||
old = env[label]
|
old = env[label]
|
||||||
env[label] = val.value(env)
|
env[label] = val.value(env)
|
||||||
if old != env[label]:
|
if old != env[label]:
|
||||||
self.changed = 1
|
self.changed = True
|
||||||
|
|
||||||
|
|
||||||
class Collapse(Pass):
|
class Collapse(Pass):
|
||||||
"""Selects as many zero-page instructions to convert as
|
"Selects as many zero-page instructions to convert as possible."
|
||||||
possible, and tracks how many instructions have been
|
|
||||||
converted this pass."""
|
|
||||||
name = "Instruction Collapse Pass"
|
name = "Instruction Collapse Pass"
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.collapsed = 0
|
self.changed = False
|
||||||
|
|
||||||
def visitMemory(self, node, env):
|
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):
|
def visitMemoryX(self, node, env):
|
||||||
if collapse_x(node, env): self.collapsed += 1
|
self.changed |= collapse_x(node, env)
|
||||||
|
|
||||||
def visitMemoryY(self, 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):
|
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):
|
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):
|
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):
|
def visitUnknown(self, node, env):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def collapse_no_index(node, env):
|
def collapse_no_index(node, env):
|
||||||
"""Transforms a Memory node into a ZeroPage one if possible.
|
"""Transforms a Memory node into a ZeroPage one if possible.
|
||||||
Returns 1 if it made the collapse, false otherwise."""
|
Returns boolean indicating whether or not it made the collapse."""
|
||||||
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][2] is not None:
|
if node.data[1].value(env) < 0x100:
|
||||||
|
if Ops.opcodes[node.data[0]][2] is not None:
|
||||||
node.nodetype = "ZeroPage"
|
node.nodetype = "ZeroPage"
|
||||||
return 1
|
return True
|
||||||
else:
|
return False
|
||||||
return 0
|
|
||||||
|
|
||||||
def collapse_x(node, env):
|
def collapse_x(node, env):
|
||||||
"""Transforms a MemoryX node into a ZeroPageX one if possible.
|
"""Transforms a MemoryX node into a ZeroPageX one if possible.
|
||||||
Returns 1 if it made the collapse, false otherwise."""
|
Returns boolean indicating whether or not it made the collapse."""
|
||||||
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][3] is not None:
|
if node.data[1].value(env) < 0x100:
|
||||||
|
if Ops.opcodes[node.data[0]][3] is not None:
|
||||||
node.nodetype = "ZeroPageX"
|
node.nodetype = "ZeroPageX"
|
||||||
return 1
|
return True
|
||||||
else:
|
return False
|
||||||
return 0
|
|
||||||
|
|
||||||
def collapse_y(node, env):
|
def collapse_y(node, env):
|
||||||
"""Transforms a MemoryY node into a ZeroPageY one if possible.
|
"""Transforms a MemoryY node into a ZeroPageY one if possible.
|
||||||
Returns 1 if it made the collapse, false otherwise."""
|
Returns boolean indicating whether or not it made the collapse."""
|
||||||
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][4] is not None:
|
if node.data[1].value(env) < 0x100:
|
||||||
|
if Ops.opcodes[node.data[0]][4] is not None:
|
||||||
node.nodetype = "ZeroPageY"
|
node.nodetype = "ZeroPageY"
|
||||||
return 1
|
return True
|
||||||
else:
|
return False
|
||||||
return 0
|
|
||||||
|
|
||||||
def collapse_no_index_ind(node, env):
|
def collapse_no_index_ind(node, env):
|
||||||
"""Transforms a Pointer node into a ZPIndirect one if possible.
|
"""Transforms a Pointer node into a ZPIndirect one if possible.
|
||||||
Returns 1 if it made the collapse, false otherwise."""
|
Returns boolean indicating whether or not it made the collapse."""
|
||||||
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][11] is not None:
|
if node.data[1].value(env) < 0x100:
|
||||||
|
if Ops.opcodes[node.data[0]][11] is not None:
|
||||||
node.nodetype = "ZPIndirect"
|
node.nodetype = "ZPIndirect"
|
||||||
return 1
|
return True
|
||||||
else:
|
return False
|
||||||
return 0
|
|
||||||
|
|
||||||
def collapse_x_ind(node, env):
|
def collapse_x_ind(node, env):
|
||||||
"""Transforms a PointerX node into an IndirectX one if possible.
|
"""Transforms a PointerX node into an IndirectX one if possible.
|
||||||
Returns 1 if it made the collapse, false otherwise."""
|
Returns boolean indicating whether or not it made the collapse."""
|
||||||
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][12] is not None:
|
if node.data[1].value(env) < 0x100:
|
||||||
|
if Ops.opcodes[node.data[0]][12] is not None:
|
||||||
node.nodetype = "IndirectX"
|
node.nodetype = "IndirectX"
|
||||||
return 1
|
return True
|
||||||
else:
|
return False
|
||||||
return 0
|
|
||||||
|
|
||||||
def collapse_y_ind(node, env):
|
def collapse_y_ind(node, env):
|
||||||
"""Transforms a PointerY node into an IndirectY one if possible.
|
"""Transforms a PointerY node into an IndirectY one if possible.
|
||||||
Returns 1 if it made the collapse, false otherwise."""
|
Returns boolean indicating whether or not it made the collapse."""
|
||||||
if node.data[1].value(env) < 0x100 and Ops.opcodes[node.data[0]][13] is not None:
|
if node.data[1].value(env) < 0x100:
|
||||||
|
if Ops.opcodes[node.data[0]][13] is not None:
|
||||||
node.nodetype = "IndirectY"
|
node.nodetype = "IndirectY"
|
||||||
return 1
|
return True
|
||||||
else:
|
return False
|
||||||
return 0
|
|
||||||
|
|
||||||
class ExtendBranches(PCTracker):
|
class ExtendBranches(PCTracker):
|
||||||
"""Eliminates any branch instructions that would end up going past
|
"""Eliminates any branch instructions that would end up going past
|
||||||
the 128-byte range, and replaces them with a branch-jump
|
the 128-byte range, and replaces them with a branch-jump pair."""
|
||||||
pair. Also tracks how many elements where changed this pass."""
|
|
||||||
name = "Branch Expansion Pass"
|
name = "Branch Expansion Pass"
|
||||||
reversed = { 'bcc': 'bcs',
|
reversed = {'bcc': 'bcs',
|
||||||
'bcs': 'bcc',
|
'bcs': 'bcc',
|
||||||
'beq': 'bne',
|
'beq': 'bne',
|
||||||
'bmi': 'bpl',
|
'bmi': 'bpl',
|
||||||
|
@ -381,47 +513,75 @@ class ExtendBranches(PCTracker):
|
||||||
'bbr7': 'bbs7',
|
'bbr7': 'bbs7',
|
||||||
'bbs7': 'bbr7'
|
'bbs7': 'bbr7'
|
||||||
}
|
}
|
||||||
|
|
||||||
def prePass(self):
|
def prePass(self):
|
||||||
self.expanded = 0
|
self.changed = False
|
||||||
|
|
||||||
def visitRelative(self, node, env):
|
def visitRelative(self, node, env):
|
||||||
(opcode, expr) = node.data
|
(opcode, expr) = node.data
|
||||||
arg = expr.value(env)
|
arg = expr.value(env)
|
||||||
arg = arg-(env.getPC()+2)
|
arg = arg - (env.getPC() + 2)
|
||||||
if arg < -128 or arg > 127:
|
if arg < -128 or arg > 127:
|
||||||
if opcode == 'bra':
|
if opcode == 'bra':
|
||||||
# If BRA - BRanch Always - is out of range, it's a JMP.
|
# If BRA - BRanch Always - is out of range, it's a JMP.
|
||||||
node.data = ('jmp', expr)
|
node.data = ('jmp', expr)
|
||||||
node.nodetype = "Absolute"
|
node.nodetype = "Absolute"
|
||||||
if Cmd.warn_on_branch_extend:
|
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:
|
else:
|
||||||
# Otherwise, we replace it with a 'macro' of sorts by hand:
|
# Otherwise, we replace it with a 'macro' of sorts by hand:
|
||||||
# $branch LOC -> $reversed_branch ^+5; JMP LOC
|
# $branch LOC -> $reversed_branch ^+5; JMP LOC
|
||||||
# We don't use temp labels here because labels need to have been fixed
|
# We don't use temp labels here because labels need to have
|
||||||
# in place by this point, and JMP is always 3 bytes long.
|
# been fixed in place by this point, and JMP is always 3
|
||||||
expansion = [IR.Node(node.ppt, "Relative", ExtendBranches.reversed[opcode], IR.SequenceExpr([IR.PCExpr(), "+", IR.ConstantExpr(5)])),
|
# 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)]
|
IR.Node(node.ppt, "Absolute", 'jmp', expr)]
|
||||||
node.nodetype='SEQUENCE'
|
node.nodetype = 'SEQUENCE'
|
||||||
node.data = expansion
|
node.data = expansion
|
||||||
if Cmd.warn_on_branch_extend:
|
if Cmd.warn_on_branch_extend:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: "+opcode+" out of range, replacing with "+ExtendBranches.reversed[opcode] +"/jmp combo"
|
print>>sys.stderr, str(node.ppt) + ": WARNING: " + \
|
||||||
self.expanded += 1
|
opcode + " out of range, " \
|
||||||
|
"replacing with " + \
|
||||||
|
ExtendBranches.reversed[opcode] + \
|
||||||
|
"/jmp combo"
|
||||||
|
self.changed = True
|
||||||
node.accept(self, env)
|
node.accept(self, env)
|
||||||
else:
|
else:
|
||||||
env.incPC(2)
|
env.incPC(2)
|
||||||
|
|
||||||
|
|
||||||
class NormalizeModes(Pass):
|
class NormalizeModes(Pass):
|
||||||
"""Eliminates the intermediate "Memory" and "Pointer" nodes,
|
"""Eliminates the intermediate "Memory" and "Pointer" nodes,
|
||||||
converting them to "Absolute"."""
|
converting them to "Absolute"."""
|
||||||
name = "Mode Normalization pass"
|
name = "Mode Normalization pass"
|
||||||
def visitMemory(self, node, env): node.nodetype = "Absolute"
|
|
||||||
def visitMemoryX(self, node, env): node.nodetype = "AbsoluteX"
|
def visitMemory(self, node, env):
|
||||||
def visitMemoryY(self, node, env): node.nodetype = "AbsoluteY"
|
node.nodetype = "Absolute"
|
||||||
def visitPointer(self, node, env): node.nodetype = "Indirect"
|
|
||||||
def visitPointerX(self, node, env): node.nodetype = "AbsIndX"
|
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.
|
# 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):
|
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
|
||||||
|
@ -436,36 +596,40 @@ class Assembler(Pass):
|
||||||
|
|
||||||
def postPass(self):
|
def postPass(self):
|
||||||
if Cmd.print_summary and Err.count == 0:
|
if Cmd.print_summary and Err.count == 0:
|
||||||
print>>sys.stderr, "Assembly complete: %s bytes output (%s code, %s data, %s filler)" \
|
print>>sys.stderr, "Assembly complete: %s bytes output " \
|
||||||
% (len(self.output), self.code, self.data, self.filler)
|
"(%s code, %s data, %s filler)" \
|
||||||
|
% (len(self.output),
|
||||||
|
self.code, self.data, self.filler)
|
||||||
|
|
||||||
def outputbyte(self, expr, env):
|
def outputbyte(self, expr, env):
|
||||||
'Outputs a byte, with range checking'
|
'Outputs a byte, with range checking'
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x00 or val > 0xff:
|
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
|
val = 0
|
||||||
self.output.append(int(val))
|
self.output.append(int(val))
|
||||||
else:
|
else:
|
||||||
Err.log("Attempt to write to data segment")
|
Err.log("Attempt to write to data segment")
|
||||||
|
|
||||||
def outputword(self, expr, env):
|
def outputword(self, expr, env):
|
||||||
'Outputs a little-endian word, with range checking'
|
'Outputs a little-endian word, with range checking'
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x0000 or val > 0xFFFF:
|
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
|
val = 0
|
||||||
self.output.append(int(val & 0xFF))
|
self.output.append(int(val & 0xFF))
|
||||||
self.output.append(int((val >> 8) & 0xFF))
|
self.output.append(int((val >> 8) & 0xFF))
|
||||||
else:
|
else:
|
||||||
Err.log("Attempt to write to data segment")
|
Err.log("Attempt to write to data segment")
|
||||||
|
|
||||||
def outputdword(self, expr, env):
|
def outputdword(self, expr, env):
|
||||||
'Outputs a little-endian dword, with range checking'
|
'Outputs a little-endian dword, with range checking'
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x00000000 or val > 0xFFFFFFFFL:
|
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
|
val = 0
|
||||||
self.output.append(int(val & 0xFF))
|
self.output.append(int(val & 0xFF))
|
||||||
self.output.append(int((val >> 8) & 0xFF))
|
self.output.append(int((val >> 8) & 0xFF))
|
||||||
|
@ -479,18 +643,19 @@ class Assembler(Pass):
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x0000 or val > 0xFFFF:
|
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
|
val = 0
|
||||||
self.output.append(int((val >> 8) & 0xFF))
|
self.output.append(int((val >> 8) & 0xFF))
|
||||||
self.output.append(int(val & 0xFF))
|
self.output.append(int(val & 0xFF))
|
||||||
else:
|
else:
|
||||||
Err.log("Attempt to write to data segment")
|
Err.log("Attempt to write to data segment")
|
||||||
|
|
||||||
def outputdword_be(self, expr, env):
|
def outputdword_be(self, expr, env):
|
||||||
'Outputs a big-endian dword, with range checking'
|
'Outputs a big-endian dword, with range checking'
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x00000000 or val > 0xFFFFFFFFL:
|
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
|
val = 0
|
||||||
self.output.append(int((val >> 24) & 0xFF))
|
self.output.append(int((val >> 24) & 0xFF))
|
||||||
self.output.append(int((val >> 16) & 0xFF))
|
self.output.append(int((val >> 16) & 0xFF))
|
||||||
|
@ -504,77 +669,122 @@ class Assembler(Pass):
|
||||||
(opcode, expr) = node.data
|
(opcode, expr) = node.data
|
||||||
bin_op = Ops.opcodes[opcode][mode]
|
bin_op = Ops.opcodes[opcode][mode]
|
||||||
if bin_op is None:
|
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
|
return
|
||||||
self.outputbyte(IR.ConstantExpr(bin_op), env)
|
self.outputbyte(IR.ConstantExpr(bin_op), env)
|
||||||
arglen = Ops.lengths[mode]
|
arglen = Ops.lengths[mode]
|
||||||
if mode == 14: # Special handling for relative mode
|
if mode == 14: # Special handling for relative mode
|
||||||
arg = expr.value(env)
|
arg = expr.value(env)
|
||||||
arg = arg-(env.getPC()+2)
|
arg = arg - (env.getPC() + 2)
|
||||||
if arg < -128 or arg > 127:
|
if arg < -128 or arg > 127:
|
||||||
Err.log("Branch target out of bounds")
|
Err.log("Branch target out of bounds")
|
||||||
arg = 0
|
arg = 0
|
||||||
if arg < 0: arg += 256
|
if arg < 0:
|
||||||
|
arg += 256
|
||||||
expr = IR.ConstantExpr(arg)
|
expr = IR.ConstantExpr(arg)
|
||||||
if arglen == 1: self.outputbyte(expr, env)
|
if arglen == 1:
|
||||||
if arglen == 2: self.outputword(expr, env)
|
self.outputbyte(expr, env)
|
||||||
env.incPC(1+arglen)
|
if arglen == 2:
|
||||||
self.code += 1+arglen
|
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):
|
def visitByte(self, node, env):
|
||||||
for expr in node.data:
|
for expr in node.data:
|
||||||
self.outputbyte(expr, env)
|
self.outputbyte(expr, env)
|
||||||
env.incPC(len(node.data))
|
env.incPC(len(node.data))
|
||||||
self.data += len(node.data)
|
self.data += len(node.data)
|
||||||
|
|
||||||
def visitWord(self, node, env):
|
def visitWord(self, node, env):
|
||||||
for expr in node.data:
|
for expr in node.data:
|
||||||
self.outputword(expr, env)
|
self.outputword(expr, env)
|
||||||
env.incPC(len(node.data)*2)
|
env.incPC(len(node.data) * 2)
|
||||||
self.data += len(node.data)*2
|
self.data += len(node.data) * 2
|
||||||
|
|
||||||
def visitDword(self, node, env):
|
def visitDword(self, node, env):
|
||||||
for expr in node.data:
|
for expr in node.data:
|
||||||
self.outputdword(expr, env)
|
self.outputdword(expr, env)
|
||||||
env.incPC(len(node.data)*4)
|
env.incPC(len(node.data) * 4)
|
||||||
self.data += len(node.data)*4
|
self.data += len(node.data) * 4
|
||||||
|
|
||||||
def visitWordBE(self, node, env):
|
def visitWordBE(self, node, env):
|
||||||
for expr in node.data:
|
for expr in node.data:
|
||||||
self.outputword_be(expr, env)
|
self.outputword_be(expr, env)
|
||||||
env.incPC(len(node.data)*2)
|
env.incPC(len(node.data) * 2)
|
||||||
self.data += len(node.data)*2
|
self.data += len(node.data) * 2
|
||||||
|
|
||||||
def visitDwordBE(self, node, env):
|
def visitDwordBE(self, node, env):
|
||||||
for expr in node.data:
|
for expr in node.data:
|
||||||
self.outputdword_be(expr, env)
|
self.outputdword_be(expr, env)
|
||||||
env.incPC(len(node.data)*4)
|
env.incPC(len(node.data) * 4)
|
||||||
self.data += len(node.data)*4
|
self.data += len(node.data) * 4
|
||||||
|
|
||||||
def visitSetPC(self, node, env):
|
def visitSetPC(self, node, env):
|
||||||
env.setPC(node.data[0].value(env))
|
env.setPC(node.data[0].value(env))
|
||||||
|
|
||||||
def visitCheckPC(self, node, env):
|
def visitCheckPC(self, node, env):
|
||||||
pc = env.getPC()
|
pc = env.getPC()
|
||||||
target = node.data[0].value(env)
|
target = node.data[0].value(env)
|
||||||
if (pc > target):
|
if (pc > target):
|
||||||
Err.log(".checkpc assertion failed: $%x > $%x" % (pc, target))
|
Err.log(".checkpc assertion failed: $%x > $%x" % (pc, target))
|
||||||
|
|
||||||
def visitAdvance(self, node, env):
|
def visitAdvance(self, node, env):
|
||||||
pc = env.getPC()
|
pc = env.getPC()
|
||||||
target = node.data[0].value(env)
|
target = node.data[0].value(env)
|
||||||
if (pc > target):
|
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:
|
else:
|
||||||
for i in xrange(target-pc): self.outputbyte(node.data[1], env)
|
for i in xrange(target - pc):
|
||||||
self.filler += target-pc
|
self.outputbyte(node.data[1], env)
|
||||||
|
self.filler += target - pc
|
||||||
env.setPC(target)
|
env.setPC(target)
|
||||||
|
|
|
@ -6,6 +6,11 @@ setup(name='Ophis',
|
||||||
author="Michael Martin",
|
author="Michael Martin",
|
||||||
author_email="mcmartin@gmail.com",
|
author_email="mcmartin@gmail.com",
|
||||||
license="MIT",
|
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'],
|
packages=['Ophis'],
|
||||||
scripts=['scripts/ophis'])
|
scripts=['scripts/ophis'])
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from distutils.core import setup
|
from distutils.core import setup
|
||||||
import py2exe, sys
|
import py2exe
|
||||||
|
import sys
|
||||||
|
|
||||||
sys.argv.append('py2exe')
|
sys.argv.append('py2exe')
|
||||||
|
|
||||||
setup(options = {'py2exe': {'bundle_files': 1}},
|
setup(options={'py2exe': {'bundle_files': 1}},
|
||||||
packages = ['Ophis'],
|
packages=['Ophis'],
|
||||||
zipfile = None,
|
zipfile=None,
|
||||||
console = [{'script': "scripts/ophis"}])
|
console=[{'script': "scripts/ophis"}])
|
||||||
|
|
|
@ -10,11 +10,13 @@ normmap = ''.join([bits[x] for x in norm])
|
||||||
ivrsmap = ''.join([bits[x] for x in ivrs])
|
ivrsmap = ''.join([bits[x] for x in ivrs])
|
||||||
blnkmap = ''.join([bits[x] for x in blnk])
|
blnkmap = ''.join([bits[x] for x in blnk])
|
||||||
|
|
||||||
|
|
||||||
def dumpfile(n, m):
|
def dumpfile(n, m):
|
||||||
f = file(n, 'wb')
|
f = file(n, 'wb')
|
||||||
f.write(m)
|
f.write(m)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
|
||||||
dumpfile('a2normal.map', normmap)
|
dumpfile('a2normal.map', normmap)
|
||||||
dumpfile('a2inverse.map', ivrsmap)
|
dumpfile('a2inverse.map', ivrsmap)
|
||||||
dumpfile('a2blink.map', blnkmap)
|
dumpfile('a2blink.map', blnkmap)
|
||||||
|
|
|
@ -3,7 +3,7 @@ import sys
|
||||||
|
|
||||||
verbose = 0
|
verbose = 0
|
||||||
|
|
||||||
prologue = '"""' +"""Opcodes file.
|
prologue = '"""' + """Opcodes file.
|
||||||
|
|
||||||
Tables for the assembly of 6502-family instructions, mapping
|
Tables for the assembly of 6502-family instructions, mapping
|
||||||
opcodes and addressing modes to binary instructions.""" + '"""' + """
|
opcodes and addressing modes to binary instructions.""" + '"""' + """
|
||||||
|
@ -33,6 +33,7 @@ modes = ["Implied", # 0
|
||||||
"(Zero Page), Y", # 13
|
"(Zero Page), Y", # 13
|
||||||
"Relative"] # 14
|
"Relative"] # 14
|
||||||
|
|
||||||
|
|
||||||
# Lengths of the argument
|
# Lengths of the argument
|
||||||
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
|
lengths = [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
|
||||||
"""
|
"""
|
||||||
|
@ -56,24 +57,28 @@ modes = ["Implied", # 0
|
||||||
|
|
||||||
flatmodes = [x.lower() for x in modes]
|
flatmodes = [x.lower() for x in modes]
|
||||||
|
|
||||||
|
|
||||||
# WARNING: This decommenter assumes that # never appears anywhere else
|
# WARNING: This decommenter assumes that # never appears anywhere else
|
||||||
# in a line.
|
# in a line.
|
||||||
def decomment (l):
|
def decomment(l):
|
||||||
if '#' in l:
|
if '#' in l:
|
||||||
l = l[:l.index('#')]
|
l = l[:l.index('#')]
|
||||||
return l.strip()
|
return l.strip()
|
||||||
|
|
||||||
def decomment_readlines (fname):
|
|
||||||
|
def decomment_readlines(fname):
|
||||||
result = [decomment(x) for x in file(fname).readlines()]
|
result = [decomment(x) for x in file(fname).readlines()]
|
||||||
return [x for x in result if len(x) > 0]
|
return [x for x in result if len(x) > 0]
|
||||||
|
|
||||||
def parse_chipset_file (fname):
|
|
||||||
|
def parse_chipset_file(fname):
|
||||||
result = [None] * 256
|
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:
|
for l in ls:
|
||||||
if len(l) == 2:
|
if len(l) == 2:
|
||||||
try:
|
try:
|
||||||
op = int (l[0], 16)
|
op = int(l[0], 16)
|
||||||
syns = l[1].split(';')
|
syns = l[1].split(';')
|
||||||
for s in syns:
|
for s in syns:
|
||||||
s_p = s.split('-')
|
s_p = s.split('-')
|
||||||
|
@ -81,7 +86,7 @@ def parse_chipset_file (fname):
|
||||||
mnem = s_p[0].lower().strip()
|
mnem = s_p[0].lower().strip()
|
||||||
mode = s_p[1].lower().strip()
|
mode = s_p[1].lower().strip()
|
||||||
if mode in flatmodes:
|
if mode in flatmodes:
|
||||||
if result[op] == None:
|
if result[op] is None:
|
||||||
result[op] = []
|
result[op] = []
|
||||||
result[op].append((mnem, flatmodes.index(mode)))
|
result[op].append((mnem, flatmodes.index(mode)))
|
||||||
else:
|
else:
|
||||||
|
@ -90,10 +95,11 @@ def parse_chipset_file (fname):
|
||||||
print "Illegal opcode '%s'" % l[0]
|
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 = {}
|
result = {}
|
||||||
for (opcode, insts) in zip (range(256), cs_list):
|
for (opcode, insts) in zip(range(256), cs_list):
|
||||||
if insts != None:
|
if insts is not None:
|
||||||
for inst in insts:
|
for inst in insts:
|
||||||
(mnem, mode) = inst
|
(mnem, mode) = inst
|
||||||
if mnem not in result:
|
if mnem not in result:
|
||||||
|
@ -115,19 +121,26 @@ def collate_chipset_map (cs_list, base):
|
||||||
del result[x]
|
del result[x]
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def mapval(x):
|
def mapval(x):
|
||||||
if x is None:
|
if x is None:
|
||||||
return "None"
|
return "None"
|
||||||
else:
|
else:
|
||||||
return "0x%02X" % x
|
return "0x%02X" % x
|
||||||
|
|
||||||
def dump_map (m, prologue = ''):
|
|
||||||
|
def dump_map(m, prologue=''):
|
||||||
mnems = m.keys()
|
mnems = m.keys()
|
||||||
mnems.sort()
|
mnems.sort()
|
||||||
for mnem in mnems:
|
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:
|
if len(sys.argv) > 1:
|
||||||
chipsets = argv[1:]
|
chipsets = argv[1:]
|
||||||
else:
|
else:
|
||||||
|
@ -135,7 +148,8 @@ if __name__=='__main__':
|
||||||
archs = []
|
archs = []
|
||||||
for x in chipsets:
|
for x in chipsets:
|
||||||
try:
|
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:
|
for l in ls:
|
||||||
if len(l) != 2:
|
if len(l) != 2:
|
||||||
print "Could not parse the chipset line '%s'" % ":".join(l)
|
print "Could not parse the chipset line '%s'" % ":".join(l)
|
||||||
|
@ -147,10 +161,9 @@ if __name__=='__main__':
|
||||||
baseset = None
|
baseset = None
|
||||||
for (field, fname) in archs:
|
for (field, fname) in archs:
|
||||||
chipset_list = parse_chipset_file(fname)
|
chipset_list = parse_chipset_file(fname)
|
||||||
instruction_map = collate_chipset_map (chipset_list, baseset)
|
instruction_map = collate_chipset_map(chipset_list, baseset)
|
||||||
if baseset == None:
|
if baseset is None:
|
||||||
baseset = instruction_map
|
baseset = instruction_map
|
||||||
print "%s = {" % field
|
print "%s = {" % field
|
||||||
dump_map (instruction_map, ' ' * (len(field) + 4))
|
dump_map(instruction_map, ' ' * (len(field) + 4))
|
||||||
print "%s}" % (' ' * (len(field) + 3))
|
print "%s}" % (' ' * (len(field) + 3))
|
||||||
print ""
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user