如何实现汇编程序

时间:2014-01-25 17:08:59

标签: python assembly mips variable-assignment

我有一个简单的任务,就是编写一个可以组装15 mips指令的汇编程序(add,addi,or ori,ori,sll,slt,beq,lw,sw,sub,jal,jr和i) &安培;我决定使用python编程,因为它是一种简单易用的语言,我的算法是要求用户输入操作然后每次操作操作数,然后输出机器代码将在file.txt中可用...仅使用条件,因为我是初学者和不知道很多关于python,有没有人建议我使用if条件&更好的算法来实现这个汇编程序。 python中的i / o文件?

inst = raw_input("enter your instruction operation:")

if ((inst[0] == 'a' and inst[1] == 'd' and inst[2] == 'd') or (inst[0] == 'a' and inst[1] == 'n' and inst[2] == 'd') or (inst[0] == 'o' and inst[1] == 'r') or (inst[0] == 'n' and inst[1] == 'o' and inst[2] == 'r') or (inst[0] == 's' and inst[1] == 'u' and inst[2] == 'b') or (inst[0] == 'j' and inst[1] == 'r') or (inst[0] == 's' and inst[1] == 'l' and inst[2] == 'l') or(inst[0] == 's' and inst[1] == 'l' and inst[2] == 't')):
        Mc_file = open("output.txt", "w")
        Rs = input("enter the destination operand:")
        rs = 
        opcode = '000000'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
elif (inst[0] == 'l' and inst[1] == 'w'):
        Mc_file = open("output.txt", "w")
        opcode = '100011'
        Mc_file.write('Opcode =' + str(opcode) + '\n')
        Mc_file.close()
elif inst[0] == 's' and inst[1] == 'w':
        Mc_file = open("output.txt", "w")
        opcode = '101011'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
elif inst[0] == 'j' and inst[1] == 'a' and inst[2] == 'l':
        Mc_file = open("output.txt", "w")
        opcode = '000011'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
elif inst[0] == 'b' and inst[1] == 'e' and inst[2] == 'q':
        Mc_file = open("output.txt", "w")
        opcode = '000100'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
elif inst[0] == 'a' and inst[1] == 'n' and inst[2] == 'd'and inst[3] == 'i':
        Mc_file = open("output.txt", "w")
        opcode = '001100'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
elif inst[0] == 'o' and inst[1] == 'r' and inst[2] == 'i':
        Mc_file = open("output.txt", "w")
        opcode = '001101'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
elif inst[0] == 'a' and inst[1] == 'd' and inst[2] == 'd'and inst[3] == 'i':
        Mc_file = open("output.txt", "w")
        opcode = '001000'
        Mc_file.write('Opcode =' + str(opcode))
        Mc_file.close()
else:
    print "Not supported operation!"

2 个答案:

答案 0 :(得分:3)

您的整个条件树(不包括第一个条件,因为我怀疑andor具有相同的操作码)可以简化为:

trans = {'lw': '100011',
    'sw': '101011',
    'jal': '000011',
    'beq': '000100',
    'andi': '001100',
    'ori': '001101',
    'addi': '00100'}

with open ('output.txt', 'w') as f:
    try: f.write (trans [inst] )
    except KeyError: print ('Operation not supported')

答案 1 :(得分:1)

David Beazley的6502汇编程序:

#!/usr/bin/env python3
# asm6502.py

"""
A simple but powerful 6502 assembler

Author : David Beazley (http://www.dabeaz.com)
Copyright (C) 2010

Parses assembly language of the following form:

var=value               ; Variable assignment

label:   OP ADDR        ; Labeled opcode and address
         OP ADDR        ; Opcode and address

Addressing modes are as follows:

         #value         ; immediate mode (8-bit value)
         %value         ; zero-page mode
         %value,X       ; zero-page X indexed
         %value,Y       ; zero-page Y indexed
         value          ; absolute
         value,X        ; absolute Y indexed
         value,Y        ; absolute Y indexed
         [value]        ; indirect
         [value,X]      ; indirect, X indexed
         [value,Y]      ; indirect, Y indexed

values and labels can be any Python expression, but the final value must
evaluate to an integer value.   Use a numeric label to set the memory
location of instructions to follow.
"""

