예제 #1
0
파일: Passes.py 프로젝트: cbmeeks/Ophis
 def visitZPRelative(self, node, env):
     (opcode, tested, expr) = node.data
     arg = expr.value(env)
     arg = arg - (env.getPC() + 3)
     if arg < -128 or arg > 127:
         # Otherwise, we replace it with a 'macro' of sorts by hand:
         # $branch LOC -> $reversed_branch ^+6; JMP LOC
         # We don't use temp labels here because labels need to have
         # been fixed in place by this point, and JMP is always 3
         # bytes long.
         expansion = [IR.Node(node.ppt, "ZPRelative",
                              ExtendBranches.reversed[opcode],
                              tested,
                              IR.SequenceExpr([IR.PCExpr(), "+",
                                               IR.ConstantExpr(6)])),
                      IR.Node(node.ppt, "Absolute", 'jmp', expr, None)]
         node.nodetype = 'SEQUENCE'
         node.data = expansion
         if Cmd.warn_on_branch_extend:
             print>>sys.stderr, str(node.ppt) + ": WARNING: " + \
                 opcode + " out of range, " \
                 "replacing with " + \
                 ExtendBranches.reversed[opcode] + \
                 "/jmp combo"
         self.changed = True
         node.accept(self, env)
     else:
         PCTracker.visitZPRelative(self, node, env)
예제 #2
0
def pragmaIncbin(ppt, line, result):
    "Includes a binary file"
    filename = line.expect("STRING").value
    offset = IR.ConstantExpr(0)
    size = None
    if str(line.lookahead(0)) == ",":
        line.pop()
        offset = FE.parse_expr(line)
        if str(line.lookahead(0)) == ",":
            line.pop()
            size = FE.parse_expr(line)
    line.expect("EOL")
    if type(filename) == str:
        try:
            f = file(os.path.join(FE.context_directory, filename), "rb")
            if offset.hardcoded and (size is None or size.hardcoded):
                # We know how big it will be, we can just use the values.
                # First check to make sure they're sane
                if offset.value() < 0:
                    Err.log("Offset may not be negative")
                    f.close()
                    return
                f.seek(0, 2)  # Seek to end of file
                if offset.value() > f.tell():
                    Err.log("Offset runs past end of file")
                    f.close()
                    return
                if size is not None:
                    if size.value() < 0:
                        Err.log("Length may not be negative")
                        f.close()
                        return
                    if offset.value() + size.value() > f.tell():
                        Err.log(".incbin length too long")
                        f.close()
                        return
                if size is None:
                    size = IR.ConstantExpr(-1)
                f.seek(offset.value())
                bytes = f.read(size.value())
                bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
                result.append(IR.Node(ppt, "Byte", *bytes))
            else:
                # offset or length could change based on label placement.
                # This seems like an unbelievably bad idea, but since we
                # don't have constant prop it will happen for any symbolic
                # alias. Don't use symbolic aliases when extracting tiny
                # pieces out of humongous files, I guess.
                bytes = f.read()
                bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
                if size is None:
                    size = IR.SequenceExpr([IR.ConstantExpr(len(bytes)),
                                            "-",
                                            offset])
                result.append(IR.Node(ppt, "ByteRange", offset, size, *bytes))
            f.close()
        except IOError:
            Err.log("Could not read " + filename)
            return
예제 #3
0
def pragmaSpace(ppt, line, result):
    "Reserves space in a data segment for a variable"
    lbl = line.expect("LABEL").value
    size = line.expect("NUM").value
    line.expect("EOL")
    result.append(IR.Node(ppt, "Label", lbl, IR.PCExpr()))
    result.append(IR.Node(ppt, "SetPC",
                          IR.SequenceExpr([IR.PCExpr(), "+",
                                           IR.ConstantExpr(size)])))
예제 #4
0
def pragmaInvoke(ppt, line, result):
    macro = line.expect("LABEL").value
    if line.lookahead(0).type == "EOL":
        args = []
    else:
        args = readData(line)
    result.append(IR.Node(ppt, "MacroInvoke", macro, *args))
