Beispiel #1
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
def readData(line):
    "Read raw data from a comma-separated list"
    if line.lookahead(0).type == "STRING":
        data = [IR.ConstantExpr(ord(x)) for x in line.expect("STRING").value]
    else:
        data = [FE.parse_expr(line)]
    next = line.expect(',', 'EOL').type
    while next == ',':
        if line.lookahead(0).type == "STRING":
            data.extend(
                [IR.ConstantExpr(ord(x)) for x in line.expect("STRING").value])
        else:
            data.append(FE.parse_expr(line))
        next = line.expect(',', 'EOL').type
    return data
Beispiel #3
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))
Beispiel #4
0
 def relativizelong(self, expr, env, arglen):
     "Convert an expression into one for use in relative addressing"
     arg = expr.value(env)
     arg = arg - (env.getPC() + arglen)
     if arg < 0:
         arg += 65536
     return IR.ConstantExpr(arg)
Beispiel #5
0
 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)
Beispiel #6
0
 def assemble(self, node, mode, env):
     "A generic instruction called by the visitor methods themselves"
     (opcode, expr, expr2) = node.data
     bin_op = Ops.opcodes[opcode][mode]
     if bin_op is None:
         Err.log('%s does not have mode "%s"' %
                 (opcode.upper(), Ops.modes[mode]))
         return
     inst_bytes = []
     self.outputbyte(IR.ConstantExpr(bin_op), env, inst_bytes)
     arglen = Ops.lengths[mode]
     val1 = None
     val2 = None
     if expr is not None:
         val1 = expr.value(env)
     if expr2 is not None:
         val2 = expr2.value(env)
     if mode == Ops.modes.index("Zero Page, Relative"):
         expr2 = self.relativize(expr2, env, arglen)
         self.outputbyte(expr, env, inst_bytes)
         self.outputbyte(expr2, env, inst_bytes)
     else:
         if mode == Ops.modes.index("Relative"):
             expr = self.relativize(expr, env, arglen)
         elif mode == Ops.modes.index("RelativeLong"):
             expr = self.relativizelong(expr, env, arglen)
         if arglen == 1:
             self.outputbyte(expr, env, inst_bytes)
         elif arglen == 2:
             self.outputword(expr, env, inst_bytes)
     self.listing.listInstruction(
         self.listing_string(env.getPC(), inst_bytes, mode, opcode, val1,
                             val2))
     env.incPC(1 + arglen)
     self.code += 1 + arglen
Beispiel #7
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)])))
Beispiel #8
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))
Beispiel #9
0
 def relativize(self, expr, env, arglen):
     "Convert an expression into one for use in relative addressing"
     arg = expr.value(env)
     arg = arg - (env.getPC() + arglen + 1)
     if arg < -128 or arg > 127:
         Err.log("Branch target out of bounds")
         arg = 0
     if arg < 0:
         arg += 256
     return IR.ConstantExpr(arg)
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))
 def visitAdvance(self, node, env):
     pc = env.getPC()
     target = node.data[0].value(env)
     if (pc > target):
         Err.log("Attempted to .advance backwards: $%x to $%x" %
                 (pc, target))
     else:
         zero = IR.ConstantExpr(0)
         for i in range(target - pc):
             self.outputbyte(zero, env)
         self.filler += target - pc
     env.setPC(target)
 def assemble(self, node, mode, env):
     "A generic instruction called by the visitor methods themselves"
     (opcode, expr) = node.data
     bin_op = Ops.opcodes[opcode][mode]
     if bin_op is None:
         Err.log('%s does not have mode "%s"' %
                 (opcode.upper(), Ops.modes[mode]))
         return
     self.outputbyte(IR.ConstantExpr(bin_op), env)
     arglen = Ops.lengths[mode]
     if mode == 11:  # Special handling for relative mode
         arg = expr.value(env)
         arg = arg - (env.getPC() + 2)
         if arg < -128 or arg > 127:
             Err.log("Branch target out of bounds")
             arg = 0
         if arg < 0: arg += 256
         expr = IR.ConstantExpr(arg)
     if arglen == 1: self.outputbyte(expr, env)
     if arglen == 2: self.outputword(expr, env)
     env.incPC(1 + arglen)
     self.code += 1 + arglen
Beispiel #13
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)
Beispiel #14
0
 def atom():
     "Parses lowest-priority expression components."
     global templabelcount
     next = line.lookahead(0).type
     if next == "NUM":
         return IR.ConstantExpr(line.expect("NUM").value)
     elif next in ["LABEL", "X", "Y", "Z", "SP", "OPCODE"]:
         return IR.LabelExpr(line.expect("LABEL").value)
     elif next == "^":
         line.expect("^")
         return IR.PCExpr()
     elif next == "[":
         line.expect("[")
         result = parse_expr(line)
         line.expect("]")
         return result
     elif next == "+":
         offset = 0
         while next == "+":
             offset += 1
             line.expect("+")
             next = line.lookahead(0).type
         return IR.LabelExpr("*" + str(templabelcount + offset))
     elif next == "-":
         offset = 1
         while next == "-":
             offset -= 1
             line.expect("-")
             next = line.lookahead(0).type
         return IR.LabelExpr("*" + str(templabelcount + offset))
     elif next == ">":
         line.expect(">")
         return IR.HighByteExpr(atom())
     elif next == "<":
         line.expect("<")
         return IR.LowByteExpr(atom())
     else:
         Err.log('Expected: expression')