from collections import Callable
import re

# Exception used for errors
class AssemblyError(Exception): pass

# Functions used in the creation of object code (used in the table below)
def VALUE_L(pc, value):
    return value & 0xff

def VALUE_H(pc, value):
    return (value & 0xff00) >> 8

def RELATIVE_ADDR(pc, value):
    offset = value - (pc + 2)
    return offset & 0xff

# Table of 6502 opcodes and supported addressing modes
opcodes_6502 = {
    'DATA' : {
        'immed' :      [VALUE_L],
        },
    'ADC' : {
        'immed' :      [0x69, VALUE_L],
        'zerop' :      [0x65, VALUE_L],
        'zerop_x' :    [0x75, VALUE_L],
        'abs' :        [0x6D, VALUE_L, VALUE_H],
        'abs_x' :      [0x7D, VALUE_L, VALUE_H],
        'abs_y' :      [0x79, VALUE_L, VALUE_H],
        'indirect_x' : [0x61, VALUE_L],
        'indirect_y' : [0x71, VALUE_L],
        },
    'AND' : {
        'immed' :      [0x29, VALUE_L],
        'zerop' :      [0x25, VALUE_L],
        'zerop_x' :    [0x35, VALUE_L],
        'abs' :        [0x2D, VALUE_L, VALUE_H],
        'abs_x' :      [0x3D, VALUE_L, VALUE_H],
        'abs_y' :      [0x39, VALUE_L, VALUE_H],
        'indirect_x' : [0x21, VALUE_L],
        'indirect_y' : [0x31, VALUE_L],
        },
    'ASL' : {
        'accum' :      [0x0a],
        'zerop' :      [0x06, VALUE_L],
        'zerop_x' :    [0x16, VALUE_L],
        'abs' :        [0x0e, VALUE_L, VALUE_H],
        'abs_x' :      [0x1e, VALUE_L, VALUE_H],
        },
    'BIT' : {
        'zerop' :      [0x24, VALUE_L],
        'abs'   :      [0x2c, VALUE_L, VALUE_H],
       },
    'BPL' : {
        'immed' :      [0x10, VALUE_L],
        'abs'   :      [0x10, RELATIVE_ADDR],
        },
    'BMI' : {
        'immed' :      [0x30, VALUE_L],
        'abs'   :      [0x30, RELATIVE_ADDR],
        },
    'BVC' : {
        'immed' :      [0x50, VALUE_L],
        'abs'   :      [0x50, RELATIVE_ADDR],
        },
    'BVS' : {
        'immed' :      [0x70, VALUE_L],
        'abs'   :      [0x70, RELATIVE_ADDR],
        },
    'BCC' : {
        'immed' :      [0x90, VALUE_L],
        'abs'   :      [0x90, RELATIVE_ADDR],
        },
    'BCS' : {
        'immed' :      [0xb0, VALUE_L],
        'abs'   :      [0xb0, RELATIVE_ADDR],
        },
    'BNE' : {
        'immed' :      [0xd0, VALUE_L],
        'abs'   :      [0xd0, RELATIVE_ADDR],
        },
    'BEQ' : {
        'immed' :      [0xf0, VALUE_L],
        'abs'   :      [0xf0, RELATIVE_ADDR],
        },
    'BRK' : {
        'accum' :      [0x00],
        'immed' :      [0x00, VALUE_L],
        },
    'CMP' : {
        'immed' :      [0xc9, VALUE_L],
        'zerop' :      [0xc5, VALUE_L],
        'zerop_x' :    [0xd5, VALUE_L],
        'abs' :        [0xcD, VALUE_L, VALUE_H],
        'abs_x' :      [0xdD, VALUE_L, VALUE_H],
        'abs_y' :      [0xd9, VALUE_L, VALUE_H],
        'indirect_x' : [0xc1, VALUE_L],
        'indirect_y' : [0xd1, VALUE_L],
        },
    'CPX' : {
        'immed' :      [0xe0, VALUE_L],
        'zerop' :      [0xe4, VALUE_L],
        'abs'   :      [0xec, VALUE_L, VALUE_H],
        },
    'CPY' : {
        'immed' :      [0xc0, VALUE_L],
        'zerop' :      [0xc4, VALUE_L],
        'abs'   :      [0xcc, VALUE_L, VALUE_H],
        },
    'DEC' : {
        'zerop' :      [0xc6, VALUE_L],
        'zerop_x' :    [0xd6, VALUE_L],
        'abs' :        [0xce, VALUE_L, VALUE_H],
        'abs_x' :      [0xde, VALUE_L, VALUE_H],
        },
    'EOR' : {
        'immed' :      [0x49, VALUE_L],
        'zerop' :      [0x45, VALUE_L],
        'zerop_x' :    [0x55, VALUE_L],
        'abs' :        [0x4D, VALUE_L, VALUE_H],
        'abs_x' :      [0x5D, VALUE_L, VALUE_H],
        'abs_y' :      [0x59, VALUE_L, VALUE_H],
        'indirect_x' : [0x41, VALUE_L],
        'indirect_y' : [0x51, VALUE_L],
        },
    'CLC' : {
        'accum' :      [0x18],
        },
    'SEC' : {
        'accum' :      [0x38],
        },
    'CLI' : {
        'accum' :      [0x58],
        },
    'SEI' : {
        'accum' :      [0x78],
        },
    'CLV' : {
        'accum' :      [0xb8],
        },
    'CLD' : {
        'accum' :      [0xd8],
        },
    'SED' : {
        'accum' :      [0xf8],
        },
    'INC' : {
        'zerop' :      [0xe6, VALUE_L],
        'zerop_x' :    [0xf6, VALUE_L],
        'abs' :        [0xee, VALUE_L, VALUE_H],
        'abs_x' :      [0xfe, VALUE_L, VALUE_H],
        },
    'JMP' : {
        'abs' :        [0x4c, VALUE_L, VALUE_H],
        'indirect' :   [0x6c, VALUE_L, VALUE_H]
        },
    'JSR' : {
        'abs' :        [0x20, VALUE_L, VALUE_H],
        },
    'LDA' : {
        'immed' :      [0xA9, VALUE_L],
        'zerop' :      [0xA5, VALUE_L],
        'zerop_x' :    [0xB5, VALUE_L],
        'abs' :        [0xAD, VALUE_L, VALUE_H],
        'abs_x' :      [0xBD, VALUE_L, VALUE_H],
        'abs_y' :      [0xB9, VALUE_L, VALUE_H],
        'indirect_x' : [0xA1, VALUE_L],
        'indirect_y' : [0xB1, VALUE_L],
        },
    'LDX' : {
        'immed' :      [0xa2, VALUE_L],
        'zerop' :      [0xa6, VALUE_L],
        'zerop_y' :    [0xb6, VALUE_L],
        'abs' :        [0xae, VALUE_L, VALUE_H],
        'abs_y' :      [0xbe, VALUE_L, VALUE_H],
        },
    'LDY' : { 
        'immed' :      [0xa0, VALUE_L],
        'zerop' :      [0xa4, VALUE_L],
        'zerop_x' :    [0xb4, VALUE_L],
        'abs' :        [0xac, VALUE_L, VALUE_H],
        'abs_x' :      [0xbc, VALUE_L, VALUE_H],
        },
    'LSR' : {
        'accum' :      [0x4a],
        'zerop' :      [0x46, VALUE_L],
        'zerop_x' :    [0x56, VALUE_L],
        'abs' :        [0x4e, VALUE_L, VALUE_H],
        'abs_x' :      [0x5e, VALUE_L, VALUE_H],
        },
    'NOP' : {
        'accum' :      [0xea],
        },
    'ORA' : {
        'immed' :      [0x09, VALUE_L],
        'zerop' :      [0x05, VALUE_L],
        'zerop_x' :    [0x15, VALUE_L],
        'abs' :        [0x0D, VALUE_L, VALUE_H],
        'abs_x' :      [0x1D, VALUE_L, VALUE_H],
        'abs_y' :      [0x19, VALUE_L, VALUE_H],
        'indirect_x' : [0x01, VALUE_L],
        'indirect_y' : [0x11, VALUE_L],
        },
    'TAX' : {
        'accum' :      [0xaa],
        },
    'TXA' : {
        'accum' :      [0x8a],
        },
    'DEX' : {
        'accum' :      [0xca],
        },
    'INX' : {
        'accum' :      [0xe8],
        },
    'TAY' : {
        'accum' :      [0xa8],
        },
    'TYA' : {
        'accum' :      [0x98],
        },
    'DEY' : {
        'accum' :      [0x88],
        },
    'INY' : {
        'accum' :      [0xc8],
        },
    'ROL' : {
        'accum' :      [0x2a],
        'zerop' :      [0x26, VALUE_L],
        'zerop_x' :    [0x36, VALUE_L],
        'abs' :        [0x2e, VALUE_L, VALUE_H],
        'abs_x' :      [0x3e, VALUE_L, VALUE_H],
        },
    'ROR' : {
        'accum' :      [0x6a],
        'zerop' :      [0x66, VALUE_L],
        'zerop_x' :    [0x76, VALUE_L],
        'abs' :        [0x6e, VALUE_L, VALUE_H],
        'abs_x' :      [0x7e, VALUE_L, VALUE_H],
        },
    'RTI' : {
        'accum' :      [0x40],
        },
    'RTS' : {
        'accum' :      [0x60],
        },
    'SBC' : {
        'immed' :      [0xe9, VALUE_L],
        'zerop' :      [0xe5, VALUE_L],
        'zerop_x' :    [0xf5, VALUE_L],
        'abs' :        [0xeD, VALUE_L, VALUE_H],
        'abs_x' :      [0xfD, VALUE_L, VALUE_H],
        'abs_y' :      [0xf9, VALUE_L, VALUE_H],
        'indirect_x' : [0xe1, VALUE_L],
        'indirect_y' : [0xf1, VALUE_L],
        },
    'STA' : {
        'zerop' :      [0x85, VALUE_L],
        'zerop_x' :    [0x95, VALUE_L],
        'abs' :        [0x8D, VALUE_L, VALUE_H],
        'abs_x' :      [0x9D, VALUE_L, VALUE_H],
        'abs_y' :      [0x99, VALUE_L, VALUE_H],
        'indirect_x' : [0x81, VALUE_L],
        'indirect_y' : [0x91, VALUE_L],
        },
    'TXS' : {
        'accum' :      [0x9a],
        },
    'TSX' : {
        'accum' :      [0xba],
        },
    'PHA' : {
        'accum' :      [0x48],
        },
    'PLA' : {
        'accum' :      [0x68],
        },
    'PHP' : {
        'accum' :      [0x08],
        },
    'PLP' : {
        'accum' :      [0x28],
        },
    'STX' : {
        'zerop' :      [0x86, VALUE_L],
        'zerop_y' :    [0x96, VALUE_L],
        'abs' :        [0x8e, VALUE_L, VALUE_H],
        },
    'STY' : {
        'zerop' :      [0x84, VALUE_L],
        'zerop_x' :    [0x94, VALUE_L],
        'abs' :        [0x8c, VALUE_L, VALUE_H],
        },
    }