예제 #5
0
def pragmaCbmfloat(ppt, line, result):
    "Parses a string into a CBM BASIC format floating point number"
    data = []
    while True:
        try:
            v_str = line.expect("STRING").value
            v = float(v_str)
            if v == 0.0:
                data.extend([0, 0, 0, 0, 0])
            else:
                if v < 0.0:
                    sign = 128
                    v = -v
                else:
                    sign = 0
                expt = math.floor(math.log(v, 2))
                if expt >= -128 and expt <= 126:
                    mantissa = v / (2**expt)
                    m1 = (mantissa - 1.0) * 128 + sign
                    m2 = m1 * 256
                    m3 = m2 * 256
                    m4 = m3 * 256
                    data.extend(
                        [int(x) % 256 for x in [expt + 129, m1, m2, m3, m4]])
                else:
                    Err.log("Floating point constant out of range")
        except ValueError:
            Err.log("Expected: floating point")
        next = line.expect(',', 'EOL').type
        if next == 'EOL':
            break
    bytes = [IR.ConstantExpr(x) for x in data]
    result.append(IR.Node(ppt, "Byte", *bytes))
예제 #6
0
 def visitRelative(self, node, env):
     (opcode, expr) = node.data[:2]
     arg = expr.value(env)
     arg = arg - (env.getPC() + 2)
     if arg < -128 or arg > 127:
         if Cmd.enable_4502_exts:
             node.nodetype = "RelativeLong"
             if Cmd.warn_on_branch_extend:
                 print(str(node.ppt) + ": WARNING: " \
                     "branch out of range, replacing with 16-bit relative branch", file=sys.stderr)
         else:
             if opcode == 'bra':
                 # If BRA - BRanch Always - is out of range, it's a JMP.
                 node.data = ('jmp', expr, None)
                 node.nodetype = "Absolute"
                 if Cmd.warn_on_branch_extend:
                     print(str(node.ppt) + ": WARNING: " \
                         "bra out of range, replacing with jmp", file=sys.stderr)
             else:
                 # Otherwise, we replace it with a 'macro' of sorts by hand:
                 # $branch LOC -> $reversed_branch ^+5; JMP LOC
                 # We don't use temp labels here because labels need to have
                 # been fixed in place by this point, and JMP is always 3
                 # bytes long.
                 expansion = [
                     IR.Node(
                         node.ppt, "Relative",
                         ExtendBranches.reversed[opcode],
                         IR.SequenceExpr(
                             [IR.PCExpr(), "+",
                              IR.ConstantExpr(5)]), None),
                     IR.Node(node.ppt, "Absolute", 'jmp', expr, None)
                 ]
                 node.nodetype = 'SEQUENCE'
                 node.data = expansion
                 if Cmd.warn_on_branch_extend:
                     print(str(node.ppt) + ": WARNING: " + \
                                    opcode + " out of range, " \
                                    "replacing with " + \
                                    ExtendBranches.reversed[opcode] + \
                                    "/jmp combo", file=sys.stderr)
                 self.changed = True
                 node.accept(self, env)
     else:
         PCTracker.visitRelative(self, node, env)
예제 #7
0
def expandMacro(ppt, name, arglist):
    global macros
    if name not in macros:
        Err.log("Undefined macro '%s'" % name)
        return IR.NullNode
    argexprs = [
        IR.Node(ppt, "Label", "_*%d" % i, arg)
        for (i, arg) in zip(xrange(1, sys.maxint), arglist)
    ]
    bindexprs = [
        IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i))
        for i in range(1,
                       len(arglist) + 1)
    ]
    body = [
        IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data)
        for node in macros[name]
    ]
    invocation = [IR.Node(ppt, "ScopeBegin")] + argexprs + [
        IR.Node(ppt, "ScopeBegin")
    ] + bindexprs + body + [
        IR.Node(ppt, "ScopeEnd"),
        IR.Node(ppt, "ScopeEnd")
    ]
    return IR.SequenceNode(ppt, invocation)
예제 #8
0
def pragmaText(ppt, line, result):
    "Switches to a text segment"
    next = line.expect("LABEL", "EOL")
    if next.type == "LABEL":
        line.expect("EOL")
        segment = next.value
    else:
        segment = "*text-default*"
    result.append(IR.Node(ppt, "TextSegment", segment))
예제 #9
0
def pragmaData(ppt, line, result):
    "Switches to a data segment (no output allowed)"
    next = line.expect("LABEL", "EOL")
    if next.type == "LABEL":
        line.expect("EOL")
        segment = next.value
    else:
        segment = "*data-default*"
    result.append(IR.Node(ppt, "DataSegment", segment))