# Parse address modes for various 6502 instructions
def parse_address_mode(mode):
    # Accumulator or implicit. Example: INC
    if not mode or mode == 'A':    return ("accum","0")  

    # Immediate value. Example : LDA #13  
    if mode.startswith("#"):       return ("immed", mode[1:]) 

    # Strip unneeded whitespace if not an immediate value
    mode = mode.replace(' ','')

    # Zero-page address with indexing. Example : LDA %25, X
    if mode.startswith("%"):
        if mode.endswith(",X"):    return ("zerop_x", mode[1:-2])
        elif mode.endswith(",Y"):  return ("zerop_y", mode[1:-2])
        else:                      return ("zerop", mode[1:])

    # Indirect addressing.Example : LDA [0xFF00, X]
    if mode.startswith("["):   
        if mode.endswith(",X]"):   return ("indirect_x", mode[1:-3])
        elif mode.endswith(",Y]"): return ("indirect_y",mode[1:-3])
        elif mode.endswith("]"):   return ("indirect", mode[1:-1])

    # Absolute address, with indexing. Example : LDA 0xFF00, X
    if mode.endswith(",X"):        return ("abs_x",mode[:-2])
    elif mode.endswith(",Y"):      return ("abs_y",mode[:-2])
    else:                          return ("abs",mode)

# Parse an opcode line into intermediate object code. Returns a tuple
# (value, objcode) where value is a string to be evaluated in the 2nd pass
def parse_opcode(line):
    fields = line.split(None,1)
    opcode = fields[0]
    arg = fields[1] if len(fields) == 2 else ""
    mode,value = parse_address_mode(arg)
    opcodemodes = opcodes_6502.get(opcode)
    if not opcodemodes:
        raise AssemblyError("Unknown opcode '%s'" % opcode)
    objcode = opcodemodes.get(mode)
    if not objcode:
        raise AssemblyError("Invalid addressing mode '%s' for opcode %s" % (arg,opcode))
    return (value,list(objcode))

# Takes a sequence of lines and strip comments and blanks
def strip_lines(lines):
    for line in lines:
        comment_index = line.find(";")
        if comment_index >= 0:
            line = line[:comment_index]
        line = line.strip()
        yield line

assign_pat = re.compile(r'(\s*)([a-zA-Z_][a-zA-Z0-9_]*)(\s*=)')

# Parse lines into intermediate object code
def parse_lines(lines,symbols):
    for lineno,line in enumerate(lines,1):
        if assign_pat.match(line):
            exec(line,symbols)
        else:
            label, *colon, statement = line.rpartition(":")
            try:
                yield lineno, label, parse_opcode(statement) if statement else (None,None)
            except AssemblyError as e:
                print("{0:4d} : Error : {1}".format(lineno,e))