def pragmaIncbin(ppt, line, result):
    "Includes a binary file"
    filename = line.expect("STRING").value
    line.expect("EOL")
    if type(filename) == str:
        f = file(filename, "rb")
        bytes = f.read()
        f.close()
        bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
        result.append(IR.Node(ppt, "Byte", *bytes))
예제 #11
0
def pragmaAdvance(ppt, line, result):
    "Outputs filler until reaching the target PC"
    newPC = FE.parse_expr(line)
    if str(line.lookahead(0)) == ",":
        line.pop()
        fillexpr = FE.parse_expr(line)
    else:
        fillexpr = IR.ConstantExpr(0)
    line.expect("EOL")
    result.append(IR.Node(ppt, "Advance", newPC, fillexpr))
예제 #12
0
def pragmaMacro(ppt, line, result):
    "Begin a macro definition"
    lbl = line.expect("LABEL").value
    line.expect("EOL")
    result.append(IR.Node(ppt, "MacroBegin", lbl))
예제 #13
0
def pragmaScend(ppt, line, result):
    "End the innermost lexical scoping block"
    line.expect("EOL")
    result.append(IR.Node(ppt, "ScopeEnd"))
예제 #14
0
def pragmaScope(ppt, line, result):
    "Create a new lexical scoping block"
    line.expect("EOL")
    result.append(IR.Node(ppt, "ScopeBegin"))
예제 #15
0
def pragmaDwordbe(ppt, line, result):
    "Raw data, a dword at a time, big-endian"
    dwords = readData(line)
    result.append(IR.Node(ppt, "DwordBE", *dwords))
예제 #16
0
def pragmaDword(ppt, line, result):
    "Raw data, a double-word at a time, little-endian"
    dwords = readData(line)
    result.append(IR.Node(ppt, "Dword", *dwords))
예제 #17
0
def pragmaWord(ppt, line, result):
    "Raw data, a word at a time, little-endian"
    words = readData(line)
    result.append(IR.Node(ppt, "Word", *words))
예제 #18
0
def pragmaByte(ppt, line, result):
    "Raw data, a byte at a time"
    bytes = readData(line)
    result.append(IR.Node(ppt, "Byte", *bytes))
def pragmaAdvance(ppt, line, result):
    "Outputs filler until reaching the target PC"
    newPC = FE.parse_expr(line)
    line.expect("EOL")
    result.append(IR.Node(ppt, "Advance", newPC))
예제 #20
0
def registerNode(node):
    global currentbody
    currentbody.append(IR.Node(node.ppt, node.nodetype, *node.data))
예제 #21
0
def pragmaMacend(ppt, line, result):
    "End a macro definition"
    line.expect("EOL")
    result.append(IR.Node(ppt, "MacroEnd"))
예제 #22
0
def pragmaCheckpc(ppt, line, result):
    "Enforces that the PC has not exceeded a certain point"
    target = FE.parse_expr(line)
    line.expect("EOL")
    result.append(IR.Node(ppt, "CheckPC", target))
예제 #23
0
def pragmaOrg(ppt, line, result):
    "Relocates the PC with no output"
    newPC = FE.parse_expr(line)
    line.expect("EOL")
    result.append(IR.Node(ppt, "SetPC", newPC))