# Assemble a sequence of lines into binary
def assemble_6502(lines,pc=0):
    objcode = []
    symbols = {}
    symbols['HIGH'] = lambda x : (x & 0xff00) >> 8
    symbols['LOW'] = lambda x : x & 0xff

    # Pass 1 : Parse instructions and create intermediate code
    for lineno, label, (value, icode) in parse_lines(lines,symbols):
        # Try to evaluate numeric labels and set the PC
        if label:
            try:
                pc = int(eval(label,symbols))
            except (ValueError,NameError):
                symbols[label] = pc

        # Store the resulting objcode for later expansion
        if icode:
            objcode.append((lineno,pc,value,icode))
            pc += len(icode)

    # Pass 2 : Create final object code by evaluating expressions
    execode = []
    for lineno, pc, value, icode in objcode:
        # Evaluate the value string
        try:
            symbols['PC'] = pc
            realvalue = eval(value,symbols)
            if isinstance(realvalue,str):
                realvalue = ord(realvalue) & 0xff
            if not isinstance(realvalue, int):
                raise TypeError("Integer expected in {0}".format(value))
        except Exception as e:
            print("{0:4d} : Error : {1}".format(lineno,e),file=sys.stderr)
            realvalue = 0
        ecode = [op(pc,realvalue) if isinstance(op,Callable) else op
                 for op in icode]
        execode.append((lineno,pc,ecode))
    return execode

if __name__ == '__main__':
    import sys
    if len(sys.argv) != 2:
        print("Usage %s infile.asm" % sys.argv[0],file=sys.stderr)
        raise SystemExit(1)
    lines = strip_lines(open(sys.argv[1]))
    if 0:
        for lineno, pc, opcode in assemble_6502(lines):
            print("%04x : " % pc, end="")
            print(*(format(op,"02x") for op in opcode))
    if 1:
        # OSI monitor format
        first = 0
        lastpc = -1
        for lineno, pc, opcode in assemble_6502(lines):
            if not first:
                first = pc
            if lastpc != pc:
                print(".%04X/" % pc,end="")
            for op in opcode:
                print("%02X" % op)
            lastpc = pc + len(opcode)
        print(".00FB/00")

或许berkeley could be useful,完整解释here