예제 #24
0
 def aux():
     "Accumulates all IR nodes defined by this line."
     if line.lookahead(0).type == "EOL":
         pass
     elif line.lookahead(1).type == ":":
         newlabel = line.expect("LABEL").value
         line.expect(":")
         result.append(IR.Node(ppt, "Label", newlabel, IR.PCExpr()))
         aux()
     elif line.lookahead(0).type == "*":
         global templabelcount
         templabelcount = templabelcount + 1
         result.append(
             IR.Node(ppt, "Label", "*" + str(templabelcount), IR.PCExpr()))
         line.expect("*")
         aux()
     elif line.lookahead(0).type == "." or line.lookahead(0).type == "`":
         which = line.expect(".", "`").type
         if (which == "."):
             pragma = line.expect("LABEL").value
         else:
             pragma = "invoke"
         pragmaFunction = "pragma" + pragma.title()
         for mod in pragma_modules:
             if hasattr(mod, pragmaFunction):
                 getattr(mod, pragmaFunction)(ppt, line, result)
                 break
         else:
             Err.log("Unknown pragma " + pragma)
     else:  # Instruction
         opcode = line.expect("OPCODE").value
         arg2 = None
         if line.lookahead(0).type == "#":
             mode = "Immediate"
             line.expect("#")
             arg = parse_expr(line)
             line.expect("EOL")
         elif line.lookahead(0).type == "(":
             line.expect("(")
             arg = parse_expr(line)
             if line.lookahead(0).type == ",":
                 line.expect(",")
                 if line.lookahead(0).type == "X":
                     mode = "PointerX"
                     line.expect("X")
                     line.expect(")")
                     line.expect("EOL")
                 else:
                     mode = "PointerSPY"
                     line.expect("SP")
                     line.expect(")")
                     line.expect(",")
                     line.expect("Y")
                     line.expect("EOL")
             else:
                 line.expect(")")
                 tok = line.expect(",", "EOL").type
                 if tok == "EOL":
                     mode = "Pointer"
                 else:
                     if line.lookahead(0).type == "Y":
                         mode = "PointerY"
                         line.expect("Y")
                         line.expect("EOL")
                     else:
                         mode = "PointerZ"
                         line.expect("Z")
                         line.expect("EOL")
         elif line.lookahead(0).type == "EOL":
             mode = "Implied"
             arg = None
         else:
             arg = parse_expr(line)
             tok = line.expect("EOL", ",").type
             if tok == ",":
                 # Parser has to special-case the BBXn instructions,
                 # Which uniquely take two addresses
                 if opcode[:3] in ["bbs", "bbr"]:
                     arg2 = parse_expr(line)
                     mode = "Memory2"
                 else:
                     tok = line.expect("X", "Y", "Z").type
                     if tok == "X":
                         mode = "MemoryX"
                     elif tok == "Y":
                         mode = "MemoryY"
                     else:
                         mode = "MemoryZ"
                 line.expect("EOL")
             else:
                 mode = "Memory"
         result.append(IR.Node(ppt, mode, opcode, arg, arg2))
예제 #25
0
def pragmaAlias(ppt, line, result):
    "Assigns an arbitrary label"
    lbl = line.expect("LABEL").value
    target = FE.parse_expr(line)
    result.append(IR.Node(ppt, "Label", lbl, target))
    def aux():
        "Accumulates all IR nodes defined by this line."
        if line.lookahead(0).type == "EOL":
            pass
        elif line.lookahead(1).type == ":":
            newlabel = line.expect("LABEL").value
            line.expect(":")
            result.append(IR.Node(ppt, "Label", newlabel, IR.PCExpr()))
            aux()
        elif line.lookahead(0).type == "*":
            global templabelcount
            templabelcount = templabelcount + 1
            result.append(
                IR.Node(ppt, "Label", "*" + str(templabelcount), IR.PCExpr()))
            line.expect("*")
            aux()
        elif line.lookahead(0).type == "." or line.lookahead(0).type == "`":
            which = line.expect(".", "`").type
            if (which == "."): pragma = line.expect("LABEL").value
            else: pragma = "invoke"
            pragmaFunction = "pragma" + pragma.title()
            for mod in pragma_modules:
                if hasattr(mod, pragmaFunction):
                    getattr(mod, pragmaFunction)(ppt, line, result)
                    break
            else:
                Err.log("Unknown pragma " + pragma)

        else:  # Instruction
            opcode = line.expect("OPCODE").value
            if line.lookahead(0).type == "#":
                mode = "Immediate"
                line.expect("#")
                arg = parse_expr(line)
                line.expect("EOL")
            elif line.lookahead(0).type == "(":
                line.expect("(")
                arg = parse_expr(line)
                if line.lookahead(0).type == ",":
                    mode = "IndirectX"
                    line.expect(",")
                    line.expect("X")
                    line.expect(")")
                    line.expect("EOL")
                else:
                    line.expect(")")
                    tok = line.expect(",", "EOL").type
                    if tok == "EOL":
                        mode = "Indirect"
                    else:
                        mode = "IndirectY"
                        line.expect("Y")
                        line.expect("EOL")
            elif line.lookahead(0).type == "EOL":
                mode = "Implied"
                arg = None
            else:
                arg = parse_expr(line)
                tok = line.expect("EOL", ",").type
                if tok == ",":
                    tok = line.expect("X", "Y").type
                    if tok == "X": mode = "MemoryX"
                    else: mode = "MemoryY"
                    line.expect("EOL")
                else:
                    mode = "Memory"
            result.append(IR.Node(ppt, mode, opcode, arg))